worsoft-frontend-codegen-local-mcp 0.1.70 → 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.
@@ -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
 
@@ -165,7 +166,8 @@ const onSubmit = async (actionType?: string) => {
165
166
  }
166
167
 
167
168
  try {
168
- form.{{PK_ATTR}} ? await putObj(form) : await addObj(form);
169
+ const submitData = Object.assign({}, form{{BUSINESS_SUBMIT_STATUS_ASSIGNMENT}});
170
+ form.{{PK_ATTR}} ? await putObj(submitData) : await addObj(submitData);
169
171
 
170
172
  let msg = form.{{PK_ATTR}} ? t('common.editSuccessText') : t('common.addSuccessText');
171
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
  };
@@ -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
 
@@ -147,7 +148,8 @@ const onSubmit = async (actionType?: string) => {
147
148
  }
148
149
 
149
150
  try {
150
- form.{{PK_ATTR}} ? await putObj(form) : await addObj(form);
151
+ const submitData = Object.assign({}, form{{BUSINESS_SUBMIT_STATUS_ASSIGNMENT}});
152
+ form.{{PK_ATTR}} ? await putObj(submitData) : await addObj(submitData);
151
153
 
152
154
  let msg = form.{{PK_ATTR}} ? t('common.editSuccessText') : t('common.addSuccessText');
153
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.70';
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,9 +204,9 @@ 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';
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
210
 
211
211
  export const closeCurrentRoutePage = (route: RouteLocationNormalizedLoaded) => {
212
212
  \tmittBus.emit('onCurrentContextmenuClick', {
@@ -229,8 +229,22 @@ export function useCloseCurrentPage() {
229
229
  \treturn {
230
230
  \t\tcloseCurrentPage,
231
231
  \t};
232
- }
233
- `;
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
+ `;
234
248
 
235
249
  const TOOL_SCHEMA = {
236
250
  type: 'object',
@@ -590,22 +604,9 @@ function renderDictRegistryContent(entries) {
590
604
  '',
591
605
  'export type DictRegistryKey = keyof typeof DictRegistry;',
592
606
  'export type DictType = (typeof DictRegistry)[DictRegistryKey];',
593
- '',
594
- 'export const DictSemanticValues = {',
595
- ' billState: {',
596
- " editing: '0',",
597
- " processing: '1',",
598
- " paused: '2',",
599
- " terminated: '3',",
600
- " completed: '4',",
601
- ' },',
602
- '} as const;',
603
- '',
604
- 'export const isBillStateEditing = (value: unknown): boolean =>',
605
- " String(value ?? '') === DictSemanticValues.billState.editing;",
606
- '',
607
- ].join('\n');
608
- }
607
+ '',
608
+ ].join('\n');
609
+ }
609
610
 
610
611
  function patchDictRegistryContent(fileContent, entriesToAdd) {
611
612
  const source = String(fileContent || '');
@@ -626,28 +627,9 @@ function patchDictRegistryContent(fileContent, entriesToAdd) {
626
627
  return source.replace(block, nextBlock);
627
628
  }
628
629
 
629
- const DICT_REGISTRY_SEMANTIC_HELPERS = [
630
- '',
631
- 'export const DictSemanticValues = {',
632
- ' billState: {',
633
- " editing: '0',",
634
- " processing: '1',",
635
- " paused: '2',",
636
- " terminated: '3',",
637
- " completed: '4',",
638
- ' },',
639
- '} as const;',
640
- '',
641
- 'export const isBillStateEditing = (value: unknown): boolean =>',
642
- " String(value ?? '') === DictSemanticValues.billState.editing;",
643
- '',
644
- ].join('\n');
645
-
646
- function ensureDictRegistrySemanticHelpers(fileContent) {
647
- const source = String(fileContent || '').replace(/\s*$/, '\n');
648
- if (source.includes('export const isBillStateEditing')) return source;
649
- return `${source}${DICT_REGISTRY_SEMANTIC_HELPERS}`;
650
- }
630
+ function ensureDictRegistrySemanticHelpers(fileContent) {
631
+ return String(fileContent || '').replace(/\s*$/, '\n');
632
+ }
651
633
 
652
634
  function isPlainObject(value) {
653
635
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
@@ -807,12 +789,18 @@ function buildLocaleLeaf(model) {
807
789
  };
808
790
  }
809
791
 
810
- const leaf = {
811
- title: model.tableComment,
812
- fields: Object.fromEntries(model.optionFields.map((field) => [field.attrName, stripDictAnnotation(field.comment)])),
813
- };
814
-
815
- if (model.children.length) {
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) {
816
804
  leaf.children = Object.fromEntries(
817
805
  model.children.map((childModel) => [
818
806
  childModel.listName,
@@ -953,24 +941,39 @@ function ensureCrudFactorySupportFile(frontendPath) {
953
941
  };
954
942
  }
955
943
 
956
- function ensureCloseCurrentPageSupportFile(frontendPath) {
957
- const hookPath = path.join(frontendPath, 'src', 'hooks', 'useCloseCurrentPage.ts');
958
- const exists = fs.existsSync(hookPath);
959
- const currentContent = exists ? readUtf8File(hookPath) : '';
960
- const isCompatible = !exists || currentContent.includes('export function useCloseCurrentPage');
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');
961
949
 
962
950
  return {
963
951
  path: hookPath,
964
952
  content: DEFAULT_CLOSE_CURRENT_PAGE_TEMPLATE,
965
953
  exists,
966
954
  isCompatible,
967
- needsWrite: !exists,
968
- };
969
- }
970
-
971
- function ensureDirectory(filePath) {
972
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
973
- }
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
+ }
974
977
 
975
978
  function writeSupportFile(filePath, content) {
976
979
  ensureDirectory(filePath);
@@ -1015,24 +1018,36 @@ function prepareSharedSupport(frontendPath, dictTypes, writeSupportFiles) {
1015
1018
  writeEnabled: false,
1016
1019
  };
1017
1020
  const closeCurrentPagePath = path.join(frontendPath, 'src', 'hooks', 'useCloseCurrentPage.ts');
1018
- const closeCurrentPage = writeSupportFiles
1019
- ? ensureCloseCurrentPageSupportFile(frontendPath)
1020
- : {
1021
- path: closeCurrentPagePath,
1022
- content: DEFAULT_CLOSE_CURRENT_PAGE_TEMPLATE,
1021
+ const closeCurrentPage = writeSupportFiles
1022
+ ? ensureCloseCurrentPageSupportFile(frontendPath)
1023
+ : {
1024
+ path: closeCurrentPagePath,
1025
+ content: DEFAULT_CLOSE_CURRENT_PAGE_TEMPLATE,
1023
1026
  exists: fs.existsSync(closeCurrentPagePath),
1024
1027
  isCompatible: true,
1025
- needsWrite: false,
1026
- writeEnabled: false,
1027
- };
1028
- return {
1029
- dictRegistry,
1030
- crudSchema,
1031
- crudFactory,
1032
- closeCurrentPage,
1033
- writeEnabled: Boolean(writeSupportFiles),
1034
- };
1035
- }
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
+ }
1036
1051
 
1037
1052
  function maybeWriteSharedSupport(sharedSupport, writeToDisk) {
1038
1053
  if (!writeToDisk || !sharedSupport.writeEnabled) return;
@@ -1061,25 +1076,35 @@ function maybeWriteSharedSupport(sharedSupport, writeToDisk) {
1061
1076
  writeSupportFile(sharedSupport.dictRegistry.path, sharedSupport.dictRegistry.content);
1062
1077
  }
1063
1078
 
1064
- if (sharedSupport.closeCurrentPage.needsWrite) {
1065
- if (!sharedSupport.closeCurrentPage.isCompatible) {
1066
- throw new Error(
1067
- 'Detected an existing src/hooks/useCloseCurrentPage.ts that MCP could not merge safely. ' +
1068
- 'Please align the useCloseCurrentPage export manually before enabling writeSupportFiles.'
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.'
1069
1084
  );
1070
- }
1071
- writeSupportFile(sharedSupport.closeCurrentPage.path, sharedSupport.closeCurrentPage.content);
1072
- }
1073
- }
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
+ }
1074
1099
 
1075
1100
  function buildSupportNote(sharedSupport, localeZhSupport) {
1076
1101
  const notes = [];
1077
1102
 
1078
- if (!sharedSupport.writeEnabled) {
1079
- notes.push(
1080
- 'Shared support file writing is disabled. Generated code still references src/utils/crudSchema.ts, src/api/common/crudFactory.ts, src/hooks/useCloseCurrentPage.ts and may reference src/enums/dict-registry.ts, so those helpers must already exist in the target project.'
1081
- );
1082
- }
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
+ }
1083
1108
 
1084
1109
  if (sharedSupport.crudSchema.exists && !sharedSupport.crudSchema.isCompatible) {
1085
1110
  notes.push(
@@ -1095,12 +1120,19 @@ function buildSupportNote(sharedSupport, localeZhSupport) {
1095
1120
  );
1096
1121
  }
1097
1122
 
1098
- if (sharedSupport.dictRegistry.exists && !sharedSupport.dictRegistry.isCompatible) {
1099
- notes.push(
1100
- 'Detected an existing src/enums/dict-registry.ts that MCP could not merge safely. ' +
1101
- 'MCP preserved the existing file and did not overwrite it.'
1102
- );
1103
- }
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
+ }
1104
1136
 
1105
1137
  if (localeZhSupport.exists && !localeZhSupport.isCompatible) {
1106
1138
  notes.push(
@@ -3303,24 +3335,45 @@ function renderSingleTableDialogDictApiFunctions(model) {
3303
3335
  ].join('\n');
3304
3336
  }
3305
3337
 
3306
- function hasBusinessBillStateEditControl(model) {
3307
- return model.pageType === 'business' && !!model.statusField && model.statusDictType === 'bill_state';
3308
- }
3309
-
3310
- function renderBusinessStatusImports(model) {
3311
- return hasBusinessBillStateEditControl(model)
3312
- ? "// 业务单据编辑态判断\nimport { isBillStateEditing } from '/@/enums/dict-registry';"
3313
- : '';
3314
- }
3315
-
3316
- function renderBusinessStatusHelpers(model) {
3317
- if (!hasBusinessBillStateEditControl(model)) return '';
3318
- const statusAttr = toCamelCase(model.statusField);
3319
- return [
3320
- '// 控制业务单据编辑按钮显隐',
3321
- `const showEditAction = (row: any): boolean => isBillStateEditing(row?.${statusAttr});`,
3322
- ].join('\n');
3323
- }
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
+ }
3324
3377
 
3325
3378
  function sanitizeComment(value) {
3326
3379
  return String(value || '').replace(/\*\//g, '* /').replace(/\r?\n/g, ' ').trim();
@@ -3417,11 +3470,21 @@ function buildReplacements(model, sharedSupport) {
3417
3470
  LIST_ACTIONS: renderSingleTableDialogActions(model, permissionPrefix),
3418
3471
  DICT_API_IMPORTS: model.pageType === 'dict' && model.statusField ? ', enableObj, disableObj' : '',
3419
3472
  DICT_LIST_HELPERS: renderSingleTableDialogDictHelpers(model),
3420
- DICT_API_FUNCTIONS: renderSingleTableDialogDictApiFunctions(model),
3421
- BUSINESS_STATUS_IMPORTS: renderBusinessStatusImports(model),
3422
- BUSINESS_EDIT_IF: hasBusinessBillStateEditControl(model) ? ' v-if="showEditAction(row)"' : '',
3423
- BUSINESS_STATUS_HELPERS: renderBusinessStatusHelpers(model),
3424
- API_REQUEST_IMPORT: renderApiRequestImport(model),
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),
3425
3488
  EXTRA_API_FUNCTIONS: renderExtraApiFunctionsV2(model),
3426
3489
  CUSTOM_QUERY_FIELDS_EXPR: model.pageType === 'dict' ? '[]' : 'queryableDictOptions.value',
3427
3490
  SHOW_RIGHT_TOOLS: model.pageType === 'dict' ? 'false' : 'true',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worsoft-frontend-codegen-local-mcp",
3
- "version": "0.1.70",
3
+ "version": "0.1.71",
4
4
  "description": "Worsoft frontend local-template code generation MCP server.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "worsoft <sw@worsoft.vip>",