@es-plus/cli 1.0.0
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/LICENSE +21 -0
- package/README.md +421 -0
- package/build/commands/create.d.ts +3 -0
- package/build/commands/create.d.ts.map +1 -0
- package/build/commands/create.js +79 -0
- package/build/commands/create.js.map +1 -0
- package/build/commands/scaffold.d.ts +3 -0
- package/build/commands/scaffold.d.ts.map +1 -0
- package/build/commands/scaffold.js +29 -0
- package/build/commands/scaffold.js.map +1 -0
- package/build/commands/validate.d.ts +3 -0
- package/build/commands/validate.d.ts.map +1 -0
- package/build/commands/validate.js +57 -0
- package/build/commands/validate.js.map +1 -0
- package/build/core/code-generator.d.ts +9 -0
- package/build/core/code-generator.d.ts.map +1 -0
- package/build/core/code-generator.js +87 -0
- package/build/core/code-generator.js.map +1 -0
- package/build/core/constants.d.ts +61 -0
- package/build/core/constants.d.ts.map +1 -0
- package/build/core/constants.js +51 -0
- package/build/core/constants.js.map +1 -0
- package/build/core/crud-engine.d.ts +12 -0
- package/build/core/crud-engine.d.ts.map +1 -0
- package/build/core/crud-engine.js +405 -0
- package/build/core/crud-engine.js.map +1 -0
- package/build/core/schema-validator.d.ts +9 -0
- package/build/core/schema-validator.d.ts.map +1 -0
- package/build/core/schema-validator.js +83 -0
- package/build/core/schema-validator.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +16 -0
- package/build/index.js.map +1 -0
- package/package.json +57 -0
- package/schemas/api-params.schema.json +36 -0
- package/schemas/btn-config.schema.json +77 -0
- package/schemas/dialog-options.schema.json +149 -0
- package/schemas/form-item.schema.json +146 -0
- package/schemas/index.schema.json +71 -0
- package/schemas/table-column.schema.json +118 -0
- package/schemas/table-options.schema.json +141 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { generateCrudConfig, generateCode } from "./crud-engine.js";
|
|
2
|
+
export function generateCrudPage(description) {
|
|
3
|
+
const config = generateCrudConfig(description);
|
|
4
|
+
const code = generateCode(config);
|
|
5
|
+
const summary = [
|
|
6
|
+
`Generated CRUD page with:`,
|
|
7
|
+
`- ${config.formItems.length} query form fields`,
|
|
8
|
+
`- ${config.columns.length} table columns`,
|
|
9
|
+
`- Actions: ${config.actions.join(", ")}`,
|
|
10
|
+
config.dialogFormItems?.length
|
|
11
|
+
? `- ${config.dialogFormItems.length} dialog form fields (with validation rules)`
|
|
12
|
+
: "",
|
|
13
|
+
config.hasStatusRender ? `- Status column with ElTag render` : "",
|
|
14
|
+
config.actions.includes("delete") ? `- Delete confirmation dialog` : "",
|
|
15
|
+
]
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.join("\n");
|
|
18
|
+
return { code, config, summary };
|
|
19
|
+
}
|
|
20
|
+
export function generateScaffold(name, features) {
|
|
21
|
+
const componentName = name.charAt(0).toUpperCase() + name.slice(1).replace(/-(\w)/g, (_, c) => c.toUpperCase());
|
|
22
|
+
const hasQuery = !features || features.includes("query");
|
|
23
|
+
const hasTable = !features || features.includes("table");
|
|
24
|
+
const hasDialog = features?.includes("dialog");
|
|
25
|
+
const lines = [];
|
|
26
|
+
lines.push(`<template>`);
|
|
27
|
+
lines.push(` <div class="${name}-page">`);
|
|
28
|
+
if (hasTable) {
|
|
29
|
+
lines.push(` <es-table`);
|
|
30
|
+
lines.push(` ref="tableRef"`);
|
|
31
|
+
lines.push(` :columns="columns"`);
|
|
32
|
+
lines.push(` :options="options"`);
|
|
33
|
+
lines.push(` v-model:data-source="tableData"`);
|
|
34
|
+
lines.push(` v-model:pagination="pagination"`);
|
|
35
|
+
lines.push(` >`);
|
|
36
|
+
if (hasQuery) {
|
|
37
|
+
lines.push(` <es-form :model="queryForm" :form-item-list="formItems" :config-btn="queryBtns" />`);
|
|
38
|
+
}
|
|
39
|
+
lines.push(` </es-table>`);
|
|
40
|
+
}
|
|
41
|
+
else if (hasQuery) {
|
|
42
|
+
lines.push(` <es-form :model="queryForm" :form-item-list="formItems" :config-btn="queryBtns" />`);
|
|
43
|
+
}
|
|
44
|
+
lines.push(` </div>`);
|
|
45
|
+
lines.push(`</template>`);
|
|
46
|
+
lines.push(``);
|
|
47
|
+
lines.push(`<script setup>`);
|
|
48
|
+
lines.push(`import { reactive, ref } from 'vue'`);
|
|
49
|
+
if (hasDialog) {
|
|
50
|
+
lines.push(`import { useDialog } from 'es-plus-ui'`);
|
|
51
|
+
}
|
|
52
|
+
lines.push(``);
|
|
53
|
+
if (hasQuery) {
|
|
54
|
+
lines.push(`const queryForm = reactive({})`);
|
|
55
|
+
lines.push(`const formItems = []`);
|
|
56
|
+
lines.push(`const queryBtns = [`);
|
|
57
|
+
lines.push(` { name: '查询', type: 'primary', key: 'query', triggerEvent: true },`);
|
|
58
|
+
lines.push(` { name: '重置', key: 'rest', triggerEvent: true },`);
|
|
59
|
+
lines.push(`]`);
|
|
60
|
+
lines.push(``);
|
|
61
|
+
}
|
|
62
|
+
if (hasTable) {
|
|
63
|
+
lines.push(`const tableRef = ref(null)`);
|
|
64
|
+
lines.push(`const tableData = ref([])`);
|
|
65
|
+
lines.push(`const pagination = ref({ current: 1, pageSize: 10, total: 0 })`);
|
|
66
|
+
lines.push(`const columns = []`);
|
|
67
|
+
lines.push(`const options = {`);
|
|
68
|
+
lines.push(` border: true,`);
|
|
69
|
+
lines.push(` stripe: true,`);
|
|
70
|
+
lines.push(` highlightCurrentRow: true,`);
|
|
71
|
+
lines.push(` headerCellStyle: { background: '#f5f7fa' },`);
|
|
72
|
+
lines.push(` httpRequest: async (params) => {`);
|
|
73
|
+
lines.push(` // TODO: 替换为实际接口调用`);
|
|
74
|
+
lines.push(` },`);
|
|
75
|
+
lines.push(` configTableOut: { total: 'total', tableData: 'data', pageSize: 'pageSize', current: 'pageIndex' },`);
|
|
76
|
+
lines.push(` rowkey: 'id'`);
|
|
77
|
+
lines.push(`}`);
|
|
78
|
+
lines.push(``);
|
|
79
|
+
}
|
|
80
|
+
if (hasDialog) {
|
|
81
|
+
lines.push(`const dialog = useDialog()`);
|
|
82
|
+
lines.push(``);
|
|
83
|
+
}
|
|
84
|
+
lines.push(`</script>`);
|
|
85
|
+
return lines.join("\n");
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=code-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-generator.js","sourceRoot":"","sources":["../../src/core/code-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export declare const FORM_TYPES: readonly [{
|
|
2
|
+
readonly type: "Input";
|
|
3
|
+
readonly description: "输入框 — 文本/数字/密码输入";
|
|
4
|
+
readonly example: "姓名、手机号、邮箱";
|
|
5
|
+
}, {
|
|
6
|
+
readonly type: "Select";
|
|
7
|
+
readonly description: "下拉选择器 — 单选/多选";
|
|
8
|
+
readonly example: "状态、类型、分类";
|
|
9
|
+
}, {
|
|
10
|
+
readonly type: "datePicker";
|
|
11
|
+
readonly description: "日期选择器 — 日期/日期范围";
|
|
12
|
+
readonly example: "创建时间、日期范围";
|
|
13
|
+
}, {
|
|
14
|
+
readonly type: "timePicker";
|
|
15
|
+
readonly description: "时间选择器 — 时间/时间范围";
|
|
16
|
+
readonly example: "开始时间、结束时间";
|
|
17
|
+
}, {
|
|
18
|
+
readonly type: "Slider";
|
|
19
|
+
readonly description: "滑块 — 数值区间选择";
|
|
20
|
+
readonly example: "价格区间、进度";
|
|
21
|
+
}, {
|
|
22
|
+
readonly type: "ColorPicker";
|
|
23
|
+
readonly description: "颜色选择器";
|
|
24
|
+
readonly example: "主题色、标签颜色";
|
|
25
|
+
}, {
|
|
26
|
+
readonly type: "Transfer";
|
|
27
|
+
readonly description: "穿梭框 — 左右列表选择";
|
|
28
|
+
readonly example: "权限分配、人员分配";
|
|
29
|
+
}, {
|
|
30
|
+
readonly type: "Cascader";
|
|
31
|
+
readonly description: "级联选择器 — 多级联动";
|
|
32
|
+
readonly example: "省市区、部门层级";
|
|
33
|
+
}, {
|
|
34
|
+
readonly type: "Radio";
|
|
35
|
+
readonly description: "单选框组";
|
|
36
|
+
readonly example: "性别、是否启用";
|
|
37
|
+
}, {
|
|
38
|
+
readonly type: "Checkbox";
|
|
39
|
+
readonly description: "多选框组";
|
|
40
|
+
readonly example: "兴趣爱好、功能模块";
|
|
41
|
+
}, {
|
|
42
|
+
readonly type: "Switch";
|
|
43
|
+
readonly description: "开关 — 布尔切换";
|
|
44
|
+
readonly example: "启用/禁用、显示/隐藏";
|
|
45
|
+
}, {
|
|
46
|
+
readonly type: "Rate";
|
|
47
|
+
readonly description: "评分 — 星级评分";
|
|
48
|
+
readonly example: "满意度、评分";
|
|
49
|
+
}, {
|
|
50
|
+
readonly type: "Upload";
|
|
51
|
+
readonly description: "上传 — 文件/图片上传";
|
|
52
|
+
readonly example: "头像、附件、证件照";
|
|
53
|
+
}];
|
|
54
|
+
export type FormType = typeof FORM_TYPES[number]['type'];
|
|
55
|
+
export declare const COMPONENT_LIST: readonly ["EsForm", "EsTable", "useDialog"];
|
|
56
|
+
export type ComponentName = typeof COMPONENT_LIST[number];
|
|
57
|
+
export declare const PRESET_EXAMPLES: {
|
|
58
|
+
label: string;
|
|
59
|
+
prompt: string;
|
|
60
|
+
}[];
|
|
61
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcb,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,cAAc,6CAA8C,CAAC;AAC1E,MAAM,MAAM,aAAa,GAAG,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,eAAe;;;GAiC3B,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const FORM_TYPES = [
|
|
2
|
+
{ type: 'Input', description: '输入框 — 文本/数字/密码输入', example: '姓名、手机号、邮箱' },
|
|
3
|
+
{ type: 'Select', description: '下拉选择器 — 单选/多选', example: '状态、类型、分类' },
|
|
4
|
+
{ type: 'datePicker', description: '日期选择器 — 日期/日期范围', example: '创建时间、日期范围' },
|
|
5
|
+
{ type: 'timePicker', description: '时间选择器 — 时间/时间范围', example: '开始时间、结束时间' },
|
|
6
|
+
{ type: 'Slider', description: '滑块 — 数值区间选择', example: '价格区间、进度' },
|
|
7
|
+
{ type: 'ColorPicker', description: '颜色选择器', example: '主题色、标签颜色' },
|
|
8
|
+
{ type: 'Transfer', description: '穿梭框 — 左右列表选择', example: '权限分配、人员分配' },
|
|
9
|
+
{ type: 'Cascader', description: '级联选择器 — 多级联动', example: '省市区、部门层级' },
|
|
10
|
+
{ type: 'Radio', description: '单选框组', example: '性别、是否启用' },
|
|
11
|
+
{ type: 'Checkbox', description: '多选框组', example: '兴趣爱好、功能模块' },
|
|
12
|
+
{ type: 'Switch', description: '开关 — 布尔切换', example: '启用/禁用、显示/隐藏' },
|
|
13
|
+
{ type: 'Rate', description: '评分 — 星级评分', example: '满意度、评分' },
|
|
14
|
+
{ type: 'Upload', description: '上传 — 文件/图片上传', example: '头像、附件、证件照' },
|
|
15
|
+
];
|
|
16
|
+
export const COMPONENT_LIST = ['EsForm', 'EsTable', 'useDialog'];
|
|
17
|
+
export const PRESET_EXAMPLES = [
|
|
18
|
+
{
|
|
19
|
+
label: '用户管理',
|
|
20
|
+
prompt: '用户管理页面,查询条件有姓名、手机号、状态,表格显示姓名、手机号、邮箱、状态、创建时间,支持新增编辑删除'
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
label: '订单列表',
|
|
24
|
+
prompt: '订单列表,查询订单号、客户名称、日期范围、状态,表格显示订单号、客户、金额、状态、创建时间,支持查看详情和删除'
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: '商品管理',
|
|
28
|
+
prompt: '商品管理,查询商品名称、分类、状态,表格显示名称、分类、价格、库存、状态,支持新增编辑删除'
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
label: '日志查询',
|
|
32
|
+
prompt: '操作日志查询,查询关键词、级别、日期范围,表格显示时间、级别、操作人、内容,只查看不编辑'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
label: '角色权限',
|
|
36
|
+
prompt: '角色管理页面,查询角色名称、状态,表格显示角色名称、描述、状态、创建时间,支持新增编辑删除'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
label: '员工花名册',
|
|
40
|
+
prompt: '员工管理,查询姓名、部门、职位,表格显示姓名、性别、年龄、部门、职位、手机号、状态,支持新增编辑'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: '文章管理',
|
|
44
|
+
prompt: '文章管理,查询标题、分类、状态,表格显示标题、分类、创建人、创建时间、状态,支持新增编辑删除'
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: '系统配置',
|
|
48
|
+
prompt: '系统配置管理,查询名称、类型,表格显示名称、编号、类型、描述、状态,支持新增编辑删除导出'
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/core/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,EAAE,WAAW,EAAE;IACxE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,UAAU,EAAE;IACrE,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,OAAO,EAAE,WAAW,EAAE;IAC5E,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,OAAO,EAAE,WAAW,EAAE;IAC5E,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE;IAClE,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE;IAClE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE;IACvE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE;IACtE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE;IAC1D,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE;IAC/D,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE;IACpE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE;IAC7D,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE;CAC7D,CAAC;AAIX,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAU,CAAC;AAG1E,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B;QACE,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,sDAAsD;KAC/D;IACD;QACE,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,yDAAyD;KAClE;IACD;QACE,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,+CAA+C;KACxD;IACD;QACE,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,8CAA8C;KACvD;IACD;QACE,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,+CAA+C;KACxD;IACD;QACE,KAAK,EAAE,OAAO;QACd,MAAM,EAAE,kDAAkD;KAC3D;IACD;QACE,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,gDAAgD;KACzD;IACD;QACE,KAAK,EAAE,MAAM;QACb,MAAM,EAAE,8CAA8C;KACvD;CACF,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface GeneratedConfig {
|
|
2
|
+
formItems: any[];
|
|
3
|
+
columns: any[];
|
|
4
|
+
queryBtns: any[];
|
|
5
|
+
tableOptions: any;
|
|
6
|
+
actions: string[];
|
|
7
|
+
dialogFormItems?: any[];
|
|
8
|
+
hasStatusRender?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function generateCrudConfig(input: string): GeneratedConfig;
|
|
11
|
+
export declare function generateCode(config: GeneratedConfig): string;
|
|
12
|
+
//# sourceMappingURL=crud-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud-engine.d.ts","sourceRoot":"","sources":["../../src/core/crud-engine.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,GAAG,EAAE,CAAA;IAChB,OAAO,EAAE,GAAG,EAAE,CAAA;IACd,SAAS,EAAE,GAAG,EAAE,CAAA;IAChB,YAAY,EAAE,GAAG,CAAA;IACjB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,eAAe,CAAC,EAAE,GAAG,EAAE,CAAA;IACvB,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AA+KD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAgGjE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAuK5D"}
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
const TYPE_RULES = [
|
|
2
|
+
{ keywords: ['状态', 'status', '类型', 'type', '分类', 'category', '级别', 'level', '来源', 'source'], type: 'Select' },
|
|
3
|
+
{ keywords: ['日期', 'date', '创建时间', 'createTime', '更新时间', 'updateTime', '开始日期', '结束日期'], type: 'datePicker', attrs: { type: 'daterange', valueFormat: 'YYYY-MM-DD' } },
|
|
4
|
+
{ keywords: ['时间', 'time', '时刻', 'timerange', 'timepicker'], type: 'timePicker', attrs: { type: 'timerange' } },
|
|
5
|
+
{ keywords: ['开关', 'switch', '是否', '启用', 'enable', 'disabled'], type: 'Switch' },
|
|
6
|
+
{ keywords: ['评分', 'rate', '星级', 'score'], type: 'Rate' },
|
|
7
|
+
{ keywords: ['颜色', 'color'], type: 'ColorPicker' },
|
|
8
|
+
{ keywords: ['图片', 'image', '头像', 'avatar', '文件', 'file', '附件', 'attachment'], type: 'Upload' },
|
|
9
|
+
{ keywords: ['备注', 'remark', '描述', 'description', '内容', 'content', '简介', 'intro'], type: 'Input', attrs: { type: 'textarea', rows: 3 } },
|
|
10
|
+
{ keywords: ['性别', 'gender', '单选', 'radio'], type: 'Radio' },
|
|
11
|
+
{ keywords: ['多选', 'checkbox', '兴趣', '爱好', '标签', 'tags'], type: 'Checkbox' },
|
|
12
|
+
{ keywords: ['省市', '城市', '地区', 'cascader', '层级', '区域'], type: 'Cascader' },
|
|
13
|
+
{ keywords: ['进度', 'slider', '区间', '范围'], type: 'Slider' },
|
|
14
|
+
{ keywords: ['穿梭', 'transfer', '分配'], type: 'Transfer' },
|
|
15
|
+
];
|
|
16
|
+
const FIELD_PROP_MAP = {
|
|
17
|
+
'姓名': 'name', '名称': 'name', '用户名': 'username',
|
|
18
|
+
'手机号': 'phone', '电话': 'phone', '手机': 'phone',
|
|
19
|
+
'邮箱': 'email', '邮件': 'email',
|
|
20
|
+
'状态': 'status', '地址': 'address',
|
|
21
|
+
'订单号': 'orderNo', '编号': 'code',
|
|
22
|
+
'金额': 'amount', '价格': 'price',
|
|
23
|
+
'日期': 'date', '时间': 'time',
|
|
24
|
+
'创建时间': 'createTime', '更新时间': 'updateTime',
|
|
25
|
+
'开始时间': 'startTime', '结束时间': 'endTime',
|
|
26
|
+
'分类': 'category', '类型': 'type',
|
|
27
|
+
'标题': 'title', '关键词': 'keyword',
|
|
28
|
+
'客户': 'customer', '客户名称': 'customerName',
|
|
29
|
+
'年龄': 'age', '性别': 'gender',
|
|
30
|
+
'部门': 'department', '职位': 'position',
|
|
31
|
+
'角色': 'role', '权限': 'permission',
|
|
32
|
+
'商品': 'product', '商品名称': 'productName',
|
|
33
|
+
'数量': 'quantity', '库存': 'stock',
|
|
34
|
+
'级别': 'level', '来源': 'source',
|
|
35
|
+
'备注': 'remark', '描述': 'description',
|
|
36
|
+
'公司': 'company', '项目': 'project', '品牌': 'brand',
|
|
37
|
+
'账号': 'account', '昵称': 'nickname',
|
|
38
|
+
'创建人': 'creator', '操作人': 'operator',
|
|
39
|
+
'内容': 'content', '简介': 'intro',
|
|
40
|
+
'头像': 'avatar', '图片': 'image',
|
|
41
|
+
'排序': 'sort', '序号': 'sortNo',
|
|
42
|
+
'标签': 'tags', '评分': 'score',
|
|
43
|
+
};
|
|
44
|
+
const STATUS_OPTIONS = [
|
|
45
|
+
{ label: '启用', value: 1 },
|
|
46
|
+
{ label: '禁用', value: 0 }
|
|
47
|
+
];
|
|
48
|
+
const TYPE_OPTIONS = [
|
|
49
|
+
{ label: '类型A', value: 'A' },
|
|
50
|
+
{ label: '类型B', value: 'B' },
|
|
51
|
+
{ label: '类型C', value: 'C' }
|
|
52
|
+
];
|
|
53
|
+
function inferType(fieldName) {
|
|
54
|
+
for (const rule of TYPE_RULES) {
|
|
55
|
+
if (rule.keywords.some(kw => fieldName.toLowerCase().includes(kw.toLowerCase()))) {
|
|
56
|
+
return { type: rule.type, attrs: rule.attrs };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return { type: 'Input' };
|
|
60
|
+
}
|
|
61
|
+
function toProp(fieldName) {
|
|
62
|
+
if (FIELD_PROP_MAP[fieldName])
|
|
63
|
+
return FIELD_PROP_MAP[fieldName];
|
|
64
|
+
if (/^[a-zA-Z_$]/.test(fieldName))
|
|
65
|
+
return fieldName;
|
|
66
|
+
const pinyin = fieldName.replace(/[一-鿿]/g, '');
|
|
67
|
+
return pinyin || `field_${Math.random().toString(36).slice(2, 6)}`;
|
|
68
|
+
}
|
|
69
|
+
function getDataOptions(fieldName) {
|
|
70
|
+
if (/状态|启用|禁用/.test(fieldName))
|
|
71
|
+
return STATUS_OPTIONS;
|
|
72
|
+
if (/类型|分类|级别|来源/.test(fieldName))
|
|
73
|
+
return TYPE_OPTIONS;
|
|
74
|
+
if (/性别/.test(fieldName))
|
|
75
|
+
return [{ label: '男', value: 'male' }, { label: '女', value: 'female' }];
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
function parseFields(input) {
|
|
79
|
+
const fields = [];
|
|
80
|
+
const queryMatch = input.match(/查询[::条件字段有]*([一-龥a-zA-Z、,,\s]+?)(?=[,,。.;;表格支持操作]|$)/);
|
|
81
|
+
const queryFieldsStr = queryMatch?.[1] || '';
|
|
82
|
+
const queryFieldNames = splitFields(queryFieldsStr);
|
|
83
|
+
const tableMatch = input.match(/表格[::显示展示字段列有]*([一-龥a-zA-Z、,,\s]+?)(?=[,,。.;;支持操作查询]|$)/);
|
|
84
|
+
const tableFieldsStr = tableMatch?.[1] || '';
|
|
85
|
+
const tableFieldNames = splitFields(tableFieldsStr);
|
|
86
|
+
if (!queryMatch && !tableMatch) {
|
|
87
|
+
const allFields = extractAllFields(input);
|
|
88
|
+
allFields.forEach(name => {
|
|
89
|
+
fields.push({
|
|
90
|
+
name,
|
|
91
|
+
prop: toProp(name),
|
|
92
|
+
type: inferType(name).type,
|
|
93
|
+
isQuery: true,
|
|
94
|
+
isTable: true,
|
|
95
|
+
isForm: true,
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
return fields;
|
|
99
|
+
}
|
|
100
|
+
const seen = new Set();
|
|
101
|
+
queryFieldNames.forEach(name => {
|
|
102
|
+
if (seen.has(name))
|
|
103
|
+
return;
|
|
104
|
+
seen.add(name);
|
|
105
|
+
fields.push({ name, prop: toProp(name), type: inferType(name).type, isQuery: true, isTable: true, isForm: true });
|
|
106
|
+
});
|
|
107
|
+
tableFieldNames.forEach(name => {
|
|
108
|
+
if (seen.has(name))
|
|
109
|
+
return;
|
|
110
|
+
seen.add(name);
|
|
111
|
+
fields.push({ name, prop: toProp(name), type: inferType(name).type, isQuery: false, isTable: true, isForm: true });
|
|
112
|
+
});
|
|
113
|
+
return fields;
|
|
114
|
+
}
|
|
115
|
+
function splitFields(str) {
|
|
116
|
+
return str
|
|
117
|
+
.split(/[、,,\s]+/)
|
|
118
|
+
.map(s => s.trim())
|
|
119
|
+
.filter(s => s.length > 0 && s.length < 10);
|
|
120
|
+
}
|
|
121
|
+
function extractAllFields(input) {
|
|
122
|
+
const cleaned = input
|
|
123
|
+
.replace(/^.*?[::]/, '')
|
|
124
|
+
.replace(/[,,]?\s*支持.*$/, '')
|
|
125
|
+
.replace(/[,,]?\s*操作.*$/, '');
|
|
126
|
+
return splitFields(cleaned);
|
|
127
|
+
}
|
|
128
|
+
function parseActions(input) {
|
|
129
|
+
const actionMatch = input.match(/(?:支持|操作[有::]?)\s*(.+?)(?:[。.]|$)/);
|
|
130
|
+
const onlyViewMatch = input.match(/只(?:查看|读|浏览)/);
|
|
131
|
+
if (onlyViewMatch) {
|
|
132
|
+
return ['view'];
|
|
133
|
+
}
|
|
134
|
+
const actionSection = actionMatch?.[1] || '';
|
|
135
|
+
if (!actionSection) {
|
|
136
|
+
return ['add', 'edit', 'delete'];
|
|
137
|
+
}
|
|
138
|
+
const actions = [];
|
|
139
|
+
const text = actionSection;
|
|
140
|
+
if (/新增|添加|创建|add|create/i.test(text))
|
|
141
|
+
actions.push('add');
|
|
142
|
+
if (/编辑|修改|更新|edit|update/i.test(text))
|
|
143
|
+
actions.push('edit');
|
|
144
|
+
if (/删除|移除|remove|delete/i.test(text))
|
|
145
|
+
actions.push('delete');
|
|
146
|
+
if (/查看|详情|detail|view/i.test(text))
|
|
147
|
+
actions.push('view');
|
|
148
|
+
if (/导出|export/i.test(text))
|
|
149
|
+
actions.push('export');
|
|
150
|
+
if (/导入|import/i.test(text))
|
|
151
|
+
actions.push('import');
|
|
152
|
+
return actions.length > 0 ? actions : ['add', 'edit', 'delete'];
|
|
153
|
+
}
|
|
154
|
+
export function generateCrudConfig(input) {
|
|
155
|
+
const fields = parseFields(input);
|
|
156
|
+
const actions = parseActions(input);
|
|
157
|
+
const formItems = fields
|
|
158
|
+
.filter(f => f.isQuery)
|
|
159
|
+
.map(f => {
|
|
160
|
+
const item = {
|
|
161
|
+
prop: f.prop,
|
|
162
|
+
label: f.name,
|
|
163
|
+
formtype: f.type,
|
|
164
|
+
span: 6,
|
|
165
|
+
attrs: { clearable: true },
|
|
166
|
+
};
|
|
167
|
+
const typeInfo = inferType(f.name);
|
|
168
|
+
if (typeInfo.attrs)
|
|
169
|
+
item.attrs = { ...item.attrs, ...typeInfo.attrs };
|
|
170
|
+
const options = getDataOptions(f.name);
|
|
171
|
+
if (options)
|
|
172
|
+
item.dataOptions = options;
|
|
173
|
+
if (f.type === 'datePicker' || f.type === 'timePicker')
|
|
174
|
+
item.span = 8;
|
|
175
|
+
return item;
|
|
176
|
+
});
|
|
177
|
+
const queryBtns = [
|
|
178
|
+
{ name: '查询', type: 'primary', key: 'query', triggerEvent: true },
|
|
179
|
+
{ name: '重置', key: 'rest', triggerEvent: true },
|
|
180
|
+
];
|
|
181
|
+
if (actions.includes('add')) {
|
|
182
|
+
queryBtns.push({ name: '新增', type: 'primary', key: 'add', icon: 'Plus' });
|
|
183
|
+
}
|
|
184
|
+
if (actions.includes('export')) {
|
|
185
|
+
queryBtns.push({ name: '导出', key: 'export', icon: 'Download' });
|
|
186
|
+
}
|
|
187
|
+
if (actions.includes('import')) {
|
|
188
|
+
queryBtns.push({ name: '导入', key: 'import', icon: 'Upload' });
|
|
189
|
+
}
|
|
190
|
+
let hasStatusRender = false;
|
|
191
|
+
const columns = fields
|
|
192
|
+
.filter(f => f.isTable)
|
|
193
|
+
.map(f => {
|
|
194
|
+
const col = { prop: f.prop, label: f.name };
|
|
195
|
+
if (f.name.includes('状态') || f.name.includes('status')) {
|
|
196
|
+
hasStatusRender = true;
|
|
197
|
+
col.render = `(_, { row }) => h(ElTag, { type: row.${f.prop} === 1 ? 'success' : 'danger' }, () => row.${f.prop} === 1 ? '启用' : '禁用')`;
|
|
198
|
+
}
|
|
199
|
+
return col;
|
|
200
|
+
});
|
|
201
|
+
const actionBtns = [];
|
|
202
|
+
if (actions.includes('view'))
|
|
203
|
+
actionBtns.push({ name: '查看', type: 'primary' });
|
|
204
|
+
if (actions.includes('edit'))
|
|
205
|
+
actionBtns.push({ name: '编辑', type: 'primary' });
|
|
206
|
+
if (actions.includes('delete'))
|
|
207
|
+
actionBtns.push({ name: '删除', type: 'danger' });
|
|
208
|
+
if (actionBtns.length > 0) {
|
|
209
|
+
columns.push({
|
|
210
|
+
prop: 'operate',
|
|
211
|
+
label: '操作',
|
|
212
|
+
width: actionBtns.length * 80 + 20,
|
|
213
|
+
btns: actionBtns
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const tableOptions = {
|
|
217
|
+
border: true,
|
|
218
|
+
stripe: true,
|
|
219
|
+
highlightCurrentRow: true,
|
|
220
|
+
headerCellStyle: { background: '#f5f7fa' },
|
|
221
|
+
configTableOut: { total: 'total', tableData: 'data', pageSize: 'pageSize', current: 'pageIndex' },
|
|
222
|
+
rowkey: 'id',
|
|
223
|
+
};
|
|
224
|
+
const dialogFormItems = fields
|
|
225
|
+
.filter(f => f.isForm)
|
|
226
|
+
.map(f => {
|
|
227
|
+
const item = {
|
|
228
|
+
prop: f.prop,
|
|
229
|
+
label: f.name,
|
|
230
|
+
formtype: f.type,
|
|
231
|
+
span: 24,
|
|
232
|
+
attrs: { clearable: true },
|
|
233
|
+
formItemOptions: {
|
|
234
|
+
rules: [{ required: true, message: `请输入${f.name}`, trigger: 'blur' }]
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
const options = getDataOptions(f.name);
|
|
238
|
+
if (options) {
|
|
239
|
+
item.dataOptions = options;
|
|
240
|
+
item.formItemOptions.rules = [{ required: true, message: `请选择${f.name}`, trigger: 'change' }];
|
|
241
|
+
}
|
|
242
|
+
const typeInfo = inferType(f.name);
|
|
243
|
+
if (typeInfo.attrs)
|
|
244
|
+
item.attrs = { ...item.attrs, ...typeInfo.attrs };
|
|
245
|
+
return item;
|
|
246
|
+
});
|
|
247
|
+
return { formItems, columns, queryBtns, tableOptions, actions, dialogFormItems, hasStatusRender };
|
|
248
|
+
}
|
|
249
|
+
export function generateCode(config) {
|
|
250
|
+
const lines = [];
|
|
251
|
+
const hasDialog = config.actions.includes('add') || config.actions.includes('edit') || config.actions.includes('view');
|
|
252
|
+
const hasDelete = config.actions.includes('delete');
|
|
253
|
+
lines.push(`<template>`);
|
|
254
|
+
lines.push(` <es-table`);
|
|
255
|
+
lines.push(` ref="tableRef"`);
|
|
256
|
+
lines.push(` :columns="columns"`);
|
|
257
|
+
lines.push(` :options="options"`);
|
|
258
|
+
lines.push(` v-model:data-source="tableData"`);
|
|
259
|
+
lines.push(` v-model:pagination="pagination"`);
|
|
260
|
+
lines.push(` >`);
|
|
261
|
+
lines.push(` <es-form :model="queryForm" :form-item-list="formItems" :config-btn="queryBtns" />`);
|
|
262
|
+
lines.push(` </es-table>`);
|
|
263
|
+
lines.push(`</template>`);
|
|
264
|
+
lines.push(``);
|
|
265
|
+
lines.push(`<script setup>`);
|
|
266
|
+
// Vue imports
|
|
267
|
+
const vueImports = ['reactive', 'ref'];
|
|
268
|
+
if (config.hasStatusRender)
|
|
269
|
+
vueImports.push('h');
|
|
270
|
+
lines.push(`import { ${vueImports.join(', ')} } from 'vue'`);
|
|
271
|
+
// es-plus-ui imports
|
|
272
|
+
if (hasDialog) {
|
|
273
|
+
lines.push(`import { useDialog } from 'es-plus-ui'`);
|
|
274
|
+
}
|
|
275
|
+
// element-plus imports
|
|
276
|
+
const epImports = [];
|
|
277
|
+
if (config.hasStatusRender)
|
|
278
|
+
epImports.push('ElTag');
|
|
279
|
+
if (hasDelete)
|
|
280
|
+
epImports.push('ElMessageBox', 'ElMessage');
|
|
281
|
+
if (epImports.length > 0) {
|
|
282
|
+
lines.push(`import { ${epImports.join(', ')} } from 'element-plus'`);
|
|
283
|
+
}
|
|
284
|
+
lines.push(``);
|
|
285
|
+
const modelFields = config.formItems.map(f => `${f.prop}: ''`).join(', ');
|
|
286
|
+
lines.push(`const queryForm = reactive({ ${modelFields} })`);
|
|
287
|
+
lines.push(`const tableData = ref([])`);
|
|
288
|
+
lines.push(`const tableRef = ref(null)`);
|
|
289
|
+
lines.push(`const pagination = ref({ current: 1, pageSize: 10, total: 0 })`);
|
|
290
|
+
if (hasDialog) {
|
|
291
|
+
lines.push(`const dialog = useDialog()`);
|
|
292
|
+
}
|
|
293
|
+
lines.push(``);
|
|
294
|
+
lines.push(`const formItems = ${JSON.stringify(config.formItems, null, 2)}`);
|
|
295
|
+
lines.push(``);
|
|
296
|
+
// queryBtns — need to serialize click handlers as code, not JSON
|
|
297
|
+
lines.push(`const queryBtns = [`);
|
|
298
|
+
for (const btn of config.queryBtns) {
|
|
299
|
+
if (btn.key === 'add') {
|
|
300
|
+
lines.push(` { name: '${btn.name}', type: '${btn.type}', key: '${btn.key}', icon: '${btn.icon}', click: () => openForm('新增') },`);
|
|
301
|
+
}
|
|
302
|
+
else if (btn.key === 'export') {
|
|
303
|
+
lines.push(` { name: '${btn.name}', key: '${btn.key}', icon: '${btn.icon}', click: () => { /* TODO: 调用导出接口 */ } },`);
|
|
304
|
+
}
|
|
305
|
+
else if (btn.key === 'import') {
|
|
306
|
+
lines.push(` { name: '${btn.name}', key: '${btn.key}', icon: '${btn.icon}', click: () => { /* TODO: 调用导入接口 */ } },`);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
const parts = [`name: '${btn.name}'`];
|
|
310
|
+
if (btn.type)
|
|
311
|
+
parts.push(`type: '${btn.type}'`);
|
|
312
|
+
parts.push(`key: '${btn.key}'`);
|
|
313
|
+
if (btn.triggerEvent)
|
|
314
|
+
parts.push(`triggerEvent: true`);
|
|
315
|
+
lines.push(` { ${parts.join(', ')} },`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
lines.push(`]`);
|
|
319
|
+
lines.push(``);
|
|
320
|
+
// columns — render functions need to be unquoted
|
|
321
|
+
const colStr = JSON.stringify(config.columns, null, 2)
|
|
322
|
+
.replace(/"render": "(.*?)"/g, (_, code) => `render: ${code.replace(/\\"/g, '"')}`);
|
|
323
|
+
lines.push(`const columns = ${colStr}`);
|
|
324
|
+
lines.push(``);
|
|
325
|
+
// table options
|
|
326
|
+
lines.push(`const options = {`);
|
|
327
|
+
lines.push(` border: true,`);
|
|
328
|
+
lines.push(` stripe: true,`);
|
|
329
|
+
lines.push(` highlightCurrentRow: true,`);
|
|
330
|
+
lines.push(` headerCellStyle: { background: '#f5f7fa' },`);
|
|
331
|
+
lines.push(` httpRequest: async (params) => {`);
|
|
332
|
+
lines.push(` // TODO: 替换为实际接口调用`);
|
|
333
|
+
lines.push(` // const res = await axios.get('/api/list', { params: params.formParams })`);
|
|
334
|
+
lines.push(` // return res.data`);
|
|
335
|
+
lines.push(` },`);
|
|
336
|
+
lines.push(` configTableOut: { total: 'total', tableData: 'data', pageSize: 'pageSize', current: 'pageIndex' },`);
|
|
337
|
+
lines.push(` rowkey: 'id'`);
|
|
338
|
+
lines.push(`}`);
|
|
339
|
+
// delete handler
|
|
340
|
+
if (hasDelete) {
|
|
341
|
+
lines.push(``);
|
|
342
|
+
lines.push(`function handleDelete(row) {`);
|
|
343
|
+
lines.push(` ElMessageBox.confirm('确定删除该条数据吗?', '提示', { type: 'warning' })`);
|
|
344
|
+
lines.push(` .then(async () => {`);
|
|
345
|
+
lines.push(` // TODO: 调用删除接口`);
|
|
346
|
+
lines.push(` // await axios.delete(\`/api/item/\${row.id}\`)`);
|
|
347
|
+
lines.push(` ElMessage.success('删除成功')`);
|
|
348
|
+
lines.push(` tableRef.value?.httpRequestInstance()`);
|
|
349
|
+
lines.push(` })`);
|
|
350
|
+
lines.push(` .catch(() => {})`);
|
|
351
|
+
lines.push(`}`);
|
|
352
|
+
}
|
|
353
|
+
// dialog form
|
|
354
|
+
if (hasDialog) {
|
|
355
|
+
lines.push(``);
|
|
356
|
+
lines.push(`function openForm(title, row = {}) {`);
|
|
357
|
+
const dialogModelFields = (config.dialogFormItems || []).map(f => `${f.prop}: ''`).join(', ');
|
|
358
|
+
lines.push(` const formData = reactive({ ${dialogModelFields}, ...row })`);
|
|
359
|
+
lines.push(` const isView = title === '查看'`);
|
|
360
|
+
lines.push(` dialog({`);
|
|
361
|
+
lines.push(` title,`);
|
|
362
|
+
lines.push(` width: '500px',`);
|
|
363
|
+
lines.push(` render: (h, { registerRef }) => (`);
|
|
364
|
+
lines.push(` <EsForm`);
|
|
365
|
+
lines.push(` ref={el => el && registerRef('form', el)}`);
|
|
366
|
+
lines.push(` model={formData}`);
|
|
367
|
+
// dialog form items without formItemOptions for view mode
|
|
368
|
+
const dialogItemsStr = JSON.stringify(config.dialogFormItems, null, 8);
|
|
369
|
+
lines.push(` formItemList={${dialogItemsStr}}`);
|
|
370
|
+
lines.push(` />`);
|
|
371
|
+
lines.push(` ),`);
|
|
372
|
+
if (config.actions.includes('view') && !config.actions.includes('add') && !config.actions.includes('edit')) {
|
|
373
|
+
// view-only: no configBtn
|
|
374
|
+
lines.push(` configBtn: isView ? [] : [`);
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
lines.push(` configBtn: isView ? [`);
|
|
378
|
+
lines.push(` { name: '关闭', click: (_, { close }) => close() }`);
|
|
379
|
+
lines.push(` ] : [`);
|
|
380
|
+
}
|
|
381
|
+
lines.push(` { name: '取消', click: (_, { close }) => close() },`);
|
|
382
|
+
lines.push(` { name: '确定', type: 'primary', click: async (_, { close, getRefs }) => {`);
|
|
383
|
+
lines.push(` try {`);
|
|
384
|
+
lines.push(` await getRefs('form')?.validate()`);
|
|
385
|
+
lines.push(` // TODO: 调用保存接口`);
|
|
386
|
+
lines.push(` // await axios.post('/api/save', formData)`);
|
|
387
|
+
lines.push(` close()`);
|
|
388
|
+
lines.push(` tableRef.value?.httpRequestInstance()`);
|
|
389
|
+
lines.push(` } catch {`);
|
|
390
|
+
lines.push(` // 表单验证失败`);
|
|
391
|
+
lines.push(` }`);
|
|
392
|
+
lines.push(` }}`);
|
|
393
|
+
lines.push(` ]`);
|
|
394
|
+
lines.push(` })`);
|
|
395
|
+
lines.push(`}`);
|
|
396
|
+
}
|
|
397
|
+
lines.push(`</script>`);
|
|
398
|
+
// Post-process: wire up action column clickEvent references
|
|
399
|
+
let code = lines.join('\n');
|
|
400
|
+
code = code.replace(/"name": "编辑",\s*"type": "primary"/g, '"name": "编辑", "type": "primary", "clickEvent": (row) => openForm(\'编辑\', row)');
|
|
401
|
+
code = code.replace(/"name": "查看",\s*"type": "primary"/g, '"name": "查看", "type": "primary", "clickEvent": (row) => openForm(\'查看\', row)');
|
|
402
|
+
code = code.replace(/"name": "删除",\s*"type": "danger"/g, '"name": "删除", "type": "danger", "clickEvent": (row) => handleDelete(row)');
|
|
403
|
+
return code;
|
|
404
|
+
}
|
|
405
|
+
//# sourceMappingURL=crud-engine.js.map
|