refactor(services): 重构服务文件结构,将服务按功能分类到不同目录
- 将服务文件按功能分类到core、ai、analytics、security等目录 - 修复logger导入路径问题,统一使用相对路径 - 更新相关文件的导入路径引用 - 添加新的批量操作组件导出文件 - 修复dashboard页面中的类型错误 - 添加dotenv依赖到package.json
This commit is contained in:
293
dashboard/generate-pages.js
Normal file
293
dashboard/generate-pages.js
Normal file
@@ -0,0 +1,293 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const pages = [
|
||||
{ name: 'Audit', route: 'audit', api: '/api/audit', description: '审计服务' },
|
||||
{ name: 'Chatbot', route: 'chatbot', api: '/api/chatbot', description: '聊天机器人' },
|
||||
{ name: 'Command', route: 'command', api: '/api/command', description: '命令服务' },
|
||||
{ name: 'Creative', route: 'creative', api: '/api/creative', description: '创意服务' },
|
||||
{ name: 'Customer', route: 'customer', api: '/api/customer', description: '客户服务' },
|
||||
{ name: 'Governance', route: 'governance', api: '/api/governance', description: '治理服务' },
|
||||
{ name: 'Monitoring', route: 'monitoring', api: '/api/monitoring', description: '监控服务' },
|
||||
{ name: 'NLP', route: 'nlp', api: '/api/nlp', description: '自然语言处理' },
|
||||
{ name: 'Omnichannel', route: 'omnichannel', api: '/api/omnichannel', description: '全渠道服务' },
|
||||
{ name: 'OrderFulfillment', route: 'order-fulfillment', api: '/api/orderFulfillment', description: '订单履约' },
|
||||
{ name: 'Recommendation', route: 'recommendation', api: '/api/recommendation', description: '推荐服务' },
|
||||
{ name: 'Sovereignty', route: 'sovereignty', api: '/api/sovereignty', description: '主权服务' },
|
||||
{ name: 'Sync', route: 'sync', api: '/api/sync', description: '同步服务' },
|
||||
{ name: 'Telemetry', route: 'telemetry', api: '/api/telemetry', description: '遥测服务' },
|
||||
{ name: 'Trace', route: 'trace', api: '/api/trace', description: '追踪服务' },
|
||||
{ name: 'Vault', route: 'vault', api: '/api/vault', description: '密钥库' },
|
||||
{ name: 'Webhook', route: 'webhook', api: '/api/webhook', description: 'Webhook服务' },
|
||||
];
|
||||
|
||||
const generatePage = (page) => {
|
||||
const componentTemplate = `import React, { useState, useEffect } from 'react';
|
||||
import { Card, Table, Button, Space, Input, message, Tag, Modal, Form, Select, DatePicker, Row, Col, Statistic } from 'antd';
|
||||
import { ReloadOutlined, PlusOutlined, SearchOutlined } from '@ant-design/icons';
|
||||
import { ${page.name}DataSource } from '@/services/${page.route}DataSource';
|
||||
import type { ${page.name}Item } from '@/services/${page.route}DataSource';
|
||||
|
||||
const { Option } = Select;
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const ${page.name}Page: React.FC = () => {
|
||||
const [data, setData] = useState<${page.name}Item[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
const loadData = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await ${page.name}DataSource.list();
|
||||
setData(result);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
message.error(\`加载失败: \${errorMessage}\`);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreate = async (values: any) => {
|
||||
try {
|
||||
await ${page.name}DataSource.create(values);
|
||||
message.success('创建成功');
|
||||
setModalVisible(false);
|
||||
form.resetFields();
|
||||
loadData();
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
message.error(\`创建失败: \${errorMessage}\`);
|
||||
}
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
render: (status: string) => {
|
||||
const color = status === 'ACTIVE' ? 'green' : status === 'INACTIVE' ? 'red' : 'default';
|
||||
return <Tag color={color}>{status}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
key: 'createdAt',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 150,
|
||||
render: (_: any, record: ${page.name}Item) => (
|
||||
<Space>
|
||||
<Button type="link" size="small">查看</Button>
|
||||
<Button type="link" size="small">编辑</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card>
|
||||
<Row gutter={16} style={{ marginBottom: 16 }}>
|
||||
<Col span={6}>
|
||||
<Statistic title="总数" value={data.length} />
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<Statistic
|
||||
title="活跃"
|
||||
value={data.filter(item => item.status === 'ACTIVE').length}
|
||||
valueStyle={{ color: '#3f8600' }}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<Space>
|
||||
<Input
|
||||
placeholder="搜索..."
|
||||
prefix={<SearchOutlined />}
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
style={{ width: 200 }}
|
||||
/>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={() => setModalVisible(true)}>
|
||||
新建
|
||||
</Button>
|
||||
<Button icon={<ReloadOutlined />} onClick={loadData}>
|
||||
刷新
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={data.filter(item =>
|
||||
item.name?.toLowerCase().includes(searchText.toLowerCase())
|
||||
)}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
pagination={{ pageSize: 20 }}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
title="新建"
|
||||
open={modalVisible}
|
||||
onCancel={() => setModalVisible(false)}
|
||||
onOk={() => form.submit()}
|
||||
>
|
||||
<Form form={form} layout="vertical" onFinish={handleCreate}>
|
||||
<Form.Item name="name" label="名称" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入名称" />
|
||||
</Form.Item>
|
||||
<Form.Item name="status" label="状态" rules={[{ required: true }]}>
|
||||
<Select placeholder="请选择状态">
|
||||
<Option value="ACTIVE">活跃</Option>
|
||||
<Option value="INACTIVE">非活跃</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ${page.name}Page;
|
||||
`;
|
||||
|
||||
return componentTemplate;
|
||||
};
|
||||
|
||||
const generateDataSource = (page) => {
|
||||
const dataSourceTemplate = `import { http } from './http';
|
||||
|
||||
export interface ${page.name}Item {
|
||||
id: string;
|
||||
name: string;
|
||||
status: string;
|
||||
createdAt: string;
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
export interface ${page.name}DataSource {
|
||||
list(): Promise<${page.name}Item[]>;
|
||||
create(data: Partial<${page.name}Item>): Promise<${page.name}Item>;
|
||||
update(id: string, data: Partial<${page.name}Item>): Promise<${page.name}Item>;
|
||||
delete(id: string): Promise<void>;
|
||||
}
|
||||
|
||||
class ${page.name}ApiDataSource implements ${page.name}DataSource {
|
||||
async list() {
|
||||
const response = await http.get('${page.api}/list');
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async create(data: Partial<${page.name}Item>) {
|
||||
const response = await http.post('${page.api}', data);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<${page.name}Item>) {
|
||||
const response = await http.put(\`${page.api}/\${id}\`, data);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
async delete(id: string) {
|
||||
await http.delete(\`${page.api}/\${id}\`);
|
||||
}
|
||||
}
|
||||
|
||||
class ${page.name}MockDataSource implements ${page.name}DataSource {
|
||||
private items: ${page.name}Item[] = [
|
||||
{ id: '1', name: '示例项目 1', status: 'ACTIVE', createdAt: new Date().toISOString() },
|
||||
{ id: '2', name: '示例项目 2', status: 'INACTIVE', createdAt: new Date().toISOString() },
|
||||
];
|
||||
|
||||
async list() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
async create(data: Partial<${page.name}Item>) {
|
||||
const item: ${page.name}Item = {
|
||||
id: String(this.items.length + 1),
|
||||
name: data.name || '',
|
||||
status: data.status || 'ACTIVE',
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
this.items.push(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<${page.name}Item>) {
|
||||
const index = this.items.findIndex(item => item.id === id);
|
||||
if (index >= 0) {
|
||||
this.items[index] = { ...this.items[index], ...data };
|
||||
return this.items[index];
|
||||
}
|
||||
throw new Error('Item not found');
|
||||
}
|
||||
|
||||
async delete(id: string) {
|
||||
const index = this.items.findIndex(item => item.id === id);
|
||||
if (index >= 0) {
|
||||
this.items.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const useMock = process.env.REACT_APP_USE_MOCK === 'true';
|
||||
export const ${page.name}DataSource: ${page.name}DataSource = useMock
|
||||
? new ${page.name}MockDataSource()
|
||||
: new ${page.name}ApiDataSource();
|
||||
`;
|
||||
|
||||
return dataSourceTemplate;
|
||||
};
|
||||
|
||||
const dashboardPath = 'd:\\trae_projects\\makemd\\makemd\\dashboard\\src';
|
||||
|
||||
pages.forEach(page => {
|
||||
const pageDir = path.join(dashboardPath, 'pages', page.name);
|
||||
const pageFile = path.join(pageDir, 'index.tsx');
|
||||
const dataSourceFile = path.join(dashboardPath, 'services', `${page.route}DataSource.ts`);
|
||||
|
||||
if (!fs.existsSync(pageDir)) {
|
||||
fs.mkdirSync(pageDir, { recursive: true });
|
||||
console.log(`Created directory: ${pageDir}`);
|
||||
}
|
||||
|
||||
fs.writeFileSync(pageFile, generatePage(page), 'utf8');
|
||||
console.log(`Created page: ${pageFile}`);
|
||||
|
||||
fs.writeFileSync(dataSourceFile, generateDataSource(page), 'utf8');
|
||||
console.log(`Created data source: ${dataSourceFile}`);
|
||||
});
|
||||
|
||||
console.log('\nAll pages and data sources generated successfully!');
|
||||
console.log('\nNext steps:');
|
||||
console.log('1. Add routes to the router configuration');
|
||||
console.log('2. Add menu items to the navigation');
|
||||
console.log('3. Implement backend API endpoints if not exists');
|
||||
Reference in New Issue
Block a user