fix(admin): 模板ID匹配改由后端裁决并 trim,修复"ID明明一致却报不属于该小程序"的误报
- 拉取模板列表接口在后端统一 trim 后比对,返回 mismatched 结论(含两侧空白差异场景) - 后台改为直接展示后端结论,避免前端字符串比对误报 - 回归 87 套件/637 用例全绿
这个提交包含在:
@@ -1402,15 +1402,11 @@ const fetchWechatTemplates = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 后台填写的4个模板ID中,哪些不在小程序模板列表里(即为 40037 的元凶)
|
||||
// 后台填写的4个模板ID中,哪些不在小程序模板列表里(以后端结论为准,避免前端字符串比对误报)
|
||||
const mismatchedTemplateIds = computed(() => {
|
||||
const t = wechatTemplates.value;
|
||||
if (!t || !Array.isArray(t.templates)) return [];
|
||||
const existing = new Set(t.templates.map((x: any) => String(x.templateId)));
|
||||
const cfg = t.configured || {};
|
||||
return Object.entries(cfg)
|
||||
.filter(([, id]) => id && !existing.has(String(id)))
|
||||
.map(([key, id]) => `${key}: ${id}`);
|
||||
if (!t || !Array.isArray(t.mismatched)) return [];
|
||||
return t.mismatched.map((m: any) => `${m.key}: ${m.templateId}`);
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -3932,6 +3932,18 @@ app.get('/api/admin/message/templates', async (_req: Request, res: Response) =>
|
||||
const list = data && Array.isArray(data.data) ? data.data : [];
|
||||
const record = await repo.getPlatformConfigByKey('message_template_rules');
|
||||
const rules = (record && record.valueJson) || {};
|
||||
const clean = (v: any) => String(v == null ? '' : v).trim();
|
||||
const configured = {
|
||||
orderStatus: clean(rules.orderStatusTemplateId),
|
||||
activityJoin: clean(rules.activityJoinTemplateId),
|
||||
withdrawSuccess: clean(rules.withdrawSuccessTemplateId),
|
||||
verifyCode: clean(rules.verifyCodeTemplateId),
|
||||
};
|
||||
// 以服务端为准做匹配:两侧均 trim,避免因末尾空白/换行导致的误报
|
||||
const existing = new Set(list.map((t: any) => clean(t.priTmplId)));
|
||||
const mismatched = Object.entries(configured)
|
||||
.filter(([, id]) => Boolean(id) && !existing.has(id))
|
||||
.map(([key, id]) => ({ key, templateId: id }));
|
||||
res.json({
|
||||
code: 20000,
|
||||
data: {
|
||||
@@ -3940,18 +3952,14 @@ app.get('/api/admin/message/templates', async (_req: Request, res: Response) =>
|
||||
errmsg: (data && data.errmsg) || 'ok',
|
||||
count: list.length,
|
||||
templates: list.map((t: any) => ({
|
||||
templateId: t.priTmplId,
|
||||
templateId: clean(t.priTmplId),
|
||||
title: t.title,
|
||||
type: t.type,
|
||||
content: t.content,
|
||||
example: t.example,
|
||||
})),
|
||||
configured: {
|
||||
orderStatus: String(rules.orderStatusTemplateId || ''),
|
||||
activityJoin: String(rules.activityJoinTemplateId || ''),
|
||||
withdrawSuccess: String(rules.withdrawSuccessTemplateId || ''),
|
||||
verifyCode: String(rules.verifyCodeTemplateId || ''),
|
||||
},
|
||||
configured,
|
||||
mismatched,
|
||||
},
|
||||
});
|
||||
} catch (err: any) {
|
||||
|
||||
@@ -44,6 +44,12 @@ describe('第七十批订阅消息原因可见与真实授权', () => {
|
||||
expect(indexCode).toContain('appIdMasked');
|
||||
});
|
||||
|
||||
it('模板ID匹配以后端为准并做 trim,避免误报不匹配', () => {
|
||||
expect(indexCode).toContain('const mismatched = Object.entries(configured)');
|
||||
expect(indexCode).toContain('const clean = (v: any) => String(v == null');
|
||||
expect(adminCode).toContain('t.mismatched');
|
||||
});
|
||||
|
||||
it('小程序真正调用订阅授权并过滤占位符', () => {
|
||||
expect(subscribeCode).toContain('requestSubscribeAll');
|
||||
expect(subscribeCode).toContain("startsWith('tmpl_')");
|
||||
|
||||
在新工单中引用
屏蔽一个用户