import { message } from 'ant-design-vue'; import axios from 'axios'; import { useAccessStore } from '@vben/stores'; // 创建 Axios 实例 const service = axios.create({ baseURL: '/im-api/', timeout: 15_000, }); // 请求拦截器 service.interceptors.request.use( (config) => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { console.error('Request error:', error); return Promise.reject(error); }, ); // 响应拦截器 service.interceptors.response.use( (response) => { const { code, result, message: msg } = response.data; if (code === 0) { return result; } else { if (code === 401) { message.error(msg); localStorage.removeItem('token'); localStorage.removeItem('chatUser'); window.location.href = '/login'; return Promise.reject(new Error(msg)); } message.error(msg); return Promise.reject(new Error(msg)); } }, (error) => { console.error('Response error:', error); // 详细的错误处理 if (error.code === 'ECONNABORTED') { console.log('请求超时,请检查网络连接'); } else if (error.response?.status === 0 || error.message.includes('CORS')) { console.log('CORS错误检测到,尝试备用方案...'); handleCORSError(error.config); } else if (error.response?.status >= 400 && error.response?.status < 500) { console.log('客户端错误:', error.response.status, error.response.data); } else if (error.response?.status >= 500) { console.log('服务器错误:', error.response.status); } else { console.log('网络错误:', error.message); } message.error('网络请求失败'); return Promise.reject(error); }, ); // CORS错误的备用处理方案 const handleCORSError = (config) => { console.log('执行CORS错误备用方案...'); const apiUrl = config.url.replace('/api', ''); return fetch(apiUrl, { method: config.method.toUpperCase(), headers: { 'Content-Type': 'application/json', ...config.headers, }, mode: 'cors', body: config.data ? JSON.stringify(config.data) : undefined, }) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .catch((error) => { console.error('备用方案也失败:', error); throw error; }); }; // 封装请求方法 export const get = (url, params = {}) => { return service.get(url, { params }); }; export const post = (url, data = {}) => { return service.post(url, data); }; export const upload = (url, file) => { const formData = new FormData(); formData.append('file', file); return service.post(url, formData, { headers: { 'Content-Type': 'multipart/form-data', }, }); }; // 发送普通消息API export const sendMessage = (data) => { const apiUrl = '/im-api/send-to-user'; // 消息类型映射 - 根据用户提供的完整映射更新 const messageTypeMap: any = { text: 0, image: 1, audio: 2, video: 3, prescription: 4, 'medical-record': 5, 'video-call': 6, 'audio-call': 7, file: 8, register: 10, 'patient-experience': 11, 'product-card': 12, 'end-consultation': 13, }; // 确保 receiver_user_id 有 user- 前缀(如果是患者端) const receiverId = data.receiverId.toString(); const normalizedReceiverId = receiverId.startsWith('user-') ? receiverId : `user-${receiverId}`; // 确保 sender_user_id 有 doctor- 前缀(医生端) const senderId = data.senderId.toString(); const normalizedSenderId = senderId.startsWith('doctor-') ? senderId : `doctor-${senderId}`; const requestData = { room_id: data.roomId, sender_user_id: normalizedSenderId, receiver_user_id: normalizedReceiverId, message_type: messageTypeMap[data.type] || 0, message_content: data.content || '', duration: data.duration || 0, }; // 如果包含通话信令,添加call_id和call_status if (data.callId) { requestData.call_id = data.callId; } if (data.callStatus) { requestData.call_status = data.callStatus; } // 从 accessStore 获取 Token const accessStore = useAccessStore(); const token = accessStore.accessToken; return axios .post(apiUrl, requestData, { headers: { 'Content-Type': 'application/json', 'Authorization': token ? (token.startsWith('Bearer ') ? token : `Bearer ${token}`) : '', }, timeout: 15_000, withCredentials: false, }) .then((response) => { console.log('消息发送成功:', response.data); return response.data; }) .catch((error) => { console.error('消息发送失败:', error); throw error; }); }; // 专门的通话信令发送方法 export const sendCallSignal = (signalData) => { const apiUrl = '/api/send-to-user'; // 验证必要参数 if (!signalData.sender_user_id) { throw new Error('缺少发送方用户ID'); } if (!signalData.receiver_user_id) { throw new Error('缺少接收方用户ID'); } if (!signalData.call_id) { throw new Error('缺少通话ID'); } if (!signalData.call_status) { throw new Error('缺少通话状态'); } // 确保 receiver_user_id 有 user- 前缀(如果是患者端) const receiverId = signalData.receiver_user_id; const normalizedReceiverId = receiverId.startsWith('user-') || receiverId.startsWith('doctor-') ? receiverId : `user-${receiverId}`; // 构建通话信令请求数据 const requestData = { sender_user_id: signalData.sender_user_id, receiver_user_id: normalizedReceiverId, message_type: signalData.message_type || 6, // 默认视频通话 message_content: signalData.message_content || JSON.stringify(signalData.data || {}), call_id: signalData.call_id, call_status: signalData.call_status, // 添加来源标记 isFromHttp: true, }; console.log('发送通话信令到API:', apiUrl, requestData); // 从 accessStore 获取 Token const accessStore = useAccessStore(); const token = accessStore.accessToken; return axios .post(apiUrl, requestData, { headers: { 'Content-Type': 'application/json', 'Authorization': token ? (token.startsWith('Bearer ') ? token : `Bearer ${token}`) : '', }, timeout: 15_000, withCredentials: false, }) .then((response) => { console.log('通话信令发送成功:', response.data); return response.data; }) .catch((error) => { console.error('通话信令发送失败:', error); // 提供更详细的错误信息 if (error.response) { console.error('响应错误:', error.response.data); console.error('响应状态:', error.response.status); console.error('响应头:', error.response.headers); } else if (error.request) { console.error('请求错误:', error.request); } else { console.error('配置错误:', error.message); } throw error; }); }; // 通话相关的便捷方法 export const callAPI = { // 发起通话邀请 invite: (senderUserId, receiverUserId, callId, callType = 6) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'invite', message_type: callType, // 6=视频, 7=语音 }); }, // 接受通话 accept: (senderUserId, receiverUserId, callId, callType = 6) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'accepted', message_type: callType, }); }, // 拒绝通话 reject: (senderUserId, receiverUserId, callId, callType = 6) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'rejected', message_type: callType, }); }, // 结束通话 end: (senderUserId, receiverUserId, callId, callType = 6) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'ended', message_type: callType, }); }, // 发送WebRTC Offer sendOffer: ( senderUserId, receiverUserId, callId, offerData, callType = 6, ) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'offer', message_type: callType, data: offerData, }); }, // 发送WebRTC Answer sendAnswer: ( senderUserId, receiverUserId, callId, answerData, callType = 6, ) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'answer', message_type: callType, data: answerData, }); }, // 发送ICE候选 sendCandidate: ( senderUserId, receiverUserId, callId, candidateData, callType = 6, ) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'candidate', message_type: callType, data: candidateData, }); }, // 发送忙线状态 sendBusy: (senderUserId, receiverUserId, callId, callType = 6) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'busy', message_type: callType, }); }, // 发送无人接听 sendNoAnswer: (senderUserId, receiverUserId, callId, callType = 6) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'no-answer', message_type: callType, }); }, // 发送通话失败 sendFailed: (senderUserId, receiverUserId, callId, callType = 6) => { return sendCallSignal({ sender_user_id: senderUserId, receiver_user_id: receiverUserId, call_id: callId, call_status: 'failed', message_type: callType, }); }, }; export default service;