@agile-team/wl-skills-ui 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/README.md +623 -0
  3. package/SKILL.md +632 -0
  4. package/bin/wl-ui.js +794 -0
  5. package/design/spec/color.md +41 -0
  6. package/design/spec/spacing.md +28 -0
  7. package/design/spec/typography.md +29 -0
  8. package/design/tokens/base.css +144 -0
  9. package/design/tokens/index.css +8 -0
  10. package/dist/ag-grid-override.scss +1 -0
  11. package/dist/element.scss +1 -0
  12. package/dist/index.scss +1 -0
  13. package/dist/portal.scss +1 -0
  14. package/dist/style-override.scss +1 -0
  15. package/dist/tokens.css +144 -0
  16. package/es/chunk-GBB7LDKQ.js +261 -0
  17. package/es/chunk-MDI2SCUP.js +281 -0
  18. package/es/chunk-QDTNMM7W.js +286 -0
  19. package/es/chunk-YLNAFAWE.js +233 -0
  20. package/es/common-preset.d.ts +38 -0
  21. package/es/common-preset.js +157 -0
  22. package/es/index.d.ts +32 -0
  23. package/es/index.js +1 -0
  24. package/es/presets/security.d.ts +16 -0
  25. package/es/presets/security.js +99 -0
  26. package/es/renderers-BFRSp2BH.d.ts +51 -0
  27. package/es/renderers-DMZbi_Gs.d.ts +51 -0
  28. package/es/renderers-DWhUlI2y.d.ts +47 -0
  29. package/es/types-04qLKHMt.d.ts +62 -0
  30. package/es/types-BrCPjAH6.d.ts +62 -0
  31. package/es/types-QZ1gy9KX.d.ts +63 -0
  32. package/examples/migration-operations-to-renderOps.md +107 -0
  33. package/examples/wk-exempt.example.json +30 -0
  34. package/mcp/server.js +394 -0
  35. package/package.json +130 -0
  36. package/reference/SelectPopupCom.vue +634 -0
  37. package/reference/ag-cell-renders.ts +644 -0
  38. package/reference/define-columns.ts +185 -0
  39. package/reference/jhlc.d.ts +1 -0
  40. package/scanner/coverage.mjs +287 -0
  41. package/scanner/exempt.mjs +127 -0
  42. package/scanner/fix.mjs +216 -0
  43. package/scanner/index.mjs +403 -0
  44. package/scanner/integration.mjs +155 -0
  45. package/scanner/report.mjs +459 -0
  46. package/scanner/rules/_shared.mjs +134 -0
  47. package/scanner/rules/button.mjs +97 -0
  48. package/scanner/rules/color.mjs +118 -0
  49. package/scanner/rules/componentFamily.mjs +184 -0
  50. package/scanner/rules/dialog.mjs +42 -0
  51. package/scanner/rules/form.mjs +86 -0
  52. package/scanner/rules/index.mjs +58 -0
  53. package/scanner/rules/table.mjs +170 -0
  54. package/scanner/rules/tag.mjs +245 -0
  55. package/scanner/snapshot.mjs +198 -0
  56. package/skills/_flows/full-audit.md +65 -0
  57. package/skills/_flows/legacy-skin-align.md +71 -0
  58. package/skills/_flows/new-project-init.md +80 -0
  59. package/skills/_flows/progressive-migrate.md +49 -0
  60. package/skills/_meta/_compat/README.md +47 -0
  61. package/skills/_meta/_compat/editors.json +76 -0
  62. package/skills/_meta/_compat/headers/agents.txt +7 -0
  63. package/skills/_meta/_compat/headers/claude-code.txt +7 -0
  64. package/skills/_meta/_compat/headers/cline.txt +7 -0
  65. package/skills/_meta/_compat/headers/cursor-mdc.txt +5 -0
  66. package/skills/_meta/_compat/headers/github-copilot.txt +5 -0
  67. package/skills/_meta/_compat/headers/kiro.txt +4 -0
  68. package/skills/_meta/_compat/headers/qoder.txt +4 -0
  69. package/skills/_meta/_compat/headers/trae.txt +3 -0
  70. package/skills/_meta/_compat/headers/windsurf.txt +5 -0
  71. package/skills/_meta/_detection.md +81 -0
  72. package/skills/_meta/_registry.md +96 -0
  73. package/skills/element/component-family/SKILL.md +71 -0
  74. package/skills/element/el-dialog/SKILL.md +124 -0
  75. package/skills/element/el-form/SKILL.md +84 -0
  76. package/skills/element/el-table/SKILL.md +86 -0
  77. package/skills/element/el-tag/SKILL.md +127 -0
  78. package/skills/layouts/detail-page/SKILL.md +99 -0
  79. package/skills/layouts/form-dialog/SKILL.md +128 -0
  80. package/skills/layouts/list-page/SKILL.md +111 -0
  81. package/skills/layouts/tree-list/SKILL.md +108 -0
  82. package/skills/ops/audit/SKILL.md +109 -0
  83. package/skills/ops/fix/SKILL.md +52 -0
  84. package/skills/ops/fix/USAGE.md +24 -0
  85. package/skills/ops/migrate/SKILL.md +157 -0
  86. package/skills/ops/scan/SKILL.md +71 -0
  87. package/skills/ops/scan/USAGE.md +16 -0
  88. package/skills/runtime/design-tokens/SKILL.md +88 -0
  89. package/skills/runtime/design-tokens/USAGE.md +19 -0
  90. package/skills/runtime/migration/SKILL.md +106 -0
  91. package/skills/runtime/migration/USAGE.md +34 -0
  92. package/skills/runtime/style-align/SKILL.md +124 -0
  93. package/skills/runtime/style-align/USAGE.md +52 -0
  94. package/skills/vendors/ag-grid/SKILL.md +94 -0
  95. package/skills/vendors/base-table/SKILL.md +57 -0
  96. package/skills/vendors/c-components/SKILL.md +36 -0
  97. package/skills/vendors/custom-wrappers/SKILL.md +45 -0
  98. package/skills/vendors/jh-components/SKILL.md +42 -0
  99. package/skills/vendors/unknown-wrapper/SKILL.md +44 -0
  100. package/standards/engineering/01-import-order.md +46 -0
  101. package/standards/engineering/02-naming.md +54 -0
  102. package/standards/engineering/03-scss-structure.md +59 -0
  103. package/standards/ui/01-table.md +111 -0
  104. package/standards/ui/02-button.md +83 -0
  105. package/standards/ui/03-form.md +118 -0
  106. package/standards/ui/04-tag-status.md +110 -0
  107. package/standards/ui/05-dialog-pagination.md +118 -0
  108. package/styles/element/_card.scss +26 -0
  109. package/styles/element/_descriptions.scss +22 -0
  110. package/styles/element/_dialog.scss +43 -0
  111. package/styles/element/_drawer.scss +22 -0
  112. package/styles/element/_feedback.scss +52 -0
  113. package/styles/element/_form.scss +22 -0
  114. package/styles/element/_navigation.scss +36 -0
  115. package/styles/element/_overlay.scss +32 -0
  116. package/styles/element/_pagination.scss +16 -0
  117. package/styles/element/_steps.scss +32 -0
  118. package/styles/element/_table.scss +13 -0
  119. package/styles/element/_tabs.scss +40 -0
  120. package/styles/element/_tree.scss +27 -0
  121. package/styles/element/_upload.scss +34 -0
  122. package/styles/element/index.scss +17 -0
  123. package/styles/index.scss +21 -0
  124. package/styles/layouts/_detail-page.scss +27 -0
  125. package/styles/layouts/_form-dialog.scss +19 -0
  126. package/styles/layouts/_list-page.scss +47 -0
  127. package/styles/layouts/_tree-list.scss +33 -0
  128. package/styles/layouts/index.scss +6 -0
  129. package/styles/presets/element-only.scss +6 -0
  130. package/styles/presets/full.scss +12 -0
  131. package/styles/presets/security.scss +37 -0
  132. package/styles/presets/skin.scss +14 -0
  133. package/styles/presets/tokens-only.scss +7 -0
  134. package/styles/tokens/index.scss +79 -0
  135. package/styles/vendors/_ag-grid.scss +273 -0
  136. package/styles/vendors/_base-components.scss +480 -0
  137. package/styles/vendors/_base-query-toolbar.scss +253 -0
  138. package/styles/vendors/_base-table.scss +41 -0
  139. package/styles/vendors/_c-components.scss +34 -0
  140. package/styles/vendors/_custom-wrappers.scss +30 -0
  141. package/styles/vendors/_jh-drag-col.scss +63 -0
  142. package/styles/vendors/_jh-pagination.scss +81 -0
  143. package/styles/vendors/_jh-tree.scss +196 -0
  144. package/styles/vendors/_portal.scss +114 -0
  145. package/styles/vendors/index.scss +17 -0
  146. package/templates/ag-grid-page/TPL-AG-GRID.md +76 -0
  147. package/templates/form-dialog/TPL-FORM-DIALOG.md +165 -0
  148. package/templates/list-page/TPL-LIST.md +139 -0
  149. package/templates/tree-list/TPL-TREE-LIST.md +176 -0
  150. package/templates/ui-optimization-report/TPL-UI-OPTIM-REPORT.md +343 -0
@@ -0,0 +1,36 @@
1
+ ---
2
+ description: |
3
+ C_/c_ 前缀的项目自封装组件(团队约定的未来主流命名)。Layer L2,优先级 #3。
4
+ 目前是占位 + 探测引导,待团队约定的具体 C_* 组件落地后填充细节。
5
+ applyTo: "**/*.vue"
6
+ ---
7
+
8
+ # Skill: vendors/c-components
9
+
10
+ > Layer L2 · Vendor priority **#3** · 团队未来主流命名约定
11
+
12
+ ## Detect
13
+
14
+ | 模式 | 示例 |
15
+ |---|---|
16
+ | PascalCase 标签 | `<C_Form>` / `<C_Table>` / `<C_DataPicker>` |
17
+ | kebab-case 标签 | `<c-form>` / `<c-table>` / `<c-data-picker>` |
18
+ | 类名 | `[class^='c-']` / `[class^='C_']` |
19
+ | Import | `from '@/components/C*/'` / `from '@/business/c-*/'` |
20
+
21
+ ## Diagnose
22
+
23
+ 由于 C_* 属于团队约定的未来主流封装,识别到时优先按以下规则:
24
+ - 检查内部是否调用了未对齐的 el-* 控件
25
+ - 自行写的颜色硬编码 → 引导改用 token
26
+ - 控件 size / 边距 / 圆角是否符合 element/_*.scss 规范
27
+
28
+ ## Repair
29
+
30
+ A 类:补 size、补 empty-text、改 hex → token
31
+ B 类:建议沉淀新的 `c-*` skill(拿到源码后)+ 在 `styles/vendors/_c-components.scss` 追加精确选择器
32
+
33
+ ## 扩展引导
34
+
35
+ 当出现新的 C_* 组件时,请把组件名称、典型 DOM 结构添加到本文件 + `_c-components.scss`,
36
+ 便于后续 AI 精确识别。
@@ -0,0 +1,45 @@
1
+ ---
2
+ description: |
3
+ 野路子自封装组件(src/components/XxxxXxxx 这类无规律前缀)的探测和兜底修复策略。
4
+ Layer L2,优先级 #4(兜底)。
5
+ applyTo: "**/*.vue"
6
+ ---
7
+
8
+ # Skill: vendors/custom-wrappers
9
+
10
+ > Layer L2 · Vendor priority **#4**(兜底)
11
+
12
+ ## Detect
13
+
14
+ 无统一前缀,但满足以下任一即视为自封装:
15
+
16
+ - 路径:`src/components/*.vue`(PascalCase 单文件)
17
+ - Import:`from '@/components/XxxXxx'`
18
+ - DOM 内部一定包含 `el-*` 元素(否则不属于本 skill)
19
+
20
+ ## 探测策略(AI 必读)
21
+
22
+ 由于没有命名规律,AI 应:
23
+ 1. 跟随 `<script setup>` 中的 `import` 找到组件源码
24
+ 2. 如能读到源码 → 按 **element-plus 规则**直接修复源码
25
+ 3. 如不能读到源码 → 走"化妆模式":在 `styles/vendors/_custom-wrappers.scss` 追加包装类
26
+ 4. 输出"建议封装迁移到 C_/c_ 前缀"作为优化建议
27
+
28
+ ## Diagnose(典型问题)
29
+
30
+ - 内部 `el-input` 没 `size="small"` → 但封装可能转发了 size prop,先确认源码
31
+ - 内部 hex 颜色 → 应改 token
32
+ - 内部布局魔法数 padding/margin → 建议改用 layouts/ 层 class
33
+
34
+ ## Repair
35
+
36
+ ### A 类(仅当能读到源码)
37
+ - 同 element/* skill 的 A 类规则
38
+
39
+ ### B 类
40
+ - 输出"建议把该组件改名为 C_*/c_* 前缀,纳入团队规范" 的修复建议
41
+ - 在 `_custom-wrappers.scss` 注入 .{业务类名} 包装层覆盖
42
+
43
+ ## 与 C_/c_ 的迁移路径
44
+
45
+ custom → 改名为 C_*/c_* → 进入 vendors/c-components 流程 → 拿到源码后从 L2 迁移到 L4 runtime
@@ -0,0 +1,42 @@
1
+ ---
2
+ description: |
3
+ jh-* 前缀的封装组件系列(jh-form / jh-table / jh-tree / jh-pagination / jh-drag-col 等)
4
+ 的识别、诊断和修复规则。Layer L2,优先级 #2(次于 Base*)。
5
+ applyTo: "**/*.vue"
6
+ ---
7
+
8
+ # Skill: vendors/jh-components
9
+
10
+ > Layer L2 · Vendor priority **#2**
11
+
12
+ ## Detect(识别)
13
+
14
+ | 子组件 | 标签 | 关键类名 |
15
+ |---|---|---|
16
+ | jh-table | `<jh-table>` | `.jh-table` |
17
+ | jh-form | `<jh-form>` | `.jh-form` |
18
+ | jh-tree | `<jh-tree>` | `.jh-tree` / `.base-tree` |
19
+ | jh-pagination | `<jh-pagination>` | `.jh-pagination` |
20
+ | jh-drag-col | `<jh-drag-col>` | `.drag-col-container` / `.drag-left` / `.slider-col` |
21
+
22
+ ## Diagnose
23
+
24
+ - ❌ 自行给 `.jh-tree` 写颜色覆盖(应用全局 `vendors/_jh-tree.scss`)
25
+ - ❌ jh-drag-col 内自定义 padding 破坏拖拽条对齐
26
+ - ❌ jh-pagination 未对齐到右侧(同 R011)
27
+ - ❌ jh-form 内不用 `size="small"` 控件(同 R006)
28
+
29
+ ## Repair
30
+
31
+ ### A 类
32
+ - 控件 size 缺失 → 补 `size="small"`
33
+ - 表单内日期选择器无宽度 → `style="width:100%"`(R007)
34
+
35
+ ### B 类
36
+ - 直接全局覆盖 `.jh-*` → 改为引入 `wk-skills-ui/styles` 由 vendors 层处理
37
+
38
+ ## 全局样式来源
39
+
40
+ - `styles/vendors/_jh-tree.scss`
41
+ - `styles/vendors/_jh-pagination.scss`
42
+ - `styles/vendors/_jh-drag-col.scss`
@@ -0,0 +1,44 @@
1
+ ---
2
+ description: |
3
+ 陌生封装组件的通用探测策略 — AI 在无 skill 匹配时的兜底逻辑。
4
+ 通过 DOM 结构推断对应的 element-plus 控件,给出可解释的诊断和保守修复方案。
5
+ applyTo: "**/*.vue"
6
+ ---
7
+
8
+ # Skill: vendors/unknown-wrapper
9
+
10
+ > 兜底探测器 — 当组件不属于已知任何 vendor 时启用
11
+
12
+ ## 工作方式
13
+
14
+ 1. **遍历 import**:识别所有非 element-plus 的组件标签
15
+ 2. **匹配 vendor skill**:
16
+ - Base* → vendors/base-table(如是表格)/ vendors/base-components
17
+ - jh-* → vendors/jh-components
18
+ - C_*/c_* → vendors/c-components
19
+ - 其他 → vendors/custom-wrappers
20
+ 3. **若仍未识别**:
21
+ - 输出"未识别的封装组件 `<XxxYy>`"
22
+ - 给出"请在 `skills/vendors/_registry.md` 追加该组件的识别规则"建议
23
+ - 不修改源码,仅输出诊断报告
24
+
25
+ ## DOM 推断表(兜底)
26
+
27
+ | 内部 DOM 包含 | 推断为 |
28
+ |---|---|
29
+ | `.el-table` | 表格类 → 应用 R001/R002/R014 |
30
+ | `.el-form` | 表单类 → 应用 R006/R008 |
31
+ | `.el-dialog` | 弹窗类 → 应用 R011/R015 |
32
+ | `.el-pagination` | 分页类 |
33
+ | `.ag-root-wrapper` | AG Grid → 走 vendors/ag-grid |
34
+
35
+ ## 输出格式
36
+
37
+ ```
38
+ [unknown-wrapper] 检测到未识别封装:<XxxYyy>(src/views/foo.vue:42)
39
+ 推断类型:表格类(内部含 .el-table)
40
+ 应用规则:R001, R002, R014
41
+ 化妆建议:在 styles/vendors/_custom-wrappers.scss 追加:
42
+ .xxx-yyy { /* 复用 vendors/_base-table.scss 的覆盖 */ }
43
+ 扩展建议:把该组件信息追加到 skills/vendors/c-components/SKILL.md(若团队约定改前缀)
44
+ ```
@@ -0,0 +1,46 @@
1
+ # 工程规范 01 — Import 顺序
2
+
3
+ ## 规则
4
+
5
+ 按以下顺序组织 import,组间空一行:
6
+
7
+ ```
8
+ 1. Node.js 内置模块(node:fs 等)
9
+ 2. 第三方依赖(vue、element-plus、lodash 等)
10
+ 3. 内部别名路径(@/、@agile-team/)
11
+ 4. 相对路径(../、./)
12
+ 5. 类型导入(import type ...)
13
+ ```
14
+
15
+ ## 示例
16
+
17
+ ```typescript
18
+ // ✅ 正确
19
+ import { ref, computed } from "vue";
20
+ import { ElMessage } from "element-plus";
21
+
22
+ import { usePageHook } from "@/hooks/page";
23
+ import type { PageResult } from "@/types";
24
+
25
+ import { renderOps, defineColumns } from "@agile-team/wk-skills-ui/runtime";
26
+
27
+ import MyModal from "./MyModal.vue";
28
+ import type { MyItem } from "./types";
29
+ ```
30
+
31
+ ```typescript
32
+ // ❌ 错误:类型与值混用,无分组
33
+ import MyModal from "./MyModal.vue";
34
+ import { ref } from "vue";
35
+ import type { MyItem } from "./types";
36
+ import { usePageHook } from "@/hooks/page";
37
+ ```
38
+
39
+ ## ESLint 配置参考
40
+
41
+ ```json
42
+ "import/order": ["error", {
43
+ "groups": ["builtin", "external", "internal", "parent", "sibling", "index", "type"],
44
+ "newlines-between": "always"
45
+ }]
46
+ ```
@@ -0,0 +1,54 @@
1
+ # 工程规范 02 — 命名规范
2
+
3
+ ## 文件命名
4
+
5
+ | 类型 | 规则 | 示例 |
6
+ | ---------- | ---------------------------------------- | -------------------- |
7
+ | Vue 组件 | PascalCase | `RiskList.vue` |
8
+ | 工具/hooks | camelCase | `usePageHook.ts` |
9
+ | 常量/枚举 | camelCase(文件名)+ UPPER_SNAKE(变量) | `statusMap.ts` |
10
+ | 样式 | kebab-case | `risk-list.scss` |
11
+ | 模板 | TPL-前缀 + UPPER_KEBAB | `TPL-FORM-DIALOG.md` |
12
+
13
+ ## 变量/函数命名
14
+
15
+ ```typescript
16
+ // ✅ 状态映射:UPPER_SNAKE + _MAP 后缀
17
+ const ENABLE_STATUS_MAP = { ... }
18
+
19
+ // ✅ Render 函数:renderXxx
20
+ const renderEnableStatus = (v) => renderTagNode(v, ENABLE_STATUS_MAP);
21
+
22
+ // ✅ API 函数:动词 + 名词
23
+ async function getRiskList(params: QueryParams) {}
24
+ async function updateRiskStatus(id: string, status: string) {}
25
+
26
+ // ✅ hooks:use 前缀
27
+ const page = usePageHook({ apiFn: getRiskList, params: () => searchForm });
28
+
29
+ // ❌ 禁止
30
+ const status_map = {} // 应用 camelCase 或 UPPER_SNAKE
31
+ function GetRiskList() {} // 大写开头的非组件函数
32
+ const renderFlag = (v) => ... // 不应叫 flag,应描述具体字段
33
+ ```
34
+
35
+ ## 组件 prop 命名
36
+
37
+ ```typescript
38
+ // ✅ camelCase(JS 侧),HTML 中用 kebab-case
39
+ defineProps<{ labelWidth: string; isReadonly: boolean }>();
40
+
41
+ // template 中
42
+ <MyComp :label-width="150" :is-readonly="true" />
43
+ ```
44
+
45
+ ## 接口/类型命名
46
+
47
+ ```typescript
48
+ // ✅ 接口:I 前缀 可选,但 Type 后缀推荐
49
+ interface RiskItem { ... }
50
+ type SearchParams = { name: string; status: string };
51
+
52
+ // ✅ 响应包装
53
+ type PageResult<T> = { records: T[]; total: number; current: number; size: number };
54
+ ```
@@ -0,0 +1,59 @@
1
+ # 工程规范 03 — SCSS 文件结构
2
+
3
+ ## 项目级样式目录
4
+
5
+ ```
6
+ src/
7
+ styles/
8
+ index.scss # 全局入口:@use 所有模块
9
+ variables.scss # 项目自定义变量(扩展 token)
10
+ mixins.scss # 项目公共 mixin
11
+ components/ # 组件级样式(按需使用)
12
+ _risk.scss
13
+ _audit.scss
14
+ pages/ # 页面级样式(scoped 内可重写)
15
+ ```
16
+
17
+ ## 全局入口 (src/styles/index.scss)
18
+
19
+ ```scss
20
+ // 1. wk-skills-ui 设计 token(必须在 index.html <link> 加载 design/tokens/base.css)
21
+
22
+ // 2. wk-skills-ui 样式重置
23
+ @use "@agile-team/wk-skills-ui/styles" as *;
24
+
25
+ // 3. 项目自定义变量
26
+ @use "./variables" as *;
27
+
28
+ // 4. 项目公共 mixin
29
+ @use "./mixins" as *;
30
+ ```
31
+
32
+ ## 规则
33
+
34
+ 1. **禁用 `@import`**(SCSS 已废弃)— 统一用 `@use` / `@forward`
35
+ 2. **颜色**必须用 CSS 变量或 token(R016/R017/R018),不写硬编码 hex
36
+ 3. **scoped 样式**中不写全局覆盖;全局覆盖统一在 `styles/components/` 中
37
+ 4. **BEM 命名**:`.block__element--modifier`
38
+ 5. 组件 `<style lang="scss" scoped>` 中只写该组件私有样式
39
+
40
+ ## 示例
41
+
42
+ ```scss
43
+ // ✅ 正确
44
+ .risk-card {
45
+ background: var(--el-bg-color);
46
+ border-radius: var(--el-border-radius-base);
47
+ color: var(--el-text-color-primary);
48
+
49
+ &__header { ... }
50
+ &__body { ... }
51
+ &--active { border-color: var(--el-color-primary); }
52
+ }
53
+
54
+ // ❌ 禁止
55
+ .risk-card {
56
+ background: #fff; // 硬编码颜色
57
+ color: rgba(0, 0, 0, 0.85); // 硬编码
58
+ }
59
+ ```
@@ -0,0 +1,111 @@
1
+ # 规范 01:表格列(el-table-column / ag-grid)
2
+
3
+ ## 适用组件
4
+ - `<el-table-column>` (Element Plus)
5
+ - AG Grid 列定义(`defineColumns` + `COLUMN_AUTO_MAP`)
6
+
7
+ ---
8
+
9
+ ## 规则 R001:所有列必须居中对齐
10
+
11
+ ```vue
12
+ <!-- ❌ 错误:缺少 align -->
13
+ <el-table-column label="状态" prop="status" />
14
+
15
+ <!-- ✅ 正确 -->
16
+ <el-table-column label="状态" prop="status" align="center" />
17
+ ```
18
+
19
+ **例外**:内容为长文本描述(如"备注"、"标准内容")的列可使用 `align="left"`,但需显式标注,不可省略。
20
+
21
+ ---
22
+
23
+ ## 规则 R002:el-table 必须设置 empty-text
24
+
25
+ ```vue
26
+ <!-- ❌ 错误:缺少 empty-text -->
27
+ <el-table :data="list">
28
+
29
+ <!-- ✅ 正确 -->
30
+ <el-table :data="list" empty-text="暂无数据">
31
+ ```
32
+
33
+ ---
34
+
35
+ ## 规则 R004:操作列使用 renderOps / jh-op-btn
36
+
37
+ 操作列按钮**不得**直接使用 `<el-button>` 或裸文本,必须通过 `renderOps` 渲染:
38
+
39
+ ```typescript
40
+ // ✅ AG Grid defineColumns 方式
41
+ import { renderOps } from '@/components/ag-cell-renders'
42
+
43
+ defineColumns([
44
+ // ...
45
+ {
46
+ field: 'ops',
47
+ headerName: '操作',
48
+ cellRenderer: (p) => renderOps(p, [
49
+ { label: '修改', type: 'primary', show: (row) => row.status === 1 },
50
+ { label: '作废', type: 'danger', show: (row) => row.status === 1 },
51
+ { label: '删除', type: 'danger', show: (row) => row.status === 0 },
52
+ ]),
53
+ },
54
+ ])
55
+ ```
56
+
57
+ ```vue
58
+ <!-- ✅ el-table 方式 -->
59
+ <el-table-column label="操作" align="center" width="120">
60
+ <template #default="{ row }">
61
+ <span class="jh-op-btn primary" @click="handleEdit(row)">修改</span>
62
+ <span class="jh-op-btn danger" @click="handleVoid(row)" v-if="row.status === 1">作废</span>
63
+ </template>
64
+ </el-table-column>
65
+ ```
66
+
67
+ ---
68
+
69
+ ## 规则 R009:选择列宽度标准
70
+
71
+ | 列类型 | 宽度 |
72
+ |-------------|----------|
73
+ | 序号列 (index) | 60px |
74
+ | 多选列 (selection) | 55px |
75
+ | 普通固定列 | 按内容估算,最小 80px |
76
+
77
+ ---
78
+
79
+ ## 状态列固定右侧 + 色块渲染
80
+
81
+ ```typescript
82
+ // ✅ 状态映射 + 渲染函数(文件顶部定义)
83
+ const STATUS_TAG_MAP: Record<string, { label: string; type: '' | 'success' | 'warning' | 'danger' | 'info' }> = {
84
+ '0': { label: '停用', type: 'danger' },
85
+ '1': { label: '启用', type: 'success' },
86
+ }
87
+
88
+ function renderStatusTag(val: string) {
89
+ const cfg = STATUS_TAG_MAP[val]
90
+ if (!cfg) return ''
91
+ return h(ElTag, { type: cfg.type }, { default: () => cfg.label })
92
+ }
93
+ ```
94
+
95
+ ```typescript
96
+ // ✅ defineColumns 中引用
97
+ { field: 'enableStatus', headerName: '启用状态', pinned: 'right', defaultSlot: renderStatusTag }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## COLUMN_AUTO_MAP 自动配置
103
+
104
+ `defineColumns` 会根据 `COLUMN_AUTO_MAP` 自动为以下字段设置标准格式:
105
+
106
+ | field 包含关键字 | 自动效果 |
107
+ |----------------|---------|
108
+ | `checkNo` | renderBadge 徽章渲染 |
109
+ | `level`, `classify` | renderClassifyTag 分级渲染 |
110
+ | `status` | 提示需自定义 renderStatusTag |
111
+ | `createTime`, `updateTime` | 宽度 160px |
@@ -0,0 +1,83 @@
1
+ # 规范 02:按钮
2
+
3
+ ## 工具栏按钮(列表页顶部)
4
+
5
+ ### 顺序规则
6
+ 1. **新增/新增申请**类按钮永远排第一
7
+ 2. 其余按钮按照操作频次降序排列
8
+
9
+ ### 类型规则
10
+
11
+ | 操作语义 | type | plain | 说明 |
12
+ |----------|-------------|--------|----------------|
13
+ | 新增/添加 | `primary` | false | 蓝色填充 |
14
+ | 导入 | `primary` | true | 蓝色线框 |
15
+ | 导出 | `success` | true | 绿色线框 |
16
+ | 删除/作废 | `danger` | false | 红色填充(批量操作慎用)|
17
+ | 审批/提交 | `primary` | false | 蓝色填充 |
18
+ | 重置/取消 | `default` | false | 默认灰色 |
19
+
20
+ ```vue
21
+ <!-- ✅ 工具栏按钮组 -->
22
+ <el-button type="primary" @click="handleCreate">新增</el-button>
23
+ <el-button type="primary" plain @click="handleImport">导入</el-button>
24
+ <el-button type="success" plain @click="handleExport">导出</el-button>
25
+ ```
26
+
27
+ ---
28
+
29
+ ## 操作列按钮(表格行内)
30
+
31
+ 使用 `jh-op-btn` 类,**禁止** `<el-button>` 在行内使用:
32
+
33
+ ```vue
34
+ <!-- ❌ 错误 -->
35
+ <el-button type="text" @click="handleEdit(row)">编辑</el-button>
36
+
37
+ <!-- ✅ 正确 -->
38
+ <span class="jh-op-btn primary" @click="handleEdit(row)">修改</span>
39
+ <span class="jh-op-btn danger" @click="handleVoid(row)">作废</span>
40
+ ```
41
+
42
+ ### 按钮标签严格对应原型
43
+
44
+ | 操作 | 正确标签 | 禁止替换为 |
45
+ |--------|---------|----------|
46
+ | 修改记录 | **修改** | ~~编辑~~ |
47
+ | 软删除 | **作废** | ~~删除~~ |
48
+ | 硬删除 | **删除** | ~~移除~~ |
49
+
50
+ ### 条件显示(不同状态不同按钮)
51
+
52
+ ```typescript
53
+ // ✅ renderOps 中用 show 控制
54
+ renderOps(p, [
55
+ { label: '修改', type: 'primary', show: (row) => row.status === 1 },
56
+ { label: '作废', type: 'danger', show: (row) => row.status === 1 },
57
+ { label: '编辑', type: 'primary', show: (row) => row.status === 0 },
58
+ { label: '删除', type: 'danger', show: (row) => row.status === 0 },
59
+ ])
60
+ ```
61
+
62
+ ---
63
+
64
+ ## 弹窗底部按钮(对话框)
65
+
66
+ ```vue
67
+ <!-- ✅ 标准:取消在左,确认在右;footer 右对齐 -->
68
+ <template #footer>
69
+ <div class="dialog-footer">
70
+ <el-button @click="handleClose">取 消</el-button>
71
+ <el-button type="primary" @click="handleConfirm">确 认</el-button>
72
+ </div>
73
+ </template>
74
+ ```
75
+
76
+ CSS 全局保证 footer 右对齐(已在 `dist/style-override.scss` 中定义):
77
+ ```scss
78
+ .el-dialog__footer .dialog-footer {
79
+ display: flex;
80
+ justify-content: flex-end;
81
+ gap: 8px;
82
+ }
83
+ ```
@@ -0,0 +1,118 @@
1
+ # 规范 03:表单(el-form)
2
+
3
+ ## 规则 R008:labelWidth 统一使用 150px
4
+
5
+ 中文标签最长 9 字(如"隐患排查内容及标准"),需要 150px 才不截断:
6
+
7
+ ```vue
8
+ <!-- ❌ 错误:100px 会截断9字标签 -->
9
+ <el-form :model="form" label-width="100px">
10
+
11
+ <!-- ✅ 正确 -->
12
+ <el-form :model="form" label-width="150px">
13
+ ```
14
+
15
+ ---
16
+
17
+ ## 规则 R006:el-input / el-select 必须加 size="small"
18
+
19
+ 系统统一使用 small 尺寸,与表格行高匹配:
20
+
21
+ ```vue
22
+ <!-- ❌ 错误 -->
23
+ <el-input v-model="form.name" />
24
+ <el-select v-model="form.type">
25
+
26
+ <!-- ✅ 正确 -->
27
+ <el-input v-model="form.name" size="small" />
28
+ <el-select v-model="form.type" size="small">
29
+ ```
30
+
31
+ ---
32
+
33
+ ## 规则 R007:el-date-picker 必须加 style="width:100%"
34
+
35
+ date-picker 默认宽度固定,在 grid 布局中需撑满列宽:
36
+
37
+ ```vue
38
+ <!-- ❌ 错误 -->
39
+ <el-date-picker v-model="form.date" type="date" />
40
+
41
+ <!-- ✅ 正确 -->
42
+ <el-date-picker v-model="form.date" type="date" style="width:100%" />
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 布局标准
48
+
49
+ ### 搜索区(列表页顶部)
50
+
51
+ ```vue
52
+ <el-form :inline="true" :model="queryForm" size="small">
53
+ <el-form-item label="关键词">
54
+ <el-input v-model="queryForm.keyword" size="small" placeholder="请输入" />
55
+ </el-form-item>
56
+ <el-form-item label="状态">
57
+ <el-select v-model="queryForm.status" size="small" placeholder="请选择" clearable>
58
+ <el-option label="启用" :value="1" />
59
+ <el-option label="停用" :value="0" />
60
+ </el-select>
61
+ </el-form-item>
62
+ <el-form-item>
63
+ <el-button type="primary" size="small" @click="handleSearch">搜索</el-button>
64
+ <el-button size="small" @click="handleReset">重置</el-button>
65
+ </el-form-item>
66
+ </el-form>
67
+ ```
68
+
69
+ ### 弹窗表单(新增/修改)
70
+
71
+ ```vue
72
+ <el-form
73
+ ref="formRef"
74
+ :model="form"
75
+ :rules="rules"
76
+ label-width="150px"
77
+ >
78
+ <el-row :gutter="20">
79
+ <el-col :span="12">
80
+ <el-form-item label="名称" prop="name">
81
+ <el-input v-model="form.name" size="small" />
82
+ </el-form-item>
83
+ </el-col>
84
+ <el-col :span="12">
85
+ <el-form-item label="日期" prop="date">
86
+ <el-date-picker
87
+ v-model="form.date"
88
+ type="date"
89
+ style="width:100%"
90
+ size="small"
91
+ />
92
+ </el-form-item>
93
+ </el-col>
94
+ </el-row>
95
+ </el-form>
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 复杂表单判断
101
+
102
+ | 条件 | 方案 |
103
+ |-----|------|
104
+ | 字段 ≤ 15,无子表 | 弹窗(`el-dialog`) |
105
+ | 字段 > 15,或含多个子表 | 独立路由页(`/xxx-form`) |
106
+ | Tab > 3 个 | 独立路由页 |
107
+
108
+ ---
109
+
110
+ ## 校验规则命名
111
+
112
+ ```typescript
113
+ const rules = {
114
+ name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
115
+ type: [{ required: true, message: '请选择类型', trigger: 'change' }],
116
+ date: [{ required: true, message: '请选择日期', trigger: 'change' }],
117
+ }
118
+ ```