311 lines
7.4 KiB
JavaScript
311 lines
7.4 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// 模块名称(首字母大写)
|
|
const moduleName = process.argv[2];
|
|
if (!moduleName) {
|
|
console.error('请提供模块名称');
|
|
process.exit(1);
|
|
}
|
|
|
|
// 模块路径
|
|
const modulePath = path.join(__dirname, '../src/pages/System', moduleName);
|
|
|
|
// 创建目录结构
|
|
const directories = [
|
|
'',
|
|
'components',
|
|
'hooks',
|
|
'styles'
|
|
];
|
|
|
|
// 创建目录
|
|
directories.forEach(dir => {
|
|
const dirPath = path.join(modulePath, dir);
|
|
if (!fs.existsSync(dirPath)) {
|
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
}
|
|
});
|
|
|
|
// 创建基础文件
|
|
const files = {
|
|
// 类型定义
|
|
'types.ts': `import type { BaseResponse } from '@/types/base/response';
|
|
import type { BaseQuery } from '@/types/base/query';
|
|
|
|
// 查询参数
|
|
export interface ${moduleName}Query extends BaseQuery {
|
|
// TODO: 添加查询参数
|
|
}
|
|
|
|
// 请求参数
|
|
export interface ${moduleName}Request {
|
|
// TODO: 添加请求参数
|
|
}
|
|
|
|
// 响应类型
|
|
export interface ${moduleName}Response extends BaseResponse {
|
|
// TODO: 添加响应字段
|
|
}
|
|
`,
|
|
|
|
// API 服务
|
|
'service.ts': `import request from '@/utils/request';
|
|
import type { ${moduleName}Response, ${moduleName}Request, ${moduleName}Query } from './types';
|
|
import type { Page } from '@/types/base/page';
|
|
|
|
const BASE_URL = '/api/v1/${moduleName.toLowerCase()}';
|
|
|
|
// 获取列表(分页)
|
|
export const get${moduleName}s = async (params?: ${moduleName}Query) =>
|
|
request.get<Page<${moduleName}Response>>(\`\${BASE_URL}/page\`, { params });
|
|
|
|
// 创建
|
|
export const create${moduleName} = async (data: ${moduleName}Request) =>
|
|
request.post<${moduleName}Response>(BASE_URL, data);
|
|
|
|
// 更新
|
|
export const update${moduleName} = async (id: number, data: ${moduleName}Request) =>
|
|
request.put<${moduleName}Response>(\`\${BASE_URL}/\${id}\`, data);
|
|
|
|
// 删除
|
|
export const delete${moduleName} = async (id: number) =>
|
|
request.delete(\`\${BASE_URL}/\${id}\`);
|
|
`,
|
|
|
|
// 主页面组件
|
|
'index.tsx': `import React from 'react';
|
|
import { Card } from 'antd';
|
|
import type { ${moduleName}Response } from './types';
|
|
import { use${moduleName}Data } from './hooks/use${moduleName}Data';
|
|
import ${moduleName}Table from './components/${moduleName}Table';
|
|
import ${moduleName}Form from './components/${moduleName}Form';
|
|
import styles from './styles/index.module.css';
|
|
|
|
const ${moduleName}: React.FC = () => {
|
|
const {
|
|
list,
|
|
pagination,
|
|
loading,
|
|
selectedRows,
|
|
handleCreate,
|
|
handleUpdate,
|
|
handleDelete,
|
|
handleSelectionChange
|
|
} = use${moduleName}Data();
|
|
|
|
return (
|
|
<Card title="${moduleName} 管理" className={styles.container}>
|
|
<${moduleName}Form onSubmit={handleCreate} />
|
|
<${moduleName}Table
|
|
loading={loading}
|
|
dataSource={list}
|
|
pagination={pagination}
|
|
selectedRows={selectedRows}
|
|
onDelete={handleDelete}
|
|
onUpdate={handleUpdate}
|
|
onSelectionChange={handleSelectionChange}
|
|
/>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export default ${moduleName};
|
|
`,
|
|
|
|
// 表格组件
|
|
'components/${moduleName}Table.tsx': `import React from 'react';
|
|
import { Table, Space, Button, Popconfirm } from 'antd';
|
|
import type { ${moduleName}Response } from '../types';
|
|
import styles from '../styles/table.module.css';
|
|
|
|
interface ${moduleName}TableProps {
|
|
loading: boolean;
|
|
dataSource: ${moduleName}Response[];
|
|
pagination: {
|
|
current: number;
|
|
pageSize: number;
|
|
total: number;
|
|
};
|
|
selectedRows: ${moduleName}Response[];
|
|
onDelete: (id: number) => Promise<void>;
|
|
onUpdate: (id: number, data: Partial<${moduleName}Response>) => Promise<void>;
|
|
onSelectionChange: (selectedRows: ${moduleName}Response[]) => void;
|
|
}
|
|
|
|
const ${moduleName}Table: React.FC<${moduleName}TableProps> = ({
|
|
loading,
|
|
dataSource,
|
|
pagination,
|
|
selectedRows,
|
|
onDelete,
|
|
onUpdate,
|
|
onSelectionChange
|
|
}) => {
|
|
const columns = [
|
|
// TODO: 添加列定义
|
|
{
|
|
title: '操作',
|
|
key: 'action',
|
|
render: (_, record: ${moduleName}Response) => (
|
|
<Space size="middle">
|
|
<Button type="link" onClick={() => onUpdate(record.id, record)}>
|
|
编辑
|
|
</Button>
|
|
<Popconfirm
|
|
title="确定要删除吗?"
|
|
onConfirm={() => onDelete(record.id)}
|
|
>
|
|
<Button type="link" danger>
|
|
删除
|
|
</Button>
|
|
</Popconfirm>
|
|
</Space>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<Table
|
|
className={styles.table}
|
|
rowKey="id"
|
|
loading={loading}
|
|
dataSource={dataSource}
|
|
columns={columns}
|
|
pagination={pagination}
|
|
rowSelection={{
|
|
selectedRowKeys: selectedRows.map(row => row.id),
|
|
onChange: (_, rows) => onSelectionChange(rows),
|
|
}}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default ${moduleName}Table;
|
|
`,
|
|
|
|
// 表单组件
|
|
'components/${moduleName}Form.tsx': `import React from 'react';
|
|
import { Form, Input, Button } from 'antd';
|
|
import type { ${moduleName}Request } from '../types';
|
|
import styles from '../styles/form.module.css';
|
|
|
|
interface ${moduleName}FormProps {
|
|
initialValues?: Partial<${moduleName}Request>;
|
|
onSubmit: (values: ${moduleName}Request) => Promise<void>;
|
|
}
|
|
|
|
const ${moduleName}Form: React.FC<${moduleName}FormProps> = ({
|
|
initialValues,
|
|
onSubmit
|
|
}) => {
|
|
const [form] = Form.useForm();
|
|
|
|
const handleSubmit = async () => {
|
|
const values = await form.validateFields();
|
|
await onSubmit(values);
|
|
form.resetFields();
|
|
};
|
|
|
|
return (
|
|
<Form
|
|
form={form}
|
|
layout="inline"
|
|
initialValues={initialValues}
|
|
className={styles.form}
|
|
>
|
|
{/* TODO: 添加表单项 */}
|
|
<Form.Item>
|
|
<Button type="primary" onClick={handleSubmit}>
|
|
提交
|
|
</Button>
|
|
</Form.Item>
|
|
</Form>
|
|
);
|
|
};
|
|
|
|
export default ${moduleName}Form;
|
|
`,
|
|
|
|
// 自定义 Hook
|
|
'hooks/use${moduleName}Data.ts': `import { useState, useCallback } from 'react';
|
|
import type { ${moduleName}Response, ${moduleName}Request } from '../types';
|
|
import { useTableData } from '@/hooks/useTableData';
|
|
import * as service from '../service';
|
|
|
|
export const use${moduleName}Data = () => {
|
|
const [selectedRows, setSelectedRows] = useState<${moduleName}Response[]>([]);
|
|
|
|
const {
|
|
list,
|
|
pagination,
|
|
loading,
|
|
loadData,
|
|
handleCreate,
|
|
handleUpdate,
|
|
handleDelete
|
|
} = useTableData<${moduleName}Response>({
|
|
service: {
|
|
baseUrl: '/api/v1/${moduleName.toLowerCase()}'
|
|
}
|
|
});
|
|
|
|
const handleSelectionChange = useCallback((rows: ${moduleName}Response[]) => {
|
|
setSelectedRows(rows);
|
|
}, []);
|
|
|
|
return {
|
|
list,
|
|
pagination,
|
|
loading,
|
|
selectedRows,
|
|
handleCreate,
|
|
handleUpdate,
|
|
handleDelete,
|
|
handleSelectionChange
|
|
};
|
|
};
|
|
`,
|
|
|
|
// 样式文件
|
|
'styles/index.module.css': `.container {
|
|
padding: 24px;
|
|
}
|
|
`,
|
|
|
|
'styles/table.module.css': `.table {
|
|
margin-top: 16px;
|
|
}
|
|
`,
|
|
|
|
'styles/form.module.css': `.form {
|
|
margin-bottom: 16px;
|
|
}
|
|
`
|
|
};
|
|
|
|
// 创建文件
|
|
Object.entries(files).forEach(([filename, content]) => {
|
|
const filePath = path.join(modulePath, filename);
|
|
if (!fs.existsSync(filePath)) {
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
fs.writeFileSync(filePath, content);
|
|
}
|
|
});
|
|
|
|
console.log(`模块 ${moduleName} 创建成功!`);
|
|
console.log(`
|
|
请确保在路由配置文件 src/router/index.tsx 中添加以下路由:
|
|
|
|
{
|
|
path: 'system/${moduleName.toLowerCase()}',
|
|
element: (
|
|
<Suspense fallback={<LoadingComponent />}>
|
|
<${moduleName} />
|
|
</Suspense>
|
|
)
|
|
}
|
|
|
|
并添加懒加载导入:
|
|
const ${moduleName} = lazy(() => import('../pages/System/${moduleName}'));
|
|
`);
|