worsoft-frontend-codegen-local-mcp 0.1.69 → 0.1.71
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.
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
|
|
39
39
|
<script setup lang="ts" name="{{CLASS_NAME}}Form">
|
|
40
40
|
// 标签页关闭总线
|
|
41
|
-
import mittBus from '/@/utils/mitt';
|
|
42
41
|
// 本地会话存储
|
|
43
42
|
import { Session } from '/@/utils/storage';
|
|
44
43
|
// 通用消息提示
|
|
45
44
|
import { useMessage } from '/@/hooks/message';
|
|
45
|
+
import { useCloseCurrentPage } from '/@/hooks/useCloseCurrentPage';
|
|
46
46
|
// 表单数据接口
|
|
47
47
|
import { getObj, addObj, putObj } from '/@/api/{{API_MODULE_PATH}}';
|
|
48
48
|
// 字典数据加载
|
|
@@ -51,6 +51,7 @@ import { useDict } from '/@/hooks/dict';
|
|
|
51
51
|
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
52
52
|
// 国际化能力
|
|
53
53
|
import { useI18n } from 'vue-i18n';
|
|
54
|
+
{{BUSINESS_FORM_STATUS_IMPORTS}}
|
|
54
55
|
// 当前页面的字段配置
|
|
55
56
|
import { allDictTypes, childFieldGroups, dataMasterEntity } from './options';
|
|
56
57
|
|
|
@@ -65,6 +66,7 @@ const scFormTable = defineAsyncComponent(() => import('/@/components/FormTable/i
|
|
|
65
66
|
const route = useRoute();
|
|
66
67
|
// 路由跳转能力
|
|
67
68
|
const router = useRouter();
|
|
69
|
+
const { closeCurrentPage } = useCloseCurrentPage();
|
|
68
70
|
// 当前页面的国际化命名空间
|
|
69
71
|
const pageI18nKey = '{{I18N_NAMESPACE}}';
|
|
70
72
|
|
|
@@ -146,14 +148,9 @@ const initPage = async () => {
|
|
|
146
148
|
}
|
|
147
149
|
};
|
|
148
150
|
|
|
149
|
-
// 关闭当前标签页
|
|
150
|
-
const closeCurrentPage = () => {
|
|
151
|
-
mittBus.emit('onCurrentContextmenuClick', { contextMenuClickId: 1, ...route });
|
|
152
|
-
};
|
|
153
|
-
|
|
154
151
|
// 返回上一页
|
|
155
152
|
const handleBack = () => {
|
|
156
|
-
|
|
153
|
+
closeCurrentPage();
|
|
157
154
|
};
|
|
158
155
|
|
|
159
156
|
// 保存、提交和流转共用同一套提交逻辑
|
|
@@ -169,7 +166,8 @@ const onSubmit = async (actionType?: string) => {
|
|
|
169
166
|
}
|
|
170
167
|
|
|
171
168
|
try {
|
|
172
|
-
|
|
169
|
+
const submitData = Object.assign({}, form{{BUSINESS_SUBMIT_STATUS_ASSIGNMENT}});
|
|
170
|
+
form.{{PK_ATTR}} ? await putObj(submitData) : await addObj(submitData);
|
|
173
171
|
|
|
174
172
|
let msg = form.{{PK_ATTR}} ? t('common.editSuccessText') : t('common.addSuccessText');
|
|
175
173
|
if (actionType === 'submit') msg = t('common.messages.quickSubmitSuccess');
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
<!-- 流转{{FEATURE_TITLE}} -->
|
|
38
38
|
<el-button text type="success" icon="position" @click="handleQuickAction(row, 'flow')">{{ commonActionLabel('flow') }}</el-button>
|
|
39
39
|
<!-- 删除{{FEATURE_TITLE}} -->
|
|
40
|
-
<el-button icon="delete" text type="primary" v-auth="'{{PERMISSION_PREFIX}}_del'" @click="handleDelete([row.{{PK_ATTR}}])">{{ t('common.delBtn') }}</el-button>
|
|
40
|
+
<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>
|
|
41
41
|
</template>
|
|
42
42
|
</SchemaListTable>
|
|
43
43
|
</div>
|
|
@@ -80,6 +80,7 @@ const router = useRouter();
|
|
|
80
80
|
const excelUploadRef = ref();
|
|
81
81
|
// 列表勾选主键集合
|
|
82
82
|
const selectObjs = ref<string[]>([]);
|
|
83
|
+
{{BUSINESS_SELECTED_ROWS_DECLARATION}}
|
|
83
84
|
// 批量删除按钮状态
|
|
84
85
|
const multiple = ref(true);
|
|
85
86
|
|
|
@@ -120,7 +121,7 @@ const toolbarProps = computed(() => ({
|
|
|
120
121
|
queryModel: state.queryForm,
|
|
121
122
|
customQueryFields: queryableDictOptions.value,
|
|
122
123
|
selectedIds: selectObjs.value,
|
|
123
|
-
deleteDisabled: multiple.value,
|
|
124
|
+
deleteDisabled: multiple.value{{BUSINESS_DELETE_DISABLED_EXPR}},
|
|
124
125
|
exportPermission: '{{PERMISSION_PREFIX}}_export',
|
|
125
126
|
}));
|
|
126
127
|
|
|
@@ -195,7 +196,8 @@ const resetQuery = () => {
|
|
|
195
196
|
};
|
|
196
197
|
|
|
197
198
|
// 删除列表数据
|
|
198
|
-
const handleDelete = async (ids: string[]) => {
|
|
199
|
+
const handleDelete = async (ids: string[]{{BUSINESS_DELETE_ROWS_PARAM}}) => {
|
|
200
|
+
{{BUSINESS_DELETE_GUARD}}
|
|
199
201
|
try {
|
|
200
202
|
await useMessageBox().confirm(t('common.delConfirmText'));
|
|
201
203
|
} catch {
|
|
@@ -223,7 +225,7 @@ const handleToolbarImport = () => {
|
|
|
223
225
|
|
|
224
226
|
// 工具栏批量删除事件
|
|
225
227
|
const handleToolbarDelete = () => {
|
|
226
|
-
handleDelete(selectObjs.value);
|
|
228
|
+
handleDelete(selectObjs.value{{BUSINESS_SELECTED_ROWS_ARG}});
|
|
227
229
|
};
|
|
228
230
|
|
|
229
231
|
// 工具栏查询事件
|
|
@@ -252,7 +254,8 @@ const handleToolbarRefresh = () => {
|
|
|
252
254
|
};
|
|
253
255
|
|
|
254
256
|
// 表格勾选变化事件
|
|
255
|
-
const handleTableSelectionChange = (payload: { ids: Array<string | number> }) => {
|
|
257
|
+
const handleTableSelectionChange = (payload: { rows: any[]; ids: Array<string | number> }) => {
|
|
258
|
+
{{BUSINESS_SELECTED_ROWS_ASSIGNMENT}}
|
|
256
259
|
selectObjs.value = payload.ids.map((id) => String(id));
|
|
257
260
|
multiple.value = !payload.ids.length;
|
|
258
261
|
};
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
|
|
35
35
|
<script setup lang="ts" name="{{CLASS_NAME}}Form">
|
|
36
36
|
// 标签页关闭总线
|
|
37
|
-
import mittBus from '/@/utils/mitt';
|
|
38
37
|
// 本地会话存储
|
|
39
38
|
import { Session } from '/@/utils/storage';
|
|
40
39
|
// 通用消息提示
|
|
41
40
|
import { useMessage } from '/@/hooks/message';
|
|
41
|
+
import { useCloseCurrentPage } from '/@/hooks/useCloseCurrentPage';
|
|
42
42
|
// 表单数据接口
|
|
43
43
|
import { getObj, addObj, putObj } from '/@/api/{{API_MODULE_PATH}}';
|
|
44
44
|
// 字典数据加载
|
|
@@ -47,6 +47,7 @@ import { useDict } from '/@/hooks/dict';
|
|
|
47
47
|
import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
|
|
48
48
|
// 国际化能力
|
|
49
49
|
import { useI18n } from 'vue-i18n';
|
|
50
|
+
{{BUSINESS_FORM_STATUS_IMPORTS}}
|
|
50
51
|
// 当前页面的字段配置
|
|
51
52
|
import { allDictTypes, dataMasterEntity } from './options';
|
|
52
53
|
|
|
@@ -58,6 +59,7 @@ const { t } = useI18n();
|
|
|
58
59
|
const route = useRoute();
|
|
59
60
|
// 路由跳转能力
|
|
60
61
|
const router = useRouter();
|
|
62
|
+
const { closeCurrentPage } = useCloseCurrentPage();
|
|
61
63
|
|
|
62
64
|
// 表单引用
|
|
63
65
|
const dataFormRef = ref();
|
|
@@ -128,14 +130,9 @@ const initPage = async () => {
|
|
|
128
130
|
}
|
|
129
131
|
};
|
|
130
132
|
|
|
131
|
-
// 关闭当前标签页
|
|
132
|
-
const closeCurrentPage = () => {
|
|
133
|
-
mittBus.emit('onCurrentContextmenuClick', { contextMenuClickId: 1, ...route });
|
|
134
|
-
};
|
|
135
|
-
|
|
136
133
|
// 返回上一页
|
|
137
134
|
const handleBack = () => {
|
|
138
|
-
|
|
135
|
+
closeCurrentPage();
|
|
139
136
|
};
|
|
140
137
|
|
|
141
138
|
// 保存、提交和流转共用同一套提交逻辑
|
|
@@ -151,7 +148,8 @@ const onSubmit = async (actionType?: string) => {
|
|
|
151
148
|
}
|
|
152
149
|
|
|
153
150
|
try {
|
|
154
|
-
|
|
151
|
+
const submitData = Object.assign({}, form{{BUSINESS_SUBMIT_STATUS_ASSIGNMENT}});
|
|
152
|
+
form.{{PK_ATTR}} ? await putObj(submitData) : await addObj(submitData);
|
|
155
153
|
|
|
156
154
|
let msg = form.{{PK_ATTR}} ? t('common.editSuccessText') : t('common.addSuccessText');
|
|
157
155
|
if (actionType === 'submit') msg = t('common.messages.quickSubmitSuccess');
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
<!-- 编辑{{FEATURE_TITLE}}:业务单据编辑态控制按需生效 -->
|
|
35
35
|
<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
36
|
<!-- 删除{{FEATURE_TITLE}} -->
|
|
37
|
-
<el-button icon="delete" text type="primary" v-auth="'{{PERMISSION_PREFIX}}_del'" @click="handleDelete([row.{{PK_ATTR}}])">{{ t('common.delBtn') }}</el-button>
|
|
37
|
+
<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>
|
|
38
38
|
</template>
|
|
39
39
|
</SchemaListTable>
|
|
40
40
|
</div>
|
|
@@ -77,6 +77,7 @@ const router = useRouter();
|
|
|
77
77
|
const excelUploadRef = ref();
|
|
78
78
|
// 列表勾选主键集合
|
|
79
79
|
const selectObjs = ref<string[]>([]);
|
|
80
|
+
{{BUSINESS_SELECTED_ROWS_DECLARATION}}
|
|
80
81
|
// 批量删除按钮状态
|
|
81
82
|
const multiple = ref(true);
|
|
82
83
|
|
|
@@ -117,7 +118,7 @@ const toolbarProps = computed(() => ({
|
|
|
117
118
|
queryModel: state.queryForm,
|
|
118
119
|
customQueryFields: queryableDictOptions.value,
|
|
119
120
|
selectedIds: selectObjs.value,
|
|
120
|
-
deleteDisabled: multiple.value,
|
|
121
|
+
deleteDisabled: multiple.value{{BUSINESS_DELETE_DISABLED_EXPR}},
|
|
121
122
|
addPermission: '{{PERMISSION_PREFIX}}_add',
|
|
122
123
|
importPermission: '{{PERMISSION_PREFIX}}_add',
|
|
123
124
|
deletePermission: '{{PERMISSION_PREFIX}}_del',
|
|
@@ -179,7 +180,8 @@ const resetQuery = () => {
|
|
|
179
180
|
};
|
|
180
181
|
|
|
181
182
|
// 删除列表数据
|
|
182
|
-
const handleDelete = async (ids: string[]) => {
|
|
183
|
+
const handleDelete = async (ids: string[]{{BUSINESS_DELETE_ROWS_PARAM}}) => {
|
|
184
|
+
{{BUSINESS_DELETE_GUARD}}
|
|
183
185
|
try {
|
|
184
186
|
await useMessageBox().confirm(t('common.delConfirmText'));
|
|
185
187
|
} catch {
|
|
@@ -207,7 +209,7 @@ const handleToolbarImport = () => {
|
|
|
207
209
|
|
|
208
210
|
// 工具栏批量删除事件
|
|
209
211
|
const handleToolbarDelete = () => {
|
|
210
|
-
handleDelete(selectObjs.value);
|
|
212
|
+
handleDelete(selectObjs.value{{BUSINESS_SELECTED_ROWS_ARG}});
|
|
211
213
|
};
|
|
212
214
|
|
|
213
215
|
// 工具栏查询事件
|
|
@@ -236,7 +238,8 @@ const handleToolbarRefresh = () => {
|
|
|
236
238
|
};
|
|
237
239
|
|
|
238
240
|
// 表格勾选变化事件
|
|
239
|
-
const handleTableSelectionChange = (payload: { ids: Array<string | number> }) => {
|
|
241
|
+
const handleTableSelectionChange = (payload: { rows: any[]; ids: Array<string | number> }) => {
|
|
242
|
+
{{BUSINESS_SELECTED_ROWS_ASSIGNMENT}}
|
|
240
243
|
selectObjs.value = payload.ids.map((id) => String(id));
|
|
241
244
|
multiple.value = !payload.ids.length;
|
|
242
245
|
};
|
package/mcp_server.js
CHANGED
|
@@ -5,7 +5,7 @@ const fs = require('fs');
|
|
|
5
5
|
const path = require('path');
|
|
6
6
|
|
|
7
7
|
const SERVER_NAME = 'worsoft-codegen-local';
|
|
8
|
-
const SERVER_VERSION = '0.1.
|
|
8
|
+
const SERVER_VERSION = '0.1.71';
|
|
9
9
|
const PROTOCOL_VERSION = '2024-11-05';
|
|
10
10
|
const TOOL_NAME = 'worsoft_codegen_local_generate_frontend';
|
|
11
11
|
const STYLE_CATALOG_PATH = path.join(__dirname, 'assets', 'style-catalog.json');
|
|
@@ -204,6 +204,48 @@ export const createCrudApi = (baseUrl: string, overrides: CrudApiPathOverrides =
|
|
|
204
204
|
});
|
|
205
205
|
`;
|
|
206
206
|
|
|
207
|
+
const DEFAULT_CLOSE_CURRENT_PAGE_TEMPLATE = `import type { RouteLocationNormalizedLoaded } from 'vue-router';
|
|
208
|
+
import { useRoute } from 'vue-router';
|
|
209
|
+
import mittBus from '/@/utils/mitt';
|
|
210
|
+
|
|
211
|
+
export const closeCurrentRoutePage = (route: RouteLocationNormalizedLoaded) => {
|
|
212
|
+
\tmittBus.emit('onCurrentContextmenuClick', {
|
|
213
|
+
\t\tcontextMenuClickId: 1,
|
|
214
|
+
\t\tpath: route.path,
|
|
215
|
+
\t\tquery: { ...route.query },
|
|
216
|
+
\t\tparams: { ...route.params },
|
|
217
|
+
\t\tmeta: { ...route.meta },
|
|
218
|
+
\t\tname: route.name,
|
|
219
|
+
\t});
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export function useCloseCurrentPage() {
|
|
223
|
+
\tconst route = useRoute();
|
|
224
|
+
|
|
225
|
+
\tconst closeCurrentPage = () => {
|
|
226
|
+
\t\tcloseCurrentRoutePage(route);
|
|
227
|
+
\t};
|
|
228
|
+
|
|
229
|
+
\treturn {
|
|
230
|
+
\t\tcloseCurrentPage,
|
|
231
|
+
\t};
|
|
232
|
+
}
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
const DEFAULT_DICT_SEMANTIC_TEMPLATE = `// This file is hand-maintained. Do NOT overwrite during dict-registry sync.
|
|
236
|
+
// Add semantic keys here for dictionaries that have meaningful state values.
|
|
237
|
+
|
|
238
|
+
export const DictSemanticValues = {
|
|
239
|
+
billState: {
|
|
240
|
+
editing: '0',
|
|
241
|
+
processing: '1',
|
|
242
|
+
paused: '2',
|
|
243
|
+
terminated: '3',
|
|
244
|
+
completed: '4',
|
|
245
|
+
},
|
|
246
|
+
} as const;
|
|
247
|
+
`;
|
|
248
|
+
|
|
207
249
|
const TOOL_SCHEMA = {
|
|
208
250
|
type: 'object',
|
|
209
251
|
properties: {
|
|
@@ -562,22 +604,9 @@ function renderDictRegistryContent(entries) {
|
|
|
562
604
|
'',
|
|
563
605
|
'export type DictRegistryKey = keyof typeof DictRegistry;',
|
|
564
606
|
'export type DictType = (typeof DictRegistry)[DictRegistryKey];',
|
|
565
|
-
'',
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
" editing: '0',",
|
|
569
|
-
" processing: '1',",
|
|
570
|
-
" paused: '2',",
|
|
571
|
-
" terminated: '3',",
|
|
572
|
-
" completed: '4',",
|
|
573
|
-
' },',
|
|
574
|
-
'} as const;',
|
|
575
|
-
'',
|
|
576
|
-
'export const isBillStateEditing = (value: unknown): boolean =>',
|
|
577
|
-
" String(value ?? '') === DictSemanticValues.billState.editing;",
|
|
578
|
-
'',
|
|
579
|
-
].join('\n');
|
|
580
|
-
}
|
|
607
|
+
'',
|
|
608
|
+
].join('\n');
|
|
609
|
+
}
|
|
581
610
|
|
|
582
611
|
function patchDictRegistryContent(fileContent, entriesToAdd) {
|
|
583
612
|
const source = String(fileContent || '');
|
|
@@ -598,28 +627,9 @@ function patchDictRegistryContent(fileContent, entriesToAdd) {
|
|
|
598
627
|
return source.replace(block, nextBlock);
|
|
599
628
|
}
|
|
600
629
|
|
|
601
|
-
|
|
602
|
-
''
|
|
603
|
-
|
|
604
|
-
' billState: {',
|
|
605
|
-
" editing: '0',",
|
|
606
|
-
" processing: '1',",
|
|
607
|
-
" paused: '2',",
|
|
608
|
-
" terminated: '3',",
|
|
609
|
-
" completed: '4',",
|
|
610
|
-
' },',
|
|
611
|
-
'} as const;',
|
|
612
|
-
'',
|
|
613
|
-
'export const isBillStateEditing = (value: unknown): boolean =>',
|
|
614
|
-
" String(value ?? '') === DictSemanticValues.billState.editing;",
|
|
615
|
-
'',
|
|
616
|
-
].join('\n');
|
|
617
|
-
|
|
618
|
-
function ensureDictRegistrySemanticHelpers(fileContent) {
|
|
619
|
-
const source = String(fileContent || '').replace(/\s*$/, '\n');
|
|
620
|
-
if (source.includes('export const isBillStateEditing')) return source;
|
|
621
|
-
return `${source}${DICT_REGISTRY_SEMANTIC_HELPERS}`;
|
|
622
|
-
}
|
|
630
|
+
function ensureDictRegistrySemanticHelpers(fileContent) {
|
|
631
|
+
return String(fileContent || '').replace(/\s*$/, '\n');
|
|
632
|
+
}
|
|
623
633
|
|
|
624
634
|
function isPlainObject(value) {
|
|
625
635
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -779,12 +789,18 @@ function buildLocaleLeaf(model) {
|
|
|
779
789
|
};
|
|
780
790
|
}
|
|
781
791
|
|
|
782
|
-
const leaf = {
|
|
783
|
-
title: model.tableComment,
|
|
784
|
-
fields: Object.fromEntries(model.optionFields.map((field) => [field.attrName, stripDictAnnotation(field.comment)])),
|
|
785
|
-
};
|
|
786
|
-
|
|
787
|
-
if (model
|
|
792
|
+
const leaf = {
|
|
793
|
+
title: model.tableComment,
|
|
794
|
+
fields: Object.fromEntries(model.optionFields.map((field) => [field.attrName, stripDictAnnotation(field.comment)])),
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
if (hasBusinessBillStateEditControl(model)) {
|
|
798
|
+
leaf.messages = {
|
|
799
|
+
completedCannotDelete: '单据状态为已完成的数据不能删除',
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if (model.children.length) {
|
|
788
804
|
leaf.children = Object.fromEntries(
|
|
789
805
|
model.children.map((childModel) => [
|
|
790
806
|
childModel.listName,
|
|
@@ -925,9 +941,39 @@ function ensureCrudFactorySupportFile(frontendPath) {
|
|
|
925
941
|
};
|
|
926
942
|
}
|
|
927
943
|
|
|
928
|
-
function
|
|
929
|
-
|
|
930
|
-
|
|
944
|
+
function ensureCloseCurrentPageSupportFile(frontendPath) {
|
|
945
|
+
const hookPath = path.join(frontendPath, 'src', 'hooks', 'useCloseCurrentPage.ts');
|
|
946
|
+
const exists = fs.existsSync(hookPath);
|
|
947
|
+
const currentContent = exists ? readUtf8File(hookPath) : '';
|
|
948
|
+
const isCompatible = !exists || currentContent.includes('export function useCloseCurrentPage');
|
|
949
|
+
|
|
950
|
+
return {
|
|
951
|
+
path: hookPath,
|
|
952
|
+
content: DEFAULT_CLOSE_CURRENT_PAGE_TEMPLATE,
|
|
953
|
+
exists,
|
|
954
|
+
isCompatible,
|
|
955
|
+
needsWrite: !exists,
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
function ensureDictSemanticSupportFile(frontendPath) {
|
|
960
|
+
const semanticPath = path.join(frontendPath, 'src', 'enums', 'dict-semantic.ts');
|
|
961
|
+
const exists = fs.existsSync(semanticPath);
|
|
962
|
+
const currentContent = exists ? readUtf8File(semanticPath) : '';
|
|
963
|
+
const isCompatible = !exists || currentContent.includes('export const DictSemanticValues');
|
|
964
|
+
|
|
965
|
+
return {
|
|
966
|
+
path: semanticPath,
|
|
967
|
+
content: DEFAULT_DICT_SEMANTIC_TEMPLATE,
|
|
968
|
+
exists,
|
|
969
|
+
isCompatible,
|
|
970
|
+
needsWrite: !exists,
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
function ensureDirectory(filePath) {
|
|
975
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
976
|
+
}
|
|
931
977
|
|
|
932
978
|
function writeSupportFile(filePath, content) {
|
|
933
979
|
ensureDirectory(filePath);
|
|
@@ -971,13 +1017,37 @@ function prepareSharedSupport(frontendPath, dictTypes, writeSupportFiles) {
|
|
|
971
1017
|
needsWrite: false,
|
|
972
1018
|
writeEnabled: false,
|
|
973
1019
|
};
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1020
|
+
const closeCurrentPagePath = path.join(frontendPath, 'src', 'hooks', 'useCloseCurrentPage.ts');
|
|
1021
|
+
const closeCurrentPage = writeSupportFiles
|
|
1022
|
+
? ensureCloseCurrentPageSupportFile(frontendPath)
|
|
1023
|
+
: {
|
|
1024
|
+
path: closeCurrentPagePath,
|
|
1025
|
+
content: DEFAULT_CLOSE_CURRENT_PAGE_TEMPLATE,
|
|
1026
|
+
exists: fs.existsSync(closeCurrentPagePath),
|
|
1027
|
+
isCompatible: true,
|
|
1028
|
+
needsWrite: false,
|
|
1029
|
+
writeEnabled: false,
|
|
1030
|
+
};
|
|
1031
|
+
const dictSemanticPath = path.join(frontendPath, 'src', 'enums', 'dict-semantic.ts');
|
|
1032
|
+
const dictSemantic = writeSupportFiles
|
|
1033
|
+
? ensureDictSemanticSupportFile(frontendPath)
|
|
1034
|
+
: {
|
|
1035
|
+
path: dictSemanticPath,
|
|
1036
|
+
content: DEFAULT_DICT_SEMANTIC_TEMPLATE,
|
|
1037
|
+
exists: fs.existsSync(dictSemanticPath),
|
|
1038
|
+
isCompatible: true,
|
|
1039
|
+
needsWrite: false,
|
|
1040
|
+
writeEnabled: false,
|
|
1041
|
+
};
|
|
1042
|
+
return {
|
|
1043
|
+
dictRegistry,
|
|
1044
|
+
crudSchema,
|
|
1045
|
+
crudFactory,
|
|
1046
|
+
closeCurrentPage,
|
|
1047
|
+
dictSemantic,
|
|
1048
|
+
writeEnabled: Boolean(writeSupportFiles),
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
981
1051
|
|
|
982
1052
|
function maybeWriteSharedSupport(sharedSupport, writeToDisk) {
|
|
983
1053
|
if (!writeToDisk || !sharedSupport.writeEnabled) return;
|
|
@@ -1005,16 +1075,36 @@ function maybeWriteSharedSupport(sharedSupport, writeToDisk) {
|
|
|
1005
1075
|
}
|
|
1006
1076
|
writeSupportFile(sharedSupport.dictRegistry.path, sharedSupport.dictRegistry.content);
|
|
1007
1077
|
}
|
|
1008
|
-
|
|
1078
|
+
|
|
1079
|
+
if (sharedSupport.closeCurrentPage.needsWrite) {
|
|
1080
|
+
if (!sharedSupport.closeCurrentPage.isCompatible) {
|
|
1081
|
+
throw new Error(
|
|
1082
|
+
'Detected an existing src/hooks/useCloseCurrentPage.ts that MCP could not merge safely. ' +
|
|
1083
|
+
'Please align the useCloseCurrentPage export manually before enabling writeSupportFiles.'
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
writeSupportFile(sharedSupport.closeCurrentPage.path, sharedSupport.closeCurrentPage.content);
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
if (sharedSupport.dictSemantic.needsWrite) {
|
|
1090
|
+
if (!sharedSupport.dictSemantic.isCompatible) {
|
|
1091
|
+
throw new Error(
|
|
1092
|
+
'Detected an existing src/enums/dict-semantic.ts that MCP could not merge safely. ' +
|
|
1093
|
+
'Please align the DictSemanticValues export manually before enabling writeSupportFiles.'
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1096
|
+
writeSupportFile(sharedSupport.dictSemantic.path, sharedSupport.dictSemantic.content);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1009
1099
|
|
|
1010
1100
|
function buildSupportNote(sharedSupport, localeZhSupport) {
|
|
1011
1101
|
const notes = [];
|
|
1012
1102
|
|
|
1013
|
-
if (!sharedSupport.writeEnabled) {
|
|
1014
|
-
notes.push(
|
|
1015
|
-
'Shared support file writing is disabled. Generated code still references src/utils/crudSchema.ts, src/api/common/crudFactory.ts and may reference src/enums/dict-registry.ts, so those helpers must already exist in the target project.'
|
|
1016
|
-
);
|
|
1017
|
-
}
|
|
1103
|
+
if (!sharedSupport.writeEnabled) {
|
|
1104
|
+
notes.push(
|
|
1105
|
+
'Shared support file writing is disabled. Generated code still references src/utils/crudSchema.ts, src/api/common/crudFactory.ts, src/hooks/useCloseCurrentPage.ts, src/enums/dict-semantic.ts and may reference src/enums/dict-registry.ts, so those helpers must already exist in the target project.'
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1018
1108
|
|
|
1019
1109
|
if (sharedSupport.crudSchema.exists && !sharedSupport.crudSchema.isCompatible) {
|
|
1020
1110
|
notes.push(
|
|
@@ -1030,12 +1120,19 @@ function buildSupportNote(sharedSupport, localeZhSupport) {
|
|
|
1030
1120
|
);
|
|
1031
1121
|
}
|
|
1032
1122
|
|
|
1033
|
-
if (sharedSupport.dictRegistry.exists && !sharedSupport.dictRegistry.isCompatible) {
|
|
1034
|
-
notes.push(
|
|
1035
|
-
'Detected an existing src/enums/dict-registry.ts that MCP could not merge safely. ' +
|
|
1036
|
-
'MCP preserved the existing file and did not overwrite it.'
|
|
1037
|
-
);
|
|
1038
|
-
}
|
|
1123
|
+
if (sharedSupport.dictRegistry.exists && !sharedSupport.dictRegistry.isCompatible) {
|
|
1124
|
+
notes.push(
|
|
1125
|
+
'Detected an existing src/enums/dict-registry.ts that MCP could not merge safely. ' +
|
|
1126
|
+
'MCP preserved the existing file and did not overwrite it.'
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
if (sharedSupport.dictSemantic.exists && !sharedSupport.dictSemantic.isCompatible) {
|
|
1131
|
+
notes.push(
|
|
1132
|
+
'Detected an existing src/enums/dict-semantic.ts that does not expose DictSemanticValues. ' +
|
|
1133
|
+
'MCP preserved the existing file and did not overwrite it.'
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1039
1136
|
|
|
1040
1137
|
if (localeZhSupport.exists && !localeZhSupport.isCompatible) {
|
|
1041
1138
|
notes.push(
|
|
@@ -1306,7 +1403,7 @@ function normalizeStructuredField(inputField, index, contextLabel) {
|
|
|
1306
1403
|
throw new Error(contextLabel + '[' + index + '] is missing required field: type');
|
|
1307
1404
|
}
|
|
1308
1405
|
|
|
1309
|
-
const { length, scale } = normalizeStructuredLengthAndScale(inputField.length, inputField.scale);
|
|
1406
|
+
const { length, scale } = normalizeStructuredLengthAndScale(inputField.length ?? inputField.maxLength, inputField.scale);
|
|
1310
1407
|
const explicitFormType = normalizeStructuredFormType(inputField.formType || inputField.componentType);
|
|
1311
1408
|
const formType = type === 'DATE' && explicitFormType === 'datetime' ? 'date' : explicitFormType;
|
|
1312
1409
|
const explicitQueryType =
|
|
@@ -1968,9 +2065,13 @@ function renderChildTableColumn(field, childListName) {
|
|
|
1968
2065
|
const selectPlaceholderExpr = `formSelectPlaceholder(${labelExpr}, ${renderDisabledBoolV2(field)})`;
|
|
1969
2066
|
const disabledAttr = renderDisabledAttrV2(field);
|
|
1970
2067
|
|
|
1971
|
-
let control = ` <el-input v-model="row.${field.attrName}" :placeholder="${inputPlaceholderExpr}"${disabledAttr} />`;
|
|
2068
|
+
let control = ` <el-input v-model="row.${field.attrName}"${renderTextMaxlengthAttrV2(field)} :placeholder="${inputPlaceholderExpr}"${disabledAttr} />`;
|
|
1972
2069
|
if (field.formType === 'upload') {
|
|
1973
2070
|
control = ` <UploadFile v-model="row.${field.attrName}"${disabledAttr} />`;
|
|
2071
|
+
} else if (field.formType === 'datetime' || field.formType === 'date') {
|
|
2072
|
+
const pickerType = field.formType === 'datetime' ? 'datetime' : 'date';
|
|
2073
|
+
const formatName = field.formType === 'datetime' ? 'dateTimeStr' : 'dateStr';
|
|
2074
|
+
control = ` <el-date-picker type="${pickerType}" :placeholder="${inputPlaceholderExpr}" v-model="row.${field.attrName}" :value-format="${formatName}" style="width: 100%"${disabledAttr}></el-date-picker>`;
|
|
1974
2075
|
} else if (field.formType === 'select' && field.dictType) {
|
|
1975
2076
|
control = [
|
|
1976
2077
|
` <el-select v-model="row.${field.attrName}" :placeholder="${selectPlaceholderExpr}" style="width: 100%"${disabledAttr}>`,
|
|
@@ -2116,7 +2217,7 @@ function renderOptionFieldV2(field, labelKey, dictRegistryRefs, indent = ' ')
|
|
|
2116
2217
|
const prdWidth = field.width ? field.width.replace('px', '') : null;
|
|
2117
2218
|
const width = prdWidth || getDefaultOptionFieldWidthV2(field);
|
|
2118
2219
|
|
|
2119
|
-
if (width !== '
|
|
2220
|
+
if (width !== '100') {
|
|
2120
2221
|
parts.push(`width: '${width}'`);
|
|
2121
2222
|
}
|
|
2122
2223
|
|
|
@@ -3234,24 +3335,45 @@ function renderSingleTableDialogDictApiFunctions(model) {
|
|
|
3234
3335
|
].join('\n');
|
|
3235
3336
|
}
|
|
3236
3337
|
|
|
3237
|
-
function hasBusinessBillStateEditControl(model) {
|
|
3238
|
-
return model.pageType === 'business' && !!model.statusField && model.statusDictType === 'bill_state';
|
|
3239
|
-
}
|
|
3240
|
-
|
|
3241
|
-
function renderBusinessStatusImports(model) {
|
|
3242
|
-
return hasBusinessBillStateEditControl(model)
|
|
3243
|
-
? "//
|
|
3244
|
-
: '';
|
|
3245
|
-
}
|
|
3246
|
-
|
|
3247
|
-
function renderBusinessStatusHelpers(model) {
|
|
3248
|
-
if (!hasBusinessBillStateEditControl(model)) return '';
|
|
3249
|
-
const statusAttr = toCamelCase(model.statusField);
|
|
3250
|
-
return [
|
|
3251
|
-
'//
|
|
3252
|
-
`const showEditAction = (row: any): boolean =>
|
|
3253
|
-
|
|
3254
|
-
|
|
3338
|
+
function hasBusinessBillStateEditControl(model) {
|
|
3339
|
+
return model.pageType === 'business' && !!model.statusField && model.statusDictType === 'bill_state';
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
function renderBusinessStatusImports(model) {
|
|
3343
|
+
return hasBusinessBillStateEditControl(model)
|
|
3344
|
+
? "// 业务单据状态枚举\nimport { DictSemanticValues } from '/@/enums/dict-semantic';"
|
|
3345
|
+
: '';
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
function renderBusinessStatusHelpers(model) {
|
|
3349
|
+
if (!hasBusinessBillStateEditControl(model)) return '';
|
|
3350
|
+
const statusAttr = toCamelCase(model.statusField);
|
|
3351
|
+
return [
|
|
3352
|
+
'// 控制业务单据编辑按钮显隐:仅编辑中允许编辑',
|
|
3353
|
+
`const showEditAction = (row: any): boolean => String(row?.${statusAttr} ?? '') === DictSemanticValues.billState.editing;`,
|
|
3354
|
+
'',
|
|
3355
|
+
'// 控制业务单据删除按钮显隐:已完成不允许删除',
|
|
3356
|
+
`const showDeleteAction = (row: any): boolean => String(row?.${statusAttr} ?? '') !== DictSemanticValues.billState.completed;`,
|
|
3357
|
+
].join('\n');
|
|
3358
|
+
}
|
|
3359
|
+
|
|
3360
|
+
function renderBusinessDeleteGuard(model) {
|
|
3361
|
+
if (!hasBusinessBillStateEditControl(model)) return '';
|
|
3362
|
+
const i18nNamespace = buildI18nNamespace(model);
|
|
3363
|
+
return [
|
|
3364
|
+
' if (rows.some((row) => !showDeleteAction(row))) {',
|
|
3365
|
+
` useMessage().warning(t('${i18nNamespace}.messages.completedCannotDelete'));`,
|
|
3366
|
+
' return;',
|
|
3367
|
+
' }',
|
|
3368
|
+
'',
|
|
3369
|
+
].join('\n');
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
function renderBusinessSubmitStatusAssignment(model) {
|
|
3373
|
+
if (!hasBusinessBillStateEditControl(model)) return '';
|
|
3374
|
+
const statusAttr = toCamelCase(model.statusField);
|
|
3375
|
+
return `, actionType === 'submit' ? { ${statusAttr}: DictSemanticValues.billState.completed } : {}`;
|
|
3376
|
+
}
|
|
3255
3377
|
|
|
3256
3378
|
function sanitizeComment(value) {
|
|
3257
3379
|
return String(value || '').replace(/\*\//g, '* /').replace(/\r?\n/g, ' ').trim();
|
|
@@ -3348,11 +3470,21 @@ function buildReplacements(model, sharedSupport) {
|
|
|
3348
3470
|
LIST_ACTIONS: renderSingleTableDialogActions(model, permissionPrefix),
|
|
3349
3471
|
DICT_API_IMPORTS: model.pageType === 'dict' && model.statusField ? ', enableObj, disableObj' : '',
|
|
3350
3472
|
DICT_LIST_HELPERS: renderSingleTableDialogDictHelpers(model),
|
|
3351
|
-
DICT_API_FUNCTIONS: renderSingleTableDialogDictApiFunctions(model),
|
|
3352
|
-
BUSINESS_STATUS_IMPORTS: renderBusinessStatusImports(model),
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3473
|
+
DICT_API_FUNCTIONS: renderSingleTableDialogDictApiFunctions(model),
|
|
3474
|
+
BUSINESS_STATUS_IMPORTS: renderBusinessStatusImports(model),
|
|
3475
|
+
BUSINESS_FORM_STATUS_IMPORTS: renderBusinessStatusImports(model),
|
|
3476
|
+
BUSINESS_EDIT_IF: hasBusinessBillStateEditControl(model) ? ' v-if="showEditAction(row)"' : '',
|
|
3477
|
+
BUSINESS_DELETE_IF: hasBusinessBillStateEditControl(model) ? ' v-if="showDeleteAction(row)"' : '',
|
|
3478
|
+
BUSINESS_DELETE_ROW_ARG: hasBusinessBillStateEditControl(model) ? ', [row]' : '',
|
|
3479
|
+
BUSINESS_SELECTED_ROWS_DECLARATION: hasBusinessBillStateEditControl(model) ? 'const selectedRows = ref<any[]>([]);' : '',
|
|
3480
|
+
BUSINESS_DELETE_DISABLED_EXPR: hasBusinessBillStateEditControl(model) ? ' || selectedRows.value.some((row) => !showDeleteAction(row))' : '',
|
|
3481
|
+
BUSINESS_DELETE_ROWS_PARAM: hasBusinessBillStateEditControl(model) ? ', rows: any[] = []' : '',
|
|
3482
|
+
BUSINESS_DELETE_GUARD: renderBusinessDeleteGuard(model),
|
|
3483
|
+
BUSINESS_SELECTED_ROWS_ARG: hasBusinessBillStateEditControl(model) ? ', selectedRows.value' : '',
|
|
3484
|
+
BUSINESS_SELECTED_ROWS_ASSIGNMENT: hasBusinessBillStateEditControl(model) ? ' selectedRows.value = payload.rows;' : '',
|
|
3485
|
+
BUSINESS_STATUS_HELPERS: renderBusinessStatusHelpers(model),
|
|
3486
|
+
BUSINESS_SUBMIT_STATUS_ASSIGNMENT: renderBusinessSubmitStatusAssignment(model),
|
|
3487
|
+
API_REQUEST_IMPORT: renderApiRequestImport(model),
|
|
3356
3488
|
EXTRA_API_FUNCTIONS: renderExtraApiFunctionsV2(model),
|
|
3357
3489
|
CUSTOM_QUERY_FIELDS_EXPR: model.pageType === 'dict' ? '[]' : 'queryableDictOptions.value',
|
|
3358
3490
|
SHOW_RIGHT_TOOLS: model.pageType === 'dict' ? 'false' : 'true',
|
package/package.json
CHANGED