158 lines
4.6 KiB
TypeScript
158 lines
4.6 KiB
TypeScript
import type { WecomTemplateEventKey } from '@dukang/shared-types';
|
|
|
|
export type WecomTemplateDefault = {
|
|
eventKey: WecomTemplateEventKey;
|
|
title: string;
|
|
body: string;
|
|
handleLabel: string;
|
|
};
|
|
|
|
/** 代码内默认文案;ensureDefaults 仅在库中无行时写入,不覆盖 HQ 已改 */
|
|
export const WECOM_PUSH_TEMPLATE_DEFAULTS: WecomTemplateDefault[] = [
|
|
{
|
|
eventKey: 'order.paid',
|
|
title: '订单支付成功',
|
|
body: [
|
|
'**订单支付成功**',
|
|
'订单号:{{orderNo}}',
|
|
'实付:¥{{payAmount}}',
|
|
'城市:{{cityName}}',
|
|
'商品:{{skuSummary}}',
|
|
'用户:{{phoneMasked}}',
|
|
'时间:{{time}}',
|
|
'[{{handleLabel}}]({{handleUrl}})',
|
|
].join('\n'),
|
|
handleLabel: '去处理',
|
|
},
|
|
{
|
|
eventKey: 'redeem.success',
|
|
title: '门店核销成功',
|
|
body: [
|
|
'**门店核销成功**',
|
|
'核销单号:{{redeemNo}}',
|
|
'金额:¥{{amount}}',
|
|
'门店:{{storeName}}',
|
|
'渠道:{{channel}}',
|
|
'时间:{{time}}',
|
|
'[{{handleLabel}}]({{handleUrl}})',
|
|
].join('\n'),
|
|
handleLabel: '去处理',
|
|
},
|
|
{
|
|
eventKey: 'store.audit_pending',
|
|
title: '门店审核待处理',
|
|
body: [
|
|
'**门店审核待处理 · {{action}}**',
|
|
'门店:{{storeName}}',
|
|
'城市:{{cityName}}',
|
|
'合伙人:{{partnerLabel}}',
|
|
'时间:{{time}}',
|
|
'[{{handleLabel}}]({{handleUrl}})',
|
|
].join('\n'),
|
|
handleLabel: '去处理',
|
|
},
|
|
{
|
|
eventKey: 'store.package_audit_pending',
|
|
title: '套餐变更待审核',
|
|
body: [
|
|
'**套餐变更待审核**',
|
|
'门店:{{storeName}}',
|
|
'城市:{{cityName}}',
|
|
'提交端:{{submitter}}',
|
|
'套餐条数:{{packageCount}}',
|
|
'时间:{{time}}',
|
|
'[{{handleLabel}}]({{handleUrl}})',
|
|
].join('\n'),
|
|
handleLabel: '去处理',
|
|
},
|
|
{
|
|
eventKey: 'store.info_change_pending',
|
|
title: '门店信息变更待审',
|
|
body: [
|
|
'**门店信息变更待审**',
|
|
'门店:{{storeName}}',
|
|
'城市:{{cityName}}',
|
|
'提交端:{{submitter}}',
|
|
'变更字段:{{changedFields}}',
|
|
'时间:{{time}}',
|
|
'[{{handleLabel}}]({{handleUrl}})',
|
|
].join('\n'),
|
|
handleLabel: '去处理',
|
|
},
|
|
{
|
|
eventKey: 'store.withdraw_pending',
|
|
title: '门店提现待审',
|
|
body: [
|
|
'**门店提现待审**',
|
|
'门店:{{storeName}}',
|
|
'提现单号:{{withdrawNo}}',
|
|
'金额:¥{{amount}}',
|
|
'明细笔数:{{payoutCount}}',
|
|
'时间:{{time}}',
|
|
'[{{handleLabel}}]({{handleUrl}})',
|
|
].join('\n'),
|
|
handleLabel: '去处理',
|
|
},
|
|
{
|
|
eventKey: 'invoice.pending',
|
|
title: '发票申请待开票',
|
|
body: [
|
|
'**发票申请待开票**',
|
|
'申请单号:{{invoiceNo}}',
|
|
'订单号:{{orderNo}}',
|
|
'金额:¥{{payAmount}}',
|
|
'抬头:{{titleName}}',
|
|
'用户:{{phoneMasked}}',
|
|
'时间:{{time}}',
|
|
'[{{handleLabel}}]({{handleUrl}})',
|
|
].join('\n'),
|
|
handleLabel: '去处理',
|
|
},
|
|
];
|
|
|
|
export function getDefaultTemplate(eventKey: string): WecomTemplateDefault | undefined {
|
|
return WECOM_PUSH_TEMPLATE_DEFAULTS.find((t) => t.eventKey === eventKey);
|
|
}
|
|
|
|
/** 将 body 中的 {{key}} 替换为 vars;缺失置空 */
|
|
export function renderWecomTemplate(
|
|
body: string,
|
|
vars: Record<string, string | number | null | undefined>,
|
|
): string {
|
|
return body.replace(/\{\{(\w+)\}\}/g, (_m, key: string) => {
|
|
const v = vars[key];
|
|
if (v == null) return '';
|
|
return String(v);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* HQ 后台公网根地址(无尾斜杠)。
|
|
* 优先 HQ_ADMIN_PUBLIC_URL;未配时按 WECOM_ALERT_ENV_LABEL / NODE_ENV 回退,
|
|
* 避免相对路径被企微解析成 http://orders/... 这类无效链接。
|
|
*/
|
|
export function resolveHqAdminPublicBase(): string {
|
|
const configured = (process.env.HQ_ADMIN_PUBLIC_URL || '').trim().replace(/\/$/, '');
|
|
if (configured) return configured;
|
|
|
|
const label = (process.env.WECOM_ALERT_ENV_LABEL || process.env.NODE_ENV || '')
|
|
.trim()
|
|
.toLowerCase();
|
|
if (label === 'production' || label === 'prod') {
|
|
return 'https://admin.dukanghaoke.com';
|
|
}
|
|
if (label === 'staging' || label === 'test' || label === 'testing') {
|
|
return 'https://admin-test.dukanghaoke.com';
|
|
}
|
|
// local / development / 未识别:本机 admin-web 默认端口
|
|
return 'http://localhost:5175';
|
|
}
|
|
|
|
export function buildHqHandleUrl(pathWithQuery: string): string {
|
|
const base = resolveHqAdminPublicBase();
|
|
let path = (pathWithQuery || '').trim();
|
|
if (!path) return base;
|
|
if (!path.startsWith('/')) path = `/${path}`;
|
|
return `${base}${path}`;
|
|
}
|