feat(system): implement dynamic platform configs for customer service, safety notice, and service agreement

这个提交包含在:
xcbyy
2026-10-10 09:47:53 +08:00
父节点 d9c8388711
当前提交 dc19189bc6
共有 10 个文件被更改,包括 613 次插入 和 10 次删除

查看文件

@@ -372,6 +372,21 @@ export async function initDatabase(): Promise<void> {
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
`);
// 20. 平台官方客服、公告及服务协议通用配置表
await conn.query(`
CREATE TABLE IF NOT EXISTS platform_configs (
id INT PRIMARY KEY AUTO_INCREMENT,
config_key VARCHAR(64) UNIQUE NOT NULL,
name VARCHAR(128) NOT NULL,
value_json JSON NOT NULL,
description VARCHAR(255) DEFAULT '',
status TINYINT DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_key (config_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
`);
// 初始化配置单条记录
const [cfgRows]: any = await conn.query('SELECT COUNT(*) as count FROM finance_config WHERE id = 1');
if (cfgRows[0].count === 0) {
@@ -626,4 +641,40 @@ async function seedInitialDataIfEmpty(conn: any): Promise<void> {
(4, '电竞开黑连胜冲星券', 10.00, 30.00, 30, 5000, 340, 'ALL', '线上游戏陪玩下单立减', 1);
`);
}
// 17. 种子平台通用配置(官方客服、履约公告指引、规范协议)
const [cfgItemRows]: any = await conn.query('SELECT COUNT(*) as count FROM platform_configs');
if (cfgItemRows[0].count === 0) {
const customerServiceVal = JSON.stringify({
hotline: '400-888-6666',
hotlineDesc: '7x24h 官方客服服务热线',
wechat: 'peiwan_vip_kefu',
wechatDesc: '官方 VIP 客服微信号',
workHours: '周一至周日 00:00 - 24:00'
});
const safetyNoticeVal = JSON.stringify({
title: '平台官方公告与指引',
points: [
'【安全履约须知】为保障搭子与陪伴师人身与财产安全,线下约局须在合规公开商业街区进行。',
'【现场核销】现场碰面后请出示 4 位数字核销码进行签到确认。',
'【平台兜底】平台提供 7x24 小时争议仲裁与资金托管保障服务,严禁脱离平台私下交易。'
],
noticePopup: false
});
const protocolVal = JSON.stringify({
title: '用户服务协议与隐私规范',
summary: '严禁发布任何违规言论及低俗诈骗行为,平台全面遵循微信内容安全风控与用户隐私保护标准。',
content: '1. 账号使用规范:用户注册与使用陪玩服务须符合国家法律法规,严禁利用平台从事涉黄、赌博、欺诈等违规行为。\n2. 资金与交易保障:平台提供全额担保交易,订单完成前款项由官方账户托管,核销确认后自动结算至大神钱包。\n3. 争议与售后:若遇服务不符或搭子违约,可随时提交争议仲裁由运营平台人工介入裁决。'
});
await conn.query(`
INSERT INTO platform_configs (config_key, name, value_json, description, status)
VALUES
('customer_service', '官方在线客服与服务热线', ?, '小程序端个人中心客服联系方式', 1),
('safety_notice', '安全履约须知与官方公告', ?, '小程序端官方指引与安全红线弹窗', 1),
('platform_protocol', '平台服务协议与合规规范', ?, '小程序端服务协议与隐私政策详情', 1);
`, [customerServiceVal, safetyNoticeVal, protocolVal]);
}
}

查看文件

@@ -1247,6 +1247,91 @@ export class MysqlRepository {
return res.affectedRows > 0;
}
// 3. 平台通用配置与指引 (Platform Configs)
async getPlatformConfigs(): Promise<{ [key: string]: any }> {
const [rows]: any = await pool.query(`
SELECT config_key as configKey, name, value_json as valueJson, description, status
FROM platform_configs
WHERE status = 1
`);
const result: { [key: string]: any } = {};
for (const r of rows) {
let val = r.valueJson;
if (typeof val === 'string') {
try {
val = JSON.parse(val);
} catch (_) {}
}
result[r.configKey] = val;
}
return result;
}
async getAdminPlatformConfigs(): Promise<any[]> {
const [rows]: any = await pool.query(`
SELECT id, config_key as configKey, name, value_json as valueJson, description, status,
created_at as createdAt, updated_at as updatedAt
FROM platform_configs
ORDER BY id ASC
`);
return rows.map((r: any) => {
let val = r.valueJson;
if (typeof val === 'string') {
try {
val = JSON.parse(val);
} catch (_) {}
}
return {
...r,
valueJson: val
};
});
}
async updatePlatformConfig(configKey: string, data: { name?: string; valueJson?: any; description?: string; status?: number }): Promise<any> {
const fields: string[] = [];
const values: any[] = [];
if (data.name !== undefined) {
fields.push('name = ?');
values.push(data.name);
}
if (data.valueJson !== undefined) {
fields.push('value_json = ?');
values.push(JSON.stringify(data.valueJson));
}
if (data.description !== undefined) {
fields.push('description = ?');
values.push(data.description);
}
if (data.status !== undefined) {
fields.push('status = ?');
values.push(Number(data.status));
}
if (fields.length > 0) {
values.push(configKey);
await pool.query(`UPDATE platform_configs SET ${fields.join(', ')} WHERE config_key = ?`, values);
}
const [rows]: any = await pool.query(`
SELECT id, config_key as configKey, name, value_json as valueJson, description, status,
created_at as createdAt, updated_at as updatedAt
FROM platform_configs
WHERE config_key = ?
`, [configKey]);
if (!rows || rows.length === 0) return null;
const r = rows[0];
let val = r.valueJson;
if (typeof val === 'string') {
try {
val = JSON.parse(val);
} catch (_) {}
}
return { ...r, valueJson: val };
}
async getArbitrations(): Promise<any[]> {

查看文件

@@ -1051,6 +1051,57 @@ app.delete('/api/admin/coupons/:id', async (req: Request, res: Response) => {
}
});
// 3. 平台官方客服、履约公告与规范协议配置接口
// 移动端:获取全部有效系统通用配置
app.get('/api/system/configs', async (_req: Request, res: Response) => {
try {
const configs = await repo.getPlatformConfigs();
res.json({ code: 20000, data: configs });
} catch (err: any) {
res.status(500).json({ code: 50000, message: err.message });
}
});
// 管理后台:获取全部配置项列表
app.get('/api/admin/system/configs', async (_req: Request, res: Response) => {
try {
const list = await repo.getAdminPlatformConfigs();
res.json({ code: 20000, data: list });
} catch (err: any) {
res.status(500).json({ code: 50000, message: err.message });
}
});
// 管理后台:更新指定配置项
app.put('/api/admin/system/configs/:key', async (req: Request, res: Response) => {
try {
const configKey = String(req.params.key);
const { name, valueJson, description, status } = req.body;
// 微信内容安全审查(检查文本内容或字符串化后的配置)
const textToCheck = `${name || ''} ${description || ''} ${JSON.stringify(valueJson || '')}`;
const sec = contentSecurityService.checkText(textToCheck);
if (!sec.pass) {
return res.status(400).json({ code: sec.code, message: sec.message });
}
const updated = await repo.updatePlatformConfig(configKey, {
name,
valueJson,
description,
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 });
}
});
// 创建新订单 (落盘 MySQL)
app.post('/api/orders', async (req: Request, res: Response) => {
try {