feat(consignment): 匹配成功短信通知并支持模板配置

This commit is contained in:
2026-11-06 14:58:29 +08:00
parent 8b7bcca36a
commit 1044948c99
10 changed files with 539 additions and 15 deletions
+36 -2
View File
@@ -20,8 +20,18 @@ type AliyunSmsClient = {
): Promise<{ body?: { code?: string; message?: string } }>
}
export type SmsTemplateMessage = {
/** 阿里云审核通过的模板 Code;Mock 模式可留空 */
templateCode: string
/** 模板变量,key 与模板中的 ${name} 对应 */
params: Record<string, string>
/** 渲染后的完整文案,仅用于 Mock 日志与发送记录 */
content: string
}
export interface SmsProvider {
sendCode(phone: string, code: string): Promise<void>
sendTemplate(phone: string, message: SmsTemplateMessage): Promise<void>
}
const ALIYUN_DEFAULT_ENDPOINT = 'dysmsapi.aliyuncs.com'
@@ -55,6 +65,15 @@ export class MockSmsProvider implements SmsProvider {
hint: '生产环境请配置 WORKER_SMS_PROVIDER=aliyun 后使用真实短信',
})
}
async sendTemplate(phone: string, message: SmsTemplateMessage) {
logWarn('[sms/mock]', `【开发模式】短信模板:${phone} → ${message.content}`, {
phone,
templateCode: message.templateCode,
params: message.params,
hint: '生产环境请配置 WORKER_SMS_PROVIDER=aliyun 后使用真实短信',
})
}
}
export class AliyunSmsProvider implements SmsProvider {
@@ -82,12 +101,27 @@ export class AliyunSmsProvider implements SmsProvider {
}
async sendCode(phone: string, code: string) {
await this.send(phone, this.templateCode, { code })
}
async sendTemplate(phone: string, message: SmsTemplateMessage) {
await this.send(phone, message.templateCode, message.params)
}
private async send(phone: string, templateCode: string, params: Record<string, string>) {
try {
const code = String(templateCode || '').trim()
if (!code) {
throw createHttpError('短信模板 Code 未配置', {
statusCode: 500,
errorCode: 'worker_sms_template_missing',
})
}
const request = new Dysmsapi.SendSmsRequest({
phoneNumbers: phone,
signName: this.signName,
templateCode: this.templateCode,
templateParam: JSON.stringify({ code }),
templateCode: code,
templateParam: JSON.stringify(params),
})
const response = await this.client.sendSmsWithOptions(request, {})
const resultCode = String(response?.body?.code || '')