refactor: 优化代码结构并修复类型问题
- 移除未使用的TabPane组件 - 修复类型定义和导入方式 - 优化mock数据源的环境变量判断逻辑 - 更新文档结构并归档旧文件 - 添加新的UI组件和Memo组件 - 调整API路径和响应处理
This commit is contained in:
201
server/src/api/routes/platform-auth.ts
Normal file
201
server/src/api/routes/platform-auth.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { PlatformAccountService } from '../../services/PlatformAccountService';
|
||||
import { requirePermission } from '../../core/guards/rbac.guard';
|
||||
import { logger } from '../../utils/logger';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/list', requirePermission('platform:read'), async (req: Request, res: Response) => {
|
||||
try {
|
||||
const tenantId = req.user?.tenantId;
|
||||
if (!tenantId) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const { platform, status, shopId } = req.query;
|
||||
const accounts = await PlatformAccountService.list(tenantId, {
|
||||
platform: platform as string,
|
||||
status: status as string,
|
||||
shopId: shopId as string,
|
||||
});
|
||||
|
||||
res.json({ success: true, data: accounts });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[PlatformAuth] List error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/stats/overview', requirePermission('platform:read'), async (req: Request, res: Response) => {
|
||||
try {
|
||||
const tenantId = req.user?.tenantId;
|
||||
if (!tenantId) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const stats = await PlatformAccountService.getStats(tenantId);
|
||||
|
||||
res.json({ success: true, data: stats });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[PlatformAuth] Stats error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:id', requirePermission('platform:read'), async (req: Request, res: Response) => {
|
||||
try {
|
||||
const id = String(req.params.id);
|
||||
const account = await PlatformAccountService.getById(id);
|
||||
|
||||
if (!account) {
|
||||
return res.status(404).json({ error: 'Account not found' });
|
||||
}
|
||||
|
||||
if (account.tenantId !== req.user?.tenantId) {
|
||||
return res.status(403).json({ error: 'Forbidden' });
|
||||
}
|
||||
|
||||
res.json({ success: true, data: account });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[PlatformAuth] Get error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/connect', requirePermission('platform:write'), async (req: Request, res: Response) => {
|
||||
try {
|
||||
const tenantId = req.user?.tenantId;
|
||||
if (!tenantId) {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
const { platform, accountName, accountId, shopId, config } = req.body;
|
||||
|
||||
if (!platform || !accountName || !accountId) {
|
||||
return res.status(400).json({ error: 'Missing required fields' });
|
||||
}
|
||||
|
||||
const account = await PlatformAccountService.create(tenantId, {
|
||||
platform,
|
||||
accountName,
|
||||
accountId,
|
||||
shopId,
|
||||
config,
|
||||
});
|
||||
|
||||
const authUrl = PlatformAccountService.generateOAuthUrl(account.id, platform);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
account,
|
||||
authUrl,
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[PlatformAuth] Connect error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/callback/:platform', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const platform = String(req.params.platform);
|
||||
const code = String(req.query.code || '');
|
||||
const state = String(req.query.state || '');
|
||||
|
||||
if (!code || !state) {
|
||||
return res.status(400).json({ error: 'Missing authorization code or state' });
|
||||
}
|
||||
|
||||
const result = await PlatformAccountService.handleOAuthCallback(platform, code, state);
|
||||
|
||||
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:8000';
|
||||
|
||||
if (result.success) {
|
||||
res.redirect(`${frontendUrl}/dashboard/settings/platform-auth?status=connected&platform=${platform}`);
|
||||
} else {
|
||||
res.redirect(`${frontendUrl}/dashboard/settings/platform-auth?status=error&message=${encodeURIComponent(result.error || 'Unknown error')}`);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[PlatformAuth] Callback error: ${errorMessage}`);
|
||||
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:8000';
|
||||
res.redirect(`${frontendUrl}/dashboard/settings/platform-auth?status=error&message=${encodeURIComponent(errorMessage)}`);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/refresh/:id', requirePermission('platform:write'), async (req: Request, res: Response) => {
|
||||
try {
|
||||
const id = String(req.params.id);
|
||||
const account = await PlatformAccountService.getById(id);
|
||||
|
||||
if (!account) {
|
||||
return res.status(404).json({ error: 'Account not found' });
|
||||
}
|
||||
|
||||
if (account.tenantId !== req.user?.tenantId) {
|
||||
return res.status(403).json({ error: 'Forbidden' });
|
||||
}
|
||||
|
||||
const refreshed = await PlatformAccountService.refreshToken(id);
|
||||
|
||||
res.json({ success: true, data: refreshed });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[PlatformAuth] Refresh error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/disconnect/:id', requirePermission('platform:write'), async (req: Request, res: Response) => {
|
||||
try {
|
||||
const id = String(req.params.id);
|
||||
const account = await PlatformAccountService.getById(id);
|
||||
|
||||
if (!account) {
|
||||
return res.status(404).json({ error: 'Account not found' });
|
||||
}
|
||||
|
||||
if (account.tenantId !== req.user?.tenantId) {
|
||||
return res.status(403).json({ error: 'Forbidden' });
|
||||
}
|
||||
|
||||
await PlatformAccountService.disconnect(id);
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[PlatformAuth] Disconnect error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:id', requirePermission('platform:write'), async (req: Request, res: Response) => {
|
||||
try {
|
||||
const id = String(req.params.id);
|
||||
const account = await PlatformAccountService.getById(id);
|
||||
|
||||
if (!account) {
|
||||
return res.status(404).json({ error: 'Account not found' });
|
||||
}
|
||||
|
||||
if (account.tenantId !== req.user?.tenantId) {
|
||||
return res.status(403).json({ error: 'Forbidden' });
|
||||
}
|
||||
|
||||
await PlatformAccountService.delete(id);
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[PlatformAuth] Delete error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
254
server/src/api/routes/service-manager.ts
Normal file
254
server/src/api/routes/service-manager.ts
Normal file
@@ -0,0 +1,254 @@
|
||||
import { Router, Request, Response } from 'express';
|
||||
import { DomainRegistry } from '../../core/runtime/DomainRegistry';
|
||||
import { logger } from '../../utils/logger';
|
||||
import { SERVICE_CONFIGS, SERVICE_CATEGORIES, ServiceCategory } from '../../config/serviceConfig';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/list', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const services = DomainRegistry.getServiceStatus();
|
||||
|
||||
const groupedServices = services.reduce((acc, service) => {
|
||||
const category = service.config?.category || 'BUSINESS';
|
||||
if (!acc[category]) {
|
||||
acc[category] = [];
|
||||
}
|
||||
acc[category].push(service);
|
||||
return acc;
|
||||
}, {} as Record<string, typeof services>);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
services,
|
||||
groupedServices,
|
||||
categories: SERVICE_CATEGORIES,
|
||||
stats: {
|
||||
total: services.length,
|
||||
enabled: services.filter(s => s.enabled).length,
|
||||
initialized: services.filter(s => s.initialized).length,
|
||||
failed: services.filter(s => s.error).length,
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[ServiceManager] List error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/stats', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const services = DomainRegistry.getServiceStatus();
|
||||
|
||||
const stats = {
|
||||
total: services.length,
|
||||
enabled: services.filter(s => s.enabled).length,
|
||||
disabled: services.filter(s => !s.enabled).length,
|
||||
initialized: services.filter(s => s.initialized).length,
|
||||
failed: services.filter(s => s.error).length,
|
||||
byCategory: {} as Record<string, { total: number; enabled: number; initialized: number }>,
|
||||
byMemoryImpact: {
|
||||
low: { total: 0, enabled: 0 },
|
||||
medium: { total: 0, enabled: 0 },
|
||||
high: { total: 0, enabled: 0 },
|
||||
},
|
||||
};
|
||||
|
||||
services.forEach(service => {
|
||||
const category = service.config?.category || 'BUSINESS';
|
||||
if (!stats.byCategory[category]) {
|
||||
stats.byCategory[category] = { total: 0, enabled: 0, initialized: 0 };
|
||||
}
|
||||
stats.byCategory[category].total++;
|
||||
if (service.enabled) stats.byCategory[category].enabled++;
|
||||
if (service.initialized) stats.byCategory[category].initialized++;
|
||||
|
||||
const memoryImpact = service.config?.memoryImpact || 'low';
|
||||
stats.byMemoryImpact[memoryImpact].total++;
|
||||
if (service.enabled) stats.byMemoryImpact[memoryImpact].enabled++;
|
||||
});
|
||||
|
||||
res.json({ success: true, data: stats });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[ServiceManager] Stats error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/categories', async (req: Request, res: Response) => {
|
||||
try {
|
||||
res.json({ success: true, data: SERVICE_CATEGORIES });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[ServiceManager] Categories error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/toggle/:name', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const name = String(req.params.name);
|
||||
const { enabled } = req.body;
|
||||
|
||||
if (typeof enabled !== 'boolean') {
|
||||
return res.status(400).json({ error: 'Missing or invalid "enabled" field' });
|
||||
}
|
||||
|
||||
const serviceConfig = SERVICE_CONFIGS.find(s => s.name === name);
|
||||
if (!serviceConfig) {
|
||||
return res.status(404).json({ error: `Service "${name}" not found` });
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
DomainRegistry.enableService(name);
|
||||
logger.info(`[ServiceManager] Service enabled: ${name}`);
|
||||
} else {
|
||||
DomainRegistry.disableService(name);
|
||||
logger.info(`[ServiceManager] Service disabled: ${name}`);
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
name,
|
||||
enabled,
|
||||
message: enabled
|
||||
? `服务 "${name}" 已启用,重启后生效`
|
||||
: `服务 "${name}" 已禁用,重启后生效`
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[ServiceManager] Toggle error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/batch-toggle', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { services, enabled } = req.body;
|
||||
|
||||
if (!Array.isArray(services) || typeof enabled !== 'boolean') {
|
||||
return res.status(400).json({ error: 'Invalid request body' });
|
||||
}
|
||||
|
||||
const results: Array<{ name: string; success: boolean; error?: string }> = [];
|
||||
|
||||
for (const name of services) {
|
||||
const serviceConfig = SERVICE_CONFIGS.find(s => s.name === name);
|
||||
if (!serviceConfig) {
|
||||
results.push({ name, success: false, error: 'Service not found' });
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
DomainRegistry.enableService(name);
|
||||
} else {
|
||||
DomainRegistry.disableService(name);
|
||||
}
|
||||
results.push({ name, success: true });
|
||||
}
|
||||
|
||||
logger.info(`[ServiceManager] Batch toggle: ${services.length} services ${enabled ? 'enabled' : 'disabled'}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
results,
|
||||
message: `已${enabled ? '启用' : '禁用'} ${results.filter(r => r.success).length} 个服务,重启后生效`
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[ServiceManager] Batch toggle error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/apply-preset/:preset', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const preset = String(req.params.preset);
|
||||
|
||||
const presets: Record<string, string[]> = {
|
||||
minimal: SERVICE_CONFIGS
|
||||
.filter(s => s.category === 'CORE' && s.enabled)
|
||||
.map(s => s.name),
|
||||
standard: SERVICE_CONFIGS
|
||||
.filter(s => s.enabled)
|
||||
.map(s => s.name),
|
||||
full: SERVICE_CONFIGS.map(s => s.name),
|
||||
development: SERVICE_CONFIGS
|
||||
.filter(s => s.category === 'CORE' || s.category === 'BUSINESS')
|
||||
.filter(s => s.memoryImpact === 'low' || s.memoryImpact === 'medium')
|
||||
.map(s => s.name),
|
||||
};
|
||||
|
||||
if (!presets[preset]) {
|
||||
return res.status(400).json({
|
||||
error: `Unknown preset: ${preset}. Available: ${Object.keys(presets).join(', ')}`
|
||||
});
|
||||
}
|
||||
|
||||
DomainRegistry.setEnabledServices(presets[preset]);
|
||||
|
||||
logger.info(`[ServiceManager] Applied preset: ${preset} (${presets[preset].length} services)`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
preset,
|
||||
enabledCount: presets[preset].length,
|
||||
message: `已应用 "${preset}" 预设,重启后生效`
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[ServiceManager] Apply preset error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/presets', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const presets = [
|
||||
{
|
||||
id: 'minimal',
|
||||
name: '最小模式',
|
||||
description: '仅启动核心服务,内存占用最低',
|
||||
serviceCount: SERVICE_CONFIGS.filter(s => s.category === 'CORE' && s.enabled).length,
|
||||
},
|
||||
{
|
||||
id: 'standard',
|
||||
name: '标准模式',
|
||||
description: '启动默认启用的服务,适合日常开发',
|
||||
serviceCount: SERVICE_CONFIGS.filter(s => s.enabled).length,
|
||||
},
|
||||
{
|
||||
id: 'development',
|
||||
name: '开发模式',
|
||||
description: '核心+业务服务,低内存占用',
|
||||
serviceCount: SERVICE_CONFIGS
|
||||
.filter(s => s.category === 'CORE' || s.category === 'BUSINESS')
|
||||
.filter(s => s.memoryImpact === 'low' || s.memoryImpact === 'medium').length,
|
||||
},
|
||||
{
|
||||
id: 'full',
|
||||
name: '完整模式',
|
||||
description: '启动所有服务,内存占用最高',
|
||||
serviceCount: SERVICE_CONFIGS.length,
|
||||
},
|
||||
];
|
||||
|
||||
res.json({ success: true, data: presets });
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
logger.error(`[ServiceManager] Presets error: ${errorMessage}`);
|
||||
res.status(500).json({ error: errorMessage });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user