Procházet zdrojové kódy

docs: 制定问卷报告管理合并计划

Developer před 1 týdnem
rodič
revize
385ef98bf0

+ 236 - 0
docs/superpowers/plans/2026-08-30-questionnaire-report-merge.md

@@ -0,0 +1,236 @@
+# 问卷管理合并报告管理 Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 在 PC 端问卷管理页面内按问卷展开评估记录和报告列表,展示生成状态并支持预览、导出、发送和重新生成。
+
+**Architecture:** 以现有 `questionnaireList.vue` 为主页面,通过 Element UI 表格展开行承载该问卷的团队评估记录;每条评估记录复用 `reportList` 组件展示报告和操作。继续复用现有 API,报告生成使用 DeerFlow `genReport` 接口;旧报告路由保留,菜单入口不通过数据库迁移修改。
+
+**Tech Stack:** Vue 2.7、Vue Router、Element UI、Jest、Vue CLI。
+
+**Spec:** `docs/superpowers/specs/2026-08-30-questionnaire-report-merge-design.md`
+
+## Global Constraints
+
+- 以问卷管理为主入口。
+- 不改变小程序端、报告生成协议和数据库结构。
+- 报告生成必须使用 `/core/team/questionnaire/genReport/{teamQuestionnaireId}`。
+- 复用现有报告预览、导出、发送、删除和重新生成权限逻辑。
+- 旧报告管理路由保持可访问。
+
+---
+
+### Task 1: Define the questionnaire/report expansion contract
+
+**Files:**
+- Create: `tests/unit/questionnaireReportMerge.spec.js`
+- Modify: `src/views/modules/agent/questionnaireList.vue`
+
+**Interfaces:**
+- Produces the page-level behaviors `toggleReportList(row)`, `loadReportEntries(row)`, and `refreshReportEntry(index)`.
+- The questionnaire row stores `reportExpanded` and `reportEntries`; each report entry has the existing team-questionnaire fields plus `showMore` and `reportList`.
+
+- [ ] **Step 1: Write the failing test**
+
+Add source-level regression assertions that the questionnaire page imports team questionnaire/report APIs, renders a `报告列表` action and an expandable report section, and does not rely on the old report-page-only questionnaire selector:
+
+```js
+const fs = require('fs')
+const path = require('path')
+
+const source = fs.readFileSync(
+  path.resolve(__dirname, '../../src/views/modules/agent/questionnaireList.vue'),
+  'utf8'
+)
+
+test('questionnaire management exposes an inline report list action', () => {
+  expect(source).toContain('报告列表')
+  expect(source).toContain('getTeamQuestionnaireList')
+  expect(source).toContain('getTeamReportWjList')
+  expect(source).toContain('reportList')
+  expect(source).toContain('reportExpanded')
+})
+```
+
+- [ ] **Step 2: Run test to verify it fails**
+
+Run: `npm test -- --runInBand tests/unit/questionnaireReportMerge.spec.js --silent`
+
+Expected: FAIL because `questionnaireList.vue` currently has no report action or report APIs.
+
+- [ ] **Step 3: Write the minimal page contract**
+
+Add the report API imports, a `reportList` component import, a `报告列表` button in the existing operation column, and an Element UI `type="expand"` column whose content renders one `reportList` component per loaded team questionnaire entry. Add row state initialization:
+
+```js
+const prepareQuestionnaireRow = row => ({
+  ...row,
+  reportExpanded: false,
+  reportEntries: [],
+  reportLoading: false
+})
+
+const dataList = ref([])
+
+const toggleReportList = async row => {
+  row.reportExpanded = !row.reportExpanded
+  if (row.reportExpanded && row.reportEntries.length === 0) {
+    await loadReportEntries(row)
+  }
+}
+```
+
+Use `getTeamQuestionnaireList({ page: 1, limit: 100, questionnaireId: row.id })` to load all matching evaluation records for the selected template and map each entry to `{ ...entry, showMore: false, reportList: [] }`.
+
+- [ ] **Step 4: Run test to verify it passes**
+
+Run: `npm test -- --runInBand tests/unit/questionnaireReportMerge.spec.js --silent`
+
+Expected: PASS.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add tests/unit/questionnaireReportMerge.spec.js src/views/modules/agent/questionnaireList.vue
+git commit -m "feat: 在问卷管理中增加报告列表入口"
+```
+
+### Task 2: Connect report status, preview, and report operations
+
+**Files:**
+- Modify: `src/views/modules/agent/questionnaireList.vue`
+- Modify: `src/components/reportList/index.vue` only if an event/prop compatibility fix is required
+- Test: `tests/unit/questionnaireReportMerge.spec.js`
+
+**Interfaces:**
+- Consumes: `getTeamReportWjList(relationId)`, `deleteTeamReportWj`, `sendReportUsers`, and `reCreateReport` from `src/api/agent/index.js`.
+- Produces: expanded report records whose state is rendered by the existing `reportList` status mapping and whose preview/export actions use existing report artifact fields.
+
+- [ ] **Step 1: Extend the failing test**
+
+Add assertions that the page wires report-list events and invokes the current DeerFlow generation helper rather than the legacy endpoint:
+
+```js
+test('expanded questionnaire reports retain report operations and current generation endpoint', () => {
+  const apiSource = fs.readFileSync(
+    path.resolve(__dirname, '../../src/api/agent/index.js'),
+    'utf8'
+  )
+  expect(source).toContain('@toggleReport')
+  expect(source).toContain('@reCreateReport')
+  expect(source).toContain('@refreshReportList')
+  expect(apiSource).toContain('/core/team/questionnaire/genReport/${teamQuestionnaireId}')
+})
+```
+
+- [ ] **Step 2: Run test to verify it fails**
+
+Run: `npm test -- --runInBand tests/unit/questionnaireReportMerge.spec.js --silent`
+
+Expected: FAIL because the page does not yet wire the report component events or report refresh behavior.
+
+- [ ] **Step 3: Implement the report event handlers**
+
+Add page handlers matching the existing report page behavior:
+
+```js
+const toggleReportEntry = (entry, index) => {
+  entry.showMore = !entry.showMore
+  if (entry.showMore) {
+    getTeamReportWjList(entry.id).then(res => {
+      if (res.code !== 0) return proxy.$message.error(res.msg)
+      entry.reportList = res.data || []
+    })
+  } else {
+    entry.reportList = []
+  }
+}
+
+const refreshReportEntry = entry => {
+  getTeamReportWjList(entry.id).then(res => {
+    if (res.code !== 0) return proxy.$message.error(res.msg)
+    entry.reportList = res.data || []
+  })
+}
+```
+
+Wire `deleteReport`, `sendReport`, `reCreateReport`, and `refreshReportList` to the same existing API methods and permissions used by `report.vue`. Keep preview and export inside `reportList/index.vue`; do not duplicate PDF modal code in the questionnaire page. Ensure the generation operation remains the already-fixed `genReportById` helper.
+
+- [ ] **Step 4: Run test to verify it passes**
+
+Run: `npm test -- --runInBand tests/unit/questionnaireReportMerge.spec.js --silent`
+
+Expected: PASS.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add tests/unit/questionnaireReportMerge.spec.js src/views/modules/agent/questionnaireList.vue src/components/reportList/index.vue
+git commit -m "feat: 在问卷页展示报告状态和操作"
+```
+
+### Task 3: Preserve navigation compatibility and verify the integrated page
+
+**Files:**
+- Modify: `src/views/modules/home.vue` if the homepage report shortcut must point to the merged questionnaire page
+- Modify: `src/views/modules/agent/report.vue` only if its legacy route requires a compatibility redirect
+- Modify: `tests/unit/questionnaireReportMerge.spec.js`
+
+**Interfaces:**
+- Consumes: existing dynamic menu and static route behavior.
+- Produces: old report links remain valid while new primary navigation lands on questionnaire management.
+
+- [ ] **Step 1: Write the failing compatibility test**
+
+Add assertions for the chosen compatibility behavior:
+
+```js
+test('homepage report shortcut points to the questionnaire management entry', () => {
+  const homeSource = fs.readFileSync(
+    path.resolve(__dirname, '../../src/views/modules/home.vue'),
+    'utf8'
+  )
+  expect(homeSource).toContain("toTurn('agent-questionnaire')")
+  expect(homeSource).not.toContain("toTurn('agent-report')")
+})
+```
+
+- [ ] **Step 2: Run test to verify it fails**
+
+Run: `npm test -- --runInBand tests/unit/questionnaireReportMerge.spec.js --silent`
+
+Expected: FAIL because the homepage still has a “更多报告” shortcut that targets the standalone report page.
+
+- [ ] **Step 3: Implement compatibility behavior**
+
+Keep `/agent-report` available for existing links. Update only new homepage navigation if required; do not delete the legacy report component or alter backend menu records. If dynamic menu configuration still exposes “报告管理”, its page remains functional while “问卷管理” becomes the primary merged entry.
+
+- [ ] **Step 4: Run the full verification suite**
+
+Run:
+
+```bash
+npm test -- --runInBand --silent
+npm run build
+```
+
+Expected: all unit suites pass and Vue CLI reports `Build complete` with exit code 0.
+
+- [ ] **Step 5: Inspect the final diff**
+
+Run:
+
+```bash
+git diff --check
+git status --short
+git diff --stat HEAD~3..HEAD
+```
+
+Confirm only the questionnaire/report merge files and plan/spec documents changed; do not stage `node_modules`, unrelated worktree files, or generated files unless deployment is separately requested.
+
+- [ ] **Step 6: Commit**
+
+```bash
+git add src/views/modules/home.vue src/views/modules/agent/report.vue tests/unit/questionnaireReportMerge.spec.js
+git commit -m "test: 验证问卷报告管理合并"
+```