worsoft-frontend-codegen-local-mcp 0.1.84 → 0.1.88
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.
- package/README.md +49 -12
- package/assets/style-catalog.json +46 -0
- package/assets/templates/ledger_master_child_jump/api.tpl +2 -2
- package/assets/templates/ledger_master_child_jump/form.tpl +1 -1
- package/assets/templates/ledger_master_child_jump/index.tpl +50 -18
- package/assets/templates/ledger_master_child_jump/menu.sql.tpl +10 -7
- package/assets/templates/ledger_single_table_jump/api.tpl +2 -2
- package/assets/templates/ledger_single_table_jump/index.tpl +49 -17
- package/assets/templates/ledger_single_table_jump/menu.sql.tpl +10 -7
- package/assets/templates/master_child_jump/form.tpl +41 -0
- package/assets/templates/master_child_jump/index.tpl +19 -7
- package/assets/templates/master_child_jump/menu.sql.tpl +14 -14
- package/assets/templates/single_table_dialog/index.tpl +15 -3
- package/assets/templates/single_table_dialog/menu.sql.tpl +12 -12
- package/assets/templates/single_table_jump/index.tpl +19 -7
- package/assets/templates/single_table_jump/menu.sql.tpl +14 -14
- package/assets/templates/single_tree_table/api.tpl +17 -0
- package/assets/templates/single_tree_table/form.tpl +139 -0
- package/assets/templates/single_tree_table/index.tpl +203 -0
- package/assets/templates/single_tree_table/menu.sql.tpl +21 -0
- package/assets/templates/single_tree_table/options.tpl +35 -0
- package/assets/templates/tree_left_list/README.md +1 -0
- package/assets/templates/tree_left_list/api.tpl +4 -0
- package/assets/templates/tree_left_list/form.tpl +3 -0
- package/assets/templates/tree_left_list/index.tpl +4 -0
- package/assets/templates/tree_left_list/menu.sql.tpl +1 -0
- package/assets/templates/tree_left_list/options.tpl +3 -0
- package/mcp_server.js +1205 -507
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,10 +9,24 @@ This MCP generates Worsoft frontend files from structured JSON metadata.
|
|
|
9
9
|
- local template rendering
|
|
10
10
|
- single-table runtime generation
|
|
11
11
|
- master-child runtime generation with explicit `children[]`
|
|
12
|
+
- single tree runtime generation with `listByParentId`
|
|
13
|
+
- left-tree-right-list runtime generation with explicit `levels[]`
|
|
12
14
|
- optional write-to-disk
|
|
13
15
|
|
|
14
16
|
## Current Inputs
|
|
15
17
|
|
|
18
|
+
Preferred input:
|
|
19
|
+
|
|
20
|
+
- `parseResultPath`
|
|
21
|
+
- `writeToDisk`
|
|
22
|
+
- `overwrite`
|
|
23
|
+
- `writeSupportFiles`
|
|
24
|
+
- `mergeI18nZh`
|
|
25
|
+
|
|
26
|
+
When `parseResultPath` is provided, MCP reads `parseResult.json` locally and uses `parseResult.mcpPayload` as the generation input. The caller should not expand `mcpPayload` in the model context.
|
|
27
|
+
|
|
28
|
+
Legacy-compatible low-level inputs:
|
|
29
|
+
|
|
16
30
|
- `featureTitle`
|
|
17
31
|
- `tableName`
|
|
18
32
|
- `tableComment`
|
|
@@ -33,7 +47,28 @@ If the caller accidentally passes the `src` directory, MCP will normalize it bac
|
|
|
33
47
|
|
|
34
48
|
## Recommended MCP Arguments
|
|
35
49
|
|
|
36
|
-
|
|
50
|
+
Preferred:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"parseResultPath": "E:/own-worker-platform/trunk/docs/03-modules/.../parseResult.json",
|
|
55
|
+
"writeToDisk": true,
|
|
56
|
+
"overwrite": true
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If `parseResult.mcpPayload` does not contain `frontendPath`, pass it as a non-semantic runtime argument:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"parseResultPath": "E:/own-worker-platform/trunk/docs/03-modules/.../parseResult.json",
|
|
65
|
+
"frontendPath": "E:/own-worker-platform/trunk/worsoft-ui",
|
|
66
|
+
"writeToDisk": true,
|
|
67
|
+
"overwrite": true
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Legacy low-level single table:
|
|
37
72
|
|
|
38
73
|
```json
|
|
39
74
|
{
|
|
@@ -54,7 +89,7 @@ Single table:
|
|
|
54
89
|
}
|
|
55
90
|
```
|
|
56
91
|
|
|
57
|
-
|
|
92
|
+
Legacy low-level master-child:
|
|
58
93
|
|
|
59
94
|
```json
|
|
60
95
|
{
|
|
@@ -103,10 +138,13 @@ Node:
|
|
|
103
138
|
|
|
104
139
|
```bash
|
|
105
140
|
node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario single
|
|
141
|
+
node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario parse_result_path
|
|
106
142
|
node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario single_dialog
|
|
107
143
|
node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario dict_single
|
|
108
144
|
node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario master
|
|
109
145
|
node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario dict_multi
|
|
146
|
+
node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario single_tree
|
|
147
|
+
node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario tree_left_list
|
|
110
148
|
```
|
|
111
149
|
|
|
112
150
|
Optional overrides:
|
|
@@ -130,9 +168,9 @@ Optional overrides:
|
|
|
130
168
|
- `mergeI18nZh=false`:
|
|
131
169
|
MCP renders `zh-cn.ts` from current metadata only and does not parse the existing file
|
|
132
170
|
|
|
133
|
-
## Master-Child Contract
|
|
171
|
+
## Legacy Low-Level Master-Child Contract
|
|
134
172
|
|
|
135
|
-
For `master_child_jump
|
|
173
|
+
For low-level `master_child_jump` calls, MCP does not infer relations. `parseResultPath` callers should let `doc-parse` populate `parseResult.mcpPayload.children`.
|
|
136
174
|
|
|
137
175
|
The caller must provide explicit `children[]`, and each child must include:
|
|
138
176
|
|
|
@@ -145,9 +183,9 @@ The caller must provide explicit `children[]`, and each child must include:
|
|
|
145
183
|
|
|
146
184
|
If these fields are missing, MCP returns a structured validation error.
|
|
147
185
|
|
|
148
|
-
## Multi-Level Dictionary Contract
|
|
186
|
+
## Legacy Low-Level Multi-Level Dictionary Contract
|
|
149
187
|
|
|
150
|
-
For `multi_level_dict`, MCP does not infer hierarchy.
|
|
188
|
+
For low-level `multi_level_dict`, MCP does not infer hierarchy. `parseResultPath` callers should let `doc-parse` populate `parseResult.mcpPayload.levels`.
|
|
151
189
|
|
|
152
190
|
The caller must provide explicit `levels[]`. Each level must include:
|
|
153
191
|
|
|
@@ -160,6 +198,10 @@ Each module must include:
|
|
|
160
198
|
- `apiPath`
|
|
161
199
|
- `fields`
|
|
162
200
|
|
|
201
|
+
For `tree_left_list`, level 1 is rendered as the left lazy tree and level 2 is rendered as the right linked list.
|
|
202
|
+
The left module may pass `treeParentField` when the parent field is not `parentId`.
|
|
203
|
+
When the same physical table is split into different logical regions, pass `moduleKey` to keep the UI state independent.
|
|
204
|
+
|
|
163
205
|
## Current Outputs
|
|
164
206
|
|
|
165
207
|
- `src/views/<module>/<function>/index.vue`
|
|
@@ -174,12 +216,7 @@ Each module must include:
|
|
|
174
216
|
- Human guide: `STYLE_TEMPLATE_GUIDE.md`
|
|
175
217
|
- Machine source: `assets/style-catalog.json`
|
|
176
218
|
|
|
177
|
-
Declared styles
|
|
178
|
-
|
|
179
|
-
- `single_table_jump`
|
|
180
|
-
- `single_table_dialog`
|
|
181
|
-
- `master_child_jump`
|
|
182
|
-
- `multi_level_dict`
|
|
219
|
+
Declared styles are defined by `assets/style-catalog.json`; README intentionally does not duplicate the full enum as a second source.
|
|
183
220
|
|
|
184
221
|
## Notes
|
|
185
222
|
|
|
@@ -90,5 +90,51 @@
|
|
|
90
90
|
"menuSql": "menu.sql.tpl"
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
},
|
|
94
|
+
"single_tree_table": {
|
|
95
|
+
"id": "single_tree_table",
|
|
96
|
+
"label": "单树形结构模板",
|
|
97
|
+
"description": "单表树形字典页面,使用 SchemaTreeTable 和 listByParentId 懒加载子节点。",
|
|
98
|
+
"templateFiles": {
|
|
99
|
+
"api": "api.md",
|
|
100
|
+
"options": "options.md",
|
|
101
|
+
"form": "表单V2025001.md",
|
|
102
|
+
"list": "树形表格V2025001.md",
|
|
103
|
+
"menuSql": "权限菜单V2025001.md"
|
|
104
|
+
},
|
|
105
|
+
"runtime": {
|
|
106
|
+
"supported": true,
|
|
107
|
+
"templateDir": "assets/templates/single_tree_table",
|
|
108
|
+
"files": {
|
|
109
|
+
"api": "api.tpl",
|
|
110
|
+
"options": "options.tpl",
|
|
111
|
+
"form": "form.tpl",
|
|
112
|
+
"list": "index.tpl",
|
|
113
|
+
"menuSql": "menu.sql.tpl"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"tree_left_list": {
|
|
118
|
+
"id": "tree_left_list",
|
|
119
|
+
"label": "左树右列表模板",
|
|
120
|
+
"description": "左侧树形表格懒加载,右侧列表根据左侧当前选中节点联动查询。",
|
|
121
|
+
"templateFiles": {
|
|
122
|
+
"api": "api.md",
|
|
123
|
+
"options": "options.md",
|
|
124
|
+
"form": "表单V2025001.md",
|
|
125
|
+
"list": "左树右列表V2025001.md",
|
|
126
|
+
"menuSql": "权限菜单V2025001.md"
|
|
127
|
+
},
|
|
128
|
+
"runtime": {
|
|
129
|
+
"supported": true,
|
|
130
|
+
"templateDir": "assets/templates/tree_left_list",
|
|
131
|
+
"files": {
|
|
132
|
+
"api": "api.tpl",
|
|
133
|
+
"options": "options.tpl",
|
|
134
|
+
"form": "form.tpl",
|
|
135
|
+
"list": "index.tpl",
|
|
136
|
+
"menuSql": "menu.sql.tpl"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
93
139
|
}
|
|
94
140
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
import { createCrudApi } from '/@/api/common/crudFactory';
|
|
3
3
|
{{API_REQUEST_IMPORT}}
|
|
4
4
|
|
|
5
|
-
// {{FEATURE_TITLE}}
|
|
6
|
-
export const { fetchList, getObj } = createCrudApi('/{{API_PATH}}');
|
|
5
|
+
// {{FEATURE_TITLE}}主子表台账只读接口:分页查询、详情查询、导出
|
|
6
|
+
export const { fetchList, getObj, exportObj } = createCrudApi('/{{API_PATH}}');
|
|
7
7
|
{{EXTRA_API_FUNCTIONS}}
|
|
@@ -47,7 +47,7 @@ import { allDictTypes, childFieldGroups, dataMasterEntity } from './options';
|
|
|
47
47
|
const dictRefs = useDict(...allDictTypes);
|
|
48
48
|
// 国际化方法
|
|
49
49
|
const { t } = useI18n();
|
|
50
|
-
//
|
|
50
|
+
// 子表表格组件:模板默认保留新增/删除按钮,后续可由任务拆分按业务规则移除
|
|
51
51
|
const scFormTable = defineAsyncComponent(() => import('/@/components/FormTable/index.vue'));
|
|
52
52
|
// 当前路由信息
|
|
53
53
|
const route = useRoute();
|
|
@@ -1,28 +1,32 @@
|
|
|
1
|
+
<!-- 功能名称:{{FEATURE_TITLE}} -->
|
|
1
2
|
<template>
|
|
2
|
-
<!-- 页面布局:{{FEATURE_TITLE}}
|
|
3
|
+
<!-- 页面布局:{{FEATURE_TITLE}}主子表台账列表页 -->
|
|
3
4
|
<div class="layout-padding">
|
|
4
5
|
<div class="layout-padding-auto layout-padding-view flex h-full flex-col">
|
|
5
|
-
<!--
|
|
6
|
+
<!-- 列表工具栏:搜索、重置、高级查询、导出和刷新,台账页不提供新增、导入、删除入口 -->
|
|
6
7
|
<SchemaListToolbar
|
|
7
8
|
v-bind="toolbarProps"
|
|
8
9
|
@update:keyword="state.queryForm.smartVal = $event"
|
|
9
10
|
@query="handleToolbarQuery"
|
|
10
11
|
@reset="handleToolbarReset"
|
|
11
12
|
@custom-query-confirm="handleToolbarCustomQueryConfirm"
|
|
13
|
+
@export="handleToolbarExport"
|
|
12
14
|
@refresh="handleToolbarRefresh"
|
|
13
15
|
/>
|
|
14
16
|
|
|
15
|
-
<!--
|
|
17
|
+
<!-- 列表表格:展示{{FEATURE_TITLE}}主表台账数据、分页、排序和行内查看操作 -->
|
|
16
18
|
<SchemaListTable
|
|
17
19
|
v-bind="tableProps"
|
|
18
20
|
row-id-key="{{PK_ATTR}}"
|
|
19
21
|
:action-column-width="100"
|
|
22
|
+
@row-current-change="handleTableRowCurrentChange"
|
|
20
23
|
@sort-change="handleTableSortChange"
|
|
21
24
|
@size-change="handleTableSizeChange"
|
|
22
25
|
@current-change="handleTableCurrentChange"
|
|
23
26
|
>
|
|
24
|
-
<!--
|
|
27
|
+
<!-- 行操作按钮:主子表台账页只允许查看详情 -->
|
|
25
28
|
<template #actions="{ row }">
|
|
29
|
+
<!-- 查看{{FEATURE_TITLE}}主子表台账详情 -->
|
|
26
30
|
<el-button text type="primary" icon="view" v-auth="'{{PERMISSION_PREFIX}}_view'" @click="handleDetail(row.{{PK_ATTR}})">{{ t('common.viewBtn') }}</el-button>
|
|
27
31
|
</template>
|
|
28
32
|
</SchemaListTable>
|
|
@@ -31,13 +35,15 @@
|
|
|
31
35
|
</template>
|
|
32
36
|
|
|
33
37
|
<script setup lang="ts" name="system{{CLASS_NAME}}">
|
|
34
|
-
//
|
|
35
|
-
import { fetchList } from '/@/api/{{API_MODULE_PATH}}';
|
|
38
|
+
// 列表接口:台账页只消费分页查询能力
|
|
39
|
+
import { fetchList, exportObj } from '/@/api/{{API_MODULE_PATH}}';
|
|
36
40
|
// 字典数据加载
|
|
37
41
|
import { useDict } from '/@/hooks/dict';
|
|
38
|
-
//
|
|
42
|
+
// 列表页字段元数据能力
|
|
39
43
|
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
40
|
-
//
|
|
44
|
+
// 列表当前行选中保持能力
|
|
45
|
+
import { useTableCurrentRow } from '/@/hooks/useTableCurrentRow';
|
|
46
|
+
// 列表页查询、分页和排序状态管理
|
|
41
47
|
import { useSchemaListQuery } from '/@/hooks/useSchemaListQuery';
|
|
42
48
|
// 统一列表工具栏组件
|
|
43
49
|
import SchemaListToolbar from '/@/components/schema-list/SchemaListToolbar.vue';
|
|
@@ -54,19 +60,27 @@ const dictRefs = useDict(...allDictTypes);
|
|
|
54
60
|
const { t } = useI18n();
|
|
55
61
|
// 路由跳转能力
|
|
56
62
|
const router = useRouter();
|
|
63
|
+
// 当前高亮行
|
|
57
64
|
|
|
58
|
-
//
|
|
59
|
-
const { state, getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle, resetQueryForm } = useSchemaListQuery({
|
|
65
|
+
// 统一管理主子表台账列表查询、分页、排序和导出
|
|
66
|
+
const { state, getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle, exportExcel: runExportExcel, resetQueryForm } = useSchemaListQuery({
|
|
60
67
|
schema: crudSchema,
|
|
61
68
|
pageList: fetchList,
|
|
62
|
-
|
|
63
|
-
exportFileName: '{{
|
|
69
|
+
exportApi: exportObj,
|
|
70
|
+
exportFileName: '{{FEATURE_TITLE}}.xlsx',
|
|
71
|
+
exportColumns: () => tableColumns.value,
|
|
64
72
|
});
|
|
65
73
|
|
|
74
|
+
// 统一处理台账列表加载后的首行选中,以及刷新后的当前行保持
|
|
75
|
+
const { currentRowKey, handleCurrentChange } = useTableCurrentRow(
|
|
76
|
+
computed(() => state.dataList),
|
|
77
|
+
'{{PK_ATTR}}'
|
|
78
|
+
);
|
|
79
|
+
|
|
66
80
|
// 提供字段标签、字典选项和查询区描述
|
|
67
81
|
const { resolveLabel, getDictOptions, visibleTableColumns, searchKeywordTooltip, queryableDictFields } = useCrudPageMeta(dataMasterEntity, dictRefs);
|
|
68
82
|
|
|
69
|
-
//
|
|
83
|
+
// 自定义查询区的字典字段配置
|
|
70
84
|
const queryableDictOptions = computed(() =>
|
|
71
85
|
queryableDictFields.value.map((field) => ({
|
|
72
86
|
...field,
|
|
@@ -85,7 +99,7 @@ const tableColumns = computed(() =>
|
|
|
85
99
|
}))
|
|
86
100
|
);
|
|
87
101
|
|
|
88
|
-
//
|
|
102
|
+
// 工具栏透传属性:显式关闭新增、导入、删除入口,保留导出
|
|
89
103
|
const toolbarProps = computed(() => ({
|
|
90
104
|
keyword: state.queryForm.smartVal,
|
|
91
105
|
searchPlaceholder: searchKeywordTooltip.value,
|
|
@@ -95,10 +109,10 @@ const toolbarProps = computed(() => ({
|
|
|
95
109
|
showAdd: false,
|
|
96
110
|
showImport: false,
|
|
97
111
|
showDelete: false,
|
|
98
|
-
exportPermission:
|
|
112
|
+
exportPermission: '{{PERMISSION_PREFIX}}_export',
|
|
99
113
|
}));
|
|
100
114
|
|
|
101
|
-
//
|
|
115
|
+
// 表格透传属性:关闭勾选列,仅保留查看操作列和当前行高亮
|
|
102
116
|
const tableProps = computed(() => ({
|
|
103
117
|
data: state.dataList,
|
|
104
118
|
loading: !!state.loading,
|
|
@@ -106,16 +120,24 @@ const tableProps = computed(() => ({
|
|
|
106
120
|
pagination: state.pagination,
|
|
107
121
|
tableStyle,
|
|
108
122
|
showSelection: false,
|
|
123
|
+
currentRowKey: currentRowKey.value,
|
|
124
|
+
highlightCurrentRow: true,
|
|
109
125
|
}));
|
|
110
126
|
|
|
111
|
-
//
|
|
127
|
+
// 列表刷新后恢复当前行:优先恢复原选中行,不存在时选中第一行
|
|
128
|
+
// 表单页路由路径
|
|
112
129
|
const getFormPath = () => '/{{VIEW_MODULE_PATH}}/form';
|
|
113
130
|
|
|
114
|
-
//
|
|
131
|
+
// 跳转主子表台账详情页,固定 detail=1
|
|
115
132
|
const handleDetail = (id: string) => {
|
|
116
133
|
router.push({ path: getFormPath(), query: { id, detail: '1', tagsViewName: t('common.viewBtn') } });
|
|
117
134
|
};
|
|
118
135
|
|
|
136
|
+
// 导出台账数据
|
|
137
|
+
const exportExcel = () => {
|
|
138
|
+
runExportExcel([]);
|
|
139
|
+
};
|
|
140
|
+
|
|
119
141
|
// 应用高级查询条件
|
|
120
142
|
const handleQueryFilterConfirm = (values: Record<string, any>) => {
|
|
121
143
|
queryableDictFields.value.forEach((field) => {
|
|
@@ -150,11 +172,21 @@ const handleToolbarCustomQueryConfirm = (payload: { values: Record<string, any>
|
|
|
150
172
|
handleQueryFilterConfirm(payload.values);
|
|
151
173
|
};
|
|
152
174
|
|
|
175
|
+
// 工具栏导出事件
|
|
176
|
+
const handleToolbarExport = () => {
|
|
177
|
+
exportExcel();
|
|
178
|
+
};
|
|
179
|
+
|
|
153
180
|
// 工具栏刷新事件
|
|
154
181
|
const handleToolbarRefresh = () => {
|
|
155
182
|
getDataList();
|
|
156
183
|
};
|
|
157
184
|
|
|
185
|
+
// 表格当前行变化事件
|
|
186
|
+
const handleTableRowCurrentChange = (payload: { row: any }) => {
|
|
187
|
+
handleCurrentChange(payload);
|
|
188
|
+
};
|
|
189
|
+
|
|
158
190
|
// 表格排序事件
|
|
159
191
|
const handleTableSortChange = (payload: { raw: any }) => {
|
|
160
192
|
sortChangeHandle(payload.raw);
|
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
-- Generated by worsoft-codegen-local on {{GENERATED_AT}}
|
|
4
4
|
|
|
5
5
|
-- 主子表台账列表菜单:只读台账入口
|
|
6
|
-
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
7
|
-
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1);
|
|
6
|
+
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name, tenant_id, bill_code)
|
|
7
|
+
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1, '{{BILL_CODE}}');
|
|
8
8
|
|
|
9
9
|
-- 主子表台账详情路由:隐藏菜单,用于列表页查看跳转
|
|
10
|
-
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, visible, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
11
|
-
values ({{MENU_BASE_ID_PLUS_6}}, '-1', '/{{MENU_ROUTE_PATH}}/form', '', '0', 'icon-biaodan', '0', '0', null, '9', null, '{{TABLE_COMMENT}}详情', 1);
|
|
10
|
+
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, visible, del_flag, create_time, sort_order, update_time, name, tenant_id, bill_code)
|
|
11
|
+
values ({{MENU_BASE_ID_PLUS_6}}, '-1', '/{{MENU_ROUTE_PATH}}/form', '', '0', 'icon-biaodan', '0', '0', null, '9', null, '{{TABLE_COMMENT}}详情', 1, '{{BILL_CODE}}');
|
|
12
12
|
|
|
13
|
-
--
|
|
14
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
15
|
-
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1);
|
|
13
|
+
-- 台账操作权限:只生成查看、导出权限,不生成新增、编辑、删除等操作权限
|
|
14
|
+
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id, bill_code)
|
|
15
|
+
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1, '{{BILL_CODE}}');
|
|
16
|
+
|
|
17
|
+
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id, bill_code)
|
|
18
|
+
values ({{MENU_BASE_ID_PLUS_5}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_export', '1', null, '1', '0', null, '4', null, '导入导出', 1, '{{BILL_CODE}}');
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
import { createCrudApi } from '/@/api/common/crudFactory';
|
|
3
3
|
{{API_REQUEST_IMPORT}}
|
|
4
4
|
|
|
5
|
-
// {{FEATURE_TITLE}}
|
|
6
|
-
export const { fetchList, getObj } = createCrudApi('/{{API_PATH}}');
|
|
5
|
+
// {{FEATURE_TITLE}}台账只读接口:分页查询、详情查询、导出
|
|
6
|
+
export const { fetchList, getObj, exportObj } = createCrudApi('/{{API_PATH}}');
|
|
7
7
|
{{EXTRA_API_FUNCTIONS}}
|
|
@@ -1,28 +1,32 @@
|
|
|
1
|
+
<!-- 功能名称:{{FEATURE_TITLE}} -->
|
|
1
2
|
<template>
|
|
2
|
-
<!-- 页面布局:{{FEATURE_TITLE}}
|
|
3
|
+
<!-- 页面布局:{{FEATURE_TITLE}}台账列表页 -->
|
|
3
4
|
<div class="layout-padding">
|
|
4
5
|
<div class="layout-padding-auto layout-padding-view flex h-full flex-col">
|
|
5
|
-
<!--
|
|
6
|
+
<!-- 列表工具栏:搜索、重置、高级查询、导出和刷新,台账页不提供新增、导入、删除入口 -->
|
|
6
7
|
<SchemaListToolbar
|
|
7
8
|
v-bind="toolbarProps"
|
|
8
9
|
@update:keyword="state.queryForm.smartVal = $event"
|
|
9
10
|
@query="handleToolbarQuery"
|
|
10
11
|
@reset="handleToolbarReset"
|
|
11
12
|
@custom-query-confirm="handleToolbarCustomQueryConfirm"
|
|
13
|
+
@export="handleToolbarExport"
|
|
12
14
|
@refresh="handleToolbarRefresh"
|
|
13
15
|
/>
|
|
14
16
|
|
|
15
|
-
<!--
|
|
17
|
+
<!-- 列表表格:展示{{FEATURE_TITLE}}台账数据、分页、排序和行内查看操作 -->
|
|
16
18
|
<SchemaListTable
|
|
17
19
|
v-bind="tableProps"
|
|
18
20
|
row-id-key="{{PK_ATTR}}"
|
|
19
21
|
:action-column-width="100"
|
|
22
|
+
@row-current-change="handleTableRowCurrentChange"
|
|
20
23
|
@sort-change="handleTableSortChange"
|
|
21
24
|
@size-change="handleTableSizeChange"
|
|
22
25
|
@current-change="handleTableCurrentChange"
|
|
23
26
|
>
|
|
24
|
-
<!--
|
|
27
|
+
<!-- 行操作按钮:台账页只允许查看详情 -->
|
|
25
28
|
<template #actions="{ row }">
|
|
29
|
+
<!-- 查看{{FEATURE_TITLE}}台账详情 -->
|
|
26
30
|
<el-button text type="primary" icon="view" v-auth="'{{PERMISSION_PREFIX}}_view'" @click="handleDetail(row.{{PK_ATTR}})">{{ t('common.viewBtn') }}</el-button>
|
|
27
31
|
</template>
|
|
28
32
|
</SchemaListTable>
|
|
@@ -31,13 +35,15 @@
|
|
|
31
35
|
</template>
|
|
32
36
|
|
|
33
37
|
<script setup lang="ts" name="system{{CLASS_NAME}}">
|
|
34
|
-
//
|
|
35
|
-
import { fetchList } from '/@/api/{{API_MODULE_PATH}}';
|
|
38
|
+
// 列表接口:台账页只消费分页查询能力
|
|
39
|
+
import { fetchList, exportObj } from '/@/api/{{API_MODULE_PATH}}';
|
|
36
40
|
// 字典数据加载
|
|
37
41
|
import { useDict } from '/@/hooks/dict';
|
|
38
|
-
//
|
|
42
|
+
// 列表页字段元数据能力
|
|
39
43
|
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
40
|
-
//
|
|
44
|
+
// 列表当前行选中保持能力
|
|
45
|
+
import { useTableCurrentRow } from '/@/hooks/useTableCurrentRow';
|
|
46
|
+
// 列表页查询、分页和排序状态管理
|
|
41
47
|
import { useSchemaListQuery } from '/@/hooks/useSchemaListQuery';
|
|
42
48
|
// 统一列表工具栏组件
|
|
43
49
|
import SchemaListToolbar from '/@/components/schema-list/SchemaListToolbar.vue';
|
|
@@ -54,19 +60,27 @@ const dictRefs = useDict(...allDictTypes);
|
|
|
54
60
|
const { t } = useI18n();
|
|
55
61
|
// 路由跳转能力
|
|
56
62
|
const router = useRouter();
|
|
63
|
+
// 当前高亮行
|
|
57
64
|
|
|
58
|
-
//
|
|
59
|
-
const { state, getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle, resetQueryForm } = useSchemaListQuery({
|
|
65
|
+
// 统一管理台账列表查询、分页、排序和导出
|
|
66
|
+
const { state, getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle, exportExcel: runExportExcel, resetQueryForm } = useSchemaListQuery({
|
|
60
67
|
schema: crudSchema,
|
|
61
68
|
pageList: fetchList,
|
|
62
|
-
|
|
63
|
-
exportFileName: '{{
|
|
69
|
+
exportApi: exportObj,
|
|
70
|
+
exportFileName: '{{FEATURE_TITLE}}.xlsx',
|
|
71
|
+
exportColumns: () => tableColumns.value,
|
|
64
72
|
});
|
|
65
73
|
|
|
74
|
+
// 统一处理台账列表加载后的首行选中,以及刷新后的当前行保持
|
|
75
|
+
const { currentRowKey, handleCurrentChange } = useTableCurrentRow(
|
|
76
|
+
computed(() => state.dataList),
|
|
77
|
+
'{{PK_ATTR}}'
|
|
78
|
+
);
|
|
79
|
+
|
|
66
80
|
// 提供字段标签、字典选项和查询区描述
|
|
67
81
|
const { resolveLabel, getDictOptions, visibleTableColumns, searchKeywordTooltip, queryableDictFields } = useCrudPageMeta(dataMasterEntity, dictRefs);
|
|
68
82
|
|
|
69
|
-
//
|
|
83
|
+
// 自定义查询区的字典字段配置
|
|
70
84
|
const queryableDictOptions = computed(() =>
|
|
71
85
|
queryableDictFields.value.map((field) => ({
|
|
72
86
|
...field,
|
|
@@ -85,7 +99,7 @@ const tableColumns = computed(() =>
|
|
|
85
99
|
}))
|
|
86
100
|
);
|
|
87
101
|
|
|
88
|
-
//
|
|
102
|
+
// 工具栏透传属性:显式关闭新增、导入、删除入口,保留导出
|
|
89
103
|
const toolbarProps = computed(() => ({
|
|
90
104
|
keyword: state.queryForm.smartVal,
|
|
91
105
|
searchPlaceholder: searchKeywordTooltip.value,
|
|
@@ -95,10 +109,10 @@ const toolbarProps = computed(() => ({
|
|
|
95
109
|
showAdd: false,
|
|
96
110
|
showImport: false,
|
|
97
111
|
showDelete: false,
|
|
98
|
-
exportPermission:
|
|
112
|
+
exportPermission: '{{PERMISSION_PREFIX}}_export',
|
|
99
113
|
}));
|
|
100
114
|
|
|
101
|
-
//
|
|
115
|
+
// 表格透传属性:关闭勾选列,仅保留查看操作列和当前行高亮
|
|
102
116
|
const tableProps = computed(() => ({
|
|
103
117
|
data: state.dataList,
|
|
104
118
|
loading: !!state.loading,
|
|
@@ -106,9 +120,12 @@ const tableProps = computed(() => ({
|
|
|
106
120
|
pagination: state.pagination,
|
|
107
121
|
tableStyle,
|
|
108
122
|
showSelection: false,
|
|
123
|
+
currentRowKey: currentRowKey.value,
|
|
124
|
+
highlightCurrentRow: true,
|
|
109
125
|
}));
|
|
110
126
|
|
|
111
|
-
//
|
|
127
|
+
// 列表刷新后恢复当前行:优先恢复原选中行,不存在时选中第一行
|
|
128
|
+
// 表单页路由路径
|
|
112
129
|
const getFormPath = () => '/{{VIEW_MODULE_PATH}}/form';
|
|
113
130
|
|
|
114
131
|
// 跳转台账详情页,固定 detail=1
|
|
@@ -116,6 +133,11 @@ const handleDetail = (id: string) => {
|
|
|
116
133
|
router.push({ path: getFormPath(), query: { id, detail: '1', tagsViewName: t('common.viewBtn') } });
|
|
117
134
|
};
|
|
118
135
|
|
|
136
|
+
// 导出台账数据
|
|
137
|
+
const exportExcel = () => {
|
|
138
|
+
runExportExcel([]);
|
|
139
|
+
};
|
|
140
|
+
|
|
119
141
|
// 应用高级查询条件
|
|
120
142
|
const handleQueryFilterConfirm = (values: Record<string, any>) => {
|
|
121
143
|
queryableDictFields.value.forEach((field) => {
|
|
@@ -150,11 +172,21 @@ const handleToolbarCustomQueryConfirm = (payload: { values: Record<string, any>
|
|
|
150
172
|
handleQueryFilterConfirm(payload.values);
|
|
151
173
|
};
|
|
152
174
|
|
|
175
|
+
// 工具栏导出事件
|
|
176
|
+
const handleToolbarExport = () => {
|
|
177
|
+
exportExcel();
|
|
178
|
+
};
|
|
179
|
+
|
|
153
180
|
// 工具栏刷新事件
|
|
154
181
|
const handleToolbarRefresh = () => {
|
|
155
182
|
getDataList();
|
|
156
183
|
};
|
|
157
184
|
|
|
185
|
+
// 表格当前行变化事件
|
|
186
|
+
const handleTableRowCurrentChange = (payload: { row: any }) => {
|
|
187
|
+
handleCurrentChange(payload);
|
|
188
|
+
};
|
|
189
|
+
|
|
158
190
|
// 表格排序事件
|
|
159
191
|
const handleTableSortChange = (payload: { raw: any }) => {
|
|
160
192
|
sortChangeHandle(payload.raw);
|
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
-- Generated by worsoft-codegen-local on {{GENERATED_AT}}
|
|
4
4
|
|
|
5
5
|
-- 台账列表菜单:只读台账入口
|
|
6
|
-
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
7
|
-
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1);
|
|
6
|
+
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name, tenant_id, bill_code)
|
|
7
|
+
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1, '{{BILL_CODE}}');
|
|
8
8
|
|
|
9
9
|
-- 台账详情路由:隐藏菜单,用于列表页查看跳转
|
|
10
|
-
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, visible, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
11
|
-
values ({{MENU_BASE_ID_PLUS_6}}, '-1', '/{{MENU_ROUTE_PATH}}/form', '', '0', 'icon-biaodan', '0', '0', null, '9', null, '{{TABLE_COMMENT}}详情', 1);
|
|
10
|
+
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, visible, del_flag, create_time, sort_order, update_time, name, tenant_id, bill_code)
|
|
11
|
+
values ({{MENU_BASE_ID_PLUS_6}}, '-1', '/{{MENU_ROUTE_PATH}}/form', '', '0', 'icon-biaodan', '0', '0', null, '9', null, '{{TABLE_COMMENT}}详情', 1, '{{BILL_CODE}}');
|
|
12
12
|
|
|
13
|
-
--
|
|
14
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
15
|
-
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1);
|
|
13
|
+
-- 台账操作权限:只生成查看、导出权限,不生成新增、编辑、删除等操作权限
|
|
14
|
+
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id, bill_code)
|
|
15
|
+
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1, '{{BILL_CODE}}');
|
|
16
|
+
|
|
17
|
+
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id, bill_code)
|
|
18
|
+
values ({{MENU_BASE_ID_PLUS_5}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_export', '1', null, '1', '0', null, '4', null, '导入导出', 1, '{{BILL_CODE}}');
|
|
@@ -131,6 +131,10 @@ const resetFormState = () => {
|
|
|
131
131
|
nextTick(() => {
|
|
132
132
|
dataFormRef.value?.resetFields();
|
|
133
133
|
{{CHILD_RESET_LISTS}}
|
|
134
|
+
Object.keys(selectedChildRowsMap).forEach((key) => {
|
|
135
|
+
selectedChildRowsMap[key] = [];
|
|
136
|
+
childTableRefMap[key]?.clearSelection?.();
|
|
137
|
+
});
|
|
134
138
|
});
|
|
135
139
|
};
|
|
136
140
|
|
|
@@ -188,6 +192,43 @@ const deleteChild = (_obj: Record<string, any>, _childPkAttr: string) => {
|
|
|
188
192
|
};
|
|
189
193
|
|
|
190
194
|
// 页面挂载后初始化数据
|
|
195
|
+
// 子表表格引用集合,用于外部新增按钮调用表格新增方法
|
|
196
|
+
const childTableRefMap = reactive<Record<string, any>>({});
|
|
197
|
+
// 子表勾选行集合,用于外部删除按钮删除已选明细
|
|
198
|
+
const selectedChildRowsMap = reactive<Record<string, Record<string, any>[]>>({});
|
|
199
|
+
|
|
200
|
+
const setChildTableRef = (childKey: string, el: any) => {
|
|
201
|
+
if (el) childTableRefMap[childKey] = el;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const getSelectedChildRows = (childKey: string) => selectedChildRowsMap[childKey] || [];
|
|
205
|
+
|
|
206
|
+
const handleChildSelectionChange = (childKey: string, rows: Record<string, any>[]) => {
|
|
207
|
+
selectedChildRowsMap[childKey] = rows || [];
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// 通过子表外部工具按钮新增一行,表格内部不显示新增入口
|
|
211
|
+
const handleAddChild = (childKey: string) => {
|
|
212
|
+
if (detail.value) return;
|
|
213
|
+
childTableRefMap[childKey]?.pushRow?.();
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// 通过子表外部工具按钮删除已勾选行,表格内部不显示删除入口
|
|
217
|
+
const handleDeleteSelectedChild = (childKey: string, childPkAttr: string) => {
|
|
218
|
+
if (detail.value) return;
|
|
219
|
+
|
|
220
|
+
const selectedRows = getSelectedChildRows(childKey);
|
|
221
|
+
if (!selectedRows.length) return;
|
|
222
|
+
|
|
223
|
+
const selectedSet = new Set(selectedRows);
|
|
224
|
+
const childRows = ((form as Record<string, any>)[childKey] || []) as Record<string, any>[];
|
|
225
|
+
const deletedRows = childRows.filter((row) => selectedSet.has(row));
|
|
226
|
+
(form as Record<string, any>)[childKey] = childRows.filter((row) => !selectedSet.has(row));
|
|
227
|
+
selectedChildRowsMap[childKey] = [];
|
|
228
|
+
childTableRefMap[childKey]?.clearSelection?.();
|
|
229
|
+
deletedRows.forEach((row) => deleteChild(row, childPkAttr));
|
|
230
|
+
};
|
|
231
|
+
|
|
191
232
|
onMounted(() => {
|
|
192
233
|
initPage();
|
|
193
234
|
});
|