From 0bf155bd97193bed1187ee01e997cf0134d9ad9e Mon Sep 17 00:00:00 2001 From: asp_ly Date: Sat, 28 Dec 2024 18:46:23 +0800 Subject: [PATCH] 1 --- frontend/scripts/generate-page.ts | 896 ++++++++++++++---- frontend/scripts/tsconfig.json | 21 + .../pages/Deploy/Application/List/index.tsx | 8 - 3 files changed, 721 insertions(+), 204 deletions(-) create mode 100644 frontend/scripts/tsconfig.json diff --git a/frontend/scripts/generate-page.ts b/frontend/scripts/generate-page.ts index db42691b..f2424a60 100644 --- a/frontend/scripts/generate-page.ts +++ b/frontend/scripts/generate-page.ts @@ -1,10 +1,17 @@ -import fs from 'fs'; -import path from 'path'; +import { promises as fs } from 'fs'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; +import { createInterface } from 'readline'; + +// 获取当前文件的目录 +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); interface GenerateOptions { name: string; // 模块名称,如 user, role 等 description: string; // 中文描述,如 "用户管理" baseUrl: string; // API基础路径,如 "/api/v1/users" + pageType?: 'list' | 'detail' | 'form'; // 页面类型,预留扩展 } // 生成 types.ts @@ -12,261 +19,758 @@ function generateTypes(options: GenerateOptions): string { const { name } = options; const typeName = name.charAt(0).toUpperCase() + name.slice(1); - return `import { BaseResponse, BaseQuery } from '@/types/base'; + return `import type { BaseResponse, BaseQuery } from '@/types/base'; export interface ${typeName}Response extends BaseResponse { name: string; + description?: string; + enabled: boolean; + sort: number; // TODO: 添加其他字段 } export interface ${typeName}Query extends BaseQuery { name?: string; + enabled?: boolean; // TODO: 添加其他查询字段 } export interface ${typeName}Request { name: string; + description?: string; + enabled: boolean; + sort: number; // TODO: 添加其他请求字段 } `; } +// 生成 schema.ts +function generateSchema(options: GenerateOptions): string { + const { name } = options; + const typeName = name.charAt(0).toUpperCase() + name.slice(1); + + return `import * as z from "zod"; + +export const searchFormSchema = z.object({ + name: z.string().optional(), + enabled: z.boolean().optional(), +}); + +export const ${typeName.toLowerCase()}FormSchema = z.object({ + name: z.string().min(1, "请输入名称").max(50, "名称不能超过50个字符"), + description: z.string().max(200, "描述不能超过200个字符").optional(), + enabled: z.boolean().default(true), + sort: z.number().min(0).default(0), +}); + +export type SearchFormValues = z.infer; +export type ${typeName}FormValues = z.infer; +`; +} + // 生成 service.ts function generateService(options: GenerateOptions): string { const { name, baseUrl } = options; const typeName = name.charAt(0).toUpperCase() + name.slice(1); - return `import { http } from '@/utils/http'; + return `import request from '@/utils/request'; +import type { Page } from '@/types/base'; import type { ${typeName}Response, ${typeName}Query, ${typeName}Request } from './types'; -// 获取列表 -export const getList = (params?: ${typeName}Query) => - http.get<${typeName}Response[]>('${baseUrl}', { params }); - -// 获取详情 -export const getDetail = (id: number) => - http.get<${typeName}Response>(\`${baseUrl}/\${id}\`); +const BASE_URL = '${baseUrl}'; // 创建 -export const create = (data: ${typeName}Request) => - http.post<${typeName}Response>('${baseUrl}', data); +export const create${typeName} = (data: ${typeName}Request) => + request.post(BASE_URL, data); // 更新 -export const update = (id: number, data: ${typeName}Request) => - http.put<${typeName}Response>(\`${baseUrl}/\${id}\`, data); +export const update${typeName} = (id: number, data: ${typeName}Request) => + request.put(\`\${BASE_URL}/\${id}\`, data); // 删除 -export const remove = (id: number) => - http.delete(\`${baseUrl}/\${id}\`); +export const delete${typeName} = (id: number) => + request.delete(\`\${BASE_URL}/\${id}\`); -// 批量删除 -export const batchRemove = (ids: number[]) => - http.post('${baseUrl}/batch-delete', { ids }); +// 获取详情 +export const get${typeName} = (id: number) => + request.get<${typeName}Response>(\`\${BASE_URL}/\${id}\`); + +// 分页查询列表 +export const get${typeName}Page = (params?: ${typeName}Query) => + request.get>(\`\${BASE_URL}/page\`, { params }); + +// 获取所有列表 +export const get${typeName}List = () => + request.get<${typeName}Response[]>(BASE_URL); + +// 条件查询列表 +export const get${typeName}ListByCondition = (params?: ${typeName}Query) => + request.get<${typeName}Response[]>(\`\${BASE_URL}/list\`, { params }); `; } -// 生成页面组件 -function generatePage(options: GenerateOptions): string { - const { name, description } = options; +// 生成 Modal 组件 +function generateModal(options: GenerateOptions): string { + const { name } = options; const typeName = name.charAt(0).toUpperCase() + name.slice(1); - - return `import { useState } from 'react'; -import { Card, Table, Button, Space, Modal, message, Form, Input } from 'antd'; -import type { ${typeName}Response, ${typeName}Query, ${typeName}Request } from './types'; -import * as service from './service'; -import { useRequest } from 'ahooks'; -const ${typeName}Page = () => { - const [query, setQuery] = useState<${typeName}Query>({}); - const [selectedRowKeys, setSelectedRowKeys] = useState([]); - const [editModalVisible, setEditModalVisible] = useState(false); - const [editingRecord, setEditingRecord] = useState<${typeName}Response | null>(null); - const [form] = Form.useForm(); + return `import React, { useEffect } from 'react'; +import type { ${typeName}Response } from '@/pages/${name}/List/types'; +import { create${typeName}, update${typeName} } from '@/pages/${name}/List/service'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Switch } from "@/components/ui/switch"; +import { useToast } from "@/components/ui/use-toast"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { ${typeName.toLowerCase()}FormSchema, type ${typeName}FormValues } from "@/pages/${name}/List/schema"; +import { Textarea } from "@/components/ui/textarea"; - // 获取列表数据 - const { data, loading, refresh } = useRequest(() => service.getList(query), { - refreshDeps: [query] - }); +interface ${typeName}ModalProps { + open: boolean; + onCancel: () => void; + onSuccess: () => void; + initialValues?: ${typeName}Response; +} - // 删除操作 - const handleDelete = async (id: number) => { - Modal.confirm({ - title: '确认删除', - content: '确定要删除这条记录吗?', - onOk: async () => { - try { - await service.remove(id); - message.success('删除成功'); - refresh(); - } catch (error) { - message.error('删除失败'); - } - } +const ${typeName}Modal: React.FC<${typeName}ModalProps> = ({ + open, + onCancel, + onSuccess, + initialValues, +}) => { + const { toast } = useToast(); + const isEdit = !!initialValues?.id; + + const form = useForm<${typeName}FormValues>({ + resolver: zodResolver(${typeName.toLowerCase()}FormSchema), + defaultValues: { + name: "", + description: "", + enabled: true, + sort: 0, + }, }); - }; - // 批量删除 - const handleBatchDelete = () => { - if (!selectedRowKeys.length) { - message.warning('请选择要删除的记录'); - return; - } - Modal.confirm({ - title: '确认删除', - content: \`确定要删除这\${selectedRowKeys.length}条记录吗?\`, - onOk: async () => { - try { - await service.batchRemove(selectedRowKeys); - message.success('删除成功'); - setSelectedRowKeys([]); - refresh(); - } catch (error) { - message.error('删除失败'); + useEffect(() => { + if (initialValues) { + form.reset({ + name: initialValues.name, + description: initialValues.description || "", + enabled: initialValues.enabled, + sort: initialValues.sort, + }); } - } - }); - }; + }, [initialValues, form]); - // 打开编辑弹窗 - const handleEdit = async (id: number) => { - try { - const detail = await service.getDetail(id); - setEditingRecord(detail); - form.setFieldsValue(detail); - setEditModalVisible(true); - } catch (error) { - message.error('获取详情失败'); - } - }; + const handleSubmit = async (values: ${typeName}FormValues) => { + try { + if (isEdit) { + await update${typeName}(initialValues.id, values); + } else { + await create${typeName}(values); + } + toast({ + title: \`\${isEdit ? '更新' : '创建'}成功\`, + duration: 3000, + }); + form.reset(); + onSuccess(); + } catch (error) { + toast({ + variant: "destructive", + title: \`\${isEdit ? '更新' : '创建'}失败\`, + description: error instanceof Error ? error.message : undefined, + duration: 3000, + }); + } + }; - // 打开新增弹窗 - const handleAdd = () => { - setEditingRecord(null); - form.resetFields(); - setEditModalVisible(true); - }; + return ( + !open && onCancel()}> + + + {isEdit ? '编辑' : '新建'} + +
+ + ( + + 名称 + + + + + + )} + /> - // 保存表单 - const handleSave = async () => { - try { - const values = await form.validateFields(); - if (editingRecord) { - await service.update(editingRecord.id, values); - message.success('更新成功'); - } else { - await service.create(values); - message.success('创建成功'); - } - setEditModalVisible(false); - refresh(); - } catch (error) { - message.error('操作失败'); - } - }; + ( + + 描述 + +