Files
AIclinicalresearch/backend/src/modules/iit-manager/test-patient-wechat-url-verify.ts
HaHafeng 96290d2f76 feat(aia): Implement Protocol Agent MVP with reusable Agent framework
Sprint 1-3 Completed (Backend + Frontend):

Backend (Sprint 1-2):
- Implement 5-layer Agent framework (Query->Planner->Executor->Tools->Reflection)
- Create agent_schema with 6 tables (agent_definitions, stages, prompts, sessions, traces, reflexion_rules)
- Create protocol_schema with 2 tables (protocol_contexts, protocol_generations)
- Implement Protocol Agent core services (Orchestrator, ContextService, PromptBuilder)
- Integrate LLM service adapter (DeepSeek/Qwen/GPT-5/Claude)
- 6 API endpoints with full authentication
- 10/10 API tests passed

Frontend (Sprint 3):
- Add Protocol Agent entry in AgentHub (indigo theme card)
- Implement ProtocolAgentPage with 3-column layout
- Collapsible sidebar (Gemini style, 48px <-> 280px)
- StatePanel with 5 stage cards (scientific_question, pico, study_design, sample_size, endpoints)
- ChatArea with sync button and action cards integration
- 100% prototype design restoration (608 lines CSS)
- Detailed endpoints structure: baseline, exposure, outcomes, confounders

Features:
- 5-stage dialogue flow for research protocol design
- Conversation-driven interaction with sync-to-protocol button
- Real-time context state management
- One-click protocol generation button (UI ready, backend pending)

Database:
- agent_schema: 6 tables for reusable Agent framework
- protocol_schema: 2 tables for Protocol Agent
- Seed data: 1 agent + 5 stages + 9 prompts + 4 reflexion rules

Code Stats:
- Backend: 13 files, 4338 lines
- Frontend: 14 files, 2071 lines
- Total: 27 files, 6409 lines

Status: MVP core functionality completed, pending frontend-backend integration testing

Next: Sprint 4 - One-click protocol generation + Word export
2026-01-24 17:29:24 +08:00

202 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 微信服务号URL验证测试脚本
*
* 功能:
* 1. 模拟微信服务器发送GET请求验证URL
* 2. 测试签名生成和验证逻辑
* 3. 验证服务端是否正确返回echostr
*/
import axios from 'axios';
import crypto from 'crypto';
import dotenv from 'dotenv';
import path from 'path';
import { fileURLToPath } from 'url';
// 获取当前文件目录
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 加载.env文件
dotenv.config({ path: path.resolve(__dirname, '../../../.env') });
const BASE_URL = process.env.API_BASE_URL || 'http://localhost:3001';
const TOKEN = process.env.WECHAT_MP_TOKEN || '';
console.log('🧪 微信服务号URL验证测试');
console.log('='.repeat(60));
console.log('');
// ==================== 1. 检查配置 ====================
if (!TOKEN) {
console.error('❌ 未配置 WECHAT_MP_TOKEN请检查 .env 文件');
process.exit(1);
}
console.log('📋 测试环境:');
console.log(` BASE_URL: ${BASE_URL}`);
console.log(` TOKEN: ${TOKEN.substring(0, 10)}... (长度: ${TOKEN.length})`);
console.log('');
// ==================== 2. 生成测试参数 ====================
console.log('🔧 生成测试参数...\n');
const timestamp = Date.now().toString();
const nonce = Math.random().toString(36).substring(2, 12);
const echostr = 'test_echo_' + Math.random().toString(36).substring(2);
console.log(' timestamp: ' + timestamp);
console.log(` nonce: ${nonce}`);
console.log(` echostr: ${echostr}\n`);
// ==================== 3. 生成签名 ====================
console.log('🔐 生成签名...\n');
const arr = [TOKEN, timestamp, nonce].sort();
const str = arr.join('');
const signature = crypto.createHash('sha1').update(str).digest('hex');
console.log(` 排序后拼接: ${str.substring(0, 50)}...`);
console.log(` SHA1哈希: ${signature}\n`);
// ==================== 4. 发送GET请求 ====================
async function testUrlVerification() {
console.log('📤 发送URL验证请求...\n');
const url = `${BASE_URL}/api/v1/iit/patient-wechat/callback`;
console.log(` 请求URL: ${url}`);
console.log(` 请求方法: GET`);
console.log(` 查询参数:`);
console.log(` signature: ${signature}`);
console.log(` timestamp: ${timestamp}`);
console.log(` nonce: ${nonce}`);
console.log(` echostr: ${echostr}\n`);
try {
const response = await axios.get(url, {
params: {
signature,
timestamp,
nonce,
echostr,
},
timeout: 5000,
});
console.log('='.repeat(60));
console.log('\n✅ URL验证成功\n');
console.log(`HTTP状态码: ${response.status}`);
console.log(`返回内容类型: ${response.headers['content-type']}`);
console.log(`返回内容: ${response.data}\n`);
// 验证返回内容
if (response.data === echostr) {
console.log('✅ 返回的echostr正确验证通过\n');
console.log('='.repeat(60));
console.log('\n🎉 测试成功!您的服务端配置正确\n');
console.log('📝 后续步骤:');
console.log(' 1. 登录微信公众平台https://mp.weixin.qq.com/');
console.log(' 2. 进入:设置与开发 → 基本配置 → 服务器配置');
console.log(' 3. 填写以下信息:');
console.log(` URL: ${BASE_URL}/api/v1/iit/patient-wechat/callback`);
console.log(` Token: ${TOKEN}`);
console.log(` EncodingAESKey: ${process.env.WECHAT_MP_ENCODING_AES_KEY?.substring(0, 10)}...`);
console.log(' 4. 选择"安全模式"');
console.log(' 5. 点击"提交"进行验证');
console.log(' 6. 验证成功后点击"启用"');
console.log('');
} else {
console.error('❌ 返回的echostr不正确');
console.error(` 期望: ${echostr}`);
console.error(` 实际: ${response.data}\n`);
process.exit(1);
}
} catch (error: any) {
console.log('='.repeat(60));
console.error('\n❌ URL验证失败\n');
if (error.code === 'ECONNREFUSED') {
console.error('连接被拒绝,可能的原因:');
console.error(' 1. 后端服务未启动');
console.error(' 2. 端口号不正确');
console.error('\n解决方法');
console.error(' 1. 运行 npm run dev 启动后端服务');
console.error(' 2. 确认服务运行在正确的端口默认3001');
} else if (error.response) {
console.error(`HTTP状态码: ${error.response.status}`);
console.error(`错误信息: ${error.response.statusText}`);
console.error(`响应内容: ${JSON.stringify(error.response.data, null, 2)}`);
if (error.response.status === 403) {
console.error('\n可能的原因');
console.error(' 1. Token配置不一致');
console.error(' 2. 签名验证失败');
console.error('\n解决方法');
console.error(' 1. 检查 .env 文件中的 WECHAT_MP_TOKEN');
console.error(' 2. 运行配置检查脚本:');
console.error(' npx tsx src/modules/iit-manager/test-patient-wechat-config.ts');
} else if (error.response.status === 404) {
console.error('\n可能的原因');
console.error(' 1. 路由未注册');
console.error(' 2. URL路径不正确');
console.error('\n解决方法');
console.error(' 1. 确认路由已在 routes/index.ts 中注册');
console.error(' 2. 检查URL路径是否正确');
}
} else {
console.error(`错误信息: ${error.message}`);
}
console.error('\n');
process.exit(1);
}
}
// ==================== 5. 执行测试 ====================
(async () => {
try {
await testUrlVerification();
} catch (error: any) {
console.error('测试执行异常:', error.message);
process.exit(1);
}
})();