This commit is contained in:
asp_ly 2024-12-28 18:46:23 +08:00
parent 15c1e1ed25
commit 0bf155bd97
3 changed files with 721 additions and 204 deletions

View File

@ -1,10 +1,17 @@
import fs from 'fs'; import { promises as fs } from 'fs';
import path from 'path'; 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 { interface GenerateOptions {
name: string; // 模块名称,如 user, role 等 name: string; // 模块名称,如 user, role 等
description: string; // 中文描述,如 "用户管理" description: string; // 中文描述,如 "用户管理"
baseUrl: string; // API基础路径如 "/api/v1/users" baseUrl: string; // API基础路径如 "/api/v1/users"
pageType?: 'list' | 'detail' | 'form'; // 页面类型,预留扩展
} }
// 生成 types.ts // 生成 types.ts
@ -12,261 +19,758 @@ function generateTypes(options: GenerateOptions): string {
const { name } = options; const { name } = options;
const typeName = name.charAt(0).toUpperCase() + name.slice(1); 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 { export interface ${typeName}Response extends BaseResponse {
name: string; name: string;
description?: string;
enabled: boolean;
sort: number;
// TODO: 添加其他字段 // TODO: 添加其他字段
} }
export interface ${typeName}Query extends BaseQuery { export interface ${typeName}Query extends BaseQuery {
name?: string; name?: string;
enabled?: boolean;
// TODO: 添加其他查询字段 // TODO: 添加其他查询字段
} }
export interface ${typeName}Request { export interface ${typeName}Request {
name: string; name: string;
description?: string;
enabled: boolean;
sort: number;
// TODO: 添加其他请求字段 // 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<typeof searchFormSchema>;
export type ${typeName}FormValues = z.infer<typeof ${typeName.toLowerCase()}FormSchema>;
`;
}
// 生成 service.ts // 生成 service.ts
function generateService(options: GenerateOptions): string { function generateService(options: GenerateOptions): string {
const { name, baseUrl } = options; const { name, baseUrl } = options;
const typeName = name.charAt(0).toUpperCase() + name.slice(1); 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'; import type { ${typeName}Response, ${typeName}Query, ${typeName}Request } from './types';
// 获取列表 const BASE_URL = '${baseUrl}';
export const getList = (params?: ${typeName}Query) =>
http.get<${typeName}Response[]>('${baseUrl}', { params });
// 获取详情
export const getDetail = (id: number) =>
http.get<${typeName}Response>(\`${baseUrl}/\${id}\`);
// 创建 // 创建
export const create = (data: ${typeName}Request) => export const create${typeName} = (data: ${typeName}Request) =>
http.post<${typeName}Response>('${baseUrl}', data); request.post<void>(BASE_URL, data);
// 更新 // 更新
export const update = (id: number, data: ${typeName}Request) => export const update${typeName} = (id: number, data: ${typeName}Request) =>
http.put<${typeName}Response>(\`${baseUrl}/\${id}\`, data); request.put<void>(\`\${BASE_URL}/\${id}\`, data);
// 删除 // 删除
export const remove = (id: number) => export const delete${typeName} = (id: number) =>
http.delete(\`${baseUrl}/\${id}\`); request.delete<void>(\`\${BASE_URL}/\${id}\`);
// 批量删除 // 获取详情
export const batchRemove = (ids: number[]) => export const get${typeName} = (id: number) =>
http.post('${baseUrl}/batch-delete', { ids }); request.get<${typeName}Response>(\`\${BASE_URL}/\${id}\`);
// 分页查询列表
export const get${typeName}Page = (params?: ${typeName}Query) =>
request.get<Page<${typeName}Response>>(\`\${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 });
`; `;
} }
// 生成页面组件 // 生成 Modal 组件
function generatePage(options: GenerateOptions): string { function generateModal(options: GenerateOptions): string {
const { name } = options;
const typeName = name.charAt(0).toUpperCase() + name.slice(1);
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";
interface ${typeName}ModalProps {
open: boolean;
onCancel: () => void;
onSuccess: () => void;
initialValues?: ${typeName}Response;
}
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,
},
});
useEffect(() => {
if (initialValues) {
form.reset({
name: initialValues.name,
description: initialValues.description || "",
enabled: initialValues.enabled,
sort: initialValues.sort,
});
}
}, [initialValues, form]);
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,
});
}
};
return (
<Dialog open={open} onOpenChange={(open) => !open && onCancel()}>
<DialogContent className="sm:max-w-[600px]">
<DialogHeader>
<DialogTitle>{isEdit ? '编辑' : '新建'}</DialogTitle>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(handleSubmit)} className="space-y-4">
<FormField
control={form.control}
name="name"
render={({field}) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<Input
{...field}
placeholder="请输入名称"
/>
</FormControl>
<FormMessage/>
</FormItem>
)}
/>
<FormField
control={form.control}
name="description"
render={({field}) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<Textarea
{...field}
placeholder="请输入描述"
rows={4}
/>
</FormControl>
<FormMessage/>
</FormItem>
)}
/>
<FormField
control={form.control}
name="enabled"
render={({field}) => (
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
<div className="space-y-0.5">
<FormLabel></FormLabel>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="sort"
render={({field}) => (
<FormItem>
<FormLabel></FormLabel>
<FormControl>
<Input
{...field}
type="number"
min={0}
onChange={(e) => field.onChange(Number(e.target.value))}
/>
</FormControl>
<FormMessage/>
</FormItem>
)}
/>
<DialogFooter>
<Button type="button" variant="outline" onClick={onCancel}>
</Button>
<Button type="submit">
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
};
export default ${typeName}Modal;
`;
}
// 生成列表页面组件
function generateListPage(options: GenerateOptions): string {
const { name, description } = options; const { name, description } = options;
const typeName = name.charAt(0).toUpperCase() + name.slice(1); const typeName = name.charAt(0).toUpperCase() + name.slice(1);
return `import { useState } from 'react'; return `import React, { useState, useEffect } from 'react';
import { Card, Table, Button, Space, Modal, message, Form, Input } from 'antd'; import { PageContainer } from '@/components/ui/page-container';
import type { ${typeName}Response, ${typeName}Query, ${typeName}Request } from './types'; import {
import * as service from './service'; PlusOutlined,
import { useRequest } from 'ahooks'; EditOutlined,
DeleteOutlined,
} from '@ant-design/icons';
import {
Table,
TableHeader,
TableBody,
TableHead,
TableRow,
TableCell,
} from "@/components/ui/table";
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import { useToast } from "@/components/ui/use-toast";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { searchFormSchema, type SearchFormValues } from "@/pages/${name}/List/schema";
import { DataTablePagination } from "@/components/ui/pagination";
import type { ${typeName}Response, ${typeName}Query } from '@/pages/${name}/List/types';
import { get${typeName}Page, delete${typeName} } from '@/pages/${name}/List/service';
import ${typeName}Modal from '@/pages/${name}/List/components/${typeName}Modal';
const ${typeName}Page = () => { interface Column {
const [query, setQuery] = useState<${typeName}Query>({}); accessorKey?: keyof ${typeName}Response;
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]); id?: string;
const [editModalVisible, setEditModalVisible] = useState(false); header: string;
const [editingRecord, setEditingRecord] = useState<${typeName}Response | null>(null); size: number;
const [form] = Form.useForm(); cell?: (props: { row: { original: ${typeName}Response } }) => React.ReactNode;
}
// 获取列表数据 const ${typeName}List: React.FC = () => {
const { data, loading, refresh } = useRequest(() => service.getList(query), { const [modalVisible, setModalVisible] = useState(false);
refreshDeps: [query] const [currentRecord, setCurrentRecord] = useState<${typeName}Response>();
}); const [list, setList] = useState<${typeName}Response[]>([]);
const [loading, setLoading] = useState(false);
// 删除操作 const [pagination, setPagination] = useState({
const handleDelete = async (id: number) => { pageNum: 1,
Modal.confirm({ pageSize: 10,
title: '确认删除', totalElements: 0,
content: '确定要删除这条记录吗?',
onOk: async () => {
try {
await service.remove(id);
message.success('删除成功');
refresh();
} catch (error) {
message.error('删除失败');
}
}
}); });
}; const { toast } = useToast();
// 批量删除 const form = useForm<SearchFormValues>({
const handleBatchDelete = () => { resolver: zodResolver(searchFormSchema),
if (!selectedRowKeys.length) { defaultValues: {
message.warning('请选择要删除的记录'); name: "",
return; enabled: undefined,
}
Modal.confirm({
title: '确认删除',
content: \`确定要删除这\${selectedRowKeys.length}条记录吗?\`,
onOk: async () => {
try {
await service.batchRemove(selectedRowKeys);
message.success('删除成功');
setSelectedRowKeys([]);
refresh();
} catch (error) {
message.error('删除失败');
} }
}
}); });
};
// 打开编辑弹窗 const loadData = async (params?: ${typeName}Query) => {
const handleEdit = async (id: number) => { setLoading(true);
try { try {
const detail = await service.getDetail(id); const queryParams: ${typeName}Query = {
setEditingRecord(detail); ...params,
form.setFieldsValue(detail); pageNum: pagination.pageNum,
setEditModalVisible(true); pageSize: pagination.pageSize,
} catch (error) { };
message.error('获取详情失败'); const data = await get${typeName}Page(queryParams);
} setList(data.content || []);
}; setPagination({
...pagination,
totalElements: data.totalElements,
});
} catch (error) {
toast({
variant: "destructive",
title: "获取列表失败",
duration: 3000,
});
} finally {
setLoading(false);
}
};
// 打开新增弹窗 const handlePageChange = (page: number) => {
const handleAdd = () => { setPagination({
setEditingRecord(null); ...pagination,
form.resetFields(); pageNum: page,
setEditModalVisible(true); });
}; };
// 保存表单 useEffect(() => {
const handleSave = async () => { loadData(form.getValues());
try { }, [pagination.pageNum, pagination.pageSize]);
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('操作失败');
}
};
const columns = [ const handleDelete = async (id: number) => {
{ try {
title: '名称', await delete${typeName}(id);
dataIndex: 'name', toast({
key: 'name', title: "删除成功",
}, duration: 3000,
{ });
title: '创建时间', loadData(form.getValues());
dataIndex: 'createTime', } catch (error) {
key: 'createTime', toast({
}, variant: "destructive",
{ title: "删除失败",
title: '操作', duration: 3000,
key: 'action', });
render: (_, record: ${typeName}Response) => ( }
<Space> };
<Button type="link" onClick={() => handleEdit(record.id)}></Button>
<Button type="link" danger onClick={() => handleDelete(record.id)}></Button>
</Space>
),
},
];
return ( const handleAdd = () => {
<> setCurrentRecord(undefined);
<Card title="${description}" extra={ setModalVisible(true);
<Space> };
<Button type="primary" onClick={handleAdd}></Button>
<Button danger onClick={handleBatchDelete}></Button>
</Space>
}>
<Form layout="inline" style={{ marginBottom: 16 }}>
<Form.Item label="名称" name="name">
<Input placeholder="请输入名称"
onChange={e => setQuery(prev => ({ ...prev, name: e.target.value }))}
/>
</Form.Item>
</Form>
<Table
rowKey="id"
columns={columns}
dataSource={data}
loading={loading}
rowSelection={{
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys as number[]),
}}
/>
</Card>
<Modal const handleEdit = (record: ${typeName}Response) => {
title={editingRecord ? '编辑' : '新增'} setCurrentRecord(record);
open={editModalVisible} setModalVisible(true);
onOk={handleSave} };
onCancel={() => setEditModalVisible(false)}
> const handleModalClose = () => {
<Form form={form} layout="vertical"> setModalVisible(false);
<Form.Item setCurrentRecord(undefined);
label="名称" };
name="name"
rules={[{ required: true, message: '请输入名称' }]} const handleSuccess = () => {
> setModalVisible(false);
<Input placeholder="请输入名称" /> setCurrentRecord(undefined);
</Form.Item> loadData(form.getValues());
{/* TODO: 添加其他表单项 */} };
</Form>
</Modal> const handleReset = () => {
</> form.reset({
); name: "",
enabled: undefined,
});
loadData();
};
const columns: Column[] = [
{
accessorKey: 'name',
header: '名称',
size: 180,
},
{
accessorKey: 'description',
header: '描述',
size: 200,
},
{
accessorKey: 'enabled',
header: '状态',
size: 100,
cell: ({row}) => (
<Badge variant={row.original.enabled ? "outline" : "secondary"}>
{row.original.enabled ? '启用' : '禁用'}
</Badge>
),
},
{
accessorKey: 'sort',
header: '排序',
size: 80,
},
{
accessorKey: 'createTime',
header: '创建时间',
size: 180,
},
{
id: 'actions',
header: '操作',
size: 180,
cell: ({row}) => (
<div className="flex items-center gap-2">
<Button
variant="ghost"
size="sm"
onClick={() => handleEdit(row.original)}
>
<EditOutlined className="mr-1"/>
</Button>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button
variant="ghost"
size="sm"
className="text-destructive"
>
<DeleteOutlined className="mr-1"/>
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle></AlertDialogTitle>
<AlertDialogDescription>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel></AlertDialogCancel>
<AlertDialogAction
onClick={() => handleDelete(row.original.id)}
>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
),
},
];
return (
<PageContainer>
<div className="flex items-center justify-between">
<h2 className="text-3xl font-bold tracking-tight">${description}</h2>
<div className="flex items-center gap-4">
<Button onClick={handleAdd}>
<PlusOutlined className="mr-1"/>
</Button>
</div>
</div>
<Card>
<div className="p-6">
<div className="flex items-center gap-4">
<Input
placeholder="名称"
{...form.register('name')}
className="max-w-[200px]"
/>
<Select
value={form.getValues('enabled')?.toString()}
onValueChange={(value) => form.setValue('enabled', value === 'true')}
>
<SelectTrigger className="max-w-[200px]">
<SelectValue placeholder="状态"/>
</SelectTrigger>
<SelectContent>
<SelectItem value="true"></SelectItem>
<SelectItem value="false"></SelectItem>
</SelectContent>
</Select>
<Button variant="outline" onClick={handleReset}>
</Button>
<Button onClick={() => loadData(form.getValues())}>
</Button>
</div>
</div>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle></CardTitle>
</CardHeader>
<CardContent>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
{columns.map((column) => (
<TableHead
key={column.accessorKey || column.id}
style={{width: column.size}}
>
{column.header}
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{list.map((item) => (
<TableRow key={item.id}>
{columns.map((column) => (
<TableCell
key={column.accessorKey || column.id}
>
{column.cell
? column.cell({row: {original: item}})
: item[column.accessorKey!]}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
<div className="flex justify-end border-t border-border bg-muted/40">
<DataTablePagination
pageIndex={pagination.pageNum}
pageSize={pagination.pageSize}
pageCount={Math.ceil(pagination.totalElements / pagination.pageSize)}
onPageChange={handlePageChange}
/>
</div>
</div>
</CardContent>
</Card>
{modalVisible && (
<${typeName}Modal
open={modalVisible}
onCancel={handleModalClose}
onSuccess={handleSuccess}
initialValues={currentRecord}
/>
)}
</PageContainer>
);
}; };
export default ${typeName}Page; export default ${typeName}List;
`; `;
} }
// 生成文件 // 生成文件
function generateFiles(options: GenerateOptions) { async function generateFiles(options: GenerateOptions) {
const { name } = options; const { name, pageType = 'list' } = options;
const basePath = path.join(process.cwd(), 'src/pages', name); const basePath = join(process.cwd(), 'src/pages', name, pageType);
const componentsPath = join(basePath, 'components');
// 创建目录 // 创建目录
if (!fs.existsSync(basePath)) { await fs.mkdir(basePath, { recursive: true });
fs.mkdirSync(basePath, { recursive: true }); await fs.mkdir(componentsPath, { recursive: true });
}
// 生成文件 // 生成文件
fs.writeFileSync(path.join(basePath, 'types.ts'), generateTypes(options)); switch (pageType) {
fs.writeFileSync(path.join(basePath, 'service.ts'), generateService(options)); case 'list':
fs.writeFileSync(path.join(basePath, 'index.tsx'), generatePage(options)); await fs.writeFile(join(basePath, 'types.ts'), generateTypes(options));
await fs.writeFile(join(basePath, 'schema.ts'), generateSchema(options));
console.log(`Successfully generated files for module "${name}" in ${basePath}`); await fs.writeFile(join(basePath, 'service.ts'), generateService(options));
await fs.writeFile(join(basePath, 'index.tsx'), generateListPage(options));
await fs.writeFile(
join(componentsPath, `${options.name.charAt(0).toUpperCase() + options.name.slice(1)}Modal.tsx`),
generateModal(options)
);
break;
case 'detail':
case 'form':
// 未来实现
break;
}
} }
// 使用示例 // 主函数
const options: GenerateOptions = { async function generate(options: GenerateOptions) {
name: process.argv[2], try {
description: process.argv[3] || '管理', await generateFiles(options);
baseUrl: process.argv[4] || `/api/v1/${process.argv[2]}`, console.log('✨ 页面生成成功!');
} catch (error) {
console.error('❌ 页面生成失败:', error);
}
}
// 创建命令行交互界面
const rl = createInterface({
input: process.stdin,
output: process.stdout
});
// 提示用户输入
const prompt = (question: string): Promise<string> => {
return new Promise((resolve) => {
rl.question(question, (answer) => {
resolve(answer);
});
});
}; };
if (!options.name) { // 交互式生成页面
console.error('Please provide a module name!'); async function generateInteractive() {
process.exit(1); try {
console.log('👋 欢迎使用页面生成器!');
console.log('-------------------');
// 获取模块名称
const name = await prompt('请输入模块名称user: ');
if (!name) {
throw new Error('模块名称不能为空!');
}
// 获取模块描述
const description = await prompt('请输入模块描述(如:用户管理): ');
if (!description) {
throw new Error('模块描述不能为空!');
}
// 获取API路径
const defaultBaseUrl = `/api/v1/${name.toLowerCase()}`;
const baseUrl = await prompt(`请输入API路径 (默认: ${defaultBaseUrl}): `) || defaultBaseUrl;
// 获取页面类型(预留)
const pageType = 'list'; // 目前固定为list
// 生成页面
generate({
name,
description,
baseUrl,
pageType,
});
console.log('');
console.log('✨ 页面生成成功!');
console.log('📁 生成的文件位置:');
console.log(`src/pages/${name}/list/`);
console.log('');
console.log('🎉 包含以下文件:');
console.log('- types.ts');
console.log('- schema.ts');
console.log('- service.ts');
console.log('- index.tsx');
console.log(`- components/${name.charAt(0).toUpperCase() + name.slice(1)}Modal.tsx`);
} catch (error) {
console.error('❌ 页面生成失败:', error);
} finally {
rl.close();
}
} }
generateFiles(options); // 根据命令行参数判断是否使用交互模式
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const args = process.argv.slice(2);
if (args.length === 0) {
// 无参数时使用交互模式
generateInteractive();
} else {
// 有参数时使用命令行模式
generate({
name: args[0],
description: args[1] || '管理',
baseUrl: args[2] || `/api/v1/${args[0]}`,
pageType: 'list',
});
}
}
export { generate, type GenerateOptions };

View File

@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"outDir": "../dist/scripts",
"baseUrl": ".",
"paths": {
"@/*": ["../src/*"]
}
},
"include": ["./**/*"],
"exclude": ["node_modules"]
}

View File

@ -15,7 +15,6 @@ import {getProjectGroupList} from '../../ProjectGroup/List/service';
import type {Application, ApplicationQuery} from './types'; import type {Application, ApplicationQuery} from './types';
import {DevelopmentLanguageTypeEnum} from './types'; import {DevelopmentLanguageTypeEnum} from './types';
import type {ProjectGroup} from '../../ProjectGroup/List/types'; import type {ProjectGroup} from '../../ProjectGroup/List/types';
import {ProjectGroupTypeEnum} from '../../ProjectGroup/List/types';
import {getProjectTypeInfo} from '../../ProjectGroup/List/utils'; import {getProjectTypeInfo} from '../../ProjectGroup/List/utils';
import ApplicationModal from './components/ApplicationModal'; import ApplicationModal from './components/ApplicationModal';
import { import {
@ -33,13 +32,6 @@ import {
CardTitle, CardTitle,
} from "@/components/ui/card"; } from "@/components/ui/card";
import {Button} from "@/components/ui/button"; import {Button} from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
} from "@/components/ui/form";
import {Input} from "@/components/ui/input"; import {Input} from "@/components/ui/input";
import { import {
Select, Select,