Files
ccdi/docs/plans/frontend/2026-03-29-project-import-history-frontend-implementation.md

11 KiB

Project Import History 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: 前端在现有 ccdiProject 列表与详情页结构上最小化改造,重点落在 ImportHistoryDialog.vueindex.vueccdiProject.jsUploadData.vueuploadFileActionRules.js。弹窗负责表单校验、历史项目查询、多选和真实提交;列表页负责成功后跳转;详情页上传记录区域负责展示历史导入来源并收敛删除操作。

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

前端验收清单

  • 导入历史项目弹窗采用“新项目配置在上、历史项目列表在下”的纵向布局
  • 历史项目支持多选,且只展示后端返回的真实历史项目数据
  • 提交成功后关闭弹窗、提示任务已开始并跳转到新项目详情页
  • 上传记录列表能展示“历史导入 · 来源项目名”
  • 历史导入文件记录不显示删除入口

Task 1: 先锁定 API 层与列表页提交后的跳转契约

Files:

  • Modify: ruoyi-ui/src/api/ccdiProject.js

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

  • Modify: ruoyi-ui/tests/unit/project-list-reanalyze-api.test.js

  • Create: ruoyi-ui/tests/unit/project-import-history-submit-flow.test.js

  • Step 1: Write the failing source-based test

新增 project-import-history-submit-flow.test.js,至少锁定以下代码痕迹:

assert(apiSource.includes("url: '/ccdi/project/history'"));
assert(apiSource.includes("url: '/ccdi/project/import'"));
assert(indexSource.includes("this.$router.push({"));
assert(indexSource.includes("path: `/ccdiProject/detail/${project.projectId}`") || indexSource.includes("path: `/ccdiProject/detail/${data.projectId}`"));

并锁定成功提示文案包含“历史项目导入任务已开始”。

  • Step 2: Run test to verify it fails

Run:

cd ruoyi-ui
node tests/unit/project-import-history-submit-flow.test.js

Expected:

  • FAIL

  • 原因是当前列表页提交导入后只本地提示成功,没有跳转详情页

  • Step 3: Implement the minimal API and jump logic

ruoyi-ui/src/api/ccdiProject.js 保留并改用真实接口:

export function listHistoryProjects(query) { ... }
export function importFromHistory(data) { ... }

index.vue 中将 handleSubmitImport(data) 收敛为:

handleSubmitImport(project) {
  this.$modal.msgSuccess("历史项目导入任务已开始");
  this.importDialogVisible = false;
  this.getList();
  this.$router.push({ path: `/ccdiProject/detail/${project.projectId}` });
}
  • Step 4: Run test to verify it passes

Run:

cd ruoyi-ui
node tests/unit/project-import-history-submit-flow.test.js

Expected:

  • PASS

  • Step 5: Commit

git add ruoyi-ui/src/api/ccdiProject.js ruoyi-ui/src/views/ccdiProject/index.vue ruoyi-ui/tests/unit/project-import-history-submit-flow.test.js
git commit -m "接通历史项目导入前端提交链路"

Task 2: 重写导入弹窗为真实纵向表单与多选列表

Files:

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

  • Create: ruoyi-ui/tests/unit/project-import-history-dialog-layout.test.js

  • Create: ruoyi-ui/tests/unit/project-import-history-dialog-behavior.test.js

  • Step 1: Write the failing layout/behavior tests

在布局测试中锁定:

assert(source.includes('label="新项目名称"'));
assert(source.includes('label="备注"'));
assert(source.includes("type=\"daterange\""));
assert(source.includes("data-multiselect") === false); // Vue 模板里应改成 checkbox/multiple 语义,而不是单选 radio
assert(source.includes("selectedProjectIds"));

在行为测试中锁定:

assert(source.includes("listHistoryProjects("));
assert(source.includes("importFromHistory("));
assert(source.includes("this.$emit('submit', response.data)"));
  • Step 2: Run tests to verify they fail

Run:

cd ruoyi-ui
node tests/unit/project-import-history-dialog-layout.test.js
node tests/unit/project-import-history-dialog-behavior.test.js

Expected:

  • FAIL

  • 原因是当前弹窗还是单选、Mock 数据、上下字段不对

  • Step 3: Implement the minimal vertical dialog

ImportHistoryDialog.vue 中完成以下最小改造:

  • 新项目配置区放上方:
    • newProjectName
    • description
    • dateRange
  • 历史项目列表区放下方:
    • 搜索框
    • 多选项目列表,状态只读展示
    • 固定高度滚动
  • 数据改为:
selectedProjectIds: [],
configForm: {
  newProjectName: "",
  description: "",
  dateRange: []
}

提交时组装:

const payload = {
  projectName: this.configForm.newProjectName,
  description: this.configForm.description,
  sourceProjectIds: this.selectedProjectIds,
  startDate: this.configForm.dateRange[0] || "",
  endDate: this.configForm.dateRange[1] || ""
};
  • Step 4: Run tests to verify they pass

Run:

cd ruoyi-ui
node tests/unit/project-import-history-dialog-layout.test.js
node tests/unit/project-import-history-dialog-behavior.test.js

Expected:

  • PASS

  • Step 5: Commit

git add ruoyi-ui/src/views/ccdiProject/components/ImportHistoryDialog.vue ruoyi-ui/tests/unit/project-import-history-dialog-layout.test.js ruoyi-ui/tests/unit/project-import-history-dialog-behavior.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/uploadFileActionRules.js

  • Modify: ruoyi-ui/tests/unit/upload-data-file-list-table.test.js

  • Modify: ruoyi-ui/tests/unit/upload-data-delete-retag-copy.test.js

  • Create: ruoyi-ui/tests/unit/upload-data-history-import-readonly.test.js

  • Step 1: Write the failing file-list tests

新增或补充断言:

assert(uploadSource.includes("sourceProjectName"));
assert(uploadSource.includes("历史导入"));
assert(actionRuleSource.includes("HISTORY_IMPORT"));
assert(!deleteBehaviorAllowsHistoryImport);

其中 upload-data-history-import-readonly.test.js 至少锁定:

assert(/if\s*\(row\.sourceType\s*===\s*["']HISTORY_IMPORT["']\)\s*\{\s*return null/.test(actionRuleSource));
  • Step 2: Run tests to verify they fail

Run:

cd ruoyi-ui
node tests/unit/upload-data-file-list-table.test.js
node tests/unit/upload-data-delete-retag-copy.test.js
node tests/unit/upload-data-history-import-readonly.test.js

Expected:

  • FAIL

  • Step 3: Implement the minimal readonly display

UploadData.vue 的表格中增加来源展示,例如:

<el-table-column prop="sourceProjectName" label="来源" min-width="180">
  <template slot-scope="scope">
    <span v-if="scope.row.sourceType === 'HISTORY_IMPORT'">
      历史导入 · {{ scope.row.sourceProjectName || '-' }}
    </span>
    <span v-else>-</span>
  </template>
</el-table-column>

uploadFileActionRules.js 中收敛删除规则:

if (row.sourceType === 'HISTORY_IMPORT') {
  return null
}
  • Step 4: Run tests to verify they pass

Run:

cd ruoyi-ui
node tests/unit/upload-data-file-list-table.test.js
node tests/unit/upload-data-delete-retag-copy.test.js
node tests/unit/upload-data-history-import-readonly.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/uploadFileActionRules.js ruoyi-ui/tests/unit/upload-data-file-list-table.test.js ruoyi-ui/tests/unit/upload-data-delete-retag-copy.test.js ruoyi-ui/tests/unit/upload-data-history-import-readonly.test.js
git commit -m "收敛历史导入文件前端只读展示"

Task 4: 收口弹窗校验、详情页衔接与回归验证

Files:

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

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

  • Modify: ruoyi-ui/tests/unit/project-detail-tagging-polling.test.js

  • Modify: docs/reports/implementation/2026-03-29-project-import-history-plan-record.md

  • Step 1: Write the failing validation/regression assertions

在弹窗行为测试里补充:

assert(source.includes("请选择历史项目"));
assert(source.includes("请输入新项目名称"));

project-detail-tagging-polling.test.js 中锁定:

assert(detailSource.includes("this.$route.params.projectId"));
assert(detailSource.includes("projectStatusPolling"));

目的是保证本次跳转详情页不会破坏现有轮询结构。

  • Step 2: Run tests to verify they fail or cover the gap

Run:

cd ruoyi-ui
node tests/unit/project-import-history-dialog-behavior.test.js
node tests/unit/project-detail-tagging-polling.test.js

Expected:

  • 历史导入弹窗测试先 FAIL

  • 轮询测试保持 PASS 或在改动后回归通过

  • Step 3: Implement the minimal validation and handoff polish

ImportHistoryDialog.vue 中补充:

  • 新项目名称必填
  • 至少选择一个历史项目
  • 提交态 loading
  • 成功后 reset 表单

detail.vue 中不新增新逻辑,只确保项目详情页跳转入口沿用现有 projectId 路由参数与状态轮询。

  • Step 4: Run the frontend regression set

Run:

cd ruoyi-ui
node tests/unit/project-import-history-submit-flow.test.js
node tests/unit/project-import-history-dialog-layout.test.js
node tests/unit/project-import-history-dialog-behavior.test.js
node tests/unit/upload-data-file-list-table.test.js
node tests/unit/upload-data-delete-retag-copy.test.js
node tests/unit/upload-data-history-import-readonly.test.js
node tests/unit/project-detail-tagging-polling.test.js

Expected:

  • 全部 PASS

  • Step 5: Commit

git add ruoyi-ui/src/views/ccdiProject/components/ImportHistoryDialog.vue ruoyi-ui/src/views/ccdiProject/detail.vue ruoyi-ui/tests/unit/project-import-history-submit-flow.test.js ruoyi-ui/tests/unit/project-import-history-dialog-layout.test.js ruoyi-ui/tests/unit/project-import-history-dialog-behavior.test.js ruoyi-ui/tests/unit/upload-data-history-import-readonly.test.js docs/reports/implementation/2026-03-29-project-import-history-plan-record.md
git commit -m "完成历史项目导入前端闭环"