You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1366 lines
36 KiB
1366 lines
36 KiB
// import http from '../../../utils/api'
|
|
Page({
|
|
data: {
|
|
// 专家信息
|
|
expertInfo: {
|
|
id: 0,
|
|
name: '',
|
|
title: '',
|
|
expertise: '',
|
|
avatar: '/images/avatars/expert1.png',
|
|
online: false,
|
|
phone: ''
|
|
},
|
|
|
|
// 用户信息
|
|
userInfo: {
|
|
id: 0,
|
|
name: '用户',
|
|
avatar: '/images/avatars/user.png'
|
|
},
|
|
|
|
// 消息列表
|
|
messageList: [],
|
|
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: '',
|
|
loading: false,
|
|
loadingMore: false,
|
|
|
|
// 滚动相关
|
|
isScrolling: false,
|
|
lastScrollTop: 0,
|
|
|
|
// 录音相关
|
|
recordStartY: 0,
|
|
|
|
// 当前专家ID
|
|
currentExpertId: 0,
|
|
|
|
// 分页相关
|
|
page: 1,
|
|
pageSize: 20,
|
|
hasMore: true,
|
|
|
|
// 时间显示间隔(分钟) - 微信默认为5分钟
|
|
timeInterval: 5,
|
|
|
|
// 用于存储最后一条显示时间的消息的时间戳
|
|
lastShowTimeStamp: 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();
|
|
});
|
|
}
|
|
|
|
// 设置键盘监听
|
|
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({
|
|
inputValue: e.detail.value
|
|
});
|
|
},
|
|
|
|
// 输入框获得焦点
|
|
onInputFocus: function() {
|
|
this.setData({
|
|
inputFocus: true
|
|
});
|
|
},
|
|
|
|
// 输入框失去焦点
|
|
onInputBlur: function() {
|
|
this.setData({
|
|
inputFocus: false
|
|
});
|
|
},
|
|
|
|
// 清除输入
|
|
clearInput: function() {
|
|
this.setData({
|
|
inputValue: '',
|
|
inputFocus: true
|
|
});
|
|
},
|
|
|
|
// 发送文本消息 - 使用您的接口调用方式
|
|
sendTextMessage: function() {
|
|
const content = this.data.inputValue.trim();
|
|
if (!content) return;
|
|
|
|
console.log('发送文本消息:', content);
|
|
|
|
const newMessage = {
|
|
id: 'msg-' + Date.now(),
|
|
sender: 'user',
|
|
type: 'text',
|
|
content: content,
|
|
timestamp: Date.now(),
|
|
status: 'sending'
|
|
};
|
|
|
|
// 处理时间显示并添加到消息列表
|
|
this.addMessageToList(newMessage);
|
|
|
|
// 清空输入框
|
|
this.setData({
|
|
inputValue: '',
|
|
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);
|
|
}, 500);
|
|
},
|
|
|
|
// 添加消息到列表
|
|
addMessageToList: function(message) {
|
|
const { messageList } = this.data;
|
|
|
|
// 处理消息时间显示
|
|
const processedMessage = this.processSingleMessageTime(message, messageList);
|
|
|
|
// 添加到列表
|
|
messageList.push(processedMessage);
|
|
|
|
this.setData({
|
|
messageList
|
|
}, () => {
|
|
// 消息添加后滚动到底部
|
|
this.scrollToBottom();
|
|
});
|
|
},
|
|
|
|
// 更新消息状态
|
|
updateMessageStatus: function(messageId, status) {
|
|
const { messageList } = this.data;
|
|
const index = messageList.findIndex(msg => msg.id === messageId);
|
|
|
|
if (index !== -1) {
|
|
messageList[index].status = status;
|
|
this.setData({ messageList });
|
|
}
|
|
},
|
|
|
|
// 接收专家回复 - 使用您的接口调用方式
|
|
receiveExpertReply: function() {
|
|
// 这里可以使用WebSocket或轮询获取新消息
|
|
// 模拟专家回复
|
|
const replies = [
|
|
'收到您的消息,让我分析一下您说的情况。',
|
|
'建议您提供更多细节,比如发病时间、具体症状等。',
|
|
'根据描述,可能是饲料问题引起的,建议调整饲料配方。',
|
|
'可以考虑添加一些维生素补充剂,改善食欲问题。',
|
|
'最好能提供照片,这样我可以更准确地判断情况。'
|
|
];
|
|
|
|
const randomReply = replies[Math.floor(Math.random() * replies.length)];
|
|
|
|
const newMessage = {
|
|
id: 'exp-' + Date.now(),
|
|
sender: 'expert',
|
|
type: 'text',
|
|
content: randomReply,
|
|
timestamp: Date.now(),
|
|
status: 'success'
|
|
};
|
|
|
|
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({
|
|
lastScrollTop: scrollTop,
|
|
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) {
|
|
this.loadMoreMessages();
|
|
}
|
|
},
|
|
|
|
// 加载更多消息
|
|
loadMoreMessages: function() {
|
|
if (this.data.loadingMore || !this.data.hasMore) return;
|
|
|
|
this.setData({
|
|
loadingMore: true
|
|
});
|
|
|
|
// 加载更多聊天记录
|
|
setTimeout(() => {
|
|
this.setData({
|
|
page: this.data.page + 1
|
|
}, () => {
|
|
this.loadChatHistory();
|
|
});
|
|
}, 500);
|
|
},
|
|
|
|
// 滚动到底部
|
|
scrollToBottom: function(animate = true) {
|
|
if (this.data.isScrolling) return;
|
|
|
|
this.setData({
|
|
scrollAnimate: animate
|
|
}, () => {
|
|
// 设置一个足够大的值确保滚动到底部
|
|
setTimeout(() => {
|
|
this.setData({
|
|
scrollTop: 999999
|
|
});
|
|
}, 100);
|
|
});
|
|
},
|
|
|
|
// 显示多媒体选择面板
|
|
showMediaActionSheet: function() {
|
|
this.setData({
|
|
showMediaSheet: true,
|
|
inputFocus: false
|
|
});
|
|
},
|
|
|
|
// 隐藏多媒体选择面板
|
|
hideMediaActionSheet: function() {
|
|
this.setData({
|
|
showMediaSheet: false
|
|
});
|
|
},
|
|
|
|
// 键盘高度变化
|
|
onKeyboardHeightChange: function(res) {
|
|
console.log('键盘高度变化:', res.height);
|
|
if (res.height > 0) {
|
|
// 键盘弹出时隐藏多媒体面板
|
|
this.setData({ showMediaSheet: false });
|
|
|
|
// 键盘弹出后滚动到底部
|
|
setTimeout(() => {
|
|
this.scrollToBottom();
|
|
}, 300);
|
|
}
|
|
},
|
|
|
|
// 选择图片
|
|
chooseImage: function() {
|
|
this.hideMediaActionSheet();
|
|
|
|
wx.chooseImage({
|
|
count: 9,
|
|
sizeType: ['compressed'],
|
|
sourceType: ['album'],
|
|
success: (res) => {
|
|
console.log('选择图片成功:', res.tempFilePaths);
|
|
this.uploadImages(res.tempFilePaths);
|
|
},
|
|
fail: (err) => {
|
|
console.error('选择图片失败:', err);
|
|
wx.showToast({
|
|
title: '选择图片失败',
|
|
icon: 'none'
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
|
|
|
|
// 选择视频
|
|
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'
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
|
|
// 选择文件
|
|
chooseFile: function() {
|
|
this.hideMediaActionSheet();
|
|
|
|
wx.chooseMessageFile({
|
|
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'
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// 上传图片
|
|
uploadImages: function(tempFilePaths) {
|
|
tempFilePaths.forEach((tempFilePath, index) => {
|
|
const fileName = `image_${Date.now()}_${index}.jpg`;
|
|
this.uploadFile(tempFilePath, fileName, 0, 'image');
|
|
});
|
|
},
|
|
|
|
// 上传视频
|
|
uploadVideo: function(tempFilePath, thumbPath) {
|
|
const fileName = `video_${Date.now()}.mp4`;
|
|
this.uploadFile(tempFilePath, fileName, 0, 'video', thumbPath);
|
|
},
|
|
|
|
// 通用文件上传
|
|
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,
|
|
sender: 'user',
|
|
type: type,
|
|
content: tempFilePath,
|
|
thumb: thumbPath,
|
|
fileName: fileName,
|
|
fileSize: fileSize,
|
|
extension: extension,
|
|
timestamp: Date.now(),
|
|
status: 'uploading',
|
|
progress: 0
|
|
};
|
|
|
|
this.addMessageToList(message);
|
|
|
|
// 模拟上传过程
|
|
this.simulateUpload(messageId, type);
|
|
},
|
|
|
|
// 模拟上传过程
|
|
simulateUpload: function(messageId, type) {
|
|
let progress = 0;
|
|
const uploadInterval = setInterval(() => {
|
|
progress += Math.random() * 20 + 10;
|
|
|
|
if (progress >= 100) {
|
|
progress = 100;
|
|
clearInterval(uploadInterval);
|
|
|
|
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);
|
|
}, 800);
|
|
}
|
|
}
|
|
}, 200);
|
|
}
|
|
|
|
// 更新进度
|
|
const { messageList } = this.data;
|
|
const index = messageList.findIndex(msg => msg.id === messageId);
|
|
if (index !== -1) {
|
|
messageList[index].progress = Math.min(progress, 100);
|
|
this.setData({ messageList });
|
|
}
|
|
}, 100);
|
|
},
|
|
|
|
// 接收媒体回复
|
|
receiveMediaReply: function(type) {
|
|
const imageReplies = [
|
|
'照片收到了,牛的状况看起来确实不太理想。',
|
|
'从照片看,饲养环境需要改善一下。',
|
|
'图片清晰,我可以更准确地判断问题了。'
|
|
];
|
|
|
|
const videoReplies = [
|
|
'视频看到了,动物的精神状态需要关注。',
|
|
'从视频可以观察到更多细节,这很有帮助。',
|
|
'视频内容很有价值,让我了解了具体情况。'
|
|
];
|
|
|
|
const replies = type === 'image' ? imageReplies : videoReplies;
|
|
const randomReply = replies[Math.floor(Math.random() * replies.length)];
|
|
|
|
const newMessage = {
|
|
id: 'exp-media-' + Date.now(),
|
|
sender: 'expert',
|
|
type: 'text',
|
|
content: randomReply,
|
|
timestamp: Date.now(),
|
|
status: 'success'
|
|
};
|
|
|
|
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'
|
|
});
|
|
},
|
|
|
|
// 语音录制触摸移动
|
|
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 ? '松开取消' : '按住 说话'
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
// 结束语音录制
|
|
endVoiceRecord: function() {
|
|
if (this.data.isRecording) {
|
|
this.recordManager.stop();
|
|
}
|
|
},
|
|
|
|
// 取消语音录制
|
|
cancelVoiceRecord: function() {
|
|
if (this.data.isRecording) {
|
|
this.setData({
|
|
isCanceling: true
|
|
});
|
|
this.recordManager.stop();
|
|
}
|
|
},
|
|
|
|
// 发送语音消息
|
|
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);
|
|
|
|
// 模拟发送成功
|
|
setTimeout(() => {
|
|
this.updateMessageStatus(message.id, 'success');
|
|
|
|
// 模拟专家回复
|
|
setTimeout(() => {
|
|
const reply = {
|
|
id: 'exp-audio-' + Date.now(),
|
|
sender: 'expert',
|
|
type: 'text',
|
|
content: '语音收到了,我会仔细听取分析。',
|
|
timestamp: Date.now(),
|
|
status: 'success'
|
|
};
|
|
this.addMessageToList(reply);
|
|
}, 1500);
|
|
}, 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: '下载中...' });
|
|
|
|
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'
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// 修复:时间格式化函数 - 确保正确显示
|
|
formatTime: function(timestamp) {
|
|
// 调试日志
|
|
console.log('formatTime 接收到的timestamp:', timestamp, '类型:', typeof timestamp);
|
|
|
|
if (!timestamp || timestamp <= 0) {
|
|
console.warn('无效的时间戳:', timestamp);
|
|
return '未知时间';
|
|
}
|
|
|
|
const timeNum = Number(timestamp);
|
|
if (isNaN(timeNum)) {
|
|
console.warn('时间戳不是有效数字:', timestamp);
|
|
return '未知时间';
|
|
}
|
|
|
|
const date = new Date(timeNum);
|
|
if (isNaN(date.getTime())) {
|
|
console.warn('无法创建有效日期对象:', timeNum);
|
|
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;
|
|
},
|
|
|
|
// 格式化文件大小
|
|
formatFileSize: function(bytes) {
|
|
if (bytes === 0 || !bytes) return '未知大小';
|
|
|
|
const units = ['B', 'KB', 'MB', 'GB'];
|
|
let size = bytes;
|
|
let unitIndex = 0;
|
|
|
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
size /= 1024;
|
|
unitIndex++;
|
|
}
|
|
|
|
return size.toFixed(1) + units[unitIndex];
|
|
},
|
|
|
|
// 阻止事件冒泡
|
|
stopPropagation: function() {
|
|
// 空函数,仅用于阻止事件冒泡
|
|
}
|
|
});
|