fix: 修复奖品图片和赞助商logo删除bug

- 修复编辑奖品时删除图片后保存,图片仍存在的问题
- 修复编辑赞助商时删除logo后保存,logo仍存在的问题
- 前端添加删除检测逻辑,传递removeImage/removeLogo标记
- 后端处理删除标记,将对应字段设为null
This commit is contained in:
Yvan
2026-04-10 09:32:29 +08:00
parent 4920620d2c
commit 2530ceb6b4
3 changed files with 310 additions and 14 deletions
+148 -6
View File
@@ -3,6 +3,7 @@ const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const auth = require('../middleware/auth');
const authSuper = require('../middleware/authSuper');
const { upload, getFileUrls } = require('../middleware/upload');
const { Admin, Activity, Registration, Expense, Photo, Sponsor, Prize } = require('../models');
const fs = require('fs');
@@ -17,7 +18,132 @@ router.post('/login', async (req, res) => {
return res.status(401).json({ error: '用户名或密码错误' });
}
const token = jwt.sign({ id: admin.id }, process.env.JWT_SECRET, { expiresIn: '7d' });
res.json({ token, admin: { id: admin.id, username: admin.username, name: admin.name } });
res.json({
token,
admin: {
id: admin.id,
username: admin.username,
name: admin.name,
role: admin.role
}
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// ========== 管理员管理API(仅超级管理员) ==========
// 获取管理员列表
router.get('/admins', authSuper, async (req, res) => {
try {
const admins = await Admin.findAll({
attributes: ['id', 'username', 'name', 'role', 'createdAt'],
order: [['createdAt', 'ASC']],
raw: true
});
res.json(admins);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 创建管理员
router.post('/admins', authSuper, async (req, res) => {
try {
const { username, password, name, role } = req.body;
if (!username || !password) {
return res.status(400).json({ error: '用户名和密码不能为空' });
}
const existing = await Admin.findOne({ where: { username } });
if (existing) {
return res.status(400).json({ error: '用户名已存在' });
}
const hashedPassword = bcrypt.hashSync(password, 10);
const admin = await Admin.create({
username,
password: hashedPassword,
name: name || username,
role: role || 'admin'
});
res.json({
id: admin.id,
username: admin.username,
name: admin.name,
role: admin.role
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 修改管理员信息
router.put('/admins/:id', authSuper, async (req, res) => {
try {
const { name, role } = req.body;
const admin = await Admin.findByPk(req.params.id);
if (!admin) {
return res.status(404).json({ error: '管理员不存在' });
}
const updateData = {};
if (name !== undefined) updateData.name = name;
if (role !== undefined) updateData.role = role;
await Admin.update(updateData, { where: { id: req.params.id } });
const updated = await Admin.findByPk(req.params.id, {
attributes: ['id', 'username', 'name', 'role']
});
res.json(updated);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 修改管理员密码
router.put('/admins/:id/password', authSuper, async (req, res) => {
try {
const { newPassword } = req.body;
if (!newPassword) {
return res.status(400).json({ error: '新密码不能为空' });
}
const admin = await Admin.findByPk(req.params.id);
if (!admin) {
return res.status(404).json({ error: '管理员不存在' });
}
const hashedPassword = bcrypt.hashSync(newPassword, 10);
await Admin.update({ password: hashedPassword }, { where: { id: req.params.id } });
res.json({ message: '密码修改成功' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 删除管理员
router.delete('/admins/:id', authSuper, async (req, res) => {
try {
const admin = await Admin.findByPk(req.params.id);
if (!admin) {
return res.status(404).json({ error: '管理员不存在' });
}
// 防止删除超级管理员
if (admin.role === 'super') {
return res.status(403).json({ error: '不能删除超级管理员' });
}
await Admin.destroy({ where: { id: req.params.id } });
res.json({ message: '删除成功' });
} catch (error) {
res.status(500).json({ error: error.message });
}
@@ -93,6 +219,16 @@ router.get('/registrations', auth, async (req, res) => {
}
});
// 删除报名
router.delete('/registrations/:id', auth, async (req, res) => {
try {
await Registration.destroy({ where: { id: req.params.id } });
res.json({ message: '删除成功' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 上传经费明细
router.post('/expenses', auth, upload.array('media', 5), async (req, res) => {
try {
@@ -274,7 +410,7 @@ router.post('/sponsors', auth, upload.single('logo'), async (req, res) => {
// 更新赞助商
router.put('/sponsors/:id', auth, upload.single('logo'), async (req, res) => {
try {
const { name, type, link, sortOrder } = req.body;
const { name, type, link, sortOrder, removeLogo } = req.body;
const updateData = { name, type, link };
if (sortOrder !== undefined) {
@@ -284,6 +420,8 @@ router.put('/sponsors/:id', auth, upload.single('logo'), async (req, res) => {
if (req.file) {
const [uploaded] = getFileUrls(req.file);
updateData.logo = uploaded.url;
} else if (removeLogo === 'true') {
updateData.logo = null;
}
await Sponsor.update(updateData, { where: { id: req.params.id } });
@@ -307,7 +445,7 @@ router.delete('/sponsors/:id', auth, async (req, res) => {
// 添加奖品
router.post('/prizes', auth, upload.single('image'), async (req, res) => {
try {
const { activityId, name, level, description, quantity, sortOrder } = req.body;
const { activityId, name, level, description, quantity, sortOrder, source, sponsor } = req.body;
let image = null;
if (req.file) {
const [uploaded] = getFileUrls([req.file]);
@@ -320,7 +458,9 @@ router.post('/prizes', auth, upload.single('image'), async (req, res) => {
description,
image,
quantity: quantity || 1,
sortOrder: sortOrder || 0
sortOrder: sortOrder || 0,
source: source || 'purchase',
sponsor: sponsor || null
});
res.json(prize);
} catch (error) {
@@ -331,12 +471,14 @@ router.post('/prizes', auth, upload.single('image'), async (req, res) => {
// 更新奖品
router.put('/prizes/:id', auth, upload.single('image'), async (req, res) => {
try {
const { name, level, description, quantity, sortOrder } = req.body;
const updateData = { name, level, description, quantity, sortOrder };
const { name, level, description, quantity, sortOrder, source, sponsor, removeImage } = req.body;
const updateData = { name, level, description, quantity, sortOrder, source, sponsor };
if (req.file) {
const [uploaded] = getFileUrls([req.file]);
updateData.image = uploaded.url;
} else if (removeImage === 'true') {
updateData.image = null;
}
await Prize.update(updateData, { where: { id: req.params.id } });