Files
ccdi/docs/plans/frontend/2026-03-24-project-archive-frontend-implementation.md

10 KiB
Raw Blame History

Project Archive Frontend Implementation Plan

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: 让项目管理列表中的“归档”按钮真正触发归档,并让已归档项目在详情页中无法点击“上传数据”“参数配置”页签。

Architecture: 前端复用现有 ruoyi-ui/src/api/ccdiProject.js 中已预留的归档接口,在列表页 index.vue 接入真实异步提交,并收敛 ArchiveConfirmDialog.vue 的超范围文案。详情页 detail.vue 负责归档态页签禁用和 URL 直达拦截,UploadData.vueParamConfig.vue 再补一层归档态禁用保护,确保页面状态和组件行为一致。

Tech Stack: Vue 2, Element UI, Axios request wrapper, Node, npm

前端验收清单

  • 列表页点击“归档”后会调用真实归档接口
  • 归档成功后关闭弹窗并刷新列表
  • 已归档项目在详情页中“上传数据”“参数配置”页签不可点击
  • 直接访问 ?tab=upload / ?tab=config 时会自动切到 overview
  • 归档确认弹窗不再出现删数据、生成 PDF、归档库等超需求文案

Task 1: 先锁定列表页归档动作与弹窗文案契约

Files:

  • Modify: ruoyi-ui/tests/unit/project-list-archive-flow.test.js

  • Modify: ruoyi-ui/src/views/ccdiProject/index.vue

  • Modify: ruoyi-ui/src/views/ccdiProject/components/ArchiveConfirmDialog.vue

  • Step 1: Write the failing source-based test

新增 ruoyi-ui/tests/unit/project-list-archive-flow.test.js,至少锁定以下行为:

assert(
  pageSource.includes("await archiveProject(data.projectId)"),
  "确认归档后应调用真实归档接口"
);

assert(
  pageSource.includes("this.$modal.msgSuccess(\"项目归档成功\")") ||
  pageSource.includes("this.$modal.msgSuccess('项目归档成功')"),
  "归档成功后应提示项目归档成功"
);

assert(
  !dialogSource.includes("自动生成项目报告PDF"),
  "归档弹窗不应保留超范围 PDF 文案"
);
  • Step 2: Run test to verify it fails

Run:

cd ruoyi-ui
node tests/unit/project-list-archive-flow.test.js

Expected:

  • FAIL

  • 原因是当前 handleConfirmArchive 仍然只有本地提示,弹窗还保留旧文案

  • Step 3: Implement the minimal list action and dialog cleanup

ruoyi-ui/src/views/ccdiProject/index.vue 中:

  1. @/api/ccdiProject 引入 archiveProject
  2. handleConfirmArchive(data) 改为真实异步提交:
async handleConfirmArchive(data) {
  try {
    await archiveProject(data.projectId)
    this.$modal.msgSuccess("项目归档成功")
    this.archiveDialogVisible = false
    this.currentArchiveProject = null
    this.getList()
  } catch (error) {
    const message = error && error.message ? error.message : "项目归档失败,请稍后重试"
    this.$modal.msgError(message)
  }
}

ArchiveConfirmDialog.vue 中:

  • 删除 deleteData

  • 删除“自动生成项目报告PDF”“归档库”“恢复”“同时删除数据”等文案和交互

  • 仅保留“确认后状态变更为已归档”的说明和 loading 提交态

  • Step 4: Run test to verify it passes

Run:

cd ruoyi-ui
node tests/unit/project-list-archive-flow.test.js

Expected:

  • PASS

  • Step 5: Commit

git add ruoyi-ui/src/views/ccdiProject/index.vue ruoyi-ui/src/views/ccdiProject/components/ArchiveConfirmDialog.vue ruoyi-ui/tests/unit/project-list-archive-flow.test.js
git commit -m "实现项目列表归档前端交互"

Task 2: 实现详情页签禁用与 URL 直达拦截

Files:

  • Modify: ruoyi-ui/src/views/ccdiProject/detail.vue

  • Modify: ruoyi-ui/tests/unit/project-detail-archive-tab-lock.test.js

  • Step 1: Write the failing detail-page test

新增 ruoyi-ui/tests/unit/project-detail-archive-tab-lock.test.js,锁定以下关键代码痕迹:

assert(
  source.includes('index="upload"') && source.includes(':disabled="isArchiveLockedTab(\'upload\')"'),
  "上传数据页签应支持归档态禁用"
);

assert(
  /initActiveTabFromRoute\(\)\s*\{[\s\S]*?this\.resolveAccessibleTab/.test(source),
  "详情页应在路由初始化时校正归档态不可访问页签"
);

assert(
  /handleMenuSelect\(index\)\s*\{[\s\S]*?if\s*\(this\.isArchiveLockedTab\(index\)\)\s*return/.test(source),
  "点击禁用页签时不应切换"
);
  • Step 2: Run test to verify it fails

Run:

cd ruoyi-ui
node tests/unit/project-detail-archive-tab-lock.test.js

Expected:

  • FAIL

  • 原因是当前详情页还没有归档态页签禁用逻辑

  • Step 3: Implement the minimal tab lock

ruoyi-ui/src/views/ccdiProject/detail.vue 中增加:

computed: {
  isProjectArchived() {
    return String(this.projectInfo.projectStatus) === "2";
  }
}

以及两个辅助方法:

isArchiveLockedTab(tab) {
  return this.isProjectArchived && ["upload", "config"].includes(tab);
},
resolveAccessibleTab(tab) {
  if (this.isArchiveLockedTab(tab)) {
    return "overview";
  }
  return tab;
}

并修改:

  • initActiveTabFromRoute():先取 tab再调用 resolveAccessibleTab(tab)

  • handleMenuSelect(index):若禁用则直接 return

  • 顶部两个 el-menu-item:加 :disabled="isArchiveLockedTab('upload')":disabled="isArchiveLockedTab('config')"

  • Step 4: Run tests to verify the tab lock passes

Run:

cd ruoyi-ui
node tests/unit/project-detail-archive-tab-lock.test.js
node tests/unit/project-detail-tagging-polling.test.js

Expected:

  • 两条测试都 PASS

  • 说明归档页签禁用未破坏现有打标轮询结构

  • Step 5: Commit

git add ruoyi-ui/src/views/ccdiProject/detail.vue ruoyi-ui/tests/unit/project-detail-archive-tab-lock.test.js
git commit -m "实现项目详情归档页签禁用"

Task 3: 给上传页和参数页补一层归档态保护

Files:

  • Modify: ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue

  • Modify: ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue

  • Modify: ruoyi-ui/tests/unit/upload-data-disabled-cards.test.js

  • Create: ruoyi-ui/tests/unit/project-archive-readonly-guard.test.js

  • Step 1: Extend the failing tests for archive guard

upload-data-disabled-cards.test.js 中补充归档态断言:

assert(
  /disabled:\s*this\.isProjectTagging\s*\|\|\s*this\.isProjectArchived/.test(source),
  "流水导入卡片应在项目已归档时同步置灰"
);

再新增 project-archive-readonly-guard.test.js 锁定:

assert(uploadSource.includes('return String(this.projectInfo.projectStatus) === "2"'));
assert(paramSource.includes('return String(this.projectInfo.projectStatus) === "2"'));
assert(paramSource.includes("已归档项目暂不可修改参数"));
  • Step 2: Run tests to verify they fail

Run:

cd ruoyi-ui
node tests/unit/upload-data-disabled-cards.test.js
node tests/unit/project-archive-readonly-guard.test.js

Expected:

  • FAIL

  • 原因是当前组件只处理“打标中”禁用

  • Step 3: Implement the minimal archived guard

UploadData.vue 中补充:

isProjectArchived() {
  return String(this.projectInfo.projectStatus) === "2";
}

并把以下禁用逻辑扩展为归档态也成立:

  • 顶部“拉取本行信息”“征信导入”
  • 流水上传卡片 disabled
  • 相关上传/拉取方法中的前置 return

ParamConfig.vue 中补充:

isProjectArchived() {
  return String(this.projectInfo.projectStatus) === "2";
}

并同步修改:

  • 顶部提示文案:归档态显示“已归档项目暂不可修改参数”

  • 输入框和保存按钮禁用条件改为 isProjectTagging || isProjectArchived

  • handleSaveAll() 中增加归档态前置拦截

  • Step 4: Run frontend regression tests

Run:

cd ruoyi-ui
node tests/unit/project-list-archive-flow.test.js
node tests/unit/project-detail-archive-tab-lock.test.js
node tests/unit/upload-data-disabled-cards.test.js
node tests/unit/project-archive-readonly-guard.test.js

Expected:

  • 全部 PASS

  • Step 5: Commit

git add ruoyi-ui/src/views/ccdiProject/components/detail/UploadData.vue ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue ruoyi-ui/tests/unit/upload-data-disabled-cards.test.js ruoyi-ui/tests/unit/project-archive-readonly-guard.test.js
git commit -m "补充项目归档前端只读保护"

Task 4: 沉淀前端实施与验证记录

Files:

  • Create: docs/tests/records/2026-03-24-project-archive-frontend-verification.md

  • Create: docs/reports/implementation/2026-03-24-project-archive-frontend-record.md

  • Step 1: Write the verification skeleton

验证记录至少包含:

# 项目归档前端验证记录

## 验证范围
- 列表归档按钮接入真实接口
- 归档确认弹窗文案已收敛
- 详情页上传数据与参数配置页签不可点击
- 归档态下上传页与参数页有组件级保护
  • Step 2: Record exact frontend test commands

把实际执行命令写入记录:

cd ruoyi-ui
node tests/unit/project-list-archive-flow.test.js
node tests/unit/project-detail-archive-tab-lock.test.js
node tests/unit/upload-data-disabled-cards.test.js
node tests/unit/project-archive-readonly-guard.test.js

Expected:

  • 记录通过结果,或失败原因

  • Step 3: Write the frontend implementation record

在实施记录中说明:

  • 为什么弹窗文案需要收敛

  • 为什么页签禁用和 URL 拦截需要同时做

  • 为什么组件级归档保护仍要保留

  • 本次前端改动覆盖了哪些文件与测试

  • Step 4: Commit

git add docs/tests/records/2026-03-24-project-archive-frontend-verification.md docs/reports/implementation/2026-03-24-project-archive-frontend-record.md
git commit -m "补充项目归档前端实施记录"