@brms/ai-skills 0.1.0

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 (90) hide show
  1. package/README.md +256 -0
  2. package/bin/brms-skills.mjs +411 -0
  3. package/package.json +30 -0
  4. package/skills/brms-prototype-generator/SKILL.md +129 -0
  5. package/skills/brms-prototype-generator/agents/openai.yaml +7 -0
  6. package/skills/brms-prototype-generator/examples/few-shot-examples.md +577 -0
  7. package/skills/brms-prototype-generator/references/01-list-query.md +444 -0
  8. package/skills/brms-prototype-generator/references/02-form-entry.md +129 -0
  9. package/skills/brms-prototype-generator/references/03-detail-display.md +125 -0
  10. package/skills/brms-prototype-generator/references/04-composite-page-package.md +339 -0
  11. package/skills/brms-prototype-generator/references/05-dialog-patterns.md +113 -0
  12. package/skills/brms-prototype-generator/references/06-backend-request-patterns.md +118 -0
  13. package/skills/brms-prototype-generator/references/resource-index.md +46 -0
  14. package/skills/brms-prototype-generator/references/system-prompt.md +242 -0
  15. package/skills/brms-prototype-generator/scripts/analyze-doc.mjs +554 -0
  16. package/skills/brms-prototype-generator/scripts/check-project.mjs +228 -0
  17. package/skills/brms-prototype-generator/scripts/discover-targets.mjs +158 -0
  18. package/skills/brms-prototype-generator/scripts/install-codex.mjs +74 -0
  19. package/skills/brms-prototype-generator/scripts/plan-pages.mjs +390 -0
  20. package/skills/brms-prototype-generator/scripts/validate-generated.mjs +838 -0
  21. package/skills/brms-prototype-generator/templates/user-input-template.md +182 -0
  22. package/skills/brms-vxe-plus-developer/SKILL.md +105 -0
  23. package/skills/brms-vxe-plus-developer/agents/openai.yaml +7 -0
  24. package/skills/brms-vxe-plus-developer/references/prototype-to-real.md +54 -0
  25. package/skills/brms-vxe-plus-developer/references/real-base-development.md +110 -0
  26. package/skills/brms-vxe-plus-developer/references/resource-index.md +43 -0
  27. package/skills/brms-vxe-plus-developer/references/review-checklist.md +49 -0
  28. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/01-mental-model.md +150 -0
  29. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/02-vxe-plus-form.md +302 -0
  30. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/03-vxe-plus-table.md +253 -0
  31. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/04-example-map.md +488 -0
  32. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/05-request-and-eiinfo.md +170 -0
  33. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/90-anti-patterns.md +137 -0
  34. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/README.md +43 -0
  35. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/README.md +21 -0
  36. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/A1/P0/A1P01601.vue +483 -0
  37. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/A1/P1/A1P11011.vue +444 -0
  38. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/AB/BP/ABBP0201.vue +1648 -0
  39. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/AM/AF/component/AMAF0601/Bidding/formConfig.ts +228 -0
  40. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/AM/AF/component/AMAF0601/Record/columns.ts +110 -0
  41. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/BM/BR/BMBR01.vue +130 -0
  42. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/BM/BR/component/BMBR01/columns.ts +94 -0
  43. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/BM/BR/component/BMBR01/formConfig.ts +108 -0
  44. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Change/formConfig.ts +123 -0
  45. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Change/index.vue +103 -0
  46. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Clause/columns.ts +48 -0
  47. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Clause/index.vue +202 -0
  48. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Correcte/formConfig.ts +117 -0
  49. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Correcte/index.vue +103 -0
  50. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Pay/Payment/formConfig.ts +90 -0
  51. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Pay/Payment/index.vue +42 -0
  52. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Pay/columns.ts +376 -0
  53. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Pay/index.vue +619 -0
  54. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/Domestic/formConfig.ts +73 -0
  55. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/Domestic/index.vue +47 -0
  56. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/Foreign/formConfig.ts +141 -0
  57. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/Foreign/index.vue +42 -0
  58. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/columns.ts +123 -0
  59. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/Settle/index.vue +593 -0
  60. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Explain/index.vue +68 -0
  61. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Fee/columns.ts +150 -0
  62. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Fee/index.vue +235 -0
  63. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Files/columns.ts +63 -0
  64. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Files/index.vue +117 -0
  65. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Goods/columns.ts +327 -0
  66. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Goods/index.vue +790 -0
  67. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Approve/formConfig.ts +341 -0
  68. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Approve/index.vue +63 -0
  69. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Approve2/formConfig.ts +232 -0
  70. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Approve2/index.vue +27 -0
  71. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Diff/columns.ts +46 -0
  72. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/Diff/index.vue +92 -0
  73. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/formConfig.ts +979 -0
  74. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Base/index.vue +62 -0
  75. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Other/formConfig.ts +179 -0
  76. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Other/index.vue +140 -0
  77. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Sign/formConfig.ts +118 -0
  78. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/Sign/index.vue +44 -0
  79. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Main/index.vue +168 -0
  80. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Party/Major/formConfig.ts +257 -0
  81. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Party/Major/index.vue +47 -0
  82. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Party/columns.ts +256 -0
  83. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Party/index.vue +738 -0
  84. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Price/formConfig.ts +174 -0
  85. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Price/index.vue +51 -0
  86. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/PM/PC/component/PMPC0101/Top/index.vue +924 -0
  87. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/SM/SW/SMSW0101.vue +567 -0
  88. package/skills/brms-vxe-plus-developer/references/vxe-plus-knowledge/sources/project/base/src/views/demo/index.vue +448 -0
  89. package/skills/brms-vxe-plus-developer/scripts/check-project.mjs +259 -0
  90. package/skills/brms-vxe-plus-developer/scripts/check-vxe-plus-page.mjs +137 -0
@@ -0,0 +1,444 @@
1
+ # 列表查询页模式
2
+
3
+ 最常用的页面模式:双卡片布局(查询条件卡片 + 结果表格卡片)。
4
+
5
+ ## 适用场景
6
+
7
+ - 数据管理和浏览(用户列表、订单列表)
8
+ - 带增删改查的标准 CRUD 页面
9
+ - 审批待办/已办列表
10
+ - 任何"筛选 → 浏览"的数据页面
11
+
12
+ ## 标准结构(双卡片模式)
13
+
14
+ ```
15
+ div.flex-col.flex.h-full
16
+ └── BxRoundedContainer ← 卡片1:查询条件
17
+ ├── BxContainer(title="查询条件") ← 卡片标题
18
+ └── VxePlusForm(:form-options) ← 查询表单
19
+ └── BxRoundedContainer.flex-1.flex.flex-col ← 卡片2:结果表格(flex-1 占满剩余空间)
20
+ ├── BxContainer.flex-initial(title="结果集") ← 卡片标题
21
+ └── VxePlusTable.flex-1(...) ← 数据表格
22
+ ```
23
+
24
+ **关键 CSS 类:**
25
+
26
+ - 最外层 `flex-col flex h-full` — 纵向 flex,撑满高度
27
+ - 查询卡片不加 `flex-1` — 避免挤压结果表格
28
+ - 结果卡片 `flex-1 flex flex-col` — 占据剩余空间
29
+ - 结果标题 `flex-initial` — 不参与伸缩
30
+ - 表格 `flex-1` — 占据卡片剩余空间
31
+
32
+ ## 生成硬规则
33
+
34
+ - 查询/重置按钮只出现在查询卡片标题:`<BxContainer title="查询条件" custom-btn-auto ... />`。
35
+ - 结果表格标题只显示标题,不放新增/编辑/删除按钮,不使用 `custom-btn-auto`。
36
+ - 不生成操作列。不要创建 `action` / `operation` / `operate` / `操作` 列,也不要依赖 `actions` 配置。
37
+ - 新增、编辑、删除、批量删除等表格动作统一使用 `VxePlusTable :toolbar-buttons="toolbarButtons"` 和 `toolbarButtonClick`,避免标题栏和表格工具栏重复生成按钮。
38
+ - 只有产品文档明确要求“标题栏区块按钮”且该按钮不是表格新增/编辑/删除动作时,才允许使用结果区 `BxContainer :custom-btn-list`。
39
+ - 需要单行“查看详情/查看矿权”时,优先让业务字段使用 `tableLink` 可点击;不要新增操作列。不要用 `cell-click` 作为默认编辑入口。
40
+ - 不在 `createColumns` 中生成 `{ type: 'checkbox' }`。需要勾选时在表格组件上设置 `:show-checkbox="true"`。
41
+ - 普通数据列默认使用 `useTable().createColumns([...], { width: undefined })` 让列自动撑开;只给序号、状态、短数字等列显式 `width`。
42
+ - 同一个表格只能选择一种编辑模式:行编辑或弹窗编辑,不能混用。
43
+
44
+ ## 变体
45
+
46
+ ### 变体 A:纯列表(无 tabs)
47
+
48
+ 最基础模式。参考 `demo/list.vue`。适合单数据源的简单列表。
49
+
50
+ ### 变体 B:Tab 切换列表
51
+
52
+ 参考 `BMBF11.vue`。适合同时展示多组数据(如待办 + 已办)。
53
+
54
+ **特征:**
55
+
56
+ - 在结果卡片内用 `vxe-tabs` 包裹多个 `VxePlusTable`
57
+ - 默认使用本地 mock 数据;只有产品文档明确给出 serviceName/methodName 时才使用 `serviceConfig`
58
+ - 共用同一个 formData
59
+
60
+ ### 变体 C:行编辑列表
61
+
62
+ 适合需要行内编辑的列表。
63
+
64
+ **特征:**
65
+
66
+ - `VxePlusTable` 设置 `:is-edit="true"` 和 `toolbarButtons`
67
+ - 可编辑字段在 `createColumns` 中配置 `editRender`
68
+ - `toolbarButtonClick` 中调用 `$grid.insertAt({})` 新增行
69
+ - 保存/删除/校验围绕 `$grid` 当前数据和勾选数据处理
70
+ - 不生成 `vxe-modal` 编辑弹窗,不生成 `handleEdit(row)` 打开弹窗
71
+
72
+ ### 变体 D:弹窗编辑列表
73
+
74
+ 适合新增/编辑字段较多、需要独立表单校验或分组排版的列表。
75
+
76
+ **特征:**
77
+
78
+ - `VxePlusTable` 不设置 `:is-edit="true"`
79
+ - 普通数据列不配置 `editRender`
80
+ - 新增/编辑/删除入口放在 `toolbarButtons` 和 `toolbarButtonClick`
81
+ - 新增/编辑打开 `vxe-modal + VxePlusForm :form-options`
82
+ - 编辑已选行时从 `$grid.getCheckboxRecords()` 或当前行取数据;不要通过 `cell-click` 暗中打开编辑弹窗
83
+
84
+ ## 关键代码骨架
85
+
86
+ ### 查询表单
87
+
88
+ ```ts
89
+ const formData = reactive({
90
+ field1Like: '',
91
+ field2: '',
92
+ dateBegin: '',
93
+ dateEnd: '',
94
+ });
95
+
96
+ const formOption = reactive({
97
+ id: 'inqu_status',
98
+ data: formData,
99
+ items: [
100
+ { field: 'field1Like', title: '字段1', itemRender: { name: 'VxeInput' } },
101
+ {
102
+ field: 'field2',
103
+ title: '字段2',
104
+ itemRender: { name: 'formSelect', props: { codeSet: 'XXX.query' } },
105
+ },
106
+ {
107
+ field: 'dateRange',
108
+ title: '日期范围',
109
+ itemRender: {
110
+ name: 'dateRange',
111
+ props: { startDate: 'dateBegin', endDate: 'dateEnd', type: 'date' },
112
+ },
113
+ },
114
+ ],
115
+ });
116
+ ```
117
+
118
+ ### 表格列定义
119
+
120
+ 普通列表/弹窗编辑列表的列默认只展示数据:
121
+
122
+ ```ts
123
+ const columns = useTable().createColumns(
124
+ [
125
+ { type: 'seq', width: 60, fixed: 'left' },
126
+ { field: 'col1', title: '列1' },
127
+ { field: 'col2', title: '列2' },
128
+ {
129
+ field: 'projectName',
130
+ title: '项目名称',
131
+ cellRender: {
132
+ name: 'tableLink',
133
+ props: { linkClick: row => router.push({ path: '/web/DMDA02', query: { id: row.id } }) },
134
+ },
135
+ },
136
+ ],
137
+ { width: undefined },
138
+ );
139
+ ```
140
+
141
+ 行编辑列表才使用 `editRender`:
142
+
143
+ ```ts
144
+ const columns = useTable().createColumns(
145
+ [
146
+ { type: 'seq', width: 60, fixed: 'left' },
147
+ { field: 'col1', title: '列1', editRender: { name: 'VxeInput' } },
148
+ {
149
+ field: 'col3',
150
+ title: '列3(下拉编辑)',
151
+ editRender: { name: 'tableSelect', props: { codeSet: 'XXX' } },
152
+ },
153
+ ],
154
+ { width: undefined },
155
+ );
156
+ ```
157
+
158
+ ## 编辑模式选择
159
+
160
+ ### 行编辑
161
+
162
+ Use when the product doc describes inline maintenance, batch row editing, editable grids, or spreadsheet-like input.
163
+
164
+ Required table shape:
165
+
166
+ ```vue
167
+ <VxePlusTable
168
+ id="DMDA01_result"
169
+ ref="gridRef"
170
+ :columns="columns"
171
+ :data="rows"
172
+ :is-edit="true"
173
+ :edit-rules="editRules"
174
+ :toolbar-buttons="toolbarButtons"
175
+ :show-checkbox="true"
176
+ v-on="gridEvents"
177
+ />
178
+ ```
179
+
180
+ Renderer selection for row edit:
181
+
182
+ - text/input cells: `editRender: { name: 'VxeInput' }`
183
+ - select cells: `editRender: { name: 'tableSelect', props: { options: [] } }` or `codeSet`
184
+ - date cells: `editRender: { name: 'VxeDatePicker', props: { type: 'date' } }`
185
+ - dialog selector cells: `editRender: { name: 'tableSelectDialog', props: { component, fields, dialogFields } }`
186
+
187
+ ### 弹窗编辑
188
+
189
+ Use when add/edit has a separate form, grouped fields, conditional fields, or confirmation flow.
190
+
191
+ Required table shape:
192
+
193
+ ```vue
194
+ <VxePlusTable
195
+ id="DMDA01_result"
196
+ ref="gridRef"
197
+ :columns="columns"
198
+ :data="rows"
199
+ :toolbar-buttons="toolbarButtons"
200
+ :show-checkbox="true"
201
+ v-on="gridEvents"
202
+ />
203
+ ```
204
+
205
+ Rules:
206
+
207
+ - Do not set `:is-edit="true"`.
208
+ - Do not add `editRender` to normal data columns.
209
+ - Use `vxe-modal + VxePlusForm :form-options` for the edit form.
210
+ - Open the modal from `toolbarButtonClick`, explicit `handleEdit(row)`, or `tableLink` on a business field.
211
+ - Do not use `@cell-click`, `cellClick`, or `handleCellClick` to open the edit modal.
212
+
213
+ Renderer selection for popup forms:
214
+
215
+ - text/input fields: `itemRender: { name: 'VxeInput' }`
216
+ - select fields: `itemRender: { name: 'formSelect', props: { options: [] } }` or `codeSet`
217
+ - date range query fields: `itemRender: { name: 'dateRange', props: { startDate, endDate, type: 'date' } }`
218
+ - dialog selector fields: `itemRender: { name: 'formSelectDialog', props: { component, fields, dialogFields } }`
219
+
220
+ ### Mock 数据和接口占位
221
+
222
+ ```ts
223
+ // @brms-mock-data product-doc: list seed rows, remove after ServiceName.query is wired
224
+ const mockRows: RowVO[] = [];
225
+
226
+ // @brms-mock-data product-doc: visible table rows derived from mockRows
227
+ const rows = ref<RowVO[]>(mockRows);
228
+
229
+ // @brms-mock-handler product-doc: local list query, replace with ServiceName.query
230
+ async function queryList() {
231
+ // TODO: 接入后台查询接口
232
+ ElMessage.info('TODO: 接入后台接口');
233
+ rows.value = mockRows.filter((row) => matchesQuery(row, formData));
234
+ }
235
+
236
+ // @brms-mock-handler product-doc: local row save, replace with ServiceName.save
237
+ async function saveRow(row: RowVO) {
238
+ // TODO: 接入后台保存接口
239
+ ElMessage.info('TODO: 接入后台接口');
240
+ upsertLocalRow(rows.value, row);
241
+ }
242
+
243
+ // @brms-mock-handler product-doc: local row delete, replace with ServiceName.delete
244
+ async function deleteRow(row: RowVO) {
245
+ // TODO: 接入后台删除接口
246
+ ElMessage.info('TODO: 接入后台接口');
247
+ rows.value = rows.value.filter((item) => item.id !== row.id);
248
+ }
249
+
250
+ // @brms-mock-handler product-doc: local mock filter helper, remove after backend query is wired
251
+ function matchesQuery(row: RowVO, query: typeof formData) {
252
+ return true;
253
+ }
254
+ ```
255
+
256
+ ### 明确接口时的 serviceConfig
257
+
258
+ 只有文档明确列出后台服务和方法时,才把表格从 `:data="rows"` 切换为 `:service-config="serviceConfig"`。生成前必须读取 `references/06-backend-request-patterns.md`。
259
+
260
+ ```ts
261
+ // @brms-explicit-interface product-doc: BMBF56.query/BMBF56.insert/BMBF56.save/BMBF56.delete
262
+ const formConfig = reactive({
263
+ id: 'inqu_status',
264
+ data: formData,
265
+ });
266
+
267
+ const serviceConfig = reactive({
268
+ serviceName: 'BMBF56',
269
+ queryMethod: 'query',
270
+ insertMethod: 'insert',
271
+ updateMethod: 'save',
272
+ deleteMethod: 'delete',
273
+ });
274
+ ```
275
+
276
+ ### 按钮配置
277
+
278
+ 列表页涉及两类按钮,分别在 BxContainer(搜索卡片标题栏)和 VxePlusTable(表格工具栏)。
279
+
280
+ ---
281
+
282
+ #### 1. 搜索卡片按钮 — BxContainer.customBtnAuto / customBtnList
283
+
284
+ **源码链路:** `bx-container-v2.vue` 的 `customBtnList` prop → `onMounted` 中先查后端权限按钮 `findBtnByPath(pageId)[containerId]`,无权限配置时 fallback 到 `customBtnList` 或内置默认按钮 → 渲染为 `el-button` → 点击 emit `btnClick({ name, code })`
285
+
286
+ **方式 A:customBtnAuto(推荐,自动生成查询/重置)**
287
+
288
+ ```vue
289
+ <BxContainer title="查询条件" custom-btn-auto @btn-click="handleSearchBtn" />
290
+ ```
291
+
292
+ `customBtnAuto` 自动生成两个按钮:
293
+
294
+ | nodeName | nodeCode | 说明 |
295
+ | -------- | -------- | ----------------------------------------- |
296
+ | 查询 | `QUERY` | 触发查询 |
297
+ | 重置 | `RESET` | 触发表单重置(`isReset` 为 false 时隐藏) |
298
+
299
+ **方式 B:customBtnList(自定义按钮列表)**
300
+
301
+ ```vue
302
+ <BxContainer title="查询条件" :custom-btn-list="searchBtnList" @btn-click="handleSearchBtn" />
303
+ ```
304
+
305
+ ```ts
306
+ const searchBtnList = [
307
+ { nodeName: '搜索', nodeCode: 'SEARCH' },
308
+ { nodeName: '导出', nodeCode: 'EXPORT' },
309
+ { nodeName: '清空', nodeCode: 'CLEAR' },
310
+ ];
311
+ ```
312
+
313
+ **CustomBtnItem 接口:**
314
+
315
+ ```ts
316
+ interface CustomBtnItem {
317
+ nodeName: string; // 按钮显示文本
318
+ nodeCode: string; // 按钮编码(emit 时作为 code 传出)
319
+ visible?: boolean; // 是否显示,默认 true
320
+ disabled?: boolean; // 是否禁用,默认 false
321
+ }
322
+ ```
323
+
324
+ **处理函数:**
325
+
326
+ ```ts
327
+ function handleSearchBtn({ code }: { code: string }) {
328
+ if (code === 'QUERY') gridRef.value?.reload();
329
+ if (code === 'RESET') formRef.value?.reset();
330
+ // 自定义按钮按 code 判断
331
+ }
332
+ ```
333
+
334
+ ---
335
+
336
+ #### 2. 表格工具栏按钮 — VxePlusTable.toolbarButtons
337
+
338
+ **源码链路:** `VxePlusTable` 的 `toolbarButtons` prop → `useToolbarConfig()` hook → 先查后端权限按钮 `findBtnByPath(pageId)['GRID:EF_GRID_${tableId}']` → 与 `props.toolbarButtons` concat 合并 → 按 `leftButtons` 拆分为左/右两组 → 由 `groupButtom` renderer 渲染 → 点击触发 vxe-grid 原生的 `toolbarButtonClick` 事件,payload 为 `{ code, $grid }`
339
+
340
+ > **注意:** toolbarButtons 定义在 `v-on="gridEvents"` 中通过 `toolbarButtonClick` 处理,不是 `@btn-click`。
341
+
342
+ ```vue
343
+ <VxePlusTable
344
+ :toolbar-buttons="toolbarButtons"
345
+ :show-checkbox="true"
346
+ :is-edit="true"
347
+ v-on="gridEvents"
348
+ />
349
+ ```
350
+
351
+ `show-checkbox` 会让表格组件生成勾选列,`createColumns` 中不要再写 `{ type: 'checkbox' }`。
352
+
353
+ ```ts
354
+ import type { VxeGridProps } from 'vxe-table';
355
+ import { ElMessage, ElMessageBox } from 'element-plus';
356
+ import to from 'await-to-js';
357
+
358
+ const toolbarButtons = ref<NonNullable<VxeGridProps['toolbarConfig']>['buttons']>([
359
+ { name: '新增', code: 'add', status: 'primary' },
360
+ { name: '删除', code: 'del', status: 'danger' },
361
+ { name: '导出', code: 'export', status: 'success' },
362
+ ]);
363
+
364
+ const gridEvents = {
365
+ toolbarButtonClick: async ({ code, $grid }: any) => {
366
+ if (code === 'add') {
367
+ // 新增行并进入编辑态
368
+ const { row: newRow } = await $grid.insertAt({});
369
+ $grid.setEditRow(newRow);
370
+ }
371
+ if (code === 'del') {
372
+ const rows = $grid.getCheckboxRecords();
373
+ if (rows.length === 0) {
374
+ ElMessage.warning('请先勾选要删除的记录');
375
+ return;
376
+ }
377
+ // 二次确认
378
+ const [err] = await to(
379
+ ElMessageBox.confirm('确定删除所选记录吗?', '提示', {
380
+ confirmButtonText: '确定',
381
+ cancelButtonText: '取消',
382
+ type: 'warning',
383
+ }),
384
+ );
385
+ if (err) return;
386
+ await $grid.remove(rows);
387
+ }
388
+ if (code === 'export') {
389
+ // 导出逻辑
390
+ }
391
+ },
392
+ };
393
+ ```
394
+
395
+ **ToolbarButton 接口:**
396
+
397
+ ```ts
398
+ interface ToolbarButton {
399
+ name: string; // 按钮显示文本
400
+ code: string; // 按钮编码(toolbarButtonClick 中作为 code 传出)
401
+ status?: string; // 按钮类型:'primary' | 'danger' | 'success' | 'warning' | ''
402
+ disabled?: boolean; // 是否禁用
403
+ visible?: boolean; // 是否显示
404
+ }
405
+ ```
406
+
407
+ **$grid 常用方法:**
408
+
409
+ | 方法 | 说明 |
410
+ | ---------------------------- | ------------------------ |
411
+ | `$grid.insertAt({})` | 插入新行,返回 `{ row }` |
412
+ | `$grid.setEditRow(row)` | 将指定行设为编辑态 |
413
+ | `$grid.getCheckboxRecords()` | 获取所有勾选行 |
414
+ | `$grid.remove(rows)` | 删除指定行 |
415
+ | `$grid.reload()` | 重新加载数据 |
416
+ | `$grid.getGridInstance()` | 获取底层 vxe-grid 实例 |
417
+
418
+ **## 关键规则:** 删除操作必须用 `ElMessageBox.confirm` 二次确认,并用 `await-to-js` 的 `to()` 包裹。
419
+
420
+ ### 表单-表格关联
421
+
422
+ ```ts
423
+ const formConfig = reactive({
424
+ id: 'inqu_status',
425
+ data: formData,
426
+ });
427
+ ```
428
+
429
+ ### 查询/重置按钮处理
430
+
431
+ 当 `BxContainer` 设置了 `customBtnAuto` 或 `customBtnList` 包含查询/重置按钮时:
432
+
433
+ ```ts
434
+ function handleBtnClick({ code }: { code: string }) {
435
+ if (code === 'QUERY') gridRef.value?.reload();
436
+ if (code === 'RESET') formRef.value?.reset();
437
+ }
438
+ ```
439
+
440
+ ## 参考文件
441
+
442
+ - **demo/list.vue**:优先使用目标项目内的 demo/list;没有时参考 `project/prototype/src/views/demo/list.vue` — 标准双卡片模式
443
+ - **BMBF11.vue**:`project/prototype/src/views/BM/BF/BMBF11.vue` — Tab 切换 + 双表格
444
+ - **demo/index.vue**:`project/prototype/src/views/demo/index.vue` — 可编辑 + 级联下拉 + 工具栏按钮
@@ -0,0 +1,129 @@
1
+ # 表单录入页模式
2
+
3
+ 数据录入/编辑页面模式:表单卡片 + 提交按钮。
4
+
5
+ 默认不接入真实后台。保存、查询详情等位置保留命名 async 方法,方法内写 TODO 注释、显示 `ElMessage.info('TODO: 接入后台接口')`,并读写本地 mock 数据。只有产品文档明确给出 serviceName/methodName 时,才按 `references/06-backend-request-patterns.md` 生成 `EiCommunicator.send` 请求。
6
+
7
+ Mock-only 保存、详情回填和本地数据 helper 必须写可搜索标记:`// @brms-mock-data <source-or-page>: <purpose>` 或 `// @brms-mock-handler <source-or-page>: <operation>`。不要只写普通 TODO。
8
+
9
+ ## 适用场景
10
+
11
+ - 新增记录
12
+ - 编辑记录
13
+ - 配置信息维护
14
+ - 任何"填写 → 保存"的数据录入
15
+
16
+ ## 标准结构
17
+
18
+ ```
19
+ div.flex-col.flex.h-full
20
+ └── BxRoundedContainer
21
+ ├── BxContainer(title="新增/编辑XXX")
22
+ ├── VxePlusForm(:form-options)
23
+ └── div(操作按钮区)
24
+ ├── el-button(保存)
25
+ └── el-button(取消)
26
+ ```
27
+
28
+ ## 关键代码骨架
29
+
30
+ ### 表单配置
31
+
32
+ ```ts
33
+ const formData = reactive({
34
+ code: '',
35
+ name: '',
36
+ type: '',
37
+ status: '1',
38
+ remark: '',
39
+ dateBegin: '',
40
+ dateEnd: '',
41
+ });
42
+
43
+ const formOption = reactive({
44
+ id: 'form_data',
45
+ data: formData,
46
+ items: [
47
+ { field: 'code', title: '编码', span: 12, itemRender: { name: 'VxeInput' } },
48
+ { field: 'name', title: '名称', span: 12, itemRender: { name: 'VxeInput' } },
49
+ {
50
+ field: 'type',
51
+ title: '类型',
52
+ span: 12,
53
+ itemRender: { name: 'formSelect', props: { codeSet: 'brmerp.common.type' } },
54
+ },
55
+ {
56
+ field: 'dateRange',
57
+ title: '有效日期',
58
+ span: 12,
59
+ itemRender: {
60
+ name: 'dateRange',
61
+ props: { startDate: 'dateBegin', endDate: 'dateEnd', type: 'date' },
62
+ },
63
+ },
64
+ { field: 'remark', title: '备注', span: 24, itemRender: { name: 'VxeInput' } },
65
+ ],
66
+ rules: {
67
+ code: [{ required: true, message: '请输入编码' }],
68
+ name: [{ required: true, message: '请输入名称' }],
69
+ },
70
+ });
71
+ ```
72
+
73
+ Required validation must live in `rules`, keyed by field. Do not use `titlePrefix: { content: '必填' }` for validation, and do not put `required: true` inside `items`; both patterns fail to enforce form validation in this wrapper.
74
+
75
+ ### 保存逻辑
76
+
77
+ ```ts
78
+ import { EiInfo, EiBlock } from '@eplat/ei';
79
+ import { ElMessage } from 'element-plus';
80
+ import to from 'await-to-js';
81
+
82
+ // @brms-mock-handler product-doc: local form save, replace with ServiceName.save
83
+ async function handleSave() {
84
+ const ei = new EiInfo();
85
+ ei.addBlock(EiBlock.build('form_data', [{ ...formData }]));
86
+
87
+ // TODO: 接入后台保存接口
88
+ ElMessage.info('TODO: 接入后台接口');
89
+ const [err] = await to(Promise.resolve(saveLocalForm(formData)));
90
+ if (err) {
91
+ ElMessage.error('保存失败');
92
+ return;
93
+ }
94
+ ElMessage.success('保存成功');
95
+ router.back();
96
+ }
97
+ ```
98
+
99
+ 如果保存接口明确,例如 `ServiceName.save`,则保留 `EiInfo` 组包并调用真实方法,同时在文件中添加 `// @brms-explicit-interface product-doc: ServiceName.save`。接口不明确时不要生成 `EiCommunicator.send`。
100
+
101
+ ### 编辑回填
102
+
103
+ ```ts
104
+ // @brms-mock-data product-doc: local detail seed rows for edit backfill
105
+ const mockDetailRows: FormVO[] = [];
106
+
107
+ // @brms-mock-handler product-doc: local detail backfill, replace with ServiceName.queryDetail
108
+ onMounted(async () => {
109
+ if (!route.query.id) return;
110
+
111
+ const ei = new EiInfo();
112
+ ei.set('id', route.query.id);
113
+
114
+ // TODO: 接入后台详情接口
115
+ ElMessage.info('TODO: 接入后台接口');
116
+ const [err, res] = await to(Promise.resolve(queryLocalDetail(id)));
117
+ if (err) return;
118
+
119
+ const row = res.getBlock('result').getMappedRows()[0];
120
+ Object.assign(formData, row);
121
+ });
122
+ ```
123
+
124
+ 如果详情接口明确,例如 `ServiceName.queryDetail`,可用 `EiCommunicator.send('ServiceName', 'queryDetail', ei)` 回填表单;否则继续从本地 mock 查询。
125
+
126
+ ## 参考文件
127
+
128
+ - **demo/list.vue**:`project/prototype/src/views/demo/list.vue` — 双卡片布局参考
129
+ - **demo/index.vue**:`project/prototype/src/views/demo/index.vue` — formOption.items 各种字段类型示例
@@ -0,0 +1,125 @@
1
+ # 详情展示页模式
2
+
3
+ 只读详情展示页面:主表信息 + 子表数据。
4
+
5
+ 默认不接入真实后台。详情加载位置保留命名 async 方法,方法内写 TODO 注释、显示 `ElMessage.info('TODO: 接入后台接口')`,并从本地 mock 数据中读取详情和子表。只有产品文档明确给出详情/子表查询 serviceName 和 methodName 时,才按 `references/06-backend-request-patterns.md` 生成 `EiCommunicator.send` 请求。
6
+
7
+ Mock-only 详情数据、子表数据和本地加载方法必须写可搜索标记:`// @brms-mock-data <source-or-page>: <purpose>` 或 `// @brms-mock-handler <source-or-page>: <operation>`。不要只写普通 TODO。
8
+
9
+ ## 适用场景
10
+
11
+ - 查看单据详情
12
+ - 审批详情页(只读数据 + 审批操作)
13
+ - 主-子表结构展示
14
+ - 任何"查看"而非"编辑"的场景
15
+
16
+ ## 标准结构
17
+
18
+ ```
19
+ div.flex-col.flex.h-full
20
+ └── BxRoundedContainer
21
+ ├── BxContainer(title="XXX详情")
22
+ ├── VxePlusForm(:form-options) ← 只读信息
23
+ ├── VxePlusTable(:columns, :data) ← 子表数据
24
+ └── div(操作按钮)
25
+ └── el-button(返回)
26
+ ```
27
+
28
+ ## 只读信息展示方式
29
+
30
+ ### 方式 A:el-descriptions(推荐)
31
+
32
+ 适合字段较少的只读信息:
33
+
34
+ ```vue
35
+ <el-descriptions :column="3" border>
36
+ <el-descriptions-item label="编码">{{ detailData.code }}</el-descriptions-item>
37
+ <el-descriptions-item label="名称">{{ detailData.name }}</el-descriptions-item>
38
+ <el-descriptions-item label="状态">
39
+ <el-tag :type="detailData.status === '1' ? 'success' : 'info'">
40
+ {{ detailData.status === '1' ? '启用' : '停用' }}
41
+ </el-tag>
42
+ </el-descriptions-item>
43
+ </el-descriptions>
44
+ ```
45
+
46
+ ### 方式 B:VxePlusForm
47
+
48
+ 适合字段较多的只读表单:
49
+
50
+ ```ts
51
+ const formData = reactive({
52
+ code: '',
53
+ name: '',
54
+ type: '',
55
+ status: '',
56
+ createTime: '',
57
+ creator: '',
58
+ });
59
+
60
+ const formOption = reactive({
61
+ id: 'detail_data',
62
+ data: formData,
63
+ items: [
64
+ { field: 'code', title: '编码', span: 8, itemRender: { name: 'VxeInput' } },
65
+ { field: 'name', title: '名称', span: 8, itemRender: { name: 'VxeInput' } },
66
+ { field: 'type', title: '类型', span: 8, itemRender: { name: 'VxeInput' } },
67
+ { field: 'status', title: '状态', span: 8, itemRender: { name: 'VxeInput' } },
68
+ { field: 'createTime', title: '创建时间', span: 8, itemRender: { name: 'VxeInput' } },
69
+ { field: 'creator', title: '创建人', span: 8, itemRender: { name: 'VxeInput' } },
70
+ ],
71
+ });
72
+ ```
73
+
74
+ 如果详情接口明确,在文件中添加 `// @brms-explicit-interface product-doc: ServiceName.queryDetail`,并只对已明确的方法发起真实请求;未明确的子表或审批动作继续使用 mock。
75
+
76
+ ## 数据加载
77
+
78
+ ```ts
79
+ // @brms-mock-data product-doc: local detail and child-table seed data
80
+ const mockDetailRows: DetailVO[] = [];
81
+
82
+ // @brms-mock-handler product-doc: local detail load, replace with ServiceName.queryDetail
83
+ onMounted(async () => {
84
+ const ei = new EiInfo();
85
+ ei.set('id', route.query.id);
86
+
87
+ // TODO: 接入后台详情接口
88
+ ElMessage.info('TODO: 接入后台接口');
89
+ const [err, res] = await to(Promise.resolve(queryLocalDetail(id)));
90
+ if (err) return;
91
+
92
+ // 主表数据
93
+ const mainRow = res.getBlock('main').getMappedRows()[0];
94
+ Object.assign(formData, mainRow);
95
+
96
+ // 子表数据
97
+ childData.value = res.getBlock('details').getMappedRows();
98
+ });
99
+ ```
100
+
101
+ ## 审批详情变体
102
+
103
+ ```vue
104
+ <div class="flex-col flex h-full">
105
+ <BxRoundedContainer>
106
+ <BxContainer title="业务信息" />
107
+ <VxePlusForm :form-options="detailFormOption" />
108
+ </BxRoundedContainer>
109
+
110
+ <BxRoundedContainer>
111
+ <BxContainer title="审批意见" />
112
+ <vxe-textarea v-model="opinion" placeholder="请输入审批意见" />
113
+ </BxRoundedContainer>
114
+
115
+ <div class="flex justify-center gap-4 py-4">
116
+ <el-button type="success" @click="approve">通过</el-button>
117
+ <el-button type="danger" @click="reject">驳回</el-button>
118
+ </div>
119
+ </div>
120
+ ```
121
+
122
+ ## 参考文件
123
+
124
+ - **BMBF10.vue**:`project/prototype/src/views/BM/BF/BMBF10.vue` — 审批详情 + 动态组件
125
+ - **BMBF10V6.vue**:`project/prototype/src/views/BM/BF/BMBF10V6.vue` — V6 版本审批详情