# MMS Mapping Layout And Config 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:** Rebuild the `mmsmapping` page into a two-phase ICD parsing and mapping generation workflow with a left-side file/result layout and a right-side configuration workspace driven by `DefaultCfg.txt`. **Architecture:** Keep the existing `getIcdMmsJson` API contract intact, but replace the raw JSON editor flow with a typed page container, a simplified left-top request panel, a left-bottom result panel, and a new right-side configuration panel. Use two utility modules to parse `DefaultCfg.txt`, generate a draft from `indexCandidates`, validate editable rows, and convert the draft back into `request.indexSelection`; validation relies on `vue-tsc`, `eslint`, and manual browser checks because this repo does not currently ship an automated frontend test runner. **Tech Stack:** Vue 3 ` ``` ```vue ``` - [ ] **Step 2: Keep the result panel focused on `mappingJson` and `problems` only** Update the header copy in `frontend/src/views/tools/mmsmapping/components/MappingResultPanel.vue`: ```vue

调试输出

左下只展示最近一次接口返回的 `mappingJson` 和 `problems`。

{{ responseStatusText }}
``` Keep the existing tab body structure, but do not reintroduce `icdDocument` or request JSON rendering. - [ ] **Step 3: Trim panel styles so the left-top card no longer reserves textarea space** Remove the obsolete request textarea blocks from `frontend/src/views/tools/mmsmapping/components/MappingRequestPanel.vue` and keep only these shared styles: ```scss .panel-content { display: flex; flex: 1; flex-direction: column; gap: 16px; min-height: 0; } .file-action-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 16px; } .file-select-row { display: flex; gap: 12px; align-items: center; min-width: 0; flex: 1; } ``` - [ ] **Step 4: Run lint on the two touched panel components** Run: ```powershell cd frontend npm run lint -- src/views/tools/mmsmapping/components/MappingRequestPanel.vue src/views/tools/mmsmapping/components/MappingResultPanel.vue ``` Expected: command exits with code `0` and no ESLint diagnostics for those files. - [ ] **Step 5: Commit the left-side panel refactor** Run: ```powershell git add frontend/src/views/tools/mmsmapping/components/MappingRequestPanel.vue frontend/src/views/tools/mmsmapping/components/MappingResultPanel.vue git commit -m "refactor: simplify mmsmapping side panels" ``` ### Task 3: Build The Right-Side Mapping Configuration Panel **Files:** - Create: `frontend/src/views/tools/mmsmapping/components/MappingConfigPanel.vue` - [ ] **Step 1: Create the component shell with typed props, emits, and immutable patch helpers** Create `frontend/src/views/tools/mmsmapping/components/MappingConfigPanel.vue` with this script scaffold: ```vue ``` - [ ] **Step 2: Add the right-top base form, template error banner, and generate action** Use this top section template in `MappingConfigPanel.vue`: ```vue ``` Then add the minimum styles needed to keep the panel scrollable: ```scss .config-panel { min-height: 0; } .candidate-report-list { display: grid; gap: 8px; margin-bottom: 16px; } .candidate-report-item { padding: 12px; border: 1px solid #dbe3f0; border-radius: 10px; background: #ffffff; } .draft-table { width: 100%; } ``` - [ ] **Step 4: Run type-check to validate the new configuration component** Run: ```powershell cd frontend npm run type-check ``` Expected: command exits with code `0`; if it fails only because `index.vue` is not wired yet, proceed directly to Task 4 before re-running. - [ ] **Step 5: Commit the new configuration panel** Run: ```powershell git add frontend/src/views/tools/mmsmapping/components/MappingConfigPanel.vue git commit -m "feat: add mmsmapping config panel" ``` ### Task 4: Rebuild `index.vue` Around Parse-And-Generate Flow **Files:** - Modify: `frontend/src/views/tools/mmsmapping/index.vue` - [ ] **Step 1: Replace raw JSON state with typed form, candidate, draft, and template-error state** In `frontend/src/views/tools/mmsmapping/index.vue`, replace `requestJsonText`, `defaultRequestPayload`, and the old JSON parsing helpers with this state block. Keep the existing `unwrapApiPayload`, `getErrorMessage`, `handleIcdFileChange`, `mappingJsonPreview`, `problemList`, and status-tag computed blocks, but rewire them to the new request flow: ```ts import { computed, ref } from 'vue' import { ElMessage } from 'element-plus' import type { ResultData } from '@/api/interface' import { getIcdMmsJsonApi } from '@/api/tools/mmsmapping' import type { MmsMapping } from '@/api/tools/mmsmapping/interface' import MappingRequestPanel from './components/MappingRequestPanel.vue' import MappingResultPanel from './components/MappingResultPanel.vue' import MappingConfigPanel from './components/MappingConfigPanel.vue' import { parseDefaultCfgTemplate } from './utils/defaultCfg' import { buildDraftGroups, buildIndexSelectionPayload, createBaseRequestPayload, validateDraftGroups } from './utils/mappingDraft' const selectedIcdFile = ref(null) const responsePayload = ref(null) const activeResultTab = ref<'mapping' | 'problem'>('mapping') const requestForm = ref({ version: '1.0', author: 'system' }) const parsedCandidates = ref([]) const configDraft = ref([]) const templateError = ref('') const defaultCfgTemplate = ref({ reportList: [] }) const isParsing = ref(false) const isGenerating = ref(false) const icdFileAccept = '.icd,.cid,.scd,.xml' try { defaultCfgTemplate.value = parseDefaultCfgTemplate() } catch { templateError.value = 'DefaultCfg.txt 解析失败,请检查模板内容' } const isSubmitting = computed(() => isParsing.value || isGenerating.value) const canGenerate = computed(() => Boolean(selectedIcdFile.value && configDraft.value.length && !templateError.value)) const selectedIcdFileName = computed(() => selectedIcdFile.value?.name || '') ``` - [ ] **Step 2: Add separate parse and generate handlers** Use these handlers in `index.vue`: ```ts const handleParseIcd = async () => { if (!selectedIcdFile.value) { ElMessage.warning('请先选择 ICD 文件') return } if (templateError.value) { ElMessage.error(templateError.value) return } isParsing.value = true responsePayload.value = null try { const response = await getIcdMmsJsonApi({ icdFile: selectedIcdFile.value, request: { ...createBaseRequestPayload(requestForm.value), indexSelection: [] } }) const payload = unwrapApiPayload(response) responsePayload.value = payload parsedCandidates.value = payload.indexCandidates || [] configDraft.value = buildDraftGroups(defaultCfgTemplate.value, parsedCandidates.value) activeResultTab.value = payload.mappingJson ? 'mapping' : 'problem' ElMessage.success(payload.message || 'ICD 解析完成') } catch (error) { responsePayload.value = null parsedCandidates.value = [] configDraft.value = [] ElMessage.error(getErrorMessage(error)) } finally { isParsing.value = false } } const handleGenerateMapping = async () => { if (!selectedIcdFile.value) { ElMessage.warning('请先选择 ICD 文件') return } const draftProblems = validateDraftGroups(configDraft.value) if (draftProblems.length) { ElMessage.warning(draftProblems[0]) responsePayload.value = { status: 'NEED_INDEX_SELECTION', message: '当前配置不完整,请继续修正', problems: draftProblems } activeResultTab.value = 'problem' return } isGenerating.value = true responsePayload.value = null try { const response = await getIcdMmsJsonApi({ icdFile: selectedIcdFile.value, request: { ...createBaseRequestPayload(requestForm.value), indexSelection: buildIndexSelectionPayload(configDraft.value) } }) const payload = unwrapApiPayload(response) responsePayload.value = payload activeResultTab.value = payload.mappingJson ? 'mapping' : 'problem' if (payload.status === 'FAILED') { ElMessage.error(payload.message || '映射生成失败') return } ElMessage.success(payload.message || '映射生成完成') } catch (error) { responsePayload.value = null ElMessage.error(getErrorMessage(error)) } finally { isGenerating.value = false } } const resetPage = () => { selectedIcdFile.value = null responsePayload.value = null parsedCandidates.value = [] configDraft.value = [] activeResultTab.value = 'mapping' requestForm.value = { version: '1.0', author: 'system' } } ``` - [ ] **Step 3: Rebuild the template and layout to left-stack the request/result panels and mount the new configuration panel** Replace the page template and layout styles in `index.vue` with: ```vue ``` ```scss .mms-mapping-layout { display: grid; grid-template-columns: minmax(320px, 0.9fr) minmax(0, 1.1fr); gap: 16px; width: 100%; height: 100%; overflow: hidden; } .left-panel-stack { display: grid; grid-template-rows: auto minmax(0, 1fr); gap: 16px; min-height: 0; } @media (max-width: 1280px) { .mms-mapping-layout { grid-template-columns: 1fr; } } ``` - [ ] **Step 4: Run lint and type-check on the full frontend after container integration** Run: ```powershell cd frontend npm run lint npm run type-check ``` Expected: both commands exit with code `0`; the lint step may rewrite formatting, so inspect the diff before committing. - [ ] **Step 5: Commit the new page flow** Run: ```powershell git add frontend/src/views/tools/mmsmapping/index.vue frontend/src/views/tools/mmsmapping/components/MappingRequestPanel.vue frontend/src/views/tools/mmsmapping/components/MappingResultPanel.vue frontend/src/views/tools/mmsmapping/components/MappingConfigPanel.vue frontend/src/views/tools/mmsmapping/utils/defaultCfg.ts frontend/src/views/tools/mmsmapping/utils/mappingDraft.ts frontend/src/api/tools/mmsmapping/interface/index.ts git commit -m "feat: rebuild mmsmapping page workflow" ``` ### Task 5: Verify The Two-Phase Workflow Manually **Files:** - Verify only: `frontend/src/views/tools/mmsmapping/index.vue` - Verify only: `frontend/src/views/tools/mmsmapping/components/MappingRequestPanel.vue` - Verify only: `frontend/src/views/tools/mmsmapping/components/MappingResultPanel.vue` - Verify only: `frontend/src/views/tools/mmsmapping/components/MappingConfigPanel.vue` - Verify only: `frontend/src/views/tools/mmsmapping/utils/defaultCfg.ts` - Verify only: `frontend/src/views/tools/mmsmapping/utils/mappingDraft.ts` - [ ] **Step 1: Run the full static verification suite one more time** Run: ```powershell cd frontend npm run lint npm run type-check ``` Expected: both commands exit with code `0`. - [ ] **Step 2: Start the frontend and open the MMS mapping route** Run: ```powershell cd frontend npm run dev ``` Expected: Vite starts successfully and prints a local URL. Open the page route that resolves to `/tools/mmsMapping`. - [ ] **Step 3: Verify the parse flow** Manual checklist: ```text 1. 进入页面后,左上仅看到文件选择、解析按钮和状态标签。 2. 选择一个合法 ICD 文件后,左上状态变为“待提交”或同类准备状态。 3. 点击“解析 ICD”后,右侧出现 version/author 表单、默认模板分组、候选辅助信息。 4. 左下不出现 icdDocument 树;只显示 mappingJson/problems 页签。 5. 若后端返回 NEED_INDEX_SELECTION,左下默认切到 problems。 ``` Expected: all five observations are true. - [ ] **Step 4: Verify repeated mapping generation without re-parsing** Manual checklist: ```text 1. 在右侧选择一个模板分组,补齐 reportName、dataSetName、lnInst。 2. 点击“生成映射”,确认左下显示新的 mappingJson 或新的 problems。 3. 不重新点击“解析 ICD”,直接修改右侧任意一行的 lnInst。 4. 再次点击“生成映射”,确认左下结果刷新为第二次生成结果。 5. 若第二次返回 NEED_INDEX_SELECTION 或 FAILED,右侧已编辑内容仍然保留。 ``` Expected: repeated generation works on the same parsed candidate set. - [ ] **Step 5: Verify reset and file replacement behavior** Manual checklist: ```text 1. 点击“清空”,确认左下结果、右侧草稿、当前候选缓存全部清空。 2. 重新选择另一个 ICD 文件,确认旧的候选和草稿不会继续显示。 3. 重新点击“解析 ICD”后,右侧根据新文件重新生成默认模板。 ``` Expected: reset and file replacement force a fresh parse cycle. ## Self-Review - Spec coverage: the tasks cover left-top simplification, left-bottom result-only output, right-side auto-generated template editing, hidden request defaults, repeated generation, candidate matching, template-parse failure handling, and lint/type-check/manual validation. - Placeholder scan: no `TODO`/`TBD`/“later” markers remain; every task includes exact file paths, code blocks, commands, and expected results. - Type consistency: the plan uses the same names throughout: `BaseRequestForm`, `DefaultCfgTemplate`, `MappingDraftGroup`, `parseDefaultCfgTemplate`, `buildDraftGroups`, `validateDraftGroups`, `buildIndexSelectionPayload`, and `createBaseRequestPayload`.