diff --git a/app.json b/app.json index b5de33e..ee7d9be 100644 --- a/app.json +++ b/app.json @@ -18,7 +18,8 @@ "pages/expertChat/expertChat", "pages/medicine/medicine", "pages/medicineDetails/medicineDetails", - "pages/attestation/attestation" + "pages/attestation/attestation", + "pages/noticeList/noticeList" ] }, { diff --git a/pages/home/home.js b/pages/home/home.js index 002b7c1..0dad56b 100644 --- a/pages/home/home.js +++ b/pages/home/home.js @@ -188,7 +188,7 @@ Page({ // 查看所有通知 viewAllNotices() { wx.navigateTo({ - url: '/pagesB/pages/noticeList/noticeList', + url: '/pagesA/pages/noticeList/noticeList', }) }, diff --git a/pages/home/home.wxml b/pages/home/home.wxml index 1d22f76..90eccf6 100644 --- a/pages/home/home.wxml +++ b/pages/home/home.wxml @@ -54,7 +54,7 @@ 问兽医 智能匹配医生 - 平均5分钟恢复 + 平均5分钟回复 @@ -174,7 +174,7 @@ - + 经验分享 分享自己养殖经验 diff --git a/pages/personal/personal.wxml b/pages/personal/personal.wxml index a72916b..3f0c3c5 100644 --- a/pages/personal/personal.wxml +++ b/pages/personal/personal.wxml @@ -94,7 +94,20 @@ - + + {{feedbackContent.length}} /200 @@ -117,7 +130,16 @@ 修改昵称 - + 最多10个字符 diff --git a/pages/personal/personal.wxss b/pages/personal/personal.wxss index 45087a5..07fadee 100644 --- a/pages/personal/personal.wxss +++ b/pages/personal/personal.wxss @@ -175,8 +175,6 @@ color: #065f46; } - - /* 卡片样式 */ .section-card { background: white; @@ -338,11 +336,13 @@ opacity: 0; visibility: hidden; transition: all 0.3s ease; + pointer-events: none; /* 防止未显示时误触 */ } .feedback-modal.show { opacity: 1; visibility: visible; + pointer-events: auto; } .modal-mask { @@ -406,7 +406,7 @@ filter: brightness(0%); } -/* 反馈输入框 */ +/* 反馈输入框 - iOS修复 */ .modal-body { padding: 40rpx; } @@ -423,6 +423,7 @@ line-height: 1.5; color: #1e293b; transition: all 0.3s ease; + -webkit-user-select: auto; /* iOS修复 */ } .feedback-input:focus { @@ -431,6 +432,10 @@ box-shadow: 0 0 0 4rpx rgba(102, 126, 234, 0.1); } +.feedback-input[disabled] { + opacity: 0.8; /* 禁用状态样式 */ +} + .placeholder { color: #94a3b8; } @@ -499,11 +504,13 @@ opacity: 0; visibility: hidden; transition: all 0.3s ease; + pointer-events: none; } .nickname-modal.show { opacity: 1; visibility: visible; + pointer-events: auto; } .nickname-modal .modal-content { @@ -610,11 +617,13 @@ opacity: 0; visibility: hidden; transition: all 0.3s ease; + pointer-events: none; } .logout-modal.show { opacity: 1; visibility: visible; + pointer-events: auto; } .logout-modal .modal-content { @@ -636,7 +645,6 @@ text-align: center; } - .logout-title { font-weight: 700; color: #1e293b; diff --git a/pagesA/pages/askingSyAdd/askingSyAdd.wxml b/pagesA/pages/askingSyAdd/askingSyAdd.wxml index 98db029..1bbf73e 100644 --- a/pagesA/pages/askingSyAdd/askingSyAdd.wxml +++ b/pagesA/pages/askingSyAdd/askingSyAdd.wxml @@ -31,7 +31,7 @@ 年龄 - + diff --git a/pagesA/pages/expert/expert.wxss b/pagesA/pages/expert/expert.wxss index d5cec68..dc97acd 100644 --- a/pagesA/pages/expert/expert.wxss +++ b/pagesA/pages/expert/expert.wxss @@ -606,15 +606,15 @@ } .phone-item .contact-icon-container { - background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%); + background: linear-gradient(135deg, #b8d8ba 0%, #c8e6c9 100%); } .email-item .contact-icon-container { - background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%); + background: linear-gradient(135deg, #a2baca 0%, #bbdefb 100%); } .institution-item .contact-icon-container { - background: linear-gradient(135deg, #f3e5f5 0%, #e1bee7 100%); + background: linear-gradient(135deg, #c9abce 0%, #e1bee7 100%); } .contact-item-icon { diff --git a/pagesA/pages/expertChat/expertChat.js b/pagesA/pages/expertChat/expertChat.js index ab284fe..e299e2a 100644 --- a/pagesA/pages/expertChat/expertChat.js +++ b/pagesA/pages/expertChat/expertChat.js @@ -1,21 +1,20 @@ -// import http from '../../../utils/api' Page({ data: { // 专家信息 expertInfo: { - id: 0, - name: '', - title: '', - expertise: '', + id: 1, + name: '张明专家', + title: '资深畜牧兽医', + expertise: '牛羊疾病防治', avatar: '/images/avatars/expert1.png', - online: false, - phone: '' + online: true, + phone: '13800138000' }, // 用户信息 userInfo: { - id: 0, - name: '用户', + id: 1001, + name: '养殖户', avatar: '/images/avatars/user.png' }, @@ -24,24 +23,13 @@ Page({ scrollTop: 0, scrollAnimate: false, - // 输入相关 + // 输入相关 - 优化 inputValue: '', inputFocus: false, - inputMode: 'keyboard', - inputPlaceholder: '请输入消息...', // 多媒体 showMediaSheet: false, - // 录音相关 - isRecording: false, - isCanceling: false, - recordingTime: 0, - recordingTip: '松开 发送', - voiceTip: '按住 说话', - recordingTimer: null, - recordManager: null, - // 页面状态 showDateDivider: true, todayDate: '', @@ -52,669 +40,42 @@ Page({ isScrolling: false, lastScrollTop: 0, - // 录音相关 - recordStartY: 0, - // 当前专家ID - currentExpertId: 0, + currentExpertId: 1, // 分页相关 page: 1, pageSize: 20, hasMore: true, - // 时间显示间隔(分钟) - 微信默认为5分钟 + // 时间显示间隔 timeInterval: 5, + lastShowTimeStamp: 0, - // 用于存储最后一条显示时间的消息的时间戳 - lastShowTimeStamp: 0 + // 键盘高度 + keyboardHeight: 0 }, onLoad: function(options) { - console.log('页面加载,参数:', options); - - // 初始化录音管理器 - this.initRecordManager(); - - // 获取今天日期 this.setTodayDate(); - - // 加载用户信息 this.loadUserInfo(); - // 加载专家信息 if (options.expertId) { this.setData({ currentExpertId: options.expertId }); this.loadExpertInfo(options.expertId); } else { - // 如果没有传expertId,使用默认值 - this.setData({ - currentExpertId: 1, - expertInfo: { - id: 1, - name: '张明专家', - title: '资深畜牧兽医', - expertise: '牛羊疾病防治', - avatar: '/images/avatars/expert1.png', - online: true, - phone: '13800138000' - } - }, () => { - // 加载聊天记录 - this.loadChatHistory(); - }); + this.loadChatHistory(); } - // 设置键盘监听 wx.onKeyboardHeightChange(this.onKeyboardHeightChange.bind(this)); }, onUnload: function() { - console.log('页面卸载'); - - // 清理定时器 - if (this.data.recordingTimer) { - clearInterval(this.data.recordingTimer); - } - - // 移除监听器 wx.offKeyboardHeightChange(); }, - onShow: function() { - console.log('页面显示'); - }, - - onReady: function() { - console.log('页面初次渲染完成'); - }, - - // 初始化录音管理器 - initRecordManager: function() { - this.recordManager = wx.getRecorderManager(); - - this.recordManager.onStart(() => { - console.log('录音开始'); - this.setData({ - isRecording: true, - recordingTime: 0, - recordingTip: '松开 发送' - }); - - // 开始计时 - const timer = setInterval(() => { - const time = this.data.recordingTime + 1; - this.setData({ recordingTime: time }); - }, 1000); - - this.setData({ recordingTimer: timer }); - }); - - this.recordManager.onStop((res) => { - console.log('录音停止', res); - if (this.data.recordingTimer) { - clearInterval(this.data.recordingTimer); - } - - const { tempFilePath, duration } = res; - if (tempFilePath && !this.data.isCanceling) { - this.sendAudioMessage(tempFilePath, Math.floor(duration / 1000)); - } - - this.setData({ - isRecording: false, - isCanceling: false, - recordingTime: 0 - }); - }); - - this.recordManager.onError((err) => { - console.error('录音失败:', err); - wx.showToast({ - title: '录音失败', - icon: 'none' - }); - this.setData({ - isRecording: false, - isCanceling: false - }); - }); - }, - - // 设置今天日期 - setTodayDate: function() { - const now = new Date(); - const month = now.getMonth() + 1; - const date = now.getDate(); - const week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()]; - this.setData({ - todayDate: `${month}月${date}日 星期${week}` - }); - }, - - // 加载用户信息 - loadUserInfo: function() { - try { - // 从本地存储获取用户信息,如果没有则使用默认值 - const userInfo = wx.getStorageSync('userInfo'); - if (userInfo) { - this.setData({ userInfo }); - } else { - // 默认用户信息 - const defaultUserInfo = { - id: 1001, - name: '养殖户', - avatar: '/images/avatars/user.png' - }; - this.setData({ userInfo: defaultUserInfo }); - wx.setStorageSync('userInfo', defaultUserInfo); - } - } catch (e) { - console.error('加载用户信息失败:', e); - // 使用默认用户信息 - this.setData({ - userInfo: { - id: 1001, - name: '养殖户', - avatar: '/images/avatars/user.png' - } - }); - } - }, - - // 加载专家信息 - 使用您的接口调用方式 - loadExpertInfo: function(expertId) { - console.log('加载专家信息:', expertId); - wx.showLoading({ title: '加载中...' }); - - // 使用您的接口调用方式 - // http.getExpertInfo({ - // data: { expertId: expertId }, - // success: (res) => { - // console.log('专家信息:', res); - - // if (res.code === 0) { - // this.setData({ - // expertInfo: res.data, - // loading: false - // }); - - // // 加载聊天记录 - // this.loadChatHistory(); - // } else { - // // 如果接口返回失败,使用默认数据 - // this.loadDefaultExpertInfo(expertId); - // } - - // wx.hideLoading(); - // }, - // fail: (err) => { - // console.error('加载专家信息失败:', err); - // wx.hideLoading(); - // wx.showToast({ - // title: '加载失败', - // icon: 'none' - // }); - - // // 如果接口调用失败,使用默认数据 - // this.loadDefaultExpertInfo(expertId); - // } - // }); - - // 模拟数据 - setTimeout(() => { - const experts = [ - { - id: 1, - name: '张明专家', - title: '资深畜牧兽医', - expertise: '牛羊疾病防治', - avatar: '/images/avatars/expert1.png', - online: true, - phone: '13800138000' - }, - { - id: 2, - name: '李华专家', - title: '高级畜牧师', - expertise: '饲料营养', - avatar: '/images/avatars/expert2.png', - online: false, - phone: '13800138001' - }, - { - id: 3, - name: '王强专家', - title: '兽医专家', - expertise: '疾病防治', - avatar: '/images/avatars/expert3.png', - online: true, - phone: '13800138002' - } - ]; - - const expertInfo = experts.find(e => e.id == expertId) || experts[0]; - - this.setData({ - expertInfo, - loading: false - }); - - wx.hideLoading(); - - // 加载聊天记录 - this.loadChatHistory(); - }, 500); - }, - - // 加载默认专家信息(当接口失败时使用) - loadDefaultExpertInfo: function(expertId) { - const experts = [ - { - id: 1, - name: '张明专家', - title: '资深畜牧兽医', - expertise: '牛羊疾病防治', - avatar: '/images/avatars/expert1.png', - online: true, - phone: '13800138000' - }, - { - id: 2, - name: '李华专家', - title: '高级畜牧师', - expertise: '饲料营养', - avatar: '/images/avatars/expert2.png', - online: false, - phone: '13800138001' - }, - { - id: 3, - name: '王强专家', - title: '兽医专家', - expertise: '疾病防治', - avatar: '/images/avatars/expert3.png', - online: true, - phone: '13800138002' - } - ]; - - const expertInfo = experts.find(e => e.id == expertId) || experts[0]; - - this.setData({ - expertInfo, - loading: false - }); - - // 加载聊天记录 - this.loadChatHistory(); - }, - - // 加载聊天记录 - 使用您的接口调用方式 - loadChatHistory: function() { - const { currentExpertId, userInfo, page, pageSize } = this.data; - - this.setData({ loading: true }); - - console.log('加载聊天记录:', { - expertId: currentExpertId, - userId: userInfo.id, - page: page, - pageSize: pageSize - }); - - // 使用您的接口调用方式 - // http.getChatHistory({ - // data: { - // expertId: currentExpertId, - // userId: userInfo.id, - // page: page, - // pageSize: pageSize - // }, - // success: (res) => { - // console.log('聊天记录:', res); - - // if (res.code === 0) { - // const messages = res.data.list || []; - - // if (messages.length > 0) { - // // 处理消息时间显示 - 使用完全修复的时间处理逻辑 - // const processedMessages = this.processMessageTimes(messages); - - // // 调试:查看处理后的消息 - // console.log('处理后的消息数据:', processedMessages.map(msg => ({ - // id: msg.id, - // showTime: msg.showTime, - // time: this.formatTime(msg.timestamp), - // timestamp: msg.timestamp - // }))); - - // this.setData({ - // messageList: processedMessages, - // loading: false, - // hasMore: messages.length >= pageSize - // }, () => { - // // 滚动到底部 - // this.scrollToBottom(true); - // }); - // } else { - // // 如果没有历史记录,添加一条欢迎消息 - // this.addWelcomeMessage(); - // } - // } else { - // // 如果接口返回失败,使用测试数据 - // this.loadMockChatHistory(); - // } - // }, - // fail: (err) => { - // console.error('加载聊天记录失败:', err); - // this.setData({ loading: false }); - - // // 如果接口调用失败,使用测试数据 - // this.loadMockChatHistory(); - // } - // }); - - // 模拟数据 - 修复时间戳问题 - setTimeout(() => { - const now = Date.now(); - let mockMessages = []; - - if (page === 1) { - // 第一页数据 - 测试不同时间间隔的消息 - mockMessages = [ - { - id: 'msg-1', - sender: 'expert', - type: 'text', - content: '您好,我是张明专家,有什么可以帮您?', - timestamp: now - 10 * 60 * 1000, // 10分钟前 - 应该显示时间 - status: 'success' - }, - { - id: 'msg-2', - sender: 'user', - type: 'text', - content: '您好,我养的牛最近食欲不振,请问是什么原因?', - timestamp: now - 9 * 60 * 1000, // 9分钟前 - 不显示时间(与上条间隔1分钟) - status: 'success' - }, - { - id: 'msg-3', - sender: 'expert', - type: 'text', - content: '可能是饲料问题或环境变化引起的,请描述一下具体情况。', - timestamp: now - 7 * 60 * 1000, // 7分钟前 - 显示时间(与上条间隔2分钟,但与第一条间隔3分钟) - status: 'success' - }, - { - id: 'msg-4', - sender: 'user', - type: 'text', - content: '具体症状是拉稀,体温偏高,精神状态不好。', - timestamp: now - 2 * 60 * 1000, // 2分钟前 - 显示时间(与上条间隔5分钟) - status: 'success' - }, - { - id: 'msg-5', - sender: 'expert', - type: 'text', - content: '明白了,建议您调整饲料配方,添加一些益生菌。', - timestamp: now - 1 * 60 * 1000, // 1分钟前 - 不显示时间(与上条间隔1分钟) - status: 'success' - } - ]; - } else { - // 更多数据 - mockMessages = [ - { - id: 'msg-6', - sender: 'user', - type: 'text', - content: '之前喂的是玉米秸秆,需要换饲料吗?', - timestamp: now - 30 * 60 * 1000, // 30分钟前 - status: 'success' - }, - { - id: 'msg-7', - sender: 'expert', - type: 'text', - content: '可以尝试添加一些豆粕和麦麸,改善营养结构。', - timestamp: now - 25 * 60 * 1000, // 25分钟前 - status: 'success' - } - ]; - } - - if (mockMessages.length > 0) { - // 处理消息时间显示 - 使用完全修复的时间处理逻辑 - const processedMessages = this.processMessageTimes(mockMessages); - - // 调试:查看处理后的消息 - console.log('处理后的消息数据:', processedMessages.map(msg => ({ - id: msg.id, - showTime: msg.showTime, - time: this.formatTime(msg.timestamp), - timestamp: msg.timestamp, - sender: msg.sender - }))); - - let newMessageList = []; - if (page === 1) { - newMessageList = processedMessages; - } else { - newMessageList = [...processedMessages, ...this.data.messageList]; - } - - this.setData({ - messageList: newMessageList, - loading: false, - loadingMore: false, - hasMore: mockMessages.length >= pageSize - }, () => { - if (page === 1) { - // 滚动到底部 - this.scrollToBottom(true); - } - }); - } else { - // 如果没有历史记录,添加一条欢迎消息 - this.addWelcomeMessage(); - } - }, 800); - }, - - // 加载模拟聊天记录(当接口失败时使用) - loadMockChatHistory: function() { - const now = Date.now(); - // 测试数据 - 确保有时间戳 - const mockMessages = [ - { - id: 'msg-1', - sender: 'expert', - type: 'text', - content: '您好,我是张明专家,有什么可以帮您?', - timestamp: now - 10 * 60 * 1000, // 10分钟前 - status: 'success' - }, - { - id: 'msg-2', - sender: 'user', - type: 'text', - content: '您好,我养的牛最近食欲不振,请问是什么原因?', - timestamp: now - 8 * 60 * 1000, // 8分钟前 - status: 'success' - }, - { - id: 'msg-3', - sender: 'expert', - type: 'text', - content: '可能是饲料问题或环境变化引起的,请描述一下具体情况。', - timestamp: now - 6 * 60 * 1000, // 6分钟前 - status: 'success' - }, - { - id: 'msg-4', - sender: 'user', - type: 'text', - content: '具体症状是...', - timestamp: now - 4 * 60 * 1000, // 4分钟前 - status: 'success' - }, - { - id: 'msg-5', - sender: 'expert', - type: 'text', - content: '明白了,建议您调整饲料配方。', - timestamp: now - 2 * 60 * 1000, // 2分钟前 - status: 'success' - } - ]; - - // 处理消息时间显示 - const processedMessages = this.processMessageTimes(mockMessages); - this.setData({ - messageList: processedMessages, - loading: false, - hasMore: false - }, () => { - // 滚动到底部 - this.scrollToBottom(true); - }); - }, - - // 添加欢迎消息 - addWelcomeMessage: function() { - const welcomeMessage = { - id: 'welcome-' + Date.now(), - sender: 'expert', - type: 'text', - content: `您好,我是${this.data.expertInfo.name},有什么可以帮您?`, - timestamp: Date.now(), - status: 'success' - }; - - const processedMessage = this.processSingleMessageTime(welcomeMessage, []); - - this.setData({ - messageList: [processedMessage], - loading: false - }, () => { - // 滚动到底部 - this.scrollToBottom(true); - }); - }, - - // 完全修复:处理消息时间显示逻辑(类似微信) - processMessageTimes: function(messages) { - if (!messages || messages.length === 0) return []; - - // 按时间排序(从早到晚) - const sortedMessages = [...messages].sort((a, b) => a.timestamp - b.timestamp); - - const processedMessages = []; - let lastShowTime = null; // 最后一条显示时间消息的时间戳 - - for (let i = 0; i < sortedMessages.length; i++) { - const msg = { ...sortedMessages[i] }; - - // 确保时间戳是有效数字 - if (!msg.timestamp || isNaN(msg.timestamp) || msg.timestamp <= 0) { - msg.timestamp = Date.now() - (sortedMessages.length - i) * 60000; - } - - // 第一条消息始终显示时间 - if (i === 0) { - msg.showTime = true; - lastShowTime = msg.timestamp; - } else { - // 计算与最后一条显示时间的消息的时间差(分钟) - const timeDiffMinutes = (msg.timestamp - lastShowTime) / (1000 * 60); - - // 超过5分钟显示时间 - if (timeDiffMinutes >= this.data.timeInterval) { - msg.showTime = true; - lastShowTime = msg.timestamp; - } else { - msg.showTime = false; - } - } - - processedMessages.push(msg); - } - - // 存储最后一条显示时间的消息的时间戳 - if (lastShowTime) { - this.setData({ lastShowTimeStamp: lastShowTime }); - } - - return processedMessages; - }, - - // 处理单条消息的时间显示(添加新消息时调用) - processSingleMessageTime: function(message, messageList) { - const msg = { ...message }; - - // 确保时间戳是有效数字 - if (!msg.timestamp || isNaN(msg.timestamp) || msg.timestamp <= 0) { - msg.timestamp = Date.now(); - } - - if (messageList.length === 0) { - // 第一条消息 - msg.showTime = true; - this.setData({ lastShowTimeStamp: msg.timestamp }); - return msg; - } - - // 获取最后一条显示时间的消息 - const lastShowTime = this.data.lastShowTimeStamp; - - // 计算时间差(分钟) - const timeDiffMinutes = (msg.timestamp - lastShowTime) / (1000 * 60); - - // 超过5分钟显示时间 - if (timeDiffMinutes >= this.data.timeInterval) { - msg.showTime = true; - this.setData({ lastShowTimeStamp: msg.timestamp }); - } else { - msg.showTime = false; - } - - return msg; - }, - - // 返回上一页 - goBack: function() { - wx.navigateBack(); - }, - - // 打电话 - makePhoneCall: function() { - const phone = this.data.expertInfo.phone; - if (!phone) { - wx.showToast({ - title: '暂无联系电话', - icon: 'none' - }); - return; - } - - wx.makePhoneCall({ - phoneNumber: phone, - success: () => { - console.log('拨打电话成功'); - }, - fail: (err) => { - console.error('拨打电话失败:', err); - wx.showToast({ - title: '拨打失败', - icon: 'none' - }); - } - }); - }, - + // ========== 输入框相关方法 ========== + // 输入处理 onInput: function(e) { this.setData({ @@ -726,6 +87,10 @@ Page({ onInputFocus: function() { this.setData({ inputFocus: true + }, () => { + setTimeout(() => { + this.scrollToBottom(); + }, 200); }); }, @@ -744,13 +109,11 @@ Page({ }); }, - // 发送文本消息 - 使用您的接口调用方式 + // 发送文本消息 sendTextMessage: function() { const content = this.data.inputValue.trim(); if (!content) return; - console.log('发送文本消息:', content); - const newMessage = { id: 'msg-' + Date.now(), sender: 'user', @@ -760,7 +123,6 @@ Page({ status: 'sending' }; - // 处理时间显示并添加到消息列表 this.addMessageToList(newMessage); // 清空输入框 @@ -769,69 +131,24 @@ Page({ inputFocus: false }); - // 使用您的接口调用方式发送消息 - // http.sendTextMessage({ - // data: { - // expertId: this.data.currentExpertId, - // userId: this.data.userInfo.id, - // content: content, - // timestamp: Date.now() - // }, - // success: (res) => { - // console.log('发送消息成功:', res); - - // if (res.code === 0) { - // // 更新消息状态 - // this.updateMessageStatus(newMessage.id, 'success'); - - // // 模拟专家回复 - // setTimeout(() => { - // this.receiveExpertReply(); - // }, 1000 + Math.random() * 1000); - // } else { - // // 发送失败 - // this.updateMessageStatus(newMessage.id, 'error'); - // wx.showToast({ - // title: '发送失败', - // icon: 'none' - // }); - // } - // }, - // fail: (err) => { - // console.error('发送消息失败:', err); - // this.updateMessageStatus(newMessage.id, 'error'); - // wx.showToast({ - // title: '发送失败', - // icon: 'none' - // }); - // } - // }); - // 模拟发送成功 setTimeout(() => { this.updateMessageStatus(newMessage.id, 'success'); - // 模拟专家回复 setTimeout(() => { this.receiveExpertReply(); - }, 1000 + Math.random() * 1000); + }, 1000); }, 500); }, // 添加消息到列表 addMessageToList: function(message) { const { messageList } = this.data; - - // 处理消息时间显示 const processedMessage = this.processSingleMessageTime(message, messageList); - // 添加到列表 messageList.push(processedMessage); - this.setData({ - messageList - }, () => { - // 消息添加后滚动到底部 + this.setData({ messageList }, () => { this.scrollToBottom(); }); }, @@ -847,10 +164,8 @@ Page({ } }, - // 接收专家回复 - 使用您的接口调用方式 + // 接收专家回复 receiveExpertReply: function() { - // 这里可以使用WebSocket或轮询获取新消息 - // 模拟专家回复 const replies = [ '收到您的消息,让我分析一下您说的情况。', '建议您提供更多细节,比如发病时间、具体症状等。', @@ -873,36 +188,9 @@ Page({ this.addMessageToList(newMessage); }, - // 切换输入模式(语音/键盘) - switchInputMode: function() { - const currentMode = this.data.inputMode; - const newMode = currentMode === 'keyboard' ? 'voice' : 'keyboard'; - - console.log('切换输入模式:', currentMode, '->', newMode); - - this.setData({ - inputMode: newMode, - showMediaSheet: false - }); - - if (newMode === 'keyboard') { - // 切换到键盘模式 - setTimeout(() => { - this.setData({ - inputFocus: true, - inputPlaceholder: '请输入消息...' - }); - }, 100); - } else { - // 切换到语音模式 - this.setData({ - inputFocus: false, - inputPlaceholder: '按住说话' - }); - } - }, - - // 滚动事件处理 + // ========== 滚动相关 ========== + + // 滚动事件 onScroll: function(e) { const scrollTop = e.detail.scrollTop; this.setData({ @@ -910,14 +198,12 @@ Page({ isScrolling: true }); - // 延迟重置滚动状态 clearTimeout(this.scrollTimer); this.scrollTimer = setTimeout(() => { this.setData({ isScrolling: false }); }, 200); - // 检查是否需要加载更多 - if (scrollTop <= 100 && !this.data.loadingMore && this.data.hasMore && this.data.page > 1) { + if (scrollTop <= 100 && !this.data.loadingMore && this.data.hasMore) { this.loadMoreMessages(); } }, @@ -927,17 +213,11 @@ Page({ if (this.data.loadingMore || !this.data.hasMore) return; this.setData({ - loadingMore: true + loadingMore: true, + page: this.data.page + 1 + }, () => { + this.loadChatHistory(); }); - - // 加载更多聊天记录 - setTimeout(() => { - this.setData({ - page: this.data.page + 1 - }, () => { - this.loadChatHistory(); - }); - }, 500); }, // 滚动到底部 @@ -947,15 +227,31 @@ Page({ this.setData({ scrollAnimate: animate }, () => { - // 设置一个足够大的值确保滚动到底部 setTimeout(() => { this.setData({ scrollTop: 999999 }); - }, 100); + }, 50); + }); + }, + + // 键盘高度变化 + onKeyboardHeightChange: function(res) { + this.setData({ + keyboardHeight: res.height }); + + if (res.height > 0) { + this.setData({ showMediaSheet: false }); + + setTimeout(() => { + this.scrollToBottom(); + }, 100); + } }, + // ========== 多媒体相关 ========== + // 显示多媒体选择面板 showMediaActionSheet: function() { this.setData({ @@ -971,20 +267,6 @@ Page({ }); }, - // 键盘高度变化 - onKeyboardHeightChange: function(res) { - console.log('键盘高度变化:', res.height); - if (res.height > 0) { - // 键盘弹出时隐藏多媒体面板 - this.setData({ showMediaSheet: false }); - - // 键盘弹出后滚动到底部 - setTimeout(() => { - this.scrollToBottom(); - }, 300); - } - }, - // 选择图片 chooseImage: function() { this.hideMediaActionSheet(); @@ -994,11 +276,9 @@ Page({ sizeType: ['compressed'], sourceType: ['album'], success: (res) => { - console.log('选择图片成功:', res.tempFilePaths); this.uploadImages(res.tempFilePaths); }, fail: (err) => { - console.error('选择图片失败:', err); wx.showToast({ title: '选择图片失败', icon: 'none' @@ -1007,21 +287,18 @@ Page({ }); }, - - // 选择视频 chooseVideo: function() { this.hideMediaActionSheet(); + wx.chooseVideo({ sourceType: ['album'], compressed: true, maxDuration: 60, success: (res) => { - console.log('选择视频成功:', res); this.uploadVideo(res.tempFilePath, res.thumbTempFilePath); }, fail: (err) => { - console.error('选择视频失败:', err); wx.showToast({ title: '选择视频失败', icon: 'none' @@ -1030,7 +307,6 @@ Page({ }); }, - // 选择文件 chooseFile: function() { this.hideMediaActionSheet(); @@ -1039,12 +315,10 @@ Page({ count: 1, type: 'all', success: (res) => { - console.log('选择文件成功:', res); const file = res.tempFiles[0]; this.uploadFile(file.path, file.name, file.size); }, fail: (err) => { - console.error('选择文件失败:', err); wx.showToast({ title: '选择文件失败', icon: 'none' @@ -1069,12 +343,6 @@ Page({ // 通用文件上传 uploadFile: function(tempFilePath, fileName, fileSize = 0, type = 'file', thumbPath = '') { - console.log('开始上传文件:', { fileName, type, fileSize }); - - // 获取文件扩展名 - const extension = fileName.split('.').pop().toLowerCase(); - - // 创建消息 const messageId = 'file-' + Date.now(); const message = { id: messageId, @@ -1084,15 +352,13 @@ Page({ thumb: thumbPath, fileName: fileName, fileSize: fileSize, - extension: extension, + extension: fileName.split('.').pop().toLowerCase(), timestamp: Date.now(), status: 'uploading', progress: 0 }; this.addMessageToList(message); - - // 模拟上传过程 this.simulateUpload(messageId, type); }, @@ -1109,14 +375,12 @@ Page({ setTimeout(() => { this.updateMessageStatus(messageId, 'success'); - // 清除进度信息 const { messageList } = this.data; const index = messageList.findIndex(msg => msg.id === messageId); if (index !== -1) { delete messageList[index].progress; this.setData({ messageList }); - // 模拟专家回复 if (type === 'image' || type === 'video') { setTimeout(() => { this.receiveMediaReply(type); @@ -1126,7 +390,6 @@ Page({ }, 200); } - // 更新进度 const { messageList } = this.data; const index = messageList.findIndex(msg => msg.id === messageId); if (index !== -1) { @@ -1165,187 +428,202 @@ Page({ this.addMessageToList(newMessage); }, - // 开始语音录制 - startVoiceRecord: function(e) { - if (e && e.touches && e.touches[0]) { - this.setData({ - recordStartY: e.touches[0].clientY - }); - } - - this.recordManager.start({ - duration: 60000, - sampleRate: 44100, - numberOfChannels: 1, - encodeBitRate: 192000, - format: 'aac' + // 预览图片 + previewImage: function(e) { + const url = e.currentTarget.dataset.url; + wx.previewImage({ + current: url, + urls: [url] }); }, - // 语音录制触摸移动 - onVoiceTouchMove: function(e) { - if (!this.data.isRecording) return; - - if (e.touches && e.touches[0]) { - const currentY = e.touches[0].clientY; - const startY = this.data.recordStartY; - const deltaY = startY - currentY; - - const isCanceling = deltaY > 50; - - if (isCanceling !== this.data.isCanceling) { - this.setData({ - isCanceling: isCanceling, - recordingTip: isCanceling ? '松开取消' : '松开 发送', - voiceTip: isCanceling ? '松开取消' : '按住 说话' - }); - } - } + // ========== 数据初始化 ========== + + // 设置今天日期 + setTodayDate: function() { + const now = new Date(); + const month = now.getMonth() + 1; + const date = now.getDate(); + const week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()]; + this.setData({ + todayDate: `${month}月${date}日 星期${week}` + }); }, - // 结束语音录制 - endVoiceRecord: function() { - if (this.data.isRecording) { - this.recordManager.stop(); + // 加载用户信息 + loadUserInfo: function() { + try { + const userInfo = wx.getStorageSync('userInfo'); + if (userInfo) { + this.setData({ userInfo }); + } + } catch (e) { + console.error('加载用户信息失败:', e); } }, - // 取消语音录制 - cancelVoiceRecord: function() { - if (this.data.isRecording) { + // 加载专家信息 + loadExpertInfo: function(expertId) { + wx.showLoading({ title: '加载中...' }); + + // 模拟网络请求 + setTimeout(() => { this.setData({ - isCanceling: true + expertInfo: { + id: Number(expertId), + name: '张明专家', + title: '资深畜牧兽医', + expertise: '牛羊疾病防治', + avatar: '/images/avatars/expert1.png', + online: true, + phone: '13800138000' + }, + loading: false }); - this.recordManager.stop(); - } + + wx.hideLoading(); + this.loadChatHistory(); + }, 500); }, - // 发送语音消息 - sendAudioMessage: function(tempFilePath, duration) { - console.log('发送语音消息:', { duration }); - - const message = { - id: 'audio-' + Date.now(), - sender: 'user', - type: 'audio', - content: tempFilePath, - duration: duration, - timestamp: Date.now(), - status: 'sending' - }; - - this.addMessageToList(message); + // 加载聊天记录 + loadChatHistory: function() { + this.setData({ loading: true }); - // 模拟发送成功 + // 模拟历史消息 setTimeout(() => { - this.updateMessageStatus(message.id, 'success'); - - // 模拟专家回复 - setTimeout(() => { - const reply = { - id: 'exp-audio-' + Date.now(), + const now = Date.now(); + const mockMessages = [ + { + id: 'msg-1', + sender: 'expert', + type: 'text', + content: '您好,我是张明专家,有什么可以帮您?', + timestamp: now - 10 * 60 * 1000, + status: 'success' + }, + { + id: 'msg-2', + sender: 'user', + type: 'text', + content: '您好,我养的牛最近食欲不振,请问是什么原因?', + timestamp: now - 9 * 60 * 1000, + status: 'success' + }, + { + id: 'msg-3', sender: 'expert', type: 'text', - content: '语音收到了,我会仔细听取分析。', - timestamp: Date.now(), + content: '可能是饲料问题或环境变化引起的,请描述一下具体情况。', + timestamp: now - 7 * 60 * 1000, + status: 'success' + }, + { + id: 'msg-4', + sender: 'user', + type: 'text', + content: '具体症状是拉稀,体温偏高,精神状态不好。', + timestamp: now - 2 * 60 * 1000, status: 'success' - }; - this.addMessageToList(reply); - }, 1500); + }, + { + id: 'msg-5', + sender: 'expert', + type: 'text', + content: '明白了,建议您调整饲料配方,添加一些益生菌。', + timestamp: now - 1 * 60 * 1000, + status: 'success' + } + ]; + + const processedMessages = this.processMessageTimes(mockMessages); + + this.setData({ + messageList: processedMessages, + loading: false, + hasMore: false + }, () => { + this.scrollToBottom(true); + }); }, 800); }, - // 预览图片 - previewImage: function(e) { - const url = e.currentTarget.dataset.url; - wx.previewImage({ - current: url, - urls: [url], - fail: (err) => { - console.error('预览图片失败:', err); - wx.showToast({ - title: '预览失败', - icon: 'none' - }); - } - }); - }, - - // 下载文件 - downloadFile: function(e) { - const url = e.currentTarget.dataset.url; - wx.showLoading({ title: '下载中...' }); + // 处理消息时间显示 + processMessageTimes: function(messages) { + if (!messages || messages.length === 0) return []; - wx.downloadFile({ - url: url, - success: (res) => { - wx.hideLoading(); - wx.showToast({ - title: '下载成功', - icon: 'success' - }); - - // 保存到相册(如果是图片) - if (url.match(/\.(jpg|jpeg|png|gif)$/i)) { - wx.saveImageToPhotosAlbum({ - filePath: res.tempFilePath, - success: () => { - wx.showToast({ - title: '已保存到相册', - icon: 'success' - }); - }, - fail: (err) => { - console.error('保存到相册失败:', err); - } - }); - } - }, - fail: (err) => { - wx.hideLoading(); - console.error('下载失败:', err); - wx.showToast({ - title: '下载失败', - icon: 'none' - }); + const sortedMessages = [...messages].sort((a, b) => a.timestamp - b.timestamp); + const processedMessages = []; + let lastShowTime = null; + + for (let i = 0; i < sortedMessages.length; i++) { + const msg = { ...sortedMessages[i] }; + + if (!msg.timestamp || isNaN(msg.timestamp) || msg.timestamp <= 0) { + msg.timestamp = Date.now() - (sortedMessages.length - i) * 60000; } - }); + + if (i === 0) { + msg.showTime = true; + lastShowTime = msg.timestamp; + } else { + const timeDiffMinutes = (msg.timestamp - lastShowTime) / (1000 * 60); + msg.showTime = timeDiffMinutes >= this.data.timeInterval; + if (msg.showTime) lastShowTime = msg.timestamp; + } + + processedMessages.push(msg); + } + + if (lastShowTime) { + this.setData({ lastShowTimeStamp: lastShowTime }); + } + + return processedMessages; }, - // 修复:时间格式化函数 - 确保正确显示 - formatTime: function(timestamp) { - // 调试日志 - console.log('formatTime 接收到的timestamp:', timestamp, '类型:', typeof timestamp); + // 处理单条消息时间 + processSingleMessageTime: function(message, messageList) { + const msg = { ...message }; - if (!timestamp || timestamp <= 0) { - console.warn('无效的时间戳:', timestamp); - return '未知时间'; + if (!msg.timestamp || isNaN(msg.timestamp) || msg.timestamp <= 0) { + msg.timestamp = Date.now(); } - const timeNum = Number(timestamp); - if (isNaN(timeNum)) { - console.warn('时间戳不是有效数字:', timestamp); - return '未知时间'; + if (messageList.length === 0) { + msg.showTime = true; + this.setData({ lastShowTimeStamp: msg.timestamp }); + return msg; } - const date = new Date(timeNum); - if (isNaN(date.getTime())) { - console.warn('无法创建有效日期对象:', timeNum); - return '未知时间'; + const lastShowTime = this.data.lastShowTimeStamp; + const timeDiffMinutes = (msg.timestamp - lastShowTime) / (1000 * 60); + + msg.showTime = timeDiffMinutes >= this.data.timeInterval; + if (msg.showTime) { + this.setData({ lastShowTimeStamp: msg.timestamp }); } - // 只显示小时和分钟 + return msg; + }, + + // ========== 工具方法 ========== + + // 格式化时间 + formatTime: function(timestamp) { + if (!timestamp || timestamp <= 0) return '未知时间'; + + const date = new Date(Number(timestamp)); + if (isNaN(date.getTime())) return '未知时间'; + const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); - - const result = `${hours}:${minutes}`; - console.log('formatTime 结果:', result); - return result; + return `${hours}:${minutes}`; }, // 格式化文件大小 formatFileSize: function(bytes) { - if (bytes === 0 || !bytes) return '未知大小'; + if (!bytes || bytes === 0) return '0B'; const units = ['B', 'KB', 'MB', 'GB']; let size = bytes; @@ -1360,7 +638,5 @@ Page({ }, // 阻止事件冒泡 - stopPropagation: function() { - // 空函数,仅用于阻止事件冒泡 - } + stopPropagation: function() {} }); \ No newline at end of file diff --git a/pagesA/pages/expertChat/expertChat.wxml b/pagesA/pages/expertChat/expertChat.wxml index c8f2b5d..75e4deb 100644 --- a/pagesA/pages/expertChat/expertChat.wxml +++ b/pagesA/pages/expertChat/expertChat.wxml @@ -32,7 +32,6 @@ - @@ -40,15 +39,12 @@ - - {{item.content}} - - - - - - - - - - - - {{item.duration || 0}}'' - - - - @@ -102,15 +83,12 @@ - - {{item.content}} - - - - - - - - - - - {{item.duration || 0}}'' - - - - - @@ -181,94 +144,64 @@ - - 加载中... - 暂无聊天记录,开始咨询吧 - - - - - - - - - - - - - {{voiceTip}} - - - - - + + + + + - - - - - - - - - - + - + show-confirm-bar="{{false}}" + disable-default-padding="{{true}}" + > - - + + - - + --> + - - - + + @@ -310,28 +243,4 @@ - - - - - - - - {{recordingTip}} - - - - - {{recordingTime}}s - - - \ No newline at end of file diff --git a/pagesA/pages/expertChat/expertChat.wxss b/pagesA/pages/expertChat/expertChat.wxss index 31b5b40..18ffbef 100644 --- a/pagesA/pages/expertChat/expertChat.wxss +++ b/pagesA/pages/expertChat/expertChat.wxss @@ -1,20 +1,21 @@ - -/* 页面整体样式 */ +/* ========== 页面整体样式 ========== */ .consult-page { width: 100vw; height: 100vh; background: #f5f5f5; display: flex; flex-direction: column; + overflow: hidden; } -/* 头部样式 */ +/* ========== 头部样式 ========== */ .consult-header { background: #ffffff; border-bottom: 1rpx solid #e5e5e5; position: relative; z-index: 1000; box-shadow: 0 1rpx 6rpx rgba(0, 0, 0, 0.05); + flex-shrink: 0; } .header-content { @@ -24,16 +25,12 @@ height: 96rpx; } - .header-center { flex: 1; display: flex; justify-content: center; } - - - .expert-info { display: flex; flex-direction: column; @@ -72,15 +69,9 @@ } @keyframes pulse { - 0% { - box-shadow: 0 0 0 0 rgba(7, 193, 96, 0.4); - } - 70% { - box-shadow: 0 0 0 8rpx rgba(7, 193, 96, 0); - } - 100% { - box-shadow: 0 0 0 0 rgba(7, 193, 96, 0); - } + 0% { box-shadow: 0 0 0 0 rgba(7, 193, 96, 0.4); } + 70% { box-shadow: 0 0 0 8rpx rgba(7, 193, 96, 0); } + 100% { box-shadow: 0 0 0 0 rgba(7, 193, 96, 0); } } .status-text { @@ -88,15 +79,14 @@ color: #666666; } - - -/* 聊天容器 */ +/* ========== 聊天容器 ========== */ .chat-container { flex: 1; padding: 20rpx 0; background: #f5f5f5; overflow-y: auto; position: relative; + height: 0; } /* 日期分隔线 */ @@ -112,13 +102,10 @@ border-radius: 100rpx; font-size: 24rpx; color: #ffffff; - font-weight: 400; background-color: #d8d8d8; } - - -/* 消息项 */ +/* ========== 消息项 ========== */ .message-item { display: flex; margin-bottom: 24rpx; @@ -130,23 +117,12 @@ } @keyframes fadeIn { - from { - opacity: 0; - transform: translateY(10rpx); - } - to { - opacity: 1; - transform: translateY(0); - } + from { opacity: 0; transform: translateY(10rpx); } + to { opacity: 1; transform: translateY(0); } } -.message-left { - justify-content: flex-start; -} - -.message-right { - justify-content: flex-end; -} +.message-left { justify-content: flex-start; } +.message-right { justify-content: flex-end; } /* 头像 */ .message-avatar { @@ -161,13 +137,8 @@ z-index: 1; } -.message-left .message-avatar { - margin-right: 16rpx; -} - -.message-right .message-avatar { - margin-left: 16rpx; -} +.message-left .message-avatar { margin-right: 16rpx; } +.message-right .message-avatar { margin-left: 16rpx; } .avatar-img { width: 100%; @@ -175,7 +146,7 @@ object-fit: cover; } -/* 消息内容包装器 */ +/* 消息内容包装器 */ .message-content-wrapper { max-width: 480rpx; position: relative; @@ -184,38 +155,31 @@ z-index: 2; } -.message-left .message-content-wrapper { - align-items: flex-start; -} +.message-left .message-content-wrapper { align-items: flex-start; } +.message-right .message-content-wrapper { align-items: flex-end; } -.message-right .message-content-wrapper { - align-items: flex-end; -} - -/* 气泡箭头*/ +/* 气泡箭头 */ .message-arrow { position: absolute; width: 0; height: 0; border-style: solid; border-width: 12rpx; - top: 30rpx; /* 固定在头像中间位置 (80rpx/2 = 40rpx) */ + top: 30rpx; z-index: 1; } -/* 左侧箭头(专家) */ .arrow-left { left: -24rpx; border-color: transparent #ffffff transparent transparent; } -/* 右侧箭头(用户) */ .arrow-right { right: -24rpx; border-color: transparent transparent transparent #95ec69; } -/* 消息气泡通用样式 */ +/* 消息气泡 */ .message-bubble { position: relative; padding: 16rpx 20rpx; @@ -226,7 +190,6 @@ align-items: center; } -/* 左侧气泡(专家) */ .bubble-left { background: #ffffff; border-radius: 10rpx; @@ -234,7 +197,6 @@ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); } -/* 右侧气泡(用户) */ .bubble-right { background: #95ec69; border-radius: 10rpx; @@ -249,11 +211,9 @@ line-height: 1.4; } -.bubble-right .message-text { - color: #000000; -} +.bubble-right .message-text { color: #000000; } -/* 媒体消息通用样式 */ +/* 媒体消息 */ .media-bubble { position: relative; border-radius: 10rpx; @@ -266,22 +226,15 @@ justify-content: center; } -.message-left .media-bubble { - border-top-left-radius: 4rpx; -} +.message-left .media-bubble { border-top-left-radius: 4rpx; } +.message-right .media-bubble { border-top-right-radius: 4rpx; } -.message-right .media-bubble { - border-top-right-radius: 4rpx; -} - -/* 图片消息 */ .message-image { width: 280rpx; height: 280rpx; display: block; } -/* 视频消息 */ .message-video { width: 280rpx; height: 280rpx; @@ -308,67 +261,6 @@ margin-left: 4rpx; } -/* 语音消息 */ -.message-audio { - min-width: 240rpx; - padding: 20rpx; - display: flex; - align-items: center; - min-height: 60rpx; -} - -.audio-icon-left, -.audio-icon-right { - width: 32rpx; - height: 32rpx; - flex-shrink: 0; -} - -.audio-icon-left { - margin-right: 16rpx; -} - -.audio-icon-right { - margin-left: 16rpx; -} - -.audio-content { - flex: 1; - display: flex; - align-items: center; - justify-content: space-between; -} - -.audio-wave { - display: flex; - align-items: flex-end; - height: 28rpx; - margin-right: 16rpx; -} - -.wave-bar { - width: 4rpx; - margin: 0 2rpx; - background: currentColor; - border-radius: 2rpx; - animation: wave 1s ease-in-out infinite; -} - -@keyframes wave { - 0%, 100% { - height: 12rpx; - } - 50% { - height: 28rpx; - } -} - -.audio-duration { - font-size: 26rpx; - font-weight: 500; - color: #000000; -} - /* 文件消息 */ .message-file { min-width: 280rpx; @@ -441,12 +333,8 @@ } @keyframes spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } } .progress-text { @@ -455,12 +343,10 @@ font-weight: 600; } -/* 底部留白区域 */ -.chat-bottom-space { - height: 40rpx; -} +/* 底部留白 */ +.chat-bottom-space { height: 40rpx; } -/* 加载更多提示 */ +/* 加载更多 */ .load-more-tip { display: flex; justify-content: center; @@ -470,7 +356,7 @@ font-size: 24rpx; } -/* 空状态提示 */ +/* 空状态 */ .empty-tip { display: flex; flex-direction: column; @@ -492,123 +378,100 @@ color: #999999; } -/* 输入区域 */ +/* ========== 输入区域 - 优化垂直对齐和按钮美化 ========== */ .input-section { background: #ffffff; border-top: 1rpx solid #e5e5e5; - padding: 20rpx 30rpx; + padding: 16rpx 30rpx; position: relative; z-index: 100; box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05); + flex-shrink: 0; + width: 100%; + box-sizing: border-box; } -/* 语音输入面板 */ -.voice-input-panel { - display: flex; - align-items: center; - gap: 20rpx; - height: 80rpx; -} - -/* 文字输入面板 */ +/* 文字输入面板 - 垂直居中优化 */ .text-input-panel { display: flex; align-items: center; - gap: 20rpx; - height: 80rpx; + gap: 16rpx; + min-height: 72rpx; } -/* 语音输入按钮(切换按钮) */ -.voice-input-btn { - width: 80rpx; - height: 80rpx; +/* 添加按钮 - 完美垂直居中 */ +.add-btn { + width: 72rpx; + height: 72rpx; display: flex; align-items: center; justify-content: center; - transition: all 0.2s; + flex-shrink: 0; } -.voice-btn-icon { - width: 70rpx; - height: 70rpx; +.add-icon { + width: 60rpx; + height: 60rpx; } -/* 输入框包装器 */ +/* 输入框包装器 - 优化高度和内边距 */ .input-wrapper { flex: 1; position: relative; background: #f5f5f5; - border-radius: 40rpx; - height: 80rpx; + border-radius: 36rpx; + min-height: 72rpx; display: flex; align-items: center; + padding: 0 24rpx; transition: all 0.2s; - overflow: hidden; - min-width: 0; -} - -/* 语音输入模式下的输入框 */ -.voice-input-panel .input-wrapper { - padding: 0; - background: #f5f5f5; -} - -/* 文字输入模式下的输入框 */ -.text-input-panel .input-wrapper { - padding: 0 30rpx; + box-sizing: border-box; } .input-wrapper:active { background: #e8e8e8; } -/* 语音输入按钮 */ -.voice-record-btn { - width: 100%; - height: 100%; - border-radius: 40rpx; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - transition: all 0.2s; -} - -.voice-record-btn:active { - background: #e0e0e0; -} - - -.voice-tip { - font-size: 24rpx; - color: #666666; -} - -/* 文字输入框 */ -.chat-input { +/* 多行文本输入框 - 优化垂直居中 */ +.chat-textarea { flex: 1; - height: 100%; - font-size: 32rpx; - color: #000000; - line-height: 80rpx; - min-width: 0; + width: 100%; + font-size: 30rpx; + color: #333333; + line-height: 1.4; + min-height: 48rpx; + max-height: 160rpx; + padding: 12rpx 0; + margin: 0; + background: transparent; + border: none; + box-sizing: border-box; + overflow-y: auto; } +/* 占位符样式 */ .input-placeholder { color: #999999; - font-size: 24rpx; + font-size: 28rpx; + line-height: 1.4; } +/* 清空按钮 - 完美垂直居中 */ .input-actions { position: absolute; - right: 20rpx; + right: 16rpx; top: 50%; transform: translateY(-50%); + z-index: 2; + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; } .clear-btn { - width: 40rpx; - height: 40rpx; + width: 36rpx; + height: 36rpx; border: none; background: transparent; padding: 0; @@ -620,70 +483,87 @@ justify-content: center; } +.clear-btn::after { + border: none; +} + .clear-btn:active { - background: rgba(0, 0, 0, 0.05); + background: rgba(0, 0, 0, 0.1); } .clear-icon { - width: 32rpx; - height: 32rpx; + width: 28rpx; + height: 28rpx; } -/* 更多按钮 */ -.more-btn { - width: 80rpx; - height: 80rpx; - border-radius: 50%; +/* 发送按钮 - 美观渐变绿色,完美垂直居中 */ +.send-btn { + background: linear-gradient(135deg, #07c160 0%, #06ae56 100%); + width: 112rpx; + height: 72rpx; + border-radius: 36rpx; border: none; - background: transparent; display: flex; align-items: center; justify-content: center; - transition: all 0.2s; + transition: all 0.3s ease; padding: 0; margin: 0; line-height: 1; flex-shrink: 0; + box-shadow: 0 4rpx 8rpx rgba(7, 193, 96, 0.2); + position: relative; + overflow: hidden; } -.more-btn:active { - background: rgba(0, 0, 0, 0.05); -} - -.more-icon { - width: 70rpx; - height: 70rpx; +/* 发送按钮点击效果 */ +.send-btn:active { + background: linear-gradient(135deg, #06ae56 0%, #059c4c 100%); + transform: scale(0.96); + box-shadow: 0 2rpx 4rpx rgba(7, 193, 96, 0.3); } -/* 发送按钮 */ -.send-btn { - background: #07c160; - width: 120rpx; - border-radius: 40rpx; - height: 80rpx; - border: none; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.2s; - padding: 0; - margin: 0; - line-height: 1; - flex-shrink: 0; +/* 发送按钮水波纹效果 */ +.send-btn::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 0; + height: 0; + border-radius: 50%; + background: rgba(255, 255, 255, 0.3); + transform: translate(-50%, -50%); + transition: width 0.3s, height 0.3s; } -.send-btn:active { - background: #06ad56; - transform: scale(0.98); +.send-btn:active::after { + width: 200rpx; + height: 200rpx; + opacity: 0; } .send-text { font-size: 28rpx; color: #ffffff; - font-weight: 500; + font-weight: 600; + letter-spacing: 2rpx; +} + +/* 发送按钮占位 - 保持布局稳定 */ +.send-placeholder { + width: 112rpx; + height: 72rpx; + flex-shrink: 0; } -/* 多媒体选择面板 */ +/* 适配小屏幕 */ +@media screen and (max-width: 320px) { + .send-btn { width: 100rpx; } + .send-placeholder { width: 100rpx; } +} + +/* ========== 多媒体选择面板 ========== */ .media-action-sheet { position: fixed; top: 0; @@ -708,12 +588,8 @@ } @keyframes slideUp { - from { - transform: translateY(100%); - } - to { - transform: translateY(0); - } + from { transform: translateY(100%); } + to { transform: translateY(0); } } .media-sheet-header { @@ -721,7 +597,7 @@ align-items: center; justify-content: space-between; margin-bottom: 40rpx; - padding: 0 10rpx 20rpx; + padding: 0 10rpx 20rpx; border-bottom: 1px solid #E4E4E4; } @@ -776,7 +652,6 @@ transform: scale(0.95); } - .option-icon-box image { width: 60rpx; height: 60rpx; @@ -796,101 +671,6 @@ color: #999999; } -/* 录音模态框 */ -.recording-modal { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.7); - display: flex; - align-items: center; - justify-content: center; - z-index: 3000; - animation: fadeIn 0.2s ease; -} - -.recording-box { - background: rgba(0, 0, 0, 0.8); - border-radius: 40rpx; - padding: 60rpx 80rpx; - display: flex; - flex-direction: column; - align-items: center; - min-width: 400rpx; -} - -.recording-box.is-canceling { - background: rgba(0, 0, 0, 0.9); -} - -.recording-icon { - width: 160rpx; - height: 160rpx; - margin-bottom: 40rpx; - display: flex; - align-items: center; - justify-content: center; -} - -.recording-mic-icon { - width: 120rpx; - height: 120rpx; -} - -.recording-tip { - font-size: 32rpx; - color: #ffffff; - font-weight: 500; - margin-bottom: 30rpx; - text-align: center; -} - -.recording-box.is-canceling .recording-tip { - color: #ff4444; -} - -.recording-meter { - display: flex; - flex-direction: column; - align-items: center; -} - -.recording-waves { - display: flex; - align-items: flex-end; - height: 60rpx; - margin-bottom: 20rpx; -} - -.recording-wave { - width: 8rpx; - margin: 0 4rpx; - background: #07c160; - border-radius: 4rpx; - animation: recordingWave 1.2s ease-in-out infinite; -} - -.recording-box.is-canceling .recording-wave { - background: #ff4444; -} - -@keyframes recordingWave { - 0%, 100% { - height: 20rpx; - } - 50% { - height: 60rpx; - } -} - -.recording-time { - font-size: 36rpx; - color: #ffffff; - font-weight: bold; -} - /* 适配全面屏 */ .safe-area-bottom { padding-bottom: env(safe-area-inset-bottom); diff --git a/pagesA/pages/noticeList/noticeList.js b/pagesA/pages/noticeList/noticeList.js new file mode 100644 index 0000000..378cf0d --- /dev/null +++ b/pagesA/pages/noticeList/noticeList.js @@ -0,0 +1,97 @@ +import http from '../../../utils/api' +Page({ + data: { + // 分类数据 + categories: [ + { name: '全部', value: 'all' }, + { name: '系统公告', value: 'system', tagBg: '#e9efff', importanceColor: '#3b82f6' }, + { name: '活动通知', value: 'activity', tagBg: '#f3e8ff', importanceColor: '#8b5cf6' }, + { name: '紧急提醒', value: 'urgent', tagBg: '#ffe4e2', importanceColor: '#ef4444' }, + { name: '学术讲座', value: 'academic', tagBg: '#dcfce7', importanceColor: '#10b981' }, + { name: '校园生活', value: 'campus', tagBg: '#fff3cd', importanceColor: '#f59e0b' }, + ], + currentCategory: 'all', // 当前选中分类 + searchKeyword: '', // 搜索关键字 + noticeList: [], // 渲染列表数据 + pageIndex: 1, // 页码 + pageSize: 8, // 每页条数 + hasMore: true, // 是否有更多 + loading: false, // 首次加载/加载中 + refreshing: false, // 下拉刷新状态 + mockTotal: 28, // 模拟总条数 + }, + + onLoad() { + // this.loadFirstPage(); + this.getdisaster() + }, + + + // 通知公告 + getdisaster(){ + http.disaster({ + data:{}, + success: res => { + console.log(111,res); + this.setData({ + noticeList:res.rows + }) + } + }) + }, + + + + + // 切换分类 + switchCategory(e) { + const category = e.currentTarget.dataset.category; + if (category === this.data.currentCategory) return; + this.setData({ currentCategory: category }); + this.loadFirstPage(); + }, + + // 搜索输入 + onSearchInput(e) { + this.setData({ searchKeyword: e.detail.value }); + }, + + // 执行搜索(确认或点击清空后也会触发重置) + handleSearch() { + this.loadFirstPage(); + }, + + // 清空搜索框 + clearSearch() { + this.setData({ searchKeyword: '' }, () => { + this.loadFirstPage(); + }); + }, + + // 上拉加载更多 + loadMore() { + const { hasMore, loading, refreshing } = this.data; + if (!hasMore || loading || refreshing) return; + this.setData({ loading: true }); + this.fetchNotices(false); + }, + + // 下拉刷新 + onRefresh() { + this.setData({ refreshing: true }); + // 重置到第一页 + this.setData({ pageIndex: 1, hasMore: true }, () => { + this.fetchNotices(true); + }); + }, + + // 查看详情 (仅跳转示意) + viewDetail(e) { + const id = e.currentTarget.dataset.id; + wx.showToast({ + title: `查看公告 ${id}`, + icon: 'none' + }); + // 实际开发: wx.navigateTo... + } +}) \ No newline at end of file diff --git a/pagesA/pages/noticeList/noticeList.json b/pagesA/pages/noticeList/noticeList.json new file mode 100644 index 0000000..6da5204 --- /dev/null +++ b/pagesA/pages/noticeList/noticeList.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText":"通知公告列表", + "usingComponents": {} +} \ No newline at end of file diff --git a/pagesA/pages/noticeList/noticeList.wxml b/pagesA/pages/noticeList/noticeList.wxml new file mode 100644 index 0000000..bed9727 --- /dev/null +++ b/pagesA/pages/noticeList/noticeList.wxml @@ -0,0 +1,108 @@ + + + + + + + + + 📋 公告·通知 + + 🔍 + + + + + + + + + + {{item.name}} + + + + + + + + + + + + + + + + + + + + + + + {{item.title}} + {{item.warningType}} + + {{item.responseMeasures}} + + + 📅 + {{item.createdTime}} + + + + + + + + + + + 加载更多 + + + —— 已经到底了 —— + + + + + + + 📭 暂无相关公告 + 试试其他关键词或分类 + + + + + \ No newline at end of file diff --git a/pagesA/pages/noticeList/noticeList.wxss b/pagesA/pages/noticeList/noticeList.wxss new file mode 100644 index 0000000..b40154b --- /dev/null +++ b/pagesA/pages/noticeList/noticeList.wxss @@ -0,0 +1,289 @@ +.page { + background: linear-gradient(145deg, #f5f7fa 0%, #f0f2f5 100%); + } + .notice-page { + min-height: 100vh; + background: transparent; + position: relative; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, sans-serif; + } + .bg-blur { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: radial-gradient(circle at 20% 30%, rgba(235, 245, 255, 0.7) 0%, rgba(255, 255, 255, 0.9) 70%); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + z-index: 0; + pointer-events: none; + } + .content { + position: relative; + z-index: 2; + display: flex; + flex-direction: column; + padding: 30rpx 32rpx 0; + box-sizing: border-box; + } + + /* 头部与搜索 */ + .header { + margin-bottom: 36rpx; + } + .title { + font-size: 48rpx; + font-weight: 700; + color: #1e293b; + letter-spacing: 2rpx; + display: block; + margin-bottom: 24rpx; + text-shadow: 0 4rpx 12rpx rgba(0,0,0,0.02); + } + .search-box { + background: rgba(255,255,255,0.7); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + border-radius: 48rpx; + padding: 16rpx 32rpx; + display: flex; + align-items: center; + border: 1rpx solid rgba(255,255,255,0.9); + box-shadow: 0 8rpx 20rpx rgba(0,0,0,0.02), 0 2rpx 4rpx rgba(0,0,0,0.02); + transition: all 0.2s; + } + .search-box:focus-within { + border-color: #b2d9ff; + background: rgba(255,255,255,0.9); + box-shadow: 0 12rpx 28rpx rgba(0,120,255,0.08); + } + .search-box .icon { + font-size: 32rpx; + color: #7c8ea0; + margin-right: 16rpx; + } + .search-box input { + flex: 1; + font-size: 30rpx; + padding: 8rpx 0; + color: #1e293b; + } + .placeholder { + color: #9aa6b2; + font-weight: 400; + } + .clear-icon { + font-size: 36rpx; + color: #8e9dac; + padding: 8rpx; + border-radius: 50%; + background: rgba(0,0,0,0.02); + width: 40rpx; + height: 40rpx; + display: flex; + align-items: center; + justify-content: center; + } + + /* 分类导航 — 磨砂质感 */ + .category-scroll { + white-space: nowrap; + margin-bottom: 32rpx; + background: rgba(255,255,255,0.5); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-radius: 60rpx; + padding: 8rpx 0; + border: 1rpx solid rgba(255,255,255,0.8); + } + .category-list { + display: inline-flex; + padding: 0 24rpx; + } + .category-item { + display: inline-flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 16rpx 36rpx; + margin-right: 12rpx; + border-radius: 60rpx; + font-size: 30rpx; + color: #475569; + background: transparent; + transition: all 0.18s; + position: relative; + font-weight: 500; + } + .category-item.active { + background: #ffffff; + color: #1e4bd2; + font-weight: 600; + box-shadow: 0 6rpx 14rpx rgba(0,80,255,0.1); + } + .dot { + width: 8rpx; + height: 8rpx; + background: #1e4bd2; + border-radius: 50%; + margin-top: 6rpx; + } + + /* 列表容器 */ + .list-container { + flex: 1; + height: calc(100vh - 280rpx); + background: transparent; + border-radius: 40rpx 40rpx 0 0; + margin-top: 8rpx; + } + .notice-scroll { + height: 100%; + padding-bottom: 20rpx; + } + .notice-list { + display: flex; + flex-direction: column; + gap: 28rpx; + } + /* 卡片设计 — 轻盈毛玻璃 */ + .notice-card { + background: rgba(255,255,255,0.7); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border-radius: 36rpx; + border: 1rpx solid rgba(255,255,255,0.9); + box-shadow: 0 8rpx 18rpx rgba(0,0,0,0.02); + display: flex; + overflow: hidden; + transition: transform 0.2s, box-shadow 0.3s; + } + .notice-card:active { + transform: scale(0.99); + box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04); + } + .card-left-bar { + width: 12rpx; + flex-shrink: 0; + background: #3b82f6; + } + .card-content { + flex: 1; + padding: 32rpx 28rpx; + } + .card-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16rpx; + } + .notice-title { + font-size: 34rpx; + font-weight: 600; + color: #0a1e3c; + max-width: 460rpx; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .notice-tag { + font-size: 24rpx; + padding: 8rpx 24rpx; + border-radius: 48rpx; + background: #eef2ff; + color: #1e4bd2; + font-weight: 500; + letter-spacing: 1rpx; + } + .notice-abstract { + font-size: 28rpx; + color: #55657a; + line-height: 1.5; + margin-bottom: 28rpx; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + } + .card-footer { + display: flex; + justify-content: space-between; + align-items: center; + color: #778a9b; + font-size: 26rpx; + } + .date-time, .view-count { + display: flex; + align-items: center; + gap: 8rpx; + } + + /* 加载更多 / 状态 */ + .load-more { + text-align: center; + padding: 48rpx 0 36rpx; + color: #8f9eb0; + font-size: 28rpx; + display: flex; + align-items: center; + justify-content: center; + gap: 12rpx; + } + .loading-icon { + font-size: 48rpx; + line-height: 1; + animation: pulse 1.2s infinite; + } + @keyframes pulse { + 0%, 100% { opacity: 0.6; } + 50% { opacity: 1; } + } + + /* 骨架屏 */ + .skeleton-list { + padding: 0 8rpx; + } + .skeleton-item { + background: rgba(255,255,255,0.6); + border-radius: 32rpx; + height: 220rpx; + margin-bottom: 28rpx; + position: relative; + overflow: hidden; + } + .skeleton-item::after { + content: ""; + position: absolute; + top: 0; + left: -150%; + width: 200%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255,255,255,0.7), transparent); + animation: shimmer 1.5s infinite; + } + @keyframes shimmer { + 100% { left: 100%; } + } + + /* 空状态 */ + .empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 120rpx 0; + color: #6f7d8c; + font-size: 32rpx; + background: rgba(255,255,255,0.4); + backdrop-filter: blur(8px); + border-radius: 48rpx; + margin-top: 60rpx; + } + + /* 模拟图片(无实际图片用文字代替) */ + .empty-state text:first-of-type { + font-size: 64rpx; + margin-bottom: 24rpx; + } \ No newline at end of file diff --git a/pagesA/pages/wzai/wzai.js b/pagesA/pages/wzai/wzai.js index 3bd1bc6..5246f10 100644 --- a/pagesA/pages/wzai/wzai.js +++ b/pagesA/pages/wzai/wzai.js @@ -1,4 +1,5 @@ import http from '../../../utils/api' + Page({ data: { // 当前时间 @@ -8,6 +9,14 @@ Page({ // 输入框相关 inputValue: '', autoFocus: false, + inputHeight: 60, + isKeyboardShow: false, + // 滚动控制 + scrollIntoView: 'welcome-message', + scrollAnimation: true, + isUserScrolling: false, // 用户是否正在手动滚动 + scrollTimer: null, // 滚动定时器 + lastMessageCount: 0, // 上次消息数量 // 症状选择 quickSymptoms: [], wzsearch: {}, @@ -22,7 +31,90 @@ Page({ onLoad() { this.initData(); - this.getInquiry() + this.getInquiry(); + // 监听键盘高度变化 + wx.onKeyboardHeightChange(this.onKeyboardHeightChange.bind(this)); + }, + + onUnload() { + // 页面卸载时移除监听 + wx.offKeyboardHeightChange(this.onKeyboardHeightChange); + // 清除定时器 + if (this.data.scrollTimer) { + clearTimeout(this.data.scrollTimer); + } + }, + + // 监听滚动事件 + onScroll(e) { + // 检测用户是否在手动滚动 + const scrollTop = e.detail.scrollTop; + + // 获取滚动容器和底部元素的位置 + const query = wx.createSelectorQuery(); + query.select('#scrollBottom').boundingClientRect(); + query.select('#chatScroll').boundingClientRect(); + query.exec((res) => { + if (res[0] && res[1]) { + const bottomPosition = res[0].top - res[1].top + res[1].height; + // 如果滚动位置不在底部(偏差超过50px),认为是用户手动滚动 + if (Math.abs(scrollTop - bottomPosition) > 100) { + if (!this.data.isUserScrolling) { + this.setData({ + isUserScrolling: true + }); + } + + // 清除之前的定时器 + if (this.data.scrollTimer) { + clearTimeout(this.data.scrollTimer); + } + + // 5秒后重置用户滚动状态 + const timer = setTimeout(() => { + this.setData({ + isUserScrolling: false + }); + // 重置后检查是否需要滚动到底部 + this.checkAndScrollToBottom(); + }, 5000); + this.setData({ scrollTimer: timer }); + } + } + }); + }, + + // 滚动到底部事件 + onScrollToLower() { + // 用户滚动到底部时,重置滚动状态 + this.setData({ + isUserScrolling: false + }); + }, + + // 键盘高度变化监听 + onKeyboardHeightChange(res) { + if (res.height > 0) { + // 键盘弹起 + this.setData({ + isKeyboardShow: true + }); + // 强制滚动到底部 + this.scrollToBottom(true); + } else { + // 键盘收起 + this.setData({ + isKeyboardShow: false + }); + } + }, + + // 检查并滚动到底部 + checkAndScrollToBottom() { + // 如果用户没有手动滚动,则滚动到底部 + if (!this.data.isUserScrolling) { + this.scrollToBottom(true); + } }, // AI问诊快捷字列表 @@ -30,19 +122,22 @@ Page({ http.inquiry({ data: {}, success: res => { - console.log(1111, res); + console.log('快捷症状列表', res); this.setData({ quickSymptoms: res.rows - }) + }); } - }) + }); }, onShow() { this.updateCurrentTime(); - this.setData({ - autoFocus: true - }); + // 延迟设置焦点,避免影响滚动 + setTimeout(() => { + this.setData({ + autoFocus: true + }); + }, 300); }, // 初始化数据 @@ -54,6 +149,11 @@ Page({ setInterval(() => { this.updateCurrentTime(); }, 60000); + + // 初始化消息数量 + this.setData({ + lastMessageCount: this.data.messages.length + }); }, // 更新当前时间 @@ -65,6 +165,86 @@ Page({ }); }, + // 滚动到底部 + scrollToBottom(force = false) { + // 如果用户正在手动滚动且不是强制滚动,则不滚动 + if (this.data.isUserScrolling && !force) { + console.log('用户正在手动滚动,跳过自动滚动'); + return; + } + + // 获取最新消息的ID + let targetId = 'scrollBottom'; + + // 优先滚动到最新的消息 + if (this.data.messages.length > 0) { + targetId = `msg-${this.data.messages.length - 1}`; + } else { + targetId = 'welcome-message'; + } + + console.log('滚动到:', targetId); + + // 先重置scrollIntoView,确保能触发滚动 + this.setData({ + scrollIntoView: '', + scrollAnimation: true + }, () => { + // 延迟一下再设置滚动目标,确保视图更新 + setTimeout(() => { + this.setData({ + scrollIntoView: targetId, + scrollAnimation: true + }); + }, 50); + }); + + // 多重保障滚动 + setTimeout(() => { + if (!this.data.isUserScrolling || force) { + this.setData({ + scrollIntoView: targetId + }); + } + }, 150); + + setTimeout(() => { + if (!this.data.isUserScrolling || force) { + this.setData({ + scrollIntoView: targetId + }); + } + }, 300); + }, + + // 输入框行数变化 + onInputLineChange(e) { + // 输入框高度变化时,确保滚动到底部 + if (this.data.isKeyboardShow) { + this.scrollToBottom(); + } + }, + + // 输入框聚焦 + onInputFocus(e) { + this.setData({ + autoFocus: true, + isKeyboardShow: true + }); + // 延迟滚动到底部,等待键盘完全弹起 + setTimeout(() => { + this.scrollToBottom(true); + }, 300); + }, + + // 输入框失焦 + onInputBlur(e) { + this.setData({ + autoFocus: false, + isKeyboardShow: false + }); + }, + // 输入框变化 onInput(e) { this.setData({ @@ -85,20 +265,32 @@ Page({ time: this.getCurrentTime() }; + // 更新消息列表 + const newMessages = [...this.data.messages, userMessage]; + this.setData({ - messages: [...this.data.messages, userMessage], inputValue: '', - autoFocus: true + autoFocus: true, + inputHeight: 60, + messages: newMessages, + isUserScrolling: false, // 发送消息时重置用户滚动状态 + lastMessageCount: newMessages.length }); - console.log(666, this.data.messages) + // 立即滚动到底部 + this.scrollToBottom(true); - // 先显示AI思考状态 + // 显示AI思考状态 this.setData({ isAIThinking: true }); - // 模拟AI思考时间(1.5-2.5秒) + // 滚动到底部(显示思考状态后) + setTimeout(() => { + this.scrollToBottom(true); + }, 100); + + // 模拟AI思考时间 setTimeout(() => { this.generateAIResponse(message); }, 1500 + Math.random() * 1000); @@ -112,14 +304,14 @@ Page({ // 生成AI响应 generateAIResponse(userMessage) { - console.log(888, userMessage); + console.log('发送消息:', userMessage); http.search({ data: { keyword: userMessage }, success: res => { - console.log('查询结果', res); + console.log('AI响应:', res); let aiMessage; if (res.rows && res.rows.length > 0) { @@ -128,12 +320,11 @@ Page({ aiMessage = { id: Date.now() + 1, type: 'assistant', - content:'根据您的描述,' + wzsearch.title || '已收到您的症状描述', + content: '根据您的描述,' + (wzsearch.title || '已收到您的症状描述'), diagnosis: wzsearch, time: this.getCurrentTime() }; } else { - // 如果没有查询到结果 aiMessage = { id: Date.now() + 1, type: 'assistant', @@ -147,38 +338,60 @@ Page({ }; } - // 添加AI消息到聊天记录并隐藏思考状态 + // 添加AI消息 + const newMessages = [...this.data.messages, aiMessage]; + this.setData({ - messages: [...this.data.messages, aiMessage], - isAIThinking: false + messages: newMessages, + isAIThinking: false, + isUserScrolling: false, // 收到新消息时强制重置用户滚动状态 + lastMessageCount: newMessages.length + }, () => { + // 消息添加后立即滚动到底部 + console.log('AI消息已添加,滚动到底部'); + this.scrollToBottom(true); + + // 多重保险滚动 + setTimeout(() => { + this.scrollToBottom(true); + }, 100); + + setTimeout(() => { + this.scrollToBottom(true); + }, 300); + + setTimeout(() => { + this.scrollToBottom(true); + }, 500); }); - - console.log(789, this.data.messages); }, fail: err => { console.error('API请求失败:', err); - // API失败时的默认响应 const aiMessage = { id: Date.now() + 1, type: 'assistant', content: '已收到您的症状描述', diagnosis: { - disease: '网络请求失败', - severity: 'unknown', - severityText: '未知', - suggestion: '请检查网络连接后重试,或直接联系兽医' + possibleDiseases: '网络请求失败', + severityLevel: '未知', + suggestions: '请检查网络连接后重试,或直接联系兽医' }, time: this.getCurrentTime() }; + const newMessages = [...this.data.messages, aiMessage]; + this.setData({ - messages: [...this.data.messages, aiMessage], - isAIThinking: false + messages: newMessages, + isAIThinking: false, + isUserScrolling: false, + lastMessageCount: newMessages.length + }, () => { + this.scrollToBottom(true); }); }, complete: () => { - // 确保无论如何都会隐藏思考状态 if (this.data.isAIThinking) { this.setData({ isAIThinking: false @@ -188,8 +401,6 @@ Page({ }); }, - - // 选择快捷症状 selectQuickSymptom(e) { const symptom = e.currentTarget.dataset.symptom.keywords; @@ -229,13 +440,15 @@ Page({ success: (res) => { if (res.confirm) { this.setData({ - messages: [{ - id: 1, - type: 'assistant', - content: '您好!我是AI健康助手,有什么可以帮您?\n\n请描述您或牲畜的健康状况,我会为您提供专业的分析和建议。', - time: this.getCurrentTime() - }], - selectedSymptoms: [] + messages: [], + selectedSymptoms: [], + isUserScrolling: false, + lastMessageCount: 0 + }, () => { + // 清空后滚动到欢迎消息 + this.setData({ + scrollIntoView: 'welcome-message' + }); }); this.closeMoreMenu(); } @@ -272,7 +485,7 @@ Page({ showInstructions() { wx.showModal({ title: '使用说明', - content: '1. 描述您或牲畜的症状2. AI助手会分析并提供建议3. 可使用快捷症状选择4. 诊断结果仅供参考,请及时咨询专业兽医', + content: '1. 描述您或牲畜的症状\n2. AI助手会分析并提供建议\n3. 可使用快捷症状选择\n4. 诊断结果仅供参考,请及时咨询专业兽医', showCancel: false }); this.closeMoreMenu(); diff --git a/pagesA/pages/wzai/wzai.wxml b/pagesA/pages/wzai/wzai.wxml index f556d68..dca2a5e 100644 --- a/pagesA/pages/wzai/wzai.wxml +++ b/pagesA/pages/wzai/wzai.wxml @@ -2,9 +2,6 @@ - - ··· - @@ -12,7 +9,7 @@ AI健康助手 智能诊断专家 - 24小时在线 + 24小时在线 专业诊断 快速响应 @@ -22,13 +19,19 @@ - + @@ -41,7 +44,7 @@ - + @@ -70,17 +73,17 @@ 可能病症: - {{item.diagnosis.possibleDiseases}} + {{item.diagnosis.possibleDiseases || item.diagnosis.title}} 严重程度: - {{item.diagnosis.severityLevel}} + {{item.diagnosis.severityLevel || '中等'}} 建议措施: - {{item.diagnosis.suggestions}} + {{item.diagnosis.suggestions || '请咨询专业兽医'}} * 本结果仅供参考,请及时咨询专业兽医 @@ -93,7 +96,10 @@ - + + + + @@ -105,6 +111,9 @@ + + + @@ -118,17 +127,25 @@ - - - + +