diff --git a/.workbuddy/memory/2026-07-14.md b/.workbuddy/memory/2026-07-14.md index 805c34b..bfb31f2 100644 --- a/.workbuddy/memory/2026-07-14.md +++ b/.workbuddy/memory/2026-07-14.md @@ -275,3 +275,13 @@ adapter `/list` 接口忽略分页,一次返回全部收藏;前端 `listShop - `pageShopChatMessage` 参数去掉 `as any` 断言(模型已支持 `conversationId`) - 新增 `getCurrentUserId()` 辅助函数 - `handleScrollToLower` 增加 `showHistory` 条件守卫(仅展开历史时才加载更多) +3. **`src/components/NavBar/index.tsx`**(关键修复,导致白屏): + - Taro 4.1.11 没有 `useNavigate` hook,原代码 `import { useNavigate } from '@tarojs/taro'` 运行时为 `undefined` + - 改为 `import Taro from '@tarojs/taro'`,回退逻辑用 `Taro.navigateBack({ delta: 1 })` +4. **删除未注册的死代码**: + - `src/pages/customer-service.tsx`(重复且仍引用 `useReachBottom`,干扰编译/热更新) + - `src/pages/customer-service.config.ts` + +### 验证 +- 全局搜索确认无其他 `useNavigate` 和 `useReachBottom` 引用 +- TypeScript 检查修改文件无错误 diff --git a/src/components/NavBar/index.tsx b/src/components/NavBar/index.tsx index 2ba723f..9774066 100644 --- a/src/components/NavBar/index.tsx +++ b/src/components/NavBar/index.tsx @@ -1,5 +1,5 @@ import { View, Text } from '@tarojs/components'; -import { useNavigate } from '@tarojs/taro'; +import Taro from '@tarojs/taro'; interface NavBarProps { title: string; @@ -9,13 +9,11 @@ interface NavBarProps { } export default function NavBar({ title, onBack, rightText, onRightClick }: NavBarProps) { - const navigate = useNavigate(); - const handleBack = () => { if (onBack) { onBack(); } else { - navigate(-1); + Taro.navigateBack({ delta: 1 }); } }; diff --git a/src/pages/customer-service.config.ts b/src/pages/customer-service.config.ts deleted file mode 100644 index 887dad7..0000000 --- a/src/pages/customer-service.config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default { - navigationBarTitleText: '在线客服', -} diff --git a/src/pages/customer-service.tsx b/src/pages/customer-service.tsx deleted file mode 100644 index fc7775d..0000000 --- a/src/pages/customer-service.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import React, { useEffect, useState, useCallback, useRef } from 'react' -import { View, Text, Button, Input, ScrollView } from '@tarojs/components' -import Taro, { useReachBottom } 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 { PageResult } from '@/api' - -definePageConfig({ - navigationBarTitleText: '在线客服', -}) - -const SERVICE_ONLINE_HOURS = '9:00-21:00' -const SERVICE_HOTLINE = '400-888-8888' -const SERVICE_WECHAT = 'shop_service' - -const CustomerServicePage: React.FC = () => { - const [conversations, setConversations] = useState([]) - const [currentConversation, setCurrentConversation] = useState(null) - const [messages, setMessages] = useState([]) - const [inputMessage, setInputMessage] = useState('') - const [loading, setLoading] = useState(true) - const [sending, setSending] = useState(false) - const [loadingMore, setLoadingMore] = useState(false) - 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() - const h = now.getHours() - return h >= 9 && h < 21 - } - - // 加载会话列表 - const loadConversations = useCallback(async () => { - setLoading(true) - try { - const params: ShopChatConversationParam = { - page: 1, - limit: 20, - order: 'desc', - sort: 'updateTime', - } - const result: PageResult = await pageShopChatConversation(params) - if (result?.list) { - setConversations(result.list) - if (result.list.length > 0) { - const latest = result.list[0] - setCurrentConversation(latest) - loadMessages(latest.id!, 1, false) - } - } - } catch (e) { - console.error('获取会话列表失败:', e) - setConversations([]) - } finally { - setLoading(false) - } - }, []) - - // 加载消息列表 - const loadMessages = useCallback(async (conversationId: number, pageNum: number = 1, isLoadMore = false) => { - if (isLoadMore) setLoadingMore(true) - try { - const result = await pageShopChatMessage({ - conversationId, - page: pageNum, - limit: 20, - order: 'asc', - sort: 'createTime', - } as any) - 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) - } - } catch (e) { - console.error('获取消息列表失败:', e) - if (!isLoadMore) setMessages([]) - } finally { - setLoadingMore(false) - } - }, []) - - useEffect(() => { - loadConversations() - }, [loadConversations]) - - useReachBottom(() => { - if (hasMore && currentConversation && !loadingMore) { - loadMessages(currentConversation.id!, msgPage + 1, true) - } - }) - - // 创建新会话 - const ensureConversation = async (): Promise => { - if (currentConversation) return currentConversation - try { - await addShopChatConversation({ type: 0 }) - // 重新拉取会话列表获取新会话 - const result = await pageShopChatConversation({ page: 1, limit: 20, order: 'desc', sort: 'updateTime' }) - if (result?.list && result.list.length > 0) { - const conv = result.list[0] - setConversations(result.list) - setCurrentConversation(conv) - return conv - } - } catch (e) { - console.error('创建会话失败:', e) - } - return null - } - - // 发送消息 - const handleSendMessage = async () => { - const text = inputMessage.trim() - if (!text) { - Taro.showToast({ title: '请输入消息内容', icon: 'none' }) - return - } - - setSending(true) - setInputMessage('') - try { - const conv = await ensureConversation() - if (!conv?.id) { - Taro.showToast({ title: '无法创建会话,请稍后重试', icon: 'none' }) - setInputMessage(text) - return - } - - await addShopChatMessage({ - content: text, - type: 'text', - toUserId: 0, // 发送给客服(服务端路由) - } as any) - - // 消息发送成功后刷新消息列表 - await loadMessages(conv.id, 1, false) - - // 同步更新会话列表 lastMessage - setConversations(prev => prev.map(c => - c.id === conv.id ? { ...c, lastMessage: text, updateTime: new Date().toISOString() } : c - )) - } catch (e: any) { - console.error('发送消息失败:', e) - setInputMessage(text) - Taro.showToast({ title: e?.message || '发送失败,请重试', icon: 'none' }) - } finally { - setSending(false) - } - } - - // 拨打热线 - const handleCallHotline = () => { - Taro.makePhoneCall({ phoneNumber: SERVICE_HOTLINE }) - } - - // 复制微信号 - const handleCopyWechat = () => { - Taro.setClipboardData({ - data: SERVICE_WECHAT, - success: () => Taro.showToast({ title: '已复制微信号', icon: 'success' }), - }) - } - - // 跳转帮助中心 - const handleGoToHelp = () => { - Taro.navigateTo({ url: '/pages/user/help-center' }) - } - - // 选择会话 - const handleSelectConversation = (conv: ShopChatConversation) => { - setCurrentConversation(conv) - setMessages([]) - setMsgPage(1) - setHasMore(true) - loadMessages(conv.id!, 1, false) - } - - const formatTime = (timeStr?: string) => { - if (!timeStr) return '' - const date = new Date(timeStr) - const m = String(date.getMonth() + 1).padStart(2, '0') - const d = String(date.getDate()).padStart(2, '0') - const h = String(date.getHours()).padStart(2, '0') - const min = String(date.getMinutes()).padStart(2, '0') - return `${m}-${d} ${h}:${min}` - } - - const online = isOnline() - - return ( - - - - - {/* 客服状态栏 */} - - - - {online ? '客服在线' : '客服离线'} - - 服务时间: {SERVICE_ONLINE_HOURS} - - - {/* 微信在线客服按钮 */} - - - - - {/* 消息记录入口 */} - {!showHistory && ( - - setShowHistory(true)} - > - - 💬 - - 历史消息记录 {conversations.length > 0 ? `(${conversations.length}条会话)` : ''} - - - - - - )} - - {/* 历史会话与消息列表 */} - {showHistory && ( - - - 历史会话 - setShowHistory(false)} - > - 收起 - - - - {loading ? ( - - ) : conversations.length === 0 ? ( - - ) : ( - - {conversations.map(conv => ( - handleSelectConversation(conv)} - > - - - {conv.content || conv.lastMessage || '暂无消息'} - - {formatTime(conv.updateTime)} - - - ))} - - )} - - {/* 当前会话的消息 */} - {currentConversation && messages.length > 0 && ( - - 消息记录 - {loadingMore && } - {messages.map(msg => ( - - - - {msg.content} - - - {formatTime(msg.createTime)} - - - - ))} - - )} - - )} - - {/* 其他联系方式 */} - - 其他联系方式 - - - 📞 - - 客服热线 - {SERVICE_HOTLINE} - - - 拨打 - - - - 💬 - - 微信号 - {SERVICE_WECHAT} - - - 复制 - - - - {/* 帮助中心入口 */} - - 常见问题 - - 查看帮助中心 - - - - - {/* 留言(离线时) */} - {!online && ( - - 离线留言 - - 客服暂时不在线,可在下方输入框留言,客服上线后会尽快回复您。 - - - )} - - - {/* 消息输入区 - 始终显示,支持发送留言 */} - - setInputMessage(e.detail.value)} - onConfirm={handleSendMessage} - disabled={sending} - /> - - {sending ? '发送中' : '发送'} - - - - ) -} - -export default CustomerServicePage