Browse Source

WebSocket实时聊天,一对一聊天,反馈建议,服务评价

master
ZhaoYang 1 month ago
parent
commit
7a8bc3d03c
  1. 168
      pages/personal/personal.js
  2. 23
      pages/personal/personal.wxml
  3. 42
      pages/personal/personal.wxss
  4. BIN
      pagesA/images/wj.png
  5. 3
      pagesA/pages/expert/expert.js
  6. 1202
      pagesA/pages/expertChat/expertChat.js
  7. 23
      pagesA/pages/expertChat/expertChat.wxml
  8. 24
      utils/api.js
  9. 4
      utils/baseUrl.js

168
pages/personal/personal.js

@ -23,6 +23,11 @@ Page({
canSubmit: false,
isSubmitting: false,
// 反馈类型相关
feedbackTypes: [], // 反馈类型列表
currentFeedbackType: '', // 当前选中的反馈类型
selectedFeedbackTypeLabel: '', // 当前选中的反馈类型名称
// 编辑相关
newNickname: '',
@ -40,12 +45,68 @@ Page({
isUpdatingNickname: false,
// 消息数字
totalToday: 0
totalToday: 0,
// 文本域焦点
textareaFocus: false
},
onLoad() {
this.gettoday()
this.getfwpj()
},
// 反馈建议和服务评价
getfwpj() {
http.fkfw({
data: {
dictType: 'feedback_type'
},
success: res => {
console.log('获取反馈类型成功', res)
if (res.code === 200 && res.rows && res.rows.length > 0) {
this.setData({
feedbackTypes: res.rows,
// 默认选中第一个
currentFeedbackType: res.rows[0].dictValue,
selectedFeedbackTypeLabel: res.rows[0].dictLabel
})
} else {
// 如果没有获取到数据,设置默认值
this.setDefaultFeedbackTypes()
}
},
fail: err => {
console.error('获取反馈类型失败', err)
// 失败时设置默认值
this.setDefaultFeedbackTypes()
}
})
},
// 设置默认反馈类型
setDefaultFeedbackTypes() {
const defaultTypes = [
{ dictValue: '1', dictLabel: '功能建议' },
{ dictValue: '2', dictLabel: '体验反馈' },
{ dictValue: '3', dictLabel: '问题反馈' },
{ dictValue: '4', dictLabel: '其他' }
]
this.setData({
feedbackTypes: defaultTypes,
currentFeedbackType: '1',
selectedFeedbackTypeLabel: '功能建议'
})
},
// 选择反馈类型
selectFeedbackType(e) {
const type = e.currentTarget.dataset.type
const label = e.currentTarget.dataset.label
this.setData({
currentFeedbackType: type,
selectedFeedbackTypeLabel: label
})
},
onShow() {
@ -56,7 +117,6 @@ Page({
this.gettoday()
},
// 获取用户信息
getUserInfo() {
http.UserInfo({
@ -71,11 +131,9 @@ Page({
})
// 更新缓存
wx.setStorageSync('userInfo', res.data)
},
fail: (err) => {
console.error('获取用户信息失败:', err)
}
})
},
@ -107,9 +165,7 @@ Page({
return
}
const {
avatarUrl
} = e.detail
const { avatarUrl } = e.detail
if (!avatarUrl) {
this.showToast('选择头像失败')
return
@ -133,47 +189,47 @@ Page({
filePath: avatarUrl,
name: 'file',
success: (uploadRes) => {
const result = JSON.parse(uploadRes.data)
console.log('上传结果', result)
const result = JSON.parse(uploadRes.data)
console.log('上传结果', result)
if (result && result.fileName) {
// 获取上传后的文件路径
const uploadedFilePath = result.fileName
this.setData({
avatarUrl: uploadedFilePath,
})
if (result && result.fileName) {
// 获取上传后的文件路径
const uploadedFilePath = result.fileName
this.setData({
avatarUrl: uploadedFilePath,
})
// 更新缓存中的用户信息
const cachedUserInfo = wx.getStorageSync('userInfo') || {}
if (!cachedUserInfo.user) {
cachedUserInfo.user = {}
}
cachedUserInfo.user.avatar = uploadedFilePath
wx.setStorageSync('userInfo', cachedUserInfo)
// 更新头像的API
http.revise({
data: {
avatar: uploadedFilePath
},
success: (res) => {
console.log('头像更新成功')
wx.hideLoading()
this.showToast('头像更新成功')
// 4. 重新获取用户信息以确保数据同步
setTimeout(() => {
this.getUserInfo()
}, 500)
},
fail: (err) => {
console.error('头像更新失败:', err)
wx.hideLoading()
this.showToast('头像保存失败,请重试')
}
})
} else {
throw new Error('上传失败:返回数据格式错误')
// 更新缓存中的用户信息
const cachedUserInfo = wx.getStorageSync('userInfo') || {}
if (!cachedUserInfo.user) {
cachedUserInfo.user = {}
}
cachedUserInfo.user.avatar = uploadedFilePath
wx.setStorageSync('userInfo', cachedUserInfo)
// 更新头像的API
http.revise({
data: {
avatar: uploadedFilePath
},
success: (res) => {
console.log('头像更新成功')
wx.hideLoading()
this.showToast('头像更新成功')
// 4. 重新获取用户信息以确保数据同步
setTimeout(() => {
this.getUserInfo()
}, 500)
},
fail: (err) => {
console.error('头像更新失败:', err)
wx.hideLoading()
this.showToast('头像保存失败,请重试')
}
})
} else {
throw new Error('上传失败:返回数据格式错误')
}
},
fail: (err) => {
wx.hideLoading()
@ -303,6 +359,8 @@ Page({
// 显示反馈弹窗
showFeedback() {
// 刷新反馈类型数据
this.getfwpj()
this.setData({
showFeedbackModal: true,
feedbackContent: '',
@ -322,7 +380,7 @@ Page({
// 反馈内容输入
onFeedbackInput(e) {
const content = e.detail.value
const canSubmit = content.trim().length > 0
const canSubmit = content.trim().length > 0 && this.data.currentFeedbackType
this.setData({
feedbackContent: content,
@ -333,19 +391,26 @@ Page({
// 提交反馈
submitFeedback() {
if (!this.data.canSubmit || this.data.isSubmitting) return
const content = this.data.feedbackContent.trim()
if (content.length < 5) {
this.showToast('请填写详细的反馈内容')
return
}
if (!this.data.currentFeedbackType) {
this.showToast('请选择反馈类型')
return
}
this.setData({
isSubmitting: true
})
http.feedback({
data: {
content: content
content: content,
feedbackType: this.data.currentFeedbackType // 添加反馈类型字段
},
success: res => {
if (res.code == 200) {
@ -356,7 +421,10 @@ Page({
this.setData({
isSubmitting: false,
showFeedbackModal: false,
textareaFocus: false
textareaFocus: false,
feedbackContent: '',
currentFeedbackType: this.data.feedbackTypes.length > 0 ? this.data.feedbackTypes[0].dictValue : '',
selectedFeedbackTypeLabel: this.data.feedbackTypes.length > 0 ? this.data.feedbackTypes[0].dictLabel : ''
})
},
fail: (err) => {
@ -411,11 +479,11 @@ Page({
onPullDownRefresh() {
this.getUserInfo()
this.gettoday() // 刷新消息数
this.getfwpj() // 刷新反馈类型
setTimeout(() => {
wx.stopPullDownRefresh()
this.showToast('刷新成功')
}, 1000)
},
}
})

23
pages/personal/personal.wxml

@ -1,6 +1,6 @@
<view class="personal-center">
<!-- 用户信息区域 -->
<view class="user-section fade-in">
<!-- 用户信息区域 -->
<view class="user-section fade-in">
<view class="user-card">
<!-- 头像 -->
<button class="avatar-btn" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
@ -81,7 +81,6 @@
<text class="item-title logout-title">退出登录</text>
</view>
</view>
</view>
</view>
@ -96,6 +95,24 @@
</view>
</view>
<!-- 反馈类型tab分类 -->
<view class="feedback-tabs">
<scroll-view class="tabs-scroll" scroll-x="{{true}}" show-scrollbar="{{false}}">
<view class="tabs-wrapper">
<view
class="tab-item {{currentFeedbackType === item.dictValue ? 'active' : ''}}"
wx:for="{{feedbackTypes}}"
wx:key="index"
data-type="{{item.dictValue}}"
data-label="{{item.dictLabel}}"
bindtap="selectFeedbackType"
>
<text>{{item.dictLabel}}</text>
</view>
</view>
</scroll-view>
</view>
<view class="modal-body">
<!-- 修复iOS输入框问题:添加focus控制并增加条件渲染 -->
<textarea

42
pages/personal/personal.wxss

@ -455,6 +455,48 @@
filter: brightness(0%);
}
/* 反馈类型tab样式 */
.feedback-tabs {
padding: 20rpx 30rpx 10rpx;
border-bottom: 1rpx solid #f1f5f9;
}
.tabs-scroll {
width: 100%;
white-space: nowrap;
}
.tabs-wrapper {
display: flex;
padding: 8rpx 20rpx;
}
.tab-item {
display: inline-block;
padding: 16rpx 32rpx;
margin-right: 20rpx;
background: #f8fafc;
border-radius: 40rpx;
font-size: 28rpx;
color: #64748b;
transition: all 0.3s ease;
border: 1rpx solid #e2e8f0;
white-space: nowrap;
}
.tab-item.active {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border-color: transparent;
box-shadow: 0 4rpx 12rpx rgba(102, 126, 234, 0.3);
transform: scale(1.05);
}
.tab-item:active {
transform: scale(0.95);
opacity: 0.8;
}
/* 反馈输入框 - iOS修复 */
.modal-body {
padding: 40rpx;

BIN
pagesA/images/wj.png

Before

Width: 200  |  Height: 200  |  Size: 2.0 KiB

3
pagesA/pages/expert/expert.js

@ -233,7 +233,6 @@ Page({
// 显示专家联系方式
showContactInfo(e) {
console.log(234,e);
const index = e.currentTarget.dataset.index;
const expert = this.data.allExperts[index];
console.log(33333,expert);
@ -339,7 +338,7 @@ Page({
setTimeout(() => {
// 跳转一对一咨询专家
wx.navigateTo({
url: '/pagesA/pages/expertChat/expertChat',
url: `/pagesA/pages/expertChat/expertChat?id=${expert.userId}`,
})
this.hideContactDialog();
}, 2000);

1202
pagesA/pages/expertChat/expertChat.js
File diff suppressed because it is too large
View File

23
pagesA/pages/expertChat/expertChat.wxml

@ -4,10 +4,10 @@
<view class="header-content">
<view class="header-center">
<view class="expert-info">
<text class="expert-name">{{expertInfo.name}}</text>
<text class="expert-name">{{conversation.otherUserName}}</text>
<view class="expert-status">
<view class="status-dot {{expertInfo.online ? 'online' : 'offline'}}"></view>
<text class="status-text">{{expertInfo.online ? '在线' : '离线'}}</text>
<text class="status-text">在线</text>
</view>
</view>
</view>
@ -33,15 +33,15 @@
<!-- 消息列表 -->
<block wx:for="{{messageList}}" wx:key="id">
<!-- 对方消息 -->
<view class="message-item message-left" wx:if="{{item.sender === 'expert'}}">
<view class="message-item message-left" wx:if="{{!item.isMe}}">
<view class="message-avatar">
<image src="/pagesA/images/name.png" class="avatar-img"></image>
<image src="{{conversation.otherUserAvatar?baseUrl+conversation.otherUserAvatar:' /pages/images/tx.png'}}" class="avatar-img"></image>
</view>
<view class="message-content-wrapper">
<view class="messages-content-wrapper">
<view class="message-arrow arrow-left"></view>
<view class="message-bubble bubble-left" wx:if="{{item.type === 'text'}}">
<view class="message-bubble bubble-left" wx:if="{{item.contentType === 'text'}}">
<text class="message-text">{{item.content}}</text>
</view>
@ -85,7 +85,7 @@
<view class="message-content-wrapper">
<view class="message-arrow arrow-right"></view>
<view class="message-bubble bubble-right" wx:if="{{item.type === 'text'}}">
<view class="message-bubble bubble-right" wx:if="{{item.contentType === 'text'}}">
<text class="message-text">{{item.content}}</text>
</view>
@ -139,7 +139,7 @@
</view>
<view class="message-avatar">
<image src="/pages/images/tx.png" class="avatar-img"></image>
<image src="{{conversation.userAvatar?baseUrl+conversation.userAvatar:'/pages/images/tx.png'}}" class="avatar-img"></image>
</view>
</view>
</block>
@ -228,13 +228,6 @@
</view>
<text class="option-text">视频</text>
</view>
<view class="media-option" bindtap="chooseFile">
<view class="option-icon-box">
<image src="/pagesA/images/wj.png"></image>
</view>
<text class="option-text">文件</text>
</view>
</view>
<view class="sheet-bottom">

24
utils/api.js

@ -250,6 +250,28 @@ function today(params) {
http('/muhu/consultation/today', 'get', params)
}
// 反馈意见和服务评价字典
function fkfw(params) {
http('/system/dict/data/list', 'get', params)
}
// 获取聊天记录列表
function sessions(params) {
http('/system/chat/sessions', 'get', params)
}
// 建立兽医一对一聊天
function create(params) {
http('/system/chat/session/create', 'post', params)
}
// 查找一对一聊天的记录
function direct(params) {
http('/system/chat/messages/direct', 'get', params)
}
export default { // 暴露接口
login,carousel,disaster,pharmacy,guidance,getPhoneNumber,inquiry,policyeDetails,shareAdd,
@ -257,5 +279,5 @@ export default { // 暴露接口
recommendationXq,queryList,tipList,article,articleDetails,articleZd,policyelucidation,
areaChildren,userCode,UserInfo,videoList,videoZd,videoDetails,forumList,forumAdd,forumDetails,
forumReply,commentReply,experience,experiencezd,experienceDetails,realName,revise,feedback,
warningType,disasterDetail,today,carouselDetail,planDetails,wzdDetails
warningType,disasterDetail,today,carouselDetail,planDetails,wzdDetails,create,direct,fkfw,
}

4
utils/baseUrl.js

@ -1,5 +1,5 @@
// var baseUrl = 'https://wx.chenhaitech.com/ymtx-prod-api'
var baseUrl = 'http://192.168.101.109:8080'
// var baseUrl = 'http://192.168.101.109:8080'
// var baseUrl = 'http://192.168.101.105:8082'
// var baseUrl = 'http://192.168.101.111:8081'
var baseUrl = 'http://192.168.101.111:8081'
module.exports = baseUrl
Loading…
Cancel
Save