chore: mqsrv backend

This commit is contained in:
Chen Gu
2026-05-09 00:52:04 +08:00
commit b84f111e8f
21 changed files with 4593 additions and 0 deletions

278
src/routes/schemes.ts Normal file
View File

@@ -0,0 +1,278 @@
import { Router, Request, Response } from 'express';
import { PrismaClient } from '@prisma/client';
import { z } from 'zod';
import { authMiddleware, optionalAuth } from '../middleware/auth';
import { encrypt } from '../utils/encryption';
const router = Router();
const prisma = new PrismaClient();
// ============================================
// 获取方案列表
// ============================================
router.get('/', optionalAuth, async (req: Request, res: Response) => {
try {
const {
page = 1,
limit = 20,
weapon,
category,
sort = 'newest',
} = req.query;
const skip = (Number(page) - 1) * Number(limit);
const where: any = { status: 'PUBLISHED' };
if (weapon) where.weaponName = { contains: String(weapon) };
if (category) where.category = String(category);
let orderBy: any = { createdAt: 'desc' };
if (sort === 'popular') orderBy = { viewsCount: 'desc' };
if (sort === 'downloads') orderBy = { downloadsCount: 'desc' };
const schemes = await prisma.scheme.findMany({
where,
orderBy,
skip,
take: Number(limit),
select: {
id: true,
title: true,
description: true,
weaponName: true,
category: true,
price: true,
viewsCount: true,
downloadsCount: true,
likesCount: true,
isOfficial: true,
createdAt: true,
user: {
select: {
id: true,
username: true,
avatar: true,
},
},
},
});
res.json({
success: true,
data: schemes,
});
} catch (error) {
console.error('Get schemes error:', error);
res.status(500).json({ success: false, message: '获取失败' });
}
});
// ============================================
// 获取单个方案详情
// ============================================
router.get('/:id', optionalAuth, async (req: Request, res: Response) => {
try {
const { id } = req.params;
const scheme = await prisma.scheme.findUnique({
where: { id },
include: {
user: {
select: {
id: true,
username: true,
avatar: true,
},
},
},
});
if (!scheme) {
return res.status(404).json({
success: false,
message: '方案不存在',
});
}
if (scheme.status !== 'PUBLISHED' && scheme.userId !== req.user?.userId) {
return res.status(404).json({
success: false,
message: '方案不存在',
});
}
// 增加浏览量
await prisma.scheme.update({
where: { id },
data: { viewsCount: { increment: 1 } },
});
// 检查是否收藏
let isFavorited = false;
if (req.user) {
const fav = await prisma.favorite.findFirst({
where: {
userId: req.user.userId,
targetType: 'SCHEME',
targetId: id,
},
});
isFavorited = !!fav;
}
// 加密方案内容
const encryptedContent = encrypt(scheme.schemeContent);
res.json({
success: true,
data: {
...scheme,
schemeContent: encryptedContent,
isFavorited,
},
});
} catch (error) {
console.error('Get scheme error:', error);
res.status(500).json({ success: false, message: '获取失败' });
}
});
// ============================================
// 创建方案
// ============================================
const createSchemeSchema = z.object({
title: z.string().min(1).max(100),
description: z.string().optional(),
weaponName: z.string().optional(),
category: z.string().optional(),
schemeContent: z.string().min(1),
price: z.number().int().min(0).default(0),
gpuModel: z.string().optional(),
driverVersion: z.string().optional(),
appVersion: z.string().optional(),
});
router.post('/', authMiddleware, async (req: Request, res: Response) => {
try {
const body = createSchemeSchema.parse(req.body);
const scheme = await prisma.scheme.create({
data: {
userId: req.user!.userId,
title: body.title,
description: body.description,
weaponName: body.weaponName,
category: body.category,
schemeContent: body.schemeContent,
price: body.price,
gpuModel: body.gpuModel,
driverVersion: body.driverVersion,
appVersion: body.appVersion,
status: 'PUBLISHED',
},
});
// 更新用户方案数
await prisma.user.update({
where: { id: req.user!.userId },
data: { schemesCount: { increment: 1 } },
});
res.json({
success: true,
message: '方案创建成功',
data: scheme,
});
} catch (error) {
console.error('Create scheme error:', error);
res.status(500).json({ success: false, message: '创建失败' });
}
});
// ============================================
// 删除方案
// ============================================
router.delete('/:id', authMiddleware, async (req: Request, res: Response) => {
try {
const { id } = req.params;
const scheme = await prisma.scheme.findUnique({
where: { id },
select: { userId: true },
});
if (!scheme) {
return res.status(404).json({
success: false,
message: '方案不存在',
});
}
if (scheme.userId !== req.user!.userId) {
return res.status(403).json({
success: false,
message: '无权删除此方案',
});
}
await prisma.scheme.update({
where: { id },
data: { status: 'DELETED' },
});
res.json({
success: true,
message: '方案已删除',
});
} catch (error) {
console.error('Delete scheme error:', error);
res.status(500).json({ success: false, message: '删除失败' });
}
});
// 记录方案使用(增加下载计数)
router.post('/:id/use', authMiddleware, async (req: Request, res: Response) => {
try {
const { id } = req.params;
const { source } = req.body;
const scheme = await prisma.scheme.findUnique({
where: { id },
select: { id: true, downloadsCount: true },
});
if (!scheme) {
return res.status(404).json({
success: false,
message: '方案不存在',
});
}
// 使用计数 +1增加 downloads 计数)
const updated = await prisma.scheme.update({
where: { id },
data: { downloadsCount: { increment: 1 } },
select: { downloadsCount: true },
});
// 记录日志
await prisma.userLog.create({
data: {
userId: req.user!.userId,
action: 'SchemeUse',
targetType: 'Scheme',
targetId: id,
},
});
res.json({
success: true,
downloadsCount: updated.downloadsCount,
});
} catch (error) {
console.error('Scheme use error:', error);
res.status(500).json({ success: false, message: '记录失败' });
}
});
export default router;