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, description } = options; const { name } = options;
const typeName = name.charAt(0).toUpperCase() + name.slice(1); 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 = () => { return `import React, { useEffect } from 'react';
const [query, setQuery] = useState<${typeName}Query>({}); import type { ${typeName}Response } from '@/pages/${name}/List/types';
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]); import { create${typeName}, update${typeName} } from '@/pages/${name}/List/service';
const [editModalVisible, setEditModalVisible] = useState(false); import {
const [editingRecord, setEditingRecord] = useState<${typeName}Response | null>(null); Dialog,
const [form] = Form.useForm(); 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 {
const { data, loading, refresh } = useRequest(() => service.getList(query), { open: boolean;
refreshDeps: [query] onCancel: () => void;
}); onSuccess: () => void;
initialValues?: ${typeName}Response;
}
// 删除操作 const ${typeName}Modal: React.FC<${typeName}ModalProps> = ({
const handleDelete = async (id: number) => { open,
Modal.confirm({ onCancel,
title: '确认删除', onSuccess,
content: '确定要删除这条记录吗?', initialValues,
onOk: async () => { }) => {
try { const { toast } = useToast();
await service.remove(id); const isEdit = !!initialValues?.id;
message.success('删除成功');
refresh(); const form = useForm<${typeName}FormValues>({
} catch (error) { resolver: zodResolver(${typeName.toLowerCase()}FormSchema),
message.error('删除失败'); defaultValues: {
} name: "",
} description: "",
enabled: true,
sort: 0,
},
}); });
};
// 批量删除 useEffect(() => {
const handleBatchDelete = () => { if (initialValues) {
if (!selectedRowKeys.length) { form.reset({
message.warning('请选择要删除的记录'); name: initialValues.name,
return; description: initialValues.description || "",
} enabled: initialValues.enabled,
Modal.confirm({ sort: initialValues.sort,
title: '确认删除', });
content: \`确定要删除这\${selectedRowKeys.length}条记录吗?\`,
onOk: async () => {
try {
await service.batchRemove(selectedRowKeys);
message.success('删除成功');
setSelectedRowKeys([]);
refresh();
} catch (error) {
message.error('删除失败');
} }
} }, [initialValues, form]);
});
};
// 打开编辑弹窗 const handleSubmit = async (values: ${typeName}FormValues) => {
const handleEdit = async (id: number) => { try {
try { if (isEdit) {
const detail = await service.getDetail(id); await update${typeName}(initialValues.id, values);
setEditingRecord(detail); } else {
form.setFieldsValue(detail); await create${typeName}(values);
setEditModalVisible(true); }
} catch (error) { toast({
message.error('获取详情失败'); title: \`\${isEdit ? '更新' : '创建'}成功\`,
} duration: 3000,
}; });
form.reset();
onSuccess();
} catch (error) {
toast({
variant: "destructive",
title: \`\${isEdit ? '更新' : '创建'}失败\`,
description: error instanceof Error ? error.message : undefined,
duration: 3000,
});
}
};
// 打开新增弹窗 return (
const handleAdd = () => { <Dialog open={open} onOpenChange={(open) => !open && onCancel()}>
setEditingRecord(null); <DialogContent className="sm:max-w-[600px]">
form.resetFields(); <DialogHeader>
setEditModalVisible(true); <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
const handleSave = async () => { control={form.control}
try { name="description"
const values = await form.validateFields(); render={({field}) => (
if (editingRecord) { <FormItem>
await service.update(editingRecord.id, values); <FormLabel></FormLabel>
message.success('更新成功'); <FormControl>
} else { <Textarea
await service.create(values); {...field}
message.success('创建成功'); placeholder="请输入描述"
} rows={4}
setEditModalVisible(false); />
refresh(); </FormControl>
} catch (error) { <FormMessage/>
message.error('操作失败'); </FormItem>
} )}
}; />
const columns = [ <FormField
{ control={form.control}
title: '名称', name="enabled"
dataIndex: 'name', render={({field}) => (
key: 'name', <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
}, <div className="space-y-0.5">
{ <FormLabel></FormLabel>
title: '创建时间', </div>
dataIndex: 'createTime', <FormControl>
key: 'createTime', <Switch
}, checked={field.value}
{ onCheckedChange={field.onChange}
title: '操作', />
key: 'action', </FormControl>
render: (_, record: ${typeName}Response) => ( </FormItem>
<Space> )}
<Button type="link" onClick={() => handleEdit(record.id)}></Button> />
<Button type="link" danger onClick={() => handleDelete(record.id)}></Button>
</Space>
),
},
];
return ( <FormField
<> control={form.control}
<Card title="${description}" extra={ name="sort"
<Space> render={({field}) => (
<Button type="primary" onClick={handleAdd}></Button> <FormItem>
<Button danger onClick={handleBatchDelete}></Button> <FormLabel></FormLabel>
</Space> <FormControl>
}> <Input
<Form layout="inline" style={{ marginBottom: 16 }}> {...field}
<Form.Item label="名称" name="name"> type="number"
<Input placeholder="请输入名称" min={0}
onChange={e => setQuery(prev => ({ ...prev, name: e.target.value }))} onChange={(e) => field.onChange(Number(e.target.value))}
/> />
</Form.Item> </FormControl>
</Form> <FormMessage/>
<Table </FormItem>
rowKey="id" )}
columns={columns} />
dataSource={data}
loading={loading}
rowSelection={{
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys as number[]),
}}
/>
</Card>
<Modal <DialogFooter>
title={editingRecord ? '编辑' : '新增'} <Button type="button" variant="outline" onClick={onCancel}>
open={editModalVisible}
onOk={handleSave} </Button>
onCancel={() => setEditModalVisible(false)} <Button type="submit">
>
<Form form={form} layout="vertical"> </Button>
<Form.Item </DialogFooter>
label="名称" </form>
name="name" </Form>
rules={[{ required: true, message: '请输入名称' }]} </DialogContent>
> </Dialog>
<Input placeholder="请输入名称" /> );
</Form.Item>
{/* TODO: 添加其他表单项 */}
</Form>
</Modal>
</>
);
}; };
export default ${typeName}Page; export default ${typeName}Modal;
`;
}
// 生成列表页面组件
function generateListPage(options: GenerateOptions): string {
const { name, description } = options;
const typeName = name.charAt(0).toUpperCase() + name.slice(1);
return `import React, { useState, useEffect } from 'react';
import { PageContainer } from '@/components/ui/page-container';
import {
PlusOutlined,
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';
interface Column {
accessorKey?: keyof ${typeName}Response;
id?: string;
header: string;
size: number;
cell?: (props: { row: { original: ${typeName}Response } }) => React.ReactNode;
}
const ${typeName}List: React.FC = () => {
const [modalVisible, setModalVisible] = useState(false);
const [currentRecord, setCurrentRecord] = useState<${typeName}Response>();
const [list, setList] = useState<${typeName}Response[]>([]);
const [loading, setLoading] = useState(false);
const [pagination, setPagination] = useState({
pageNum: 1,
pageSize: 10,
totalElements: 0,
});
const { toast } = useToast();
const form = useForm<SearchFormValues>({
resolver: zodResolver(searchFormSchema),
defaultValues: {
name: "",
enabled: undefined,
}
});
const loadData = async (params?: ${typeName}Query) => {
setLoading(true);
try {
const queryParams: ${typeName}Query = {
...params,
pageNum: pagination.pageNum,
pageSize: pagination.pageSize,
};
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) => {
setPagination({
...pagination,
pageNum: page,
});
};
useEffect(() => {
loadData(form.getValues());
}, [pagination.pageNum, pagination.pageSize]);
const handleDelete = async (id: number) => {
try {
await delete${typeName}(id);
toast({
title: "删除成功",
duration: 3000,
});
loadData(form.getValues());
} catch (error) {
toast({
variant: "destructive",
title: "删除失败",
duration: 3000,
});
}
};
const handleAdd = () => {
setCurrentRecord(undefined);
setModalVisible(true);
};
const handleEdit = (record: ${typeName}Response) => {
setCurrentRecord(record);
setModalVisible(true);
};
const handleModalClose = () => {
setModalVisible(false);
setCurrentRecord(undefined);
};
const handleSuccess = () => {
setModalVisible(false);
setCurrentRecord(undefined);
loadData(form.getValues());
};
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}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,