diff --git a/doc/2026-04-15-全量迁移892-without-redis前端实施计划.md b/doc/2026-04-15-全量迁移892-without-redis前端实施计划.md new file mode 100644 index 0000000..a3513ba --- /dev/null +++ b/doc/2026-04-15-全量迁移892-without-redis前端实施计划.md @@ -0,0 +1,420 @@ +# 全量迁移 `892-without-redis` 前端实施计划 + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 在当前前端工程中迁入 `origin/892-without-redis` 的贷款定价页面、登录页与缓存监控相关行为,并与后端迁移后的接口契约完全对齐。 + +**Architecture:** 以前端 `ruoyi-ui` 为基线,新增贷款定价页面目录、API 封装、密码传输工具与页面测试脚本,按“接口先对齐、页面后对齐”的顺序迁移。对目标分支与当前分支冲突位置优先保留当前工程的 Vue2/RuoYi 组织方式,再把目标功能按现有结构接进去。 + +**Tech Stack:** Vue 2, Vue Router, Vuex, Element UI, Axios API wrappers, Node via nvm + +--- + +> 仓库约束补充:执行前端验证时必须先在 `ruoyi-ui` 下执行 `nvm use`;若拉起前端 dev 进程,验证结束后要主动关闭。 + +## 文件结构映射 + +### 路由、登录、公共工具 + +- Modify: `ruoyi-ui/src/router/index.js` +- Modify: `ruoyi-ui/src/views/login.vue` +- Modify: `ruoyi-ui/src/api/login.js` +- Create: `ruoyi-ui/src/utils/passwordTransfer.js` + +### 贷款定价 API 与页面 + +- Create: `ruoyi-ui/src/api/loanPricing/workflow.js` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/index.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/detail.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/CorporateWorkflowDetail.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/CustomerTypeSelector.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue` + +### 缓存监控页面 + +- Modify: `ruoyi-ui/src/api/monitor/cache.js` +- Modify: `ruoyi-ui/src/views/monitor/cache/index.vue` +- Modify: `ruoyi-ui/src/views/monitor/cache/list.vue` + +### 前端静态测试脚本 + +- Create: `ruoyi-ui/tests/password-transfer-api.test.js` +- Create: `ruoyi-ui/tests/personal-create-input-params.test.js` +- Create: `ruoyi-ui/tests/retail-display-fields.test.js` +- Create: `ruoyi-ui/tests/personal-final-calculate-rate-display.test.js` +- Create: `ruoyi-ui/tests/workflow-detail-card-order.test.js` +- Create: `ruoyi-ui/tests/workflow-index-refresh.test.js` +- Create: `ruoyi-ui/tests/login-default-credentials.test.js` + +### 前端实施记录 + +- Create: `doc/2026-04-15-全量迁移892-without-redis前端实施记录.md` + +--- + +### Task 1: 接入贷款定价路由、API 和页面骨架 + +**Files:** +- Modify: `ruoyi-ui/src/router/index.js` +- Create: `ruoyi-ui/src/api/loanPricing/workflow.js` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/index.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/detail.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/CustomerTypeSelector.vue` + +- [ ] **Step 1: 先写路由/页面缺失断言脚本** + +在 `ruoyi-ui/tests/workflow-index-refresh.test.js` 先写最小源码断言: + +```js +expect(routerSource).toContain("LoanPricingWorkflow") +expect(routerSource).toContain("@/views/loanPricing/workflow/index") +expect(routerSource).toContain("@/views/loanPricing/workflow/detail") +``` + +- [ ] **Step 2: 创建 API 封装** + +`ruoyi-ui/src/api/loanPricing/workflow.js` 至少提供: + +```js +export function listWorkflow(query) {} +export function getWorkflow(serialNum) {} +export function createPersonalWorkflow(data) {} +export function createCorporateWorkflow(data) {} +export function updateExecuteRate(data) {} +``` + +- [ ] **Step 3: 接入默认首页和详情路由** + +`ruoyi-ui/src/router/index.js` 需要包含: + +```js +component: () => import('@/views/loanPricing/workflow/index') +``` + +以及隐藏详情路由: + +```js +path: '/loanPricing/workflow-detail' +``` + +- [ ] **Step 4: 创建最小页面骨架** + +`index.vue` 至少包含: + +```vue + +``` + +`detail.vue` 至少包含: + +```vue + + +``` + +- [ ] **Step 5: 运行前端源码测试** + +Run: + +```bash +cd ruoyi-ui && node tests/workflow-index-refresh.test.js +``` + +Expected: 断言通过。 + +- [ ] **Step 6: 提交** + +```bash +git add ruoyi-ui/src/router/index.js ruoyi-ui/src/api/loanPricing/workflow.js ruoyi-ui/src/views/loanPricing +git commit -m "接入贷款定价前端页面骨架" +``` + +### Task 2: 实现流程列表与详情展示行为 + +**Files:** +- Modify: `ruoyi-ui/src/views/loanPricing/workflow/index.vue` +- Modify: `ruoyi-ui/src/views/loanPricing/workflow/detail.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/BargainingPoolDisplay.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/CorporateWorkflowDetail.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue` +- Test: `ruoyi-ui/tests/retail-display-fields.test.js` +- Test: `ruoyi-ui/tests/personal-final-calculate-rate-display.test.js` +- Test: `ruoyi-ui/tests/workflow-detail-card-order.test.js` + +- [ ] **Step 1: 先写详情字段失败测试** + +在源码断言里至少覆盖: + +```js +expect(source).toContain("loanTerm") +expect(source).toContain("finalCalculateRate") +expect(source).toContain("referenceRate") +expect(source).toContain("smoothRange") +``` + +并为卡片顺序加断言: + +```js +expect(detailSource.indexOf("基础信息")).toBeLessThan(detailSource.indexOf("测算结果")) +``` + +- [ ] **Step 2: 改列表列定义** + +`index.vue` 要明确展示: + +```vue + + + +``` + +个人最终测算利率按目标分支行为取后端返回的 `finalCalculateRate` 或已统一好的 `calculateRate`。 + +- [ ] **Step 3: 改详情页面与模型输出组件** + +`PersonalWorkflowDetail.vue` 必须展示: + +- `loanTerm` +- `finalCalculateRate` +- 调整后的详情卡片顺序 + +`ModelOutputDisplay.vue` 必须展示: + +- `loanRateHistory` +- `minRateProduct` +- `smoothRange` +- `finalCalculateRate` +- `referenceRate` + +- [ ] **Step 4: 运行源码测试** + +Run: + +```bash +cd ruoyi-ui && node tests/retail-display-fields.test.js && node tests/personal-final-calculate-rate-display.test.js && node tests/workflow-detail-card-order.test.js +``` + +Expected: 断言通过。 + +- [ ] **Step 5: 提交** + +```bash +git add ruoyi-ui/src/views/loanPricing ruoyi-ui/tests +git commit -m "迁移流程列表与详情展示逻辑" +``` + +### Task 3: 实现个人/企业建单弹窗与输入参数对齐 + +**Files:** +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue` +- Create: `ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue` +- Modify: `ruoyi-ui/src/views/loanPricing/workflow/index.vue` +- Test: `ruoyi-ui/tests/personal-create-input-params.test.js` + +- [ ] **Step 1: 先写个人入参失败测试** + +```js +expect(source).toContain("loanPurpose") +expect(source).toContain("loanTerm") +expect(source).toContain("loanLoop") +expect(source).toContain("collThirdParty") +expect(source).toContain("['一类', '二类', '三类']") +``` + +- [ ] **Step 2: 实现个人建单弹窗** + +`PersonalCreateDialog.vue` 至少补齐: + +```js +form: { + custIsn: '', + custName: '', + idType: '', + idNum: '', + guarType: '', + applyAmt: '', + loanPurpose: '', + loanTerm: '', + bizProof: false, + loanLoop: false, + collThirdParty: false, + collType: '' +} +``` + +并在提交时直接调用 `createPersonalWorkflow`,不在前端增加补丁式兜底。 + +- [ ] **Step 3: 实现企业建单弹窗并接入列表页** + +`index.vue` 中要能根据客户类型打开对应建单对话框,且提交后刷新列表。 + +- [ ] **Step 4: 跑源码测试** + +Run: + +```bash +cd ruoyi-ui && node tests/personal-create-input-params.test.js +``` + +Expected: 断言通过。 + +- [ ] **Step 5: 提交** + +```bash +git add ruoyi-ui/src/views/loanPricing ruoyi-ui/tests/personal-create-input-params.test.js +git commit -m "迁移贷款定价建单弹窗" +``` + +### Task 4: 迁移登录密码传输与登录页展示 + +**Files:** +- Modify: `ruoyi-ui/src/views/login.vue` +- Modify: `ruoyi-ui/src/api/login.js` +- Create: `ruoyi-ui/src/utils/passwordTransfer.js` +- Test: `ruoyi-ui/tests/password-transfer-api.test.js` +- Test: `ruoyi-ui/tests/login-default-credentials.test.js` + +- [ ] **Step 1: 先写登录页失败测试** + +`login-default-credentials.test.js` 要先断言旧默认账号密码提示不存在: + +```js +expect(source).not.toContain("admin") +expect(source).not.toContain("123456") +``` + +`password-transfer-api.test.js` 要断言登录 API 使用密码传输工具: + +```js +expect(apiSource).toContain("transferPassword") +``` + +- [ ] **Step 2: 新增密码传输工具** + +`ruoyi-ui/src/utils/passwordTransfer.js` 最小接口: + +```js +export function transferPassword(password) { + return password +} +``` + +后续再替换为与后端一致的实际传输处理,但调用入口先统一。 + +- [ ] **Step 3: 改登录 API 与页面** + +`src/api/login.js` 在登录、注册、修改密码等调用入口统一接 `transferPassword`。 + +`src/views/login.vue` 删除默认账号密码展示,保留验证码、记住密码和现有交互。 + +- [ ] **Step 4: 跑源码测试** + +Run: + +```bash +cd ruoyi-ui && node tests/password-transfer-api.test.js && node tests/login-default-credentials.test.js +``` + +Expected: 断言通过。 + +- [ ] **Step 5: 提交** + +```bash +git add ruoyi-ui/src/api/login.js ruoyi-ui/src/utils/passwordTransfer.js ruoyi-ui/src/views/login.vue ruoyi-ui/tests +git commit -m "迁移登录页与密码传输前端逻辑" +``` + +### Task 5: 迁移缓存监控页并对齐内存缓存行为 + +**Files:** +- Modify: `ruoyi-ui/src/api/monitor/cache.js` +- Modify: `ruoyi-ui/src/views/monitor/cache/index.vue` +- Modify: `ruoyi-ui/src/views/monitor/cache/list.vue` + +- [ ] **Step 1: 先核对后端缓存接口字段** + +执行前先读后端 `CacheController` 最终返回字段,记录页面需要显示哪些统计项,禁止继续按 Redis 键空间展示。 + +- [ ] **Step 2: 改 API 与页面展示** + +`cache.js` 按后端实际接口字段更新。 + +`index.vue` / `list.vue` 改成展示内存缓存统计、命中率、键数量、过期数量等目标分支行为要求的内容。 + +- [ ] **Step 3: 做页面级静态检查** + +至少确认源码里不再假设 Redis 特有结构,例如: + +```js +expect(source).not.toContain("redis") +``` + +如需要,可新增一个简短源码测试脚本并与本任务一起提交。 + +- [ ] **Step 4: 提交** + +```bash +git add ruoyi-ui/src/api/monitor/cache.js ruoyi-ui/src/views/monitor/cache +git commit -m "迁移缓存监控前端页面" +``` + +### Task 6: 前端总验收与实施记录 + +**Files:** +- Modify: `doc/2026-04-15-全量迁移892-without-redis前端实施计划.md` +- Create: `doc/2026-04-15-全量迁移892-without-redis前端实施记录.md` + +- [ ] **Step 1: 安装依赖并构建** + +Run: + +```bash +cd ruoyi-ui +nvm use +npm install +npm run build:prod +``` + +Expected: 生产构建成功。 + +- [ ] **Step 2: 启动前端进行关键页面冒烟** + +Run: + +```bash +cd ruoyi-ui +nvm use +npm run dev +``` + +检查: + +- 登录页 +- 流程列表 +- 流程详情 +- 个人建单 +- 缓存监控页 + +验证完成后主动停止前端进程。 + +- [ ] **Step 3: 补前端实施记录** + +`doc/2026-04-15-全量迁移892-without-redis前端实施记录.md` 至少记录: + +- 实际迁入页面与 API +- 与目标分支不做原样搬运的整合点 +- `nvm use` 的 Node 版本 +- 构建结果 +- 页面冒烟结果 + +- [ ] **Step 4: 提交** + +```bash +git add doc/2026-04-15-全量迁移892-without-redis前端实施计划.md doc/2026-04-15-全量迁移892-without-redis前端实施记录.md +git commit -m "补充全量迁移前端实施记录" +``` diff --git a/doc/2026-04-15-全量迁移892-without-redis后端实施计划.md b/doc/2026-04-15-全量迁移892-without-redis后端实施计划.md new file mode 100644 index 0000000..1fb2872 --- /dev/null +++ b/doc/2026-04-15-全量迁移892-without-redis后端实施计划.md @@ -0,0 +1,587 @@ +# 全量迁移 `892-without-redis` 后端实施计划 + +> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 在保留当前分支 JDK8 与去 Redis 基线的前提下,把 `origin/892-without-redis` 的后端业务、脚本、SQL、配置能力完整迁移到当前分支,并保证行为对齐。 + +**Architecture:** 以后端主工程为基线,新增 `ruoyi-loan-pricing` 业务模块并接入 `ruoyi-admin`、根 `pom.xml` 与 SQL/脚本目录。所有与 Redis 或高版本 JDK 冲突的实现只迁业务行为,不回退当前分支的技术底座;同文件冲突采用手工整合,不做整文件覆盖。 + +**Tech Stack:** Java 8, Spring Boot 2.5.x, Maven multi-module, MyBatis/XML Mapper, JUnit, Shell scripts, SQL + +--- + +> 仓库约束补充:本仓库 `AGENTS.md` 明确要求不开启 subagent,因此执行本计划时应在当前会话内分批完成,不走子代理评审流。 + +## 文件结构映射 + +### 根工程与模块接入 + +- Modify: `pom.xml` +- Modify: `ruoyi-admin/pom.xml` +- Create: `ruoyi-loan-pricing/pom.xml` + +### 贷款定价后端模块 + +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/LoanPricingWorkflowController.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/LoanRatePricingMockController.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFields.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelCorpOutputFields.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/vo/LoanPricingWorkflowListVO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/vo/LoanPricingWorkflowVO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/mapper/LoanPricingWorkflowMapper.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/mapper/ModelRetailOutputFieldsMapper.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/mapper/ModelCorpOutputFieldsMapper.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/ILoanPricingWorkflowService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/ModelService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java` +- Create: `ruoyi-loan-pricing/src/main/resources/mapper/loanpricing/LoanPricingWorkflowMapper.xml` +- Create: `ruoyi-loan-pricing/src/main/resources/data/corp_output.json` +- Create: `ruoyi-loan-pricing/src/main/resources/data/retail_output.json` + +### 登录密码传输与系统接口调整 + +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java` +- Modify: `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java` +- Modify: `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java` + +### 缓存、配置、部署与 SQL + +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java` +- Modify: `ruoyi-admin/src/main/resources/application.yml` +- Create: `ruoyi-admin/src/main/resources/application-pro.yml` +- Create: `ruoyi-admin/src/main/resources/application-uat.yml` +- Modify: `bin/restart_java_backend.sh` +- Create: `bin/restart_java_backend_test.sh` +- Create: `bin/prod/deploy_from_package.sh` +- Create: `bin/prod/deploy_from_package_test.sh` +- Create: `bin/prod/deploy_release.sh` +- Create: `bin/prod/install_env.sh` +- Create: `bin/prod/restart_java.sh` +- Create: `bin/prod/restart_java_test.sh` +- Create: `deploy/nginx.conf` +- Create: `deploy/2026-03-31-local-nginx-java-install-manual.md` +- Create: `sql/loan_pricing_schema_20260328.sql` +- Create: `sql/loan_pricing_required_data_20260328.sql` +- Create: `sql/loan_pricing_prod_init_20260331.sql` +- Create: `sql/loan_pricing_menu.sql` +- Create: `sql/loan_pricing_workflow.sql` +- Create: `sql/model_retail.sql` +- Create: `sql/model_corp.sql` + +### 后端测试 + +- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFieldsTest.java` +- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/vo/LoanPricingWorkflowListVOTest.java` +- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/mapper/LoanPricingWorkflowMapperXmlTest.java` +- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServicePersonalParamsTest.java` +- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingModelServiceTest.java` +- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayServiceTest.java` +- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoServiceTest.java` +- Create: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImplTest.java` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysLoginControllerPasswordTransferTest.java` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysRegisterControllerPasswordTransferTest.java` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysProfileControllerPasswordTransferTest.java` +- Create: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysUserControllerPasswordTransferTest.java` +- Modify: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/monitor/CacheControllerTest.java` + +### 后端实施记录 + +- Create: `doc/2026-04-15-全量迁移892-without-redis后端实施记录.md` + +--- + +### Task 1: 接入 `ruoyi-loan-pricing` 模块到底座工程 + +**Files:** +- Modify: `pom.xml` +- Modify: `ruoyi-admin/pom.xml` +- Create: `ruoyi-loan-pricing/pom.xml` + +- [ ] **Step 1: 写出模块接入失败测试条件** + +在计划执行时,先确认当前工程不存在贷款定价模块: + +```bash +test -d ruoyi-loan-pricing || echo "ruoyi-loan-pricing missing" +``` + +Expected: 输出 `ruoyi-loan-pricing missing` + +- [ ] **Step 2: 建立最小模块骨架** + +创建: + +```text +ruoyi-loan-pricing/ +ruoyi-loan-pricing/pom.xml +ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/ +ruoyi-loan-pricing/src/main/resources/ +ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/ +``` + +`ruoyi-loan-pricing/pom.xml` 最小内容应包含: + +```xml +ruoyi-loan-pricing + + + com.ruoyi + ruoyi-common + + + com.ruoyi + ruoyi-framework + + + com.ruoyi + ruoyi-system + + +``` + +- [ ] **Step 3: 把模块接入聚合与启动工程** + +修改 `pom.xml`: + +```xml + + com.ruoyi + ruoyi-loan-pricing + ${ruoyi.version} + +``` + +以及: + +```xml +ruoyi-loan-pricing +``` + +修改 `ruoyi-admin/pom.xml` 增加: + +```xml + + com.ruoyi + ruoyi-loan-pricing + +``` + +- [ ] **Step 4: 运行 Maven 校验模块被识别** + +Run: + +```bash +mvn -pl ruoyi-loan-pricing -am -DskipTests package +``` + +Expected: Maven 能识别 `ruoyi-loan-pricing` 模块;若后续类未补齐可先因编译缺类失败,但不能再是“模块不存在”。 + +- [ ] **Step 5: 提交** + +```bash +git add pom.xml ruoyi-admin/pom.xml ruoyi-loan-pricing +git commit -m "接入贷款定价后端模块骨架" +``` + +### Task 2: 落地贷款定价后端主链与 Mapper + +**Files:** +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/LoanPricingWorkflowController.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/controller/LoanRatePricingMockController.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/CorporateLoanPricingCreateDTO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/PersonalLoanPricingCreateDTO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/dto/ModelInvokeDTO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/LoanPricingWorkflow.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFields.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelCorpOutputFields.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/vo/LoanPricingWorkflowListVO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/vo/LoanPricingWorkflowVO.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/mapper/LoanPricingWorkflowMapper.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/mapper/ModelRetailOutputFieldsMapper.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/mapper/ModelCorpOutputFieldsMapper.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/ILoanPricingWorkflowService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/ModelService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/util/LoanPricingConverter.java` +- Create: `ruoyi-loan-pricing/src/main/resources/mapper/loanpricing/LoanPricingWorkflowMapper.xml` +- Test: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/mapper/LoanPricingWorkflowMapperXmlTest.java` +- Test: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImplTest.java` + +- [ ] **Step 1: 先写列表/详情契约失败测试** + +在 `LoanPricingWorkflowMapperXmlTest` 中先写断言,覆盖: + +```java +assertThat(xml).contains("calculate_rate"); +assertThat(xml).contains("execute_rate"); +assertThat(xml).contains("update_time"); +assertThat(xml).contains("final_calculate_rate"); +``` + +以及在 `LoanPricingWorkflowServiceImplTest` 中先写: + +```java +assertEquals("个人", workflow.getCustType()); +assertEquals("1", dto.getRunType()); +``` + +- [ ] **Step 2: 创建 DTO / Entity / VO / Mapper 骨架** + +最小要保证这些字段到位: + +```java +private String serialNum; +private String custIsn; +private String custName; +private String idNum; +private String custType; +private BigDecimal executeRate; +private BigDecimal calculateRate; +private BigDecimal finalCalculateRate; +private Date updateTime; +``` + +- [ ] **Step 3: 实现列表 SQL 与详情装配** + +`LoanPricingWorkflowMapper.xml` 中明确写联表,不做前端拼装: + +```xml +LEFT JOIN model_retail_output_fields mr ON lpw.model_output_id = mr.id +LEFT JOIN model_corp_output_fields mc ON lpw.model_output_id = mc.id +``` + +个人列表测算利率按目标分支行为取: + +```sql +CASE WHEN lpw.cust_type = '个人' THEN mr.final_calculate_rate + WHEN lpw.cust_type = '企业' THEN mc.calculate_rate +END AS calculateRate +``` + +并返回: + +```sql +lpw.execute_rate AS executeRate, +lpw.update_time AS updateTime +``` + +- [ ] **Step 4: 实现建单与模型调用链路** + +`PersonalLoanPricingCreateDTO` 至少补齐: + +```java +private String loanPurpose; +private Integer loanTerm; +private String loanLoop; +private String collThirdParty; +``` + +`ModelInvokeDTO` 至少补齐: + +```java +private String loanPurpose; +private Integer loanTerm; +private String loanLoop; +``` + +`LoanPricingConverter` 和 `LoanPricingModelService` 保证个人入参完整透传。 + +- [ ] **Step 5: 跑定向测试** + +Run: + +```bash +mvn -pl ruoyi-loan-pricing -Dtest=LoanPricingWorkflowMapperXmlTest,LoanPricingWorkflowServiceImplTest,LoanPricingModelServicePersonalParamsTest test +``` + +Expected: 以上测试通过。 + +- [ ] **Step 6: 提交** + +```bash +git add ruoyi-loan-pricing +git commit -m "迁移贷款定价后端主链" +``` + +### Task 3: 落地敏感字段加密脱敏与个人展示字段 + +**Files:** +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoService.java` +- Create: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayService.java` +- Modify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/impl/LoanPricingWorkflowServiceImpl.java` +- Modify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/service/LoanPricingModelService.java` +- Modify: `ruoyi-loan-pricing/src/main/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFields.java` +- Test: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/SensitiveFieldCryptoServiceTest.java` +- Test: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/service/LoanPricingSensitiveDisplayServiceTest.java` +- Test: `ruoyi-loan-pricing/src/test/java/com/ruoyi/loanpricing/domain/entity/ModelRetailOutputFieldsTest.java` + +- [ ] **Step 1: 先写加解密和脱敏失败测试** + +```java +assertThat(crypto.encrypt("张三")).isNotEqualTo("张三"); +assertThat(crypto.decrypt(cipher)).isEqualTo("张三"); +assertThat(display.maskIdNum("330102199001011234")).contains("****"); +``` + +再补个人输出字段断言: + +```java +assertThat(fieldsClassText).contains("loanRateHistory"); +assertThat(fieldsClassText).contains("minRateProduct"); +assertThat(fieldsClassText).contains("smoothRange"); +assertThat(fieldsClassText).contains("finalCalculateRate"); +assertThat(fieldsClassText).contains("referenceRate"); +``` + +- [ ] **Step 2: 实现敏感字段服务** + +`SensitiveFieldCryptoService` 只做: + +```java +String encrypt(String plainText) +String decrypt(String cipherText) +``` + +`LoanPricingSensitiveDisplayService` 只做: + +```java +String maskName(String name) +String maskIdNum(String idNum) +void maskWorkflow(LoanPricingWorkflowVO vo) +``` + +- [ ] **Step 3: 接入流程创建、详情、列表、模型调用** + +在 `LoanPricingWorkflowServiceImpl` 中: + +```java +workflow.setCustName(cryptoService.encrypt(workflow.getCustName())); +workflow.setIdNum(cryptoService.encrypt(workflow.getIdNum())); +``` + +在返回前: + +```java +sensitiveDisplayService.maskWorkflow(vo); +``` + +在 `LoanPricingModelService` 调模型前: + +```java +invokeDTO.setCustName(cryptoService.decrypt(workflow.getCustName())); +invokeDTO.setIdNum(cryptoService.decrypt(workflow.getIdNum())); +``` + +- [ ] **Step 4: 补实体字段与详情组装** + +`ModelRetailOutputFields` 增加: + +```java +private BigDecimal loanRateHistory; +private BigDecimal minRateProduct; +private BigDecimal smoothRange; +private BigDecimal finalCalculateRate; +private BigDecimal referenceRate; +``` + +- [ ] **Step 5: 跑定向测试** + +Run: + +```bash +mvn -pl ruoyi-loan-pricing -Dtest=SensitiveFieldCryptoServiceTest,LoanPricingSensitiveDisplayServiceTest,ModelRetailOutputFieldsTest,LoanPricingModelServiceTest test +``` + +Expected: 以上测试通过。 + +- [ ] **Step 6: 提交** + +```bash +git add ruoyi-loan-pricing +git commit -m "补齐贷款定价敏感信息与详情字段" +``` + +### Task 4: 迁移登录密码传输与缓存监控后端行为 + +**Files:** +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java` +- Modify: `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java` +- Modify: `ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java` +- Modify: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java` +- Test: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysLoginControllerPasswordTransferTest.java` +- Test: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysRegisterControllerPasswordTransferTest.java` +- Test: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysProfileControllerPasswordTransferTest.java` +- Test: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/system/SysUserControllerPasswordTransferTest.java` +- Test: `ruoyi-admin/src/test/java/com/ruoyi/web/controller/monitor/CacheControllerTest.java` + +- [ ] **Step 1: 先写密码透传失败测试** + +每个测试至少断言控制器能接收透传后的密码字段: + +```java +assertEquals("plain-password", body.getPassword()); +``` + +或断言 controller 调 service 前已拿到预期值。 + +- [ ] **Step 2: 调整请求体与控制器** + +`LoginBody` / `RegisterBody` 保证可承接前端密码传输字段,控制器保持接口路径不变,只修正入参读取与传递行为。 + +- [ ] **Step 3: 校准缓存监控行为** + +按当前分支去 Redis 底座整合目标分支缓存监控效果,不回退到 Redis 实现。`CacheController` 只输出内存缓存统计所需字段。 + +- [ ] **Step 4: 跑 admin 定向测试** + +Run: + +```bash +mvn -pl ruoyi-admin -am -Dtest=SysLoginControllerPasswordTransferTest,SysRegisterControllerPasswordTransferTest,SysProfileControllerPasswordTransferTest,SysUserControllerPasswordTransferTest,CacheControllerTest test +``` + +Expected: 以上测试通过。 + +- [ ] **Step 5: 提交** + +```bash +git add ruoyi-admin ruoyi-common +git commit -m "迁移登录密码传输与缓存监控后端逻辑" +``` + +### Task 5: 迁移环境配置、脚本和 SQL 资产 + +**Files:** +- Modify: `ruoyi-admin/src/main/resources/application.yml` +- Create: `ruoyi-admin/src/main/resources/application-pro.yml` +- Create: `ruoyi-admin/src/main/resources/application-uat.yml` +- Modify: `bin/restart_java_backend.sh` +- Create: `bin/restart_java_backend_test.sh` +- Create: `bin/prod/deploy_from_package.sh` +- Create: `bin/prod/deploy_from_package_test.sh` +- Create: `bin/prod/deploy_release.sh` +- Create: `bin/prod/install_env.sh` +- Create: `bin/prod/restart_java.sh` +- Create: `bin/prod/restart_java_test.sh` +- Create: `deploy/nginx.conf` +- Create: `deploy/2026-03-31-local-nginx-java-install-manual.md` +- Create: `sql/loan_pricing_schema_20260328.sql` +- Create: `sql/loan_pricing_required_data_20260328.sql` +- Create: `sql/loan_pricing_prod_init_20260331.sql` +- Create: `sql/loan_pricing_menu.sql` +- Create: `sql/loan_pricing_workflow.sql` +- Create: `sql/model_retail.sql` +- Create: `sql/model_corp.sql` +- Create: `test_api/test_personal_create.http` +- Create: `test_api/test_personal_create.sh` +- Create: `test_api/test_corporate_create.http` +- Create: `test_api/test_corporate_create.sh` + +- [ ] **Step 1: 先校验当前文件缺失** + +Run: + +```bash +ls ruoyi-admin/src/main/resources/application-pro.yml bin/prod sql/loan_pricing_schema_20260328.sql test_api 2>/dev/null || true +``` + +Expected: 当前分支大部分路径不存在。 + +- [ ] **Step 2: 迁入配置与脚本骨架** + +先把文件原样引入,再逐个检查: + +- 端口 +- profile 名称 +- jar 名称 +- 目录路径 +- `ps -ef` / 端口识别逻辑 + +禁止直接照搬掉当前分支去 Redis 配置。 + +- [ ] **Step 3: 迁入 SQL 与 API 示例** + +SQL 必须覆盖: + +- 贷款定价表结构 +- 初始化基础数据 +- 菜单 +- 模型输出表字段补齐 + +测试脚本只作为联调辅助,不允许替代单元测试。 + +- [ ] **Step 4: 跑脚本与 SQL 静态自检** + +Run: + +```bash +bash -n bin/restart_java_backend.sh +bash -n bin/prod/deploy_from_package.sh +bash -n bin/prod/deploy_release.sh +``` + +Expected: Shell 语法检查通过。 + +- [ ] **Step 5: 提交** + +```bash +git add ruoyi-admin/src/main/resources bin deploy sql test_api +git commit -m "迁移部署脚本与贷款定价SQL资产" +``` + +### Task 6: 后端总验收与实施记录 + +**Files:** +- Modify: `doc/2026-04-15-全量迁移892-without-redis后端实施计划.md` +- Create: `doc/2026-04-15-全量迁移892-without-redis后端实施记录.md` + +- [ ] **Step 1: 运行后端回归测试** + +Run: + +```bash +mvn test +``` + +Expected: 全仓后端测试通过;若存在外部依赖导致个别测试不可跑,必须记录具体模块与原因。 + +- [ ] **Step 2: 运行后端启动验证** + +Run: + +```bash +mvn -pl ruoyi-admin -am spring-boot:run +``` + +Expected: 服务启动成功,贷款定价相关 Bean 可加载;验证后主动停止进程。 + +- [ ] **Step 3: 补实施记录** + +`doc/2026-04-15-全量迁移892-without-redis后端实施记录.md` 至少记录: + +- 实际迁入模块 +- 与目标分支不做原样复制的整合点 +- 测试命令与结果 +- 启动验证结果 + +- [ ] **Step 4: 提交** + +```bash +git add doc/2026-04-15-全量迁移892-without-redis后端实施计划.md doc/2026-04-15-全量迁移892-without-redis后端实施记录.md +git commit -m "补充全量迁移后端实施记录" +```