import {useState, useEffect, useRef} from 'react' import {View, Text} from '@tarojs/components' import Taro, {useDidShow, useRouter, useLoad} from '@tarojs/taro' import {Input, Button} from '@nutui/nutui-react-taro' import {Voice, FaceMild} from '@nutui/icons-react-taro' import {getClinicDoctorUserByUserId} from "@/api/clinic/clinicDoctorUser"; import {addShopChatMessage, listShopChatMessage} from "@/api/shop/shopChatMessage"; import {ShopChatMessage} from "@/api/shop/shopChatMessage/model"; import {addShopChatConversation, chatConversationByBothUserId} from "@/api/shop/shopChatConversation"; // @ts-ignore import {WS_URL} from "@/config/env"; import {clinicPatientUserByPatientUserId} from "@/api/clinic/clinicPatientUser"; const CustomerIndex = () => { const {params} = useRouter() const [messages, setMessages] = useState([]) const [conversationId, setConversationId] = useState(null) const [friendUserId, setFriendUserId] = useState('') const [messageInput, setMessageInput] = useState('') const [sending, setSending] = useState(false) const [isDoctor, setIsDoctor] = useState(false) const socketRef = useRef(null) const quickActions = [ {label: '开方', type: 'prescription'}, {label: '快捷回复', type: 'quickReply'}, {label: '发问诊单', type: 'sendInquiry'} ] const handleQuickAction = (actionType: string) => { switch (actionType) { case 'prescription': if (friendUserId) { Taro.navigateTo({url: `/doctor/orders/add?id=${friendUserId}`}) } else { Taro.showToast({title: '请选择患者', icon: 'none'}) } break case 'quickReply': Taro.showToast({title: '快捷回复敬请期待', icon: 'none'}) break case 'sendInquiry': Taro.showToast({title: '问诊单功能敬请期待', icon: 'none'}) break } } const fetchData = async (userId?: string) => { if (!userId) return try { console.log("Taro.getStorageSync('Doctor')", Taro.getStorageSync('Doctor')) if (Taro.getStorageSync('Doctor')) { setIsDoctor(true) } const isDoctorData = Taro.getStorageSync('Doctor') if (!isDoctorData) { const doctorUser = await getClinicDoctorUserByUserId(Number(params.userId)) if (doctorUser?.realName) { await Taro.setNavigationBarTitle({title: `${doctorUser.realName}`}) } } else { const patient = await clinicPatientUserByPatientUserId(Number(params.userId)) if (patient?.realName) { await Taro.setNavigationBarTitle({title: `${patient.realName}`}) } } let conversation = await chatConversationByBothUserId(userId) if (!conversation) { conversation = await addShopChatConversation({ friendId: parseInt(userId, 10), content: '' }) } if (conversation?.id) { setConversationId(conversation.id) const messageList = await listShopChatMessage({conversationId: conversation.id}) setMessages(messageList || []) } else { setMessages([]) } } catch (error) { console.error('加载聊天数据失败:', error) Taro.showToast({title: '聊天加载失败', icon: 'none'}) } } const connectWebSocket = async (id: number) => { const base = (WS_URL || '').replace(/\/$/, '') if (!base) { console.warn('WS_URL 未配置') return } if (socketRef.current) { socketRef.current.close({}) } const userId = Taro.getStorageSync('UserId') const result = Taro.connectSocket({ url: `${base}/${id}_${userId}` }) const socketTask = typeof (result as Promise)?.then === 'function' ? await (result as Promise) : (result as Taro.SocketTask) if (!socketTask) { return } socketRef.current = socketTask socketTask.onOpen(() => { console.log('WebSocket连接成功') }) socketTask.onMessage((event) => { console.log('收到消息:', event,) try { if (event.data === '连接成功' || event.data === 'pong') return const payload = typeof event.data === 'string' ? JSON.parse(event.data) : event.data if (!payload) return if (Array.isArray(payload)) { setMessages(prev => [...prev, ...payload]) } else { payload.isMine = parseInt(payload.fromUserId) !== parseInt(params?.userId) setMessages(prev => [...prev, payload]) } } catch (err) { console.error('解析消息失败:', err) } }) socketTask.onError((err) => { console.error('WebSocket异常:', err) }) socketTask.onClose(() => { socketRef.current = null }) } const handleSendMessage = async () => { const content = messageInput.trim() if (!content) { Taro.showToast({title: '请输入内容', icon: 'none'}) return } if (!conversationId || !friendUserId) { Taro.showToast({title: '会话未初始化', icon: 'none'}) return } if (sending) { return } try { setSending(true) await addShopChatMessage({ content, conversationId, toUserId: parseInt(friendUserId, 10), type: 'text' }) // const localMessage: ShopChatMessage = { // id: Date.now(), // content, // conversationId, // toUserId: parseInt(friendUserId, 10), // type: 'text', // isMine: true // } // // setMessages(prev => [...prev, localMessage]) setMessageInput('') } catch (error) { console.error('发送消息失败:', error) Taro.showToast({title: '发送失败,请重试', icon: 'none'}) } finally { setSending(false) } } useLoad((options) => { if (options?.userId) { const userId = String(options.userId) setFriendUserId(userId) fetchData(userId) } console.log('Taro.getStorageSync(\'UserId\')', Taro.getStorageSync('UserId')) }) useEffect(() => { if (conversationId) { connectWebSocket(conversationId).catch(err => { console.error('WebSocket连接失败:', err) }) } return () => { socketRef.current?.close() socketRef.current = null } }, [conversationId]) return ( {messages.length === 0 ? ( 暂时还没有聊天记录 ) : ( messages.map((item, index) => ( {item.content} )) )} {quickActions.map(action => ( handleQuickAction(action.type)} style={{ padding: '6px 12px', borderRadius: '20px', backgroundColor: '#fff', fontSize: '14px', color: '#8b5a2b', boxShadow: '0 4px 10px rgba(0,0,0,0.05)', display: 'flex', alignItems: 'center', flexShrink: 0 }} > {action.label} ))} setMessageInput(value)} confirmType="send" onConfirm={handleSendMessage} /> ) } export default CustomerIndex;