diff --git a/CommunicationRecords/.cloudbase/container/debug.json b/CommunicationRecords/.cloudbase/container/debug.json
new file mode 100644
index 0000000..0d44458
--- /dev/null
+++ b/CommunicationRecords/.cloudbase/container/debug.json
@@ -0,0 +1 @@
+{"containers":[],"config":{}}
\ No newline at end of file
diff --git a/CommunicationRecords/.gitignore b/CommunicationRecords/.gitignore
new file mode 100644
index 0000000..14ea590
--- /dev/null
+++ b/CommunicationRecords/.gitignore
@@ -0,0 +1,14 @@
+# Windows
+[Dd]esktop.ini
+Thumbs.db
+$RECYCLE.BIN/
+
+# macOS
+.DS_Store
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+
+# Node.js
+node_modules/
diff --git a/CommunicationRecords/app.js b/CommunicationRecords/app.js
index 2db4645..a6df4b4 100644
--- a/CommunicationRecords/app.js
+++ b/CommunicationRecords/app.js
@@ -15,7 +15,11 @@ App({
},
globalData: {
userInfo: null,
- baseUrl: 'https://你的域名' // 后端 API 根地址
+ baseUrl: 'https://你的域名', // 后端 API 根地址
+ userKey:"",
+ avatarUrl:"",
+ weChatName:"",
+
}
})
diff --git a/CommunicationRecords/app.wxss b/CommunicationRecords/app.wxss
index 06c6fc9..d494213 100644
--- a/CommunicationRecords/app.wxss
+++ b/CommunicationRecords/app.wxss
@@ -1,4 +1,4 @@
-/**app.wxss**/
+
.container {
height: 100%;
display: flex;
diff --git a/CommunicationRecords/assets/default.png b/CommunicationRecords/assets/default.png
new file mode 100644
index 0000000..8c2af15
Binary files /dev/null and b/CommunicationRecords/assets/default.png differ
diff --git a/CommunicationRecords/images/Blvlogo.png b/CommunicationRecords/images/Blvlogo.png
new file mode 100644
index 0000000..8c2af15
Binary files /dev/null and b/CommunicationRecords/images/Blvlogo.png differ
diff --git a/CommunicationRecords/images/Icon_阅读模式_7.487_7.504.png b/CommunicationRecords/images/Icon_阅读模式_7.487_7.504.png
new file mode 100644
index 0000000..502e851
Binary files /dev/null and b/CommunicationRecords/images/Icon_阅读模式_7.487_7.504.png differ
diff --git a/CommunicationRecords/images/Keyboard.png b/CommunicationRecords/images/Keyboard.png
new file mode 100644
index 0000000..5424e0e
Binary files /dev/null and b/CommunicationRecords/images/Keyboard.png differ
diff --git a/CommunicationRecords/images/Voice.png b/CommunicationRecords/images/Voice.png
new file mode 100644
index 0000000..8f4f99f
Binary files /dev/null and b/CommunicationRecords/images/Voice.png differ
diff --git a/CommunicationRecords/images/lock.png b/CommunicationRecords/images/lock.png
new file mode 100644
index 0000000..0e029b3
Binary files /dev/null and b/CommunicationRecords/images/lock.png differ
diff --git a/CommunicationRecords/images/lock2.png b/CommunicationRecords/images/lock2.png
new file mode 100644
index 0000000..fecdf92
Binary files /dev/null and b/CommunicationRecords/images/lock2.png differ
diff --git a/CommunicationRecords/images/lock_3.png b/CommunicationRecords/images/lock_3.png
new file mode 100644
index 0000000..6af681e
Binary files /dev/null and b/CommunicationRecords/images/lock_3.png differ
diff --git a/CommunicationRecords/images/lock_r.png b/CommunicationRecords/images/lock_r.png
new file mode 100644
index 0000000..54e8876
Binary files /dev/null and b/CommunicationRecords/images/lock_r.png differ
diff --git a/CommunicationRecords/images/logo.png b/CommunicationRecords/images/logo.png
new file mode 100644
index 0000000..5238212
Binary files /dev/null and b/CommunicationRecords/images/logo.png differ
diff --git a/CommunicationRecords/images/touxiang.png b/CommunicationRecords/images/touxiang.png
new file mode 100644
index 0000000..2f6ca82
Binary files /dev/null and b/CommunicationRecords/images/touxiang.png differ
diff --git a/CommunicationRecords/images/unlock_b.png b/CommunicationRecords/images/unlock_b.png
new file mode 100644
index 0000000..6b9dfa8
Binary files /dev/null and b/CommunicationRecords/images/unlock_b.png differ
diff --git a/CommunicationRecords/images/unlock_blue.png b/CommunicationRecords/images/unlock_blue.png
new file mode 100644
index 0000000..d81d2e4
Binary files /dev/null and b/CommunicationRecords/images/unlock_blue.png differ
diff --git a/CommunicationRecords/pages/chat/chat.js b/CommunicationRecords/pages/chat/chat.js
new file mode 100644
index 0000000..e4e70d0
--- /dev/null
+++ b/CommunicationRecords/pages/chat/chat.js
@@ -0,0 +1,1126 @@
+// 在文件顶部引入配置
+const config = require('../../utils/config.js');
+const mock = require('./mock.js')
+const app = getApp()
+// 1. 引入插件
+const plugin = requirePlugin('WechatSI');
+// 2. 获取全局唯一的语音识别管理器
+const manager = plugin.getRecordRecognitionManager();
+function formatNumber(n) {
+ n = n.toString()
+ return n[1] ? n : '0' + n
+}
+function formatTime(date) {
+ const y = date.getFullYear()
+ const m = formatNumber(date.getMonth() + 1)
+ const d = formatNumber(date.getDate())
+ const h = formatNumber(date.getHours())
+ const mi = formatNumber(date.getMinutes())
+ return {
+ date: `${y}-${m}-${d}`,
+ time: `${y}-${m}-${d} ${h}:${mi}`
+ }
+}
+
+Page({
+ data: {
+ chatTitle: '宝来威智能AI',
+ msgList: [],
+ OriginalmsgList: [],
+ toView: '',
+ qinputTxt: '',
+ ginputTxt: '',
+ voiceMode: true,
+ recording: false,
+ recording1: false,
+ cancelSend: false,
+ cancelSend1: false,
+ TabCur:1,
+ UserKey:"",
+ resultText: '' , // 识别出的文本结果
+ triggered: false, // 控制下拉状态
+ pulling: false, // 是否正在下拉
+ pullText: '下拉刷新',
+ PageNumber:1,
+ RecordingStatus:0,//0 丢弃 /1 全局/2私有
+ TrhandleTouchEnd:0,
+ scrollHeight:500,
+ Keyboard:"",
+ Voice:"",
+ timer: null, // 用于存储定时器ID[5,6](@ref)
+ modalName:"",
+ inputValue:"",
+ RevisemsgId:-1,
+ isFocused: false,
+ avatarUrl:"/images/touxiang.png",
+ weChatName:"",
+ },
+
+ onLoad() {
+
+
+ this.setData({avatarUrl:app.globalData.avatarUrl,weChatName:app.globalData.weChatName})
+ this.loadHistory()
+ this.initRecordManager()
+ this.GetmyScrollhight()
+ // this.initSound()
+ this.startTimer();
+ },
+ // 初始化提示音
+ // initSound() {
+ // // this.dingCtx = wx.createInnerAudioContext();
+ // // this.dingCtx.src = '/assets/sounds/ding.wav'; // 指向生成的音频文件
+ // },
+// 页面卸载时清理资源
+onUnload: function () {
+ this.clearTimer();
+ if (this.data.recording) {
+ manager.stop();
+ this.setData({
+ recording: false,
+ recording1: false,
+ cancelSend: false,
+ cancelSend1: false,
+ RecordingStatus: 0
+ });
+ }
+},
+onHide() {
+ this.clearTimer();
+ // 停止录音
+ if (this.data.recording || this.data.recording1) {
+ manager.stop();
+ this.setData({
+ recording: false,
+ recording1: false,
+ cancelSend: false,
+ cancelSend1: false,
+ RecordingStatus: 0
+ });
+ }
+},
+onShow: function() {
+ // 如果页面从后台返回,可以重新启动定时器[6](@ref)
+ this.startTimer();
+},
+
+ // 启动定时器
+ startTimer: function() {
+ // 先清除可能存在的旧定时器,防止重复创建[6](@ref)
+ this.clearTimer();
+
+ const that = this;
+ // 设置一个每秒执行一次的定时器,并保存其ID[1](@ref)
+ const timerId = setInterval(function() {
+ // 在这里编写你需要每秒执行的逻辑
+ that.executePerSecond();
+ }, 1000);
+
+ // 将定时器ID存入data中,便于管理[5,6](@ref)
+ this.setData({
+ timer: timerId
+ });
+ },
+ executePerSecond: function() {
+ const list = this.data.OriginalmsgList
+ const TabCur=this.data.TabCur
+ if (!list ||list.length==0) {
+ return
+ }
+ const t =Date.now()
+ let cuncvl =0
+ //debugger
+
+ let dateObj //= new Date(dateString);
+ for (let index = 0; index < list.length; index++) {
+ const element = list[list.length-index-1];
+ if (element.lock==='Unlock') {
+ let dateObj=new Date(element.time);
+ cuncvl =t - dateObj
+ if (cuncvl>300000) {
+ element.lock='lock'
+ list[list.length-index-1]=element
+ this.setData({OriginalmsgList:list})
+ this.tabSelect1(TabCur)
+
+ }
+ }
+
+
+
+ }
+
+ },
+ // 清除定时器
+ clearTimer: function() {
+ if (this.data.timer !== null) {
+ clearInterval(this.data.timer); // 清除定时器[4](@ref)
+ this.setData({
+ timer: null
+ });
+ console.log('定时器已清除');
+ }
+},
+async onAvatar(e){
+ let tempFilePath =e.detail.avatarUrl
+ let UserKey = wx.getStorageSync('openid');
+ this.uploadAvatarToServer(tempFilePath,UserKey)
+},
+uploadAvatarToServer(tempFilePath,userKey) {
+ // 显示加载提示,提升用户体验
+ wx.showLoading({ title: '上传中...' });
+
+ wx.uploadFile({
+ url: 'https://wx-xcx-check.blv-oa.com:4433/api/Check/UploadFile', // 你的服务器上传接口
+ filePath: tempFilePath,
+ name: 'file', // 与后端约定的文件参数名
+ formData: {
+ 'rootPathType': 'Avatar', // 指定保存到 wwwroot/Avatar 目录
+ 'userKey': userKey // 指定要更新头像的用户
+ },
+ success: (res) => {
+ wx.hideLoading();
+ const data = JSON.parse(res.data); // 注意: uploadFile返回的data是字符串,需解析
+ if (data.success) {
+ // 上传成功,拿到服务器返回的永久链接
+ const permanentUrl = data.url;
+ this.setData({
+ avatarUrl: permanentUrl // 更新为永久链接
+ });
+ // 接下来可以将 permanentUrl 保存到本地缓存或发送给后端更新用户信息
+ wx.showToast({ title: '上传成功' });
+ } else {
+ wx.showToast({ title: '上传失败: ' + data.message, icon: 'none' });
+ }
+ },
+ fail: (err) => {
+ wx.hideLoading();
+ console.error('上传接口调用失败', err);
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ });
+},
+
+ /* ---------- 历史消息 ---------- */
+ loadHistory() {
+ // 本地 Mock,上线改为请求接口
+
+ //const list = mock.map(item => ({ ...item, showDate: true }))
+ let UserKey=wx.getStorageSync('openid')
+ try {
+ this.GetConversations(UserKey,0)
+ } catch (error) {
+ // console.error('获取历史信息失败!:', error);
+ wx.showToast({
+ title: "获取历史信息失败!",
+ icon: 'none'
+ });
+ }
+
+ //this.setData({ msgList: list })
+ this.scrollBottom()
+ },
+ async GetConversations(UserKey ,MessageType) {
+
+ const apiRes = await new Promise((resolve, reject) => {
+ wx.request({
+ url: `${config.baseUrl}/api/Check/GetConversationsByPage`,
+ method: 'POST',
+ data: {UserKey:UserKey ,Page:1,PageSize:20 ,MessageType:0},
+ success: res =>{
+ console.log(res)
+ const list = this.data.msgList
+ for (let index = 0; index < res.data.data.conversations.length; index++) {
+ const element = res.data.data.conversations[index];
+ const createTime = element.createTime.toString().replace("T"," ")
+ let location =`${element.latitude},${element.longitude}`
+ const newMsg = {
+ id: element.id,
+ location:location,
+ guid :element.guid,
+ content:element.conversationContent,
+ date:createTime,
+ time:createTime,
+ isSelf:element.messageType,
+ showDate:createTime,
+ sendMethod:element.sendMethod,
+ voicetime:element.speakingTime,
+ status: 'success',
+ lock:'lock'
+ }
+ list.push(newMsg)
+
+ }
+
+ this.setData({ msgList: list,OriginalmsgList: list})
+ },
+ fail: reject
+ });
+ });
+
+ },
+ /* ---------- 文字输入 ---------- */
+ qonInput(e) {
+ this.setData({ qinputTxt: e.detail.value })
+ },
+ gonInput(e) {
+ this.setData({ ginputTxt: e.detail.value })
+ },
+ qsendText() {
+
+ let txt = this.data.qinputTxt.trim()
+ if (!txt) return
+ if (txt.length>100000) {
+ txt=txt.substring(0,100000).trim()
+ }
+ this.pushMsg(txt, 1,0)
+ this.upload(txt, 'text',1)
+ this.setData({ qinputTxt: '' })
+ },
+ gsendText() {
+
+ let txt = this.data.qinputTxt.trim()
+ if (!txt) return
+ if (txt.length>1000) {
+ txt=txt.substring(0,1000).trim()
+ }
+ this.pushMsg(txt, 2,0)
+ this.upload(txt, 'text',2)
+ this.setData({ qinputTxt: '' })
+ },
+ /* ---------- 模式切换 ---------- */
+ switchInputMode() {
+ this.setData({ voiceMode: !this.data.voiceMode })
+ },
+
+ /* ---------- 语音录制 ---------- */
+ initRecordManager: function () {
+ const that = this;
+
+ // 识别开始事件
+ manager.onStart = function (res) {
+ console.log("开始录音识别");
+ // 可以在这里触发手机振动反馈
+ wx.vibrateShort({ type: 'medium' });
+ console.log("触发手机振动反馈");
+
+
+ };
+
+ // 有新的识别内容返回(实时返回)
+ manager.onRecognize = function (res) {
+ console.log('实时识别结果:', res.result);
+ // 如果需要实时显示,可以在这里 setData
+ that.setData({ resultText: res.result });
+ };
+
+ // 识别结束事件(返回最终结果)
+ manager.onStop = function (res) {
+ console.log('识别结束', res);
+ let finalText = res.result;
+ if (!finalText||finalText.length==0) {
+ wx.showToast({ title: '未识别到内容', icon: 'none' });
+ finalText = '';
+ return
+ }
+ //发送
+ //debugger
+ let RecordingStatus =that.data.RecordingStatus
+ let TrhandleTouchEnd = that.data.TrhandleTouchEnd
+ let cost = Date.now() - that.recordStartTime
+ console.log(cost)
+ console.log(RecordingStatus)
+ if (RecordingStatus!==0 ||cost>=60000) {
+ // 播放提示音
+ if (this.dingCtx) {
+ this.dingCtx.stop();
+ this.dingCtx.play();
+ }
+ if (finalText.length>100000) {
+ finalText=finalText.substring(0,100000).trim()
+ }
+
+ if (cost>=60000) {
+ cost=60
+ }else{
+ cost = Math.ceil(cost / 1000)
+ }
+
+ that.pushMsg(finalText, TrhandleTouchEnd,cost)
+ that.upload(finalText, 'voice',TrhandleTouchEnd)
+ }
+
+
+
+ // 更新结果到页面
+ that.setData({
+ resultText: '', // 识别结束清空实时显示
+ recording1: false,
+ recording: false,
+ RecordingStatus:0
+ });
+ };
+
+ // 识别错误事件
+ manager.onError = function (res) {
+ // console.log('识别错误:'+ res);
+ // let TrhandleTouchEnd =that.data.TrhandleTouchEnd
+ // if (TrhandleTouchEnd==1) {
+ // manager.stop()
+ // }
+ // if (TrhandleTouchEnd==2) {
+ // manager.stop()
+ // }
+
+
+
+ that.setData({ recording: false,recording1: false });
+ // 可以根据错误码给出具体提示
+ const errorMap = {
+ '-30003': '说话时间太短',
+ '-30004': '没有听清,请重试',
+ '-30011': '上个录音正在识别中'
+ };
+ const msg = errorMap[res.retcode] || '识别失败';
+ wx.showToast({ title: msg, icon: 'none' });
+
+ };
+ },
+ // 开始录音
+ startRecord: function () {
+ const that = this;
+ // 先检查授权
+ wx.getSetting({
+ success(res) {
+ if (res.authSetting['scope.record']) {
+ // 已有授权,开始录音
+ that.doStartRecord();
+ } else {
+ // 请求授权
+ wx.authorize({
+ scope: 'scope.record',
+ success() { that.doStartRecord(); },
+ fail() {
+ wx.showModal({
+ title: '权限申请',
+ content: '需要您授权使用麦克风',
+ success(modalRes) {
+ if (modalRes.confirm) {
+ wx.openSetting(); // 引导用户去设置页开启
+ }
+ }
+ });
+ }
+ });
+ }
+ }
+ });
+ },
+ // 执行开始录音操作
+ doStartRecord: function () {
+ console.log("doStartRecord");
+
+ this.setData({
+ // recording: true,
+ resultText: '' // 开始新的录音时清空上次结果
+ });
+ // 调用插件的start方法,传入参数
+ setTimeout(() => {
+ console.log("调用插件的start方法,传入参数");
+
+ let TrhandleTouchEnd =this.data.TrhandleTouchEnd
+ console.log(TrhandleTouchEnd);
+ if (TrhandleTouchEnd==1) {
+ let recording =this.data.recording
+ console.log(recording);
+ if (recording==false) {
+
+ // this.stopRecord1()
+ // this.stopRecord()
+ // console.log("打断录音");
+ return
+ }
+ }
+ if (TrhandleTouchEnd==2) {
+ let recording1 =this.data.recording1
+ console.log(recording1);
+ if (recording1==false) {
+
+ // this.stopRecord1()
+ // this.stopRecord()
+ // console.log("打断录音");
+ return
+ }
+ }
+ manager.start({
+ lang: 'zh_CN', // 语言,支持 zh_CN(中文)、en_US(英文)等
+ duration: 60000 // 录音时长,单位毫秒(这里是60秒)
+ });
+
+ }, 300);
+},
+
+// 停止录音
+stopRecord: function () {
+ if (this.data.recording) {
+ manager.stop(); // 停止录音并触发 onStop 回调
+ }
+},
+stopRecord1: function () {
+ if (this.data.recording1) {
+ manager.stop(); // 停止录音并触发 onStop 回调
+ }
+},
+
+ handleTouchStart(e) {
+
+ console.log("handleTouchStart")
+ this.startY = e.touches[0].pageY
+ this.recordStartTime = Date.now()
+ this.setData({ recording: true, cancelSend: false ,RecordingStatus:0,TrhandleTouchEnd:1})
+ //this.recorderManager.start({ duration: 60000, format: 'mp3' })
+ const recording =this.data.recording
+ //wx.vibrateShort('heavy');
+ if (recording) {
+ this.startRecord()
+ console.log("startRecord")
+ }
+ console.log("handleTouchStart_en")
+ },
+ handleTouchStart1(e) {
+ //wx.vibrateLong();
+// wx.vibrateShort('heavy');
+ console.log("handleTouchStart1")
+ this.startY1 = e.touches[0].pageY
+ this.recordStartTime = Date.now()
+ this.setData({ recording1: true, cancelSend1: false ,RecordingStatus:0,TrhandleTouchEnd:2})
+ //this.recorderManager.start({ duration: 60000, format: 'mp3' })
+ this.startRecord()
+ },
+ handleTouchMove(e) {
+
+ //console.log("handleTouchMove")
+ const diff = this.startY - e.touches[0].pageY
+ //console.log(diff)
+ if (diff > 100) {
+ this.setData({ cancelSend:true,RecordingStatus:0})
+ manager.stop();
+ }
+
+ },
+ handleTouchMove1(e) {
+ //console.log("handleTouchMove1")
+ const diff = this.startY1 - e.touches[0].pageY
+ //console.log(diff)
+ if (diff > 100) {
+ this.setData({ cancelSend1:true,RecordingStatus:0})
+ manager.stop();
+ }
+
+ },
+ handleTouchEnd() {
+ console.log("handleTouchEnd")
+ const cost = Date.now() - this.recordStartTime
+ if (cost < 350) {
+ //this.recorderManager.stop()
+ manager.stop();
+ this.setData({ recording: false,RecordingStatus:0 })
+ console.log( this.data.recording)
+ return
+ }
+ //this.recorderManager.stop()
+ manager.stop();
+ this.setData({ recording: false ,RecordingStatus:1})
+ console.log( this.data.recording)
+ },
+ handleTouchEnd1() {
+ console.log("handleTouchEnd1")
+ const cost = Date.now() - this.recordStartTime
+ if (cost < 350) {
+ //this.recorderManager.stop()
+ manager.stop();
+ this.setData({ recording1: false })
+ console.log( this.data.recording)
+ return
+ }
+ //this.recorderManager.stop()
+ manager.stop();
+ this.setData({ recording1: false,RecordingStatus:2 })
+ console.log( this.data.recording)
+ },
+ handleTouchCancel() {
+ console.log("handleTouchCancel")
+ //this.recorderManager.stop()
+ manager.stop();
+ this.setData({ recording: false, cancelSend: false ,RecordingStatus:0})
+ },
+ handleTouchCancel1() {
+
+ console.log("handleTouchCancel1")
+ //this.recorderManager.stop()
+ this.stopRecord()
+ this.setData({ recording1: false, cancelSend1: false,RecordingStatus:0 })
+ },
+
+
+
+ /* ---------- 消息渲染 ---------- */
+ pushMsg(content, MessageType,voicetime) {
+ const { date, time } = formatTime(new Date())
+ const list = this.data.OriginalmsgList
+ const last = list[list.length - 1]
+ const showDate = !last || last.date !== date
+ const newMsg = {
+ id: Date.now(),
+ voicetime,voicetime,
+ content,
+ date,
+ time,
+ isSelf:MessageType,
+ showDate,
+ status: 'sending', // 添加状态字段: sending, success, failed
+ lock:'Unlock'
+ }
+ list.push(newMsg)
+ this.setData({ OriginalmsgList: list })
+ let TabCur=this.data.TabCur
+ this.tabSelect1(TabCur)
+ this.scrollBottom()
+ return newMsg.id;
+ },
+ scrollBottom() {
+ setTimeout(() => {
+ this.setData({ toView: `msg-${this.data.msgList.length - 1}` })
+ }, 100)
+ },
+
+ /* ---------- 上传服务器 ---------- */
+async upload(txt, type, MessageType) {
+ console.log('upload')
+ const msgId = this.data.OriginalmsgList[this.data.OriginalmsgList.length - 1].id;
+
+
+ try {
+ const location = await new Promise((resolve, reject) => {
+ wx.getLocation({
+ type: 'gcj02',
+ success(res) {
+ console.log('getLocation')
+ resolve(`${res.latitude},${res.longitude}`)
+ },
+ fail(err) {
+ console.error('获取位置失败:', err)
+ resolve('') // 位置获取失败时使用空字符串
+ }
+ })
+ })
+ const list = [...this.data.OriginalmsgList]
+ const msgIndex = list.findIndex(msg => msg.id === msgId)
+ list[msgIndex].location=location
+ list[msgIndex].sendMethod=type
+ list[msgIndex].isSelf=MessageType
+ list[msgIndex].time=this.GetTimeDate()
+ this.setData({ OriginalmsgList: list })
+
+ const apiRes = await this.post(txt, type, location, MessageType,list[msgIndex].voicetime)
+
+
+ console.log(apiRes)
+ // 更新消息状态为成功
+
+ this.updateMessageStatus(msgId, 'success')
+ list[msgIndex].time=apiRes.data.receivedTime
+ list[msgIndex].guid =apiRes.data.conversationGuid
+ this.setData({ OriginalmsgList: list })
+ console.log(this.data.OriginalmsgList)
+ } catch (error) {
+ console.error('上传失败:')
+ console.error(error)
+
+ // 更新消息状态为失败
+ this.updateMessageStatus(msgId, 'failed')
+ wx.showToast({
+ title: '发送失败,请重试',
+ icon: 'none'
+ })
+ }
+ },
+
+
+// 添加更新消息状态的方法
+updateMessageStatus(msgId, status) {
+
+ console.log('updateMessageStatus')
+ console.log(status)
+ const list = [...this.data.OriginalmsgList]
+ const msgIndex = list.findIndex(msg => msg.id === msgId)
+ if (msgIndex !== -1) {
+ list[msgIndex].status = status
+ this.setData({ OriginalmsgList: list })
+ let TabCur = this.data.TabCur
+ this.tabSelect1(TabCur)
+ }
+},
+// 添加重发消息方法
+retryMessage(e) {
+ const { id } = e.currentTarget.dataset
+ const list = this.data.OriginalmsgList
+ const msgIndex = list.findIndex(msg => msg.id === id)
+ if (msgIndex !== -1) {
+ const msg = list[msgIndex]
+ this.updateMessageStatus(id, 'sending')
+ this.upload(msg.content, msg.sendMethod, msg.isSelf)
+ }
+},
+
+ async post(content, sendMethod, location,MessagType,voicetime) {
+ // console.log('post')
+
+ let UserKey=wx.getStorageSync('openid')
+ const apiRes = await new Promise((resolve, reject) => {
+ wx.request({
+ url: `${config.baseUrl}/api/Check/AddConversation`,
+ method: 'POST',
+ data: {
+ UserKey:UserKey ,
+ ConversationContent: content,
+ SendMethod: sendMethod,
+ UserLocation: location,
+ MessageType:MessagType,
+ SpeakingTime:voicetime,
+ Guid:""
+ },
+ success: res =>{
+ // console.log(res);
+ resolve(res); // 增加这行,解析Promise并返回结果
+ },
+ fail: (err) => {
+ //console.error('请求失败:', err);
+ reject(err);
+ }
+ });
+ });
+ //console.log(apiRes);
+ return apiRes
+
+ },
+
+
+
+ tabSelect(e){
+ this.tabSelect1(e.currentTarget.dataset.id)
+ },
+ tabSelect1(type) {
+ let list = []
+ let Oldlist = []
+ switch (type) {
+ case 1:
+ list =this.data.OriginalmsgList
+ break;
+ case 2:
+ Oldlist =this.data.OriginalmsgList
+ for (let index = 0; index < Oldlist.length; index++) {
+ const element = Oldlist[index];
+ if (element.isSelf===1) {
+ list.push(element)
+ }
+ }
+ break;
+ case 3:
+ Oldlist =this.data.OriginalmsgList
+ for (let index = 0; index < Oldlist.length; index++) {
+ const element = Oldlist[index];
+ if (element.isSelf===2) {
+ list.push(element)
+ }
+ }
+ break;
+ default:
+ list =this.data.OriginalmsgList
+ break;
+ }
+ this.setData({
+ msgList: list,
+ TabCur: type,
+ scrollLeft: (type-1)*60
+ })
+ },
+
+ /* 1. 下拉中(实时)*/
+ onPulling(e) {
+
+ if (!this.data.pulling) this.setData({ pulling: true })
+ const dy = e.detail.dy // 下拉垂直距离
+ this.setData({ pullText: dy > 80 ? '释放立即刷新' : '下拉刷新' })
+ },
+ /* 2. 达到阈值松手 → 真正刷新 */
+ async onRefresh() {
+
+ // this.setData({ pullText: '加载中…' })
+ // await this.loadData(true) // true=刷新模式
+ // this.setData({ triggered: false }) // 关闭下拉状态
+
+ // 记录刷新开始时间,用于计算最少展示时间
+ const startTime = Date.now();
+ const minAnimationTime = 1000; // 最少展示1秒动画
+
+ this.setData({
+ pullText: '加载中…',
+ isLoading: true // 添加加载状态标识
+ });
+
+ try {
+ // 执行数据加载
+ await this.loadData(true);
+
+ // 计算已用时间,如果不足1秒则延迟补足
+ const elapsedTime = Date.now() - startTime;
+ const remainingTime = Math.max(minAnimationTime - elapsedTime, 0);
+
+ if (remainingTime > 0) {
+ await new Promise(resolve => setTimeout(resolve, remainingTime));
+ }
+
+ // 显示"已加载最新记录"提示
+ this.setData({
+ pullText: '已加载最新记录'
+ });
+
+ // 短暂显示提示文字后再关闭下拉状态
+ await new Promise(resolve => setTimeout(resolve, 500));
+
+ } catch (error) {
+ console.error('下拉刷新失败:', error);
+ this.setData({
+ pullText: '加载失败,请重试'
+ });
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ } finally {
+ // 无论成功失败,最终都关闭下拉状态
+ this.setData({
+ triggered: false,
+ isLoading: false
+ });
+ }
+
+
+ },
+ /* 3. 回弹复位 */
+ onRestore() {
+ this.setData({ pulling: false, pullText: '下拉刷新' })
+ },
+ /* 4. 请求数据 */
+ async loadData(reload = false) {
+ let oldli =this.data.OriginalmsgList
+ let pagenumber =Math.floor(oldli.length /20)
+ let yushu =oldli.length % 20
+ if (yushu>0) {
+ let nli =[]
+ for (let nindex = yushu; nindex < oldli.length; nindex++) {
+ const element = oldli[nindex];
+ nli.push(element)
+ }
+ oldli=nli
+ }
+ let UserKey=wx.getStorageSync('openid')
+ pagenumber=pagenumber+1
+ const apiRes = await new Promise((resolve, reject) => {
+
+ wx.request({
+ url: `${config.baseUrl}/api/Check/GetConversationsByPage`,
+ method: 'POST',
+ data: {UserKey:UserKey ,Page:pagenumber,PageSize:20 ,MessageType:0},
+ success: res =>{
+ console.log(res)
+ let list = []
+ for (let index = 0; index < res.data.data.conversations.length; index++) {
+ const element = res.data.data.conversations[index];
+ const createTime = element.createTime.toString().replace("T"," ")
+ let location =`${element.latitude},${element.longitude}`
+ const newMsg = {
+ id: element.id,
+ guid :element.guid,
+ location:location,
+ content:element.conversationContent,
+ date:createTime,
+ time:createTime,
+ isSelf:element.messageType,
+ showDate:createTime,
+ sendMethod:element.sendMethod,
+ voicetime:element.speakingTime,
+ status: 'success',
+ lock:'lock'
+ }
+ list.push(newMsg)
+ }
+
+ const newArray = list.concat(oldli)
+ this.setData({ PageNumber: pagenumber,OriginalmsgList: newArray,triggered: false})
+ let TabCur=this.data.TabCur
+ this.tabSelect1(TabCur)
+
+
+ },
+ fail: reject
+ });
+ });
+ },
+ handleLongPressmsg(e){
+ console.log(e)
+
+ const id = e.currentTarget.id
+ const list = this.data.OriginalmsgList
+ if (!id||!list ||list.length==0) {
+ return
+ }
+
+ for (let index = 0; index < list.length; index++) {
+ const element = list[list.length-index-1];
+ if (id==element.id) {
+ if (element.status=='success' && element.lock=='Unlock') {
+
+ this.setData({
+ inputValue:element.content,
+ RevisemsgId:id,
+ modalName: "DialogModal1" // px→rpx
+ });
+
+ }
+ return
+ }
+
+ }
+
+
+ },
+ inputSearchForHotels(e){
+
+ this.setData({
+ inputValue: e.detail.value
+ })
+ },
+ async hideModal(e) {
+
+ this.setData({
+ modalName: ""
+ })
+ if (e.currentTarget.id=='ok') {
+ const id = this.data.RevisemsgId
+ const inputValue =this.data.inputValue
+ let TabCur=this.data.TabCur
+ const list = this.data.OriginalmsgList
+ if (inputValue.length==0) {
+ wx.showToast({
+ title: '修改内容不能为空',
+ icon: 'none',
+ duration:2000
+ })
+
+ return
+ }
+
+ for (let index = 0; index < list.length; index++) {
+ const element = list[list.length-index-1];
+ if (id==element.id) {
+ try {
+ const result = await this.updateConversation(
+ element.guid, // 会话ID
+ inputValue, // 新内容
+ element.sendMethod, // 发送方式
+ element.location, // 定位信息(可选)
+ element.isSelf // 消息类型(可选)
+ );
+ list[list.length-index-1].content=inputValue
+ list[list.length-index-1].time=result.data.receivedTime
+ this.setData({ OriginalmsgList: list })
+ this.tabSelect1(TabCur)
+ return
+ } catch (error) {
+ wx.showToast({
+ title: '网络异常修改内容失败!',
+ icon: 'none',
+ duration:2000
+ })
+ list[list.length-index-1].time=this.GetTimeDate()
+ list[list.length-index-1].lock='Unlock'
+ this.setData({ OriginalmsgList: list })
+ this.tabSelect1(TabCur)
+ return
+ }
+
+
+ }
+
+ }
+ }else if (e.currentTarget.id=='Withdrawal') {
+ const id = this.data.RevisemsgId
+
+ let TabCur=this.data.TabCur
+ const list = this.data.OriginalmsgList
+ let Nlist =this.data.OriginalmsgList
+
+ for (let index = 0; index < list.length; index++) {
+ const element = list[list.length-index-1];
+ if (id==element.id) {
+ try {
+ const result = await this.deleteConversation(element.guid);
+ Nlist.splice(list.length-index-1,1);
+ this.setData({ OriginalmsgList: Nlist,qinputTxt:element.content ,voiceMode:false})
+ this.tabSelect1(TabCur)
+ return
+ } catch (error) {
+ wx.showToast({
+ title: '网络异常修改内容失败!',
+ icon: 'none',
+ duration:2000
+ })
+ list[list.length-index-1].time=this.GetTimeDate()
+ list[list.length-index-1].lock='Unlock'
+ this.setData({ OriginalmsgList: list })
+ this.tabSelect1(TabCur)
+ return
+ }
+
+
+ }
+
+ }
+ }
+
+ },
+ GetTimeDate(){
+// 1. 获取当前时间戳
+let timestamp = Date.now(); // 例如:1733225035000
+
+// 2. 将时间戳转换为 Date 对象
+let dateObj = new Date(timestamp);
+
+// 3. 获取各个时间部分并进行格式化
+let year = dateObj.getFullYear(); // 年份(四位)
+let month = String(dateObj.getMonth() + 1).padStart(2, '0'); // 月份(补零)
+let day = String(dateObj.getDate()).padStart(2, '0'); // 日期(补零)
+let hours = String(dateObj.getHours()).padStart(2, '0'); // 小时(补零)
+let minutes = String(dateObj.getMinutes()).padStart(2, '0'); // 分钟(补零)
+let seconds = String(dateObj.getSeconds()).padStart(2, '0'); // 秒(补零)
+
+// 4. 拼接成所需的字符串格式
+// 格式:YYYY-MM-DD HH:mm:ss("yyyy-MM-dd HH:mm:ss")
+let formattedString1 = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+return formattedString1
+},
+
+/**
+ * 软删除会话记录
+ * @param {number|string} id - 会话记录ID
+ * @returns {Promise} - API响应结果
+ */
+async deleteConversation(id) {
+ let UserKey = wx.getStorageSync('openid');
+ const apiRes = await new Promise((resolve, reject) => {
+ wx.request({
+ url: `${config.baseUrl}/api/Check/DeleteConversation`,
+ method: 'POST',
+ data: {
+ Guid: id,
+ UserKey: UserKey
+ },
+ success: res => {
+ resolve(res);
+ },
+ fail: (err) => {
+ console.error('删除会话记录失败:', err);
+ reject(err);
+ }
+ });
+ });
+ return apiRes;
+},
+/**
+ * 更新会话记录
+ * @param {number|string} id - 会话记录ID
+ * @param {string} content - 新的会话内容
+ * @param {string} sendMethod - 新的发送方式
+ * @param {string} [location] - 新的用户定位信息(可选)
+ * @param {number} [messageType] - 消息类型:1-公有消息,2-私有消息(可选)
+ * @returns {Promise} - API响应结果
+ */
+async updateConversation(id, content, sendMethod, location = '', messageType = null) {
+ let UserKey = wx.getStorageSync('openid');
+ const apiRes = await new Promise((resolve, reject) => {
+ wx.request({
+ url: `${config.baseUrl}/api/Check/UpdateConversation`,
+ method: 'POST',
+ data: {
+ Guid: id,
+ UserKey: UserKey,
+ ConversationContent: content,
+ SendMethod: sendMethod,
+ UserLocation: location,
+ MessageType: messageType
+ },
+ success: res => {
+ resolve(res);
+ },
+ fail: (err) => {
+ console.error('更新会话记录失败:', err);
+ reject(err);
+ }
+ });
+ });
+ return apiRes;
+},
+// 获得焦点时的处理函数
+onTextareaFocus: function(e) {
+ console.log('textarea 获得焦点', e.detail);
+ // 示例:记录焦点状态,用于UI变化
+ this.setData({
+ isFocused: true
+ });
+},
+
+// 失去焦点时的处理函数
+onTextareaBlur: function(e) {
+ console.log('textarea 失去焦点', e.detail.value);
+ // 示例:进行表单验证或提交数据
+ this.setData({
+ isFocused: false
+ });
+
+},
+
+
+ GetmyScrollhight(){
+
+ wx.createSelectorQuery()
+ .in(this)
+ .select('#myScroll')
+ .boundingClientRect(rect => {
+ if (rect) {
+ const topPx = rect.top; // px
+ const bottomPx = 10 / 2; // 10rpx → 5px(2倍屏)
+ //const heightPx = screenHeight - topPx - bottomPx;
+
+ wx.createSelectorQuery()
+ .in(this)
+ .select('#BottomFrame') //底部输入栏
+ .boundingClientRect(nrect => {
+ if (nrect) {
+ const BottomFrametopPx = nrect.top; // px
+ const BottomFramebottomPx = 40 / 2; // 10rpx → 5px(2倍屏)
+ const BottomFrameheightPx = BottomFrametopPx-topPx- bottomPx;
+
+
+ // 3. 转 rpx 并写入
+ this.setData({
+ scrollHeight: BottomFrameheightPx //* 2 // px→rpx
+ });
+ }
+ })
+ .exec();
+
+
+ }
+ })
+ .exec();
+ }
+})
\ No newline at end of file
diff --git a/CommunicationRecords/pages/chat/chat.json b/CommunicationRecords/pages/chat/chat.json
new file mode 100644
index 0000000..8835af0
--- /dev/null
+++ b/CommunicationRecords/pages/chat/chat.json
@@ -0,0 +1,3 @@
+{
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/CommunicationRecords/pages/chat/chat.wxml b/CommunicationRecords/pages/chat/chat.wxml
new file mode 100644
index 0000000..8c692bf
--- /dev/null
+++ b/CommunicationRecords/pages/chat/chat.wxml
@@ -0,0 +1,167 @@
+
+
+
+
+
+
+
+
+ {{weChatName}}
+
+
+
+
+
+ 全部信息
+
+
+ 公开信息
+
+
+ 个人信息
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ pullText }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ({{!item.voicetime? 0:item.voicetime}} s)
+ {{item.time}}
+
+
+ {{item.content}}
+ 发送中...
+ 发送失败,点击重发
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{resultText}}
+ 正在转换中...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 修改信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CommunicationRecords/pages/chat/chat.wxss b/CommunicationRecords/pages/chat/chat.wxss
new file mode 100644
index 0000000..9847668
--- /dev/null
+++ b/CommunicationRecords/pages/chat/chat.wxss
@@ -0,0 +1,408 @@
+page{background:#ededed;}
+
+.top-bar{
+ height:88rpx;
+ line-height:88rpx;
+ text-align:center;
+ color :#000;
+ background:#f0f5f5;
+ font-size:34rpx;
+ display: flex;
+}
+.msg-area{
+ position:fixed;
+ top:88rpx;
+ bottom:20rpx;
+ left:0;
+ right:0;
+ padding:20rpx;
+ box-sizing:border-box;
+}
+.date-bar{
+ text-align:center;
+ font-size:24rpx;
+ color:#888;
+ background:#e5e5e5;
+ line-height:44rpx;
+ border-radius:22rpx;
+ margin:20rpx auto;
+ padding:0 20rpx;
+ display:inline-block;
+}
+.msg-item{
+ display:flex;
+ flex-direction:column;
+ margin-bottom:20rpx;
+}
+.msg-item.self{
+ align-items:flex-end;
+}
+.msg-item.self1{
+ align-items:flex-end;
+}
+.bubble{
+ max-width:70%;
+ padding: 0rpx 20rpx 12rpx 20rpx;
+ border-radius:12rpx;
+ background:#fff;
+ font-size:32rpx;
+
+}
+.msg-item.self .bubble{
+ background:#95ec69;
+}
+.msg-item.self1 .bubble{
+ background:#ADD8E6;
+}
+.time{
+ font-size:24rpx;
+ color:#888;
+ margin-top:8rpx;
+ margin-left:10rpx;
+}
+
+
+
+/* 底部整体 */
+.input-bar{
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 180rpx;
+ background: #fff;
+ display: flex;
+ align-items: center;
+ padding: 0 20rpx;
+ border-top: 1rpx solid #e0e0e0;
+}
+
+/* 语音/键盘切换 */
+.switch-btn{
+ width: 36rpx; /* 微信同宽 */
+ height: 76rpx;
+ line-height: 76rpx;
+ background: #f5f5f5;
+ border-radius: 12rpx;
+ margin-right: 16rpx;
+ padding: 0;
+ font-size: 40rpx;
+ flex-shrink: 0; /* 防止被挤压 */
+ flex: 1;
+ align-items: center;
+ justify-content: center;
+}
+
+/* 文字模式容器 */
+.text-row{
+ flex: 9;
+ display: flex;
+ align-items: center;
+}
+
+/* 输入框:占满剩余空间 */
+.input-box{
+ flex: 4;
+ height: 150rpx;
+ background: #f5f5f5;
+ border-radius: 18rpx;
+ padding: 6 6rpx;
+ margin-right: 16rpx;
+ margin: 8rpx;
+
+}
+
+/* 发送按钮:固定 76 rpx */
+.send-btn{
+ width: 36rpx;
+ height: 70rpx;
+ line-height: 76rpx;
+ padding: 0;
+ background: #07c160;
+ color: #fff;
+ font-size: 26rpx;
+ border-radius: 12rpx;
+ flex-shrink: 0;
+ flex: 1;
+ margin: 8rpx;
+}
+
+/* 语音模式大按钮 */
+
+.voice-row{
+ flex: 9;
+ height: 80%;
+ align-items: center;
+ justify-content: center;
+}
+.voice-record-btn{
+ font-size: 20rpx;
+ width: 50%;
+ height: 100%;
+ /* flex: 1; */
+ /*
+ height: 76rpx;
+ line-height: 76rpx;
+ border-radius: 12rpx;
+ background: #f5f5f5;
+
+ padding: 0 12rpx;
+ white-space: pre-line;
+ transition: background .15s; */
+}
+.voice-record-btn.recording{
+ background: #FF3B30;
+ color: #fff;
+}
+.voice-record-btn.cancel{
+ background: #FF3B30;
+ color: #fff;
+}
+.voice-btn-group{
+
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ gap: 1rpx; /* 两按钮间距 10 rpx */
+}
+
+.nav {
+ white-space: nowrap;
+}
+.nav .cu-item {
+ height: 90%;
+ display: inline-block;
+ line-height: 90rpx;
+ margin: 0 10rpx;
+ padding: 0 5rpx;
+ font-size: 26rpx;
+}
+.text-center {
+ text-align: center;
+}
+.text-blue {
+ color: #007aff;
+}
+.curline {
+ border-bottom: 10rpx solid #007aff; /* 蓝色,粗细 5rpx */
+}
+
+/* 实时语音转文字显示区域 */
+.recording-toast {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ /* height: 50rpx; */
+ width: 100vw;
+ transform: translate(-30%, -30%);
+ background-color: rgba(0, 0, 0, 0.7);
+ padding: 30rpx;
+ border-radius: 16rpx;
+ z-index: 1000;
+ /* max-width: 80%;
+ min-width: 300rpx; */
+ max-height: 50vh;
+ min-height: 50rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+/* 添加消息状态样式 */
+.msg-status {
+ font-size: 24rpx;
+ margin-left: 10rpx;
+}
+.msg-status.error {
+ color: #ff3b30;
+}
+.recording-text {
+ color: #fff;
+ font-size: 34rpx;
+ text-align: center;
+ line-height: 1.4;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+/* 实时语音转文字显示区域 */
+.recording-toast {
+ position: fixed;
+ top: 40%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background-color: rgba(0, 0, 0, 0.7);
+ padding: 30rpx;
+ border-radius: 16rpx;
+ z-index: 1000;
+ max-width: 80%;
+ min-width: 300rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.recording-text {
+ color: #fff;
+ font-size: 34rpx;
+ text-align: center;
+ line-height: 1.4;
+ word-wrap: break-word;
+ word-break: break-all;
+}
+.cu-modal {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1110;
+ opacity: 0;
+ outline: 0;
+ text-align: center;
+ -ms-transform: scale(1);
+ transform: scale(1);
+ backface-visibility: hidden;
+ perspective: 2000rpx;
+ background: rgba(0, 0, 0, 0.6);
+ transition: all 0.3s ease-in-out 0s;
+ pointer-events: none;
+}
+
+.cu-modal::before {
+ content: "\200B";
+ display: inline-block;
+ /* height: 100%; */
+ vertical-align: middle;
+}
+
+.cu-modal.show {
+ opacity: 1;
+ transition-duration: 0.3s;
+ -ms-transform: scale(1);
+ transform: scale(1);
+ overflow-x: hidden;
+ overflow-y: auto;
+ pointer-events: auto;
+}
+.user-info {
+ display: flex;
+ align-items: center;
+}
+.cu-dialog {
+
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ margin-left: auto;
+ margin-right: auto;
+ width: 680rpx;
+ max-width: 100%;
+ background-color: #f8f8f8;
+ border-radius: 10rpx;
+ overflow: hidden;
+}
+
+.cu-modal.bottom-modal::before {
+ vertical-align: bottom;
+}
+
+.cu-modal.bottom-modal .cu-dialog {
+ width: 100%;
+ border-radius: 0;
+}
+
+.cu-modal.bottom-modal {
+ margin-bottom: -1000rpx;
+}
+
+.cu-modal.bottom-modal.show {
+ margin-bottom: 0;
+}
+.bg-white {
+ background-color: #ffffff;
+ color: #666666;
+}
+
+.justify-end {
+ justify-content: flex-end;
+}
+.justify-between {
+ justify-content: space-between;
+}
+.cu-bar .action {
+ display: flex;
+ align-items: center;
+ height: 100%;
+ justify-content: center;
+ max-width: 100%;
+}
+
+.cu-bar .content {
+ position: absolute;
+ text-align: center;
+ width: calc(100% - 340rpx);
+ left: 0;
+ right: 0;
+ bottom: 0;
+ top: 0;
+ margin: auto;
+ height: 60rpx;
+ font-size: 32rpx;
+ line-height: 60rpx;
+ cursor: none;
+ pointer-events: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+.cu-bar {
+ display: flex;
+ position: relative;
+ align-items: center;
+ min-height: 100rpx;
+ justify-content: space-between;
+}
+.cu-bar .action {
+ display: flex;
+ align-items: center;
+ height: 100%;
+ justify-content: center;
+ max-width: 100%;
+}
+.text-red,
+.line-red,
+.lines-red {
+ color: #ff3b30;
+}
+.cu-bar .action>text[class*="cuIcon-"],
+.cu-bar .action>view[class*="cuIcon-"] {
+ font-size: 36rpx;
+}
+
+[class*="cuIcon-"] {
+ font-family: "cuIcon";
+ font-size: inherit;
+ font-style: normal;
+}
+.cuIcon-close:before {
+ content: "\e646";
+}
+.textarea {
+ width: 100%;
+ height: 150rpx;
+ padding: 10rpx;
+ box-sizing: border-box; /* 确保内边距不影响总宽度 */
+ word-wrap: break-word; /* 确保长内容也能换行 */
+ /*border: 1rpx solid #ddd; 可选,添加边框 */
+ border-radius: 8rpx; /* 可选,圆角 */
+}
+.Btextarea {
+ width: 100%;
+ height: 150rpx;
+ padding: 10rpx;
+ box-sizing: border-box; /* 确保内边距不影响总宽度 */
+ word-wrap: break-word; /* 确保长内容也能换行 */
+ border: 1rpx solid #ddd; /*可选,添加边框 */
+ border-radius: 8rpx; /* 可选,圆角 */
+}
\ No newline at end of file
diff --git a/CommunicationRecords/pages/chat/mock.js b/CommunicationRecords/pages/chat/mock.js
new file mode 100644
index 0000000..1bc246b
--- /dev/null
+++ b/CommunicationRecords/pages/chat/mock.js
@@ -0,0 +1,30 @@
+/**
+ * 本地历史消息 Mock
+ * 字段与真实接口保持一致,方便后续直接替换
+ */
+module.exports = [
+ {
+ id: 1,
+ content: '你好,这是本地历史消息!',
+ date: '2025-10-31',
+ time: '2025-10-31 10:30',
+ isSelf: 2,
+ showDate: true
+ },
+ {
+ id: 2,
+ content: '收到,准备替换为接口数据~',
+ date: '2025-10-31',
+ time: '2025-10-31 10:32',
+ isSelf: 1,
+ showDate: false
+ },
+ {
+ id: 3,
+ content: '跨天消息示例',
+ date: '2025-11-01',
+ time: '2025-11-01 09:00',
+ isSelf: 2,
+ showDate: true
+ }
+]
diff --git a/CommunicationRecords/pages/logs/logs.js b/CommunicationRecords/pages/logs/logs.js
index 6befce4..a86fd86 100644
--- a/CommunicationRecords/pages/logs/logs.js
+++ b/CommunicationRecords/pages/logs/logs.js
@@ -1,6 +1,6 @@
import { authorizeBatch } from '../../utils/authorize'
const util = require('../../utils/util.js')
-
+const app = getApp()
Page({
data: {
isAgree: false,
@@ -8,7 +8,6 @@ Page({
showAuthModal: false,
userInfo: null,
needReg: false,
- openid: '',
avatarUrl: '/images/Blvlogo.png',
nickName: '',
form: {
@@ -17,6 +16,14 @@ Page({
}
},
onLoad() {
+
+const isAgree = wx.getStorageSync('isAgree');
+
+if (typeof isAgree !== 'undefined'){
+ this.setData({ isAgree:isAgree });
+}
+
+
this.handleLogin()
},
onAvatar(e) {
@@ -61,13 +68,18 @@ Page({
UserKey: openid,
WeChatName:nickName,
PhoneNumber:form.phone,
- AvatarUrl:avatarUrl
+ AvatarUrl:""
},
success: res =>{
- if (res.data.success && res.data.data.userName && res.data.data.weChatName && res.data.data.phoneNumber) {
+
+ this.uploadAvatarToServer(avatarUrl,res.data.data.userKey)
+ if (res.data.success && res.data.data.userName && res.data.data.weChatName && res.data.data.phoneNumber) {
wx.setStorageSync('openid', res.data.data.userKey);
- this.setData({openid:res.data.data.userKey});
+ this.setData({openid:res.data.data.userKey});
+ app.globalData.userKey=res.data.data.userKey
+ app.globalData.weChatName=res.data.data.weChatName
+ app.globalData.avatarUrl=this.data.avatarUrl
wx.navigateTo({url: '/pages/chat/chat'});
}
else{
@@ -99,6 +111,8 @@ Page({
console.log(e)
this.setData({ isAgree: e.detail.value.length > 0 });
+ wx.setStorageSync('isAgree', this.data.isAgree);
+
},
openContract() {
@@ -134,6 +148,7 @@ Page({
//////////debugger
// 保存到全局
getApp().globalData.userInfo = userInfo;
+
await this.onGetAuth()
// 继续登录流程
await this.completeLogin();
@@ -162,7 +177,40 @@ async onGetAuth() {
})
}
},
-
+uploadAvatarToServer(tempFilePath,userKey) {
+ // 显示加载提示,提升用户体验
+ wx.showLoading({ title: '上传中...' });
+
+ wx.uploadFile({
+ url: 'https://wx-xcx-check.blv-oa.com:4433/api/Check/UploadFile', // 你的服务器上传接口
+ filePath: tempFilePath,
+ name: 'file', // 与后端约定的文件参数名
+ formData: {
+ 'rootPathType': 'Avatar', // 指定保存到 wwwroot/Avatar 目录
+ 'userKey': userKey // 指定要更新头像的用户
+ },
+ success: (res) => {
+ wx.hideLoading();
+ const data = JSON.parse(res.data); // 注意: uploadFile返回的data是字符串,需解析
+ if (data.success) {
+ // 上传成功,拿到服务器返回的永久链接
+ const permanentUrl = data.url;
+ this.setData({
+ avatarUrl: permanentUrl // 更新为永久链接
+ });
+ // 接下来可以将 permanentUrl 保存到本地缓存或发送给后端更新用户信息
+ wx.showToast({ title: '上传成功' });
+ } else {
+ wx.showToast({ title: '上传失败: ' + data.message, icon: 'none' });
+ }
+ },
+ fail: (err) => {
+ wx.hideLoading();
+ console.error('上传接口调用失败', err);
+ wx.showToast({ title: '网络错误', icon: 'none' });
+ }
+ });
+},
// 完整的登录流程
async completeLogin() {
@@ -190,14 +238,20 @@ async completeLogin() {
success: res =>{
wx.hideLoading()
if (res.data.success){
+
this.setData({openid: res.data.data.userKey});
console.log(this.data.openid)
wx.setStorageSync('openid', res.data.data.userKey);
+ app.globalData.userKey=res.data.data.userKey
+ app.globalData.weChatName=res.data.data.weChatName
+ app.globalData.avatarUrl=res.data.data.avatarUrl
+
}
if (res.data.success && res.data.data.userName && res.data.data.weChatName && res.data.data.phoneNumber) {
wx.navigateTo({url: '/pages/chat/chat'});
}
+
else{
wx.showToast({
title: `登录失败: 用户未注册。请先填写完整信息再进行登录`,
diff --git a/CommunicationRecords/pages/logs/logs.wxss b/CommunicationRecords/pages/logs/logs.wxss
index fdbdf09..6cce405 100644
--- a/CommunicationRecords/pages/logs/logs.wxss
+++ b/CommunicationRecords/pages/logs/logs.wxss
@@ -112,7 +112,7 @@ page {
.tip {
margin-top: 8rpx;
- font-size: 24rpx;
+ font-size: 28rpx;
color: #888;
}
/* wxss */
diff --git a/CommunicationRecords/utils/authorize.js b/CommunicationRecords/utils/authorize.js
new file mode 100644
index 0000000..28a646f
--- /dev/null
+++ b/CommunicationRecords/utils/authorize.js
@@ -0,0 +1,52 @@
+// utils/authorize.js
+const SCOPE_MAP = { // 中文提示,可扩展
+ 'scope.record':'录音',
+ 'scope.userLocation': '位置信息'
+}
+
+/**
+ * 一次性申请多个权限
+ * @param {Array} scopes 例:['scope.camera','scope.record']
+ * @returns {Promise