fix(customer-service): 修复在线客服功能使其可用

- 在微信客服按钮补全必要属性 sessionFrom、onContact、showMessageCard 和 sendMessageTitle
- 将按钮样式由 Tailwind 类改为内联样式,避免 border-0 干扰原生按钮渲染
- 添加真机预览测试提示,解决开发者工具无法使用问题
- `ShopChatMessage` 和相关接口新增 conversationId 字段支持消息会话关联
- 消息发送时补全 conversationId 和发送人 ID,保证消息关联准确
- 将会话列表中引用的不存在字段 lastMessage 替换为 content
- 移除无用的 useReachBottom,改用 ScrollView 的 onScrollToLower 事件加载历史消息
- 删除未使用的 scrollToBottom ref
- 增加条件守卫避免非历史展开时加载更多消息
This commit is contained in:
2026-07-14 20:49:28 +08:00
parent 78abab1364
commit 889a0f983e
3 changed files with 83 additions and 16 deletions

View File

@@ -244,3 +244,34 @@ adapter `/list` 接口忽略分页,一次返回全部收藏;前端 `listShop
1.`useCartContext` 额外解构 `totalCount``refresh`
2. 引入 `useDidShow`,页面显示时(已登录)调 `refresh()` 拉取最新购物车,保证角标准确
3. 购物车图标外包一层 `relative` 容器,`totalCount > 0` 时右上角显示红色圆角角标(>99 显示 `99+`),样式与商城列表页浮动购物车角标一致
## 在线客服功能修复2026-07-14
### 问题
`pages/user/customer-service/index` 在线客服功能使用不了,用户已在微信后台添加客服人员。
### 根因(多个问题叠加)
1. **`openType="contact"` 按钮缺少关键属性**:缺少 `sessionFrom`(会话来源标识)、`onContact`(客服回调)、`showMessageCard`/`sendMessageTitle`(客服消息卡片),且按钮被 Tailwind `border-0` 类可能干扰原生渲染
2. **开发者工具限制**`open-type="contact"` 在微信开发者工具中不生效,只能在真机上使用,页面缺少提示
3. **自定义聊天系统消息发送缺失 `conversationId`**`addShopChatMessage` 调用未传 `conversationId`,消息无法关联到会话;`ShopChatMessage` 模型本身也缺少该字段
4. **消息发送缺失 `formUserId`**:发送人 ID 未设置
5. **`conv.lastMessage` 字段不存在**`ShopChatConversation` 模型只有 `content` 字段,代码引用了不存在的 `lastMessage`
6. **`useReachBottom` 用错场景**:页面使用 `ScrollView` 组件,`useReachBottom` 是页面级滚动钩子,对 ScrollView 无效,应改用 `onScrollToLower`
7. **`scrollToBottom` ref 设了但从未使用**:死代码
### 修改
1. **`src/api/shop/shopChatMessage/model/index.ts`**
- `ShopChatMessage` 接口新增 `conversationId?: number`
- `ShopChatMessageParam` 接口新增 `conversationId?: number`
2. **`src/pages/user/customer-service/index.tsx`**(全面修复):
- 微信客服按钮补全 `sessionFrom="customer_service"``onContact``showMessageCard``sendMessageTitle`
- 按钮样式从 Tailwind 类改为 inline style避免 `border-0` 干扰原生按钮),显式设置 `border: 'none'`
- 添加"需真机预览测试"提示文字
- `addShopChatMessage` 调用补全 `conversationId``formUserId`(从 `Taro.getStorageSync('UserId')` 获取)
- `conv.lastMessage` 全部改为 `conv.content`
- 会话列表更新 `lastMessage: text` 改为 `content: text`
- 移除 `useReachBottom`,改用 ScrollView `onScrollToLower` + `lowerThreshold={50}`
- 移除未使用的 `scrollToBottom` ref
- `pageShopChatMessage` 参数去掉 `as any` 断言(模型已支持 `conversationId`
- 新增 `getCurrentUserId()` 辅助函数
- `handleScrollToLower` 增加 `showHistory` 条件守卫(仅展开历史时才加载更多)

View File

@@ -6,6 +6,8 @@ import type { PageParam } from '@/api';
export interface ShopChatMessage {
// 自增ID
id?: number;
// 会话ID
conversationId?: number;
// 发送人ID
formUserId?: number;
// 发送人名称
@@ -60,4 +62,5 @@ export interface ShopChatMessage {
export interface ShopChatMessageParam extends PageParam {
id?: number;
keywords?: string;
conversationId?: number;
}

View File

@@ -1,13 +1,13 @@
import React, { useEffect, useState, useCallback, useRef } from 'react'
import { View, Text, Button, Input, ScrollView } from '@tarojs/components'
import Taro, { useReachBottom } from '@tarojs/taro'
import Taro from '@tarojs/taro'
import NavBar from '@/components/NavBar'
import LoadMore from '@/components/common/LoadMore'
import EmptyState from '@/components/common/EmptyState'
import { pageShopChatConversation, addShopChatConversation } from '@/api/shop/shopChatConversation'
import { pageShopChatMessage, addShopChatMessage } from '@/api/shop/shopChatMessage'
import type { ShopChatConversation, ShopChatConversationParam } from '@/api/shop/shopChatConversation/model'
import type { ShopChatMessage } from '@/api/shop/shopChatMessage/model'
import type { ShopChatMessage, ShopChatMessageParam } from '@/api/shop/shopChatMessage/model'
import type { PageResult } from '@/api'
definePageConfig({
@@ -29,7 +29,6 @@ const CustomerServicePage: React.FC = () => {
const [hasMore, setHasMore] = useState(true)
const [msgPage, setMsgPage] = useState(1)
const [showHistory, setShowHistory] = useState(false)
const scrollToBottom = useRef(false)
const isOnline = () => {
const now = new Date()
@@ -37,6 +36,12 @@ const CustomerServicePage: React.FC = () => {
return h >= 9 && h < 21
}
// 获取当前用户ID
const getCurrentUserId = (): number | undefined => {
const id = Taro.getStorageSync('UserId')
return id || undefined
}
// 加载会话列表
const loadConversations = useCallback(async () => {
setLoading(true)
@@ -68,19 +73,19 @@ const CustomerServicePage: React.FC = () => {
const loadMessages = useCallback(async (conversationId: number, pageNum: number = 1, isLoadMore = false) => {
if (isLoadMore) setLoadingMore(true)
try {
const result = await pageShopChatMessage({
const params: ShopChatMessageParam = {
conversationId,
page: pageNum,
limit: 20,
order: 'asc',
sort: 'createTime',
} as any)
}
const result = await pageShopChatMessage(params)
if (result?.list) {
if (isLoadMore) {
setMessages(prev => [...result.list!, ...prev])
} else {
setMessages(result.list)
scrollToBottom.current = true
}
setHasMore((result.list.length ?? 0) >= 20)
setMsgPage(pageNum)
@@ -97,11 +102,12 @@ const CustomerServicePage: React.FC = () => {
loadConversations()
}, [loadConversations])
useReachBottom(() => {
if (hasMore && currentConversation && !loadingMore) {
// ScrollView 滚动到底部加载更多历史消息
const handleScrollToLower = () => {
if (hasMore && currentConversation && !loadingMore && showHistory) {
loadMessages(currentConversation.id!, msgPage + 1, true)
}
})
}
// 创建新会话
const ensureConversation = async (): Promise<ShopChatConversation | null> => {
@@ -140,18 +146,21 @@ const CustomerServicePage: React.FC = () => {
return
}
const userId = getCurrentUserId()
await addShopChatMessage({
conversationId: conv.id,
content: text,
type: 'text',
formUserId: userId,
toUserId: 0, // 发送给客服(服务端路由)
} as any)
})
// 消息发送成功后刷新消息列表
await loadMessages(conv.id, 1, false)
// 同步更新会话列表 lastMessage
// 同步更新会话列表 content 字段
setConversations(prev => prev.map(c =>
c.id === conv.id ? { ...c, lastMessage: text, updateTime: new Date().toISOString() } : c
c.id === conv.id ? { ...c, content: text, updateTime: new Date().toISOString() } : c
))
} catch (e: any) {
console.error('发送消息失败:', e)
@@ -162,6 +171,11 @@ const CustomerServicePage: React.FC = () => {
}
}
// 微信客服回调 - 用户从客服会话返回时触发
const handleContact = (e: any) => {
console.log('客服会话回调:', e.detail)
}
// 拨打热线
const handleCallHotline = () => {
Taro.makePhoneCall({ phoneNumber: SERVICE_HOTLINE })
@@ -205,7 +219,12 @@ const CustomerServicePage: React.FC = () => {
<View className="flex flex-col min-h-screen bg-gray-100">
<NavBar title="在线客服" />
<ScrollView scrollY className="flex-1">
<ScrollView
scrollY
className="flex-1"
onScrollToLower={handleScrollToLower}
lowerThreshold={50}
>
{/* 客服状态栏 */}
<View className="bg-white px-4 py-3 flex items-center justify-between">
<View className="flex items-center gap-2">
@@ -222,11 +241,25 @@ const CustomerServicePage: React.FC = () => {
<View className="px-4 py-3 bg-white border-t border-gray-50">
<Button
openType="contact"
className="w-full h-12 rounded-lg text-white font-medium text-base border-0"
style={{ backgroundColor: '#07c160', lineHeight: '48px' }}
sessionFrom="customer_service"
onContact={handleContact}
showMessageCard
sendMessageTitle="欢迎咨询"
className="w-full rounded-lg text-white font-medium text-base"
style={{
backgroundColor: '#07c160',
lineHeight: '48px',
height: '48px',
borderRadius: '8px',
border: 'none',
padding: '0',
}}
>
线
</Button>
<Text className="text-xs text-gray-400 block text-center mt-2">
</Text>
</View>
{/* 消息记录入口 */}
@@ -276,7 +309,7 @@ const CustomerServicePage: React.FC = () => {
>
<View className="flex justify-between items-center">
<Text className="text-sm text-gray-700" style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{conv.content || conv.lastMessage || '暂无消息'}
{conv.content || '暂无消息'}
</Text>
<Text className="text-xs text-gray-400 ml-2">{formatTime(conv.updateTime)}</Text>
</View>