worsoft-frontend-codegen-local-mcp 0.1.83 → 0.1.85
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 +10 -0
- package/assets/style-catalog.json +46 -0
- package/assets/templates/ledger_master_child_jump/form.tpl +1 -1
- package/assets/templates/ledger_master_child_jump/index.tpl +46 -15
- package/assets/templates/ledger_master_child_jump/menu.sql.tpl +10 -7
- package/assets/templates/ledger_single_table_jump/index.tpl +45 -14
- 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 +15 -4
- package/assets/templates/master_child_jump/menu.sql.tpl +14 -14
- package/assets/templates/single_table_dialog/index.tpl +11 -0
- package/assets/templates/single_table_dialog/menu.sql.tpl +12 -12
- package/assets/templates/single_table_jump/index.tpl +15 -4
- 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 +1078 -464
- package/package.json +1 -1
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
-- Suggested default parent_id: -1
|
|
3
3
|
-- Generated by worsoft-codegen-local on {{GENERATED_AT}}
|
|
4
4
|
|
|
5
|
-
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
6
|
-
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1);
|
|
5
|
+
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)
|
|
6
|
+
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1, '{{BILL_CODE}}');
|
|
7
7
|
|
|
8
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
9
|
-
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1);
|
|
8
|
+
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)
|
|
9
|
+
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1, '{{BILL_CODE}}');
|
|
10
10
|
|
|
11
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
12
|
-
values ({{MENU_BASE_ID_PLUS_2}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_add', '1', null, '1', '0', null, '1', null, '{{TABLE_COMMENT}}新增', 1);
|
|
11
|
+
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)
|
|
12
|
+
values ({{MENU_BASE_ID_PLUS_2}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_add', '1', null, '1', '0', null, '1', null, '{{TABLE_COMMENT}}新增', 1, '{{BILL_CODE}}');
|
|
13
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_3}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_edit', '1', null, '1', '0', null, '2', null, '{{TABLE_COMMENT}}修改', 1);
|
|
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_3}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_edit', '1', null, '1', '0', null, '2', null, '{{TABLE_COMMENT}}修改', 1, '{{BILL_CODE}}');
|
|
16
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)
|
|
18
|
-
values ({{MENU_BASE_ID_PLUS_4}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_del', '1', null, '1', '0', null, '3', null, '{{TABLE_COMMENT}}删除', 1);
|
|
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_4}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_del', '1', null, '1', '0', null, '3', null, '{{TABLE_COMMENT}}删除', 1, '{{BILL_CODE}}');
|
|
19
19
|
|
|
20
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
21
|
-
values ({{MENU_BASE_ID_PLUS_5}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_export', '1', null, '1', '0', null, '4', null, '导入导出', 1);
|
|
20
|
+
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)
|
|
21
|
+
values ({{MENU_BASE_ID_PLUS_5}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_export', '1', null, '1', '0', null, '4', null, '导入导出', 1, '{{BILL_CODE}}');
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
row-id-key="{{PK_ATTR}}"
|
|
24
24
|
:action-column-width="320"
|
|
25
25
|
@selection-change="handleTableSelectionChange"
|
|
26
|
+
@row-current-change="handleTableRowCurrentChange"
|
|
26
27
|
@sort-change="handleTableSortChange"
|
|
27
28
|
@size-change="handleTableSizeChange"
|
|
28
29
|
@current-change="handleTableCurrentChange"
|
|
@@ -33,10 +34,10 @@
|
|
|
33
34
|
<el-button text type="primary" icon="view" v-auth="'{{PERMISSION_PREFIX}}_view'" @click="handleDetail(row.{{PK_ATTR}})">{{ t('common.viewBtn') }}</el-button>
|
|
34
35
|
<!-- 编辑{{FEATURE_TITLE}}:业务单据编辑态控制按需生效 -->
|
|
35
36
|
<el-button{{BUSINESS_EDIT_IF}} icon="edit-pen" text type="primary" v-auth="'{{PERMISSION_PREFIX}}_edit'" @click="handleEdit(row.{{PK_ATTR}})">{{ t('common.editBtn') }}</el-button>
|
|
36
|
-
<!-- 提交{{FEATURE_TITLE}} -->
|
|
37
|
-
<el-button text type="primary" icon="check" @click="handleQuickAction(row, 'submit')">{{ commonActionLabel('submit') }}</el-button>
|
|
38
|
-
<!-- 流转{{FEATURE_TITLE}} -->
|
|
39
|
-
<el-button text type="success" icon="position" @click="handleQuickAction(row, 'flow')">{{ commonActionLabel('flow') }}</el-button>
|
|
37
|
+
<!-- 提交{{FEATURE_TITLE}}:仅在编辑中状态时可用 -->
|
|
38
|
+
<el-button{{BUSINESS_SUBMIT_IF}} text type="primary" icon="check" @click="handleQuickAction(row, 'submit')">{{ commonActionLabel('submit') }}</el-button>
|
|
39
|
+
<!-- 流转{{FEATURE_TITLE}}:仅在编辑中状态时可用 -->
|
|
40
|
+
<el-button{{BUSINESS_FLOW_IF}} text type="success" icon="position" @click="handleQuickAction(row, 'flow')">{{ commonActionLabel('flow') }}</el-button>
|
|
40
41
|
<!-- 删除{{FEATURE_TITLE}} -->
|
|
41
42
|
<el-button{{BUSINESS_DELETE_IF}} icon="delete" text type="primary" v-auth="'{{PERMISSION_PREFIX}}_del'" @click="handleDelete([row.{{PK_ATTR}}]{{BUSINESS_DELETE_ROW_ARG}})">{{ t('common.delBtn') }}</el-button>
|
|
42
43
|
</template>
|
|
@@ -57,6 +58,8 @@ import { useMessage, useMessageBox } from '/@/hooks/message';
|
|
|
57
58
|
import { useDict } from '/@/hooks/dict';
|
|
58
59
|
// 列表页字段元数据能力
|
|
59
60
|
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
61
|
+
// 列表当前行选中保持能力
|
|
62
|
+
import { useTableCurrentRow } from '/@/hooks/useTableCurrentRow';
|
|
60
63
|
// 列表页查询与分页状态
|
|
61
64
|
import { useSchemaListQuery } from '/@/hooks/useSchemaListQuery';
|
|
62
65
|
// 统一列表工具栏组件
|
|
@@ -93,6 +96,12 @@ const { state, getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHan
|
|
|
93
96
|
exportFileName: '{{FUNCTION_NAME}}.xlsx',
|
|
94
97
|
});
|
|
95
98
|
|
|
99
|
+
// 统一处理列表加载后的首行选中,以及刷新后的当前行保持
|
|
100
|
+
const { currentRowKey, handleCurrentChange: handleTableRowCurrentChange } = useTableCurrentRow(
|
|
101
|
+
computed(() => state.dataList),
|
|
102
|
+
'{{PK_ATTR}}'
|
|
103
|
+
);
|
|
104
|
+
|
|
96
105
|
// 提供字段标签、字典选项和查询区描述
|
|
97
106
|
const { resolveLabel, getDictOptions, commonActionLabel, visibleTableColumns, searchKeywordTooltip, queryableDictFields } = useCrudPageMeta(dataMasterEntity, dictRefs);
|
|
98
107
|
|
|
@@ -136,6 +145,8 @@ const tableProps = computed(() => ({
|
|
|
136
145
|
columns: tableColumns.value,
|
|
137
146
|
pagination: state.pagination,
|
|
138
147
|
tableStyle,
|
|
148
|
+
currentRowKey: currentRowKey.value,
|
|
149
|
+
highlightCurrentRow: true,
|
|
139
150
|
}));
|
|
140
151
|
|
|
141
152
|
// 表单页路由路径
|
|
@@ -2,25 +2,25 @@
|
|
|
2
2
|
-- Suggested default parent_id: -1
|
|
3
3
|
-- Generated by worsoft-codegen-local on {{GENERATED_AT}}
|
|
4
4
|
|
|
5
|
-
insert into sys_menu (menu_id, parent_id, path, permission, menu_type, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
6
|
-
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1);
|
|
5
|
+
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)
|
|
6
|
+
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1, '{{BILL_CODE}}');
|
|
7
7
|
|
|
8
8
|
-- Form route SQL for jump-based pages. Hidden from sidebar, used by list page add/edit/view navigation.
|
|
9
9
|
-- Keep it as a sibling of the list page, not a child of the list page, because index.vue has no nested router-view.
|
|
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{{BUSINESS_FORM_KEEP_ALIVE_COLUMN}})
|
|
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}}'{{BUSINESS_FORM_KEEP_ALIVE_VALUE}});
|
|
12
12
|
|
|
13
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
14
|
-
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1);
|
|
13
|
+
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)
|
|
14
|
+
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1, '{{BILL_CODE}}');
|
|
15
15
|
|
|
16
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
17
|
-
values ({{MENU_BASE_ID_PLUS_2}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_add', '1', null, '1', '0', null, '1', null, '{{TABLE_COMMENT}}新增', 1);
|
|
16
|
+
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)
|
|
17
|
+
values ({{MENU_BASE_ID_PLUS_2}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_add', '1', null, '1', '0', null, '1', null, '{{TABLE_COMMENT}}新增', 1, '{{BILL_CODE}}');
|
|
18
18
|
|
|
19
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
20
|
-
values ({{MENU_BASE_ID_PLUS_3}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_edit', '1', null, '1', '0', null, '2', null, '{{TABLE_COMMENT}}修改', 1);
|
|
19
|
+
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)
|
|
20
|
+
values ({{MENU_BASE_ID_PLUS_3}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_edit', '1', null, '1', '0', null, '2', null, '{{TABLE_COMMENT}}修改', 1, '{{BILL_CODE}}');
|
|
21
21
|
|
|
22
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
23
|
-
values ({{MENU_BASE_ID_PLUS_4}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_del', '1', null, '1', '0', null, '3', null, '{{TABLE_COMMENT}}删除', 1);
|
|
22
|
+
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)
|
|
23
|
+
values ({{MENU_BASE_ID_PLUS_4}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_del', '1', null, '1', '0', null, '3', null, '{{TABLE_COMMENT}}删除', 1, '{{BILL_CODE}}');
|
|
24
24
|
|
|
25
|
-
insert into sys_menu (menu_id, parent_id, permission, menu_type, path, icon, del_flag, create_time, sort_order, update_time, name, tenant_id)
|
|
26
|
-
values ({{MENU_BASE_ID_PLUS_5}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_export', '1', null, '1', '0', null, '4', null, '导入导出', 1);
|
|
25
|
+
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)
|
|
26
|
+
values ({{MENU_BASE_ID_PLUS_5}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_export', '1', null, '1', '0', null, '4', null, '导入导出', 1, '{{BILL_CODE}}');
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import request from '/@/utils/request';
|
|
2
|
+
import { createCrudApi } from '/@/api/common/crudFactory';
|
|
3
|
+
|
|
4
|
+
// {{FEATURE_TITLE}} 通用列表、新增、详情、删除、更新、导出接口
|
|
5
|
+
export const { fetchList, addObj, getObj, delObjs, putObj, exportObj } = createCrudApi('/{{API_PATH}}');
|
|
6
|
+
|
|
7
|
+
// {{FEATURE_TITLE}} 树形子节点列表
|
|
8
|
+
export function fetchTreeList(payload?: any) {
|
|
9
|
+
return request({
|
|
10
|
+
url: '/{{API_PATH}}/listByParentId',
|
|
11
|
+
method: 'get',
|
|
12
|
+
params: payload,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
{{DICT_API_FUNCTIONS}}
|
|
17
|
+
{{EXTRA_API_FUNCTIONS}}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- 表单弹窗:新增或编辑{{FEATURE_TITLE}}数据 -->
|
|
3
|
+
<el-dialog v-model="visible" :title="form.{{PK_ATTR}} ? t('common.editBtn') : t('common.addBtn')" :close-on-click-modal="false" draggable>
|
|
4
|
+
<!-- 弹窗表单:按 PRD 表单显隐和顺序渲染字段 -->
|
|
5
|
+
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="100px" v-loading="loading">
|
|
6
|
+
<!-- 主表字段区:字段级注释由 MCP 根据字段名称生成 -->
|
|
7
|
+
<el-row :gutter="24">
|
|
8
|
+
{{FORM_FIELDS}}
|
|
9
|
+
</el-row>
|
|
10
|
+
</el-form>
|
|
11
|
+
<!-- 弹窗底部操作按钮:取消和确认提交 -->
|
|
12
|
+
<template #footer>
|
|
13
|
+
<span class="dialog-footer">
|
|
14
|
+
<el-button @click="visible = false">{{ t('common.cancelButtonText') }}</el-button>
|
|
15
|
+
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ t('common.confirmButtonText') }}</el-button>
|
|
16
|
+
</span>
|
|
17
|
+
</template>
|
|
18
|
+
</el-dialog>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts" name="{{CLASS_NAME}}Dialog">
|
|
22
|
+
// 通用消息提示
|
|
23
|
+
import { useMessage } from '/@/hooks/message';
|
|
24
|
+
// 本地会话存储
|
|
25
|
+
import { Session } from '/@/utils/storage';
|
|
26
|
+
// 表单数据接口
|
|
27
|
+
import { getObj, addObj, putObj } from '/@/api/{{API_MODULE_PATH}}';
|
|
28
|
+
// 字典数据加载
|
|
29
|
+
import { useDict } from '/@/hooks/dict';
|
|
30
|
+
// 表单字段元数据能力
|
|
31
|
+
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
32
|
+
// 国际化能力
|
|
33
|
+
import { useI18n } from 'vue-i18n';
|
|
34
|
+
// 当前页面的字段配置
|
|
35
|
+
import { allDictTypes, dataMasterEntity } from './options';
|
|
36
|
+
|
|
37
|
+
// 页面所需的字典引用
|
|
38
|
+
const dictRefs = useDict(...allDictTypes);
|
|
39
|
+
// 国际化方法
|
|
40
|
+
const { t } = useI18n();
|
|
41
|
+
// 弹窗刷新事件
|
|
42
|
+
const emit = defineEmits(['refresh']);
|
|
43
|
+
|
|
44
|
+
// 表单引用
|
|
45
|
+
const dataFormRef = ref();
|
|
46
|
+
// 弹窗显示状态
|
|
47
|
+
const visible = ref(false);
|
|
48
|
+
// 提交加载状态
|
|
49
|
+
const loading = ref(false);
|
|
50
|
+
|
|
51
|
+
// 主表字段的双语、字典和校验提示统一由公共 hook 提供
|
|
52
|
+
const {
|
|
53
|
+
getFieldMeta: getMasterFieldMeta,
|
|
54
|
+
getFieldLabel: getMasterFieldLabel,
|
|
55
|
+
getDictOptions,
|
|
56
|
+
inputPlaceholder,
|
|
57
|
+
selectPlaceholder,
|
|
58
|
+
fieldRequiredMessage,
|
|
59
|
+
} = useCrudPageMeta(dataMasterEntity, dictRefs);
|
|
60
|
+
|
|
61
|
+
const formInputPlaceholder = (label: string, disabled = false) => (disabled ? '' : inputPlaceholder(label));
|
|
62
|
+
const formSelectPlaceholder = (label: string, disabled = false) => (disabled ? '' : selectPlaceholder(label));
|
|
63
|
+
|
|
64
|
+
// 统一维护表单默认值
|
|
65
|
+
const createDefaultFormState = () => ({
|
|
66
|
+
{{FORM_DEFAULTS}}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// 表单响应式数据
|
|
70
|
+
const form = reactive(createDefaultFormState());
|
|
71
|
+
|
|
72
|
+
// 表单校验规则
|
|
73
|
+
const dataRules = ref({
|
|
74
|
+
{{FORM_RULES}}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 根据主键加载详情数据
|
|
78
|
+
const get{{CLASS_NAME}}Data = async (id: string) => {
|
|
79
|
+
try {
|
|
80
|
+
loading.value = true;
|
|
81
|
+
const { data } = await getObj({ {{PK_ATTR}}: id });
|
|
82
|
+
Object.assign(form, Array.isArray(data) ? data[0] || {} : data || {});
|
|
83
|
+
} catch (error) {
|
|
84
|
+
useMessage().error(t('common.messages.fetchError'));
|
|
85
|
+
} finally {
|
|
86
|
+
loading.value = false;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// 重置表单为初始状态
|
|
91
|
+
const resetFormState = () => {
|
|
92
|
+
Object.assign(form, createDefaultFormState());
|
|
93
|
+
nextTick(() => {
|
|
94
|
+
dataFormRef.value?.resetFields();
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// 打开弹窗并按需加载详情
|
|
99
|
+
const openDialog = async (id?: string, parentId?: string | number) => {
|
|
100
|
+
visible.value = true;
|
|
101
|
+
resetFormState();
|
|
102
|
+
|
|
103
|
+
if (parentId !== undefined && parentId !== null && parentId !== '') {
|
|
104
|
+
form.{{TREE_PARENT_ATTR}} = parentId;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (id) {
|
|
108
|
+
form.{{PK_ATTR}} = id;
|
|
109
|
+
await get{{CLASS_NAME}}Data(id);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// 提交弹窗表单
|
|
114
|
+
const onSubmit = async () => {
|
|
115
|
+
loading.value = true;
|
|
116
|
+
|
|
117
|
+
const valid = await dataFormRef.value.validate().catch(() => {});
|
|
118
|
+
if (!valid) {
|
|
119
|
+
loading.value = false;
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
form.{{PK_ATTR}} ? await putObj(form) : await addObj(form);
|
|
125
|
+
useMessage().success(form.{{PK_ATTR}} ? t('common.editSuccessText') : t('common.addSuccessText'));
|
|
126
|
+
visible.value = false;
|
|
127
|
+
emit('refresh');
|
|
128
|
+
} catch (err: any) {
|
|
129
|
+
useMessage().error(err.msg || t('common.messages.submitError'));
|
|
130
|
+
} finally {
|
|
131
|
+
loading.value = false;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// 向父组件暴露打开弹窗方法
|
|
136
|
+
defineExpose({
|
|
137
|
+
openDialog,
|
|
138
|
+
});
|
|
139
|
+
</script>
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
<!-- 功能名称:{{FEATURE_TITLE}} -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="layout-padding">
|
|
4
|
+
<div class="layout-padding-auto layout-padding-view flex h-full flex-col">
|
|
5
|
+
<SchemaListToolbar
|
|
6
|
+
v-bind="toolbarProps"
|
|
7
|
+
:show-add="false"
|
|
8
|
+
@update:keyword="state.queryForm.smartVal = $event"
|
|
9
|
+
@query="handleToolbarQuery"
|
|
10
|
+
@reset="handleToolbarReset"
|
|
11
|
+
@refresh="handleToolbarRefresh"
|
|
12
|
+
>
|
|
13
|
+
<template #prepend-actions>
|
|
14
|
+
<el-dropdown trigger="click" @command="handleAddTreeNode">
|
|
15
|
+
<el-button type="primary">
|
|
16
|
+
{{ t('common.addBtn') }}
|
|
17
|
+
<el-icon class="ml-1"><ArrowDown /></el-icon>
|
|
18
|
+
</el-button>
|
|
19
|
+
<template #dropdown>
|
|
20
|
+
<el-dropdown-menu>
|
|
21
|
+
<el-dropdown-item command="root">{{ resolveText('common.treeActions.addRoot', '新增根节点') }}</el-dropdown-item>
|
|
22
|
+
<el-dropdown-item command="sibling" :disabled="!currentRow">{{ resolveText('common.treeActions.addSibling', '新增同级节点') }}</el-dropdown-item>
|
|
23
|
+
<el-dropdown-item command="child" :disabled="!currentRow">{{ resolveText('common.treeActions.addChild', '新增子节点') }}</el-dropdown-item>
|
|
24
|
+
</el-dropdown-menu>
|
|
25
|
+
</template>
|
|
26
|
+
</el-dropdown>
|
|
27
|
+
</template>
|
|
28
|
+
</SchemaListToolbar>
|
|
29
|
+
|
|
30
|
+
<SchemaTreeTable
|
|
31
|
+
v-bind="tableProps"
|
|
32
|
+
row-id-key="{{PK_ATTR}}"
|
|
33
|
+
:load="loadTreeChildren"
|
|
34
|
+
:action-column-width="{{ACTION_COLUMN_WIDTH}}"
|
|
35
|
+
@row-current-change="handleTableRowCurrentChange"
|
|
36
|
+
>
|
|
37
|
+
<template #actions="{ row }">
|
|
38
|
+
{{LIST_ACTIONS}}
|
|
39
|
+
</template>
|
|
40
|
+
</SchemaTreeTable>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<script setup lang="ts" name="system{{CLASS_NAME}}">
|
|
48
|
+
import { ArrowDown } from '@element-plus/icons-vue';
|
|
49
|
+
import { computed, defineAsyncComponent, onMounted, reactive, ref, watch } from 'vue';
|
|
50
|
+
import { useI18n } from 'vue-i18n';
|
|
51
|
+
import { fetchTreeList, delObjs{{DICT_API_IMPORTS}} } from '/@/api/{{API_MODULE_PATH}}';
|
|
52
|
+
import { useMessage, useMessageBox } from '/@/hooks/message';
|
|
53
|
+
import { useDict } from '/@/hooks/dict';
|
|
54
|
+
{{DICT_SEMANTIC_IMPORT_BLOCK}}
|
|
55
|
+
import { useTable } from '/@/hooks/table';
|
|
56
|
+
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
57
|
+
// 列表当前行选中保持能力
|
|
58
|
+
import { useTableCurrentRow } from '/@/hooks/useTableCurrentRow';
|
|
59
|
+
import { buildSchemaQueryParams } from '/@/utils/schemaQuery';
|
|
60
|
+
import SchemaListToolbar from '/@/components/schema-list/SchemaListToolbar.vue';
|
|
61
|
+
import SchemaTreeTable from '/@/components/schema-list/SchemaTreeTable.vue';
|
|
62
|
+
import { allDictTypes, crudSchema, dataMasterEntity } from './options';
|
|
63
|
+
|
|
64
|
+
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
|
65
|
+
const formDialogRef = ref();
|
|
66
|
+
const { t } = useI18n();
|
|
67
|
+
const dictRefs = useDict(...allDictTypes);
|
|
68
|
+
const { tableStyle } = useTable({ createdIsNeed: false });
|
|
69
|
+
|
|
70
|
+
const state = reactive({
|
|
71
|
+
loading: false,
|
|
72
|
+
dataList: [] as any[],
|
|
73
|
+
queryForm: {
|
|
74
|
+
smartVal: '',
|
|
75
|
+
} as Record<string, any>,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 统一处理树表加载后的首行选中、刷新后的当前行保持,并保留当前行供新增同级/子级使用
|
|
79
|
+
const { currentRow, currentRowKey, handleCurrentChange: handleTableRowCurrentChange } = useTableCurrentRow(
|
|
80
|
+
computed(() => state.dataList),
|
|
81
|
+
'{{PK_ATTR}}'
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const { resolveLabel, getDictOptions, visibleTableColumns, searchKeywordTooltip } = useCrudPageMeta(dataMasterEntity, dictRefs);
|
|
85
|
+
|
|
86
|
+
const resolveText = (key: string, fallback: string) => {
|
|
87
|
+
const translated = t(key);
|
|
88
|
+
return translated === key ? fallback : translated;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const tableColumns = computed(() =>
|
|
92
|
+
visibleTableColumns.value.map((column) => ({
|
|
93
|
+
prop: column.prop,
|
|
94
|
+
label: resolveLabel(column.labelKey, column.fallbackLabel),
|
|
95
|
+
width: column.width,
|
|
96
|
+
dictType: column.dictType,
|
|
97
|
+
options: column.dictType ? getDictOptions(column.dictType) : [],
|
|
98
|
+
}))
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const toolbarProps = computed(() => ({
|
|
102
|
+
keyword: state.queryForm.smartVal,
|
|
103
|
+
searchPlaceholder: searchKeywordTooltip.value,
|
|
104
|
+
queryModel: state.queryForm,
|
|
105
|
+
customQueryFields: [],
|
|
106
|
+
selectedIds: [],
|
|
107
|
+
showImport: false,
|
|
108
|
+
showDelete: false,
|
|
109
|
+
showRightTools: false,
|
|
110
|
+
}));
|
|
111
|
+
|
|
112
|
+
const tableProps = computed(() => ({
|
|
113
|
+
data: state.dataList,
|
|
114
|
+
loading: !!state.loading,
|
|
115
|
+
columns: tableColumns.value,
|
|
116
|
+
tableStyle,
|
|
117
|
+
currentRowKey: currentRowKey.value,
|
|
118
|
+
lazy: true,
|
|
119
|
+
highlightCurrentRow: true,
|
|
120
|
+
}));
|
|
121
|
+
|
|
122
|
+
const normalizeTreeRows = (rows: any[]) =>
|
|
123
|
+
rows.map((row) => ({
|
|
124
|
+
...row,
|
|
125
|
+
hasChildren:
|
|
126
|
+
typeof row.hasChildren === 'boolean'
|
|
127
|
+
? row.hasChildren
|
|
128
|
+
: typeof row.hasChild === 'boolean'
|
|
129
|
+
? row.hasChild
|
|
130
|
+
: typeof row.childCount === 'number'
|
|
131
|
+
? row.childCount > 0
|
|
132
|
+
: true,
|
|
133
|
+
}));
|
|
134
|
+
|
|
135
|
+
const getQueryParams = () => ({
|
|
136
|
+
{{TREE_PARENT_ATTR}}: {{TREE_ROOT_PARENT_VALUE}},
|
|
137
|
+
...buildSchemaQueryParams(crudSchema.filterTypes, state.queryForm),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const getDataList = async () => {
|
|
141
|
+
state.loading = true;
|
|
142
|
+
try {
|
|
143
|
+
const { data } = await fetchTreeList(getQueryParams());
|
|
144
|
+
const rows = Array.isArray(data) ? data : data?.records || data?.list || [];
|
|
145
|
+
state.dataList = normalizeTreeRows(rows);
|
|
146
|
+
} finally {
|
|
147
|
+
state.loading = false;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
{{DICT_LIST_HELPERS}}
|
|
152
|
+
|
|
153
|
+
const handleAddTreeNode = (command: 'root' | 'sibling' | 'child') => {
|
|
154
|
+
let parentId: string | number = {{TREE_ROOT_PARENT_VALUE}};
|
|
155
|
+
if (command === 'sibling' && currentRow.value) parentId = currentRow.value.{{TREE_PARENT_ATTR}} ?? {{TREE_ROOT_PARENT_VALUE}};
|
|
156
|
+
if (command === 'child' && currentRow.value) parentId = currentRow.value.{{PK_ATTR}};
|
|
157
|
+
formDialogRef.value?.openDialog(undefined, parentId);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const handleDelete = async (ids: string[]) => {
|
|
161
|
+
try {
|
|
162
|
+
await useMessageBox().confirm(t('common.delConfirmText'));
|
|
163
|
+
} catch {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
await delObjs(ids);
|
|
169
|
+
await getDataList();
|
|
170
|
+
useMessage().success(t('common.delSuccessText'));
|
|
171
|
+
} catch (err: any) {
|
|
172
|
+
useMessage().error(err.msg || t('common.delBtn'));
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const handleToolbarQuery = () => {
|
|
177
|
+
getDataList();
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const handleToolbarReset = () => {
|
|
181
|
+
Object.keys(state.queryForm).forEach((key) => delete state.queryForm[key]);
|
|
182
|
+
state.queryForm.smartVal = '';
|
|
183
|
+
getDataList();
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const handleToolbarRefresh = () => {
|
|
187
|
+
getDataList();
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const loadTreeChildren = async (row: any, _treeNode: any, resolve: (data: any[]) => void) => {
|
|
191
|
+
try {
|
|
192
|
+
const { data } = await fetchTreeList({ {{TREE_PARENT_ATTR}}: row?.{{PK_ATTR}} });
|
|
193
|
+
const rows = Array.isArray(data) ? data : data?.records || data?.list || [];
|
|
194
|
+
resolve(normalizeTreeRows(rows));
|
|
195
|
+
} catch {
|
|
196
|
+
resolve([]);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
onMounted(() => {
|
|
201
|
+
getDataList();
|
|
202
|
+
});
|
|
203
|
+
</script>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- Do not execute directly. Review parent menu id and tenant settings before import.
|
|
2
|
+
-- Suggested default parent_id: -1
|
|
3
|
+
-- Generated by worsoft-codegen-local on {{GENERATED_AT}}
|
|
4
|
+
|
|
5
|
+
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)
|
|
6
|
+
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1, '{{BILL_CODE}}');
|
|
7
|
+
|
|
8
|
+
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)
|
|
9
|
+
values ({{MENU_BASE_ID_PLUS_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1, '{{BILL_CODE}}');
|
|
10
|
+
|
|
11
|
+
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)
|
|
12
|
+
values ({{MENU_BASE_ID_PLUS_2}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_add', '1', null, '1', '0', null, '1', null, '{{TABLE_COMMENT}}新增', 1, '{{BILL_CODE}}');
|
|
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_3}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_edit', '1', null, '1', '0', null, '2', 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_4}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_del', '1', null, '1', '0', null, '3', null, '{{TABLE_COMMENT}}删除', 1, '{{BILL_CODE}}');
|
|
19
|
+
|
|
20
|
+
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)
|
|
21
|
+
values ({{MENU_BASE_ID_PLUS_5}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_export', '1', null, '1', '0', null, '4', null, '导入导出', 1, '{{BILL_CODE}}');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// 字典注册表
|
|
2
|
+
{{DICT_REGISTRY_IMPORT_BLOCK}}
|
|
3
|
+
// schema 构建工具
|
|
4
|
+
import { createCrudSchema } from '/@/utils/crudSchema';
|
|
5
|
+
// schema 类型定义
|
|
6
|
+
import type { CrudSchemaDefinition } from '/@/utils/crudSchema';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* {{TABLE_NAME}} 页面字段声明
|
|
10
|
+
* 这里维护字段 key、双语 key、字典类型和显示元数据
|
|
11
|
+
*/
|
|
12
|
+
const definition: CrudSchemaDefinition = {
|
|
13
|
+
master: [
|
|
14
|
+
{{MASTER_OPTION_FIELDS}}
|
|
15
|
+
],
|
|
16
|
+
children: {
|
|
17
|
+
{{CHILD_OPTION_GROUPS}}
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// 将页面字段声明转换为 index/form 共用的 schema 结果
|
|
22
|
+
const schema = createCrudSchema(definition);
|
|
23
|
+
|
|
24
|
+
// 完整 CRUD schema
|
|
25
|
+
export const crudSchema = schema;
|
|
26
|
+
// 主表字段配置,供列表页和表单页使用
|
|
27
|
+
export const dataMasterEntity = schema.master;
|
|
28
|
+
// 子表字段配置,当前无子表时保留统一出口
|
|
29
|
+
export const childFieldGroups = schema.children;
|
|
30
|
+
// 列表/查询使用的主表字段类型映射
|
|
31
|
+
export const filterTypes = schema.filterTypes;
|
|
32
|
+
// 子表字段类型映射
|
|
33
|
+
export const childFilterTypes = schema.childFilterTypes;
|
|
34
|
+
// 当前页面需要一次性加载的全部字典类型
|
|
35
|
+
export const allDictTypes = schema.allDictTypes;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tree_left_list 由 mcp_server.js 的多层字典模型专用渲染函数生成,目录用于样式目录注册和模板资产归档。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
-- 左树右列表菜单 SQL 模板复用多层字典菜单 SQL 渲染逻辑。
|