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
137 lines
2.1 KiB
TypeScript
137 lines
2.1 KiB
TypeScript
/**
|
||
* DC模块 - 最近任务Hook
|
||
*
|
||
* 管理最近任务列表的状态和数据获取
|
||
*/
|
||
|
||
import { useState, useEffect } from 'react';
|
||
import type { Task } from '../types/portal';
|
||
|
||
// Mock数据
|
||
const mockTasks: Task[] = [
|
||
{
|
||
id: 'task-001',
|
||
name: '2025糖尿病研究数据提取',
|
||
tool: 'tool-b',
|
||
toolName: 'AI结构化',
|
||
status: 'completed',
|
||
progress: 100,
|
||
createdAt: '2025-12-01T10:30:00Z',
|
||
completedAt: '2025-12-01T11:45:00Z'
|
||
},
|
||
{
|
||
id: 'task-002',
|
||
name: '高血压病历结构化处理',
|
||
tool: 'tool-b',
|
||
toolName: 'AI结构化',
|
||
status: 'processing',
|
||
progress: 65,
|
||
createdAt: '2025-12-02T09:15:00Z'
|
||
},
|
||
{
|
||
id: 'task-003',
|
||
name: '多中心数据合并任务',
|
||
tool: 'tool-a',
|
||
toolName: '超级合并器',
|
||
status: 'pending',
|
||
progress: 0,
|
||
createdAt: '2025-12-02T13:20:00Z'
|
||
}
|
||
];
|
||
|
||
export const useRecentTasks = () => {
|
||
const [tasks, setTasks] = useState<Task[]>([]);
|
||
const [loading, setLoading] = useState(true);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
// 获取任务列表
|
||
const fetchTasks = async () => {
|
||
try {
|
||
setLoading(true);
|
||
|
||
// TODO: 替换为真实API调用
|
||
// const response = await fetch('/api/v1/dc/tasks/recent');
|
||
// const data = await response.json();
|
||
|
||
// 模拟API延迟
|
||
await new Promise(resolve => setTimeout(resolve, 500));
|
||
|
||
setTasks(mockTasks);
|
||
setError(null);
|
||
} catch (err) {
|
||
setError(err instanceof Error ? err.message : '获取任务列表失败');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
// 轮询更新(processing状态的任务每5秒更新一次)
|
||
useEffect(() => {
|
||
fetchTasks();
|
||
|
||
const hasProcessingTasks = tasks.some(t => t.status === 'processing');
|
||
|
||
if (hasProcessingTasks) {
|
||
const interval = setInterval(() => {
|
||
fetchTasks();
|
||
}, 5000); // 5秒轮询
|
||
|
||
return () => clearInterval(interval);
|
||
}
|
||
}, []);
|
||
|
||
// 刷新任务列表
|
||
const refresh = () => {
|
||
fetchTasks();
|
||
};
|
||
|
||
return {
|
||
tasks,
|
||
loading,
|
||
error,
|
||
refresh
|
||
};
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|