Parcourir la source

修复商城客服消息在消息列表中无法显示问题

蒋开心 il y a 2 semaines
Parent
commit
cbd9f8bdff

+ 12 - 12
common/chat-utils.js

@@ -1,21 +1,21 @@
 /**
- * 保存聊天記錄到本地緩存
- * @param {Object} data - 消息數據
- * @param {String} send - 'send' 表示發送的消息,其他表示接收的消息
+ * 保存聊天記錄到本地緩存(與 $appKit.send / runtime-bridge 統一前綴)
  */
+import { STORAGE } from '@/core/constants/storage-keys'
+
 export function setChat(data, send) {
-  let uid = send === 'send' ? data.to_id : data.form.id
+  const uid = send === 'send' ? data.to_id : data.form.id
+  const key = STORAGE.chatMsgPrefix + uid
   uni.getStorage({
-    key: 'wanlchat:message_' + uid,
-    success: function (res) {
-      // 只保存最近 100 條消息,超過的通過接口獲取歷史記錄
-      let arr = res.data.slice(-96)
+    key,
+    success(res) {
+      const arr = res.data.slice(-96)
       arr.push(data)
-      uni.setStorageSync('wanlchat:message_' + uid, arr)
+      uni.setStorageSync(key, arr)
     },
-    fail: function (res) {
-      uni.setStorageSync('wanlchat:message_' + uid, [data])
+    fail() {
+      uni.setStorageSync(key, [data])
     }
   })
   return data
-}
+}

+ 2 - 2
common/config/runtime-manifest.js

@@ -12,8 +12,8 @@ const ENDPOINTS = Object.freeze(
 )
 
 const IDENTITY = Object.freeze({
-	releaseLabel: '1.1.40',
-	numericBuild: '1140',
+	releaseLabel: '1.1.41',
+	numericBuild: '1141',
 	// 排查"看不到直播"期间临时开启,正式发布请改回 false
 	traceVerbose: false,
 	geoServiceKey: '',

+ 21 - 1
features/mall/gateway/im.js

@@ -10,6 +10,26 @@ export async function getChatHistory(params) {
   return post('/wanlshop/chat/history', params)
 }
 
+/** 会话列表 */
+export async function getChatLists(params = {}) {
+  return post('/wanlshop/chat/lists', params)
+}
+
+/** 删除会话 */
+export async function delChatSession(params) {
+  return post('/wanlshop/chat/del', params)
+}
+
+/** 清空某会话未读 */
+export async function clearChatUnread(params) {
+  return post('/wanlshop/chat/clear', params)
+}
+
+/** 全部已读 */
+export async function readAllChat(params = {}) {
+  return post('/wanlshop/chat/read', params)
+}
+
 /** 获取浏览过的商品(发给商家) */
 export async function getBrowsingToShop(params) {
   return post('/wanlshop/product/getBrowsingToShop', params)
@@ -24,4 +44,4 @@ export async function getOrderListToShop(params) {
 export async function getUploadConfig() {
   const { data } = await get('/wanlshop/common/uploadData')
   return data
-}
+}

+ 2 - 2
manifest.json

@@ -2,8 +2,8 @@
     "name" : "88live",
     "appid" : "__UNI__3F63D9A",
     "description" : "",
-    "versionName" : "1.1.40",
-    "versionCode" : 1140,
+    "versionName" : "1.1.41",
+    "versionCode" : 1141,
     "transformPx" : false,
     /* 5+App特有相关 */
     "app-plus" : {

+ 23 - 4
pages/notice/chat.vue

@@ -313,7 +313,8 @@
 const emotions = require('@/static/json/emotions.json')
 import { mapMutations } from 'vuex'
 import { getShopChat, getChatHistory, getBrowsingToShop, getOrderListToShop, getUploadConfig } from '@/features/mall/gateway/im'
-import { setChat } from '@/common/chat-utils.js'  // 新增這行
+import { setChat } from '@/common/chat-utils.js'
+import { STORAGE } from '@/core/constants/storage-keys'
 export default {
   data() {
     return {
@@ -383,7 +384,9 @@ export default {
       this.shop_avatar = res.data.avatar
       uni.setNavigationBarTitle({ title: res.data.shopname + (res.data.isOnline == 1 ? '-' + this.$t('chat.online') : '-' + this.$t('chat.offline')) })
       this.getMsgList(res.data.user_id)
-      // 新增:進入頁面時自動加載歷史消息
+      // 進入聊天頁:暫停全局角标提示,並清零該會話未讀
+      this.setIschat({ notice: false })
+      this.$store.dispatch('chat/update', { type: 'del', id: res.data.user_id }).catch(() => {})
       setTimeout(() => {
         this.loadHistory()
       }, 500)
@@ -408,14 +411,21 @@ export default {
   },
   onUnload() {
     uni.$off('onMessage', this.onSend)
+    if (this.to_id) {
+      this.$store.dispatch('chat/update', { type: 'del', id: this.to_id }).catch(() => {})
+    }
+    this.setIschat({ notice: true, number: 0 })
   },
   onShow() {
     this.scrollTop = 9999999
   },
   methods: {
+    ...mapMutations({
+      setIschat: 'chat/setIschat'
+    }),
     getMsgList(id) {
       uni.getStorage({
-        key: 'wanlchat:message_' + id,
+        key: STORAGE.chatMsgPrefix + id,
         success: res => {
           var list = res.data
           for (let i = 0; i < list.length; i++) {
@@ -491,8 +501,17 @@ export default {
         createtime: parseInt(new Date().getTime() / 1000)
       }
       this.onChat(JSON.parse(JSON.stringify(data)))
-      // 新增:保存到本地緩存
       setChat(data, 'send')
+      this.$store.dispatch('chat/update', {
+        type: 'send',
+        data,
+        shop: {
+          id: this.shop_id,
+          user_id: this.to_id,
+          name: this.shop_name,
+          avatar: this.shop_avatar
+        }
+      }).catch(() => {})
       this.$appKit.send(data)
     },
     addTextMsg(msg) {

+ 11 - 2
pages/notice/mall-notice/index.vue

@@ -64,7 +64,7 @@
 						</view>
 					</view>
 					<view class="action">
-						<view class="text-gray text-sm">{{ item.createtime }}</view>
+						<view class="text-gray text-sm">{{ $appKit.timeToChat(item.createtime) }}</view>
 						<view class="cu-tag bg-red" v-if="item.count > 0">{{ item.count }}</view>
 					</view>
 					<view class="move">
@@ -100,6 +100,10 @@ export default {
 			top: statusBarHeight,
 			height: statusBarHeight + uni.upx2px(90)
 		}
+		this.$store.dispatch('chat/get').catch(() => {})
+	},
+	onShow() {
+		this.$store.dispatch('chat/get').catch(() => {})
 	},
 	computed: {
 		...mapState(['chat', 'statistics'])
@@ -116,7 +120,12 @@ export default {
 			uni.navigateTo({ url })
 		},
 		handleChat(item) {
-			uni.navigateTo({ url: `/pages/notice/sys-notice/index?id=${item.id}` })
+			// item.id 为店铺 id;私信页按 shop_id 打开
+			if (this.$appKit && typeof this.$appKit.toChat === 'function') {
+				this.$appKit.toChat(item.id)
+			} else {
+				uni.navigateTo({ url: `/pages/notice/chat?shop_id=${item.id}` })
+			}
 		},
 		ListTouchStart(e) {
 			this.listTouchStart = e.touches[0].pageX

+ 1 - 1
pages/notice/notice.vue

@@ -4,7 +4,7 @@
     <view class="wanl-logistics-list margin-top-bj" v-if="dataList.length != 0">
       <block v-for="(item, index) in dataList" :key="item.id">
         <view class="text-center wanl-gray">
-          {{ item.createtime }}
+          {{ $appKit.timeToChat(item.createtime) }}
         </view>
         <view class="item margin-lr-bj margin-tb bg-white radius-bock padding-bj" @tap="handleTap(item.url)">
           <view class="title margin-bottom-bj">

+ 38 - 46
store/modules/chat.js

@@ -1,6 +1,12 @@
 // 店铺客服聊天模块
 import Vue from 'vue'
-import appSettings from '@/core/config/app-settings'
+import {
+	getChatLists,
+	delChatSession,
+	clearChatUnread,
+	readAllChat
+} from '@/features/mall/gateway/im'
+import { STORAGE } from '@/core/constants/storage-keys'
 
 export default {
 	namespaced: true,
@@ -25,35 +31,27 @@ export default {
 	actions: {
 		async get({ state, dispatch }) {
 			try {
-				const res = await uni.request({
-					url: '/wanlshop/chat/lists',
-					method: 'POST'
-				})
-				if (res && res.data) {
-					state.list = res.data
-					let count = 0
-					res.data.forEach(item => { count += item.count })
-					dispatch('storage', { type: 'statis', number: count })
-				}
+				const res = await getChatLists()
+				const rows = Array.isArray(res.data) ? res.data : (res.data && res.data.rows) || []
+				state.list = rows
+				let count = 0
+				rows.forEach(item => { count += Number(item.count) || 0 })
+				dispatch('storage', { type: 'statis', number: count })
 			} catch (e) {
 				console.error('[chat] get failed:', e)
 			}
 		},
 		async del({ state, dispatch }, index) {
-			let list = state.list
-			dispatch('storage', { type: 'del', number: list[index].count })
+			const list = state.list
+			const row = list[index]
+			if (!row) return
+			dispatch('storage', { type: 'del', number: row.count })
 			uni.removeStorage({
-				key: 'wanlchat:message_' + list[index].user_id,
-				success: () => {
-					console.log('[chat] 删除消息成功')
-				}
+				key: STORAGE.chatMsgPrefix + row.user_id,
+				success: () => {}
 			})
 			try {
-				await uni.request({
-					url: '/wanlshop/chat/del',
-					method: 'POST',
-					data: { id: list[index].user_id }
-				})
+				await delChatSession({ id: row.user_id })
 			} catch (e) {
 				console.error('[chat] del failed:', e)
 			}
@@ -62,17 +60,15 @@ export default {
 		async empty({ state, dispatch }) {
 			uni.showModal({
 				content: '確定將所有數據標為已讀嗎?',
-				success: res => {
-					if (res.confirm) {
-						state.list.forEach(item => { item.count = 0 })
-						dispatch('storage', { type: 'empty' })
-						uni.request({
-							url: '/wanlshop/chat/read',
-							method: 'POST',
-							success: () => {
-								uni.showToast({ title: '已全部標為已讀', icon: 'none' })
-							}
-						})
+				success: async res => {
+					if (!res.confirm) return
+					state.list.forEach(item => { item.count = 0 })
+					dispatch('storage', { type: 'empty' })
+					try {
+						await readAllChat()
+						uni.showToast({ title: '已全部標為已讀', icon: 'none' })
+					} catch (e) {
+						console.error('[chat] read failed:', e)
 					}
 				}
 			})
@@ -89,17 +85,13 @@ export default {
 				})
 				dispatch('storage', { type: 'del', number: counts })
 				try {
-					await uni.request({
-						url: '/wanlshop/chat/clear',
-						method: 'POST',
-						data: { id: id }
-					})
+					await clearChatUnread({ id })
 				} catch (e) {
 					console.error('[chat] update clear failed:', e)
 				}
 			} else if (type == 'chat' || type == 'send') {
 				let content = ''
-				let createtime = data.createtime
+				const createtime = data.createtime
 				let chat_id = 0
 				if (data.message.type == 'text') {
 					content = data.message.content.text
@@ -118,7 +110,7 @@ export default {
 				} else if (type == 'send') {
 					chat_id = data.to_id
 				}
-				let result = state.list.some(chat => {
+				const result = state.list.some(chat => {
 					if (chat.user_id == chat_id) {
 						if (type == 'chat') {
 							chat.count += 1
@@ -128,20 +120,20 @@ export default {
 						return true
 					}
 				})
-				if (!result) {
-					Vue.set(state.list, 0, {
+				if (!result && shop) {
+					state.list.unshift({
 						id: shop.id,
 						user_id: shop.user_id,
 						name: shop.name,
 						avatar: shop.avatar,
 						content: content,
-						count: 1,
+						count: type == 'chat' ? 1 : 0,
 						createtime: createtime
 					})
 				}
 			}
 		},
-		async storage({ state, rootState }, { type, number }) {
+		async storage({ rootState }, { type, number }) {
 			if (type == 'statis') {
 				rootState.statistics.notice.chat = number
 			} else if (type == 'order') {
@@ -157,7 +149,7 @@ export default {
 				rootState.statistics.notice.order = 0
 				rootState.statistics.notice.notice = 0
 			}
-			uni.setStorageSync('wanlshop:statis', rootState.statistics)
+			uni.setStorageSync(STORAGE.stats, rootState.statistics)
 		}
 	}
-}
+}

+ 50 - 21
store/modules/im.js

@@ -1,6 +1,7 @@
 import { SocketSession } from '@/store/services/socket-session'
 import appSettings from '@/core/config/app-settings'
 import { bindSocketClient, isLiveRoomPacket } from '@/features/im/socket-bind'
+import { setChat } from '@/common/chat-utils.js'
 
 let session = null
 
@@ -61,7 +62,7 @@ export default {
 		async bindClient(_, clientId) {
 			await bindSocketClient(clientId)
 		},
-		dispatchPacket({ dispatch }, message) {
+		dispatchPacket({ dispatch, rootState }, message) {
 			let packet
 			try {
 				packet = JSON.parse(message.data)
@@ -79,31 +80,59 @@ export default {
 				case 'init':
 					dispatch('bindClient', packet.client_id).catch(() => {})
 					return
-				case 'chat':
-				uni.$emit('im:chat', packet)
-				uni.$emit('onMessage', packet)
-				return
-			case 'service':
-				uni.$emit('onService', packet)
-				return
-			case 'live':
-				uni.$emit('onLiveMessage', packet)
-				return
-			case 'tip_done':
-			case 'end':
-			case 'gift':
-				uni.$emit('onLiveMessage', packet)
-				return
-			default:
-				break
+				case 'chat': {
+					// 落本地缓存 + 更新会话列表(对齐 88live chat/onMessage)
+					try {
+						setChat(packet, 'receive')
+					} catch (_) {}
+					const form = packet.form || {}
+					dispatch(
+						'chat/update',
+						{
+							type: 'chat',
+							data: packet,
+							shop: {
+								id: form.shop_id,
+								user_id: form.id,
+								name: form.name,
+								avatar: form.avatar
+							}
+						},
+						{ root: true }
+					).catch(() => {})
+					uni.$emit('im:chat', packet)
+					uni.$emit('onMessage', packet)
+					return
+				}
+				case 'order':
+					dispatch('chat/storage', { type: 'order' }, { root: true }).catch(() => {})
+					uni.$emit('im:order', packet)
+					return
+				case 'notice':
+					dispatch('chat/storage', { type: 'notice' }, { root: true }).catch(() => {})
+					uni.$emit('im:notice', packet)
+					return
+				case 'service':
+					uni.$emit('onService', packet)
+					return
+				case 'live':
+					uni.$emit('onLiveMessage', packet)
+					return
+				case 'tip_done':
+				case 'end':
+				case 'gift':
+					uni.$emit('onLiveMessage', packet)
+					return
+				default:
+					break
 			}
 
 			if (isLiveRoomPacket(packet)) {
 				uni.$emit('onLiveMessage', packet)
 			}
 		},
-		async fetchInbox() {
-			// 占位:登录后拉取会话列表,页面接入后实现具体接口
+		async fetchInbox({ dispatch }) {
+			await dispatch('chat/get', null, { root: true })
 		}
 	}
-}
+}