worsoft-frontend-codegen-local-mcp 0.1.53 → 0.1.55

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.
@@ -79,6 +79,9 @@ const {
79
79
  commonActionLabel,
80
80
  } = useCrudPageMeta(dataMasterEntity, dictRefs, childFieldGroups);
81
81
 
82
+ const formInputPlaceholder = (label: string, disabled = false) => (detail.value || disabled ? '' : inputPlaceholder(label));
83
+ const formSelectPlaceholder = (label: string, disabled = false) => (detail.value || disabled ? '' : selectPlaceholder(label));
84
+
82
85
  // 子表分组标题从功能级词条中读取
83
86
  const childSectionTitle = (groupName: string) => t(`${pageI18nKey}.children.${groupName}.title`);
84
87
 
@@ -54,6 +54,9 @@ const {
54
54
  fieldRequiredMessage,
55
55
  } = useCrudPageMeta(dataMasterEntity, dictRefs);
56
56
 
57
+ const formInputPlaceholder = (label: string, disabled = false) => (disabled ? '' : inputPlaceholder(label));
58
+ const formSelectPlaceholder = (label: string, disabled = false) => (disabled ? '' : selectPlaceholder(label));
59
+
57
60
  // 统一维护表单默认值
58
61
  const createDefaultFormState = () => ({
59
62
  {{FORM_DEFAULTS}}
@@ -70,6 +70,9 @@ const {
70
70
  commonActionLabel,
71
71
  } = useCrudPageMeta(dataMasterEntity, dictRefs);
72
72
 
73
+ const formInputPlaceholder = (label: string, disabled = false) => (detail.value || disabled ? '' : inputPlaceholder(label));
74
+ const formSelectPlaceholder = (label: string, disabled = false) => (detail.value || disabled ? '' : selectPlaceholder(label));
75
+
73
76
  // 统一维护表单默认值
74
77
  const createDefaultFormState = () => ({
75
78
  {{FORM_DEFAULTS}}
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.53';
8
+ const SERVER_VERSION = '0.1.55';
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');
@@ -462,9 +462,9 @@ function toConstantCase(value) {
462
462
  .toUpperCase();
463
463
  }
464
464
 
465
- function parseDictRegistryEntries(fileContent) {
466
- const blockMatch = String(fileContent || '').match(/export const DictRegistry\s*=\s*{([\s\S]*?)}\s*as const;/);
467
- if (!blockMatch) return [];
465
+ function parseDictRegistryEntries(fileContent) {
466
+ const blockMatch = String(fileContent || '').match(/export const DictRegistry\s*=\s*{([\s\S]*?)}\s*as const;/);
467
+ if (!blockMatch) return [];
468
468
 
469
469
  const entries = [];
470
470
  const entryRegex = /^\s*([A-Z0-9_]+)\s*:\s*['"]([^'"]+)['"]\s*,?\s*$/gm;
@@ -473,23 +473,78 @@ function parseDictRegistryEntries(fileContent) {
473
473
  entries.push({ key: match[1], value: match[2] });
474
474
  match = entryRegex.exec(blockMatch[1]);
475
475
  }
476
- return entries;
477
- }
478
-
479
- function renderDictRegistryContent(entries) {
480
- const lines = entries.map((entry) => ` ${entry.key}: '${entry.value}',`);
481
- return [
482
- 'export const DictRegistry = {',
483
- ...lines,
484
- '} as const;',
485
- '',
486
- 'export type DictRegistryKey = keyof typeof DictRegistry;',
487
- 'export type DictType = (typeof DictRegistry)[DictRegistryKey];',
488
- '',
489
- ].join('\n');
490
- }
491
-
492
- function isPlainObject(value) {
476
+ return entries;
477
+ }
478
+
479
+ function renderDictRegistryContent(entries) {
480
+ const lines = entries.map((entry) => ` ${entry.key}: '${entry.value}',`);
481
+ return [
482
+ 'export const DictRegistry = {',
483
+ ...lines,
484
+ '} as const;',
485
+ '',
486
+ 'export type DictRegistryKey = keyof typeof DictRegistry;',
487
+ 'export type DictType = (typeof DictRegistry)[DictRegistryKey];',
488
+ '',
489
+ 'export const DictSemanticValues = {',
490
+ ' billState: {',
491
+ " editing: '0',",
492
+ " processing: '1',",
493
+ " paused: '2',",
494
+ " terminated: '3',",
495
+ " completed: '4',",
496
+ ' },',
497
+ '} as const;',
498
+ '',
499
+ 'export const isBillStateEditing = (value: unknown): boolean =>',
500
+ " String(value ?? '') === DictSemanticValues.billState.editing;",
501
+ '',
502
+ ].join('\n');
503
+ }
504
+
505
+ function patchDictRegistryContent(fileContent, entriesToAdd) {
506
+ const source = String(fileContent || '');
507
+ const blockMatch = source.match(/export const DictRegistry\s*=\s*{([\s\S]*?)}\s*as const;/);
508
+ if (!blockMatch) return null;
509
+
510
+ const block = blockMatch[0];
511
+ const insertAt = block.lastIndexOf('}');
512
+ if (insertAt < 0) return null;
513
+
514
+ const linesToAdd = entriesToAdd.map((entry) => ` ${entry.key}: '${entry.value}',`).join('\n');
515
+ if (!linesToAdd) return source;
516
+
517
+ const prefix = block.slice(0, insertAt).replace(/\s*$/, '');
518
+ const suffix = block.slice(insertAt);
519
+ const nextBlock = `${prefix}\n${linesToAdd}\n${suffix}`;
520
+
521
+ return source.replace(block, nextBlock);
522
+ }
523
+
524
+ const DICT_REGISTRY_SEMANTIC_HELPERS = [
525
+ '',
526
+ 'export const DictSemanticValues = {',
527
+ ' billState: {',
528
+ " editing: '0',",
529
+ " processing: '1',",
530
+ " paused: '2',",
531
+ " terminated: '3',",
532
+ " completed: '4',",
533
+ ' },',
534
+ '} as const;',
535
+ '',
536
+ 'export const isBillStateEditing = (value: unknown): boolean =>',
537
+ " String(value ?? '') === DictSemanticValues.billState.editing;",
538
+ '',
539
+ ].join('\n');
540
+
541
+ function ensureDictRegistrySemanticHelpers(fileContent) {
542
+ const source = String(fileContent || '').replace(/\s*$/, '\n');
543
+ if (source.includes('export const isBillStateEditing')) return source;
544
+ return `${source}${DICT_REGISTRY_SEMANTIC_HELPERS}`;
545
+ }
546
+
547
+ function isPlainObject(value) {
493
548
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
494
549
  }
495
550
 
@@ -720,33 +775,43 @@ function prepareZhCnLocaleFile(model, mergeExisting) {
720
775
  };
721
776
  }
722
777
 
723
- function prepareDictRegistry(frontendPath, dictTypes) {
724
- const registryPath = path.join(frontendPath, 'src', 'enums', 'dict-registry.ts');
725
- const exists = fs.existsSync(registryPath);
726
- const existingEntries = exists ? parseDictRegistryEntries(readUtf8File(registryPath)) : [];
727
- const entries = existingEntries.map((entry) => ({ ...entry }));
728
- const keyByValue = new Map(entries.map((entry) => [entry.value, entry.key]));
729
- const existingByKey = new Map(entries.map((entry) => [entry.key, entry.value]));
730
- const usedKeys = new Set(entries.map((entry) => entry.key));
731
- let changed = !exists;
732
-
733
- for (const dictType of dictTypes) {
734
- if (!dictType || keyByValue.has(dictType)) continue;
735
- const key = buildUniqueDictRegistryKey(dictType, usedKeys, existingByKey);
736
- entries.push({ key, value: dictType });
737
- keyByValue.set(dictType, key);
738
- existingByKey.set(key, dictType);
739
- usedKeys.add(key);
740
- changed = true;
741
- }
742
-
743
- return {
744
- path: registryPath,
745
- entries,
746
- keyByValue,
747
- needsWrite: changed,
748
- };
749
- }
778
+ function prepareDictRegistry(frontendPath, dictTypes) {
779
+ const registryPath = path.join(frontendPath, 'src', 'enums', 'dict-registry.ts');
780
+ const exists = fs.existsSync(registryPath);
781
+ const currentContent = exists ? readUtf8File(registryPath) : '';
782
+ const existingEntries = exists ? parseDictRegistryEntries(currentContent) : [];
783
+ const entries = existingEntries.map((entry) => ({ ...entry }));
784
+ const keyByValue = new Map(entries.map((entry) => [entry.value, entry.key]));
785
+ const existingByKey = new Map(entries.map((entry) => [entry.key, entry.value]));
786
+ const usedKeys = new Set(entries.map((entry) => entry.key));
787
+ const entriesToAdd = [];
788
+ let changed = !exists;
789
+
790
+ for (const dictType of dictTypes) {
791
+ if (!dictType || keyByValue.has(dictType)) continue;
792
+ const key = buildUniqueDictRegistryKey(dictType, usedKeys, existingByKey);
793
+ const entry = { key, value: dictType };
794
+ entries.push(entry);
795
+ entriesToAdd.push(entry);
796
+ keyByValue.set(dictType, key);
797
+ existingByKey.set(key, dictType);
798
+ usedKeys.add(key);
799
+ changed = true;
800
+ }
801
+
802
+ const patchedContent = exists ? patchDictRegistryContent(currentContent, entriesToAdd) : renderDictRegistryContent(entries);
803
+ const content = patchedContent ? ensureDictRegistrySemanticHelpers(patchedContent) : null;
804
+ const needsSemanticHelpers = exists && Boolean(content) && content !== currentContent;
805
+
806
+ return {
807
+ path: registryPath,
808
+ entries,
809
+ keyByValue,
810
+ content,
811
+ isCompatible: !exists || Boolean(content),
812
+ needsWrite: changed || needsSemanticHelpers,
813
+ };
814
+ }
750
815
 
751
816
  function ensureCrudSchemaSupportFile(frontendPath) {
752
817
  const schemaPath = path.join(frontendPath, 'src', 'utils', 'crudSchema.ts');
@@ -817,10 +882,16 @@ function maybeWriteSharedSupport(sharedSupport, writeToDisk) {
817
882
  writeSupportFile(sharedSupport.crudSchema.path, sharedSupport.crudSchema.content);
818
883
  }
819
884
 
820
- if (sharedSupport.dictRegistry.needsWrite) {
821
- writeSupportFile(sharedSupport.dictRegistry.path, renderDictRegistryContent(sharedSupport.dictRegistry.entries));
822
- }
823
- }
885
+ if (sharedSupport.dictRegistry.needsWrite) {
886
+ if (!sharedSupport.dictRegistry.isCompatible) {
887
+ throw new Error(
888
+ 'Detected an existing src/enums/dict-registry.ts that MCP could not merge safely. ' +
889
+ 'Please align the DictRegistry export shape manually before enabling writeSupportFiles.'
890
+ );
891
+ }
892
+ writeSupportFile(sharedSupport.dictRegistry.path, sharedSupport.dictRegistry.content);
893
+ }
894
+ }
824
895
 
825
896
  function buildSupportNote(sharedSupport, localeZhSupport) {
826
897
  const notes = [];
@@ -831,14 +902,21 @@ function buildSupportNote(sharedSupport, localeZhSupport) {
831
902
  );
832
903
  }
833
904
 
834
- if (sharedSupport.crudSchema.exists && !sharedSupport.crudSchema.isCompatible) {
835
- notes.push(
836
- 'Detected an existing src/utils/crudSchema.ts that does not match the expected helper signature. ' +
837
- 'MCP preserved the existing file and did not overwrite it. Generated pages now depend on that file being manually aligned.'
838
- );
839
- }
840
-
841
- if (localeZhSupport.exists && !localeZhSupport.isCompatible) {
905
+ if (sharedSupport.crudSchema.exists && !sharedSupport.crudSchema.isCompatible) {
906
+ notes.push(
907
+ 'Detected an existing src/utils/crudSchema.ts that does not match the expected helper signature. ' +
908
+ 'MCP preserved the existing file and did not overwrite it. Generated pages now depend on that file being manually aligned.'
909
+ );
910
+ }
911
+
912
+ if (sharedSupport.dictRegistry.exists && !sharedSupport.dictRegistry.isCompatible) {
913
+ notes.push(
914
+ 'Detected an existing src/enums/dict-registry.ts that MCP could not merge safely. ' +
915
+ 'MCP preserved the existing file and did not overwrite it.'
916
+ );
917
+ }
918
+
919
+ if (localeZhSupport.exists && !localeZhSupport.isCompatible) {
842
920
  notes.push(
843
921
  `Detected an existing ${path.relative(localeZhSupport.frontendPath, localeZhSupport.path).replace(/\\/g, '/')} that MCP could not parse. ` +
844
922
  'The file was preserved and not updated, so new Chinese i18n keys may need to be merged manually.'
@@ -1634,23 +1712,24 @@ function renderTableColumn(field) {
1634
1712
  function renderChildTableColumn(field, childListName) {
1635
1713
  const rules = field.notNull ? ` :rules="[{ required: true, trigger: 'blur' }]"` : '';
1636
1714
  const labelExpr = `getChildFieldLabel('${childListName}', '${field.attrName}')`;
1637
- const inputPlaceholderExpr = `inputPlaceholder(getChildFieldLabel('${childListName}', '${field.attrName}'))`;
1638
- const selectPlaceholderExpr = `selectPlaceholder(getChildFieldLabel('${childListName}', '${field.attrName}'))`;
1715
+ const inputPlaceholderExpr = `formInputPlaceholder(${labelExpr}, ${renderDisabledBoolV2(field)})`;
1716
+ const selectPlaceholderExpr = `formSelectPlaceholder(${labelExpr}, ${renderDisabledBoolV2(field)})`;
1717
+ const disabledAttr = renderDisabledAttrV2(field);
1639
1718
 
1640
- let control = ` <el-input v-model="row.${field.attrName}" :placeholder="${inputPlaceholderExpr}" />`;
1719
+ let control = ` <el-input v-model="row.${field.attrName}" :placeholder="${inputPlaceholderExpr}"${disabledAttr} />`;
1641
1720
  if (field.formType === 'upload') {
1642
- control = ` <UploadFile v-model="row.${field.attrName}" />`;
1721
+ control = ` <UploadFile v-model="row.${field.attrName}"${disabledAttr} />`;
1643
1722
  } else if (field.formType === 'select' && field.dictType) {
1644
1723
  control = [
1645
- ` <el-select v-model="row.${field.attrName}" :placeholder="${selectPlaceholderExpr}" style="width: 100%">`,
1724
+ ` <el-select v-model="row.${field.attrName}" :placeholder="${selectPlaceholderExpr}" style="width: 100%"${disabledAttr}>`,
1646
1725
  ` <el-option v-for="item in ${field.dictType}" :key="item.value" :label="item.label" :value="item.value" />`,
1647
1726
  ' </el-select>',
1648
- ].join('\n');
1649
- } else if (field.formType === 'number') {
1650
- const max = field.comment.includes('%') || /\u6BD4\u4F8B/.test(field.comment) ? ' :max="100"' : '';
1651
- const precision = field.sqlType === 'DECIMAL' && field.scale ? ` :precision="${field.scale}" :step="0.01"` : '';
1652
- control = ` <el-input-number v-model="row.${field.attrName}" :min="0"${max}${precision} style="width: 100%" />`;
1653
- }
1727
+ ].join('\n');
1728
+ } else if (field.formType === 'number') {
1729
+ const max = field.comment.includes('%') || /\u6BD4\u4F8B/.test(field.comment) ? ' :max="100"' : '';
1730
+ const precision = field.sqlType === 'DECIMAL' && field.scale ? ` :precision="${field.scale}" :step="0.01"` : '';
1731
+ control = ` <el-input-number v-model="row.${field.attrName}" :min="0"${max}${precision} :placeholder="${inputPlaceholderExpr}" style="width: 100%"${disabledAttr} />`;
1732
+ }
1654
1733
 
1655
1734
  return [
1656
1735
  ` <el-table-column :label="${labelExpr}" prop="${field.attrName}">`,
@@ -1864,11 +1943,15 @@ function renderTextareaMaxlengthAttrsV2(field) {
1864
1943
  return ` :maxlength="${field.length}" show-word-limit`;
1865
1944
  }
1866
1945
 
1867
- function renderDisabledAttrV2(field) {
1868
- return field.readonly ? ' disabled' : '';
1869
- }
1870
-
1871
- function isAttachmentLikeField(field) {
1946
+ function renderDisabledAttrV2(field) {
1947
+ return field.readonly ? ' disabled' : '';
1948
+ }
1949
+
1950
+ function renderDisabledBoolV2(field) {
1951
+ return field.readonly ? 'true' : 'false';
1952
+ }
1953
+
1954
+ function isAttachmentLikeField(field) {
1872
1955
  const fieldName = String(field?.fieldName || field?.attrName || '').toLowerCase();
1873
1956
  const comment = String(field?.comment || field?.description || '').toLowerCase();
1874
1957
  return fieldName.includes('attachment') || comment.includes('\u9644\u4ef6') || comment.includes('\u4e0a\u4f20');
@@ -1884,6 +1967,7 @@ function renderFormFieldV2(field) {
1884
1967
  const labelExpr = `getMasterFieldLabel('${prop}')`;
1885
1968
  const dictExpr = `getMasterFieldMeta('${prop}')?.dictType`;
1886
1969
  const disabledAttr = renderDisabledAttrV2(field);
1970
+ const disabledBool = renderDisabledBoolV2(field);
1887
1971
 
1888
1972
  if (field.formType === 'upload') {
1889
1973
  return [
@@ -1901,7 +1985,7 @@ function renderFormFieldV2(field) {
1901
1985
  renderFieldCommentV2(field),
1902
1986
  ` <el-col :span="12" class="mb20">`,
1903
1987
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
1904
- ` <el-select v-model="form.${prop}" :placeholder="selectPlaceholder(${labelExpr})" style="width: 100%"${disabledAttr}>`,
1988
+ ` <el-select v-model="form.${prop}" :placeholder="formSelectPlaceholder(${labelExpr}, ${disabledBool})" style="width: 100%"${disabledAttr}>`,
1905
1989
  ` <el-option v-for="item in getDictOptions(${dictExpr})" :key="item.value" :label="item.label" :value="item.value" />`,
1906
1990
  ' </el-select>',
1907
1991
  ' </el-form-item>',
@@ -1916,7 +2000,7 @@ function renderFormFieldV2(field) {
1916
2000
  renderFieldCommentV2(field),
1917
2001
  ` <el-col :span="12" class="mb20">`,
1918
2002
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
1919
- ` <el-input-number v-model="form.${prop}" :min="0"${max}${precision} :placeholder="inputPlaceholder(${labelExpr})" style="width: 100%"${disabledAttr} />`,
2003
+ ` <el-input-number v-model="form.${prop}" :min="0"${max}${precision} :placeholder="formInputPlaceholder(${labelExpr}, ${disabledBool})" style="width: 100%"${disabledAttr} />`,
1920
2004
  ' </el-form-item>',
1921
2005
  ' </el-col>',
1922
2006
  ].join('\n');
@@ -1929,7 +2013,7 @@ function renderFormFieldV2(field) {
1929
2013
  renderFieldCommentV2(field),
1930
2014
  ` <el-col :span="12" class="mb20">`,
1931
2015
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
1932
- ` <el-date-picker type="${pickerType}" :placeholder="inputPlaceholder(${labelExpr})" v-model="form.${prop}" :value-format="${formatName}" style="width: 100%"${disabledAttr}></el-date-picker>`,
2016
+ ` <el-date-picker type="${pickerType}" :placeholder="formInputPlaceholder(${labelExpr}, ${disabledBool})" v-model="form.${prop}" :value-format="${formatName}" style="width: 100%"${disabledAttr}></el-date-picker>`,
1933
2017
  ' </el-form-item>',
1934
2018
  ' </el-col>',
1935
2019
  ].join('\n');
@@ -1941,7 +2025,7 @@ function renderFormFieldV2(field) {
1941
2025
  renderFieldCommentV2(field),
1942
2026
  ` <el-col :span="24" class="mb20">`,
1943
2027
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
1944
- ` <el-input type="textarea" v-model="form.${prop}" :placeholder="inputPlaceholder(${labelExpr})"${textareaAttrs}${disabledAttr} />`,
2028
+ ` <el-input type="textarea" v-model="form.${prop}" :placeholder="formInputPlaceholder(${labelExpr}, ${disabledBool})"${textareaAttrs}${disabledAttr} />`,
1945
2029
  ' </el-form-item>',
1946
2030
  ' </el-col>',
1947
2031
  ].join('\n');
@@ -1952,7 +2036,7 @@ function renderFormFieldV2(field) {
1952
2036
  renderFieldCommentV2(field),
1953
2037
  ` <el-col :span="12" class="mb20">`,
1954
2038
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
1955
- ` <el-input v-model="form.${prop}" :placeholder="inputPlaceholder(${labelExpr})"${maxlengthAttr}${disabledAttr} />`,
2039
+ ` <el-input v-model="form.${prop}" :placeholder="formInputPlaceholder(${labelExpr}, ${disabledBool})"${maxlengthAttr}${disabledAttr} />`,
1956
2040
  ' </el-form-item>',
1957
2041
  ' </el-col>',
1958
2042
  ].join('\n');
@@ -2144,10 +2228,11 @@ function renderMultiLevelApiTs(model) {
2144
2228
  ].join('\n');
2145
2229
  }
2146
2230
 
2147
- function renderMultiLevelFormField(field) {
2148
- const labelExpr = `getFieldLabel('${field.attrName}')`;
2149
- const prop = field.attrName;
2150
- const disabledAttr = renderDisabledAttrV2(field);
2231
+ function renderMultiLevelFormField(field) {
2232
+ const labelExpr = `getFieldLabel('${field.attrName}')`;
2233
+ const prop = field.attrName;
2234
+ const disabledAttr = renderDisabledAttrV2(field);
2235
+ const disabledBool = renderDisabledBoolV2(field);
2151
2236
 
2152
2237
  if (isAttachmentLikeField(field)) {
2153
2238
  return [
@@ -2165,7 +2250,7 @@ function renderMultiLevelFormField(field) {
2165
2250
  renderFieldCommentV2(field),
2166
2251
  ' <el-col :span="12" class="mb20">',
2167
2252
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
2168
- ` <el-select v-model="form.${prop}" :placeholder="selectPlaceholder(${labelExpr})" style="width: 100%"${disabledAttr}>`,
2253
+ ` <el-select v-model="form.${prop}" :placeholder="formSelectPlaceholder(${labelExpr}, ${disabledBool})" style="width: 100%"${disabledAttr}>`,
2169
2254
  ` <el-option v-for="item in getDictOptions(getFieldMeta('${prop}')?.dictType)" :key="item.value" :label="item.label" :value="item.value" />`,
2170
2255
  ' </el-select>',
2171
2256
  ' </el-form-item>',
@@ -2180,7 +2265,7 @@ function renderMultiLevelFormField(field) {
2180
2265
  renderFieldCommentV2(field),
2181
2266
  ' <el-col :span="12" class="mb20">',
2182
2267
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
2183
- ` <el-input-number v-model="form.${prop}" :min="0"${max}${precision} :placeholder="inputPlaceholder(${labelExpr})" style="width: 100%"${disabledAttr} />`,
2268
+ ` <el-input-number v-model="form.${prop}" :min="0"${max}${precision} :placeholder="formInputPlaceholder(${labelExpr}, ${disabledBool})" style="width: 100%"${disabledAttr} />`,
2184
2269
  ' </el-form-item>',
2185
2270
  ' </el-col>',
2186
2271
  ].join('\n');
@@ -2193,7 +2278,7 @@ function renderMultiLevelFormField(field) {
2193
2278
  renderFieldCommentV2(field),
2194
2279
  ' <el-col :span="12" class="mb20">',
2195
2280
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
2196
- ` <el-date-picker type="${pickerType}" :placeholder="inputPlaceholder(${labelExpr})" v-model="form.${prop}" :value-format="${formatName}" style="width: 100%"${disabledAttr}></el-date-picker>`,
2281
+ ` <el-date-picker type="${pickerType}" :placeholder="formInputPlaceholder(${labelExpr}, ${disabledBool})" v-model="form.${prop}" :value-format="${formatName}" style="width: 100%"${disabledAttr}></el-date-picker>`,
2197
2282
  ' </el-form-item>',
2198
2283
  ' </el-col>',
2199
2284
  ].join('\n');
@@ -2205,7 +2290,7 @@ function renderMultiLevelFormField(field) {
2205
2290
  renderFieldCommentV2(field),
2206
2291
  ' <el-col :span="24" class="mb20">',
2207
2292
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
2208
- ` <el-input type="textarea" v-model="form.${prop}" :placeholder="inputPlaceholder(${labelExpr})"${textareaAttrs}${disabledAttr} />`,
2293
+ ` <el-input type="textarea" v-model="form.${prop}" :placeholder="formInputPlaceholder(${labelExpr}, ${disabledBool})"${textareaAttrs}${disabledAttr} />`,
2209
2294
  ' </el-form-item>',
2210
2295
  ' </el-col>',
2211
2296
  ].join('\n');
@@ -2215,7 +2300,7 @@ function renderMultiLevelFormField(field) {
2215
2300
  renderFieldCommentV2(field),
2216
2301
  ' <el-col :span="12" class="mb20">',
2217
2302
  ` <el-form-item :label="${labelExpr}" prop="${prop}">`,
2218
- ` <el-input v-model="form.${prop}" :placeholder="inputPlaceholder(${labelExpr})"${renderInputMaxlengthAttr(field)}${disabledAttr} />`,
2303
+ ` <el-input v-model="form.${prop}" :placeholder="formInputPlaceholder(${labelExpr}, ${disabledBool})"${renderInputMaxlengthAttr(field)}${disabledAttr} />`,
2219
2304
  ' </el-form-item>',
2220
2305
  ' </el-col>',
2221
2306
  ].join('\n');
@@ -2281,6 +2366,8 @@ ${moduleModel.visibleFields.map(renderMultiLevelFormField).join('\n')}
2281
2366
 
2282
2367
  // 字段标签、字典和校验提示
2283
2368
  const { getFieldMeta, getFieldLabel, getDictOptions, inputPlaceholder, selectPlaceholder, fieldRequiredMessage } = useCrudPageMeta(${fieldsMapExpr}, dictRefs);
2369
+ const formInputPlaceholder = (label: string, disabled = false) => (disabled ? '' : inputPlaceholder(label));
2370
+ const formSelectPlaceholder = (label: string, disabled = false) => (disabled ? '' : selectPlaceholder(label));
2284
2371
 
2285
2372
  // 统一维护表单默认值
2286
2373
  const createDefaultFormState = () => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worsoft-frontend-codegen-local-mcp",
3
- "version": "0.1.53",
3
+ "version": "0.1.55",
4
4
  "description": "Worsoft frontend local-template code generation MCP server.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "worsoft <sw@worsoft.vip>",