Files
workspace/code/fms/.codebuddy/plans/module-management-v2-refactor_c50f14c4.md
2026-09-11 17:31:34 +08:00

16 KiB
Raw Permalink Blame History

name, overview, todos
name overview todos
module-management-v2-refactor 将 fms-vue 的 module-management 从旧表结构(category/data/query、s_field_group/s_field_view/s_field_edit/s_field_query 行模型、s_i18n 带 b_id/b_module_id)重构为《FMS新系统核心表结构设计》V2:模块类型 module/data/virtual + 模块树 b_depth/b_path,布局统一存 s_module_schema(view/edit/query) 的 b_schema_json JSON 节点,s_field 精简为 b_source_field/b_type,i18n 主键改 (b_key,b_locale),并同步更新 menu-management 的模块类型过滤。
id content status
rewrite-utils 重写 module-management/utils.js:模块类型映射、view/edit/query JSON 默认结构与 stableStringify、受管 i18n 键、树 b_depth/b_path 计算;同步改 menu-management 类型过滤 completed
id content status dependencies
refactor-orchestrator 重构 index.vue 编排层:maindata/fields/view_schema/edit_schema/query_schema/autocode/i18n 成对基线与加载/校验/diff 保存/重载、树增删移与 b_depth/b_path、按新键删除清理 completed
rewrite-utils
id content status dependencies
refactor-basic 重构 ModuleBasicPanel:新类型 module/data/virtual 与新 s_module 列及类型联动校验 completed
refactor-orchestrator
id content status dependencies
refactor-fields 重构 ModuleFieldsPanel:新 s_field 列、同步字段写 b_source_field、参与勾选改为 JSON 节点增删 completed
refactor-orchestrator
id content status dependencies
rewrite-editor-kernel 用 [subagent:code-explorer] 梳理设计器依赖后,重写 useStructureEditing 与 fieldDefaults 为 JSON 节点模型内核 completed
rewrite-utils
id content status dependencies
rewrite-editors 重写 TableDesignEditor/FormDesignEditor 及子组件消费产出 view/edit JSON,并更新 ModuleListConfigPanel/ModuleEditPanel completed
rewrite-editor-kernel
id content status dependencies
refactor-query-i18n 重构 ModuleQueryConfigPanel 为 query JSON,重构 ModuleI18nPanel 与 i18n 工具为 (b_key,b_locale) 复合键 completed
refactor-orchestrator
id content status dependencies
update-tests 用 [skill:lsp-code-analysis] 全局核对引用,更新受影响单测并运行 pnpm test/lint/build completed
rewrite-editors
refactor-fields
refactor-query-i18n

产品概述

模块管理页(左树右面板)与 V2 表结构(FMS新系统核心表结构设计.md + sql/fms_core.sql)对齐,并把 开发规范.md 的面板式配置页约定落实到编排层与各面板。界面外观与既有交互(树搜索/右键/拖拽、分节 Tab、字段表格、列表/表单设计器的拖拽与预览、查询条件表、自动编码预览、多语言透视表)保持不变,仅调整底层数据模型、加载与保存逻辑。

用户需求

  • 按 V2 重构 fms-vue/src/views/module/module-management/ 全部代码。
  • 布局配置完整迁移为 JSON:列表/表单/查询分别存 s_module_schema 的 view/edit/query 三行 b_schema_json,字段分组由独立表变为 JSON 节点。
  • 模块类型改为 module / data / virtual(category→module、query→virtual、data 不变),新增/移动节点时维护模块树 b_depth / b_path。
  • 同步更新 menu-management 中对模块类型的过滤条件。
  • 不新增 s_relation 面板。

核心功能

  • 模块树:加载/搜索/展开/右键新增/删除/拖拽排序;节点承载 b_depth、b_path,并随新增与移动同步维护。
  • 基础信息:维护新 s_module 列(b_view_table/b_save_table/b_key_field/b_order_sql/b_query_sql/b_config_json 等)与类型联动校验。
  • 字段定义:维护新 s_field(b_source_field/b_name/b_i18n/b_type/b_canuse/b_xh);按查询表/视图同步字段;表单/列表/查询“参与”勾选改为在对应 JSON 中增删字段节点。
  • 界面配置:列表(view JSON,支持分组列/多级表头)、表单(edit JSON,分组+行+字段、栅格/只读/必填)、查询(query JSON,quick + 条件组)。
  • 自动编码:单条 s_autocode 规则与实时预览(列名已与 V2 一致)。
  • 多语言:基于 s_i18n 的 (b_key, b_locale) 复合键维护受管资源键与翻译。
  • 保存:handleSave → beforeSave → buildSaveData → 通用保存接口 → afterSave,按 _org 基线 diff,无变化不提交;切换模块保留未保存确认。

技术栈

  • 前端:Vue 3(Composition API + <script setup> + defineModel),JavaScript(沿用项目现有 .vue/.js,不引入 TS)。
  • UI:项目内 @/components/ui(Tabs/Splitter/Modal/Form/FmsTable 等)与 @/components/fms-table/FmsTable.vue。
  • 数据访问:@/services/api(loadDataApi / saveObjectApi / describeApi)——写库走 {table, key_field|keyFields, inserts, updates, deletes}。
  • 变更工具:@/utils/dataChanges(diffRows/diffRow/tableChange/hasChanges/sanitizeSaveReqs/stripInternalKeys)与 @/utils/tree(buildTree/sortTree/findTreeNode/insertTreeNode/removeTreeNode)。
  • 依赖:多语言语言清单来自 @/stores/i18n(s_i18n_type)。

实现方案

核心决策

  1. JSON 节点模型 + 保留未知属性:view/edit/query 以对象形式在编排层持有;面板原地修改已知节点,序列化时保留其余属性(符合规范 1.8「JSON 可扩展新属性」)。顶层带 schemaVersion: 1。
  2. 稳定序列化 + 基线比对防“打开即脏”:新增 stableStringify(对象键递归排序、数组保序)。加载时把库中字符串与新 schema 的默认结构都规范化为基线字符串;保存时用对象序列化结果与基线字符串比较,一致则不插入默认行。
  3. 配置表用业务键/联合主键,不用雪花临时 ID:s_field 用 (b_module_id,b_field);s_module_schema 用 (b_module_id,b_schema_type);s_autocode 用 (b_module_id,b_field);s_i18n 用 (b_key,b_locale)。diffRows 传对应 keyFields,deletes 仅带主键列。
  4. 模块树层级维护:b_parent_id 为权威关系,前端新增/移动时按「父路径 + 节点编码」计算 b_path(形如 /sea/container/,根为 /sea/,b_depth 根为 0),并同步更新受影响节点及其后代。
  5. 多语言按资源键前缀加载/清理:s_i18n 无 b_module_id,模块的多语言行按资源键匹配加载(b_key = 'module.{id}' 或 b_key LIKE 'field.{id}.%',分组键取 JSON 节点中的 i18n 精确值);删除模块时按这些已知键清理。
  6. 编辑方式切换的处理:V2 已移除 s_module.b_edit_mode 且本次不引入 s_relation,故表单设计只面向 edit JSON(保留画布/分组/预览交互),移除依赖 b_edit_mode 的“主表表单/子表表格”切换。

数据流

graph LR
  API[loadDataApi] --> ORCH[index.vue 编排层]
  ORCH -->|v-model| BASIC[ModuleBasicPanel]
  ORCH -->|v-model fields| FIELDS[ModuleFieldsPanel]
  ORCH -->|v-model view_schema| LIST[ModuleListConfigPanel -> TableDesignEditor]
  ORCH -->|v-model edit_schema| EDIT[ModuleEditPanel -> FormDesignEditor]
  ORCH -->|v-model query_schema| QUERY[ModuleQueryConfigPanel]
  ORCH -->|v-model autocode| AUTO[ModuleAutoCodePanel]
  ORCH -->|v-model i18n| I18N[ModuleI18nPanel]
  ORCH -->|watch 幂等联动| FIELDS
  ORCH -->|diff + saveObjectApi| API

性能与可靠性

  • 加载时按模块只解析一次 JSON;保存时 stableStringify 为 O(n)(n 为节点/字段数),无深层递归热路径。
  • 树 b_depth/b_path 重算仅在新增/移动的子树范围进行,避免全树反复遍历。
  • 保存失败不改写 _org 基线,afterSave 成功后重新加载为准。

实施要点

  • 数据成对命名:maindata/maindata_org、fields/fields_org、view_schema/view_schema_org、edit_schema/edit_schema_org、query_schema/query_schema_org、autocode/autocode_org、i18n/i18n_org;禁止 drafts/originals 聚合对象。
  • 就绪判据统一 v-if="maindata";整批清空收敛到 clearModuleData()。
  • 跨面板副作用由编排层幂等 watch 承担(删除分组清理 JSON 中分组引用;自动编码字段在表单 JSON 中置只读)。
  • 表格/节点编辑采用“就地 patch + 提交换新引用”触发重渲染。
  • _/v_ 前缀内部派生字段不参与 diff,提交前经 sanitizeSaveReqs 统一剥离。
  • 多语言不做实时响应:加载后 reconcile 一次、保存前再 reconcile 一次;人工翻译不被覆盖。
  • 面板范围:基础信息对所有类型;字段/列表/表单/查询对 data 与 virtual;自动编码仅 data;多语言对所有类型。
  • 影响面提示(本次不修改):components/fms-module-list/FmsModuleListPage.vue、components/fms-module-edit/FmsModuleEditModal.vue 仍读取旧列/旧布局表,需另立任务迁移到 V2,避免超范围改动。

关键结构

三份 schema(顶层均含 schemaVersion,通过字段编码引用 s_field,不重复定义数据库类型):

// view
{ "schemaVersion": 1, "columns": [
  { "field": "b_no", "visible": true, "width": 140, "fixed": "left" },
  { "type": "group", "title": "费用信息", "i18n": "group.cw_fee.amount",
    "children": [ { "field": "mx_amount", "width": 120, "format": "money" } ] } ] }

// edit
{ "schemaVersion": 1, "children": [
  { "type": "group", "title": "基础信息", "i18n": "group.sea_main.basic", "children": [
    { "type": "row", "children": [
      { "field": "b_no", "span": 12, "readonly": true },
      { "field": "b_name", "span": 12, "required": true } ] } ] } ] }

// query
{ "schemaVersion": 1, "quick": ["b_no", "b_name"], "groups": [
  { "logic": "and", "conditions": [ { "field": "b_status", "operator": "eq" } ] } ] }

s_module_schema 保存契约(按联合主键 diff;无变化不提交;不发送审计列):

// 行身份:b_module_id + b_schema_type(view|edit|query)
// 比较值:b_schema_json = stableStringify(草稿对象),基线为库中原串(或缺省 schema)规范化后的串
{ table: 's_module_schema', key_field: 'b_module_id,b_schema_type',
  inserts|updates: [ { b_module_id, b_schema_type, b_schema_json, b_canuse } ] }

目录结构

本次重构涉及 fms-vue/src/views/module/module-management/ 与受影响测试;结构沿用现有目录,不新增无意义层级。

fms-vue/
├── src/
│   ├── views/module/
│   │   ├── module-management/
│   │   │   ├── index.vue                        # [MODIFY] 编排层:持有 maindata/fields/view_schema/edit_schema/query_schema/autocode/i18n 及各自 _org 基线;load→validate→diff 保存→重载主流程;模块树加载/新增/删除/拖拽与 b_depth/b_path 维护;s_module_schema 三行加载与保存;按新表名与新资源键清理删除;跨面板幂等 watch
│   │   │   ├── utils.js                         # [MODIFY] 纯函数:模块类型映射与图标/新增项、view/edit/query 默认结构、parseSchema、stableStringify、字段节点增删与查找、受管 i18n 键规则与 reconcile、i18n 变更请求((b_key,b_locale))、树 b_depth/b_path 计算与兄弟重排
│   │   │   ├── ModuleTreePanel.vue              # [MODIFY] 消费新类型图标/新增项;保留搜索/展开/右键/拖拽交互;未保存节点禁用作为父级
│   │   │   ├── ModuleBasicPanel.vue             # [MODIFY] 新类型 module/data/virtual 与新列(b_view_table/b_save_table/b_key_field/b_order_sql/b_query_sql/b_config_json);类型联动清空与校验
│   │   │   ├── ModuleFieldsPanel.vue            # [MODIFY] 新 s_field 列(b_field/b_source_field/b_name/b_type/b_i18n/b_canuse/b_xh);describeApi 同步字段写 b_source_field、列序回写 b_xh、库中已删列标记 b_canuse=0;参与勾选改为在 view/edit/query JSON 增删字段节点
│   │   │   ├── ModuleListConfigPanel.vue        # [MODIFY] 壳:接收 view_schema 对象,接线 TableDesignEditor(mode=list)
│   │   │   ├── ModuleEditPanel.vue              # [MODIFY] 壳:接收 edit_schema 对象,接线 FormDesignEditor(移除 b_edit_mode 切换)
│   │   │   ├── ModuleQueryConfigPanel.vue       # [MODIFY] 左字段库 + 右条件表,读写 query_schema.groups[0].conditions(保留 quick 等其余属性)
│   │   │   ├── ModuleAutoCodePanel.vue          # [MODIFY] 列名与 V2 一致,随 b_type 取值调整文本字段判定
│   │   │   ├── ModuleI18nPanel.vue              # [MODIFY] 透视行改为 (b_key,b_locale) 复合键,row-key 与增删逻辑相应调整
│   │   │   └── components/
│   │   │       ├── fieldDefaults.js             # [REWRITE] 字段→view 列节点 / query 条件节点的默认属性与工厂(JSON)
│   │   │       └── design-editor/
│   │   │           ├── TableDesignEditor.vue    # [REWRITE] 列表 view JSON 设计器(分组列/多级表头/预览),替换旧行模型
│   │   │           ├── FormDesignEditor.vue     # [REWRITE] 表单 edit JSON 设计器(分组/行/栅格/属性/预览)
│   │   │           ├── common/useStructureEditing.js  # [REWRITE] JSON 节点模型内核:分组树、多级表头、节点增删移、选中态、属性剪贴板;改造为对 columns/children 节点树操作
│   │   │           ├── common/FieldLibrary.vue  # [MODIFY] 字段库数据契约适配(节点存在性判定)
│   │   │           ├── common/EditDataView.vue  # [MODIFY] 数据视图适配新节点属性
│   │   │           ├── table/StructureTree.vue      # [REWRITE] 分组节点树展示与拖动
│   │   │           ├── table/StructureTreeNode.vue  # [REWRITE] 节点渲染/重命名
│   │   │           ├── table/TableInspector.vue     # [MODIFY] 选中列/分组节点的属性编辑
│   │   │           ├── table/TablePreview.vue       # [MODIFY] 依据 view JSON 渲染表头/列预览
│   │   │           ├── form/FormInspector.vue       # [MODIFY] 选中字段/分组节点属性
│   │   │           ├── form/FormPreview.vue         # [MODIFY] 依据 edit JSON 渲染表单预览
│   │   │           └── form/useFormGrid.js          # [MODIFY] 栅格计算适配 JSON 行/字段节点
│   │   └── menu-management/index.vue            # [MODIFY] 模块类型过滤 IN ('data','query') → IN ('data','virtual')
│   └── ...
└── tests/unit/
    ├── module-list-config-panel-dnd.spec.js     # [MODIFY] 适配 view JSON
    ├── module-table-edit-panel-dnd.spec.js      # [MODIFY] 适配 edit JSON
    ├── module-fields-panel-participation.spec.js# [MODIFY] 适配 JSON 节点参与
    ├── module-i18n-reconcile.spec.js            # [MODIFY] 适配 (b_key,b_locale) 复合键
    ├── form-edit-panel-mount.spec.js            # [MODIFY] 适配新设计器
    └── delete-confirm-regression.spec.js        # [MODIFY] 适配删除清理逻辑

Agent Extensions

SubAgent

  • code-explorer
  • Purpose: 在重写设计器内核前,系统梳理 design-editor/ 下 FormDesignEditor、TableDesignEditor、StructureTree、TableInspector/FormInspector、TablePreview/FormPreview、useFormGrid 之间的数据依赖与事件契约,明确需保留的交互点。
  • Expected outcome: 输出设计器内部组件依赖清单与需替换的数据结构映射,作为 JSON 节点模型重写的依据,避免遗漏交互。

Skill

  • lsp-code-analysis
  • Purpose: 在重构与收尾阶段做全局引用与影响分析,定位 b_viewtable/b_savetable/b_keyfield/b_orderfield/b_delete_policy/b_edit_mode、s_field_view/s_field_edit/s_field_query/s_field_group、旧 i18n 主键等符号的全部引用点,确认引用清理完整。
  • Expected outcome: 产出受改符号的完整引用清单,确保无旧路径/旧字段/旧方法名残留,指导受影响的单测与调用点同步更新。