- 新增 programs.json 配置文件 - 新增 ProgramConfigService 服务 - 新增节目配置 API 接口 (GET/PUT /api/admin/programs) - 修改 AdminService 使用配置服务替代硬编码 - 添加单元测试
209 lines
4.5 KiB
TypeScript
209 lines
4.5 KiB
TypeScript
import { Router, IRouter } from 'express';
|
|
import multer from 'multer';
|
|
import { participantService } from '../services/participant.service';
|
|
import { prizeConfigService } from '../services/prize-config.service';
|
|
import { programConfigService } from '../services/program-config.service';
|
|
|
|
const router: IRouter = Router();
|
|
const upload = multer({ storage: multer.memoryStorage() });
|
|
|
|
/**
|
|
* GET /api/admin/stats
|
|
* Get system statistics
|
|
*/
|
|
router.get('/stats', async (_req, res, next) => {
|
|
try {
|
|
// TODO: Implement admin stats
|
|
return res.json({
|
|
success: true,
|
|
data: {
|
|
totalUsers: participantService.getCount(),
|
|
totalVotes: 0,
|
|
activeConnections: 0,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/admin/prizes
|
|
* Get prize configuration
|
|
*/
|
|
router.get('/prizes', async (_req, res, next) => {
|
|
try {
|
|
const config = prizeConfigService.getFullConfig();
|
|
return res.json({
|
|
success: true,
|
|
data: config,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* PUT /api/admin/prizes
|
|
* Update prize configuration
|
|
*/
|
|
router.put('/prizes', async (req, res, next) => {
|
|
try {
|
|
const { prizes, settings } = req.body;
|
|
|
|
if (prizes) {
|
|
const result = await prizeConfigService.updatePrizes(prizes);
|
|
if (!result.success) {
|
|
return res.status(400).json({ success: false, error: result.error });
|
|
}
|
|
}
|
|
|
|
if (settings) {
|
|
const result = await prizeConfigService.updateSettings(settings);
|
|
if (!result.success) {
|
|
return res.status(400).json({ success: false, error: result.error });
|
|
}
|
|
}
|
|
|
|
return res.json({
|
|
success: true,
|
|
data: prizeConfigService.getFullConfig(),
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/admin/programs
|
|
* Get program configuration
|
|
*/
|
|
router.get('/programs', async (_req, res, next) => {
|
|
try {
|
|
const config = programConfigService.getFullConfig();
|
|
return res.json({
|
|
success: true,
|
|
data: config,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* PUT /api/admin/programs
|
|
* Update program configuration
|
|
*/
|
|
router.put('/programs', async (req, res, next) => {
|
|
try {
|
|
const { programs, settings } = req.body;
|
|
|
|
if (programs) {
|
|
const result = await programConfigService.updatePrograms(programs);
|
|
if (!result.success) {
|
|
return res.status(400).json({ success: false, error: result.error });
|
|
}
|
|
}
|
|
|
|
if (settings) {
|
|
const result = await programConfigService.updateSettings(settings);
|
|
if (!result.success) {
|
|
return res.status(400).json({ success: false, error: result.error });
|
|
}
|
|
}
|
|
|
|
return res.json({
|
|
success: true,
|
|
data: programConfigService.getFullConfig(),
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/admin/draw/start
|
|
* Start a lucky draw
|
|
*/
|
|
router.post('/draw/start', async (_req, res, next) => {
|
|
try {
|
|
// TODO: Implement draw start
|
|
return res.json({
|
|
success: true,
|
|
message: 'Draw started',
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/admin/draw/stop
|
|
* Stop the current draw
|
|
*/
|
|
router.post('/draw/stop', async (_req, res, next) => {
|
|
try {
|
|
// TODO: Implement draw stop
|
|
return res.json({
|
|
success: true,
|
|
message: 'Draw stopped',
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/admin/participants/import
|
|
* Import participants from Excel file
|
|
* Expected columns: 岗位, 姓名, 年份
|
|
*/
|
|
router.post('/participants/import', upload.single('file'), async (req, res, next) => {
|
|
try {
|
|
if (!req.file) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: '请上传 Excel 文件',
|
|
});
|
|
}
|
|
|
|
const result = await participantService.importFromExcel(req.file.buffer);
|
|
|
|
return res.json({
|
|
success: result.success,
|
|
data: {
|
|
totalCount: result.totalCount,
|
|
importedCount: result.importedCount,
|
|
tagDistribution: result.tagDistribution,
|
|
errors: result.errors,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* GET /api/admin/participants
|
|
* Get all participants with statistics
|
|
*/
|
|
router.get('/participants', async (_req, res, next) => {
|
|
try {
|
|
const participants = participantService.getAll();
|
|
const stats = participantService.getStats();
|
|
return res.json({
|
|
success: true,
|
|
data: {
|
|
count: participants.length,
|
|
tagDistribution: stats.tagDistribution,
|
|
participants,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
});
|
|
|
|
export default router;
|
|
|