feat(banner): support dynamic banner management in admin and sync with miniprogram
这个提交包含在:
@@ -615,7 +615,7 @@ app.get('/api/expert/stats/:id', async (req: Request, res: Response) => {
|
||||
});
|
||||
|
||||
|
||||
// 首页运营 Banner 列表 (配置化接口)
|
||||
// 首页运营 Banner 列表 (小程序端读取启用状态)
|
||||
app.get('/api/banners', async (_req: Request, res: Response) => {
|
||||
try {
|
||||
const banners = await repo.getBanners();
|
||||
@@ -625,6 +625,120 @@ app.get('/api/banners', async (_req: Request, res: Response) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 管理后台: 获取全部 Banner 列表 (含停用状态)
|
||||
app.get('/api/admin/banners', async (_req: Request, res: Response) => {
|
||||
try {
|
||||
const banners = await repo.getAdminBanners();
|
||||
res.json({ code: 20000, data: banners });
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ code: 50000, message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 管理后台: 新增 Banner
|
||||
app.post('/api/admin/banners', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { title, subtitle, tag, badge, badgeType, bg, image, link, sortOrder, status } = req.body;
|
||||
if (!title || !title.trim()) {
|
||||
return res.status(400).json({ code: 40000, message: 'Banner 标题不能为空' });
|
||||
}
|
||||
|
||||
// 微信内容安全检测
|
||||
const secCheck = contentSecurityService.checkText(title + ' ' + (subtitle || ''));
|
||||
if (!secCheck.pass) {
|
||||
return res.status(400).json({ code: secCheck.code, message: secCheck.message });
|
||||
}
|
||||
|
||||
const banner = await repo.createBanner({
|
||||
title: title.trim(),
|
||||
subtitle: subtitle ? subtitle.trim() : '',
|
||||
tag,
|
||||
badge,
|
||||
badgeType,
|
||||
bg,
|
||||
image,
|
||||
link,
|
||||
sortOrder: sortOrder !== undefined ? Number(sortOrder) : 0,
|
||||
status: status !== undefined ? Number(status) : 1
|
||||
});
|
||||
|
||||
res.json({ code: 20000, data: banner, message: '轮播图创建成功' });
|
||||
} catch (err: any) {
|
||||
res.status(400).json({ code: 40000, message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 管理后台: 修改 Banner
|
||||
app.put('/api/admin/banners/:id', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const bannerId = req.params.id;
|
||||
const { title, subtitle, tag, badge, badgeType, bg, image, link, sortOrder, status } = req.body;
|
||||
|
||||
if (title) {
|
||||
const secCheck = contentSecurityService.checkText(title + ' ' + (subtitle || ''));
|
||||
if (!secCheck.pass) {
|
||||
return res.status(400).json({ code: secCheck.code, message: secCheck.message });
|
||||
}
|
||||
}
|
||||
|
||||
const updated = await repo.updateBanner(bannerId, {
|
||||
title,
|
||||
subtitle,
|
||||
tag,
|
||||
badge,
|
||||
badgeType,
|
||||
bg,
|
||||
image,
|
||||
link,
|
||||
sortOrder: sortOrder !== undefined ? Number(sortOrder) : undefined,
|
||||
status: status !== undefined ? Number(status) : undefined
|
||||
});
|
||||
|
||||
if (!updated) {
|
||||
return res.status(404).json({ code: 40400, message: '轮播图不存在或已被删除' });
|
||||
}
|
||||
|
||||
res.json({ code: 20000, data: updated, message: '轮播图修改成功' });
|
||||
} catch (err: any) {
|
||||
res.status(400).json({ code: 40000, message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 管理后台: 切换 Banner 上架/下线状态
|
||||
app.post('/api/admin/banners/:id/status', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const bannerId = req.params.id;
|
||||
const { status } = req.body;
|
||||
if (status === undefined || (status !== 0 && status !== 1)) {
|
||||
return res.status(400).json({ code: 40000, message: '状态参数必须为 0 或 1' });
|
||||
}
|
||||
|
||||
const updated = await repo.updateBannerStatus(bannerId, Number(status));
|
||||
if (!updated) {
|
||||
return res.status(404).json({ code: 40400, message: '轮播图不存在' });
|
||||
}
|
||||
|
||||
res.json({ code: 20000, data: updated, message: status === 1 ? '轮播图已上架生效' : '轮播图已下线隐藏' });
|
||||
} catch (err: any) {
|
||||
res.status(400).json({ code: 40000, message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 管理后台: 删除 Banner
|
||||
app.delete('/api/admin/banners/:id', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const bannerId = req.params.id;
|
||||
const ok = await repo.deleteBanner(bannerId);
|
||||
if (!ok) {
|
||||
return res.status(404).json({ code: 40400, message: '轮播图不存在或已被删除' });
|
||||
}
|
||||
|
||||
res.json({ code: 20000, data: null, message: '轮播图已删除' });
|
||||
} catch (err: any) {
|
||||
res.status(400).json({ code: 40000, message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// 创建新订单 (落盘 MySQL)
|
||||
app.post('/api/orders', async (req: Request, res: Response) => {
|
||||
try {
|
||||
|
||||
在新工单中引用
屏蔽一个用户