deepseek v4pro 治理前端公共组件真香

6 阅读12分钟

组件治理

1. 治理目标

src/components 当前已经形成较完整的公共组件资产,但也出现了以下典型治理问题:

  1. 同类能力并存,AI 和人工都不容易第一时间选到“标准件”。
  2. 部分旧组件已进入兼容/废弃态,但仍与新组件共存,容易继续被误用。
  3. 重点组件缺少 README、示例或迁移说明,导致“看得到目录、用不对组件”。

本治理文档的目标是:

  • 识别重复实现、废弃组件和高优先级公共资产。
  • 划分“核心 UI 组件”和“特殊场景专用组件”。
  • 明确后续文档补齐与规则拦截方向。

2. 盘点结论

2.1 核心 UI 组件

以下组件应视为优先复用的“平台标准件”:

分类标准组件说明
搜索BaseQuery复杂列表页搜索区标准实现,支持高级条件、分组、业务组件注册
表格CmcTable标准表格场景首选
卡片表格CmcCardTable高密度、多行信息、卡片式列表场景首选
数据网格CmcDataGrid超复杂交互表格、虚拟滚动、列配置、导出等重场景
弹窗CmcDialog标准弹窗首选
选择器CmcSelect统一选择器底座,逐步承接多种业务选择能力
图标CmcIcon新标准图标组件
标签CmcTagCmcFlexibleTag标准状态标签与自适应标签
分页Pagination统一分页组件

2.2 特殊场景专用组件

以下组件不是“到处可用”的通用控件,而是有明确业务或交互边界:

分类组件适用场景
船期/港口检索VesselVoyageKeywordSelectPortSelectTradeLaneSelect船名航次、港口、航线类业务检索
业务查询组合ShipScheduleSearchschedule-search/*船期搜索专用场景
文件/解析ExcelParseCmcFileUploadCmcGroupedUploadUploadWithPreview导入导出、附件上传、文件预览
风险/确认CmcConfirmOperationLogDialogBookingOptionsDialog确认、日志、业务决策类弹窗
特殊业务字段DangerousGoodsCasGroupAgreementNoDialogContainerBaseDataSelect特定业务域输入与选择
性能/骨架SkeletonLoaderSimpleLoaderProgressiveLoaderGlobalLoadingCmcLoading加载阶段、全局遮罩、骨架屏等不同层次场景

2.3 已明确废弃 / 兼容态组件

以下组件已经在代码中明确出现 @deprecated 或废弃警告,应禁止新页面继续使用:

组件当前状态建议替代
CmcContentDialog已废弃CmcDialog
SvgIcon兼容层,建议停用CmcIcon
BaseDataSelect已废弃CmcSelect
Pagination.condition 传参已废弃用法独立的 pageNo/pageSize/total

2.4 疑似重复实现 / 需要进一步归并的组件族

以下不是“立刻删除”,而是需要纳入后续治理的重点分组:

组件族现状治理建议
选择器族CountrySelectCurrencySelectDictSelectPortSelectTradeLaneSelectCmcSelect 并存逐步形成“CmcSelect 底座 + 业务壳组件”的双层结构
表格族CmcTableCmcCardTableCmcDataGrid 能力边界容易混淆补文档,明确场景边界,禁止误选
加载族CmcLoadingGlobalLoadingSkeletonLoaderSimpleLoaderProgressiveLoader明确“全局遮罩 / 区域加载 / 骨架屏 / 渐进加载”分层
容器尺寸选择族CntrSizeTypeSelectContainerSelectSizeTypeContainerBaseDataSelect 命名与职责有重叠感统一命名与使用建议,避免新增第 4 套实现
搜索增强族BaseQueryQueryExpandAllConditionChange确立 BaseQuery 为主入口,其他作为局部增强能力

3. 重点问题说明

3.1 为什么会“重复造轮子”

根因不是单一文档缺失,而是以下问题叠加:

  1. 规则层只强调“优先复用”,但缺少“场景强映射”。
  2. 重点组件没有形成 README + 示例 + 测试 + 迁移说明的闭环。
  3. 兼容组件仍然可用,导致新代码继续沿用旧实现。
  4. 组件命名存在历史包袱,AI 和人工都可能凭直觉误选。

3.2 BaseQuery 的治理结论

BaseQuery 已经是成熟的复杂搜索组件,不应再让复杂列表页自行拼装原生 el-form

建议形成硬规则:

  1. 当页面顶部存在“查询 + 重置 + 展开/收起 + 多字段联动”时,优先使用 BaseQuery
  2. 当只是 1 到 2 个极简单字段时,可保留原生 el-form
  3. .mdc 规则中增加“复杂搜索区 -> BaseQuery”的强映射。

4. 组件分层建议

4.1 推荐分层

层级说明代表组件
基础 UI 层通用视觉控件CmcIconCmcTagCmcDividerCmcButtonGroup
容器交互层表格、弹窗、分页、查询等结构性组件BaseQueryCmcTableCmcCardTableCmcDialogPagination
业务选择器层与港口、航次、字典、基础资料绑定的组件PortSelectTradeLaneSelectVesselVoyageKeywordSelectCmcSelect
特殊业务层针对某一业务域或复杂流程的组件DangerousGoodsCasGroupAgreementNoDialogBookingOptionsDialog
兼容迁移层仅为历史代码保留,不得新增使用CmcContentDialogSvgIconBaseDataSelect

4.2 新增组件准入原则

新增组件前必须回答 4 个问题:

  1. src/components 中是否已有 80% 可复用实现?
  2. 是通用 UI 还是业务专用?
  3. 是否只是旧组件换名字再实现一次?
  4. 是否需要 README、单测、迁移说明一起补齐?

只要有一个问题答不清,就不应直接新增组件。


5. 文档补齐优先级

5.1 已补或已有 README

  • CmcDialog
  • CmcSelect
  • TextEllipsis
  • ExcelParse
  • OptimizedImage

5.2 当前最优先补齐

  1. BaseQuery
  2. CmcTable
  3. CmcCardTable

原因:

  • 它们是复杂 B 端页面的主骨架。
  • AI 是否能稳定复用,直接决定“会不会再重复造轮子”。
  • 它们的场景边界如果不清晰,最容易被误用。

5.3 第二梯队建议

  1. CmcDataGrid
  2. Pagination
  3. VesselVoyageKeywordSelect
  4. PortSelect

6. 废弃组件影响面详细清单

盘点时间: 2026-04-27 | 数据来源: 全仓 grep 扫描 src/views/

6.1 CmcContentDialog → CmcDialog(🟠 中高风险)

涉及生产页面(7 个)

文件所属域
export/booking/index.vue订舱管理
export/booking/components/SoListItem.vue订舱-S/O明细
export/manifest_manage/index.vue舱单管理
export/lading/management/LadingInfo.vue提单-提单详情
export/lading/components/UserName/src/UserNameSelect.vue提单-用户名选择
payment_settlement/pay-manage/index.vue结算-支付管理
payment_settlement/pay-manage/components/StatementDetails.vue结算-账单明细

迁移复杂度:中

Props 差异要点:

  • CmcContentDialog 默认 :show-close="false" :close-on-click-modal="false" draggable — 迁移到 CmcDialog 需显式设置
  • bodyHeight 属性已废弃,改用 CSS
  • footer slot 结构一致

迁移模板

<!-- ❌ 旧 -->
<CmcContentDialog v-model="visible" title="标题" :width="750">
  <template #footer>...</template>
</CmcContentDialog>

<!-- ✅ 新 -->
<CmcDialog v-model="visible" title="标题" :width="750"
  :show-close="false" :close-on-click-modal="false"
  :close-on-press-escape="false" draggable destroy-on-close
>
  <template #footer>...</template>
</CmcDialog>

已验证测试覆盖CmcDialog 已有单测 (__tests__/CmcDialog.test.ts)。


6.2 SvgIcon → CmcIcon(🟡 低风险)

涉及生产页面(10 个)

文件所属域
export/booking/ModifySchedulePort/components/SearchForm.vue订舱-改港
export/booking/ModifySchedule/SearchForm.vue订舱-改船期
export/booking/components/SearchSchedule/search-form/PointToPointSearchForm.vue订舱-船期搜索
export/manifest_manage/components/AddBoxDialog.vue舱单-加箱
export/lading/components/container/Edit.vue提单-箱信息编辑
export/container-manage/components/form-dialog/VgmInfoSection.vue箱管-VGM
search_service/ship-schedules/components/PortTimeDetailsCard.vue船期查询
search_service/qick-search/surcharge-rate/index.vue快查-附加费
search_service/statistics/CostStatistics.vue统计-费用
search_service/statistics/CargoStatistics.vue统计-货量

迁移复杂度:极低

  • SvgIcon 已是兼容代理层,内部转发到 CmcIcon
  • 运行时行为完全一致
  • 只需替换 import 路径:~/components/SvgIcon~/components/CmcIcon
  • 组件用法不变:<SvgIcon name="xxx" /><CmcIcon name="xxx" />

迁移模板

<!-- ❌ 旧 -->
import SvgIcon from '~/components/SvgIcon'
<SvgIcon name="booking" :size="16" />

<!-- ✅ 新 -->
import CmcIcon from '~/components/CmcIcon'
<CmcIcon name="booking" :size="16" />

6.3 BaseDataSelect → CmcSelect(🔴 高风险 — 暂不执行迁移)

涉及生产页面(14 个)

文件所属域
export/booking/components/BookingApprove.vue订舱-审批
export/booking/components/BookingQuery.vue订舱-查询
export/booking/components/SelectTemplate.vue订舱-模板
export/booking/components/SearchSchedule/search-form/PointToPointSearchForm.vue订舱-船期搜索
export/booking/components/SearchSchedule/search-form/VesselVoyageSearchForm.vue订舱-船期搜索
export/lading/components/SIBasicInfo.vue提单-SI基本信息
export/lading/components/cargo/index.vue提单-货物信息
export/lading/components/container/Edit.vue提单-箱信息编辑
export/lading/split/SplitBasicInfo.vue提单-分单
export/manifest_manage/components/OrderInfoHeader.vue舱单-订单头
export/manifest_manage/components/GoodInfoSingle.vue舱单-单票货
export/manifest_manage/components/GoodInfoMultiple.vue舱单-多票货
export/manifest_manage/components/AddBoxDialog.vue舱单-加箱
search_service/qick-search/surcharge-rate/index.vue快查-附加费

迁移复杂度:高(暂不执行)

Props 差异完整映射表:

BaseDataSelect PropsCmcSelect Props
categorycategory(一致)
only-showreadonly
label-shallowvariant="underline"
clearableclearable(一致)
filterablefilterable(一致)
set-default❌ 不支持,需手动处理
bind-label❌ 不支持,使用 @change 替代
emit-item❌ 不支持,使用 @change 获取完整 option
save-to-selection❌ 不支持,需手动调用 selectionStore

风险点

  1. setDefault/bindLabel/emitItem/saveToSelection 等 Props 在 CmcSelect 中无对应
  2. BaseDataSelect 通过 useDocBaseCodes composable 加载数据 + selectionStore 联动
  3. CmcSelect 的 baseData 数据源行为需逐页验证

⚠️ 处置策略:暂不迁移。仅通过规则拦截禁止新页面使用。待 CmcSelect 的 selectionStore 联动能力补齐后再启动迁移。


7. 生产环境分阶段治理计划

核心原则:先堵增量,再治存量;每次变更可独立回滚。

阶段 0:规则拦截(立即执行,零生产风险)

目标:阻止任何新的废弃组件进入代码库。

操作

  1. 修改 .trae/rules/vue-component.mdc,加入以下硬规则:
# 组件使用强制映射(违反则阻断)
- 新弹窗  → 必须使用 CmcDialog(禁止 CmcContentDialog)
- 新图标  → 必须使用 CmcIcon(禁止 SvgIcon)
- 新基础数据选择 → 必须使用 CmcSelect data-source="baseData"(禁止 BaseDataSelect)
- 复杂搜索区   → 必须使用 BaseQuery(禁止手写 el-form 拼装)
- 标准表格     → 必须使用 CmcTable
- 卡片列表     → 必须使用 CmcCardTable
- Pagination.condition 传参 → 已废弃,必须使用独立的 pageNo/pageSize/total
  1. src/components/BaseDataSelect/index.ts 中添加 @deprecated JSDoc 注释的构建时警告(如果构建工具支持)。

回滚方式:恢复 .mdc 文件即可。


阶段 1:文档补齐(本周完成,零生产风险)

已完成 README

  • CmcDialog
  • CmcSelect
  • CmcTable
  • CmcCardTable
  • BaseQuery
  • TextEllipsis
  • ExcelParse
  • OptimizedImage

待补齐

优先级组件需包含内容
P0Pagination新旧 API 对比、废弃用法警告
P1CmcDataGrid场景边界(与 CmcTable/CmcCardTable 的区别)
P1VesselVoyageKeywordSelectProps、事件、远程搜索行为
P1PortSelect与 CmcSelect preset="port" 的关系
P2CmcContentDialogMIGRATION.md(含迁移模板和常见坑)
P2BaseDataSelectMIGRATION.md(含 Props 对照表和暂不迁移声明)
P2SvgIconMIGRATION.md(仅 import 替换说明)

阶段 2:SvgIcon 批量迁移(第 1 批,低风险)

范围:~10 个页面,仅 import 路径替换。

步骤

  1. 创建 feature 分支 refactor/migrate-svgicon-to-cmcicon
  2. 逐文件替换:import SvgIcon from '~/components/SvgIcon'import CmcIcon from '~/components/CmcIcon'
  3. <SvgIcon<CmcIcon(标签名替换)
  4. 本地 npm run type-check && npm run lint:check
  5. 视觉回归:在 dev 环境逐个检查使用了图标的页面
  6. 合并 → 部署 → 生产验证

回滚方式:每个 commit 为一个文件,可单独 revert。

验收标准:所有图标渲染与原效果一致,无控制台警告。


阶段 3:CmcContentDialog 逐页迁移(第 2 批,中风险)

范围:~7 个页面。

步骤(每个页面独立完成):

  1. 创建 page 级 feature 分支(如 refactor/migrate-dialog-booking
  2. 替换 CmcContentDialog → CmcDialog,按迁移模板设置 props
  3. 本地打开该页面,测试:弹窗打开/关闭、确认/取消按钮、footer 自定义内容、拖拽、点击遮罩不关闭
  4. npm run type-check
  5. 合并 → 部署 → 生产验证
  6. 验证通过后再迁移下一个页面

迁移检查清单(每页必验)

  • 弹窗正常打开和关闭
  • 确认/取消按钮行为正确
  • footer 自定义内容正常渲染
  • 点击遮罩层不关闭弹窗(保持旧行为)
  • 弹窗可拖拽
  • 关闭时内容销毁(destroy-on-close)
  • 无 console 报错或警告

回滚方式:每个页面独立分支,出问题只回滚该页面。


阶段 4:BaseDataSelect 迁移(第 3 批,高风险 — 暂缓)

前置条件(任一不满足则不启动):

  1. CmcSelect 补齐 saveToSelection / setDefault / bindLabel / emitItem 等价能力
  2. 或通过 composable 封装解决 selectionStore 联动问题
  3. 至少 2 个页面在 staging 环境完成完整回归测试

暂不启动的原因

  • 涉及 14 个生产页面,覆盖订舱/提单/舱单/快查四大核心域
  • API 差异大,迁移不当会导致基础数据加载失败
  • selectionStore 联动逻辑需要额外封装
  • 收益/风险比不足(旧组件功能正常,暂无 Bug)

阶段 5:废弃源码清理(全部迁移完成后)

触发条件:阶段 2、3、4 全部完成并通过生产验证。

操作

  1. 删除 src/components/CmcContentDialog/src/components/BaseDataSelect/src/components/SvgIcon/ 源码目录
  2. 各目录保留 index.ts,改为仅重导出新组件(保持向后兼容)
  3. package.json 中记录 breaking change(如果后续有大版本发布)

8. 回滚策略总览

阶段风险回滚粒度回滚方式
阶段 0(规则拦截)文件级恢复 .mdc 文件
阶段 1(文档补齐)-无需回滚
阶段 2(SvgIcon 迁移)commit 级git revert 单 commit
阶段 3(CmcContentDialog 迁移)页面级每个页面独立分支,出问题只 revert 该分支
阶段 4(BaseDataSelect 迁移)页面级暂不执行
阶段 5(源码清理)-仅在全部迁移完成且生产稳定后执行

9. 持续监控指标

指标目标值监控方式
新页面使用废弃组件0CI 中 grep 检查
已迁移页面回归 Bug0每个迁移页面必须手动验证
组件 README 覆盖率≥ 80%人工定期盘点
SvgIcon 存活文件数趋于 0grep 命令

10. 当前结论

当前 src/components 不是“没有公共组件”,而是“公共组件很多,但标准入口和迁移边界还不够强”。

治理重点不是继续无序新增,而是:

  1. 立标准件
  2. 标废弃件
  3. 补重点文档
  4. 用规则把复杂场景强行映射到标准件

只有这样,AI 和人工才能在复杂页面中真正做到高复用,而不是继续重复实现。


执行优先级总结

优先级动作风险状态
🔴 P0 立即修改 .trae/rules/vue-component.mdc 加入强制映射 + 禁止废弃组件⬜ 待执行
🟡 P1 本周补齐 Pagination/CmcDataGrid 等 README + 3 个 MIGRATION.md⬜ 待执行
🟢 P2 本周SvgIcon → CmcIcon 批量 import 替换(~10 页)⬜ 待执行
🟠 P3 本月CmcContentDialog → CmcDialog 逐页迁移(~7 页)⬜ 待执行
🔴 P4 暂缓BaseDataSelect → CmcSelect 迁移(~14 页)⛔ 暂缓

一句话总结:先通过规则把"增量"管住,再用最安全的方式逐步消化"存量"。每步都可独立回滚,不影响生产稳定性。