From 866d9ae0830d225a353ef083b10f49cc499b171b Mon Sep 17 00:00:00 2001 From: lq Date: Tue, 22 Jul 2025 16:54:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=81=8A=E5=A4=A9=EF=BC=88=E5=B7=B2?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=8F=91=E9=80=81=E6=96=87=E6=9C=AC=E9=9F=B3?= =?UTF-8?q?=E9=A2=91=E6=B6=88=E6=81=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/home/home.vue | 7 +- pages/index/index.vue | 136 ++++- request/api/request.js | 5 + store/chat/chat.js | 58 +- subPackages/chat/chat.vue | 619 ++++++++++---------- subPackages/chat/components/AudioPlayer.vue | 84 +++ 6 files changed, 563 insertions(+), 346 deletions(-) create mode 100644 subPackages/chat/components/AudioPlayer.vue diff --git a/pages/home/home.vue b/pages/home/home.vue index 0f0ab48..cb458b5 100644 --- a/pages/home/home.vue +++ b/pages/home/home.vue @@ -609,7 +609,7 @@ .nav { width: 710rpx; background: #FFFFFF; - border-radius: 8rpx; + border-radius: 15rpx; display: flex; align-items: center; justify-content: space-between; @@ -623,6 +623,7 @@ justify-content: space-around; background: url('/static/home/bg01.png') no-repeat; background-size: 100% 100%; + border-radius: 24rpx; .nav_service_img { width: 116rpx; @@ -670,7 +671,7 @@ .list { width: 710rpx; background: linear-gradient(180deg, #E2F1FF 0%, #FBFDFF 54%, #FFFFFF 100%); - border-radius: 16rpx; + border-radius: 24rpx; padding: 12rpx 30rpx 22rpx; margin: 32rpx auto 52rpx; box-shadow: 0px 0px 16px 0px rgba(0, 0, 0, 0.08); @@ -861,7 +862,7 @@ .lists { width: 710rpx; background: linear-gradient(180deg, #E2F1FF 0%, #FBFDFF 54%, #FFFFFF 100%); - border-radius: 16rpx; + border-radius: 24rpx; padding: 30rpx; margin: 32rpx auto 52rpx; box-shadow: 0px 0px 16px 0px rgba(0, 0, 0, 0.08); diff --git a/pages/index/index.vue b/pages/index/index.vue index 0d19007..e4eeb36 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -23,10 +23,10 @@ 系统消息 - {{system.time}} + {{ system.time }} - 您有{{system.num}}条未读信息 + 您有{{ system.num }}条未读信息 暂无新消息 @@ -47,10 +47,10 @@ 产品订单 - {{order.time}} + {{ order.time }} - 您有{{order.num}}条未读信息 + 您有{{ order.num }}条未读信息 暂无新消息 @@ -71,10 +71,10 @@ 医生消息 - {{doctor.time}} + {{ doctor.time }} - 您有{{doctor.num}}条新的消息 + 您有{{ doctor.num }}条新的消息 暂无新消息 @@ -96,10 +96,10 @@ 在线问诊 - {{doctor.time}} + {{ doctor.time }} - 您有{{doctor.num}}条新的消息 + 您有{{ doctor.num }}条新的消息 暂无新消息 @@ -107,15 +107,15 @@ - + 在线问诊 - - - - + + + + @@ -124,20 +124,21 @@ - {{ item.nick_name }} - {{item.last_message_time}} + {{ item.last_message_time }} - +

{{ item.last_message }}

-

您有{{item.un_read_num}}条新的消息

+
- + 暂无新消息 @@ -150,20 +151,21 @@ import { getseesionInfo, getseesionRead } from '../../request/api/api' + export default { data() { return { order: [], system: [], - doctor:[], - imChat:[ + doctor: [], + imChat: [ { - id: 'doctor-1', + id: 'doctor-39', room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', nick_name: '李二狗', avatar: 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg', - un_read_num: 0, - last_message: '[图片]', + un_read_num: 99, + last_message: '多喝水即可', last_message_time: '2021-07-05 09:05:05' }, { @@ -174,7 +176,89 @@ export default { un_read_num: 0, last_message: '[图片]', last_message_time: '2021-07-05 09:05:05' - } + }, + { + id: 'doctor-3', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王五五', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[图片]', + last_message_time: '2021-07-05 09:05:05' + }, + { + id: 'doctor-4', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王六六', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[图片]', + last_message_time: '2021-07-05 09:05:05' + }, + { + id: 'doctor-5', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王六六1', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[音频]', + last_message_time: '2021-07-05 09:05:05' + }, + { + id: 'doctor-6', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王六六2', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[视频]', + last_message_time: '2021-07-05 09:05:05' + }, + { + id: 'doctor-7', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王六六3', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[文件]', + last_message_time: '2021-07-05 09:05:05' + }, + { + id: 'doctor-8', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王六六', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[图片]', + last_message_time: '2021-07-05 09:05:05' + }, + { + id: 'doctor-9', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王六六1', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[音频]', + last_message_time: '2021-07-05 09:05:05' + }, + { + id: 'doctor-10', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王六六2', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[视频]', + last_message_time: '2021-07-05 09:05:05' + }, + { + id: 'doctor-11', + room_id: 'xk_chat_room_68786b4fd071233eb15dfa3e62c1', + nick_name: '王六六3', + avatar: '/static/xx/ysxx.png', + un_read_num: 0, + last_message: '[文件]', + last_message_time: '2021-07-05 09:05:05' + }, + ], type: "" } @@ -271,7 +355,7 @@ export default { // console.log(res, 'info'); this.order = res.data.data.order this.system = res.data.data.system - this.doctor=res.data.data.doctor_news + this.doctor = res.data.data.doctor_news }) } }, @@ -281,7 +365,7 @@ export default { onShow() { this.order = [] this.system = [] - this.doctor=[] + this.doctor = [] this.getInfo() } } diff --git a/request/api/request.js b/request/api/request.js index 496d64c..56dc89e 100644 --- a/request/api/request.js +++ b/request/api/request.js @@ -27,9 +27,14 @@ function request(url, params, method = 0) { if (url.split('/').indexOf('newApi') !== -1) { baseURL = "https://shop.xiaokang88.com/member" } + if (url.split('/').indexOf('xkApi') !== -1) { + // baseURL = "https://api.xiaokang88.com/member" + baseURL = "https://127.0.0.1:18001/member" + } url = url.replace('/oldApi', ''); url = url.replace('/newApi', ''); url = url.replace('/imApi', ''); + url = url.replace('/xkApi', ''); // 加密 if (params != null) { diff --git a/store/chat/chat.js b/store/chat/chat.js index 7ebd08e..e44abfa 100644 --- a/store/chat/chat.js +++ b/store/chat/chat.js @@ -1,5 +1,7 @@ -// chat.js -// 聊天消息管理器 +/** + * 聊天消息管理器 + * @type {{currentRoomId: null, unreadCounts: {}, messageCache: {}, roomMessages: {}, enterRoom(*): void, leaveRoom(): void, getCurrentRoomId(): *, increaseUnreadCount(*): void, resetUnreadCount(*): void, getUnreadCount(*): *, getAllUnreadCount(): *, notifyUnreadChange(): void, cacheMessage(*, *): void, addMessageToRoom(*, *): void, getRoomMessages(*): *, handleIncomingMessage(*): void}} + */ const ChatManager = { // 当前房间ID currentRoomId: null, @@ -7,11 +9,29 @@ const ChatManager = { // 存储未读消息数 { roomId: count } unreadCounts: {}, + // 消息缓存 { roomId: [message1, message2, ...] } + messageCache: {}, + + // 房间消息存储 { roomId: [message1, message2, ...] } + roomMessages: {}, + // 进入聊天室 enterRoom(roomId) { this.currentRoomId = roomId; uni.setStorageSync('currentRoomId', roomId); console.log(`进入房间: ${roomId}`); + + // 重置当前房间的未读消息 + this.resetUnreadCount(roomId); + + // 如果有缓存消息,则触发事件,然后清除缓存 + if (this.messageCache[roomId]) { + const cachedMessages = this.messageCache[roomId]; + cachedMessages.forEach(message => { + this.addMessageToRoom(roomId, message); + }); + delete this.messageCache[roomId]; + } }, // 离开聊天室 @@ -63,17 +83,43 @@ const ChatManager = { }); }, + // 缓存消息(当收到消息但不在该房间时) + cacheMessage(roomId, message) { + if (!this.messageCache[roomId]) { + this.messageCache[roomId] = []; + } + this.messageCache[roomId].push(message); + }, + + // 添加消息到房间 + addMessageToRoom(roomId, message) { + if (!this.roomMessages[roomId]) { + this.roomMessages[roomId] = []; + } + this.roomMessages[roomId].push(message); + }, + + // 获取房间消息 + getRoomMessages(roomId) { + return this.roomMessages[roomId] || []; + }, + // 处理收到的消息 handleIncomingMessage(message) { + const roomId = message.room_id; const currentRoomId = this.getCurrentRoomId(); + // 添加消息到房间 + this.addMessageToRoom(roomId, message); + // 如果当前在消息所属的房间,直接显示 - if (currentRoomId === message.room_id) { + if (currentRoomId === roomId) { // 通知聊天页面显示消息 - uni.$emit('new-message', message); + uni.$emit('new-room-message', message); } else { - // 不在当前房间,增加未读消息数 - this.increaseUnreadCount(message.room_id); + // 不在当前房间,缓存消息并增加未读消息数 + this.cacheMessage(roomId, message); + this.increaseUnreadCount(roomId); } } }; diff --git a/subPackages/chat/chat.vue b/subPackages/chat/chat.vue index dd8bef2..98ec1e2 100644 --- a/subPackages/chat/chat.vue +++ b/subPackages/chat/chat.vue @@ -1,6 +1,6 @@ @@ -206,8 +219,12 @@ import { webSocketManager } from '@/utils/ws/websocket'; import { ChatManager } from '@/store/chat/chat.js'; import {sendToUserApi} from "@/request/api/im"; +import AudioPlayer from './components/AudioPlayer.vue'; export default { + components: { + AudioPlayer + }, data() { return { doctorUserInfo: { @@ -217,11 +234,101 @@ export default { room_id: '' }, showDoctorDetail: false, // 控制医生详情展开 - currentUserId: 'user-252', + currentUserId: '', doctorId: 'doctor-1', doctorAvatar: 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg', userAvatar: 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk_upload_20250108/29bdb9560340373bb3096394a845afa5.jpg', - messages: [ + messages: [], + newMessage: '', + voiceInputActive: false, + showMoreActions: false, + recording: false, + recordingTime: 0, + recordingTimer: null, + showRecordingModal: false, + currentPlayingAudio: null, + scrollTop: 0, + page: 1, + pageSize: 20, + hasMore: true, + loading: false, // 新增加载状态 + }; + }, + onLoad: function (option) { + this.doctorUserInfo = option; + if (option.avatar) { + this.doctorAvatar = option.avatar; + } + + this.currentUserId = 'user-' + uni.getStorageSync('user_id') || 'user-2512'; + + this.doctorId = option.user_id; + + // 进入聊天室时缓存房间ID + ChatManager.enterRoom(option.room_id); + + // 重置当前房间的未读消息 + ChatManager.resetUnreadCount(option.room_id); + + // 从ChatManager获取房间消息 + this.messages = ChatManager.getRoomMessages(option.room_id); + + // 如果没有消息,添加示例消息 + if (this.messages.length === 0) { + this.addExampleMessages(); + } + + uni.setNavigationBarTitle({ + title: `与${this.doctorUserInfo.nick_name}医生的对话`, + success: () => { + console.log('修改标题成功'); + }, + fail: () => { + console.log('修改标题失败'); + }, + complete: () => { + console.log('修改标题结束'); + } + }); + + // 设置滚动到底部 + this.$nextTick(() => { + this.scrollToBottom(); + }); + }, + onUnload() { + // 离开聊天室时清除房间缓存 + ChatManager.leaveRoom(); + // 停止音频播放 + if (this.$refs.audioPlayer) { + this.$refs.audioPlayer.stop(); + } + }, + onShow() { + // 监听当前房间的新消息事件 + uni.$on('new-room-message', this.handleNewRoomMessage); + }, + onHide() { + // 移除消息监听 + uni.$off('new-room-message', this.handleNewRoomMessage); + }, + mounted() { + // 初始化录音管理器 + this.recorderManager = uni.getRecorderManager(); + this.initRecorder(); + + // 监听WebSocket消息 + webSocketManager.addMessageHandler(this.handleSocketMessage); + }, + beforeDestroy() { + // 移除WebSocket监听 + webSocketManager.removeMessageHandler(this.handleSocketMessage); + }, + + methods: { + // 添加示例消息 + addExampleMessages() { + const exampleMessages = [ { id: '1', sender: 'doctor-1', @@ -266,7 +373,7 @@ export default { id: '6', sender: 'user-252', type: 'audio', - content: 'https://lv-sycdn.kuwo.cn/35581c6b5aa0e579312193399190e51a/687a023d/resource/30106/trackmedia/M800001zMQr71F1Qo8.mp3', + content: 'https://er-sycdn.kuwo.cn/f7c3be4ff67cc7b135e38e8365479e06/687d941e/resource/30106/trackmedia/M800004emQMs09Z1lz.mp3', duration: 15, time: '09:36', timestamp: Date.now() - 3240000 @@ -275,107 +382,46 @@ export default { id: '7', sender: 'doctor-1', type: 'audio', - content: 'https://lv-sycdn.kuwo.cn/35581c6b5aa0e579312193399190e51a/687a023d/resource/30106/trackmedia/M800001zMQr71F1Qo8.mp3', + content: 'https://er-sycdn.kuwo.cn/f7c3be4ff67cc7b135e38e8365479e06/687d941e/resource/30106/trackmedia/M800004emQMs09Z1lz.mp3', duration: 8, time: '09:37', timestamp: Date.now() - 3180000 } - ], - newMessage: '', - voiceInputActive: false, - showMoreActions: false, - recording: false, - recordingTime: 0, - recordingTimer: null, - showRecordingModal: false, - audioContexts: {}, - currentPlayingAudio: null, - scrollTop: 0, - scrollToBottomFlag: true, - page: 1, - pageSize: 20, - hasMore: true, - }; - }, - onLoad: function (option) { - this.doctorUserInfo = option; - if (option.avatar) { - this.doctorAvatar = option.avatar; - } + ]; - // 进入聊天室时缓存房间ID - ChatManager.enterRoom(option.room_id); - - // 重置当前房间的未读消息 - ChatManager.resetUnreadCount(option.room_id); - }, - onUnload() { - // 离开聊天室时清除房间缓存 - ChatManager.leaveRoom(); - }, - onShow() { - // 监听新消息事件 - uni.$on('new-message', this.handleNewMessage); - }, - onHide() { - // 移除消息监听 - uni.$off('new-message', this.handleNewMessage); - }, - mounted() { - // 初始化录音管理器 - this.recorderManager = uni.getRecorderManager(); - this.initRecorder(); - - // 设置滚动到底部 - this.$nextTick(() => { - this.scrollToBottom(); - }); - - // 监听WebSocket消息 - webSocketManager.addMessageHandler(this.handleSocketMessage); - }, - beforeDestroy() { - // 移除WebSocket监听 - webSocketManager.removeMessageHandler(this.handleSocketMessage); - }, - - methods: { - // 处理WebSocket消息 - handleSocketMessage(data) { - // 只处理当前房间的消息 - if (data.room_id === this.doctorUserInfo.room_id) { - // 处理不同类型的消息 - switch (data.message_type) { - case 0: // 文本 - this.handleTextMessage(data); - break; - case 1: // 图片 - this.handleImageMessage(data); - break; - case 2: // 音频 - this.handleAudioMessage(data); - break; - case 3: // 视频 - this.handleVideoMessage(data); - break; - default: - console.warn('未知消息类型:', data); - } - } + // 添加到ChatManager和本地消息列表 + exampleMessages.forEach(msg => { + ChatManager.addMessageToRoom(this.doctorUserInfo.room_id, msg); + }); + this.messages = [...exampleMessages]; }, - // 处理新消息事件 - handleNewMessage(message) { - if (message.room_id === this.doctorUserInfo.room_id) { - this.addMessage({ - id: message.id, - sender: message.sender_user_id, - type: this.getMessageType(message.message_type), - content: message.message_content, - time: this.formatTime(message.timestamp), - timestamp: message.timestamp - }); + // 处理WebSocket消息 + handleSocketMessage(data) { + // 将消息交给ChatManager统一处理 + ChatManager.handleIncomingMessage(data); + }, + + // 处理当前房间的新消息事件 + handleNewRoomMessage(message) { + // 处理不同类型的消息 + const msgType = this.getMessageType(message.message_type); + const newMsg = { + id: message.id, + sender: message.sender_user_id, + type: msgType, + content: message.content, + time: this.formatTime(message.send_time), + timestamp: message.send_time + }; + + // 对于音频和视频消息,可能有额外字段 + if (msgType === 'audio' || msgType === 'video') { + newMsg.duration = message.duration || 0; } + + // 添加到消息列表 + this.addMessage(newMsg); }, // 根据消息类型ID获取类型名称 @@ -391,56 +437,6 @@ export default { return types[typeId] || 'text'; }, - // 处理文本消息 - handleTextMessage(data) { - this.addMessage({ - id: data.id, - sender: data.sender_user_id, - type: 'text', - content: data.message_content, - time: this.formatTime(data.timestamp), - timestamp: data.timestamp - }); - }, - - // 处理图片消息 - handleImageMessage(data) { - this.addMessage({ - id: data.id, - sender: data.sender_user_id, - type: 'image', - content: data.file_url, - time: this.formatTime(data.timestamp), - timestamp: data.timestamp - }); - }, - - // 处理音频消息 - handleAudioMessage(data) { - this.addMessage({ - id: data.id, - sender: data.sender_user_id, - type: 'audio', - content: data.file_url, - duration: data.duration, - time: this.formatTime(data.timestamp), - timestamp: data.timestamp - }); - }, - - // 处理视频消息 - handleVideoMessage(data) { - this.addMessage({ - id: data.id, - sender: data.sender_user_id, - type: 'video', - content: data.file_url, - duration: data.duration, - time: this.formatTime(data.timestamp), - timestamp: data.timestamp - }); - }, - // 添加消息到列表 addMessage(message) { // 避免重复添加 @@ -452,7 +448,30 @@ export default { // 格式化时间 formatTime(timestamp) { - const date = new Date(timestamp); + let date; + + // 处理不同输入类型 + if (typeof timestamp === 'number') { + // 数字直接作为时间戳处理 + date = new Date(timestamp); + } else if (timestamp instanceof Date) { + // Date对象直接使用 + date = timestamp; + } else if (typeof timestamp === 'string') { + // 字符串类型:尝试转换为时间戳 + const parsed = Date.parse(timestamp); + if (isNaN(parsed)) { + // 转换失败则使用当前时间 + date = new Date(); + } else { + date = new Date(parsed); + } + } else { + // 其他类型使用当前时间 + date = new Date(); + } + + // 格式化时间为 HH:MM return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`; }, @@ -474,7 +493,7 @@ export default { this.sendMessage({ type: 'audio', - content: 'https://lv-sycdn.kuwo.cn/35581c6b5aa0e579312193399190e51a/687a023d/resource/30106/trackmedia/M800001zMQr71F1Qo8.mp3', + content: 'https://er-sycdn.kuwo.cn/f7c3be4ff67cc7b135e38e8365479e06/687d941e/resource/30106/trackmedia/M800004emQMs09Z1lz.mp3', duration: Math.floor(res.duration / 1000), }); @@ -507,10 +526,9 @@ export default { time: timeStr, timestamp: now.getTime() }; - // - // // 添加到本地消息列表 - // this.messages.push(fullMessage); - // this.scrollToBottom(); + + // 添加到ChatManager + ChatManager.addMessageToRoom(this.doctorUserInfo.room_id, fullMessage); // 构建请求数据 const messageTypeMap = { @@ -531,7 +549,7 @@ export default { isFromHttp: true, duration: message.duration || 0 }; - console.log('发送数据:', requestData) + sendToUserApi(requestData).then(res => { console.log('发送成功:', res); // 添加到本地消息列表 @@ -563,7 +581,8 @@ export default { success: () => { this.startRecording(); }, - fail: () => { + fail: (e) => { + console.log('失败', e) uni.showToast({ title: '需要录音权限', icon: 'none' @@ -598,62 +617,31 @@ export default { this.recorderManager.stop(); }, - // 播放音频 - 修复后的逻辑 + // 播放音频 playAudio(msg) { - if (!msg.content) return; - - // 如果当前正在播放的是同一个音频 - if (this.currentPlayingAudio === msg.id) { - const audioContext = this.audioContexts[msg.id]; - if (audioContext.paused) { - audioContext.play(); - } else { - audioContext.pause(); - } - return; + if (this.$refs.audioPlayer) { + this.$refs.audioPlayer.play({ + id: msg.id, + src: msg.content + }); } - - // 停止当前播放的音频 - if (this.currentPlayingAudio) { - const prevAudio = this.audioContexts[this.currentPlayingAudio]; - prevAudio.stop(); - prevAudio.destroy(); - delete this.audioContexts[this.currentPlayingAudio]; - this.currentPlayingAudio = null; - } - - // 创建新的音频上下文 - const audioContext = uni.createInnerAudioContext(); - audioContext.src = msg.content; - audioContext.autoplay = true; - - audioContext.onPlay(() => { - this.currentPlayingAudio = msg.id; - }); - - audioContext.onPause(() => { - // 暂停时不改变currentPlayingAudio,以便继续播放 - }); - - audioContext.onEnded(() => { - this.currentPlayingAudio = null; - }); - - audioContext.onError((err) => { - console.error('音频播放失败:', err); - uni.showToast({ title: '播放失败', icon: 'none' }); - this.currentPlayingAudio = null; - }); - - this.audioContexts[msg.id] = audioContext; - this.currentPlayingAudio = msg.id; }, // 检查是否正在播放 isPlaying(msg) { - return this.currentPlayingAudio === msg.id && - this.audioContexts[msg.id] && - !this.audioContexts[msg.id].paused; + return this.$refs.audioPlayer && this.$refs.audioPlayer.isPlaying(msg.id); + }, + + // 音频播放事件 + handleAudioPlay(audioId) { + // 更新UI + this.currentPlayingAudio = audioId; + }, + handleAudioPause() { + this.currentPlayingAudio = null; + }, + handleAudioEnd() { + this.currentPlayingAudio = null; }, // 打开媒体选择器 @@ -691,7 +679,6 @@ export default { // 打开相机拍照 openCamera() { - this.showMoreActions = false; uni.chooseImage({ count: 1, sourceType: ['camera'], @@ -706,7 +693,6 @@ export default { // 发送文件 sendFile() { - this.showMoreActions = false; uni.chooseMessageFile({ count: 1, type: 'all', @@ -724,7 +710,6 @@ export default { // 发送处方 sendPrescription() { - this.showMoreActions = false; // 模拟处方数据 const prescription = { id: 'RX20230718001', @@ -760,7 +745,6 @@ export default { // 切换语音输入 toggleVoiceInput() { this.voiceInputActive = !this.voiceInputActive; - this.showMoreActions = false; }, // 滚动到底部 @@ -771,33 +755,40 @@ export default { }, // 加载历史消息 - loadHistory() { - if (!this.hasMore) return; + async loadHistory() { + if (!this.hasMore || this.loading) return; - // 模拟加载历史消息 - setTimeout(() => { - const newMessages = [ - { - id: 'h1', - sender: 'doctor-1', - type: 'text', - content: '这是更早的消息', - time: '09:20', - timestamp: Date.now() - 7200000 - }, - { - id: 'h2', - sender: 'user-252', - type: 'text', - content: '是的,这是历史消息', - time: '09:21', - timestamp: Date.now() - 7140000 - } - ]; + this.loading = true; + try { + // 模拟加载历史消息 + const newMessages = await new Promise(resolve => { + setTimeout(() => { + resolve([ + { + id: 'h1', + sender: 'doctor-1', + type: 'text', + content: '这是更早的消息', + time: '09:20', + timestamp: Date.now() - 7200000 + }, + { + id: 'h2', + sender: 'user-252', + type: 'text', + content: '是的,这是历史消息', + time: '09:21', + timestamp: Date.now() - 7140000 + } + ]); + }, 500); + }); this.messages = [...newMessages, ...this.messages]; this.hasMore = false; // 假设没有更多历史消息 - }, 500); + } finally { + this.loading = false; + } } } }; @@ -903,7 +894,7 @@ $light-bg: #f5f9ff; .chat-messages { flex: 1; padding: 16px; - padding-bottom: 80px; + padding-bottom: 120px; overflow: hidden; background-color: #f5f9ff; } @@ -1050,13 +1041,19 @@ $light-bg: #f5f9ff; background-color: #a0c8ff; margin: 0 2px; border-radius: 2px; - transition: all 0.3s ease; + height: 10px; + transition: height 0.3s ease; - &:nth-child(1) { height: 14px; animation: wave 1s infinite 0.1s; } - &:nth-child(2) { height: 18px; animation: wave 1s infinite 0.2s; } - &:nth-child(3) { height: 22px; animation: wave 1s infinite 0.3s; } - &:nth-child(4) { height: 18px; animation: wave 1s infinite 0.4s; } - &:nth-child(5) { height: 14px; animation: wave 1s infinite 0.5s; } + &.wave-bar-active { + animation: wave 1s infinite; + height: 24px; + + &:nth-child(1) { animation-delay: 0.1s; } + &:nth-child(2) { animation-delay: 0.2s; } + &:nth-child(3) { animation-delay: 0.3s; } + &:nth-child(4) { animation-delay: 0.4s; } + &:nth-child(5) { animation-delay: 0.5s; } + } } } @@ -1068,7 +1065,7 @@ $light-bg: #f5f9ff; } @keyframes wave { - 0%, 100% { height: 14px; } + 0%, 100% { height: 10px; } 50% { height: 24px; } } @@ -1082,26 +1079,51 @@ $light-bg: #f5f9ff; .chat-input { background-color: #fff; border-top: 1px solid #eaeef5; - padding: 16px; + padding: 10px 16px; position: fixed; bottom: 0; left: 0; right: 0; - z-index: 100; + z-index: 1000; box-shadow: 0 -4px 12px rgba(41, 141, 255, 0.1); } -.input-area { +/* 工具按钮行 */ +.toolbar-row { + display: flex; + justify-content: space-around; + padding: 8px 0; + margin-bottom: 8px; + border-bottom: 1px solid #f0f7ff; +} + +.tool-btn { + display: flex; + flex-direction: column; + align-items: center; + padding: 4px 8px; + border-radius: 8px; + transition: all 0.3s ease; + + &:active { + background-color: #f0f7ff; + } + + text { + font-size: 12px; + color: #555; + margin-top: 4px; + font-weight: 500; + } +} + +/* 输入框行 */ +.input-row { display: flex; align-items: center; gap: 10px; } -.action-buttons { - display: flex; - gap: 8px; -} - .action-btn { width: 46px; height: 46px; @@ -1193,38 +1215,6 @@ $light-bg: #f5f9ff; } } -.more-actions { - display: flex; - justify-content: space-around; - padding: 20px 0; - margin-bottom: 12px; - background-color: #fff; - border-radius: 16px; - flex-wrap: wrap; -} - -.action-item { - display: flex; - flex-direction: column; - align-items: center; - padding: 8px 16px; - border-radius: 12px; - transition: all 0.3s ease; - width: 20%; - box-sizing: border-box; - - &:active { - background-color: #f0f7ff; - } - - text { - font-size: 12px; - color: #555; - margin-top: 6px; - font-weight: 500; - } -} - .recording-modal { position: fixed; top: 0; @@ -1243,7 +1233,7 @@ $light-bg: #f5f9ff; border-radius: 20px; text-align: center; width: 280px; - box-shadow: 0 10px 30px rgba(41, 141, 255, 0.4); + //box-shadow: 0 10px 30px rgba(41, 141, 255, 0.4); } .recording-icon { @@ -1290,4 +1280,11 @@ $light-bg: #f5f9ff; 50% { transform: scale(1.1); opacity: 1; } 100% { transform: scale(0.9); opacity: 0.7; } } + +/* 加载指示器 */ +.loading-indicator { + display: flex; + justify-content: center; + padding: 20px; +} \ No newline at end of file diff --git a/subPackages/chat/components/AudioPlayer.vue b/subPackages/chat/components/AudioPlayer.vue new file mode 100644 index 0000000..d639847 --- /dev/null +++ b/subPackages/chat/components/AudioPlayer.vue @@ -0,0 +1,84 @@ + + \ No newline at end of file