feat(iit-manager): Add WeChat Official Account integration for patient notifications

Features:
- PatientWechatCallbackController for URL verification and message handling
- PatientWechatService for template and customer messages
- Support for secure mode (message encryption/decryption)
- Simplified route /wechat/patient/callback for WeChat config
- Event handlers for subscribe/unsubscribe/text messages
- Template message for visit reminders

Technical details:
- Reuse @wecom/crypto for encryption (compatible with Official Account)
- Relaxed Fastify schema validation to prevent early request blocking
- Access token caching (7000s with 5min pre-refresh)
- Comprehensive logging for debugging

Testing: Local URL verification passed, ready for SAE deployment

Status: Code complete, waiting for WeChat platform configuration
This commit is contained in:
2026-01-04 22:53:42 +08:00
parent dfc472810b
commit b31255031e
167 changed files with 3055 additions and 2 deletions

View File

@@ -0,0 +1,167 @@
/**
* 生成微信服务号Token和EncodingAESKey
*
* 功能:
* 1. 生成符合要求的Token3-32位
* 2. 生成符合要求的EncodingAESKey43位
* 3. 输出可直接复制的环境变量配置
*/
import crypto from 'crypto';
console.log('🔐 微信服务号Token和EncodingAESKey生成器');
console.log('='.repeat(60));
console.log('');
// ==================== 1. 生成Token ====================
console.log('🔑 生成Token用于签名验证...\n');
function generateToken(length: number = 32): string {
// 生成随机字符串(只包含字母和数字)
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let token = '';
const randomBytes = crypto.randomBytes(length);
for (let i = 0; i < length; i++) {
token += chars[randomBytes[i] % chars.length];
}
return token;
}
const token = generateToken(32);
console.log(' 生成的Token:');
console.log(` ${token}`);
console.log(` 长度: ${token.length}`);
console.log(` 说明: 用于URL验证和消息签名验证`);
console.log('');
// ==================== 2. 生成EncodingAESKey ====================
console.log('🔐 生成EncodingAESKey用于消息加解密...\n');
function generateEncodingAESKey(): string {
// 生成43位随机字符串Base64字符集不包含/+=
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let aesKey = '';
const randomBytes = crypto.randomBytes(43);
for (let i = 0; i < 43; i++) {
aesKey += chars[randomBytes[i] % chars.length];
}
return aesKey;
}
const aesKey = generateEncodingAESKey();
console.log(' 生成的EncodingAESKey:');
console.log(` ${aesKey}`);
console.log(` 长度: ${aesKey.length}`);
console.log(` 说明: 用于消息加密和解密(安全模式必需)`);
console.log('');
// ==================== 3. 输出环境变量配置 ====================
console.log('='.repeat(60));
console.log('\n📋 环境变量配置(复制以下内容到 backend/.env 文件)\n');
console.log('='.repeat(60));
console.log('');
console.log('# ==========================================');
console.log('# 微信服务号配置(患者端)');
console.log('# ==========================================');
console.log('');
console.log('# 微信服务号基础配置');
console.log('WECHAT_MP_APP_ID=wx062568ff49e4570c');
console.log('WECHAT_MP_APP_SECRET=c0d19435d1a1e948939c16d767ec0faf');
console.log('');
console.log('# 微信服务号回调配置(消息加解密,安全模式)');
console.log(`WECHAT_MP_TOKEN=${token}`);
console.log(`WECHAT_MP_ENCODING_AES_KEY=${aesKey}`);
console.log('');
console.log('# 微信小程序配置(可选,后续开发)');
console.log('WECHAT_MINI_APP_ID=');
console.log('');
// ==================== 4. 输出微信公众平台配置 ====================
console.log('='.repeat(60));
console.log('\n📋 微信公众平台配置(复制以下内容到公众平台)\n');
console.log('='.repeat(60));
console.log('');
console.log('登录地址https://mp.weixin.qq.com/');
console.log('配置路径:设置与开发 → 基本配置 → 服务器配置');
console.log('');
console.log('配置参数:');
console.log('');
console.log(' 【URL】');
console.log(' 生产环境https://iit.xunzhengyixue.com/api/v1/iit/patient-wechat/callback');
console.log(' 开发环境https://devlocal.xunzhengyixue.com/api/v1/iit/patient-wechat/callback');
console.log('');
console.log(' 【Token】');
console.log(` ${token}`);
console.log('');
console.log(' 【EncodingAESKey】');
console.log(` ${aesKey}`);
console.log('');
console.log(' 【消息加解密方式】');
console.log(' 安全模式(推荐)');
console.log('');
console.log(' 【数据格式】');
console.log(' XML');
console.log('');
// ==================== 5. 输出后续步骤 ====================
console.log('='.repeat(60));
console.log('\n📝 后续步骤\n');
console.log('='.repeat(60));
console.log('');
console.log('Step 1: 更新环境变量');
console.log(' 1. 复制上面的环境变量配置');
console.log(' 2. 粘贴到 backend/.env 文件');
console.log(' 3. 保存文件');
console.log('');
console.log('Step 2: 验证配置');
console.log(' 运行配置检查脚本:');
console.log(' npx tsx src/modules/iit-manager/test-patient-wechat-config.ts');
console.log('');
console.log('Step 3: 启动服务');
console.log(' 本地开发npm run dev');
console.log(' 生产环境部署到SAE');
console.log('');
console.log('Step 4: 配置微信公众平台');
console.log(' 1. 登录微信公众平台');
console.log(' 2. 填写上面的配置参数');
console.log(' 3. 点击"提交"进行URL验证');
console.log(' 4. 验证成功后点击"启用"');
console.log('');
console.log('Step 5: 测试功能');
console.log(' 运行URL验证测试脚本');
console.log(' npx tsx src/modules/iit-manager/test-patient-wechat-url-verify.ts');
console.log('');
console.log('='.repeat(60));
console.log('\n⚠ 重要提示\n');
console.log('='.repeat(60));
console.log('');
console.log(' 1. Token和EncodingAESKey必须在.env和微信公众平台中保持一致');
console.log(' 2. 不要将Token和EncodingAESKey提交到Git仓库');
console.log(' 3. 生产环境需要在SAE中配置这些环境变量');
console.log(' 4. 如果配置错误,可以重新运行本脚本生成新的值');
console.log(' 5. 修改配置后需要重启服务才能生效');
console.log('');
console.log('🎉 生成完成!');
console.log('');