worsoft-frontend-codegen-local-mcp 0.1.80 → 0.1.81
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/assets/templates/ledger_master_child_jump/api.tpl +5 -0
- package/assets/templates/ledger_master_child_jump/form.tpl +103 -0
- package/assets/templates/ledger_master_child_jump/index.tpl +140 -0
- package/assets/templates/ledger_master_child_jump/menu.sql.tpl +12 -0
- package/assets/templates/ledger_master_child_jump/options.tpl +21 -0
- package/assets/templates/ledger_single_table_jump/api.tpl +5 -0
- package/assets/templates/ledger_single_table_jump/form.tpl +94 -0
- package/assets/templates/ledger_single_table_jump/index.tpl +140 -0
- package/assets/templates/ledger_single_table_jump/menu.sql.tpl +12 -0
- package/assets/templates/ledger_single_table_jump/options.tpl +21 -0
- package/mcp_server.js +63 -38
- package/package.json +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="layout-padding-auto layout-padding-view">
|
|
3
|
+
<el-card shadow="never" class="w100">
|
|
4
|
+
<template #header>
|
|
5
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
6
|
+
<span style="font-size: 16px; font-weight: bold;">{{ t('common.viewBtn') }}</span>
|
|
7
|
+
<el-button @click="handleBack" icon="back">{{ commonActionLabel('back') }}</el-button>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<el-form ref="dataFormRef" :model="form" disabled v-loading="loading">
|
|
11
|
+
<el-row :gutter="24">
|
|
12
|
+
{{FORM_FIELDS}}
|
|
13
|
+
</el-row>
|
|
14
|
+
<el-row :gutter="24">
|
|
15
|
+
{{LEDGER_CHILD_SECTIONS}}
|
|
16
|
+
</el-row>
|
|
17
|
+
</el-form>
|
|
18
|
+
</el-card>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts" name="{{CLASS_NAME}}Form">
|
|
23
|
+
import { Session } from '/@/utils/storage';
|
|
24
|
+
import { useMessage } from '/@/hooks/message';
|
|
25
|
+
import { useCloseCurrentPage } from '/@/hooks/useCloseCurrentPage';
|
|
26
|
+
import { getObj } from '/@/api/{{API_MODULE_PATH}}';
|
|
27
|
+
import { useDict } from '/@/hooks/dict';
|
|
28
|
+
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
29
|
+
import { useI18n } from 'vue-i18n';
|
|
30
|
+
import { allDictTypes, childFieldGroups, dataMasterEntity } from './options';
|
|
31
|
+
|
|
32
|
+
const dictRefs = useDict(...allDictTypes);
|
|
33
|
+
const { t } = useI18n();
|
|
34
|
+
const scFormTable = defineAsyncComponent(() => import('/@/components/FormTable/index.vue'));
|
|
35
|
+
const route = useRoute();
|
|
36
|
+
const { closeCurrentPage } = useCloseCurrentPage();
|
|
37
|
+
const pageI18nKey = '{{I18N_NAMESPACE}}';
|
|
38
|
+
|
|
39
|
+
const dataFormRef = ref();
|
|
40
|
+
const loading = ref(false);
|
|
41
|
+
const detail = ref(true);
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
getFieldMeta: getMasterFieldMeta,
|
|
45
|
+
getFieldLabel: getMasterFieldLabel,
|
|
46
|
+
getChildFieldLabel,
|
|
47
|
+
getDictOptions,
|
|
48
|
+
inputPlaceholder,
|
|
49
|
+
selectPlaceholder,
|
|
50
|
+
fieldRequiredMessage,
|
|
51
|
+
commonActionLabel,
|
|
52
|
+
} = useCrudPageMeta(dataMasterEntity, dictRefs, childFieldGroups);
|
|
53
|
+
|
|
54
|
+
const formInputPlaceholder = () => '';
|
|
55
|
+
const formSelectPlaceholder = () => '';
|
|
56
|
+
const childSectionTitle = (groupName: string) => t(`${pageI18nKey}.children.${groupName}.title`);
|
|
57
|
+
|
|
58
|
+
const createDefaultFormState = () => ({
|
|
59
|
+
{{FORM_DEFAULTS}}
|
|
60
|
+
{{CHILD_FORM_LIST_DEFAULTS}}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const form = reactive(createDefaultFormState());
|
|
64
|
+
|
|
65
|
+
const get{{CLASS_NAME}}Data = async (id: string) => {
|
|
66
|
+
try {
|
|
67
|
+
loading.value = true;
|
|
68
|
+
const { data } = await getObj({ {{PK_ATTR}}: id });
|
|
69
|
+
Object.assign(form, Array.isArray(data) ? data[0] || {} : data || {});
|
|
70
|
+
} catch (error) {
|
|
71
|
+
useMessage().error(t('common.messages.fetchError'));
|
|
72
|
+
} finally {
|
|
73
|
+
loading.value = false;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const resetFormState = () => {
|
|
78
|
+
Object.assign(form, createDefaultFormState());
|
|
79
|
+
nextTick(() => {
|
|
80
|
+
dataFormRef.value?.resetFields();
|
|
81
|
+
{{CHILD_RESET_LISTS}}
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const initPage = async () => {
|
|
86
|
+
const id = route.query.id as string;
|
|
87
|
+
detail.value = true;
|
|
88
|
+
resetFormState();
|
|
89
|
+
|
|
90
|
+
if (id) {
|
|
91
|
+
form.{{PK_ATTR}} = id;
|
|
92
|
+
await get{{CLASS_NAME}}Data(id);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const handleBack = () => {
|
|
97
|
+
closeCurrentPage();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
onMounted(() => {
|
|
101
|
+
initPage();
|
|
102
|
+
});
|
|
103
|
+
</script>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="layout-padding">
|
|
3
|
+
<div class="layout-padding-auto layout-padding-view flex h-full flex-col">
|
|
4
|
+
<SchemaListToolbar
|
|
5
|
+
v-bind="toolbarProps"
|
|
6
|
+
@update:keyword="state.queryForm.smartVal = $event"
|
|
7
|
+
@query="handleToolbarQuery"
|
|
8
|
+
@reset="handleToolbarReset"
|
|
9
|
+
@custom-query-confirm="handleToolbarCustomQueryConfirm"
|
|
10
|
+
@refresh="handleToolbarRefresh"
|
|
11
|
+
/>
|
|
12
|
+
|
|
13
|
+
<SchemaListTable
|
|
14
|
+
v-bind="tableProps"
|
|
15
|
+
row-id-key="{{PK_ATTR}}"
|
|
16
|
+
:action-column-width="100"
|
|
17
|
+
@sort-change="handleTableSortChange"
|
|
18
|
+
@size-change="handleTableSizeChange"
|
|
19
|
+
@current-change="handleTableCurrentChange"
|
|
20
|
+
>
|
|
21
|
+
<template #actions="{ row }">
|
|
22
|
+
<el-button text type="primary" icon="view" v-auth="'{{PERMISSION_PREFIX}}_view'" @click="handleDetail(row.{{PK_ATTR}})">{{ t('common.viewBtn') }}</el-button>
|
|
23
|
+
</template>
|
|
24
|
+
</SchemaListTable>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts" name="system{{CLASS_NAME}}">
|
|
30
|
+
import { fetchList } from '/@/api/{{API_MODULE_PATH}}';
|
|
31
|
+
import { useDict } from '/@/hooks/dict';
|
|
32
|
+
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
33
|
+
import { useSchemaListQuery } from '/@/hooks/useSchemaListQuery';
|
|
34
|
+
import SchemaListToolbar from '/@/components/schema-list/SchemaListToolbar.vue';
|
|
35
|
+
import SchemaListTable from '/@/components/schema-list/SchemaListTable.vue';
|
|
36
|
+
import { useI18n } from 'vue-i18n';
|
|
37
|
+
import { allDictTypes, crudSchema, dataMasterEntity } from './options';
|
|
38
|
+
|
|
39
|
+
const dictRefs = useDict(...allDictTypes);
|
|
40
|
+
const { t } = useI18n();
|
|
41
|
+
const router = useRouter();
|
|
42
|
+
|
|
43
|
+
const { state, getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle, resetQueryForm } = useSchemaListQuery({
|
|
44
|
+
schema: crudSchema,
|
|
45
|
+
pageList: fetchList,
|
|
46
|
+
exportUrl: '/{{API_PATH}}/export',
|
|
47
|
+
exportFileName: '{{FUNCTION_NAME}}.xlsx',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const { resolveLabel, getDictOptions, visibleTableColumns, searchKeywordTooltip, queryableDictFields } = useCrudPageMeta(dataMasterEntity, dictRefs);
|
|
51
|
+
|
|
52
|
+
const queryableDictOptions = computed(() =>
|
|
53
|
+
queryableDictFields.value.map((field) => ({
|
|
54
|
+
...field,
|
|
55
|
+
options: getDictOptions(field.dictType),
|
|
56
|
+
}))
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const tableColumns = computed(() =>
|
|
60
|
+
visibleTableColumns.value.map((column) => ({
|
|
61
|
+
prop: column.prop,
|
|
62
|
+
label: resolveLabel(column.labelKey, column.fallbackLabel),
|
|
63
|
+
width: column.width,
|
|
64
|
+
dictType: column.dictType,
|
|
65
|
+
options: column.dictType ? getDictOptions(column.dictType) : [],
|
|
66
|
+
}))
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const toolbarProps = computed(() => ({
|
|
70
|
+
keyword: state.queryForm.smartVal,
|
|
71
|
+
searchPlaceholder: searchKeywordTooltip.value,
|
|
72
|
+
queryModel: state.queryForm,
|
|
73
|
+
customQueryFields: queryableDictOptions.value,
|
|
74
|
+
selectedIds: [],
|
|
75
|
+
showAdd: false,
|
|
76
|
+
showImport: false,
|
|
77
|
+
showDelete: false,
|
|
78
|
+
exportPermission: false,
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
const tableProps = computed(() => ({
|
|
82
|
+
data: state.dataList,
|
|
83
|
+
loading: !!state.loading,
|
|
84
|
+
columns: tableColumns.value,
|
|
85
|
+
pagination: state.pagination,
|
|
86
|
+
tableStyle,
|
|
87
|
+
showSelection: false,
|
|
88
|
+
}));
|
|
89
|
+
|
|
90
|
+
const getFormPath = () => '/{{VIEW_MODULE_PATH}}/form';
|
|
91
|
+
|
|
92
|
+
const handleDetail = (id: string) => {
|
|
93
|
+
router.push({ path: getFormPath(), query: { id, detail: '1', tagsViewName: t('common.viewBtn') } });
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const handleQueryFilterConfirm = (values: Record<string, any>) => {
|
|
97
|
+
queryableDictFields.value.forEach((field) => {
|
|
98
|
+
const nextValue = values[field.prop];
|
|
99
|
+
if (Array.isArray(nextValue) && nextValue.length) {
|
|
100
|
+
state.queryForm[field.prop] = nextValue;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
delete state.queryForm[field.prop];
|
|
104
|
+
});
|
|
105
|
+
getDataList();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const resetQuery = () => {
|
|
109
|
+
resetQueryForm();
|
|
110
|
+
getDataList();
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const handleToolbarQuery = () => {
|
|
114
|
+
getDataList();
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const handleToolbarReset = () => {
|
|
118
|
+
resetQuery();
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const handleToolbarCustomQueryConfirm = (payload: { values: Record<string, any> }) => {
|
|
122
|
+
handleQueryFilterConfirm(payload.values);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const handleToolbarRefresh = () => {
|
|
126
|
+
getDataList();
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const handleTableSortChange = (payload: { raw: any }) => {
|
|
130
|
+
sortChangeHandle(payload.raw);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const handleTableSizeChange = (payload: { size: number }) => {
|
|
134
|
+
sizeChangeHandle(payload.size);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleTableCurrentChange = (payload: { current: number }) => {
|
|
138
|
+
currentChangeHandle(payload.current);
|
|
139
|
+
};
|
|
140
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
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)
|
|
6
|
+
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1);
|
|
7
|
+
|
|
8
|
+
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)
|
|
9
|
+
values ({{MENU_BASE_ID_PLUS_6}}, '-1', '/{{MENU_ROUTE_PATH}}/form', '', '0', 'icon-biaodan', '0', '0', null, '9', null, '{{TABLE_COMMENT}}详情', 1);
|
|
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_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{{DICT_REGISTRY_IMPORT_BLOCK}}
|
|
2
|
+
import { createCrudSchema } from '/@/utils/crudSchema';
|
|
3
|
+
import type { CrudSchemaDefinition } from '/@/utils/crudSchema';
|
|
4
|
+
|
|
5
|
+
const definition: CrudSchemaDefinition = {
|
|
6
|
+
master: [
|
|
7
|
+
{{MASTER_OPTION_FIELDS}}
|
|
8
|
+
],
|
|
9
|
+
children: {
|
|
10
|
+
{{CHILD_OPTION_GROUPS}}
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const schema = createCrudSchema(definition);
|
|
15
|
+
|
|
16
|
+
export const crudSchema = schema;
|
|
17
|
+
export const dataMasterEntity = schema.master;
|
|
18
|
+
export const childFieldGroups = schema.children;
|
|
19
|
+
export const filterTypes = schema.filterTypes;
|
|
20
|
+
export const childFilterTypes = schema.childFilterTypes;
|
|
21
|
+
export const allDictTypes = schema.allDictTypes;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="layout-padding-auto layout-padding-view">
|
|
3
|
+
<el-card shadow="never" class="w100">
|
|
4
|
+
<template #header>
|
|
5
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
6
|
+
<span style="font-size: 16px; font-weight: bold;">{{ t('common.viewBtn') }}</span>
|
|
7
|
+
<el-button @click="handleBack" icon="back">{{ commonActionLabel('back') }}</el-button>
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
<el-form ref="dataFormRef" :model="form" disabled v-loading="loading">
|
|
11
|
+
<el-row :gutter="24">
|
|
12
|
+
{{FORM_FIELDS}}
|
|
13
|
+
</el-row>
|
|
14
|
+
</el-form>
|
|
15
|
+
</el-card>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts" name="{{CLASS_NAME}}Form">
|
|
20
|
+
import { Session } from '/@/utils/storage';
|
|
21
|
+
import { useMessage } from '/@/hooks/message';
|
|
22
|
+
import { useCloseCurrentPage } from '/@/hooks/useCloseCurrentPage';
|
|
23
|
+
import { getObj } from '/@/api/{{API_MODULE_PATH}}';
|
|
24
|
+
import { useDict } from '/@/hooks/dict';
|
|
25
|
+
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
26
|
+
import { useI18n } from 'vue-i18n';
|
|
27
|
+
import { allDictTypes, dataMasterEntity } from './options';
|
|
28
|
+
|
|
29
|
+
const dictRefs = useDict(...allDictTypes);
|
|
30
|
+
const { t } = useI18n();
|
|
31
|
+
const route = useRoute();
|
|
32
|
+
const { closeCurrentPage } = useCloseCurrentPage();
|
|
33
|
+
|
|
34
|
+
const dataFormRef = ref();
|
|
35
|
+
const loading = ref(false);
|
|
36
|
+
const detail = ref(true);
|
|
37
|
+
|
|
38
|
+
const {
|
|
39
|
+
getFieldMeta: getMasterFieldMeta,
|
|
40
|
+
getFieldLabel: getMasterFieldLabel,
|
|
41
|
+
getDictOptions,
|
|
42
|
+
inputPlaceholder,
|
|
43
|
+
selectPlaceholder,
|
|
44
|
+
fieldRequiredMessage,
|
|
45
|
+
commonActionLabel,
|
|
46
|
+
} = useCrudPageMeta(dataMasterEntity, dictRefs);
|
|
47
|
+
|
|
48
|
+
const formInputPlaceholder = () => '';
|
|
49
|
+
const formSelectPlaceholder = () => '';
|
|
50
|
+
|
|
51
|
+
const createDefaultFormState = () => ({
|
|
52
|
+
{{FORM_DEFAULTS}}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const form = reactive(createDefaultFormState());
|
|
56
|
+
|
|
57
|
+
const get{{CLASS_NAME}}Data = async (id: string) => {
|
|
58
|
+
try {
|
|
59
|
+
loading.value = true;
|
|
60
|
+
const { data } = await getObj({ {{PK_ATTR}}: id });
|
|
61
|
+
Object.assign(form, Array.isArray(data) ? data[0] || {} : data || {});
|
|
62
|
+
} catch (error) {
|
|
63
|
+
useMessage().error(t('common.messages.fetchError'));
|
|
64
|
+
} finally {
|
|
65
|
+
loading.value = false;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const resetFormState = () => {
|
|
70
|
+
Object.assign(form, createDefaultFormState());
|
|
71
|
+
nextTick(() => {
|
|
72
|
+
dataFormRef.value?.resetFields();
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const initPage = async () => {
|
|
77
|
+
const id = route.query.id as string;
|
|
78
|
+
detail.value = true;
|
|
79
|
+
resetFormState();
|
|
80
|
+
|
|
81
|
+
if (id) {
|
|
82
|
+
form.{{PK_ATTR}} = id;
|
|
83
|
+
await get{{CLASS_NAME}}Data(id);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const handleBack = () => {
|
|
88
|
+
closeCurrentPage();
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
onMounted(() => {
|
|
92
|
+
initPage();
|
|
93
|
+
});
|
|
94
|
+
</script>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="layout-padding">
|
|
3
|
+
<div class="layout-padding-auto layout-padding-view flex h-full flex-col">
|
|
4
|
+
<SchemaListToolbar
|
|
5
|
+
v-bind="toolbarProps"
|
|
6
|
+
@update:keyword="state.queryForm.smartVal = $event"
|
|
7
|
+
@query="handleToolbarQuery"
|
|
8
|
+
@reset="handleToolbarReset"
|
|
9
|
+
@custom-query-confirm="handleToolbarCustomQueryConfirm"
|
|
10
|
+
@refresh="handleToolbarRefresh"
|
|
11
|
+
/>
|
|
12
|
+
|
|
13
|
+
<SchemaListTable
|
|
14
|
+
v-bind="tableProps"
|
|
15
|
+
row-id-key="{{PK_ATTR}}"
|
|
16
|
+
:action-column-width="100"
|
|
17
|
+
@sort-change="handleTableSortChange"
|
|
18
|
+
@size-change="handleTableSizeChange"
|
|
19
|
+
@current-change="handleTableCurrentChange"
|
|
20
|
+
>
|
|
21
|
+
<template #actions="{ row }">
|
|
22
|
+
<el-button text type="primary" icon="view" v-auth="'{{PERMISSION_PREFIX}}_view'" @click="handleDetail(row.{{PK_ATTR}})">{{ t('common.viewBtn') }}</el-button>
|
|
23
|
+
</template>
|
|
24
|
+
</SchemaListTable>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
28
|
+
|
|
29
|
+
<script setup lang="ts" name="system{{CLASS_NAME}}">
|
|
30
|
+
import { fetchList } from '/@/api/{{API_MODULE_PATH}}';
|
|
31
|
+
import { useDict } from '/@/hooks/dict';
|
|
32
|
+
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
33
|
+
import { useSchemaListQuery } from '/@/hooks/useSchemaListQuery';
|
|
34
|
+
import SchemaListToolbar from '/@/components/schema-list/SchemaListToolbar.vue';
|
|
35
|
+
import SchemaListTable from '/@/components/schema-list/SchemaListTable.vue';
|
|
36
|
+
import { useI18n } from 'vue-i18n';
|
|
37
|
+
import { allDictTypes, crudSchema, dataMasterEntity } from './options';
|
|
38
|
+
|
|
39
|
+
const dictRefs = useDict(...allDictTypes);
|
|
40
|
+
const { t } = useI18n();
|
|
41
|
+
const router = useRouter();
|
|
42
|
+
|
|
43
|
+
const { state, getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, tableStyle, resetQueryForm } = useSchemaListQuery({
|
|
44
|
+
schema: crudSchema,
|
|
45
|
+
pageList: fetchList,
|
|
46
|
+
exportUrl: '/{{API_PATH}}/export',
|
|
47
|
+
exportFileName: '{{FUNCTION_NAME}}.xlsx',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const { resolveLabel, getDictOptions, visibleTableColumns, searchKeywordTooltip, queryableDictFields } = useCrudPageMeta(dataMasterEntity, dictRefs);
|
|
51
|
+
|
|
52
|
+
const queryableDictOptions = computed(() =>
|
|
53
|
+
queryableDictFields.value.map((field) => ({
|
|
54
|
+
...field,
|
|
55
|
+
options: getDictOptions(field.dictType),
|
|
56
|
+
}))
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const tableColumns = computed(() =>
|
|
60
|
+
visibleTableColumns.value.map((column) => ({
|
|
61
|
+
prop: column.prop,
|
|
62
|
+
label: resolveLabel(column.labelKey, column.fallbackLabel),
|
|
63
|
+
width: column.width,
|
|
64
|
+
dictType: column.dictType,
|
|
65
|
+
options: column.dictType ? getDictOptions(column.dictType) : [],
|
|
66
|
+
}))
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const toolbarProps = computed(() => ({
|
|
70
|
+
keyword: state.queryForm.smartVal,
|
|
71
|
+
searchPlaceholder: searchKeywordTooltip.value,
|
|
72
|
+
queryModel: state.queryForm,
|
|
73
|
+
customQueryFields: queryableDictOptions.value,
|
|
74
|
+
selectedIds: [],
|
|
75
|
+
showAdd: false,
|
|
76
|
+
showImport: false,
|
|
77
|
+
showDelete: false,
|
|
78
|
+
exportPermission: false,
|
|
79
|
+
}));
|
|
80
|
+
|
|
81
|
+
const tableProps = computed(() => ({
|
|
82
|
+
data: state.dataList,
|
|
83
|
+
loading: !!state.loading,
|
|
84
|
+
columns: tableColumns.value,
|
|
85
|
+
pagination: state.pagination,
|
|
86
|
+
tableStyle,
|
|
87
|
+
showSelection: false,
|
|
88
|
+
}));
|
|
89
|
+
|
|
90
|
+
const getFormPath = () => '/{{VIEW_MODULE_PATH}}/form';
|
|
91
|
+
|
|
92
|
+
const handleDetail = (id: string) => {
|
|
93
|
+
router.push({ path: getFormPath(), query: { id, detail: '1', tagsViewName: t('common.viewBtn') } });
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const handleQueryFilterConfirm = (values: Record<string, any>) => {
|
|
97
|
+
queryableDictFields.value.forEach((field) => {
|
|
98
|
+
const nextValue = values[field.prop];
|
|
99
|
+
if (Array.isArray(nextValue) && nextValue.length) {
|
|
100
|
+
state.queryForm[field.prop] = nextValue;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
delete state.queryForm[field.prop];
|
|
104
|
+
});
|
|
105
|
+
getDataList();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const resetQuery = () => {
|
|
109
|
+
resetQueryForm();
|
|
110
|
+
getDataList();
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const handleToolbarQuery = () => {
|
|
114
|
+
getDataList();
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const handleToolbarReset = () => {
|
|
118
|
+
resetQuery();
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const handleToolbarCustomQueryConfirm = (payload: { values: Record<string, any> }) => {
|
|
122
|
+
handleQueryFilterConfirm(payload.values);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const handleToolbarRefresh = () => {
|
|
126
|
+
getDataList();
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const handleTableSortChange = (payload: { raw: any }) => {
|
|
130
|
+
sortChangeHandle(payload.raw);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const handleTableSizeChange = (payload: { size: number }) => {
|
|
134
|
+
sizeChangeHandle(payload.size);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleTableCurrentChange = (payload: { current: number }) => {
|
|
138
|
+
currentChangeHandle(payload.current);
|
|
139
|
+
};
|
|
140
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
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)
|
|
6
|
+
values ({{MENU_BASE_ID}}, '-1', '/{{MENU_ROUTE_PATH}}/index', '', '0', 'icon-bangzhushouji', '0', null, '8', null, '{{TABLE_COMMENT}}管理', 1);
|
|
7
|
+
|
|
8
|
+
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)
|
|
9
|
+
values ({{MENU_BASE_ID_PLUS_6}}, '-1', '/{{MENU_ROUTE_PATH}}/form', '', '0', 'icon-biaodan', '0', '0', null, '9', null, '{{TABLE_COMMENT}}详情', 1);
|
|
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_1}}, {{MENU_BASE_ID}}, '{{PERMISSION_PREFIX}}_view', '1', null, '1', '0', null, '0', null, '{{TABLE_COMMENT}}查看', 1);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{{DICT_REGISTRY_IMPORT_BLOCK}}
|
|
2
|
+
import { createCrudSchema } from '/@/utils/crudSchema';
|
|
3
|
+
import type { CrudSchemaDefinition } from '/@/utils/crudSchema';
|
|
4
|
+
|
|
5
|
+
const definition: CrudSchemaDefinition = {
|
|
6
|
+
master: [
|
|
7
|
+
{{MASTER_OPTION_FIELDS}}
|
|
8
|
+
],
|
|
9
|
+
children: {
|
|
10
|
+
{{CHILD_OPTION_GROUPS}}
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const schema = createCrudSchema(definition);
|
|
15
|
+
|
|
16
|
+
export const crudSchema = schema;
|
|
17
|
+
export const dataMasterEntity = schema.master;
|
|
18
|
+
export const childFieldGroups = schema.children;
|
|
19
|
+
export const filterTypes = schema.filterTypes;
|
|
20
|
+
export const childFilterTypes = schema.childFilterTypes;
|
|
21
|
+
export const allDictTypes = schema.allDictTypes;
|
package/mcp_server.js
CHANGED
|
@@ -267,10 +267,10 @@ const TOOL_SCHEMA = {
|
|
|
267
267
|
tableName: { type: 'string', description: 'Canonical main table name from PRD-aligned structured metadata.' },
|
|
268
268
|
tableComment: { type: 'string', description: 'Canonical main table comment or feature label from PRD-aligned structured metadata.' },
|
|
269
269
|
apiPath: { type: 'string', description: 'Backend API base path from pre-parsed structured metadata, for example iwmEmpOutsourcePerson.' },
|
|
270
|
-
pageType: {
|
|
271
|
-
type: 'string',
|
|
272
|
-
enum: ['business', 'dict', 'non_standard'],
|
|
273
|
-
description: 'Structured page type from parseResult. MCP consumes this value but does not derive it. Dict pages are restricted to dialog-based templates.',
|
|
270
|
+
pageType: {
|
|
271
|
+
type: 'string',
|
|
272
|
+
enum: ['business', 'dict', 'ledger', 'non_standard'],
|
|
273
|
+
description: 'Structured page type from parseResult. MCP consumes this value but does not derive it. Dict pages are restricted to dialog-based templates. Ledger pages are read-only jump-based templates.',
|
|
274
274
|
},
|
|
275
275
|
style: { type: 'string', enum: Object.keys(STYLE_CATALOG), description: 'Final style id from parseResult or translated mcpPayload. MCP validates it but does not infer it.' },
|
|
276
276
|
fields: {
|
|
@@ -1641,12 +1641,12 @@ function getStylePreset(styleId) {
|
|
|
1641
1641
|
return preset;
|
|
1642
1642
|
}
|
|
1643
1643
|
|
|
1644
|
-
function normalizePageTypeInput(pageType) {
|
|
1645
|
-
if (pageType === undefined || pageType === null || pageType === '') return '';
|
|
1646
|
-
const normalized = String(pageType).trim();
|
|
1647
|
-
if (['business', 'dict', 'non_standard'].includes(normalized)) return normalized;
|
|
1648
|
-
throw new Error(`Unsupported pageType: ${normalized}. Allowed values are dict, business, non_standard.`);
|
|
1649
|
-
}
|
|
1644
|
+
function normalizePageTypeInput(pageType) {
|
|
1645
|
+
if (pageType === undefined || pageType === null || pageType === '') return '';
|
|
1646
|
+
const normalized = String(pageType).trim();
|
|
1647
|
+
if (['business', 'dict', 'ledger', 'non_standard'].includes(normalized)) return normalized;
|
|
1648
|
+
throw new Error(`Unsupported pageType: ${normalized}. Allowed values are dict, business, ledger, non_standard.`);
|
|
1649
|
+
}
|
|
1650
1650
|
|
|
1651
1651
|
function rejectSemanticStageInputs(input) {
|
|
1652
1652
|
const forbiddenKeys = [
|
|
@@ -1669,17 +1669,23 @@ function validatePageTypeAndStyle(pageType, style) {
|
|
|
1669
1669
|
if (pageType === 'non_standard') {
|
|
1670
1670
|
throw new Error('non_standard pages are not supported by worsoft_codegen_local_generate_frontend');
|
|
1671
1671
|
}
|
|
1672
|
-
if (pageType === 'business') {
|
|
1673
|
-
if (style === 'single_table_dialog') {
|
|
1674
|
-
throw new Error('Business pages must use jump-based styles. pageType=business does not support style=single_table_dialog; use single_table_jump for single-table business pages or master_child_jump for master-child business pages.');
|
|
1675
|
-
}
|
|
1676
|
-
return;
|
|
1677
|
-
}
|
|
1678
|
-
if (pageType
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1672
|
+
if (pageType === 'business') {
|
|
1673
|
+
if (style === 'single_table_dialog') {
|
|
1674
|
+
throw new Error('Business pages must use jump-based styles. pageType=business does not support style=single_table_dialog; use single_table_jump for single-table business pages or master_child_jump for master-child business pages.');
|
|
1675
|
+
}
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
if (pageType === 'ledger') {
|
|
1679
|
+
if (style !== 'single_table_jump' && style !== 'master_child_jump') {
|
|
1680
|
+
throw new Error('Ledger pages must use jump-based styles. pageType=ledger supports single_table_jump or master_child_jump only.');
|
|
1681
|
+
}
|
|
1682
|
+
return;
|
|
1683
|
+
}
|
|
1684
|
+
if (pageType !== 'dict') return;
|
|
1685
|
+
if (style === 'single_table_jump' || style === 'master_child_jump') {
|
|
1686
|
+
throw new Error(`Dict pages must use dialog-based styles. pageType=dict does not support style=${style}`);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1683
1689
|
|
|
1684
1690
|
function hasRuntimeSupport(stylePreset) {
|
|
1685
1691
|
return Boolean(stylePreset.runtime && stylePreset.runtime.supported && stylePreset.runtime.templateDir);
|
|
@@ -2181,8 +2187,8 @@ function renderChildTempDeclaration(childModel) {
|
|
|
2181
2187
|
].join('\n');
|
|
2182
2188
|
}
|
|
2183
2189
|
|
|
2184
|
-
function renderChildSection(childModel, childCount) {
|
|
2185
|
-
const deleteExpression = `deleteChild(obj, '${childModel.pk.attrName}')`;
|
|
2190
|
+
function renderChildSection(childModel, childCount) {
|
|
2191
|
+
const deleteExpression = `deleteChild(obj, '${childModel.pk.attrName}')`;
|
|
2186
2192
|
|
|
2187
2193
|
return [
|
|
2188
2194
|
' <el-col :span="24" class="mb20">',
|
|
@@ -3413,6 +3419,21 @@ function renderBusinessDeleteGuard(model) {
|
|
|
3413
3419
|
].join('\n');
|
|
3414
3420
|
}
|
|
3415
3421
|
|
|
3422
|
+
function asReadonlyField(field) {
|
|
3423
|
+
return { ...field, readonly: true };
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3426
|
+
function renderLedgerChildSection(childModel) {
|
|
3427
|
+
return [
|
|
3428
|
+
' <el-col :span="24" class="mb20">',
|
|
3429
|
+
` <div class="mb10" style="font-weight: 600;">{{ childSectionTitle('${childModel.listName}') }}</div>`,
|
|
3430
|
+
` <sc-form-table v-model="form.${childModel.listName}" hide-add hide-delete :placeholder="t('common.noData')">`,
|
|
3431
|
+
childModel.visibleFields.map((field) => renderChildTableColumn(asReadonlyField(field), childModel.listName)).join('\n'),
|
|
3432
|
+
' </sc-form-table>',
|
|
3433
|
+
' </el-col>',
|
|
3434
|
+
].join('\n');
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3416
3437
|
function renderBusinessSubmitStatusAssignment(model) {
|
|
3417
3438
|
if (!hasBusinessBillStateEditControl(model)) return '';
|
|
3418
3439
|
const statusAttr = toCamelCase(model.statusField);
|
|
@@ -3541,7 +3562,7 @@ function buildReplacements(model, sharedSupport) {
|
|
|
3541
3562
|
MENU_BASE_ID_PLUS_5: menuBaseId + 5,
|
|
3542
3563
|
MENU_BASE_ID_PLUS_6: menuBaseId + 6,
|
|
3543
3564
|
GENERATED_AT: new Date().toISOString(),
|
|
3544
|
-
FORM_FIELDS: model.visibleFields.map(renderFormFieldV2).join('\n'),
|
|
3565
|
+
FORM_FIELDS: (model.pageType === 'ledger' ? model.visibleFields.map(asReadonlyField) : model.visibleFields).map(renderFormFieldV2).join('\n'),
|
|
3545
3566
|
TABLE_COLUMNS: model.gridFields.map((field) => renderTableColumn(field, dictRegistryRefs)).join('\n'),
|
|
3546
3567
|
FORM_DEFAULTS: renderFormDefaults(model),
|
|
3547
3568
|
DICT_REGISTRY_IMPORT_BLOCK: model.dictTypes.length ? "import { DictRegistry } from '/@/enums/dict-registry';" : '',
|
|
@@ -3549,21 +3570,25 @@ function buildReplacements(model, sharedSupport) {
|
|
|
3549
3570
|
CHILD_OPTION_GROUPS: model.children.map((childModel) => renderChildOptionGroupV2(model, childModel, dictRegistryRefs)).join('\n'),
|
|
3550
3571
|
FORM_RULES: renderFormRulesV2(model.visibleFields),
|
|
3551
3572
|
CHILD_FORM_LIST_DEFAULTS: renderChildFormListDefaults(model.children),
|
|
3552
|
-
CHILD_TEMP_DECLARATIONS: renderChildTempDeclarations(model.children),
|
|
3553
|
-
CHILD_RESET_LISTS: renderChildResetListLines(model.children),
|
|
3554
|
-
CHILD_SECTIONS: model.children.map((childModel) => renderChildSection(childModel, model.children.length)).join('\n'),
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
function renderFiles(model, stylePreset, sharedSupport, localeZhSupport) {
|
|
3559
|
-
if (!hasRuntimeSupport(stylePreset)) throw new Error('Runtime templates are not implemented for style: ' + model.style);
|
|
3560
|
-
if (model.style === 'multi_level_dict') {
|
|
3561
|
-
return renderMultiLevelFiles(model, sharedSupport, localeZhSupport);
|
|
3562
|
-
}
|
|
3573
|
+
CHILD_TEMP_DECLARATIONS: renderChildTempDeclarations(model.children),
|
|
3574
|
+
CHILD_RESET_LISTS: renderChildResetListLines(model.children),
|
|
3575
|
+
CHILD_SECTIONS: model.children.map((childModel) => renderChildSection(childModel, model.children.length)).join('\n'),
|
|
3576
|
+
LEDGER_CHILD_SECTIONS: model.children.map((childModel) => renderLedgerChildSection(childModel)).join('\n'),
|
|
3577
|
+
};
|
|
3578
|
+
}
|
|
3563
3579
|
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3580
|
+
function renderFiles(model, stylePreset, sharedSupport, localeZhSupport) {
|
|
3581
|
+
if (!hasRuntimeSupport(stylePreset)) throw new Error('Runtime templates are not implemented for style: ' + model.style);
|
|
3582
|
+
if (model.style === 'multi_level_dict') {
|
|
3583
|
+
return renderMultiLevelFiles(model, sharedSupport, localeZhSupport);
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
const runtime = stylePreset.runtime;
|
|
3587
|
+
const templateDir =
|
|
3588
|
+
model.pageType === 'ledger'
|
|
3589
|
+
? path.resolve(__dirname, 'assets/templates/ledger_' + model.style)
|
|
3590
|
+
: path.resolve(__dirname, runtime.templateDir);
|
|
3591
|
+
const replacements = buildReplacements(model, sharedSupport);
|
|
3567
3592
|
const formTemplate = fs.readFileSync(path.join(templateDir, runtime.files.form), 'utf8');
|
|
3568
3593
|
const listTemplate = fs.readFileSync(path.join(templateDir, runtime.files.list), 'utf8');
|
|
3569
3594
|
const optionsTemplate = fs.readFileSync(path.join(templateDir, runtime.files.options), 'utf8');
|
package/package.json
CHANGED