worsoft-frontend-codegen-local-mcp 0.1.7 → 0.1.9

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.
@@ -5,14 +5,14 @@
5
5
  <div style="display: flex; justify-content: space-between; align-items: center;">
6
6
  <span style="font-size: 16px; font-weight: bold;">{{ form.{{PK_ATTR}} ? (detail ? t('common.viewBtn') : t('common.editBtn')) : t('common.addBtn') }}</span>
7
7
  <div v-if="!detail">
8
- <el-button @click="onSubmit('save')" :disabled="loading" icon="document">{{ actionLabel('save') }}</el-button>
9
- <el-button @click="onSubmit('flow')" :disabled="loading" plain type="success" icon="position">{{ actionLabel('flow') }}</el-button>
10
- <el-button @click="onSubmit('submit')" :disabled="loading" type="primary" icon="check">{{ actionLabel('submit') }}</el-button>
8
+ <el-button @click="onSubmit('save')" :disabled="loading" icon="document">{{ commonActionLabel('save') }}</el-button>
9
+ <el-button @click="onSubmit('flow')" :disabled="loading" plain type="success" icon="position">{{ commonActionLabel('flow') }}</el-button>
10
+ <el-button @click="onSubmit('submit')" :disabled="loading" type="primary" icon="check">{{ commonActionLabel('submit') }}</el-button>
11
11
  <el-divider direction="vertical" />
12
12
  <el-button @click="handleBack" icon="close">{{ t('common.cancelButtonText') }}</el-button>
13
13
  </div>
14
14
  <div v-else>
15
- <el-button @click="handleBack" icon="back">{{ actionLabel('back') }}</el-button>
15
+ <el-button @click="handleBack" icon="back">{{ commonActionLabel('back') }}</el-button>
16
16
  </div>
17
17
  </div>
18
18
  </template>
@@ -71,10 +71,10 @@ const getChildFieldLabel = (groupName: string, prop: string) => {
71
71
  };
72
72
  const childSectionTitle = (groupName: string) => t(`${pageI18nKey}.children.${groupName}.title`);
73
73
  const getDictOptions = (dictType?: string) => (dictType ? dictRefs[dictType]?.value || [] : []);
74
- const inputPlaceholder = (label: string) => t(`${pageI18nKey}.placeholders.input`, { label });
75
- const selectPlaceholder = (label: string) => t(`${pageI18nKey}.placeholders.select`, { label });
76
- const fieldRequiredMessage = (prop: string) => t(`${pageI18nKey}.messages.required`, { label: getMasterFieldLabel(prop) });
77
- const actionLabel = (action: string) => t(`${pageI18nKey}.actions.${action}`);
74
+ const inputPlaceholder = (label: string) => t('common.placeholders.input', { label });
75
+ const selectPlaceholder = (label: string) => t('common.placeholders.select', { label });
76
+ const fieldRequiredMessage = (prop: string) => t('common.messages.required', { label: getMasterFieldLabel(prop) });
77
+ const commonActionLabel = (action: string) => t('common.actions.' + action);
78
78
 
79
79
  const form = reactive({
80
80
  {{FORM_DEFAULTS}}
@@ -93,7 +93,7 @@ const get{{CLASS_NAME}}Data = async (id: string) => {
93
93
  const { data } = await getObj({ {{PK_ATTR}}: id });
94
94
  Object.assign(form, data[0] || {});
95
95
  } catch (error) {
96
- useMessage().error(t(`${pageI18nKey}.messages.fetchError`));
96
+ useMessage().error(t('common.messages.fetchError'));
97
97
  } finally {
98
98
  loading.value = false;
99
99
  }
@@ -143,14 +143,14 @@ const onSubmit = async (actionType?: string) => {
143
143
  try {
144
144
  form.{{PK_ATTR}} ? await putObj(form) : await addObj(form);
145
145
 
146
- let msg = form.{{PK_ATTR}} ? t(`${pageI18nKey}.messages.updateSuccess`) : t(`${pageI18nKey}.messages.createSuccess`);
147
- if (actionType === 'submit') msg = t(`${pageI18nKey}.messages.quickSubmitSuccess`);
148
- if (actionType === 'flow') msg = t(`${pageI18nKey}.messages.quickFlowSuccess`);
146
+ let msg = form.{{PK_ATTR}} ? t('common.editSuccessText') : t('common.addSuccessText');
147
+ if (actionType === 'submit') msg = t('common.messages.quickSubmitSuccess');
148
+ if (actionType === 'flow') msg = t('common.messages.quickFlowSuccess');
149
149
 
150
150
  useMessage().success(msg);
151
151
  closeCurrentPage();
152
152
  } catch (err: any) {
153
- useMessage().error(err.msg || t(`${pageI18nKey}.messages.submitError`));
153
+ useMessage().error(err.msg || t('common.messages.submitError'));
154
154
  } finally {
155
155
  loading.value = false;
156
156
  }
@@ -39,8 +39,8 @@
39
39
  <template #default="scope">
40
40
  <el-button text type="primary" icon="view" v-auth="'{{PERMISSION_PREFIX}}_view'" @click="handleDetail(scope.row.id)">{{ t('common.viewBtn') }}</el-button>
41
41
  <el-button icon="edit-pen" text type="primary" v-auth="'{{PERMISSION_PREFIX}}_edit'" @click="handleEdit(scope.row.id)">{{ t('common.editBtn') }}</el-button>
42
- <el-button text type="primary" icon="check" @click="handleQuickAction(scope.row, 'submit')">{{ actionLabel('submit') }}</el-button>
43
- <el-button text type="success" icon="position" @click="handleQuickAction(scope.row, 'flow')">{{ actionLabel('flow') }}</el-button>
42
+ <el-button text type="primary" icon="check" @click="handleQuickAction(scope.row, 'submit')">{{ commonActionLabel('submit') }}</el-button>
43
+ <el-button text type="success" icon="position" @click="handleQuickAction(scope.row, 'flow')">{{ commonActionLabel('flow') }}</el-button>
44
44
  <el-button icon="delete" text type="primary" v-auth="'{{PERMISSION_PREFIX}}_del'" @click="handleDelete([scope.row.id])">{{ t('common.delBtn') }}</el-button>
45
45
  </template>
46
46
  </el-table-column>
@@ -67,7 +67,6 @@ import { allDictTypes, dataMasterEntity } from './options';
67
67
  const dictRefs = useDict(...allDictTypes);
68
68
  const { t } = useI18n();
69
69
  const router = useRouter();
70
- const pageI18nKey = '{{I18N_NAMESPACE}}';
71
70
 
72
71
  const excelUploadRef = ref();
73
72
  const showSearch = ref(true);
@@ -85,7 +84,7 @@ const resolveLabel = (labelKey?: string, fallback = '') => {
85
84
  return translated === labelKey ? fallback : translated;
86
85
  };
87
86
 
88
- const actionLabel = (action: string) => t(`${pageI18nKey}.actions.${action}`);
87
+ const commonActionLabel = (action: string) => t('common.actions.' + action);
89
88
 
90
89
  const visibleTableColumns = computed(() =>
91
90
  Object.entries(dataMasterEntity)
@@ -118,13 +117,13 @@ const handleEdit = (id: string) => {
118
117
  };
119
118
 
120
119
  const handleQuickAction = async (row: any, actionType: string) => {
121
- const actionName = actionLabel(actionType);
120
+ const actionName = commonActionLabel(actionType);
122
121
  try {
123
- await useMessageBox().confirm(t(`${pageI18nKey}.messages.quickActionConfirm`, { action: actionName }));
122
+ await useMessageBox().confirm(t('common.messages.quickActionConfirm', { action: actionName }));
124
123
  useMessage().success(
125
124
  actionType === 'submit'
126
- ? t(`${pageI18nKey}.messages.quickSubmitSuccess`)
127
- : t(`${pageI18nKey}.messages.quickFlowSuccess`)
125
+ ? t('common.messages.quickSubmitSuccess')
126
+ : t('common.messages.quickFlowSuccess')
128
127
  );
129
128
  getDataList();
130
129
  } catch {}
@@ -23,7 +23,6 @@ import { allDictTypes, dataMasterEntity } from './options';
23
23
 
24
24
  const dictRefs = useDict(...allDictTypes);
25
25
  const { t } = useI18n();
26
- const pageI18nKey = '{{I18N_NAMESPACE}}';
27
26
  const emit = defineEmits(['refresh']);
28
27
 
29
28
  const dataFormRef = ref();
@@ -47,9 +46,9 @@ const getMasterFieldLabel = (prop: string) => {
47
46
  return resolveLabel(config?.labelKey, config?.label || prop);
48
47
  };
49
48
  const getDictOptions = (dictType?: string) => (dictType ? dictRefs[dictType]?.value || [] : []);
50
- const inputPlaceholder = (label: string) => t(`${pageI18nKey}.placeholders.input`, { label });
51
- const selectPlaceholder = (label: string) => t(`${pageI18nKey}.placeholders.select`, { label });
52
- const fieldRequiredMessage = (prop: string) => t(`${pageI18nKey}.messages.required`, { label: getMasterFieldLabel(prop) });
49
+ const inputPlaceholder = (label: string) => t('common.placeholders.input', { label });
50
+ const selectPlaceholder = (label: string) => t('common.placeholders.select', { label });
51
+ const fieldRequiredMessage = (prop: string) => t('common.messages.required', { label: getMasterFieldLabel(prop) });
53
52
 
54
53
  const form = reactive({
55
54
  {{FORM_DEFAULTS}}
@@ -65,7 +64,7 @@ const get{{CLASS_NAME}}Data = async (id: string) => {
65
64
  const { data } = await getObj({ {{PK_ATTR}}: id });
66
65
  Object.assign(form, data[0] || {});
67
66
  } catch (error) {
68
- useMessage().error(t(`${pageI18nKey}.messages.fetchError`));
67
+ useMessage().error(t('common.messages.fetchError'));
69
68
  } finally {
70
69
  loading.value = false;
71
70
  }
@@ -101,11 +100,11 @@ const onSubmit = async () => {
101
100
 
102
101
  try {
103
102
  form.{{PK_ATTR}} ? await putObj(form) : await addObj(form);
104
- useMessage().success(form.{{PK_ATTR}} ? t(`${pageI18nKey}.messages.updateSuccess`) : t(`${pageI18nKey}.messages.createSuccess`));
103
+ useMessage().success(form.{{PK_ATTR}} ? t('common.editSuccessText') : t('common.addSuccessText'));
105
104
  visible.value = false;
106
105
  emit('refresh');
107
106
  } catch (err: any) {
108
- useMessage().error(err.msg || t(`${pageI18nKey}.messages.submitError`));
107
+ useMessage().error(err.msg || t('common.messages.submitError'));
109
108
  } finally {
110
109
  loading.value = false;
111
110
  }
@@ -29,7 +29,6 @@ const dictRefs = useDict(...allDictTypes);
29
29
  const { t } = useI18n();
30
30
  const route = useRoute();
31
31
  const router = useRouter();
32
- const pageI18nKey = '{{I18N_NAMESPACE}}';
33
32
 
34
33
  const dataFormRef = ref();
35
34
  const loading = ref(false);
@@ -52,9 +51,9 @@ const getMasterFieldLabel = (prop: string) => {
52
51
  return resolveLabel(config?.labelKey, config?.label || prop);
53
52
  };
54
53
  const getDictOptions = (dictType?: string) => (dictType ? dictRefs[dictType]?.value || [] : []);
55
- const inputPlaceholder = (label: string) => t(`${pageI18nKey}.placeholders.input`, { label });
56
- const selectPlaceholder = (label: string) => t(`${pageI18nKey}.placeholders.select`, { label });
57
- const fieldRequiredMessage = (prop: string) => t(`${pageI18nKey}.messages.required`, { label: getMasterFieldLabel(prop) });
54
+ const inputPlaceholder = (label: string) => t('common.placeholders.input', { label });
55
+ const selectPlaceholder = (label: string) => t('common.placeholders.select', { label });
56
+ const fieldRequiredMessage = (prop: string) => t('common.messages.required', { label: getMasterFieldLabel(prop) });
58
57
 
59
58
  const form = reactive({
60
59
  {{FORM_DEFAULTS}}
@@ -70,7 +69,7 @@ const get{{CLASS_NAME}}Data = async (id: string) => {
70
69
  const { data } = await getObj({ {{PK_ATTR}}: id });
71
70
  Object.assign(form, data[0] || {});
72
71
  } catch (error) {
73
- useMessage().error(t(`${pageI18nKey}.messages.fetchError`));
72
+ useMessage().error(t('common.messages.fetchError'));
74
73
  } finally {
75
74
  loading.value = false;
76
75
  }
@@ -117,10 +116,10 @@ const onSubmit = async () => {
117
116
 
118
117
  try {
119
118
  form.{{PK_ATTR}} ? await putObj(form) : await addObj(form);
120
- useMessage().success(form.{{PK_ATTR}} ? t(`${pageI18nKey}.messages.updateSuccess`) : t(`${pageI18nKey}.messages.createSuccess`));
119
+ useMessage().success(form.{{PK_ATTR}} ? t('common.editSuccessText') : t('common.addSuccessText'));
121
120
  closeCurrentPage();
122
121
  } catch (err: any) {
123
- useMessage().error(err.msg || t(`${pageI18nKey}.messages.submitError`));
122
+ useMessage().error(err.msg || t('common.messages.submitError'));
124
123
  } finally {
125
124
  loading.value = false;
126
125
  }
package/mcp_server.js CHANGED
@@ -5,12 +5,12 @@ 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.7';
8
+ const SERVER_VERSION = '0.1.9';
9
9
  const PROTOCOL_VERSION = '2024-11-05';
10
10
  const TOOL_NAME = 'worsoft_codegen_local_generate_frontend';
11
11
  const TEMPLATE_LIBRARY_ROOT = path.resolve(__dirname, '..', 'template');
12
12
  const STYLE_CATALOG_PATH = path.join(__dirname, 'assets', 'style-catalog.json');
13
- const DEFAULT_DESIGN_FILE = path.resolve(__dirname, '..', 'sql', 'SQL 设计说明.md');
13
+ const DEFAULT_DESIGN_FILE = path.resolve(__dirname, '..', 'sql', 'SQL 璁捐璇存槑.md');
14
14
  const STYLE_CATALOG = loadStyleCatalog();
15
15
  const DEFAULT_DICT_REGISTRY_KEYS = {
16
16
  add_start_stop: 'COMMON_STATUS',
@@ -127,7 +127,7 @@ export function createCrudSchema(
127
127
  const TOOL_SCHEMA = {
128
128
  type: 'object',
129
129
  properties: {
130
- designFile: { type: 'string', description: 'Absolute or relative Markdown design file path. Defaults to ../sql/SQL 设计说明.md when omitted.' },
130
+ designFile: { type: 'string', description: 'Absolute or relative Markdown design file path. Defaults to ../sql/SQL 璁捐璇存槑.md when omitted.' },
131
131
  tableName: { type: 'string', description: 'Target main table name from the design file.' },
132
132
  style: { type: 'string', enum: Object.keys(STYLE_CATALOG), description: 'Style id from assets/style-catalog.json.' },
133
133
  children: {
@@ -324,6 +324,30 @@ function buildI18nNamespace(model) {
324
324
  return buildI18nNamespaceSegments(model).join('.');
325
325
  }
326
326
 
327
+ function removeFeatureCommonLocaleSections(localeObject, model) {
328
+ if (!isPlainObject(localeObject)) {
329
+ return localeObject;
330
+ }
331
+
332
+ const segments = buildI18nNamespaceSegments(model);
333
+ let cursor = localeObject;
334
+ for (let index = 0; index < segments.length; index += 1) {
335
+ const segment = segments[index];
336
+ if (!isPlainObject(cursor[segment])) {
337
+ return localeObject;
338
+ }
339
+ if (index === segments.length - 1) {
340
+ delete cursor[segment].placeholders;
341
+ delete cursor[segment].actions;
342
+ delete cursor[segment].messages;
343
+ return localeObject;
344
+ }
345
+ cursor = cursor[segment];
346
+ }
347
+
348
+ return localeObject;
349
+ }
350
+
327
351
  function buildFieldLabelKey(model, field) {
328
352
  return `${buildI18nNamespace(model)}.fields.${field.attrName}`;
329
353
  }
@@ -340,26 +364,6 @@ function buildLocaleLeaf(model) {
340
364
  const leaf = {
341
365
  title: model.tableComment,
342
366
  fields: Object.fromEntries(model.visibleFields.map((field) => [field.attrName, stripDictAnnotation(field.comment)])),
343
- placeholders: {
344
- input: '请输入{label}',
345
- select: '请选择{label}',
346
- },
347
- actions: {
348
- save: '保存',
349
- submit: '提交',
350
- flow: '流转',
351
- back: '返回',
352
- },
353
- messages: {
354
- required: '{label}不能为空',
355
- fetchError: '获取数据失败',
356
- submitError: '提交失败',
357
- createSuccess: '添加成功',
358
- updateSuccess: '修改成功',
359
- quickSubmitSuccess: '提交操作成功',
360
- quickFlowSuccess: '流转操作成功',
361
- quickActionConfirm: '确定要{action}该记录吗?',
362
- },
363
367
  };
364
368
 
365
369
  if (model.children.length) {
@@ -399,7 +403,8 @@ function prepareZhCnLocaleFile(model) {
399
403
  const currentObject = exists ? parseExportDefaultObject(currentContent) : null;
400
404
  const generatedObject = buildZhCnLocaleObject(model);
401
405
  const isCompatible = !exists || isPlainObject(currentObject);
402
- const mergedObject = isCompatible ? deepMergeMissing(currentObject || {}, generatedObject) : null;
406
+ const sanitizedCurrentObject = isCompatible ? removeFeatureCommonLocaleSections(currentObject || {}, model) : null;
407
+ const mergedObject = isCompatible ? deepMergeMissing(sanitizedCurrentObject || {}, generatedObject) : null;
403
408
 
404
409
  return {
405
410
  path: localePath,
@@ -544,7 +549,7 @@ function isAuditField(fieldName) {
544
549
 
545
550
  function findDictType(comment) {
546
551
  return extractDictType(comment);
547
- const match = comment.match(/(?:字典|dict)[::\s]*([a-zA-Z0-9_]+)/i);
552
+ const match = comment.match(/(?:瀛楀吀|dict)[锛?\s]*([a-zA-Z0-9_]+)/i);
548
553
  }
549
554
 
550
555
  function mapFieldType(field) {
@@ -583,7 +588,7 @@ function stripDictAnnotation(label) {
583
588
  return '';
584
589
  }
585
590
  return text
586
- .replace(/\s*[((]\s*(?:字典|dict)(?:类型|type)?\s*[::=]?\s*[a-zA-Z0-9_-]+\s*[))]\s*/gi, '')
591
+ .replace(/\s*[锛?]\s*(?:瀛楀吀|dict)(?:绫诲瀷|type)?\s*[:锛?]?\s*[a-zA-Z0-9_-]+\s*[锛?]\s*/gi, '')
587
592
  .replace(/\s+/g, ' ')
588
593
  .trim();
589
594
  }
@@ -595,9 +600,9 @@ function extractDictType(text) {
595
600
  }
596
601
 
597
602
  const patterns = [
598
- /(?:字典|dict)(?:类型|type)?\s*[::=]\s*([a-zA-Z0-9_-]+)/i,
599
- /(?:字典|dict)(?:类型|type)?\s*[((]\s*([a-zA-Z0-9_-]+)\s*[))]/i,
600
- /[((]\s*(?:字典|dict)(?:类型|type)?\s*[::=]?\s*([a-zA-Z0-9_-]+)\s*[))]/i,
603
+ /(?:瀛楀吀|dict)(?:绫诲瀷|type)?\s*[:锛?]\s*([a-zA-Z0-9_-]+)/i,
604
+ /(?:瀛楀吀|dict)(?:绫诲瀷|type)?\s*[锛?]\s*([a-zA-Z0-9_-]+)\s*[锛?]/i,
605
+ /[锛?]\s*(?:瀛楀吀|dict)(?:绫诲瀷|type)?\s*[:锛?]?\s*([a-zA-Z0-9_-]+)\s*[锛?]/i,
601
606
  ];
602
607
 
603
608
  for (const pattern of patterns) {
@@ -616,7 +621,7 @@ function resolveDictType(comment, explicitDictType) {
616
621
 
617
622
  function detectDictType(comment) {
618
623
  return extractDictType(comment);
619
- return findDictType(comment) || ((comment.match(/(?:字典|dict)\s*[::\((]?\s*([a-zA-Z0-9_]+)/i) || [])[1] ?? null);
624
+ return findDictType(comment) || ((comment.match(/(?:瀛楀吀|dict)\s*[:锛歕(锛圿?\s*([a-zA-Z0-9_]+)/i) || [])[1] ?? null);
620
625
  }
621
626
 
622
627
  function splitLength(value) {
@@ -638,7 +643,7 @@ function normalizeDefaultValue(value) {
638
643
 
639
644
  function parseRequiredFlag(value) {
640
645
  const normalized = String(value || '').trim().toLowerCase();
641
- return ['是', 'y', 'yes', '1', 'true', '必填'].includes(normalized);
646
+ return ['鏄?, 'y', 'yes', '1', 'true', '蹇呭~'].includes(normalized);
642
647
  }
643
648
 
644
649
  function parseMarkdownRow(line) {
@@ -664,7 +669,7 @@ function findPrimaryKeyFromText(text, fields) {
664
669
  return quotedMatch[1];
665
670
  }
666
671
 
667
- const commentPk = fields.find((field) => /主键/i.test(field.comment));
672
+ const commentPk = fields.find((field) => /涓婚敭/i.test(field.comment));
668
673
  if (commentPk) {
669
674
  return commentPk.fieldName;
670
675
  }
@@ -697,14 +702,14 @@ function parseMarkdownTableSection(tableName, tableComment, sectionLines) {
697
702
 
698
703
  const headers = rows[0];
699
704
  const dataRows = rows.slice(1).filter((cells) => !isMarkdownSeparatorRow(cells));
700
- const fieldNameIndex = findHeaderIndex(headers, [/字段名/, /列名/i, /field/i]);
701
- const sqlTypeIndex = findHeaderIndex(headers, [/类型/, /数据类型/, /type/i]);
702
- const lengthIndex = findHeaderIndex(headers, [/长度/, /精度/, /length/i]);
703
- const requiredIndex = findHeaderIndex(headers, [/必填/, /必输/, /required/i]);
704
- const defaultIndex = findHeaderIndex(headers, [/默认/, /default/i]);
705
- const commentIndex = findHeaderIndex(headers, [/说明/, /备注/, /comment/i]);
705
+ const fieldNameIndex = findHeaderIndex(headers, [/瀛楁鍚?, /鍒楀悕/i, /field/i]);
706
+ const sqlTypeIndex = findHeaderIndex(headers, [/绫诲瀷/, /鏁版嵁绫诲瀷/, /type/i]);
707
+ const lengthIndex = findHeaderIndex(headers, [/闀垮害/, /绮惧害/, /length/i]);
708
+ const requiredIndex = findHeaderIndex(headers, [/蹇呭~/, /蹇呰緭/, /required/i]);
709
+ const defaultIndex = findHeaderIndex(headers, [/榛樿/, /default/i]);
710
+ const commentIndex = findHeaderIndex(headers, [/璇存槑/, /澶囨敞/, /comment/i]);
706
711
 
707
- const dictTypeIndex = findHeaderIndex(headers, [/字典/, /dict/i, /dict_?type/i]);
712
+ const dictTypeIndex = findHeaderIndex(headers, [/瀛楀吀/, /dict/i, /dict_?type/i]);
708
713
 
709
714
  if (fieldNameIndex < 0 || sqlTypeIndex < 0) {
710
715
  throw new Error('Markdown field table headers are missing required columns for ' + tableName);
@@ -752,7 +757,7 @@ function parseMarkdownDesignTables(markdownText) {
752
757
 
753
758
  for (let index = 0; index < lines.length; index += 1) {
754
759
  const heading = lines[index].trim();
755
- const headingMatch = heading.match(/^###\s+\S+\s+([a-zA-Z0-9_]+)\s*[\((]([^)\n)]+)[\))]/);
760
+ const headingMatch = heading.match(/^###\s+\S+\s+([a-zA-Z0-9_]+)\s*[\(锛圿([^)\n锛塢+)[\)锛塢/);
756
761
  if (!headingMatch) continue;
757
762
 
758
763
  const tableName = headingMatch[1];
@@ -811,9 +816,9 @@ function parseMarkdownRelations(markdownText) {
811
816
  const relations = [];
812
817
  for (const block of blocks) {
813
818
  const lines = block.body.split('\n').map((line) => line.trim()).filter(Boolean);
814
- const mainLine = lines.find((line) => /(主表|父表)\s*[::]/.test(line));
815
- const childLine = lines.find((line) => /(从表|子表)\s*[::]/.test(line));
816
- const fieldLine = lines.find((line) => /关联字段\s*[::]/.test(line));
819
+ const mainLine = lines.find((line) => /(涓昏〃|鐖惰〃)\s*[:锛歖/.test(line));
820
+ const childLine = lines.find((line) => /(浠庤〃|瀛愯〃)\s*[:锛歖/.test(line));
821
+ const fieldLine = lines.find((line) => /鍏宠仈瀛楁\s*[:锛歖/.test(line));
817
822
  if (!mainLine || !childLine || !fieldLine) continue;
818
823
 
819
824
  const mainIdentifiers = extractIdentifiersFromLine(mainLine);
@@ -821,14 +826,14 @@ function parseMarkdownRelations(markdownText) {
821
826
  const fieldIdentifiers = extractIdentifiersFromLine(fieldLine);
822
827
  if (!mainIdentifiers.length || !childIdentifiers.length || fieldIdentifiers.length < 2) continue;
823
828
 
824
- const relationTypeLine = lines.find((line) => /关系类型\s*[::]/.test(line));
829
+ const relationTypeLine = lines.find((line) => /鍏崇郴绫诲瀷\s*[:锛歖/.test(line));
825
830
  relations.push({
826
831
  title: block.title,
827
832
  mainTableName: mainIdentifiers[0],
828
833
  childTableName: childIdentifiers[0],
829
834
  childField: fieldIdentifiers[0],
830
835
  mainField: fieldIdentifiers[1],
831
- relationType: relationTypeLine ? relationTypeLine.split(/[::]/).slice(1).join(':').trim() : '',
836
+ relationType: relationTypeLine ? relationTypeLine.split(/[:锛歖/).slice(1).join(':').trim() : '',
832
837
  });
833
838
  }
834
839
 
@@ -965,13 +970,13 @@ function buildRetryArguments(safeArgs, sourceFile, childTableName) {
965
970
  function buildRelationCorrectionEntry(safeArgs, sourceFile, candidates, selectedChildTableName) {
966
971
  return {
967
972
  field: 'childTableName',
968
- title: '主子表关联修正入口',
973
+ title: '涓诲瓙琛ㄥ叧鑱斾慨姝e叆鍙?,
969
974
  tableName: safeArgs.tableName,
970
975
  style: safeArgs.style,
971
976
  designFile: sourceFile,
972
977
  description: candidates.length
973
978
  ? 'If the current child relation is not the one you want, pass childTableName to choose a candidate from the design file.'
974
- : 'No child relation was found. Check the 主从表关联说明 section in the design file.',
979
+ : 'No child relation was found. Check the 涓讳粠琛ㄥ叧鑱旇鏄?section in the design file.',
975
980
  currentValue: selectedChildTableName || '',
976
981
  options: candidates.map((item) => item.childTableName),
977
982
  candidates,
@@ -1184,7 +1189,7 @@ function renderFormField(field) {
1184
1189
  return [
1185
1190
  ' <el-col :span="12" class="mb20">',
1186
1191
  ` <el-form-item label="${label}" prop="${prop}">`,
1187
- ` <el-select v-model="form.${prop}" placeholder="请选择${label}" style="width: 100%">`,
1192
+ ` <el-select v-model="form.${prop}" placeholder="璇烽€夋嫨${label}" style="width: 100%">`,
1188
1193
  ` <el-option v-for="item in ${field.dictType}" :key="item.value" :label="item.label" :value="Number(item.value)" />`,
1189
1194
  ' </el-select>',
1190
1195
  ' </el-form-item>',
@@ -1193,12 +1198,12 @@ function renderFormField(field) {
1193
1198
  }
1194
1199
 
1195
1200
  if (field.formType === 'number') {
1196
- const max = field.comment.includes('%') || field.comment.includes('比例') ? ' :max="100"' : '';
1201
+ const max = field.comment.includes('%') || field.comment.includes('姣斾緥') ? ' :max="100"' : '';
1197
1202
  const precision = field.sqlType === 'DECIMAL' && field.scale ? ` :precision="${field.scale}" :step="0.01"` : '';
1198
1203
  return [
1199
1204
  ' <el-col :span="12" class="mb20">',
1200
1205
  ` <el-form-item label="${label}" prop="${prop}">`,
1201
- ` <el-input-number v-model="form.${prop}" :min="0"${max}${precision} placeholder="请输入${label}" style="width: 100%" />`,
1206
+ ` <el-input-number v-model="form.${prop}" :min="0"${max}${precision} placeholder="璇疯緭鍏?{label}" style="width: 100%" />`,
1202
1207
  ' </el-form-item>',
1203
1208
  ' </el-col>',
1204
1209
  ].join('\n');
@@ -1210,7 +1215,7 @@ function renderFormField(field) {
1210
1215
  return [
1211
1216
  ' <el-col :span="12" class="mb20">',
1212
1217
  ` <el-form-item label="${label}" prop="${prop}">`,
1213
- ` <el-date-picker type="${pickerType}" placeholder="请选择${label}" v-model="form.${prop}" :value-format="${formatName}" style="width: 100%"></el-date-picker>`,
1218
+ ` <el-date-picker type="${pickerType}" placeholder="璇烽€夋嫨${label}" v-model="form.${prop}" :value-format="${formatName}" style="width: 100%"></el-date-picker>`,
1214
1219
  ' </el-form-item>',
1215
1220
  ' </el-col>',
1216
1221
  ].join('\n');
@@ -1220,7 +1225,7 @@ function renderFormField(field) {
1220
1225
  return [
1221
1226
  ' <el-col :span="24" class="mb20">',
1222
1227
  ` <el-form-item label="${label}" prop="${prop}">`,
1223
- ` <el-input type="textarea" v-model="form.${prop}" placeholder="请输入${label}" />`,
1228
+ ` <el-input type="textarea" v-model="form.${prop}" placeholder="璇疯緭鍏?{label}" />`,
1224
1229
  ' </el-form-item>',
1225
1230
  ' </el-col>',
1226
1231
  ].join('\n');
@@ -1229,7 +1234,7 @@ function renderFormField(field) {
1229
1234
  return [
1230
1235
  ' <el-col :span="12" class="mb20">',
1231
1236
  ` <el-form-item label="${label}" prop="${prop}">`,
1232
- ` <el-input v-model="form.${prop}" placeholder="请输入${label}" />`,
1237
+ ` <el-input v-model="form.${prop}" placeholder="璇疯緭鍏?{label}" />`,
1233
1238
  ' </el-form-item>',
1234
1239
  ' </el-col>',
1235
1240
  ].join('\n');
@@ -1256,12 +1261,12 @@ function renderChildTableColumn(field, childListName) {
1256
1261
  let control = ` <el-input v-model="row.${field.attrName}" />`;
1257
1262
  if (field.formType === 'select' && field.dictType) {
1258
1263
  control = [
1259
- ` <el-select v-model="row.${field.attrName}" placeholder="请选择${label}" style="width: 100%">`,
1264
+ ` <el-select v-model="row.${field.attrName}" placeholder="璇烽€夋嫨${label}" style="width: 100%">`,
1260
1265
  ` <el-option v-for="item in ${field.dictType}" :key="item.value" :label="item.label" :value="Number(item.value)" />`,
1261
1266
  ' </el-select>',
1262
1267
  ].join('\n');
1263
1268
  } else if (field.formType === 'number') {
1264
- const max = field.comment.includes('%') || field.comment.includes('比例') ? ' :max="100"' : '';
1269
+ const max = field.comment.includes('%') || field.comment.includes('姣斾緥') ? ' :max="100"' : '';
1265
1270
  const precision = field.sqlType === 'DECIMAL' && field.scale ? ` :precision="${field.scale}" :step="0.01"` : '';
1266
1271
  control = ` <el-input-number v-model="row.${field.attrName}" :min="0"${max}${precision} style="width: 100%" />`;
1267
1272
  }
@@ -1325,7 +1330,7 @@ function renderChildSection(childModel, childCount) {
1325
1330
  return [
1326
1331
  ' <el-col :span="24" class="mb20">',
1327
1332
  ` <div class="mb10" style="font-weight: 600;">${title}</div>`,
1328
- ` <sc-form-table v-model="form.${childModel.listName}" :addTemplate="childTemp${childModel.className}" @delete="(obj) => ${deleteExpression}" placeholder="暂无数据">`,
1333
+ ` <sc-form-table v-model="form.${childModel.listName}" :addTemplate="childTemp${childModel.className}" @delete="(obj) => ${deleteExpression}" :placeholder="t('common.noData')">`,
1329
1334
  childModel.visibleFields.map((field) => renderChildTableColumn(field, childModel.listName)).join('\n'),
1330
1335
  ' </sc-form-table>',
1331
1336
  ' </el-col>',
@@ -1414,7 +1419,7 @@ function renderFormFieldV2(field) {
1414
1419
  }
1415
1420
 
1416
1421
  if (field.formType === 'number') {
1417
- const max = field.comment.includes('%') || field.comment.includes('姣斾緥') ? ' :max="100"' : '';
1422
+ const max = field.comment.includes('%') || field.comment.includes('濮f柧绶?) ? ' :max="100"' : '';
1418
1423
  const precision = field.sqlType === 'DECIMAL' && field.scale ? ` :precision="${field.scale}" :step="0.01"` : '';
1419
1424
  return [
1420
1425
  ` <el-col v-if="${visibilityExpr}" :span="12" class="mb20">`,
@@ -1485,7 +1490,7 @@ function renderChildTableColumnV2(field, childListName) {
1485
1490
  ' </el-select>',
1486
1491
  ].join('\n');
1487
1492
  } else if (field.formType === 'number') {
1488
- const max = field.comment.includes('%') || field.comment.includes('姣斾緥') ? ' :max="100"' : '';
1493
+ const max = field.comment.includes('%') || field.comment.includes('濮f柧绶?) ? ' :max="100"' : '';
1489
1494
  const precision = field.sqlType === 'DECIMAL' && field.scale ? ` :precision="${field.scale}" :step="0.01"` : '';
1490
1495
  control = ` <el-input-number v-model="row.${field.attrName}" :min="0"${max}${precision} style="width: 100%" />`;
1491
1496
  } else if (field.formType === 'datetime' || field.formType === 'date') {
@@ -1516,7 +1521,7 @@ function renderChildSectionV2(childModel, childCount) {
1516
1521
  return [
1517
1522
  ' <el-col :span="24" class="mb20">',
1518
1523
  ` <div class="mb10" style="font-weight: 600;">{{ childSectionTitle('${childModel.listName}') }}</div>`,
1519
- ` <sc-form-table v-model="form.${childModel.listName}" :addTemplate="childTemp${childModel.className}" @delete="(obj) => ${deleteExpression}" placeholder="鏆傛棤鏁版嵁">`,
1524
+ ` <sc-form-table v-model="form.${childModel.listName}" :addTemplate="childTemp${childModel.className}" @delete="(obj) => ${deleteExpression}" :placeholder="t('common.noData')">`,
1520
1525
  childModel.visibleFields.map((field) => renderChildTableColumnV2(field, childModel.listName)).join('\n'),
1521
1526
  ' </sc-form-table>',
1522
1527
  ' </el-col>',
@@ -1526,7 +1531,7 @@ function renderChildSectionV2(childModel, childCount) {
1526
1531
  function renderValidationRule(field) {
1527
1532
  if (!field.notNull) return null;
1528
1533
  const label = stripDictAnnotation(field.comment).replace(/'/g, "\\'");
1529
- return ` ${field.attrName}: [{ required: true, message: '${label}不能为空', trigger: 'blur' }],`;
1534
+ return ` ${field.attrName}: [{ required: true, message: '${label}涓嶈兘涓虹┖', trigger: 'blur' }],`;
1530
1535
  }
1531
1536
 
1532
1537
  function renderFormRules(visibleFields) {
@@ -1810,3 +1815,4 @@ function start() {
1810
1815
  }
1811
1816
 
1812
1817
  start();
1818
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worsoft-frontend-codegen-local-mcp",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Worsoft frontend local-template code generation MCP server.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "worsoft <sw@worsoft.vip>",