Browse Source

专家列表,状态调整

master
ZhaoYang 1 month ago
parent
commit
52422357e5
  1. 15
      pagesA/pages/expert/expert.js
  2. 24
      pagesA/pages/expert/expert.wxml
  3. 110
      pagesA/pages/expertChat/expertChat.js
  4. 46
      pagesA/pages/expertChat/expertChat.wxml
  5. 77
      pagesA/pages/expertChat/expertChat.wxss
  6. 2
      utils/api.js

15
pagesA/pages/expert/expert.js

@ -1,5 +1,5 @@
import http from '../../../utils/api'
const baseUr = require('../../../utils/baseUrl')
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
// 搜索关键词
@ -10,7 +10,7 @@ Page({
// 所有专家数据
allExperts: [],
baseUr: baseUr,
baseUrl: baseUrl,
formzj: {
isOnline: null,
@ -181,11 +181,9 @@ Page({
wx.showModal({
title: '咨询确认',
content: expert.isOnline=='在线' ?
`确定要立即咨询 ${expert.realName} 专家吗?` : `确定要预约咨询 ${expert.realName} 专家吗?`,
content: `确定要立即咨询 ${expert.realName} 专家吗?`,
success: (res) => {
if (res.confirm) {
if (expert.isOnline=='在线') {
wx.showToast({
title: '正在为您连接',
icon: 'loading',
@ -198,13 +196,6 @@ Page({
})
this.hideContactDialog();
}, 2000);
} else {
wx.showToast({
title: '预约成功,专家将尽快回复',
icon: 'success'
});
this.hideContactDialog();
}
}
}
});

24
pagesA/pages/expert/expert.wxml

@ -91,10 +91,10 @@
<!-- 专家头像和在线状态 -->
<view class="card-left">
<view class="avatar-container">
<image src="{{baseUr+item.avatar}}" class="expert-avatar" mode="aspectFill"></image>
<view class="online-badge {{item.isOnline=='在线' ? 'online' : 'offline'}}">
<image src="{{baseUrl+item.avatar}}" class="expert-avatar" mode="aspectFill"></image>
<!-- <view class="online-badge {{item.isOnline=='在线' ? 'online' : 'offline'}}">
{{item.isOnline}}
</view>
</view> -->
</view>
</view>
@ -102,14 +102,14 @@
<view class="card-middle">
<view class="name-title-row">
<text class="expert-name">{{item.realName}}</text>
<text class="expert-title">{{item.expert}}</text>
<text class="expert-title">{{item.expertType}}</text>
</view>
<!-- 专门的信息展示区域 -->
<view class="info-display">
<view class="info-item">
<text class="info-label">擅长领域:</text>
<text class="info-value">{{item.expertiseArea}}</text>
<text class="info-value">{{item.specialty}}</text>
</view>
<view class="info-item">
@ -120,8 +120,8 @@
</view>
<!-- 点击按钮 -->
<view class="contact-btn {{item.isOnline=='在线' ? 'online-btn' : 'offline-btn'}}" bindtap="showContactInfo" data-index="{{index}}">
{{item.isOnline=='在线' ? '立即咨询' : '查看联系'}}
<view class="contact-btn online-btn" bindtap="showContactInfo" data-index="{{index}}">
立即咨询
</view>
</view>
</block>
@ -137,7 +137,7 @@
<!-- 模态框头部 -->
<view class="modal-header">
<view class="header-left">
<image src="/pages/images/tx.png" class="modal-avatar"></image>
<image src="{{currentExpert.avatar?baseUrl+currentExpert.avatar:'/pages/images/tx.png'}}" class="modal-avatar"></image>
<view class="expert-intro">
<view class="modallei">
<view class="modal-name">{{currentExpert.realName}}</view>
@ -158,7 +158,7 @@
<view class="bio-header">
<text class="bio-title">专家简介</text>
</view>
<text class="bio-content">{{currentExpert.bio || '资深牲畜养殖专家,拥有丰富的实践经验和理论知识,擅长解决各类养殖难题'}}</text>
<text class="bio-content">{{currentExpert.introduction || '资深牲畜养殖专家,拥有丰富的实践经验和理论知识,擅长解决各类养殖难题'}}</text>
</view>
<!-- 联系方式 -->
@ -170,7 +170,7 @@
</view>
<view class="contact-info">
<text class="contact-label">联系电话</text>
<text class="contact-value">{{currentExpert.iphone}}</text>
<text class="contact-value">{{currentExpert.phone}}</text>
<text class="contact-desc">可直接拨打电话咨询</text>
</view>
<button class="action-btn call-btn" bindtap="makePhoneCall" data-phone="{{currentExpert.iphone}}">
@ -200,7 +200,7 @@
</view>
<view class="contact-info">
<text class="contact-label">工作单位</text>
<text class="contact-value">{{currentExpert.institution}}</text>
<text class="contact-value">{{currentExpert.hospital}}</text>
<text class="contact-desc">专业机构认证专家</text>
</view>
<button class="action-btn address-btn" bindtap="viewLocation" data-address="{{currentExpert.address}}">
@ -226,7 +226,7 @@
<view class="modal-actions">
<button class="secondary-btn" bindtap="hideContactDialog">稍后联系</button>
<button class="primary-btn" bindtap="startConsultation">
{{currentExpert.isOnline=='在线' ? '立即咨询' : '预约咨询'}}
立即咨询
</button>
</view>
</view>

110
pagesA/pages/expertChat/expertChat.js

@ -79,7 +79,12 @@ Page({
messageIds: new Set(),
// 正在发送中的消息ID集合
sendingMessages: new Set()
sendingMessages: new Set(),
// 显示发送中提示
showSendingTip: false,
// 发送中的消息数量
sendingCount: 0
},
onLoad: function(options) {
@ -103,7 +108,9 @@ Page({
earliestMsgTime: 0,
firstLoadComplete: false,
messageIds: new Set(),
sendingMessages: new Set()
sendingMessages: new Set(),
showSendingTip: false,
sendingCount: 0
});
// 先创建对话,然后获取聊天记录
@ -401,9 +408,8 @@ Page({
console.log('格式化消息使用的用户ID:', userId);
return messages.map(msg => {
// 判断消息类型
let contentType = msg.contentType || 'text';
let type = msg.type || 'text';
// 统一使用contentType字段
let contentType = msg.contentType || msg.type || 'text';
let content = msg.content || '';
// 判断发送者
@ -418,11 +424,13 @@ Page({
sender: isMe ? 'user' : 'expert',
senderId: msg.senderId || msg.fromUserId || msg.userId,
contentType: contentType,
type: type,
content: content,
timestamp: msg.createTime || msg.timestamp || Date.now(),
status: msg.status || 'success',
...msg
fileName: msg.fileName || '',
fileSize: msg.fileSize || 0,
thumb: msg.thumb || '',
progress: msg.progress || 100
};
});
},
@ -740,7 +748,11 @@ Page({
// 从发送中集合移除
const sendingMessages = new Set(this.data.sendingMessages);
sendingMessages.delete(messageId);
this.setData({ sendingMessages: sendingMessages });
this.setData({
sendingMessages: sendingMessages,
sendingCount: sendingMessages.size,
showSendingTip: sendingMessages.size > 0
});
// 更新本地消息状态为成功
this.updateMessageStatus(messageId, 'success');
@ -773,18 +785,20 @@ Page({
return;
}
// 创建新消息对象
// 创建新消息对象 - 统一使用contentType
const newMessage = {
id: messageId,
isMe: isMe,
sender: isMe ? 'user' : 'expert',
senderId: senderId,
contentType: messageData.contentType || messageData.type || 'text',
type: messageData.type || messageData.contentType || 'text',
content: messageData.content || '',
timestamp: messageData.timestamp || Date.now(),
status: 'success',
progress: 100
status: 'success', // 对方消息直接显示成功
progress: 100,
fileName: messageData.fileName || '',
fileSize: messageData.fileSize || 0,
thumb: messageData.thumb || ''
};
console.log('创建的新消息对象:', newMessage);
@ -838,10 +852,8 @@ Page({
}
});
// 如果不是自己发的消息,震动提示
// 如果不是自己发的消息,发送已读回执
if (!isMe) {
// wx.vibrateShort({ type: 'light' });
// 发送已读回执
this.sendReadReceipt(messageId);
}
});
@ -859,10 +871,14 @@ Page({
}
// 如果收到成功状态,从发送中集合移除
if (data.status === 'success') {
if (data.status === 'success' || data.status === 'read') {
const sendingMessages = new Set(this.data.sendingMessages);
sendingMessages.delete(messageId);
this.setData({ sendingMessages: sendingMessages });
this.setData({
sendingMessages: sendingMessages,
sendingCount: sendingMessages.size,
showSendingTip: sendingMessages.size > 0
});
}
},
@ -890,7 +906,7 @@ Page({
},
// 发送消息到服务器
sendMessageToServer: function(content, type, messageId) {
sendMessageToServer: function(content, contentType, messageId) {
const receiverId = this.data.otherUserId;
const senderId = this.getCurrentUserId();
@ -898,7 +914,7 @@ Page({
senderId: senderId,
receiverId: receiverId,
content: content,
type: type,
contentType: contentType,
messageId: messageId
});
@ -912,7 +928,11 @@ Page({
// 发送失败,从发送中集合移除
const sendingMessages = new Set(this.data.sendingMessages);
sendingMessages.delete(messageId);
this.setData({ sendingMessages: sendingMessages });
this.setData({
sendingMessages: sendingMessages,
sendingCount: sendingMessages.size,
showSendingTip: sendingMessages.size > 0
});
// 更新消息状态为失败
this.updateMessageStatus(messageId, 'failed');
@ -924,7 +944,7 @@ Page({
receiverId: receiverId,
senderId: senderId,
content: content,
contentType: type || 'text',
contentType: contentType,
timestamp: Date.now(),
messageId: messageId
};
@ -990,24 +1010,28 @@ Page({
const sendingMessages = new Set(this.data.sendingMessages);
sendingMessages.add(messageId);
// 创建本地消息
// 创建本地消息 - 使用contentType
const newMessage = {
id: messageId,
isMe: true,
sender: 'user',
senderId: this.getCurrentUserId(),
contentType: 'text',
type: 'text',
content: content,
timestamp: Date.now(),
status: 'sending'
status: 'sending', // 设置为发送中状态
progress: 100
};
// 添加到列表
this.addMessageToList(newMessage);
// 更新发送中集合
this.setData({ sendingMessages: sendingMessages });
// 更新发送中集合和发送计数
this.setData({
sendingMessages: sendingMessages,
sendingCount: sendingMessages.size,
showSendingTip: sendingMessages.size > 0
});
// 清空输入框
this.setData({ inputValue: '' });
@ -1024,7 +1048,11 @@ Page({
// 从发送中集合移除
const sendingMessages = new Set(this.data.sendingMessages);
sendingMessages.delete(messageId);
this.setData({ sendingMessages: sendingMessages });
this.setData({
sendingMessages: sendingMessages,
sendingCount: sendingMessages.size,
showSendingTip: sendingMessages.size > 0
});
wx.showToast({
title: '发送超时',
@ -1049,7 +1077,7 @@ Page({
},
// 通用文件上传
uploadFile: function(tempFilePath, fileName, fileSize = 0, type = 'file', thumbPath = '') {
uploadFile: function(tempFilePath, fileName, fileSize = 0, contentType = 'file', thumbPath = '') {
const messageId = 'file_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
// 将消息ID添加到发送中集合
@ -1060,8 +1088,7 @@ Page({
id: messageId,
isMe: true,
sender: 'user',
type: type,
contentType: type,
contentType: contentType,
content: tempFilePath,
thumb: thumbPath,
fileName: fileName,
@ -1073,12 +1100,16 @@ Page({
};
this.addMessageToList(message);
this.setData({ sendingMessages: sendingMessages });
this.simulateUpload(messageId, type, tempFilePath);
this.setData({
sendingMessages: sendingMessages,
sendingCount: sendingMessages.size,
showSendingTip: sendingMessages.size > 0
});
this.simulateUpload(messageId, contentType, tempFilePath);
},
// 模拟上传
simulateUpload: function(messageId, type, tempFilePath) {
simulateUpload: function(messageId, contentType, tempFilePath) {
let progress = 0;
const uploadInterval = setInterval(() => {
progress += Math.random() * 20 + 10;
@ -1097,7 +1128,7 @@ Page({
this.setData({ messageList });
const fileUrl = tempFilePath;
this.sendMessageToServer(fileUrl, type, messageId);
this.sendMessageToServer(fileUrl, contentType, messageId);
}
}, 200);
}
@ -1146,6 +1177,17 @@ Page({
if (index !== -1) {
messageList[index].status = status;
this.setData({ messageList });
// 如果是失败状态,从发送中集合移除
if (status === 'failed' || status === 'timeout') {
const sendingMessages = new Set(this.data.sendingMessages);
sendingMessages.delete(messageId);
this.setData({
sendingMessages: sendingMessages,
sendingCount: sendingMessages.size,
showSendingTip: sendingMessages.size > 0
});
}
}
},

46
pagesA/pages/expertChat/expertChat.wxml

@ -30,6 +30,16 @@
<text class="date-text">{{todayDate}}</text>
</view>
<!-- 发送中提示 -->
<view class="sending-tip-container" wx:if="{{sendingCount > 0}}">
<view class="sending-tip">
<view class="sending-dot"></view>
<view class="sending-dot"></view>
<view class="sending-dot"></view>
<text class="sending-text">正在发送{{sendingCount}}条消息...</text>
</view>
</view>
<!-- 消息列表 -->
<block wx:for="{{messageList}}" wx:key="index">
<!-- 对方消息 -->
@ -38,14 +48,16 @@
<image src="{{conversation.otherUserAvatar?baseUrl+conversation.otherUserAvatar:' /pages/images/tx.png'}}" class="avatar-img"></image>
</view>
<view class="messages-content-wrapper">
<view class="message-content-wrapper">
<view class="message-arrow arrow-left"></view>
<!-- 文本消息 -->
<view class="message-bubble bubble-left" wx:if="{{item.contentType === 'text'}}">
<text class="message-text">{{item.content}}</text>
</view>
<view class="media-bubble" wx:elif="{{item.type === 'image'}}">
<!-- 图片消息 -->
<view class="media-bubble" wx:elif="{{item.contentType === 'image'}}">
<image
src="{{item.content}}"
class="message-image"
@ -55,20 +67,20 @@
></image>
</view>
<view class="media-bubble" wx:elif="{{item.type === 'video'}}">
<!-- 视频消息 -->
<view class="media-bubble" wx:elif="{{item.contentType === 'video'}}">
<video
src="{{item.content}}"
class="message-video"
controls
show-center-play-btn
poster="{{item.thumb}}"
object-fit="contain"
></video>
<view class="video-play-overlay">
<image src="/images/icons/play.png" class="play-icon"></image>
</view>
</view>
<view class="message-bubble bubble-left message-file" wx:elif="{{item.type === 'file'}}">
<!-- 文件消息 -->
<view class="message-bubble bubble-left message-file" wx:elif="{{item.contentType === 'file'}}">
<view class="file-icon-box">
<image src="/images/icons/file_icon.png" class="file-icon"></image>
</view>
@ -77,6 +89,11 @@
<text class="file-size">{{formatFileSize(item.fileSize)}}</text>
</view>
</view>
<!-- 消息状态 - 仅对方消息显示已读状态 -->
<view class="message-status" wx:if="{{item.status === 'read'}}">
<text class="status-text">已读</text>
</view>
</view>
</view>
@ -85,11 +102,13 @@
<view class="message-content-wrapper">
<view class="message-arrow arrow-right"></view>
<!-- 文本消息 -->
<view class="message-bubble bubble-right" wx:if="{{item.contentType === 'text'}}">
<text class="message-text">{{item.content}}</text>
</view>
<view class="media-bubble" wx:elif="{{item.type === 'image'}}">
<!-- 图片消息 -->
<view class="media-bubble" wx:elif="{{item.contentType === 'image'}}">
<image
src="{{item.content}}"
class="message-image"
@ -97,6 +116,7 @@
bindtap="previewImage"
data-url="{{item.content}}"
></image>
<!-- 上传进度 -->
<view class="upload-progress" wx:if="{{item.status === 'uploading'}}">
<view class="progress-circle">
<text class="progress-text">{{item.progress}}%</text>
@ -104,17 +124,16 @@
</view>
</view>
<view class="media-bubble" wx:elif="{{item.type === 'video'}}">
<!-- 视频消息 -->
<view class="media-bubble" wx:elif="{{item.contentType === 'video'}}">
<video
src="{{item.content}}"
class="message-video"
controls
show-center-play-btn
poster="{{item.thumb}}"
object-fit="contain"
></video>
<view class="video-play-overlay">
<image src="/images/icons/play.png" class="play-icon"></image>
</view>
<view class="upload-progress" wx:if="{{item.status === 'uploading'}}">
<view class="progress-circle">
<text class="progress-text">{{item.progress}}%</text>
@ -122,7 +141,8 @@
</view>
</view>
<view class="message-bubble bubble-right message-file" wx:elif="{{item.type === 'file'}}">
<!-- 文件消息 -->
<view class="message-bubble bubble-right message-file" wx:elif="{{item.contentType === 'file'}}">
<view class="file-icon-box">
<image src="/images/icons/file_icon.png" class="file-icon"></image>
</view>

77
pagesA/pages/expertChat/expertChat.wxss

@ -105,6 +105,57 @@
background-color: #d8d8d8;
}
/* ========== 发送中提示 ========== */
.sending-tip-container {
display: flex;
justify-content: center;
margin: 10rpx 0 20rpx;
animation: fadeIn 0.3s ease;
}
.sending-tip {
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(10px);
padding: 12rpx 32rpx;
border-radius: 40rpx;
display: flex;
align-items: center;
gap: 8rpx;
}
.sending-dot {
width: 8rpx;
height: 8rpx;
background: #ffffff;
border-radius: 50%;
animation: sendingPulse 1.4s infinite;
}
.sending-dot:nth-child(2) {
animation-delay: 0.2s;
}
.sending-dot:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes sendingPulse {
0%, 60%, 100% {
transform: scale(1);
opacity: 1;
}
30% {
transform: scale(1.5);
opacity: 0.5;
}
}
.sending-text {
font-size: 24rpx;
color: #ffffff;
margin-left: 8rpx;
}
/* ========== 消息项 ========== */
.message-item {
display: flex;
@ -146,7 +197,7 @@
object-fit: cover;
}
/* 消息内容包装器 */
/* 消息内容包装器 - 统一类名 */
.message-content-wrapper {
max-width: 480rpx;
position: relative;
@ -241,26 +292,6 @@
background: #000000;
}
.video-play-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
}
.play-icon {
width: 40rpx;
height: 40rpx;
margin-left: 4rpx;
}
/* 文件消息 */
.message-file {
min-width: 280rpx;
@ -306,6 +337,8 @@
color: #666666;
}
/* 上传进度 */
.upload-progress {
position: absolute;
@ -366,8 +399,6 @@
color: #999999;
}
.empty-text {
font-size: 28rpx;
color: #999999;

2
utils/api.js

@ -96,7 +96,7 @@ function wzdxq(params) {
// 专家列表
function expertsList(params) {
http('/vet/experts/list', 'get', params)
http('/sys/vet/audit/approved/list', 'get', params)
}
// 药品推荐列表

Loading…
Cancel
Save