/** * KRA - Auto Code Generator Page * 自动化代码生成页面 */ import React, { useState, useEffect, useRef, useCallback } from 'react'; import { Card, Table, Button, Space, Form, Input, Select, Checkbox, Row, Col, Drawer, Collapse, Tooltip, message, Alert, Upload, Modal, Switch, Tag, } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { PlusOutlined, DeleteOutlined, EditOutlined, DownloadOutlined, UploadOutlined, QuestionCircleOutlined, RobotOutlined, EyeOutlined, SaveOutlined, ClearOutlined, CodeOutlined, HolderOutlined, ReloadOutlined, FileAddOutlined, MenuOutlined, } from '@ant-design/icons'; import { PageContainer } from '@ant-design/pro-components'; import { useParams, useSearchParams, useNavigate } from '@umijs/max'; import { getDB, getTable, getColumn, createTemp, preview, getPackage, getMeta, llmAuto, eye, getTemplates, type AutoCodeParams, } from '@/services/kratos/autoCode'; import { getDict } from '@/utils/dictionary'; import { getSysDictionaryList } from '@/services/kratos/dictionary'; import WarningBar from '@/components/WarningBar'; import CodePreview from './components/CodePreview'; import styles from './index.less'; const { Panel } = Collapse; const { TextArea } = Input; // 字段模板 const fieldTemplate = { fieldName: '', fieldDesc: '', fieldType: '', dataType: '', fieldJson: '', columnName: '', dataTypeLong: '', comment: '', defaultValue: '', require: false, sort: false, form: true, desc: true, table: true, excel: false, errorText: '', primaryKey: false, clearable: true, fieldSearchType: '', fieldSearchHide: false, fieldIndexType: '', dictType: '', onlyNumber: '', dataSource: { dbName: '', association: 1, table: '', label: '', value: '', hasDeletedAt: false, }, }; // KRA默认字段列表 const gormModelList = ['id', 'created_at', 'updated_at', 'deleted_at']; const dataModelList = ['created_by', 'updated_by', 'deleted_by']; // 字段类型选项 const typeOptions = [ { label: '字符串', value: 'string' }, { label: '富文本', value: 'richtext' }, { label: '整型', value: 'int' }, { label: '布尔值', value: 'bool' }, { label: '浮点型', value: 'float64' }, { label: '时间', value: 'time.Time' }, { label: '枚举', value: 'enum' }, { label: '单图片(字符串)', value: 'picture' }, { label: '多图片(json字符串)', value: 'pictures' }, { label: '视频(字符串)', value: 'video' }, { label: '文件(json字符串)', value: 'file' }, { label: 'JSON', value: 'json' }, { label: '数组', value: 'array' }, ]; // 搜索条件选项 const typeSearchOptions = [ { label: '=', value: '=' }, { label: '<>', value: '<>' }, { label: '>', value: '>' }, { label: '<', value: '<' }, { label: 'LIKE', value: 'LIKE' }, { label: 'BETWEEN', value: 'BETWEEN' }, { label: 'NOT BETWEEN', value: 'NOT BETWEEN' }, ]; // 索引类型选项 const typeIndexOptions = [ { label: 'index', value: 'index' }, { label: 'uniqueIndex', value: 'uniqueIndex' }, ]; // 工具函数 const toUpperCase = (str: string) => { if (!str) return ''; return str.charAt(0).toUpperCase() + str.slice(1); }; const toLowerCase = (str: string) => { if (!str) return ''; return str.charAt(0).toLowerCase() + str.slice(1); }; const toHump = (str: string) => { if (!str) return ''; return str.replace(/_(\w)/g, (_, letter) => letter.toUpperCase()); }; const toSQLLine = (str: string) => { if (!str) return ''; return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, ''); }; const getOnlyNumber = () => { let randomNumber = ''; while (randomNumber.length < 16) { randomNumber += Math.random().toString(16).substring(2); } return randomNumber.substring(0, 16); }; interface FieldItem { fieldName: string; fieldDesc: string; fieldType: string; dataType?: string; fieldJson: string; columnName: string; dataTypeLong: string; comment: string; defaultValue: string; require: boolean; sort: boolean; form: boolean; desc: boolean; table: boolean; excel: boolean; errorText?: string; primaryKey: boolean; clearable?: boolean; fieldSearchType: string; fieldSearchHide?: boolean; fieldIndexType: string; dictType?: string; onlyNumber?: string; disabled?: boolean; dataSource?: { dbName: string; association: number; table: string; label: string; value: string; hasDeletedAt: boolean; }; } interface FormData { structName: string; tableName: string; packageName: string; package: string; abbreviation: string; description: string; businessDB: string; autoCreateApiToSql: boolean; autoCreateMenuToSql: boolean; autoCreateBtnAuth: boolean; autoMigrate: boolean; gvaModel: boolean; autoCreateResource: boolean; onlyTemplate: boolean; isTree: boolean; generateWeb: boolean; generateServer: boolean; treeJson: string; humpPackageName?: string; templateType: string; // 模板类型:package 或 plugin fields: FieldItem[]; } const AutoCodePage: React.FC = () => { const params = useParams(); const [searchParams] = useSearchParams(); const navigate = useNavigate(); const [loading, setLoading] = useState(false); const [prompt, setPrompt] = useState(''); const [isAdd, setIsAdd] = useState(false); // 数据库选择 const [dbList, setDbList] = useState([]); const [dbOptions, setDbOptions] = useState([]); const [tableOptions, setTableOptions] = useState([]); const [dbform, setDbform] = useState({ businessDB: '', dbName: '', tableName: '', }); // 模板列表 const [pkgs, setPkgs] = useState([]); // 模板类型选项 const [templateTypes, setTemplateTypes] = useState(['package', 'plugin']); // 字段类型映射 const [fdMap, setFdMap] = useState>({}); // 表单数据 const [form, setForm] = useState({ structName: '', tableName: '', packageName: '', package: '', abbreviation: '', description: '', businessDB: '', autoCreateApiToSql: true, autoCreateMenuToSql: true, autoCreateBtnAuth: false, autoMigrate: true, gvaModel: true, autoCreateResource: false, onlyTemplate: false, isTree: false, generateWeb: true, generateServer: true, treeJson: '', templateType: 'package', // 默认使用 package 模板 fields: [], }); // 字段编辑弹窗 const [fieldDialogVisible, setFieldDialogVisible] = useState(false); const [editingField, setEditingField] = useState(null); const [addFlag, setAddFlag] = useState<'add' | 'edit'>('add'); const [dialogMiddle, setDialogMiddle] = useState({ ...fieldTemplate } as FieldItem); const [bk, setBk] = useState(null); // 预览弹窗 const [previewVisible, setPreviewVisible] = useState(false); const [previewCode, setPreviewCode] = useState(null); // TextArea焦点状态 const [textareaFocused, setTextareaFocused] = useState(false); // 字典选项列表 const [dictOptions, setDictOptions] = useState([]); // 数据源相关状态 const [dbTableList, setDbTableList] = useState([]); const [dbColumnList, setDbColumnList] = useState([]); const [dataSourceCollapsed, setDataSourceCollapsed] = useState([]); // 键盘快捷键处理 - Ctrl+Enter 或 Cmd+Enter 直接生成 const handleKeydown = useCallback((event: KeyboardEvent) => { if ((event.ctrlKey || event.metaKey) && event.key === 'Enter') { llmAutoFunc(); } }, []); // 剪贴板粘贴图片处理 const handlePaste = useCallback(async (event: Event) => { const clipboardEvent = event as ClipboardEvent; const items = clipboardEvent.clipboardData?.items; if (!items) return; for (let i = 0; i < items.length; i++) { if (items[i].type.indexOf('image') !== -1) { const file = items[i].getAsFile(); if (file) { const reader = new FileReader(); reader.onload = async (e) => { const base64String = e.target?.result as string; try { const res = await eye({ picture: base64String, command: 'eye' }); if (res.code === 0) { setPrompt(res.data); llmAutoFunc(); } } catch (error) { message.error('识图失败'); } }; reader.readAsDataURL(file); } } } }, []); // TextArea 焦点处理 const handleFocus = () => { setTextareaFocused(true); document.addEventListener('keydown', handleKeydown); document.addEventListener('paste', handlePaste); }; const handleBlur = () => { setTextareaFocused(false); document.removeEventListener('keydown', handleKeydown); document.removeEventListener('paste', handlePaste); }; // 清理事件监听 useEffect(() => { return () => { document.removeEventListener('keydown', handleKeydown); document.removeEventListener('paste', handlePaste); }; }, [handleKeydown, handlePaste]); // 初始化 useEffect(() => { init(); }, []); // 监听generateServer变化 useEffect(() => { if (!form.generateServer) { setForm(prev => ({ ...prev, autoCreateApiToSql: false, autoMigrate: false, })); } }, [form.generateServer]); // 监听generateWeb变化 useEffect(() => { if (!form.generateWeb) { setForm(prev => ({ ...prev, autoCreateMenuToSql: false, autoCreateBtnAuth: false, })); } }, [form.generateWeb]); const init = async () => { await getDbFunc(); await setFdMapFunc(); await getPkgs(); await getDictOptionsFunc(); await getTemplateTypesFunc(); // 从路由获取ID const id = params.id; if (id) { await getAutoCodeJson(Number(id)); } // 获取缓存 getCatch(); }; // 获取模板类型列表 const getTemplateTypesFunc = async () => { try { const res = await getTemplates(); if (res.code === 0 && res.data) { setTemplateTypes(res.data || ['package', 'plugin']); } } catch (error) { console.error('获取模板类型失败:', error); } }; // 获取字典选项列表 const getDictOptionsFunc = async () => { try { const res = await getSysDictionaryList({ page: 1, pageSize: 999999 } as any); if (res.code === 0 && res.data) { setDictOptions(res.data.list || res.data || []); } } catch (error) { console.error('获取字典列表失败:', error); } }; // 获取数据库列表 const getDbFunc = async () => { try { const res = await getDB({ businessDB: dbform.businessDB }); if (res.code === 0 && res.data) { setDbOptions(res.data.dbs || []); setDbList(res.data.dbList || []); } } catch (error) { console.error('获取数据库失败:', error); } }; // 获取表列表 const getTableFunc = async () => { try { const res = await getTable({ businessDB: dbform.businessDB, dbName: dbform.dbName, }); if (res.code === 0 && res.data) { setTableOptions(res.data.tables || []); } setDbform(prev => ({ ...prev, tableName: '' })); } catch (error) { console.error('获取表列表失败:', error); } }; // 获取字段列表 const getColumnFunc = async () => { if (!dbform.dbName || !dbform.tableName) { message.warning('请选择数据库和表'); return; } try { const res = await getColumn(dbform); if (res.code === 0 && res.data) { let dbtype = ''; if (dbform.businessDB) { const dbtmp = dbList.find(item => item.aliasName === dbform.businessDB); if (dbtmp) { dbtype = dbtmp.dbtype; } } const tbHump = toHump(dbform.tableName); const newFields: FieldItem[] = []; res.data.columns?.forEach((item: any) => { if (needAppend(item)) { const fbHump = toHump(item.columnName); newFields.push({ onlyNumber: getOnlyNumber(), fieldName: toUpperCase(fbHump), fieldDesc: item.columnComment || fbHump + '字段', fieldType: fdMap[item.dataType] || 'string', dataType: item.dataType, fieldJson: fbHump, primaryKey: item.primaryKey || false, dataTypeLong: item.dataTypeLong?.split(',')[0] || '', columnName: dbtype === 'oracle' ? item.columnName.toUpperCase() : item.columnName, comment: item.columnComment || '', defaultValue: '', require: false, errorText: '', clearable: true, fieldSearchType: '', fieldIndexType: '', dictType: '', form: true, table: true, excel: false, desc: true, sort: false, dataSource: { dbName: '', association: 1, table: '', label: '', value: '', hasDeletedAt: false, }, }); } }); setForm(prev => ({ ...prev, gvaModel: false, structName: toUpperCase(tbHump), tableName: dbform.tableName, packageName: toLowerCase(tbHump), abbreviation: toLowerCase(tbHump), description: tbHump + '表', autoCreateApiToSql: true, generateServer: true, generateWeb: true, fields: newFields, })); message.success('字段获取成功'); } } catch (error) { message.error('获取字段失败'); } }; // 判断是否需要添加字段 const needAppend = (item: any) => { if (form.gvaModel && gormModelList.includes(item.columnName)) { return false; } if (form.autoCreateResource && dataModelList.includes(item.columnName)) { return false; } return true; }; // 设置字段类型映射 const setFdMapFunc = async () => { const fdTypes = ['string', 'int', 'bool', 'float64', 'time.Time']; const newFdMap: Record = {}; for (const fdtype of fdTypes) { try { const res = await getDict(fdtype); res?.forEach((item: any) => { newFdMap[item.label] = fdtype; }); } catch (error) { // ignore } } setFdMap(newFdMap); }; // 获取模板列表 const getPkgs = async () => { try { const res = await getPackage(); if (res.code === 0 && res.data) { setPkgs(res.data.pkgs || []); } } catch (error) { console.error('获取模板列表失败:', error); } }; // 获取历史代码配置 const getAutoCodeJson = async (id: number) => { try { const res = await getMeta({ id }); if (res.code === 0 && res.data) { const add = searchParams.get('isAdd'); setIsAdd(!!add); const meta = JSON.parse(res.data.meta); if (add) { meta.fields?.forEach((item: FieldItem) => { item.disabled = true; }); } setForm(meta); } } catch (error) { console.error('获取配置失败:', error); } }; // AI生成 const llmAutoFunc = async (flag?: boolean) => { if (flag && !form.structName) { message.error('请输入结构体名称'); return; } if (!flag && !prompt) { message.error('请输入描述'); return; } if (form.fields.length > 0) { Modal.confirm({ title: '提示', content: 'AI生成会清空当前数据,是否继续?', onOk: async () => { await doLlmAuto(flag); }, }); } else { await doLlmAuto(flag); } }; const doLlmAuto = async (flag?: boolean) => { setLoading(true); try { const res = await llmAuto({ prompt: flag ? '结构体名称为' + form.structName : prompt, }); if (res.code === 0) { const json = JSON.parse(res.data); json.fields?.forEach((item: FieldItem) => { item.fieldName = toUpperCase(item.fieldName); }); setForm(prev => ({ ...prev, ...json, generateServer: true, generateWeb: true, fields: json.fields || [], })); message.success('AI生成成功'); } } catch (error) { message.error('AI生成失败'); } finally { setLoading(false); } }; // 识图功能 const eyeFunc = () => { const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; input.onchange = async (event: any) => { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = async (e) => { const base64String = e.target?.result as string; try { const res = await eye({ picture: base64String, command: 'eye' }); if (res.code === 0) { setPrompt(res.data); llmAutoFunc(); } } catch (error) { message.error('识图失败'); } }; reader.readAsDataURL(file); } }; input.click(); }; // 使用KRA结构 const useKraModel = (checked: boolean) => { if (checked && form.fields.length > 0) { Modal.confirm({ title: '注意', content: '如果您开启KRA默认结构,会自动添加ID,CreatedAt,UpdatedAt,DeletedAt字段,此行为将自动清除您目前在下方创建的重名字段,是否继续?', onOk: () => { setForm(prev => ({ ...prev, gvaModel: true, fields: prev.fields.filter(item => !gormModelList.includes(item.columnName)), })); }, onCancel: () => { setForm(prev => ({ ...prev, gvaModel: false })); }, }); } else { setForm(prev => ({ ...prev, gvaModel: checked })); } }; // 自动填充字段Json和数据库字段 const autoFillField = () => { if (!dialogMiddle.fieldName) { message.warning('请先输入字段名称'); return; } const fieldJson = toLowerCase(dialogMiddle.fieldName); const columnName = toSQLLine(fieldJson); setDialogMiddle(prev => ({ ...prev, fieldJson, columnName, })); }; // 清除字段类型相关选项 const clearFieldTypeOptions = () => { setDialogMiddle(prev => ({ ...prev, fieldSearchType: '', dictType: '', })); }; // 数据源关联模式变更 const handleAssociationChange = (val: number) => { if (val === 2) { Modal.confirm({ title: '提示', content: '一对多关联模式下,数据类型会改变为数组,后端表现为json,具体表现为数组模式,是否继续?', onOk: () => { setDialogMiddle(prev => ({ ...prev, fieldType: 'array', dataSource: { ...prev.dataSource!, association: 2 }, })); }, onCancel: () => { setDialogMiddle(prev => ({ ...prev, dataSource: { ...prev.dataSource!, association: 1 }, })); }, }); } else { setDialogMiddle(prev => ({ ...prev, dataSource: { ...prev.dataSource!, association: val }, })); } }; // 获取数据源表列表 const getDBTableListFunc = async (dbName?: string) => { try { const res = await getTable({ businessDB: dbName || dialogMiddle.dataSource?.dbName || '' }); if (res.code === 0 && res.data) { setDbTableList((res.data.tables || []).map((item: any) => ({ tableName: item.tableName, value: item.tableName, }))); } } catch (error) { console.error('获取表列表失败:', error); } }; // 选择数据源表 const selectDataSourceTable = async (tableName: string, isInit?: boolean) => { if (!tableName) { setDbColumnList([]); setDialogMiddle(prev => ({ ...prev, dataSource: { ...prev.dataSource!, table: '', label: '', value: '', hasDeletedAt: false, }, })); return; } try { const res = await getColumn({ businessDB: dialogMiddle.dataSource?.dbName || '', tableName, }); if (res.code === 0 && res.data) { let hasDeletedAt = false; const columns = (res.data.columns || []).map((item: any) => { if (item.columnName === 'deleted_at') { hasDeletedAt = true; } return { columnName: item.columnName, value: item.columnName, type: item.dataType, isPrimary: item.primaryKey, comment: item.columnComment, }; }); setDbColumnList(columns); if (!isInit && columns.length > 0) { setDialogMiddle(prev => ({ ...prev, dataSource: { ...prev.dataSource!, table: tableName, label: columns[0].columnName, value: columns[0].columnName, hasDeletedAt, }, })); } else { setDialogMiddle(prev => ({ ...prev, dataSource: { ...prev.dataSource!, table: tableName, hasDeletedAt, }, })); } } } catch (error) { console.error('获取字段列表失败:', error); } }; // 数据源数据库变更 const handleDataSourceDbChange = (dbName: string) => { setDialogMiddle(prev => ({ ...prev, dataSource: { ...prev.dataSource!, dbName, table: '', label: '', value: '', }, })); setDbColumnList([]); if (dbName) { getDBTableListFunc(dbName); } }; // 清除数据源选择 const clearDataSourceAccess = () => { setDialogMiddle(prev => ({ ...prev, dataSource: { ...prev.dataSource!, label: '', value: '', }, })); }; // 拖拽排序处理 const moveField = (dragIndex: number, hoverIndex: number) => { const newFields = [...form.fields]; const [draggedItem] = newFields.splice(dragIndex, 1); newFields.splice(hoverIndex, 0, draggedItem); setForm(prev => ({ ...prev, fields: newFields })); }; // 新增/编辑字段 const editAndAddField = (item?: FieldItem) => { setFieldDialogVisible(true); if (item) { setAddFlag('edit'); if (!item.dataSource) { item.dataSource = { dbName: '', association: 1, table: '', label: '', value: '', hasDeletedAt: false, }; } setBk(JSON.parse(JSON.stringify(item))); setDialogMiddle(item); // 如果有数据源表,加载字段列表 if (item.dataSource?.table) { getDBTableListFunc(item.dataSource.dbName); selectDataSourceTable(item.dataSource.table, true); } } else { setAddFlag('add'); const newField = { ...fieldTemplate, onlyNumber: getOnlyNumber(), } as FieldItem; setDialogMiddle(newField); setDbTableList([]); setDbColumnList([]); } }; // 确认字段编辑 const enterDialog = () => { if (!dialogMiddle.fieldName) { message.error('请输入字段名称'); return; } const updatedField = { ...dialogMiddle, fieldName: toUpperCase(dialogMiddle.fieldName), }; if (addFlag === 'add') { setForm(prev => ({ ...prev, fields: [...prev.fields, updatedField], })); } else { setForm(prev => ({ ...prev, fields: prev.fields.map(f => f.onlyNumber === updatedField.onlyNumber ? updatedField : f ), })); } setFieldDialogVisible(false); }; // 关闭字段编辑 const closeDialog = () => { if (addFlag === 'edit' && bk) { // 恢复备份 setForm(prev => ({ ...prev, fields: prev.fields.map(f => f.onlyNumber === bk.onlyNumber ? bk : f ), })); } setFieldDialogVisible(false); }; // 删除字段 const deleteField = (index: number) => { Modal.confirm({ title: '提示', content: '确定要删除吗?', onOk: () => { setForm(prev => ({ ...prev, fields: prev.fields.filter((_, i) => i !== index), })); }, }); }; // 暂存 const catchData = () => { sessionStorage.setItem('autoCode', JSON.stringify(form)); message.success('暂存成功'); }; // 获取缓存 const getCatch = () => { const data = sessionStorage.getItem('autoCode'); if (data) { try { setForm(JSON.parse(data)); } catch (error) { // ignore } } }; // 清除缓存 const clearCatch = () => { setForm({ structName: '', tableName: '', packageName: '', package: '', abbreviation: '', description: '', businessDB: '', autoCreateApiToSql: true, autoCreateMenuToSql: true, autoCreateBtnAuth: false, autoMigrate: true, gvaModel: true, autoCreateResource: false, onlyTemplate: false, isTree: false, generateWeb: true, generateServer: true, treeJson: '', templateType: 'package', fields: [], }); sessionStorage.removeItem('autoCode'); message.success('清除成功'); }; // 导出JSON const exportJson = () => { const dataStr = JSON.stringify(form, null, 2); const blob = new Blob([dataStr], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'form_data.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; // 导入JSON const importJson = (file: File) => { const reader = new FileReader(); reader.onload = (e) => { try { const data = JSON.parse(e.target?.result as string); setForm({ ...data, generateServer: true, generateWeb: true, }); message.success('JSON文件导入成功'); } catch (error) { message.error('无效的JSON文件'); } }; reader.readAsText(file); return false; }; // 验证表单 const validateForm = (): boolean => { if (form.isTree && !form.treeJson) { message.error('请填写树型结构的前端展示json属性'); return false; } if (!form.generateWeb && !form.generateServer) { message.error('请至少选择一个生成项'); return false; } if (!form.onlyTemplate) { if (form.fields.length <= 0) { message.error('请填写至少一个field'); return false; } if (!form.gvaModel && form.fields.every(item => !item.primaryKey)) { message.error('您至少需要创建一个主键才能保证自动化代码的可行性'); return false; } if (form.fields.some(item => item.fieldName === form.structName)) { message.error('存在与结构体同名的字段'); return false; } if (form.fields.some(item => item.fieldJson === form.package)) { message.error('存在与模板同名的字段JSON'); return false; } if (form.fields.some(item => !item.fieldType)) { message.error('请填写所有字段类型后进行提交'); return false; } if (form.package === form.abbreviation) { message.error('package和结构体简称不可同名'); return false; } } if (!form.structName) { message.error('请输入结构体名称'); return false; } if (!form.abbreviation) { message.error('请输入结构体简称'); return false; } if (!form.description) { message.error('请输入结构体描述'); return false; } if (!form.packageName) { message.error('请输入文件名称'); return false; } if (!form.package) { message.error('请选择模板'); return false; } if (form.structName === form.abbreviation) { message.error('structName和struct简称不能相同'); return false; } return true; }; // 提交表单(预览或生成) const enterForm = async (isPreview: boolean) => { if (!validateForm()) return; // 处理表单数据 const submitForm = { ...form }; submitForm.structName = toUpperCase(submitForm.structName.trim()); submitForm.tableName = submitForm.tableName.replace(' ', ''); if (!submitForm.tableName) { submitForm.tableName = toSQLLine(toLowerCase(submitForm.structName)); } submitForm.humpPackageName = toSQLLine(submitForm.packageName); // 处理字段 submitForm.fields = submitForm.fields.map(item => { const newItem = { ...item }; newItem.fieldName = toUpperCase(newItem.fieldName); if (newItem.fieldType === 'enum') { newItem.dataTypeLong = newItem.dataTypeLong.replace(/[\[\]{}()]/g, ''); const arr = newItem.dataTypeLong.split(','); newItem.dataTypeLong = arr.map(ele => ele.indexOf("'") === -1 ? `'${ele}'` : ele ).join(','); } return newItem; }); setLoading(true); try { if (isPreview) { const res = await preview({ ...submitForm, isAdd: isAdd, fields: submitForm.fields.filter(item => !item.disabled), } as AutoCodeParams); if (res.code === 0 && res.data) { setPreviewCode(res.data.autoCode || res.data); setPreviewVisible(true); } } else { const res = await createTemp(submitForm as AutoCodeParams); if (res.code === 0) { message.success('自动化代码创建成功,自动移动成功'); clearCatch(); } } } catch (error) { message.error(isPreview ? '预览失败' : '生成失败'); } finally { setLoading(false); } }; // 判断搜索条件是否可选 const canSelect = (fieldType: string, item: string) => { if (fieldType === 'richtext') { return item !== 'LIKE'; } if (fieldType !== 'string' && item === 'LIKE') { return true; } const nonNumericTypes = ['int', 'time.Time', 'float64']; if (!nonNumericTypes.includes(fieldType) && ['BETWEEN', 'NOT BETWEEN'].includes(item)) { return true; } return false; }; // 跳转到模板管理 const goPkgs = () => { navigate('/systemTools/autoPkg'); }; // 字段表格列定义 const fieldColumns: ColumnsType = [ { title: '', key: 'drag', width: 50, render: (_, __, index) => ( ), }, { title: '序列', key: 'index', width: 60, render: (_, __, index) => index + 1 }, { title: '主键', dataIndex: 'primaryKey', width: 60, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].primaryKey = e.target.checked; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '字段名称', dataIndex: 'fieldName', width: 140, render: (val) => , }, { title: '中文名', dataIndex: 'fieldDesc', width: 140, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].fieldDesc = e.target.value; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '默认值', dataIndex: 'defaultValue', width: 120, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].defaultValue = e.target.value; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '必填', dataIndex: 'require', width: 60, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].require = e.target.checked; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '排序', dataIndex: 'sort', width: 60, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].sort = e.target.checked; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '新建/编辑', dataIndex: 'form', width: 90, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].form = e.target.checked; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '表格', dataIndex: 'table', width: 60, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].table = e.target.checked; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '详情', dataIndex: 'desc', width: 60, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].desc = e.target.checked; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, ...(!isAdd ? [{ title: '导入/导出', dataIndex: 'excel', width: 90, render: (val: boolean, record: FieldItem, index: number) => ( { const newFields = [...form.fields]; newFields[index].excel = e.target.checked; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }] : []), { title: '字段Json', dataIndex: 'fieldJson', width: 140, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].fieldJson = e.target.value; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '字段类型', dataIndex: 'fieldType', width: 140, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].dictType = value; setForm(prev => ({ ...prev, fields: newFields })); }} > {dictOptions.map((dict: any) => ( {`${dict.type}(${dict.name})`} ))} ), }, { title: '索引类型', dataIndex: 'fieldIndexType', width: 120, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].dataTypeLong = e.target.value; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '数据库字段', dataIndex: 'columnName', width: 140, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].columnName = e.target.value; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '数据库字段描述', dataIndex: 'comment', width: 140, render: (val, record, index) => ( { const newFields = [...form.fields]; newFields[index].comment = e.target.value; setForm(prev => ({ ...prev, fields: newFields })); }} /> ), }, { title: '搜索条件', dataIndex: 'fieldSearchType', width: 120, render: (val, record, index) => ( ), }, { title: '操作', key: 'action', width: 150, fixed: 'right', render: (_, record, index) => ( {!record.disabled && ( <> )} ), }, ]; return ( {/* 警告栏 */} 此功能为开发环境使用,不建议发布到生产, 具体使用效果请点我观看 } type="warning" showIcon className={styles.warningBar} /> {/* AI生成区域 */} {!isAdd && ( 使用AI创建 获取AiPath } className={styles.sectionCard} >