diff --git a/apps/web-antd/src/views/code-generation/components/ai-prompt.vue b/apps/web-antd/src/views/code-generation/components/ai-prompt.vue new file mode 100644 index 00000000..814f4284 --- /dev/null +++ b/apps/web-antd/src/views/code-generation/components/ai-prompt.vue @@ -0,0 +1,477 @@ + + + + + + diff --git a/apps/web-antd/src/views/code-generation/components/json-import.vue b/apps/web-antd/src/views/code-generation/components/json-import.vue new file mode 100644 index 00000000..1df2473e --- /dev/null +++ b/apps/web-antd/src/views/code-generation/components/json-import.vue @@ -0,0 +1,663 @@ + + + + + + diff --git a/apps/web-antd/src/views/code-generation/components/manual-form.vue b/apps/web-antd/src/views/code-generation/components/manual-form.vue new file mode 100644 index 00000000..b1a2b750 --- /dev/null +++ b/apps/web-antd/src/views/code-generation/components/manual-form.vue @@ -0,0 +1,433 @@ + + + + + + diff --git a/apps/web-antd/src/views/code-generation/components/mode-selector.vue b/apps/web-antd/src/views/code-generation/components/mode-selector.vue new file mode 100644 index 00000000..b0af42b9 --- /dev/null +++ b/apps/web-antd/src/views/code-generation/components/mode-selector.vue @@ -0,0 +1,629 @@ + + + + + diff --git a/apps/web-antd/src/views/code-generation/index.vue b/apps/web-antd/src/views/code-generation/index.vue index d7e3930c..dfe949e2 100644 --- a/apps/web-antd/src/views/code-generation/index.vue +++ b/apps/web-antd/src/views/code-generation/index.vue @@ -1,97 +1,156 @@ - + diff --git a/apps/web-antd/src/views/code-generation/utils/data-transformer.ts b/apps/web-antd/src/views/code-generation/utils/data-transformer.ts new file mode 100644 index 00000000..18fd16fa --- /dev/null +++ b/apps/web-antd/src/views/code-generation/utils/data-transformer.ts @@ -0,0 +1,201 @@ +/** + * 代码生成数据转换工具 + * 确保三种模式输出统一的数据格式 + */ + +export interface FieldType { + name: string; + type: string; + type_length: string; + default: string; + comment: string; + not_null: boolean; + formShow: boolean; + tableShow: boolean; + formType: string; + search: boolean; + searchValue: string; +} + +export interface CodeGenData { + class_name: string; + class_comment: string; + icon: string; + sort: number; + pid: number; + field: FieldType[]; +} + +/** + * 默认字段结构 + */ +const createDefaultField = (): FieldType => ({ + name: '', + type: 'varchar', + type_length: '', + default: '', + comment: '', + not_null: true, + formShow: true, + tableShow: true, + formType: 'VbenInput', + search: true, + searchValue: '=', +}); + +/** + * JSON模式数据转换 + */ +export function transformJsonToStandard(json: any): CodeGenData { + // 如果JSON包含完整结构,直接使用 + if (json.class_name && json.field) { + return { + class_name: json.class_name || '', + class_comment: json.class_comment || '', + icon: json.icon || '', + sort: json.sort ?? 9999, + pid: json.pid ?? 0, + field: Array.isArray(json.field) + ? json.field.map((f: any) => ({ + name: f.name || '', + type: f.type || 'varchar', + type_length: f.type_length || '', + default: f.default || '', + comment: f.comment || '', + not_null: f.not_null !== undefined ? f.not_null : true, + formShow: f.formShow !== undefined ? f.formShow : true, + tableShow: f.tableShow !== undefined ? f.tableShow : true, + formType: f.formType || 'VbenInput', + search: f.search !== undefined ? f.search : true, + searchValue: f.searchValue || '=', + })) + : [], + }; + } + + // 如果只有字段数组,需要用户补充基础信息 + if (Array.isArray(json)) { + return { + class_name: '', + class_comment: '', + icon: '', + sort: 9999, + pid: 0, + field: json.map((f: any) => ({ + name: f.name || '', + type: f.type || 'varchar', + type_length: f.type_length || '', + default: f.default || '', + comment: f.comment || '', + not_null: f.not_null !== undefined ? f.not_null : true, + formShow: f.formShow !== undefined ? f.formShow : true, + tableShow: f.tableShow !== undefined ? f.tableShow : true, + formType: f.formType || 'VbenInput', + search: f.search !== undefined ? f.search : true, + searchValue: f.searchValue || '=', + })), + }; + } + + // 默认返回空结构 + return { + class_name: '', + class_comment: '', + icon: '', + sort: 9999, + pid: 0, + field: [createDefaultField()], + }; +} + +/** + * 手动模式数据转换 + */ +export function transformManualToStandard( + formData: Record, + fields: FieldType[], +): CodeGenData { + return { + class_name: formData.class_name || '', + class_comment: formData.class_comment || '', + icon: formData.icon || '', + sort: formData.sort ?? 9999, + pid: formData.pid ?? 0, + field: Array.isArray(fields) ? fields : [], + }; +} + +/** + * AI模式数据转换 + */ +export function transformAiToStandard(aiData: any): CodeGenData { + // AI返回完整表单数据 + if (aiData && aiData.class_name) { + return { + class_name: aiData.class_name || '', + class_comment: aiData.class_comment || '', + icon: aiData.icon || '', + sort: aiData.sort ?? 9999, + pid: aiData.pid ?? 0, + field: Array.isArray(aiData.field) + ? aiData.field.map((f: any) => ({ + name: f.name || '', + type: f.type || 'varchar', + type_length: f.type_length || '', + default: f.default || '', + comment: f.comment || '', + not_null: f.not_null !== undefined ? f.not_null : true, + formShow: f.formShow !== undefined ? f.formShow : true, + tableShow: f.tableShow !== undefined ? f.tableShow : true, + formType: f.formType || 'VbenInput', + search: f.search !== undefined ? f.search : true, + searchValue: f.searchValue || '=', + })) + : [], + }; + } + + // 默认返回空结构 + return { + class_name: '', + class_comment: '', + icon: '', + sort: 9999, + pid: 0, + field: [createDefaultField()], + }; +} + +/** + * 数据验证 + */ +export function validateData(data: CodeGenData): { + valid: boolean; + message?: string; +} { + if (!data.class_name || !data.class_name.trim()) { + return { valid: false, message: '类名不能为空' }; + } + + if (!data.class_comment || !data.class_comment.trim()) { + return { valid: false, message: '中文名称不能为空' }; + } + + if (!data.icon || !data.icon.trim()) { + return { valid: false, message: '菜单图标不能为空' }; + } + + if (!Array.isArray(data.field) || data.field.length === 0) { + return { valid: false, message: '至少需要一个字段' }; + } + + // 验证字段 + for (const field of data.field) { + if (!field.name || !field.name.trim()) { + return { valid: false, message: '字段名不能为空' }; + } + } + + return { valid: true }; +} + diff --git a/apps/web-antd/src/views/code-generation/utils/draft-manager.ts b/apps/web-antd/src/views/code-generation/utils/draft-manager.ts new file mode 100644 index 00000000..e2a47780 --- /dev/null +++ b/apps/web-antd/src/views/code-generation/utils/draft-manager.ts @@ -0,0 +1,254 @@ +/** + * 草稿管理工具 + * 使用 localStorage 存储草稿,每种模式独立存储 + */ + +export type GenerationMode = 'json' | 'manual' | 'ai'; + +export interface DraftItem { + id: string; + name: string; + mode: GenerationMode; + data: any; + createdAt: number; + updatedAt: number; +} + +const STORAGE_PREFIX = 'code-gen-draft'; +const MAX_DRAFTS_PER_MODE = 10; // 每种模式最多保存10个草稿 + +/** + * 获取存储key + */ +function getStorageKey(mode: GenerationMode, id?: string): string { + if (id) { + return `${STORAGE_PREFIX}-${mode}-${id}`; + } + return `${STORAGE_PREFIX}-${mode}`; +} + +/** + * 获取所有草稿的索引key + */ +function getIndexKey(mode: GenerationMode): string { + return `${STORAGE_PREFIX}-index-${mode}`; +} + +/** + * 生成草稿ID + */ +function generateDraftId(): string { + return `draft-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; +} + +/** + * 获取草稿索引列表 + */ +function getDraftIndex(mode: GenerationMode): string[] { + try { + const key = getIndexKey(mode); + const indexStr = localStorage.getItem(key); + if (indexStr) { + return JSON.parse(indexStr); + } + } catch (error) { + console.error('获取草稿索引失败:', error); + } + return []; +} + +/** + * 保存草稿索引 + */ +function saveDraftIndex(mode: GenerationMode, ids: string[]): void { + try { + const key = getIndexKey(mode); + localStorage.setItem(key, JSON.stringify(ids)); + } catch (error) { + console.error('保存草稿索引失败:', error); + } +} + +/** + * 获取默认草稿名称 + */ +function getDefaultDraftName(mode: GenerationMode, index: number): string { + const modeNames = { + json: 'JSON导入', + manual: '手动填写', + ai: 'AI提示词', + }; + const numbers = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']; + const number = numbers[index] || `${index + 1}`; + return `${modeNames[mode]} - 草稿${number}`; +} + +/** + * 保存草稿 + */ +export function saveDraft( + mode: GenerationMode, + data: any, + name?: string, + draftId?: string, +): string { + try { + const id = draftId || generateDraftId(); + const now = Date.now(); + const index = getDraftIndex(mode); + + // 如果指定了draftId,更新现有草稿 + if (draftId && index.includes(draftId)) { + const existingDraft = loadDraft(mode, draftId); + const draftName = name || existingDraft?.name || getDefaultDraftName(mode, 0); + const draft: DraftItem = { + id, + name: draftName, + mode, + data, + createdAt: existingDraft?.createdAt || now, + updatedAt: now, + }; + + const key = getStorageKey(mode, id); + localStorage.setItem(key, JSON.stringify(draft)); + return id; + } + + // 创建新草稿 + const draftName = + name || getDefaultDraftName(mode, index.length); + const draft: DraftItem = { + id, + name: draftName, + mode, + data, + createdAt: now, + updatedAt: now, + }; + + // 保存草稿 + const key = getStorageKey(mode, id); + localStorage.setItem(key, JSON.stringify(draft)); + + // 更新索引(限制数量) + const newIndex = [id, ...index].slice(0, MAX_DRAFTS_PER_MODE); + saveDraftIndex(mode, newIndex); + + // 如果超出限制,删除最旧的草稿 + if (index.length >= MAX_DRAFTS_PER_MODE) { + const oldIds = index.slice(MAX_DRAFTS_PER_MODE - 1); + oldIds.forEach((oldId) => { + try { + localStorage.removeItem(getStorageKey(mode, oldId)); + } catch (error) { + console.error('删除旧草稿失败:', error); + } + }); + } + + return id; + } catch (error) { + console.error('保存草稿失败:', error); + throw error; + } +} + +/** + * 加载草稿 + */ +export function loadDraft( + mode: GenerationMode, + id: string, +): DraftItem | null { + try { + const key = getStorageKey(mode, id); + const draftStr = localStorage.getItem(key); + if (draftStr) { + const draft = JSON.parse(draftStr) as DraftItem; + // 验证模式是否匹配 + if (draft.mode === mode) { + return draft; + } + } + } catch (error) { + console.error('加载草稿失败:', error); + } + return null; +} + +/** + * 列出所有草稿 + */ +export function listDrafts(mode: GenerationMode): DraftItem[] { + try { + const index = getDraftIndex(mode); + const drafts: DraftItem[] = []; + + for (const id of index) { + const draft = loadDraft(mode, id); + if (draft) { + drafts.push(draft); + } + } + + // 按更新时间倒序排列 + return drafts.sort((a, b) => b.updatedAt - a.updatedAt); + } catch (error) { + console.error('列出草稿失败:', error); + return []; + } +} + +/** + * 删除草稿 + */ +export function deleteDraft(mode: GenerationMode, id: string): boolean { + try { + const key = getStorageKey(mode, id); + localStorage.removeItem(key); + + // 更新索引 + const index = getDraftIndex(mode); + const newIndex = index.filter((draftId) => draftId !== id); + saveDraftIndex(mode, newIndex); + + return true; + } catch (error) { + console.error('删除草稿失败:', error); + return false; + } +} + +/** + * 获取草稿名称 + */ +export function getDraftName(mode: GenerationMode, id: string): string { + const draft = loadDraft(mode, id); + return draft?.name || getDefaultDraftName(mode, 0); +} + +/** + * 清空所有草稿(用于测试或重置) + */ +export function clearAllDrafts(mode?: GenerationMode): void { + try { + if (mode) { + // 清空指定模式的草稿 + const index = getDraftIndex(mode); + index.forEach((id) => { + localStorage.removeItem(getStorageKey(mode, id)); + }); + localStorage.removeItem(getIndexKey(mode)); + } else { + // 清空所有模式的草稿 + const modes: GenerationMode[] = ['json', 'manual', 'ai']; + modes.forEach((m) => { + clearAllDrafts(m); + }); + } + } catch (error) { + console.error('清空草稿失败:', error); + } +} +