worsoft-frontend-codegen-local-mcp 0.1.41 → 0.1.43

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/README.md CHANGED
@@ -104,6 +104,7 @@ Node:
104
104
  ```bash
105
105
  node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario single
106
106
  node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario single_dialog
107
+ node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario dict_single
107
108
  node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario master
108
109
  node plugins/worsoft-codegen-local/smoke_test_mcp.js --scenario dict_multi
109
110
  ```
@@ -30,7 +30,7 @@
30
30
 
31
31
  <script setup lang="ts" name="{{CLASS_NAME}}Form">
32
32
  import mittBus from '/@/utils/mitt';
33
- import { Local } from '/@/utils/storage';
33
+ import { Session } from '/@/utils/storage';
34
34
  import { useMessage } from '/@/hooks/message';
35
35
  import { getObj, addObj, putObj } from '/@/api/{{API_MODULE_PATH}}';
36
36
  import { useDict } from '/@/hooks/dict';
@@ -38,4 +38,6 @@ export function putObj(obj?: object) {
38
38
  method: 'put',
39
39
  data: obj,
40
40
  });
41
- }
41
+ }
42
+
43
+ {{DICT_API_FUNCTIONS}}
@@ -16,7 +16,7 @@
16
16
 
17
17
  <script setup lang="ts" name="{{CLASS_NAME}}Dialog">
18
18
  import { useMessage } from '/@/hooks/message';
19
- import { Local } from '/@/utils/storage';
19
+ import { Session } from '/@/utils/storage';
20
20
  import { getObj, addObj, putObj } from '/@/api/{{API_MODULE_PATH}}';
21
21
  import { useDict } from '/@/hooks/dict';
22
22
  import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
@@ -17,15 +17,14 @@
17
17
  <SchemaListTable
18
18
  v-bind="tableProps"
19
19
  row-id-key="{{PK_ATTR}}"
20
- :action-column-width="180"
20
+ :action-column-width="{{ACTION_COLUMN_WIDTH}}"
21
21
  @selection-change="handleTableSelectionChange"
22
22
  @sort-change="handleTableSortChange"
23
23
  @size-change="handleTableSizeChange"
24
24
  @current-change="handleTableCurrentChange"
25
25
  >
26
26
  <template #actions="{ row }">
27
- <el-button icon="edit-pen" text type="primary" v-auth="'{{PERMISSION_PREFIX}}_edit'" @click="formDialogRef.openDialog(row.{{PK_ATTR}})">{{ t('common.editBtn') }}</el-button>
28
- <el-button icon="delete" text type="primary" v-auth="'{{PERMISSION_PREFIX}}_del'" @click="handleDelete([row.{{PK_ATTR}}])">{{ t('common.delBtn') }}</el-button>
27
+ {{LIST_ACTIONS}}
29
28
  </template>
30
29
  </SchemaListTable>
31
30
  </div>
@@ -36,7 +35,7 @@
36
35
  </template>
37
36
 
38
37
  <script setup lang="ts" name="system{{CLASS_NAME}}">
39
- import { fetchList, delObjs } from '/@/api/{{API_MODULE_PATH}}';
38
+ import { fetchList, delObjs{{DICT_API_IMPORTS}} } from '/@/api/{{API_MODULE_PATH}}';
40
39
  import { useMessage, useMessageBox } from '/@/hooks/message';
41
40
  import { useDict } from '/@/hooks/dict';
42
41
  import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
@@ -102,6 +101,8 @@ const tableProps = computed(() => ({
102
101
  tableStyle,
103
102
  }));
104
103
 
104
+ {{DICT_LIST_HELPERS}}
105
+
105
106
  const exportExcel = () => {
106
107
  runExportExcel(selectObjs.value);
107
108
  };
@@ -27,7 +27,7 @@
27
27
 
28
28
  <script setup lang="ts" name="{{CLASS_NAME}}Form">
29
29
  import mittBus from '/@/utils/mitt';
30
- import { Local } from '/@/utils/storage';
30
+ import { Session } from '/@/utils/storage';
31
31
  import { useMessage } from '/@/hooks/message';
32
32
  import { getObj, addObj, putObj } from '/@/api/{{API_MODULE_PATH}}';
33
33
  import { useDict } from '/@/hooks/dict';
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.41';
8
+ const SERVER_VERSION = '0.1.43';
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');
@@ -1483,22 +1483,23 @@ function buildChildModels(safeArgs, mainFields, mainPk) {
1483
1483
  });
1484
1484
  }
1485
1485
 
1486
- function buildModel(safeArgs) {
1487
- if (safeArgs.style === 'multi_level_dict') {
1488
- return buildMultiLevelDictModel(safeArgs);
1489
- }
1490
-
1491
- const pkField = findPrimaryKeyFromStructuredFields(safeArgs.fields);
1492
- const fields = normalizeFields({
1493
- fields: safeArgs.fields,
1494
- });
1495
- const optionFields = fields.filter((field) => field.fieldName !== pkField.fieldName && !field.isAudit);
1496
- const visibleFields = optionFields.filter((field) => field.show !== false);
1497
- const listFields = optionFields.filter((field) => field.listShow !== false);
1498
- const gridFields = listFields.slice(0, 8);
1499
- const children = buildChildModels(safeArgs, fields, pkField);
1500
- const childDictTypes = children.flatMap((child) => child.optionFields.map((field) => field.dictType).filter(Boolean));
1501
- const dictTypes = [...new Set([...optionFields.map((field) => field.dictType).filter(Boolean), ...childDictTypes])];
1486
+ function buildModel(safeArgs) {
1487
+ if (safeArgs.style === 'multi_level_dict') {
1488
+ return buildMultiLevelDictModel(safeArgs);
1489
+ }
1490
+
1491
+ const pkField = findPrimaryKeyFromStructuredFields(safeArgs.fields);
1492
+ const fields = normalizeFields({
1493
+ fields: safeArgs.fields,
1494
+ });
1495
+ const optionFields = fields.filter((field) => field.fieldName !== pkField.fieldName && !field.isAudit);
1496
+ const visibleFields = optionFields.filter((field) => field.show !== false);
1497
+ const listFields = optionFields.filter((field) => field.listShow !== false);
1498
+ const gridFields = listFields.slice(0, 8);
1499
+ const statusField = detectStatusField(fields, safeArgs.statusField);
1500
+ const children = buildChildModels(safeArgs, fields, pkField);
1501
+ const childDictTypes = children.flatMap((child) => child.optionFields.map((field) => field.dictType).filter(Boolean));
1502
+ const dictTypes = [...new Set([...optionFields.map((field) => field.dictType).filter(Boolean), ...childDictTypes])];
1502
1503
 
1503
1504
  const derivedFunctionName = toCamelCase(safeArgs.tableName);
1504
1505
  const apiPath = safeArgs.apiPath || derivedFunctionName;
@@ -1525,14 +1526,16 @@ function buildModel(safeArgs) {
1525
1526
  pk: pkField,
1526
1527
  fields,
1527
1528
  optionFields,
1528
- visibleFields,
1529
- listFields,
1530
- gridFields,
1531
- dictTypes,
1532
- frontendPath: normalizeFrontendRootPath(safeArgs.frontendPath),
1533
- style: safeArgs.style,
1534
- children,
1535
- };
1529
+ visibleFields,
1530
+ listFields,
1531
+ gridFields,
1532
+ statusField: statusField ? statusField.fieldName : '',
1533
+ statusDictType: statusField ? statusField.dictType || '' : '',
1534
+ dictTypes,
1535
+ frontendPath: normalizeFrontendRootPath(safeArgs.frontendPath),
1536
+ style: safeArgs.style,
1537
+ children,
1538
+ };
1536
1539
  }
1537
1540
 
1538
1541
  function renderTemplate(templateText, replacements) {
@@ -1674,7 +1677,7 @@ function renderFormDefaults(model) {
1674
1677
  const lines = [` ${model.pk.attrName}: '',`];
1675
1678
  for (const field of model.fields.filter((item) => item.fieldName !== model.pk.fieldName && !item.isAudit)) lines.push(renderDefaultLine(field));
1676
1679
  lines.push(` version: 1,`);
1677
- lines.push(` tenantId: Local.getTenant(),`);
1680
+ lines.push(` tenantId: Session.getTenant(),`);
1678
1681
  return lines.join('\n');
1679
1682
  }
1680
1683
 
@@ -2174,7 +2177,7 @@ function renderMultiLevelFormVue(model, moduleModel) {
2174
2177
  ` ${moduleModel.pk.attrName}: '',`,
2175
2178
  ...moduleModel.optionFields.map((field) => renderDefaultLine(field)),
2176
2179
  ` version: 1,`,
2177
- ` tenantId: Local.getTenant(),`,
2180
+ ` tenantId: Session.getTenant(),`,
2178
2181
  ].join('\n');
2179
2182
  const rules = renderFormRulesV2(moduleModel.visibleFields);
2180
2183
  return `<template>
@@ -2195,7 +2198,7 @@ ${moduleModel.visibleFields.map(renderMultiLevelFormField).join('\n')}
2195
2198
 
2196
2199
  <script setup lang="ts" name="${componentName}">
2197
2200
  import { useMessage } from '/@/hooks/message';
2198
- import { Local } from '/@/utils/storage';
2201
+ import { Session } from '/@/utils/storage';
2199
2202
  import { useDict } from '/@/hooks/dict';
2200
2203
  import { useCrudPageMeta } from '/@/hooks/useCrudPageMeta';
2201
2204
  import { useI18n } from 'vue-i18n';
@@ -2377,36 +2380,62 @@ const handleCurrentChange = (row: any) => {
2377
2380
  `;
2378
2381
  }
2379
2382
 
2380
- function renderMultiLevelLevelSlot(levelVarName, activeKeyVarName, activeModuleVarName) {
2381
- return [
2382
- ` <div class="multi-level-slot" v-if="${levelVarName}">`,
2383
- ' <el-tabs class="multi-level-tabs" v-if="' + `${levelVarName}.moduleKeys.length > 1` + `" v-model="${activeKeyVarName}">`,
2384
- ` <el-tab-pane v-for="moduleKey in ${levelVarName}.moduleKeys" :key="moduleKey" :label="resolveModuleTitle(moduleConfigs[moduleKey])" :name="moduleKey" />`,
2385
- ' </el-tabs>',
2386
- ' <div class="multi-level-panel" v-if="' + `${activeModuleVarName}` + `">`,
2387
- ` <LevelPanel`,
2388
- ` :columns="getListFields(${activeModuleVarName}.key)"`,
2389
- ` :dict-types="${activeModuleVarName}.dictTypes"`,
2390
- ` :data-list="moduleStateMap[${activeModuleVarName}.key].dataList"`,
2391
- ` :loading="moduleStateMap[${activeModuleVarName}.key].loading"`,
2392
- ` :add-disabled="isAddDisabled(${activeModuleVarName}.key)"`,
2393
- ` :status-field="${activeModuleVarName}.statusField"`,
2394
- ` :current-page="moduleStateMap[${activeModuleVarName}.key].currentPage"`,
2395
- ` :page-size="moduleStateMap[${activeModuleVarName}.key].pageSize"`,
2396
- ` :total="moduleStateMap[${activeModuleVarName}.key].total"`,
2397
- ` @add="openCreate(${activeModuleVarName}.key)"`,
2398
- ` @edit="openEdit(${activeModuleVarName}.key, $event)"`,
2399
- ` @delete="handleDelete(${activeModuleVarName}.key, $event)"`,
2400
- ` @enable="handleEnable(${activeModuleVarName}.key, $event)"`,
2401
- ` @disable="handleDisable(${activeModuleVarName}.key, $event)"`,
2402
- ` @current-change="handleCurrentPageChange(${activeModuleVarName}.key, $event)"`,
2403
- ` @size-change="handlePageSizeChange(${activeModuleVarName}.key, $event)"`,
2404
- ` @select-row="handleSelectRow(${activeModuleVarName}.key, $event)"`,
2405
- ' />',
2406
- ' </div>',
2407
- ` </div>`,
2408
- ].join('\n');
2409
- }
2383
+ function renderMultiLevelLevelSlot(levelVarName, activeKeyVarName, activeModuleVarName) {
2384
+ return [
2385
+ ` <div class="multi-level-slot" v-if="${levelVarName}">`,
2386
+ ' <el-tabs class="multi-level-tabs" v-if="' + `${levelVarName}.moduleKeys.length > 1` + `" v-model="${activeKeyVarName}">`,
2387
+ ` <el-tab-pane v-for="moduleKey in ${levelVarName}.moduleKeys" :key="moduleKey" :label="resolveModuleTitle(moduleConfigs[moduleKey])" :name="moduleKey" />`,
2388
+ ' </el-tabs>',
2389
+ ' <div class="multi-level-panel" v-if="' + `${activeModuleVarName}` + `">`,
2390
+ ' <div class="layout-padding-auto layout-padding-view flex h-full flex-col">',
2391
+ ' <div class="mb8" style="width: 100%">',
2392
+ ` <el-button icon="folder-add" type="primary" class="ml10" :disabled="isAddDisabled(${activeModuleVarName}.key)" @click="openCreate(${activeModuleVarName}.key)">{{ t('common.addBtn') }}</el-button>`,
2393
+ ' </div>',
2394
+ ' <el-table',
2395
+ ` :data="moduleStateMap[${activeModuleVarName}.key].dataList"`,
2396
+ ` v-loading="moduleStateMap[${activeModuleVarName}.key].loading"`,
2397
+ ' border',
2398
+ ' height="100%"',
2399
+ ' highlight-current-row',
2400
+ ` @current-change="handlePanelCurrentChange(${activeModuleVarName}.key, $event)"`,
2401
+ ' >',
2402
+ ` <el-table-column type="index" :label="t('common.serial')" width="60" />`,
2403
+ ` <el-table-column`,
2404
+ ` v-for="column in getListFields(${activeModuleVarName}.key)"`,
2405
+ ' :key="column.key"',
2406
+ ' :prop="column.key"',
2407
+ ` :label="resolveLabel(column.labelKey, column.key || '')"`,
2408
+ ` :min-width="column.width || '120'"`,
2409
+ ' show-overflow-tooltip',
2410
+ ' >',
2411
+ ' <template #default="scope">',
2412
+ ' <dict-tag v-if="column.dictType" :options="getDictOptions(column.dictType)" :value="scope.row[column.key]" />',
2413
+ ' <span v-else>{{ scope.row[column.key] }}</span>',
2414
+ ' </template>',
2415
+ ' </el-table-column>',
2416
+ ` <el-table-column :label="t('common.action')" width="260">`,
2417
+ ' <template #default="{ row }">',
2418
+ ` <el-button v-if="showModuleAction(${activeModuleVarName}.key, 'edit', row)" icon="edit-pen" text type="primary" @click="openEdit(${activeModuleVarName}.key, row)">{{ t('common.editBtn') }}</el-button>`,
2419
+ ` <el-button v-if="showModuleAction(${activeModuleVarName}.key, 'delete', row)" icon="delete" text type="primary" @click="handleDelete(${activeModuleVarName}.key, row)">{{ t('common.delBtn') }}</el-button>`,
2420
+ ` <el-button v-if="showModuleAction(${activeModuleVarName}.key, 'enable', row)" icon="circle-check" text type="primary" @click="handleEnable(${activeModuleVarName}.key, row)">启用</el-button>`,
2421
+ ` <el-button v-if="showModuleAction(${activeModuleVarName}.key, 'disable', row)" icon="remove" text type="primary" @click="handleDisable(${activeModuleVarName}.key, row)">禁用</el-button>`,
2422
+ ' </template>',
2423
+ ' </el-table-column>',
2424
+ ' </el-table>',
2425
+ ' <div class="mt-2.5 flex shrink-0 justify-end">',
2426
+ ' <pagination',
2427
+ ` :current-page="moduleStateMap[${activeModuleVarName}.key].currentPage"`,
2428
+ ` :page-size="moduleStateMap[${activeModuleVarName}.key].pageSize"`,
2429
+ ` :total="moduleStateMap[${activeModuleVarName}.key].total"`,
2430
+ ` @current-change="handleCurrentPageChange(${activeModuleVarName}.key, $event)"`,
2431
+ ` @size-change="handlePageSizeChange(${activeModuleVarName}.key, $event)"`,
2432
+ ' />',
2433
+ ' </div>',
2434
+ ' </div>',
2435
+ ' </div>',
2436
+ ` </div>`,
2437
+ ].join('\n');
2438
+ }
2410
2439
 
2411
2440
  function renderMultiLevelIndexVue(model) {
2412
2441
  const level2 = model.levels.find((level) => level.levelIndex === 2);
@@ -2463,14 +2492,14 @@ ${formComponents}
2463
2492
  </div>
2464
2493
  </template>
2465
2494
 
2466
- <script setup lang="ts" name="system${model.className}">
2467
- import { useMessage, useMessageBox } from '/@/hooks/message';
2468
- import { useMultiLevelDictMeta } from '/@/hooks/useMultiLevelDictMeta';
2469
- import { useMultiLevelDictPage } from '/@/hooks/useMultiLevelDictPage';
2470
- import { useI18n } from 'vue-i18n';
2471
- import LevelPanel from '/@/components/DictLevelPanel/index.vue';
2472
- import { levelConfigs, moduleConfigs } from './options';
2473
- import { ${apiImports} } from '/@/api/${model.moduleName}/${model.functionName}';
2495
+ <script setup lang="ts" name="system${model.className}">
2496
+ import { useMessage, useMessageBox } from '/@/hooks/message';
2497
+ import { useDict } from '/@/hooks/dict';
2498
+ import { useMultiLevelDictMeta } from '/@/hooks/useMultiLevelDictMeta';
2499
+ import { useMultiLevelDictPage } from '/@/hooks/useMultiLevelDictPage';
2500
+ import { useI18n } from 'vue-i18n';
2501
+ import { allDictTypes, levelConfigs, moduleConfigs } from './options';
2502
+ import { ${apiImports} } from '/@/api/${model.moduleName}/${model.functionName}';
2474
2503
 
2475
2504
  ${asyncImports}
2476
2505
 
@@ -2478,10 +2507,11 @@ ${formRefs}
2478
2507
  ${formRefMap}
2479
2508
  ${apiHandlerMap}
2480
2509
 
2481
- const { t } = useI18n();
2482
-
2483
- const {
2484
- level1Config,
2510
+ const { t } = useI18n();
2511
+ const dictRefs = useDict(...allDictTypes);
2512
+
2513
+ const {
2514
+ level1Config,
2485
2515
  level2Config,
2486
2516
  level3Config,
2487
2517
  activeLevel1Key,
@@ -2497,12 +2527,25 @@ const resolveLabel = (labelKey?: string, fallback = '') => {
2497
2527
  if (!labelKey) return fallback;
2498
2528
  const translated = t(labelKey);
2499
2529
  return translated === labelKey ? fallback : translated;
2500
- };
2501
-
2502
- const resolveModuleTitle = (moduleConfig: any) => resolveLabel(moduleConfig?.titleKey, moduleConfig?.key || '');
2503
-
2504
- const {
2505
- moduleStateMap,
2530
+ };
2531
+
2532
+ const resolveModuleTitle = (moduleConfig: any) => resolveLabel(moduleConfig?.titleKey, moduleConfig?.key || '');
2533
+ const getDictOptions = (dictType?: string) => (dictType ? dictRefs[dictType]?.value || [] : []);
2534
+ const isStatusEnabled = (value: any) => ['1', 1, true, 'true', 'enable', 'enabled'].includes(value);
2535
+ const isStatusNew = (value: any) => ['0', 0, false, 'false', 'new', '新增'].includes(value);
2536
+ const isStatusNewOrDisabled = (value: any) => ['0', 0, false, 'false', 'new', '新增', '2', '禁用', 'disabled'].includes(value);
2537
+ const showModuleAction = (moduleKey: string, action: 'edit' | 'delete' | 'enable' | 'disable', row: any): boolean => {
2538
+ const moduleConfig = moduleConfigs[moduleKey];
2539
+ const statusValue = moduleConfig?.statusField ? row?.[moduleConfig.statusField] : undefined;
2540
+ if (action === 'edit') return statusValue === undefined || isStatusNewOrDisabled(statusValue);
2541
+ if (action === 'delete') return statusValue === undefined || isStatusNew(statusValue);
2542
+ if (action === 'enable') return !!moduleConfig?.statusField && isStatusNewOrDisabled(statusValue);
2543
+ if (action === 'disable') return !!moduleConfig?.statusField && isStatusEnabled(statusValue);
2544
+ return false;
2545
+ };
2546
+
2547
+ const {
2548
+ moduleStateMap,
2506
2549
  getParentIdForModule,
2507
2550
  getListFields,
2508
2551
  isAddDisabled,
@@ -2528,12 +2571,16 @@ const openCreate = (moduleKey: string) => {
2528
2571
  formRefMap[moduleKey]?.value?.openDialog(undefined, getParentIdForModule(moduleKey));
2529
2572
  };
2530
2573
 
2531
- const openEdit = (moduleKey: string, row: any) => {
2532
- const primaryKey = moduleConfigs[moduleKey].primaryKey;
2533
- formRefMap[moduleKey]?.value?.openDialog(row?.[primaryKey], getParentIdForModule(moduleKey));
2534
- };
2535
-
2536
- const handleDelete = async (moduleKey: string, row: any) => {
2574
+ const openEdit = (moduleKey: string, row: any) => {
2575
+ const primaryKey = moduleConfigs[moduleKey].primaryKey;
2576
+ formRefMap[moduleKey]?.value?.openDialog(row?.[primaryKey], getParentIdForModule(moduleKey));
2577
+ };
2578
+
2579
+ const handlePanelCurrentChange = (moduleKey: string, row: any) => {
2580
+ if (row) handleSelectRow(moduleKey, row);
2581
+ };
2582
+
2583
+ const handleDelete = async (moduleKey: string, row: any) => {
2537
2584
  try {
2538
2585
  await useMessageBox().confirm(t('common.delConfirmText'));
2539
2586
  } catch {
@@ -2584,10 +2631,10 @@ function renderMultiLevelMenuSql(model) {
2584
2631
  ].join('\n');
2585
2632
  }
2586
2633
 
2587
- function renderMultiLevelFiles(model, sharedSupport, localeZhSupport) {
2588
- const dictRegistryRefs = sharedSupport.dictRegistry.keyByValue;
2589
- const viewRoot = buildViewRoot(model);
2590
- const apiFilePath = buildApiFilePath(model);
2634
+ function renderMultiLevelFiles(model, sharedSupport, localeZhSupport) {
2635
+ const dictRegistryRefs = sharedSupport.dictRegistry.keyByValue;
2636
+ const viewRoot = buildViewRoot(model);
2637
+ const apiFilePath = buildApiFilePath(model);
2591
2638
  const menuRoot = path.join(model.frontendPath, 'menu');
2592
2639
  const files = [
2593
2640
  { type: 'list', path: path.join(viewRoot, 'index.vue'), content: renderMultiLevelIndexVue(model) },
@@ -2610,15 +2657,90 @@ function renderMultiLevelFiles(model, sharedSupport, localeZhSupport) {
2610
2657
  content: renderMultiLevelFormVue(model, moduleModel),
2611
2658
  });
2612
2659
  });
2613
-
2614
- return files;
2615
- }
2616
-
2617
- function buildReplacements(model, sharedSupport) {
2618
- const menuBaseId = Date.now();
2619
- const apiModulePath = model.targetApiModule || `${model.moduleName}/${model.functionName}`;
2620
- const apiRoutePath = buildApiRoutePath(model.moduleName, model.apiPath || model.functionName).replace(/^\/+/, '');
2621
- const routePath = `${model.moduleName}/${model.functionName}`;
2660
+
2661
+ return files;
2662
+ }
2663
+
2664
+ function renderSingleTableDialogActions(model, permissionPrefix) {
2665
+ const pkAttr = model.pk.attrName;
2666
+ const isDictWithStatus = model.pageType === 'dict' && model.statusField;
2667
+ const lines = [
2668
+ ` <el-button${isDictWithStatus ? ` v-if="showDictAction('edit', row)"` : ''} icon="edit-pen" text type="primary" v-auth="'${permissionPrefix}_edit'" @click="formDialogRef.openDialog(row.${pkAttr})">{{ t('common.editBtn') }}</el-button>`,
2669
+ ` <el-button${isDictWithStatus ? ` v-if="showDictAction('delete', row)"` : ''} icon="delete" text type="primary" v-auth="'${permissionPrefix}_del'" @click="handleDelete([row.${pkAttr}])">{{ t('common.delBtn') }}</el-button>`,
2670
+ ];
2671
+ if (isDictWithStatus) {
2672
+ lines.push(` <el-button v-if="showDictAction('enable', row)" icon="circle-check" text type="primary" @click="handleEnable(row.${pkAttr})">启用</el-button>`);
2673
+ lines.push(` <el-button v-if="showDictAction('disable', row)" icon="remove" text type="primary" @click="handleDisable(row.${pkAttr})">禁用</el-button>`);
2674
+ }
2675
+ return lines.join('\n');
2676
+ }
2677
+
2678
+ function renderSingleTableDialogDictHelpers(model) {
2679
+ if (model.pageType !== 'dict' || !model.statusField) return '';
2680
+ const statusField = model.statusField;
2681
+ return [
2682
+ "const isStatusEnabled = (value: any) => ['1', 1, true, 'true', 'enable', 'enabled'].includes(value);",
2683
+ "const isStatusNew = (value: any) => ['0', 0, false, 'false', 'new', '新增'].includes(value);",
2684
+ "const isStatusNewOrDisabled = (value: any) => ['0', 0, false, 'false', 'new', '新增', '2', '禁用', 'disabled'].includes(value);",
2685
+ '',
2686
+ "const showDictAction = (action: 'edit' | 'delete' | 'enable' | 'disable', row: any): boolean => {",
2687
+ ` const status = row?.${statusField};`,
2688
+ " if (action === 'edit') return isStatusNewOrDisabled(status);",
2689
+ " if (action === 'delete') return isStatusNew(status);",
2690
+ " if (action === 'enable') return isStatusNewOrDisabled(status);",
2691
+ " if (action === 'disable') return isStatusEnabled(status);",
2692
+ ' return false;',
2693
+ '};',
2694
+ '',
2695
+ 'const handleEnable = async (id: string | number) => {',
2696
+ ' try {',
2697
+ ' await enableObj(id);',
2698
+ ' getDataList();',
2699
+ " useMessage().success(t('common.messages.enableSuccess'));",
2700
+ ' } catch (err: any) {',
2701
+ " useMessage().error(err.msg || t('common.messages.enableError'));",
2702
+ ' }',
2703
+ '};',
2704
+ '',
2705
+ 'const handleDisable = async (id: string | number) => {',
2706
+ ' try {',
2707
+ ' await disableObj(id);',
2708
+ ' getDataList();',
2709
+ " useMessage().success(t('common.messages.disableSuccess'));",
2710
+ ' } catch (err: any) {',
2711
+ " useMessage().error(err.msg || t('common.messages.disableError'));",
2712
+ ' }',
2713
+ '};',
2714
+ ].join('\n');
2715
+ }
2716
+
2717
+ function renderSingleTableDialogDictApiFunctions(model) {
2718
+ if (model.pageType !== 'dict' || !model.statusField) return '';
2719
+ const apiRoutePath = buildApiRoutePath(model.moduleName, model.apiPath || model.functionName).replace(/^\/+/, '');
2720
+ return [
2721
+ "export function enableObj(id: string | number) {",
2722
+ ' return request({',
2723
+ ` url: '/${apiRoutePath}/enable',`,
2724
+ " method: 'post',",
2725
+ ' params: { id },',
2726
+ ' });',
2727
+ '}',
2728
+ '',
2729
+ "export function disableObj(id: string | number) {",
2730
+ ' return request({',
2731
+ ` url: '/${apiRoutePath}/disable',`,
2732
+ " method: 'post',",
2733
+ ' params: { id },',
2734
+ ' });',
2735
+ '}',
2736
+ ].join('\n');
2737
+ }
2738
+
2739
+ function buildReplacements(model, sharedSupport) {
2740
+ const menuBaseId = Date.now();
2741
+ const apiModulePath = model.targetApiModule || `${model.moduleName}/${model.functionName}`;
2742
+ const apiRoutePath = buildApiRoutePath(model.moduleName, model.apiPath || model.functionName).replace(/^\/+/, '');
2743
+ const routePath = `${model.moduleName}/${model.functionName}`;
2622
2744
  const permissionPrefix = `${model.moduleName}/${model.functionName}`.replace(/\//g, '_');
2623
2745
  const dictRegistryRefs = sharedSupport.dictRegistry.keyByValue;
2624
2746
  const i18nNamespace = buildI18nNamespace(model);
@@ -2633,12 +2755,17 @@ function buildReplacements(model, sharedSupport) {
2633
2755
  API_MODULE_PATH: apiModulePath,
2634
2756
  API_PATH: apiRoutePath,
2635
2757
  VIEW_MODULE_PATH: routePath,
2636
- MENU_ROUTE_PATH: routePath,
2637
- I18N_NAMESPACE: i18nNamespace,
2638
- PERMISSION_PREFIX: permissionPrefix,
2639
- MENU_BASE_ID: menuBaseId,
2640
- MENU_BASE_ID_PLUS_1: menuBaseId + 1,
2641
- MENU_BASE_ID_PLUS_2: menuBaseId + 2,
2758
+ MENU_ROUTE_PATH: routePath,
2759
+ I18N_NAMESPACE: i18nNamespace,
2760
+ PERMISSION_PREFIX: permissionPrefix,
2761
+ ACTION_COLUMN_WIDTH: model.pageType === 'dict' && model.statusField ? 300 : 180,
2762
+ LIST_ACTIONS: renderSingleTableDialogActions(model, permissionPrefix),
2763
+ DICT_API_IMPORTS: model.pageType === 'dict' && model.statusField ? ', enableObj, disableObj' : '',
2764
+ DICT_LIST_HELPERS: renderSingleTableDialogDictHelpers(model),
2765
+ DICT_API_FUNCTIONS: renderSingleTableDialogDictApiFunctions(model),
2766
+ MENU_BASE_ID: menuBaseId,
2767
+ MENU_BASE_ID_PLUS_1: menuBaseId + 1,
2768
+ MENU_BASE_ID_PLUS_2: menuBaseId + 2,
2642
2769
  MENU_BASE_ID_PLUS_3: menuBaseId + 3,
2643
2770
  MENU_BASE_ID_PLUS_4: menuBaseId + 4,
2644
2771
  MENU_BASE_ID_PLUS_5: menuBaseId + 5,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worsoft-frontend-codegen-local-mcp",
3
- "version": "0.1.41",
3
+ "version": "0.1.43",
4
4
  "description": "Worsoft frontend local-template code generation MCP server.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "worsoft <sw@worsoft.vip>",