Ver Fonte

1.完善消息相关页面国际化 2.修复聊天页首次进入没有滑动到底部最新消息

蒋开心 há 2 semanas atrás
pai
commit
f440ab195a

+ 12 - 0
locale/en.json

@@ -1052,6 +1052,18 @@
   "notice.loadFailed": "Failed to load",
   "notice.loadMore": "Pull up to load more",
   "notice.noMore": "No more items",
+  "notice.headTitle": "Messages",
+  "notice.viewComment": "Comments",
+  "notice.viewNotice": "Notices",
+  "notice.viewSys": "System",
+  "notice.unreadMessages": " unread",
+  "notice.noUnread": "No unread messages",
+  "notice.noMessages": "No messages",
+  "notice.delete": "Delete",
+  "notice.from": "From",
+  "notice.noCouponLiveProduct": "No coupon, live or new product notices",
+  "chat.markAllReadConfirm": "Mark all messages as read?",
+  "chat.markAllReadSuccess": "All marked as read",
   "work": "Works",
   "my_like": "Likes",
   "send_work": "Publish Now",

+ 12 - 0
locale/zh-Hans.json

@@ -1025,6 +1025,18 @@
   "notice.loadFailed": "加载失败",
   "notice.loadMore": "上拉加载更多",
   "notice.noMore": "没有更多了",
+  "notice.headTitle": "消息中心",
+  "notice.viewComment": "查看评论",
+  "notice.viewNotice": "通知消息",
+  "notice.viewSys": "系统消息",
+  "notice.unreadMessages": "条未读消息",
+  "notice.noUnread": "暂无未读消息",
+  "notice.noMessages": "暂无消息",
+  "notice.delete": "删除",
+  "notice.from": "来自",
+  "notice.noCouponLiveProduct": "没有任何优惠券、直播、新品消息",
+  "chat.markAllReadConfirm": "确定将所有数据标为已读吗?",
+  "chat.markAllReadSuccess": "已全部标为已读",
   "work": "作品",
   "my_like": "喜欢",
   "send_work": "立即发布",

+ 12 - 0
locale/zh-Hant.json

@@ -1078,6 +1078,18 @@
   "notice.loadFailed": "加載失敗",
   "notice.loadMore": "上拉加載更多",
   "notice.noMore": "沒有更多了",
+  "notice.headTitle": "消息中心",
+  "notice.viewComment": "查看評論",
+  "notice.viewNotice": "通知消息",
+  "notice.viewSys": "系統消息",
+  "notice.unreadMessages": "條未讀消息",
+  "notice.noUnread": "暫無未讀消息",
+  "notice.noMessages": "暫無消息",
+  "notice.delete": "刪除",
+  "notice.from": "來自",
+  "notice.noCouponLiveProduct": "沒有任何優惠券、直播、新品消息",
+  "chat.markAllReadConfirm": "確定將所有數據標為已讀嗎?",
+  "chat.markAllReadSuccess": "已全部標為已讀",
   "work": "作品",
   "my_like": "喜歡",
   "send_work": "立即發布",

+ 1 - 1
pages.json

@@ -680,7 +680,7 @@
 			"path": "pages/notice/mall-notice/index",
 			"style": {
 				"navigationStyle": "custom",
-				"navigationBarTitleText": "%pagesNav.mallNotice%",
+				"navigationBarTitleText": "%notice.headTitle%",
 				"backgroundColor": "#f5f5f5",
 				"app-plus": {
 					"titleNView": false,

+ 111 - 57
pages/notice/chat.vue

@@ -388,7 +388,7 @@ export default {
       this.setIschat({ notice: false })
       this.$store.dispatch('chat/update', { type: 'del', id: res.data.user_id }).catch(() => {})
       setTimeout(() => {
-        this.loadHistory()
+        this.loadHistory({ bootstrap: true })
       }, 500)
     } catch (e) {
       console.error('[chat] getShopChat failed:', e)
@@ -417,35 +417,127 @@ export default {
     this.setIschat({ notice: true, number: 0 })
   },
   onShow() {
-    this.scrollTop = 9999999
+    if (this.msgList.length) {
+      this.scrollToLatest()
+    }
   },
   methods: {
     ...mapMutations({
       setIschat: 'chat/setIschat'
     }),
+    /** 滚到最新消息(强制变更 scrollTop,避免同值不生效) */
+    scrollToLatest() {
+      if (!this.msgList.length) return
+      const last = this.msgList[this.msgList.length - 1]
+      this.scrollAnimation = false
+      this.scrollToView = ''
+      this.scrollTop = 0
+      this.$nextTick(() => {
+        this.scrollTop = 9999999 + (Date.now() % 1000)
+        this.scrollToView = 'msg' + last.id
+        this.$nextTick(() => {
+          this.scrollAnimation = true
+        })
+      })
+    },
     getMsgList(id) {
-      uni.getStorage({
-        key: STORAGE.chatMsgPrefix + id,
-        success: res => {
-          var list = res.data
-          for (let i = 0; i < list.length; i++) {
-            if (list[i].type == 'chat' && list[i].message.type == 'img') {
-              list[i].message.content = this.setPicSize(list[i].message.content)
-              this.msgImgList.push(list[i].message.content.url)
-            }
-            if (list[i].type == 'chat' && list[i].message.type == 'text') {
-              list[i].message.content.text = this.replaceEmoji(list[i].message.content.text)
-            }
+      const primary = STORAGE.chatMsgPrefix + id
+      const legacy = 'wanlchat:message_' + id
+      let list = uni.getStorageSync(primary)
+      if (!Array.isArray(list) || !list.length) {
+        list = uni.getStorageSync(legacy)
+        // 旧 key 有数据时迁移到统一前缀
+        if (Array.isArray(list) && list.length) {
+          uni.setStorageSync(primary, list)
+        }
+      }
+      if (!Array.isArray(list) || !list.length) return
+      for (let i = 0; i < list.length; i++) {
+        if (list[i].type == 'chat' && list[i].message && list[i].message.type == 'img') {
+          list[i].message.content = this.setPicSize(list[i].message.content)
+          this.msgImgList.push(list[i].message.content.url)
+        }
+        if (list[i].type == 'chat' && list[i].message && list[i].message.type == 'text') {
+          list[i].message.content.text = this.replaceEmoji(list[i].message.content.text)
+        }
+      }
+      this.msgList = list
+      this.$nextTick(() => {
+        this.scrollToLatest()
+      })
+    },
+    async loadHistory(options) {
+      // scrolltoupper 传入事件对象;进页引导传 { bootstrap: true }
+      const bootstrap = !!(options && options.bootstrap)
+      if (this.isHistoryLoading || this.reload || !this.to_id) return
+      this.isHistoryLoading = true
+      this.scrollAnimation = false
+      const hadLocal = this.msgList.length > 0
+      // 上拉加载更多时锚定原第一条;首次进页要滚到最新,不能锚到顶部
+      const view_id = (!bootstrap && hadLocal) ? this.msgList[0].id : null
+      try {
+        const res = await getChatHistory({ to_id: this.to_id, page: this.current_page })
+        const page = res && res.data
+        let list = []
+        let currentPage = 1
+        let lastPage = 1
+        if (Array.isArray(page)) {
+          list = page
+        } else if (page && typeof page === 'object') {
+          list = page.data || page.rows || page.list || []
+          currentPage = Number(page.current_page) || 1
+          lastPage = Number(page.last_page) || currentPage
+        }
+        if (!Array.isArray(list)) list = []
+
+        // 先拷贝一份用于本地缓存(避免把表情 HTML 写回)
+        const forStore = currentPage == 1 ? JSON.parse(JSON.stringify(list)) : null
+
+        for (let i = 0; i < list.length; i++) {
+          if (list[i].type == 'chat' && list[i].message && list[i].message.type == 'img') {
+            list[i].message.content = this.setPicSize(list[i].message.content)
+            this.msgImgList.unshift(list[i].message.content.url)
           }
-          this.msgList = list
-          this.$nextTick(() => {
-            this.scrollTop = 9999
+          if (list[i].type == 'chat' && list[i].message && list[i].message.type == 'text') {
+            list[i].message.content.text = this.replaceEmoji(list[i].message.content.text)
+          }
+        }
+        list.sort(function (a, b) {
+          return (a.updatetime || a.createtime || 0) - (b.updatetime || b.createtime || 0)
+        })
+
+        if (currentPage == 1) {
+          // 本地已有且服务端本页为空时,保留本地,避免被清空
+          if (list.length || !hadLocal) {
+            this.msgList = list
+          }
+          if (forStore && forStore.length && this.to_id) {
+            uni.setStorageSync(STORAGE.chatMsgPrefix + this.to_id, forStore)
+          }
+        } else {
+          this.msgList = list.concat(this.msgList)
+        }
+
+        this.$nextTick(() => {
+          if (bootstrap || !view_id) {
+            this.scrollToLatest()
+          } else {
+            this.scrollToView = 'msg' + view_id
             this.$nextTick(() => {
               this.scrollAnimation = true
             })
-          })
+          }
+        })
+
+        if (currentPage >= lastPage || list.length === 0) {
+          this.reload = true
+        } else {
+          this.current_page = currentPage + 1
         }
-      })
+      } catch (e) {
+        console.error('[chat] loadHistory failed:', e)
+      }
+      this.isHistoryLoading = false
     },
     onChat(msg) {
       if (msg.type == 'system') {
@@ -463,7 +555,6 @@ export default {
     },
     onSend(msg) {
       if (msg.form.id == this.to_id) {
-        // 新增:保存到本地緩存
         setChat(msg, 'receive')
         if (msg.type == 'system') {
           if (msg.msg.type == 'text') this.addSystemTextMsg(msg)
@@ -566,43 +657,6 @@ export default {
     tabSelect(e) {
       this.TabCur = e.currentTarget.dataset.id
     },
-    async loadHistory() {
-      if (this.isHistoryLoading || this.reload) return
-      this.isHistoryLoading = true
-      this.scrollAnimation = false
-      let view_id = this.msgList[0].id
-      try {
-        const res = await getChatHistory({ to_id: this.to_id, page: this.current_page })
-        let list = res.data.data
-        for (let i = 0; i < list.length; i++) {
-          if (list[i].type == 'chat' && list[i].message.type == 'img') {
-            list[i].message.content = this.setPicSize(list[i].message.content)
-            this.msgImgList.unshift(list[i].message.content.url)
-          }
-          if (list[i].type == 'chat' && list[i].message.type == 'text') {
-            list[i].message.content.text = this.replaceEmoji(list[i].message.content.text)
-          }
-        }
-        list.sort(function (a, b) {
-          return a.updatetime - b.updatetime
-        })
-        this.msgList = res.data.current_page == 1 ? list : list.concat(this.msgList)
-        this.$nextTick(() => {
-          this.scrollToView = 'msg' + view_id
-          this.$nextTick(() => {
-            this.scrollAnimation = true
-          })
-        })
-        if (res.data.current_page == res.data.last_page) {
-          this.reload = true
-        } else {
-          this.current_page = res.data.current_page + 1
-        }
-      } catch (e) {
-        console.error('[chat] loadHistory failed:', e)
-      }
-      this.isHistoryLoading = false
-    },
     setPicSize(content) {
       let maxW = uni.upx2px(350)
       let maxH = uni.upx2px(350)

+ 10 - 9
pages/notice/mall-notice/index.vue

@@ -11,7 +11,7 @@
 					<text class="wlIcon-fanhui1" style="margin-left: 0;" @tap="handleBack"></text>
 				</view>
 				<view class="content" :style="{ top: sys.top + 'px' }">
-					通知消息
+					{{ $t('notice.headTitle') }}
 				</view>
 				<view class="action">
 					<text class="wlIcon-qingkong" @tap="empty"></text>
@@ -22,8 +22,8 @@
 		<!-- 消息中心工具栏 -->
 		<view class="wanl-notice bg-bgcolor">
 			<view class="tool">
-				<view class="text-sm margin-right" v-if="statistics.notice.chat > 0">{{ statistics.notice.chat }}條未讀消息</view>
-				<view class="text-sm margin-right" v-else>暫無未讀消息</view>
+				<view class="text-sm margin-right" v-if="statistics.notice.chat > 0">{{ statistics.notice.chat }}{{ $t('notice.unreadMessages') }}</view>
+				<view class="text-sm margin-right" v-else>{{ $t('notice.noUnread') }}</view>
 			</view>
 			<!-- 消息中心模式选择 -->
 			<view class="mode padding-bj">
@@ -31,19 +31,19 @@
 					<!-- 查看评论 -->
 					<view class="logistics" @tap="handleNav('/pages/user/comment/comment')">
 						<text class="wlIcon-liuyan-fill"></text>
-						查看評論
+						{{ $t('notice.viewComment') }}
 						<view class="cu-tag badge" v-if="statistics.notice.order != 0">{{ statistics.notice.order }}</view>
 					</view>
 					<!-- 查看通知 -->
 					<view class="notice" @tap="handleNav('/pages/notice/notice')">
 						<text class="wlIcon-tongzhi"></text>
-						通知消息
+						{{ $t('notice.viewNotice') }}
 						<view class="cu-tag badge" v-if="statistics.notice.notice != 0">{{ statistics.notice.notice }}</view>
 					</view>
 					<!-- 查看系统消息 -->
 					<view class="Interaction" @tap="handleNav('/pages/notice/sys-notice/index')">
 						<text class="wlIcon-liuyan-fill"></text>
-						系統消息
+						{{ $t('notice.viewSys') }}
 					</view>
 				</view>
 			</view>
@@ -68,13 +68,13 @@
 						<view class="cu-tag bg-red" v-if="item.count > 0">{{ item.count }}</view>
 					</view>
 					<view class="move">
-						<view class="bg-red" @tap.stop="del(index)">刪除</view>
+						<view class="bg-red" @tap.stop="del(index)">{{ $t('notice.delete') }}</view>
 					</view>
 				</view>
 			</view>
 		</view>
 		<!-- 消息中心空消息提示 -->
-		<wanl-empty v-else src="notice_default3x" text="暫無消息" />
+		<wanl-empty v-else src="notice_default3x" :text="$t('notice.noMessages')" />
 		<view class="edgeInsetBottom"></view>
 	</view>
 </template>
@@ -100,6 +100,7 @@ export default {
 			top: statusBarHeight,
 			height: statusBarHeight + uni.upx2px(90)
 		}
+		uni.setNavigationBarTitle({ title: this.$t('notice.headTitle') })
 		this.$store.dispatch('chat/get').catch(() => {})
 	},
 	onShow() {
@@ -166,4 +167,4 @@ export default {
 	overflow: hidden;
 	padding-top: 96rpx;
 }
-</style>
+</style>

+ 4 - 3
pages/notice/notice.vue

@@ -15,13 +15,13 @@
             <image :src="$appKit.oss(item.image, 82, 82)"></image>
             <view class="padding-xs flex flex-wrap align-content-between">
               <view class="text-df margin-bottom-xs">{{ item.content }}</view>
-              <text class="text-sm wanl-gray">來自 {{ item.come }}</text>
+              <text class="text-sm wanl-gray">{{ $t('notice.from') }} {{ item.come }}</text>
             </view>
           </view>
         </view>
       </block>
     </view>
-    <wanl-empty src="notice_default3x" text="沒有任何優惠券、直播、新品消息" v-else />
+    <wanl-empty src="notice_default3x" :text="$t('notice.noCouponLiveProduct')" v-else />
     <view class="edgeInsetBottom"></view>
   </view>
 </template>
@@ -39,12 +39,13 @@ export default {
       status: 'more',
       contentText: {
         contentdown: ' ',
-        contentrefresh: '加載中...',
+        contentrefresh: '',
         contentnomore: ''
       }
     }
   },
   onLoad() {
+    this.contentText.contentrefresh = this.$t('notice.loading')
     this.loadData()
     // 清除本地角标
     this.$store.commit('statistics/noticec', { notice: 0 })

+ 16 - 2
store/modules/chat.js

@@ -58,15 +58,29 @@ export default {
 			Vue.delete(state.list, index)
 		},
 		async empty({ state, dispatch }) {
+			const translate = (key, fallback) => {
+				try {
+					const app = typeof getApp === 'function' ? getApp() : null
+					const vm = app && app.$vm
+					if (vm && typeof vm.$t === 'function') {
+						const v = vm.$t(key)
+						if (v && v !== key) return v
+					}
+				} catch (_) {}
+				return fallback
+			}
 			uni.showModal({
-				content: '確定將所有數據標為已讀嗎?',
+				content: translate('chat.markAllReadConfirm', 'Mark all as read?'),
 				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' })
+						uni.showToast({
+							title: translate('chat.markAllReadSuccess', 'Done'),
+							icon: 'none'
+						})
 					} catch (e) {
 						console.error('[chat] read failed:', e)
 					}