fix(report): optimize wechat toast length limit and add admin violation reports management center
这个提交包含在:
@@ -469,11 +469,24 @@ export async function initDatabase(): Promise<void> {
|
||||
description VARCHAR(500) DEFAULT '',
|
||||
evidence JSON,
|
||||
status VARCHAR(32) NOT NULL DEFAULT '待处理',
|
||||
handle_result VARCHAR(64) DEFAULT '',
|
||||
handle_note VARCHAR(500) DEFAULT '',
|
||||
handled_at DATETIME DEFAULT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_target (target_type, target_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
`);
|
||||
|
||||
try {
|
||||
await conn.query('ALTER TABLE reports ADD COLUMN handle_result VARCHAR(64) DEFAULT ""');
|
||||
} catch (_) {}
|
||||
try {
|
||||
await conn.query('ALTER TABLE reports ADD COLUMN handle_note VARCHAR(500) DEFAULT ""');
|
||||
} catch (_) {}
|
||||
try {
|
||||
await conn.query('ALTER TABLE reports ADD COLUMN handled_at DATETIME DEFAULT NULL');
|
||||
} catch (_) {}
|
||||
|
||||
// 22. 陪玩收藏表 (收藏喜欢的陪玩,实时高亮在接单状态)
|
||||
await conn.query(`
|
||||
CREATE TABLE IF NOT EXISTS favorites (
|
||||
|
||||
@@ -1669,8 +1669,19 @@ export class MysqlRepository {
|
||||
async getReports(): Promise<any[]> {
|
||||
const [rows]: any = await pool.query(`
|
||||
SELECT
|
||||
id, reporter_id as reporterId, target_type as targetType, target_id as targetId,
|
||||
target_name as targetName, reason, description, evidence, status, created_at as createdAt
|
||||
id,
|
||||
reporter_id as reporterId,
|
||||
target_type as targetType,
|
||||
target_id as targetId,
|
||||
target_name as targetName,
|
||||
reason,
|
||||
description,
|
||||
evidence,
|
||||
status,
|
||||
COALESCE(handle_result, '') as handleResult,
|
||||
COALESCE(handle_note, '') as handleNote,
|
||||
handled_at as handledAt,
|
||||
created_at as createdAt
|
||||
FROM reports
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 200
|
||||
@@ -1678,6 +1689,46 @@ export class MysqlRepository {
|
||||
return rows;
|
||||
}
|
||||
|
||||
async handleReport(
|
||||
id: string,
|
||||
action: 'punish' | 'reject',
|
||||
handleNote?: string,
|
||||
penaltyOptions?: { deductCredit?: number; banDays?: number }
|
||||
): Promise<any> {
|
||||
const status = action === 'punish' ? '已核实处罚' : '已驳回';
|
||||
const handleResult = action === 'punish' ? '违规属实,已给予处分' : '证据不足,予以驳回';
|
||||
const note = handleNote || (action === 'punish' ? '经平台安全与风控团队核查,违规行为属实,已给予处分并记录违规档案。' : '经安全团队核验,现有证据不足以判定违规,予以驳回。');
|
||||
|
||||
await pool.query(`
|
||||
UPDATE reports
|
||||
SET status = ?, handle_result = ?, handle_note = ?, handled_at = NOW()
|
||||
WHERE id = ?
|
||||
`, [status, handleResult, note, id]);
|
||||
|
||||
try {
|
||||
const [rows]: any = await pool.query('SELECT * FROM reports WHERE id = ?', [id]);
|
||||
const report = rows && rows[0];
|
||||
if (report && action === 'punish' && report.target_type === 'EXPERT') {
|
||||
const expertId = Number(report.target_id);
|
||||
if (expertId > 0) {
|
||||
await pool.query(`
|
||||
UPDATE companions
|
||||
SET rating = GREATEST(1.0, rating - 0.2)
|
||||
WHERE id = ?
|
||||
`, [expertId]);
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
return {
|
||||
id,
|
||||
status,
|
||||
handleResult,
|
||||
handleNote: note,
|
||||
handledAt: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
// 财务相关
|
||||
async getFinanceRecords(): Promise<any[]> {
|
||||
const [rows]: any = await pool.query(`
|
||||
|
||||
@@ -1337,6 +1337,25 @@ app.get('/api/reports', async (_req: Request, res: Response) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 管理员处置不良违规举报工单
|
||||
app.post('/api/reports/:id/handle', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { action, handleNote, penaltyOptions } = req.body || {};
|
||||
if (!action || !['punish', 'reject'].includes(action)) {
|
||||
return res.status(400).json({ code: 40000, message: '请指定合法的处理动作 (punish 或 reject)' });
|
||||
}
|
||||
const result = await repo.handleReport(id, action, handleNote, penaltyOptions);
|
||||
res.json({
|
||||
code: 20000,
|
||||
data: result,
|
||||
message: action === 'punish' ? '已核实举报并执行违规处置' : '已驳回该违规举报工单'
|
||||
});
|
||||
} catch (err: any) {
|
||||
res.status(500).json({ code: 50000, message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/arbitrations', async (_req: Request, res: Response) => {
|
||||
try {
|
||||
const arbitrations = await repo.getArbitrations();
|
||||
|
||||
在新工单中引用
屏蔽一个用户