worsoft-frontend-codegen-local-mcp 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mcp_server.js +102 -62
- package/package.json +1 -1
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.23';
|
|
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');
|
|
@@ -234,12 +234,33 @@ function toPascalCase(value) {
|
|
|
234
234
|
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
function normalizeModuleName(moduleName) {
|
|
238
|
-
if (!moduleName) {
|
|
239
|
-
return 'admin/test';
|
|
240
|
-
}
|
|
241
|
-
return moduleName.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
|
242
|
-
}
|
|
237
|
+
function normalizeModuleName(moduleName) {
|
|
238
|
+
if (!moduleName) {
|
|
239
|
+
return 'admin/test';
|
|
240
|
+
}
|
|
241
|
+
return moduleName.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function normalizeModulePathForFeature(moduleName, functionName, apiPath) {
|
|
245
|
+
const normalized = normalizeModuleName(moduleName);
|
|
246
|
+
const segments = normalized.split('/').filter(Boolean);
|
|
247
|
+
if (segments.length <= 1) {
|
|
248
|
+
return normalized;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const duplicateNames = new Set(
|
|
252
|
+
[functionName, apiPath]
|
|
253
|
+
.filter(Boolean)
|
|
254
|
+
.map((item) => String(item).trim())
|
|
255
|
+
.filter(Boolean)
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
while (segments.length > 1 && duplicateNames.has(segments[segments.length - 1])) {
|
|
259
|
+
segments.pop();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return segments.join('/');
|
|
263
|
+
}
|
|
243
264
|
|
|
244
265
|
function toConstantCase(value) {
|
|
245
266
|
return String(value || '')
|
|
@@ -917,14 +938,16 @@ function buildModel(safeArgs) {
|
|
|
917
938
|
const childDictTypes = children.flatMap((child) => child.visibleFields.map((field) => field.dictType).filter(Boolean));
|
|
918
939
|
const dictTypes = [...new Set([...visibleFields.map((field) => field.dictType).filter(Boolean), ...childDictTypes])];
|
|
919
940
|
|
|
941
|
+
const functionName = toCamelCase(safeArgs.tableName);
|
|
942
|
+
const apiPath = safeArgs.apiPath || functionName;
|
|
920
943
|
return {
|
|
921
944
|
featureTitle: safeArgs.featureTitle || safeArgs.tableComment || safeArgs.tableName,
|
|
922
945
|
tableName: safeArgs.tableName,
|
|
923
946
|
tableComment: safeArgs.tableComment || safeArgs.featureTitle || safeArgs.tableName,
|
|
924
|
-
apiPath
|
|
947
|
+
apiPath,
|
|
925
948
|
className: toPascalCase(safeArgs.tableName),
|
|
926
|
-
functionName
|
|
927
|
-
moduleName:
|
|
949
|
+
functionName,
|
|
950
|
+
moduleName: normalizeModulePathForFeature(safeArgs.moduleName, functionName, apiPath),
|
|
928
951
|
pk: pkField,
|
|
929
952
|
fields,
|
|
930
953
|
visibleFields,
|
|
@@ -1226,21 +1249,32 @@ function renderTextareaMaxlengthAttrsV2(field) {
|
|
|
1226
1249
|
if (!field.length) return '';
|
|
1227
1250
|
return ` :maxlength="${field.length}" show-word-limit`;
|
|
1228
1251
|
}
|
|
1229
|
-
|
|
1252
|
+
|
|
1253
|
+
function renderDisabledAttrV2(field) {
|
|
1254
|
+
return field.readonly ? ' disabled' : '';
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
function renderFieldCommentV2(field, indent = ' ') {
|
|
1258
|
+
const label = stripDictAnnotation(field.comment || field.attrName).replace(/-->/g, '').trim() || field.attrName;
|
|
1259
|
+
return `${indent}<!-- 字段:${label} -->`;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1230
1262
|
function renderFormFieldV2(field) {
|
|
1231
1263
|
const prop = field.attrName;
|
|
1232
1264
|
const labelExpr = `getMasterFieldLabel('${prop}')`;
|
|
1233
1265
|
const dictExpr = `getMasterFieldMeta('${prop}')?.dictType`;
|
|
1266
|
+
const disabledAttr = renderDisabledAttrV2(field);
|
|
1234
1267
|
|
|
1235
1268
|
if (field.formType === 'select') {
|
|
1236
1269
|
return [
|
|
1270
|
+
renderFieldCommentV2(field),
|
|
1237
1271
|
` <el-col :span="12" class="mb20">`,
|
|
1238
1272
|
` <el-form-item :label="${labelExpr}" prop="${prop}">`,
|
|
1239
|
-
` <el-select v-model="form.${prop}" :placeholder="selectPlaceholder(${labelExpr})" style="width: 100%">`,
|
|
1273
|
+
` <el-select v-model="form.${prop}" :placeholder="selectPlaceholder(${labelExpr})" style="width: 100%"${disabledAttr}>`,
|
|
1240
1274
|
` <el-option v-for="item in getDictOptions(${dictExpr})" :key="item.value" :label="item.label" :value="Number(item.value)" />`,
|
|
1241
|
-
' </el-select>',
|
|
1242
|
-
' </el-form-item>',
|
|
1243
|
-
' </el-col>',
|
|
1275
|
+
' </el-select>',
|
|
1276
|
+
' </el-form-item>',
|
|
1277
|
+
' </el-col>',
|
|
1244
1278
|
].join('\n');
|
|
1245
1279
|
}
|
|
1246
1280
|
|
|
@@ -1248,46 +1282,50 @@ function renderFormFieldV2(field) {
|
|
|
1248
1282
|
const max = field.comment.includes('%') || /\u6BD4\u4F8B/.test(field.comment) ? ' :max="100"' : '';
|
|
1249
1283
|
const precision = field.sqlType === 'DECIMAL' && field.scale ? ` :precision="${field.scale}" :step="0.01"` : '';
|
|
1250
1284
|
return [
|
|
1285
|
+
renderFieldCommentV2(field),
|
|
1251
1286
|
` <el-col :span="12" class="mb20">`,
|
|
1252
1287
|
` <el-form-item :label="${labelExpr}" prop="${prop}">`,
|
|
1253
|
-
` <el-input-number v-model="form.${prop}" :min="0"${max}${precision} :placeholder="inputPlaceholder(${labelExpr})" style="width: 100%" />`,
|
|
1288
|
+
` <el-input-number v-model="form.${prop}" :min="0"${max}${precision} :placeholder="inputPlaceholder(${labelExpr})" style="width: 100%"${disabledAttr} />`,
|
|
1254
1289
|
' </el-form-item>',
|
|
1255
|
-
' </el-col>',
|
|
1256
|
-
].join('\n');
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1290
|
+
' </el-col>',
|
|
1291
|
+
].join('\n');
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1259
1294
|
if (field.formType === 'datetime' || field.formType === 'date') {
|
|
1260
1295
|
const pickerType = field.formType === 'datetime' ? 'datetime' : 'date';
|
|
1261
1296
|
const formatName = field.formType === 'datetime' ? 'dateTimeStr' : 'dateStr';
|
|
1262
1297
|
return [
|
|
1298
|
+
renderFieldCommentV2(field),
|
|
1263
1299
|
` <el-col :span="12" class="mb20">`,
|
|
1264
1300
|
` <el-form-item :label="${labelExpr}" prop="${prop}">`,
|
|
1265
|
-
` <el-date-picker type="${pickerType}" :placeholder="inputPlaceholder(${labelExpr})" v-model="form.${prop}" :value-format="${formatName}" style="width: 100%"></el-date-picker>`,
|
|
1301
|
+
` <el-date-picker type="${pickerType}" :placeholder="inputPlaceholder(${labelExpr})" v-model="form.${prop}" :value-format="${formatName}" style="width: 100%"${disabledAttr}></el-date-picker>`,
|
|
1266
1302
|
' </el-form-item>',
|
|
1267
|
-
' </el-col>',
|
|
1268
|
-
].join('\n');
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1303
|
+
' </el-col>',
|
|
1304
|
+
].join('\n');
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1271
1307
|
if (field.formType === 'textarea') {
|
|
1272
1308
|
const textareaAttrs = renderTextareaMaxlengthAttrsV2(field);
|
|
1273
1309
|
return [
|
|
1310
|
+
renderFieldCommentV2(field),
|
|
1274
1311
|
` <el-col :span="24" class="mb20">`,
|
|
1275
1312
|
` <el-form-item :label="${labelExpr}" prop="${prop}">`,
|
|
1276
|
-
` <el-input type="textarea" v-model="form.${prop}" :placeholder="inputPlaceholder(${labelExpr})"${textareaAttrs} />`,
|
|
1313
|
+
` <el-input type="textarea" v-model="form.${prop}" :placeholder="inputPlaceholder(${labelExpr})"${textareaAttrs}${disabledAttr} />`,
|
|
1277
1314
|
' </el-form-item>',
|
|
1278
|
-
' </el-col>',
|
|
1279
|
-
].join('\n');
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1315
|
+
' </el-col>',
|
|
1316
|
+
].join('\n');
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1282
1319
|
const maxlengthAttr = renderInputMaxlengthAttr(field);
|
|
1283
1320
|
return [
|
|
1321
|
+
renderFieldCommentV2(field),
|
|
1284
1322
|
` <el-col :span="12" class="mb20">`,
|
|
1285
1323
|
` <el-form-item :label="${labelExpr}" prop="${prop}">`,
|
|
1286
|
-
` <el-input v-model="form.${prop}" :placeholder="inputPlaceholder(${labelExpr})"${maxlengthAttr} />`,
|
|
1324
|
+
` <el-input v-model="form.${prop}" :placeholder="inputPlaceholder(${labelExpr})"${maxlengthAttr}${disabledAttr} />`,
|
|
1287
1325
|
' </el-form-item>',
|
|
1288
|
-
' </el-col>',
|
|
1289
|
-
].join('\n');
|
|
1290
|
-
}
|
|
1326
|
+
' </el-col>',
|
|
1327
|
+
].join('\n');
|
|
1328
|
+
}
|
|
1291
1329
|
|
|
1292
1330
|
function renderTableColumnV2(field, dictRegistryRefs) {
|
|
1293
1331
|
const label = stripDictAnnotation(field.comment).replace(/'/g, "\\'");
|
|
@@ -1305,34 +1343,36 @@ function renderTableColumnV2(field, dictRegistryRefs) {
|
|
|
1305
1343
|
return ` { ${parts.join(', ')} },`;
|
|
1306
1344
|
}
|
|
1307
1345
|
|
|
1308
|
-
function renderChildTableColumnV2(field, childListName) {
|
|
1309
|
-
const rules = field.notNull ? ` :rules="[{ required: true, trigger: 'blur' }]"` : '';
|
|
1310
|
-
const labelExpr = `getChildFieldLabel('${childListName}', '${field.attrName}')`;
|
|
1311
|
-
const dictExpr = `getChildFieldMeta('${childListName}', '${field.attrName}')?.dictType`;
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
`
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
const
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
`
|
|
1346
|
+
function renderChildTableColumnV2(field, childListName) {
|
|
1347
|
+
const rules = field.notNull ? ` :rules="[{ required: true, trigger: 'blur' }]"` : '';
|
|
1348
|
+
const labelExpr = `getChildFieldLabel('${childListName}', '${field.attrName}')`;
|
|
1349
|
+
const dictExpr = `getChildFieldMeta('${childListName}', '${field.attrName}')?.dictType`;
|
|
1350
|
+
const disabledAttr = renderDisabledAttrV2(field);
|
|
1351
|
+
|
|
1352
|
+
let control = ` <el-input v-model="row.${field.attrName}" :placeholder="inputPlaceholder(${labelExpr})"${renderTextMaxlengthAttrV2(field)}${disabledAttr} />`;
|
|
1353
|
+
if (field.formType === 'select' && field.dictType) {
|
|
1354
|
+
control = [
|
|
1355
|
+
` <el-select v-model="row.${field.attrName}" :placeholder="selectPlaceholder(${labelExpr})" style="width: 100%"${disabledAttr}>`,
|
|
1356
|
+
` <el-option v-for="item in getDictOptions(${dictExpr})" :key="item.value" :label="item.label" :value="Number(item.value)" />`,
|
|
1357
|
+
' </el-select>',
|
|
1358
|
+
].join('\n');
|
|
1359
|
+
} else if (field.formType === 'number') {
|
|
1360
|
+
const max = field.comment.includes('%') || /\u6BD4\u4F8B/.test(field.comment) ? ' :max="100"' : '';
|
|
1361
|
+
const precision = field.sqlType === 'DECIMAL' && field.scale ? ` :precision="${field.scale}" :step="0.01"` : '';
|
|
1362
|
+
control = ` <el-input-number v-model="row.${field.attrName}" :min="0"${max}${precision} style="width: 100%"${disabledAttr} />`;
|
|
1363
|
+
} else if (field.formType === 'datetime' || field.formType === 'date') {
|
|
1364
|
+
const pickerType = field.formType === 'datetime' ? 'datetime' : 'date';
|
|
1365
|
+
const formatName = field.formType === 'datetime' ? 'dateTimeStr' : 'dateStr';
|
|
1366
|
+
control = ` <el-date-picker type="${pickerType}" v-model="row.${field.attrName}" :value-format="${formatName}" :placeholder="inputPlaceholder(${labelExpr})" style="width: 100%"${disabledAttr}></el-date-picker>`;
|
|
1367
|
+
} else if (field.formType === 'textarea') {
|
|
1368
|
+
control = ` <el-input type="textarea" v-model="row.${field.attrName}" :placeholder="inputPlaceholder(${labelExpr})"${renderTextareaMaxlengthAttrsV2(field)}${disabledAttr} />`;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
return [
|
|
1372
|
+
renderFieldCommentV2(field, ' '),
|
|
1373
|
+
` <el-table-column :label="${labelExpr}" prop="${field.attrName}">`,
|
|
1374
|
+
' <template #default="{ row, $index }">',
|
|
1375
|
+
` <el-form-item :prop="\`${childListName}.\${$index}.${field.attrName}\`"${rules}>`,
|
|
1336
1376
|
control,
|
|
1337
1377
|
' </el-form-item>',
|
|
1338
1378
|
' </template>',
|
package/package.json
CHANGED