<!-- 机构端 - 消息中心（客服工作台） -->
<template>
<view class="messages-page">
<view class="wb-header-right">
<view class="wb-status-wrap">
<view class="wb-status-dot"></view>
<text class="wb-status-text">在线</text>
</view>
<view class="wb-pending-wrap" v-if="pendingCount > 0">
<text class="wb-pending-text">{{ pendingCount }}条待处理</text>
</view>
</view>

<!-- ===== 三模块 Tab 切换栏 ===== -->
<view class="wb-tabs">
<view class="wb-tab-item" :class="{ 'wb-tab-active': activeTab === 0 }" @click="activeTab = 0">
<text class="wb-tab-icon">💬</text>
<text class="wb-tab-label">会话列表</text>
<view v-if="totalUnread > 0 && activeTab !== 0" class="wb-tab-badge">
<text class="wb-tab-badge-num">{{ totalUnread }}</text>
</view>
</view>
<view class="wb-tab-item" :class="{ 'wb-tab-active': activeTab === 1 }" @click="activeTab = 1">
<text class="wb-tab-icon">🗨</text>
<text class="wb-tab-label">聊天记录</text>
</view>
<view class="wb-tab-item" :class="{ 'wb-tab-active': activeTab === 2 }" @click="activeTab = 2">
<text class="wb-tab-icon">📋</text>
<text class="wb-tab-label">用户资料</text>
</view>
</view>

<!-- 当前会话提示条 -->
<view v-if="activeTab !== 0" class="session-hint-bar">
<text class="session-hint-avatar">{{ currentSession.avatar }}</text>
<text class="session-hint-name">{{ currentSession.userName }}</text>
<view class="session-hint-status" :class="'shs-' + currentSession.status">
<text class="session-hint-status-text">{{ currentSession.status === 'pending' ? '待回复' : currentSession.status === 'active' ? '服务中' : '已结束' }}</text>
</view>
<view class="session-hint-switch" @click="activeTab = 0">
<text class="session-hint-switch-text">切换会话</text>
</view>
</view>

<!-- ===== 内容区 ===== -->
<view class="wb-content">

<!-- ──────────── 模块一：会话列表 ──────────── -->
<view v-if="activeTab === 0" class="module-sessions">
<view class="sessions-search-wrap">
<input class="sessions-search-input" placeholder="🔍 搜索用户或会话内容..." v-model="searchKey" />
</view>
<scroll-view scroll-y class="sessions-scroll">
<view
v-for="sess in filteredSessions"
:key="sess.id"
class="session-card"
:class="{ 'session-card-active': currentSessionId === sess.id }"
@click="selectSession(sess.id)"
>
<view class="sc-avatar-wrap">
<text class="sc-avatar-emoji">{{ sess.avatar }}</text>
<view v-if="sess.unread > 0" class="sc-unread-badge">
<text class="sc-unread-num">{{ sess.unread > 99 ? '99+' : sess.unread }}</text>
</view>
</view>
<view class="sc-info">
<view class="sc-row-top">
<text class="sc-name">{{ sess.userName }}</text>
<text class="sc-time">{{ sess.lastTime }}</text>
</view>
<text class="sc-consult-type">{{ sess.consultType }}</text>
<view class="sc-row-bottom">
<text class="sc-preview" :class="{ 'sc-preview-bold': sess.unread > 0 }">{{ sess.lastMsg }}</text>
<view class="sc-status-tag" :class="'sc-status-' + sess.status">
<text class="sc-status-text">{{ sess.status === 'pending' ? '待回复' : sess.status === 'active' ? '服务中' : '已结束' }}</text>
</view>
</view>
</view>
<text class="sc-arrow">›</text>
</view>
<view v-if="filteredSessions.length === 0" class="sessions-empty">
<text class="sessions-empty-icon">🔍</text>
<text class="sessions-empty-text">暂无匹配会话</text>
</view>
<view class="sessions-safe-bottom"></view>
</scroll-view>
</view>

<!-- ──────────── 模块二：聊天记录 ──────────── -->
<view v-else-if="activeTab === 1" class="module-chat">
<scroll-view scroll-y class="chat-messages-scroll" :scroll-into-view="scrollTarget" :scroll-with-animation="true">
<view class="chat-messages-inner">
<view
v-for="msg in currentMessages"
:key="msg.id"
:id="'msg_' + msg.id"
class="msg-row"
:class="{ 'msg-row-system': msg.type === 'system' }"
>
<!-- 系统消息 -->
<view v-if="msg.type === 'system'" class="msg-system">
<text class="msg-system-text">{{ msg.content }}</text>
</view>
<!-- 用户消息（左） -->
<view v-else-if="msg.fromUser" class="msg-left">
<text class="msg-avatar">{{ currentSession.avatar }}</text>
<view class="msg-body">
<text class="msg-sender">{{ currentSession.userName }}</text>
<view v-if="msg.type === 'text'" class="bubble bubble-user">
<text class="bubble-text">{{ msg.content }}</text>
<text class="bubble-time">{{ msg.time }}</text>
</view>
<view v-else-if="msg.type === 'image'" class="bubble bubble-user bubble-image">
<text class="bubble-image-icon">🖼</text>
<text class="bubble-image-hint">[图片消息]</text>
<text class="bubble-time">{{ msg.time }}</text>
</view>
<view v-else-if="msg.type === 'product'" class="msg-card-wrap">
<view class="product-card">
<view class="pc-thumb">
<text class="pc-thumb-emoji">{{ msg.cardData != null ? (msg.cardData as ProductCardData).emoji : '📦' }}</text>
</view>
<view class="pc-info">
<text class="pc-name">{{ msg.cardData != null ? (msg.cardData as ProductCardData).name : '' }}</text>
<text class="pc-price">¥{{ msg.cardData != null ? (msg.cardData as ProductCardData).price : '' }}</text>
<text class="pc-tag">{{ msg.cardData != null ? (msg.cardData as ProductCardData).tag : '' }}</text>
</view>
</view>
<text class="card-time">{{ msg.time }}</text>
</view>
<view v-else-if="msg.type === 'order'" class="msg-card-wrap">
<view class="order-card">
<view class="oc-row1">
<text class="oc-label">订单号</text>
<text class="oc-no">{{ msg.cardData != null ? (msg.cardData as OrderCardData).orderNo : '' }}</text>
<view class="oc-status-tag" :class="'oc-' + (msg.cardData != null ? (msg.cardData as OrderCardData).statusCode : '')">
<text class="oc-status-text">{{ msg.cardData != null ? (msg.cardData as OrderCardData).status : '' }}</text>
</view>
</view>
<text class="oc-amount">¥{{ msg.cardData != null ? (msg.cardData as OrderCardData).amount : '' }}</text>
<text class="oc-items">{{ msg.cardData != null ? (msg.cardData as OrderCardData).itemsDesc : '' }}</text>
</view>
<text class="card-time">{{ msg.time }}</text>
</view>
</view>
</view>
<!-- 商家消息（右） -->
<view v-else class="msg-right">
<view class="msg-body msg-body-right">
<view v-if="msg.type === 'text'" class="bubble bubble-me">
<text class="bubble-text">{{ msg.content }}</text>
<text class="bubble-time bubble-time-right">{{ msg.time }}</text>
</view>
<view v-else-if="msg.type === 'image'" class="bubble bubble-me bubble-image">
<text class="bubble-image-icon">🖼</text>
<text class="bubble-image-hint">[图片消息]</text>
<text class="bubble-time bubble-time-right">{{ msg.time }}</text>
</view>
<view v-else-if="msg.type === 'product'" class="msg-card-wrap msg-card-right">
<view class="product-card">
<view class="pc-thumb">
<text class="pc-thumb-emoji">{{ msg.cardData != null ? (msg.cardData as ProductCardData).emoji : '📦' }}</text>
</view>
<view class="pc-info">
<text class="pc-name">{{ msg.cardData != null ? (msg.cardData as ProductCardData).name : '' }}</text>
<text class="pc-price">¥{{ msg.cardData != null ? (msg.cardData as ProductCardData).price : '' }}</text>
<text class="pc-tag">{{ msg.cardData != null ? (msg.cardData as ProductCardData).tag : '' }}</text>
</view>
</view>
<text class="card-time card-time-right">{{ msg.time }}</text>
</view>
<view v-else-if="msg.type === 'order'" class="msg-card-wrap msg-card-right">
<view class="order-card">
<view class="oc-row1">
<text class="oc-label">订单号</text>
<text class="oc-no">{{ msg.cardData != null ? (msg.cardData as OrderCardData).orderNo : '' }}</text>
<view class="oc-status-tag" :class="'oc-' + (msg.cardData != null ? (msg.cardData as OrderCardData).statusCode : '')">
<text class="oc-status-text">{{ msg.cardData != null ? (msg.cardData as OrderCardData).status : '' }}</text>
</view>
</view>
<text class="oc-amount">¥{{ msg.cardData != null ? (msg.cardData as OrderCardData).amount : '' }}</text>
<text class="oc-items">{{ msg.cardData != null ? (msg.cardData as OrderCardData).itemsDesc : '' }}</text>
</view>
<text class="card-time card-time-right">{{ msg.time }}</text>
</view>
</view>
<text class="msg-avatar me-avatar">🏥</text>
</view>
</view>
</view>
</scroll-view>

<!-- 底部输入区 -->
<view class="chat-input-area">
<view v-if="showQuickReplies" class="quick-reply-panel">
<view class="qr-header">
<text class="qr-title">⚡ 快捷回复</text>
<text class="qr-close" @click="showQuickReplies = false">✕</text>
</view>
<scroll-view scroll-y class="qr-scroll">
<view v-for="qr in quickReplies" :key="qr" class="qr-item" @click="sendQuickReply(qr)">
<text class="qr-text">{{ qr }}</text>
</view>
</scroll-view>
</view>
<view class="chat-toolbar">
<view class="toolbar-btn" @click="insertImageMsg">
<text class="toolbar-icon">🖼</text>
<text class="toolbar-label">图片</text>
</view>
<view class="toolbar-btn" @click="insertProductMsg">
<text class="toolbar-icon">📦</text>
<text class="toolbar-label">商品</text>
</view>
<view class="toolbar-btn" @click="insertOrderMsg">
<text class="toolbar-icon">📋</text>
<text class="toolbar-label">订单</text>
</view>
<view class="toolbar-btn" @click="showQuickReplies = !showQuickReplies" :class="{ 'toolbar-btn-active': showQuickReplies }">
<text class="toolbar-icon">⚡</text>
<text class="toolbar-label">快捷</text>
</view>
</view>
<view class="input-row">
<textarea class="chat-textarea" v-model="inputText" placeholder="输入回复内容..." :maxlength="500" />
<view class="send-btn" :class="{ 'send-btn-active': inputText.trim() !== '' }" @click="sendTextMsg">
<text class="send-btn-text">发送</text>
</view>
</view>
</view>
<!-- 为固定 TabBar 留出空间 -->
<view class="chat-tabbar-spacer"></view>
</view>

<!-- ──────────── 模块三：用户资料 ──────────── -->
<view v-else-if="activeTab === 2" class="module-info">
<scroll-view scroll-y class="info-scroll">
<view class="info-user-card">
<text class="info-big-avatar">{{ currentSession.avatar }}</text>
<view class="info-user-main">
<text class="info-user-name">{{ currentSession.userName }}</text>
<view class="info-tags-row">
<view v-for="tag in (currentUserInfo.tags as string[])" :key="tag" class="info-tag">
<text class="info-tag-text">{{ tag }}</text>
</view>
</view>
</view>
</view>

<view class="info-section">
<view class="info-section-header">
<text class="info-section-icon">👤</text>
<text class="info-section-title">基本信息</text>
</view>
<view class="info-kv">
<text class="info-key">手机号</text>
<text class="info-val">{{ currentUserInfo.phone }}</text>
</view>
<view class="info-kv">
<text class="info-key">注册时间</text>
<text class="info-val">{{ currentUserInfo.registerDate }}</text>
</view>
<view class="info-kv">
<text class="info-key">历史订单</text>
<text class="info-val info-val-red">{{ currentUserInfo.totalOrders }} 单</text>
</view>
<view class="info-kv">
<text class="info-key">累计消费</text>
<text class="info-val info-val-red">¥{{ currentUserInfo.totalSpent }}</text>
</view>
</view>

<view class="info-section" v-if="currentUserInfo.consultProduct != null">
<view class="info-section-header">
<text class="info-section-icon">🛒</text>
<text class="info-section-title">正在咨询</text>
</view>
<view class="consult-product">
<text class="cp-big-emoji">{{ (currentUserInfo.consultProduct as ConsultProduct).emoji }}</text>
<view class="cp-detail">
<text class="cp-pname">{{ (currentUserInfo.consultProduct as ConsultProduct).name }}</text>
<text class="cp-pprice">¥{{ (currentUserInfo.consultProduct as ConsultProduct).price }}</text>
</view>
</view>
</view>

<view class="info-section">
<view class="info-section-header">
<text class="info-section-icon">👁</text>
<text class="info-section-title">最近浏览</text>
</view>
<view v-for="item in (currentUserInfo.recentViewed as RecentItem[])" :key="item.name" class="recent-row">
<text class="recent-emoji">{{ item.emoji }}</text>
<view class="recent-detail">
<text class="recent-name">{{ item.name }}</text>
<text class="recent-price">¥{{ item.price }}</text>
</view>
</view>
</view>

<view class="info-section">
<view class="info-section-header">
<text class="info-section-icon">📋</text>
<text class="info-section-title">最近订单</text>
</view>
<view v-for="order in (currentUserInfo.recentOrders as RecentOrder[])" :key="order.no" class="order-mini-card">
<view class="omc-row1">
<text class="omc-no">{{ order.no }}</text>
<view class="omc-status-tag" :class="'omc-' + order.statusCode">
<text class="omc-status-text">{{ order.status }}</text>
</view>
</view>
<view class="omc-row2">
<text class="omc-items">{{ order.itemsDesc }}</text>
<text class="omc-amount">¥{{ order.amount }}</text>
</view>
</view>
</view>

<view class="info-actions">
<view class="info-action-btn primary" @click="goToChat">
<text class="info-action-text">进入聊天</text>
</view>
<view class="info-action-btn" @click="closeSession">
<text class="info-action-text">结束会话</text>
</view>
</view>
<view class="info-safe-bottom"></view>
</scroll-view>
</view>

</view>

<!-- 商家端自定义 TabBar -->
<merchant-tab-bar :current="1"></merchant-tab-bar>
</view>
</template>

<script lang="uts">
import MerchantTabBar from '@/components/merchant-tabbar/MerchantTabBar.uvue'
import { requireMerchantAuth } from '@/utils/merchantAuth.uts'

type ProductCardData = {
emoji: string
name: string
price: string
tag: string
}

type OrderCardData = {
orderNo: string
status: string
statusCode: string
amount: string
itemsDesc: string
}

type ChatMessage = {
id: string
fromUser: boolean
type: string
content: string
time: string
cardData: ProductCardData | OrderCardData | null
}

type Session = {
id: string
userName: string
avatar: string
lastMsg: string
lastTime: string
unread: number
status: string
consultType: string
}

type ConsultProduct = {
emoji: string
name: string
price: string
}

type RecentItem = {
emoji: string
name: string
price: string
}

type RecentOrder = {
no: string
status: string
statusCode: string
amount: string
itemsDesc: string
}

type UserInfo = {
phone: string
registerDate: string
totalOrders: number
totalSpent: string
tags: string[]
consultProduct: ConsultProduct | null
recentViewed: RecentItem[]
recentOrders: RecentOrder[]
}

const MOCK_SESSIONS: Session[] = [
{ id: 'sess_001', userName: '李奶奶（家属：李女士）', avatar: '👩‍🦳', lastMsg: '请问居家护理服务是每天上门吗？', lastTime: '10:32', unread: 3, status: 'pending', consultType: '居家护理咨询' },
{ id: 'sess_002', userName: '王大爷', avatar: '👴', lastMsg: '好的，我明白了，谢谢！', lastTime: '09:15', unread: 0, status: 'active', consultType: '慢病管理套餐' },
{ id: 'sess_003', userName: '张先生（代父咨询）', avatar: '🧑', lastMsg: '这个订单什么时候能安排上门？', lastTime: '昨天', unread: 1, status: 'pending', consultType: '订单跟进' }
]

const MOCK_MESSAGES: Record<string, ChatMessage[]> = {
'sess_001': [
{ id: 'm001', fromUser: false, type: 'system', content: '会话开始 · 居家护理咨询 · 2026-03-24 10:20', time: '', cardData: null },
{ id: 'm002', fromUser: true, type: 'text', content: '您好，我是李奶奶的女儿，想咨询一下居家护理服务的安排。', time: '10:20', cardData: null },
{ id: 'm003', fromUser: false, type: 'text', content: '您好！感谢您的咨询，我们的居家护理服务可以每日或隔日上门，具体频次根据长者身体状况定制。', time: '10:21', cardData: null },
{ id: 'm004', fromUser: true, type: 'text', content: '请问上门的护理员都是专业持证的吗？', time: '10:22', cardData: null },
{ id: 'm005', fromUser: false, type: 'text', content: '是的，我们所有上门人员均持有护理员资格证，并经过机构内部培训和背景审查。', time: '10:23', cardData: null },
{ id: 'm006', fromUser: false, type: 'product', content: '', time: '10:25', cardData: { emoji: '🩺', name: '居家护理基础套餐（月服务）', price: '2800', tag: '每日上门 · 含基础生活护理' } as ProductCardData },
{ id: 'm007', fromUser: true, type: 'image', content: '', time: '10:28', cardData: null },
{ id: 'm008', fromUser: true, type: 'text', content: '请问居家护理服务是每天上门吗？', time: '10:32', cardData: null }
],
'sess_002': [
{ id: 'm101', fromUser: false, type: 'system', content: '会话开始 · 慢病管理套餐 · 2026-03-24 09:00', time: '', cardData: null },
{ id: 'm102', fromUser: true, type: 'text', content: '我父亲有高血压和糖尿病，想了解一下慢病管理套餐包含哪些内容？', time: '09:00', cardData: null },
{ id: 'm103', fromUser: false, type: 'text', content: '您好！我们慢病管理套餐包含：每月4次上门随访、血压血糖监测记录、用药指导和饮食建议，以及每季度体检报告解读。', time: '09:01', cardData: null },
{ id: 'm104', fromUser: false, type: 'product', content: '', time: '09:02', cardData: { emoji: '💊', name: '慢病综合管理套餐（季度）', price: '4200', tag: '含随访+监测+体检解读' } as ProductCardData },
{ id: 'm105', fromUser: true, type: 'text', content: '价格合理，这个套餐可以报销医保吗？', time: '09:05', cardData: null },
{ id: 'm106', fromUser: false, type: 'text', content: '目前部分项目可以使用长护险，具体需要根据您所在区域的长护险政策，我们可以协助您申请。', time: '09:06', cardData: null },
{ id: 'm107', fromUser: true, type: 'order', content: '', time: '09:10', cardData: { orderNo: 'SV20240315002', status: '服务中', statusCode: 'active', amount: '2800.00', itemsDesc: '居家护理基础套餐 × 1月' } as OrderCardData },
{ id: 'm108', fromUser: true, type: 'text', content: '好的，我明白了，谢谢！', time: '09:15', cardData: null }
],
'sess_003': [
{ id: 'm201', fromUser: false, type: 'system', content: '会话开始 · 订单跟进 · 2026-03-23 15:00', time: '', cardData: null },
{ id: 'm202', fromUser: true, type: 'text', content: '你好，我父亲上周下了一个陪诊服务的订单，现在是什么状态了？', time: '昨天 15:00', cardData: null },
{ id: 'm203', fromUser: false, type: 'text', content: '您好！请问您的订单号是多少？我来为您查询。', time: '昨天 15:01', cardData: null },
{ id: 'm204', fromUser: true, type: 'order', content: '', time: '昨天 15:02', cardData: { orderNo: 'SV20240320007', status: '待上门', statusCode: 'pending', amount: '380.00', itemsDesc: '专业陪诊服务（半日） × 1次' } as OrderCardData },
{ id: 'm205', fromUser: false, type: 'text', content: '已为您查到，该订单目前处于"待上门"状态，陪诊师将于明天上午9:00~10:00联系您父亲确认时间。', time: '昨天 15:05', cardData: null },
{ id: 'm206', fromUser: false, type: 'text', content: '您也可以在小程序"服务订单"中实时查看服务进度，如需备注特殊要求请告知。', time: '昨天 15:06', cardData: null },
{ id: 'm207', fromUser: true, type: 'text', content: '这个订单什么时候能安排上门？', time: '昨天 15:08', cardData: null }
]
}

const MOCK_USER_INFO: Record<string, UserInfo> = {
'sess_001': {
phone: '186****3421', registerDate: '2025-11-10', totalOrders: 4, totalSpent: '8,400',
tags: ['长者家属', '居家护理', '高意向'],
consultProduct: { emoji: '🩺', name: '居家护理基础套餐', price: '2800' } as ConsultProduct,
recentViewed: [
{ emoji: '🩺', name: '居家护理基础套餐', price: '2800' } as RecentItem,
{ emoji: '🛁', name: '洗浴护理服务', price: '188' } as RecentItem,
{ emoji: '🦽', name: '轮椅租赁月服务', price: '360' } as RecentItem
],
recentOrders: [
{ no: 'SV20240210003', status: '已完成', statusCode: 'done', amount: '2800', itemsDesc: '居家护理基础套餐' } as RecentOrder,
{ no: 'SV20240115001', status: '已完成', statusCode: 'done', amount: '188', itemsDesc: '洗浴护理服务 × 1次' } as RecentOrder
]
},
'sess_002': {
phone: '139****8802', registerDate: '2025-08-22', totalOrders: 7, totalSpent: '15,600',
tags: ['高消费', '慢病管理', '复购客户'],
consultProduct: { emoji: '💊', name: '慢病综合管理套餐', price: '4200' } as ConsultProduct,
recentViewed: [
{ emoji: '💊', name: '慢病综合管理套餐', price: '4200' } as RecentItem,
{ emoji: '🩸', name: '上门抽血检测服务', price: '98' } as RecentItem,
{ emoji: '❤️', name: '心电图上门检测', price: '128' } as RecentItem
],
recentOrders: [
{ no: 'SV20240315002', status: '服务中', statusCode: 'active', amount: '2800', itemsDesc: '居家护理基础套餐' } as RecentOrder,
{ no: 'SV20240201008', status: '已完成', statusCode: 'done', amount: '4200', itemsDesc: '慢病综合管理套餐' } as RecentOrder
]
},
'sess_003': {
phone: '158****7760', registerDate: '2026-01-05', totalOrders: 1, totalSpent: '380',
tags: ['新用户', '陪诊咨询'],
consultProduct: { emoji: '🏥', name: '专业陪诊服务（半日）', price: '380' } as ConsultProduct,
recentViewed: [
{ emoji: '🏥', name: '专业陪诊服务（半日）', price: '380' } as RecentItem,
{ emoji: '🚑', name: '专业陪诊服务（全日）', price: '680' } as RecentItem
],
recentOrders: [
{ no: 'SV20240320007', status: '待上门', statusCode: 'pending', amount: '380', itemsDesc: '专业陪诊服务（半日）× 1次' } as RecentOrder
]
}
}

const QUICK_REPLIES: string[] = [
'您好，感谢您的咨询！我是在线客服，请问有什么可以帮您？',
'好的，我马上为您查询，请稍候。',
'我们的服务人员均持有专业资格证，请放心。',
'您的订单已安排，服务人员将提前联系您确认时间。',
'如需进一步了解，欢迎预约免费上门评估服务。',
'感谢您的信任，祝长辈身体健康！'
]

export default {
components: { MerchantTabBar },
data() {
return {
sessions: MOCK_SESSIONS as Session[],
messageMap: MOCK_MESSAGES as Record<string, ChatMessage[]>,
userInfoMap: MOCK_USER_INFO as Record<string, UserInfo>,
quickReplies: QUICK_REPLIES as string[],
activeTab: 0,
currentSessionId: 'sess_001',
inputText: '',
scrollTarget: '',
showQuickReplies: false,
searchKey: ''
}
},

computed: {
filteredSessions(): Session[] {
if (this.searchKey.trim() === '') return this.sessions
const key = this.searchKey.toLowerCase()
return this.sessions.filter((s: Session) =>
s.userName.toLowerCase().includes(key) || s.lastMsg.toLowerCase().includes(key)
)
},
currentSession(): Session {
const found = this.sessions.find((s: Session) => s.id === this.currentSessionId)
return found ?? this.sessions[0]
},
currentMessages(): ChatMessage[] {
return this.messageMap[this.currentSessionId] ?? []
},
currentUserInfo(): UserInfo {
return this.userInfoMap[this.currentSessionId] ?? this.userInfoMap['sess_001']
},
pendingCount(): number {
let count = 0
for (let i = 0; i < this.sessions.length; i++) {
if (this.sessions[i].status === 'pending') count++
}
return count
},
totalUnread(): number {
let total = 0
for (let i = 0; i < this.sessions.length; i++) {
total += this.sessions[i].unread
}
return total
}
},

onShow() {
this.handlePageShow()
},

methods: {
	async ensureMerchantAuth(): Promise<boolean> {
		const result = await requireMerchantAuth({ redirectOnFail: true, toastOnFail: true })
		return result.ok
	},

	async handlePageShow() {
		const passed = await this.ensureMerchantAuth()
		if (!passed) return
		this.scrollToBottom()
	},

selectSession(id: string) {
this.currentSessionId = id
this.showQuickReplies = false
const idx = this.sessions.findIndex((s: Session) => s.id === id)
if (idx >= 0) {
this.sessions[idx].unread = 0
if (this.sessions[idx].status === 'pending') this.sessions[idx].status = 'active'
}
this.activeTab = 1
setTimeout(() => { this.scrollToBottom() }, 150)
},

goToChat() {
this.activeTab = 1
setTimeout(() => { this.scrollToBottom() }, 150)
},

scrollToBottom() {
const msgs = this.currentMessages
if (msgs.length === 0) return
const last = msgs[msgs.length - 1]
this.scrollTarget = ''
setTimeout(() => { this.scrollTarget = 'msg_' + last.id }, 100)
},

nowTime(): string {
const d = new Date()
return d.getHours().toString().padStart(2, '0') + ':' + d.getMinutes().toString().padStart(2, '0')
},

pushMessage(msg: ChatMessage) {
if (this.messageMap[this.currentSessionId] == null) {
this.messageMap[this.currentSessionId] = []
}
this.messageMap[this.currentSessionId].push(msg)
const idx = this.sessions.findIndex((s: Session) => s.id === this.currentSessionId)
if (idx >= 0) {
this.sessions[idx].lastMsg = msg.type === 'text' ? msg.content :
msg.type === 'image' ? '[图片]' :
msg.type === 'product' ? '[商品推荐]' : '[订单信息]'
this.sessions[idx].lastTime = this.nowTime()
}
setTimeout(() => { this.scrollToBottom() }, 100)
},

sendTextMsg() {
const text = this.inputText.trim()
if (text === '') return
this.inputText = ''
this.showQuickReplies = false
this.pushMessage({ id: 'local_' + Date.now().toString(), fromUser: false, type: 'text', content: text, time: this.nowTime(), cardData: null } as ChatMessage)
},

sendQuickReply(text: string) {
this.showQuickReplies = false
this.pushMessage({ id: 'qr_' + Date.now().toString(), fromUser: false, type: 'text', content: text, time: this.nowTime(), cardData: null } as ChatMessage)
},

insertImageMsg() {
this.pushMessage({ id: 'img_' + Date.now().toString(), fromUser: false, type: 'image', content: '', time: this.nowTime(), cardData: null } as ChatMessage)
},

insertProductMsg() {
this.pushMessage({ id: 'prod_' + Date.now().toString(), fromUser: false, type: 'product', content: '', time: this.nowTime(), cardData: { emoji: '🩺', name: '居家护理定制套餐', price: '3200', tag: '可定制频次，支持长护险' } as ProductCardData } as ChatMessage)
},

insertOrderMsg() {
this.pushMessage({ id: 'ord_' + Date.now().toString(), fromUser: false, type: 'order', content: '', time: this.nowTime(), cardData: { orderNo: 'SV' + Date.now().toString().slice(-8), status: '待接单', statusCode: 'pending', amount: '2800.00', itemsDesc: '居家护理基础套餐 × 1月' } as OrderCardData } as ChatMessage)
},

closeSession() {
uni.showModal({
title: '结束会话',
content: '确认结束与该用户的当前咨询会话吗？',
success: (res) => {
if (res.confirm) {
const idx = this.sessions.findIndex((s: Session) => s.id === this.currentSessionId)
if (idx >= 0) this.sessions[idx].status = 'closed'
this.pushMessage({ id: 'sys_' + Date.now().toString(), fromUser: false, type: 'system', content: '会话已由客服结束 · ' + this.nowTime(), time: '', cardData: null } as ChatMessage)
this.activeTab = 0
}
}
})
}
}
}
</script>

<style>
/* ===== 页面容器 ===== */
.messages-page {
	display: flex;
	flex-direction: column;
	height: 100vh;
	background-color: #f4f6f9;
}

/* ===== 顶部导航（微信小程序） ===== */
.mp-tab-navbar {
	background-color: #09C39D;
	padding-top: var(--status-bar-height);
	flex-shrink: 0;
}
.wb-navbar-content {
	height: 88rpx;
	display: flex;
	flex-direction: row;
	align-items: center;
	padding: 0 24rpx;
}
.mp-tab-title {
	font-size: 34rpx;
	font-weight: bold;
	color: #fff;
	flex: 1;
}
.wb-header-right {
	display: flex;
	flex-direction: row;
	align-items: center;
	justify-content: flex-end;
	gap: 16rpx;
	padding: calc(16rpx + var(--status-bar-height)) 24rpx 16rpx;
	background-color: #09C39D;
}
.wb-status-wrap {
	display: flex;
	flex-direction: row;
	align-items: center;
	background-color: rgba(255,255,255,0.15);
	border-radius: 20rpx;
	padding: 6rpx 16rpx;
}
.wb-status-dot {
	width: 14rpx;
	height: 14rpx;
	border-radius: 7rpx;
	background-color: #52c41a;
	margin-right: 8rpx;
}
.wb-status-text { font-size: 22rpx; color: #fff; }
.wb-pending-wrap { background-color: #ff4d4f; border-radius: 20rpx; padding: 6rpx 16rpx; }
.wb-pending-text { font-size: 22rpx; color: #fff; font-weight: bold; }

/* ===== 三模块 Tab 切换栏 ===== */
.wb-tabs {
	display: flex;
	flex-direction: row;
	background-color: #fff;
	border-bottom-width: 2rpx;
	border-bottom-style: solid;
	border-bottom-color: #e8e8e8;
	flex-shrink: 0;
}
.wb-tab-item {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 20rpx 0 16rpx;
	position: relative;
}
.wb-tab-item:active { background-color: #f5f7fa; }
.wb-tab-icon { font-size: 38rpx; }
.wb-tab-label { font-size: 24rpx; color: #888; margin-top: 6rpx; }
.wb-tab-active .wb-tab-label { color: #09C39D; font-weight: bold; }
.wb-tab-active { border-bottom-width: 4rpx; border-bottom-style: solid; border-bottom-color: #09C39D; }
.wb-tab-badge { position: absolute; top: 10rpx; right: 16rpx; min-width: 28rpx; height: 28rpx; background-color: #ff4d4f; border-radius: 14rpx; display: flex; align-items: center; justify-content: center; padding: 0 6rpx; }
.wb-tab-badge-num { font-size: 18rpx; color: #fff; font-weight: bold; }

/* ===== 当前会话提示条 ===== */
.session-hint-bar {
	background-color: #f0f7ff;
	border-bottom-width: 1rpx;
	border-bottom-style: solid;
	border-bottom-color: #d0e8ff;
	padding: 14rpx 24rpx;
	display: flex;
	flex-direction: row;
	align-items: center;
	flex-shrink: 0;
}
.session-hint-avatar { font-size: 32rpx; margin-right: 10rpx; }
.session-hint-name { font-size: 24rpx; color: #09C39D; font-weight: bold; flex: 1; }
.session-hint-status { border-radius: 8rpx; padding: 2rpx 12rpx; margin-right: 16rpx; }
.shs-pending { background-color: #fff3e0; }
.shs-pending .session-hint-status-text { font-size: 20rpx; color: #ff8c00; }
.shs-active { background-color: #e8f5e9; }
.shs-active .session-hint-status-text { font-size: 20rpx; color: #388e3c; }
.shs-closed { background-color: #f5f5f5; }
.shs-closed .session-hint-status-text { font-size: 20rpx; color: #999; }
.session-hint-switch { background-color: #09C39D; border-radius: 20rpx; padding: 6rpx 20rpx; }
.session-hint-switch-text { font-size: 20rpx; color: #fff; }

/* ===== 内容区（flex:1 填充剩余高度） ===== */
.wb-content {
	flex: 1;
	overflow: hidden;
	display: flex;
	flex-direction: column;
}

/* ====== 模块一：会话列表 ====== */
.module-sessions { flex: 1; display: flex; flex-direction: column; background-color: #fff; overflow: hidden; }
.sessions-search-wrap {
	padding: 24rpx;
	background-color: #f8f9fc;
	border-bottom-width: 1rpx;
	border-bottom-style: solid;
	border-bottom-color: #eee;
	flex-shrink: 0;
}
.sessions-search-input {
	background-color: #fff;
	border-width: 1rpx;
	border-style: solid;
	border-color: #d0d0d0;
	border-radius: 44rpx;
	height: 88rpx;
	line-height: 88rpx;
	padding: 0 32rpx;
	font-size: 28rpx;
	width: 100%;
}
.sessions-scroll { flex: 1; height: 0; }

.session-card { display: flex; flex-direction: row; align-items: center; padding: 28rpx 24rpx; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f0f0f0; }
.session-card:active { background-color: #f0f7ff; }
.session-card-active { background-color: #E3F7ED; border-left-width: 6rpx; border-left-style: solid; border-left-color: #09C39D; }
.sc-avatar-wrap { position: relative; margin-right: 20rpx; flex-shrink: 0; }
.sc-avatar-emoji { font-size: 80rpx; }
.sc-unread-badge { position: absolute; top: -6rpx; right: -6rpx; min-width: 32rpx; height: 32rpx; background-color: #ff4d4f; border-radius: 16rpx; display: flex; align-items: center; justify-content: center; padding: 0 8rpx; border-width: 2rpx; border-style: solid; border-color: #fff; }
.sc-unread-num { font-size: 18rpx; color: #fff; font-weight: bold; }
.sc-info { flex: 1; overflow: hidden; }
.sc-row-top { display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin-bottom: 4rpx; }
.sc-name { font-size: 30rpx; font-weight: bold; color: #1a1a1a; flex: 1; }
.sc-time { font-size: 22rpx; color: #aaa; flex-shrink: 0; margin-left: 16rpx; }
.sc-consult-type { font-size: 22rpx; color: #09C39D; display: block; margin-bottom: 8rpx; }
.sc-row-bottom { display: flex; flex-direction: row; align-items: center; }
.sc-preview { font-size: 26rpx; color: #999; flex: 1; }
.sc-preview-bold { color: #333; font-weight: bold; }
.sc-status-tag { border-radius: 8rpx; padding: 4rpx 14rpx; flex-shrink: 0; margin-left: 12rpx; }
.sc-status-pending { background-color: #fff3e0; }
.sc-status-pending .sc-status-text { color: #ff8c00; font-size: 22rpx; }
.sc-status-active { background-color: #e8f5e9; }
.sc-status-active .sc-status-text { color: #388e3c; font-size: 22rpx; }
.sc-status-closed { background-color: #f5f5f5; }
.sc-status-closed .sc-status-text { color: #999; font-size: 22rpx; }
.sc-arrow { font-size: 36rpx; color: #ccc; margin-left: 12rpx; flex-shrink: 0; }
.sessions-empty { padding: 100rpx 0; display: flex; flex-direction: column; align-items: center; }
.sessions-empty-icon { font-size: 80rpx; margin-bottom: 20rpx; }
.sessions-empty-text { font-size: 28rpx; color: #bbb; }
.sessions-safe-bottom { height: 140rpx; }

/* ====== 模块二：聊天记录 ====== */
.module-chat { flex: 1; display: flex; flex-direction: column; background-color: #f4f6f9; overflow: hidden; }
.chat-messages-scroll { flex: 1; height: 0; }
.chat-messages-inner { padding: 24rpx 20rpx 20rpx; display: flex; flex-direction: column; }

.msg-row { margin-bottom: 28rpx; }
.msg-row-system { display: flex; justify-content: center; }
.msg-system { background-color: rgba(0,0,0,0.05); border-radius: 10rpx; padding: 10rpx 24rpx; }
.msg-system-text { font-size: 22rpx; color: #999; }

.msg-left { display: flex; flex-direction: row; align-items: flex-start; }
.msg-right { display: flex; flex-direction: row; align-items: flex-start; justify-content: flex-end; }
.msg-avatar { font-size: 64rpx; flex-shrink: 0; }
.me-avatar { margin-left: 14rpx; }
.msg-body { margin-left: 14rpx; max-width: 80%; }
.msg-body-right { margin-left: 0; margin-right: 14rpx; display: flex; flex-direction: column; align-items: flex-end; }
.msg-sender { font-size: 22rpx; color: #999; margin-bottom: 8rpx; display: block; }

.bubble { border-radius: 18rpx; padding: 20rpx 24rpx; display: flex; flex-direction: column; }
.bubble-user { background-color: #fff; border-top-left-radius: 4rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06); }
.bubble-me { background-color: #e8f0fe; border-top-right-radius: 4rpx; }
.bubble-text { font-size: 30rpx; color: #1a1a1a; line-height: 1.6; }
.bubble-time { font-size: 20rpx; color: #bbb; margin-top: 8rpx; }
.bubble-time-right { text-align: right; }
.bubble-image { flex-direction: row; align-items: center; gap: 12rpx; }
.bubble-image-icon { font-size: 44rpx; }
.bubble-image-hint { font-size: 26rpx; color: #666; }

.msg-card-wrap { display: flex; flex-direction: column; }
.msg-card-right { align-items: flex-end; }
.card-time { font-size: 20rpx; color: #bbb; margin-top: 8rpx; padding: 0 4rpx; }
.card-time-right { text-align: right; }

.product-card { background-color: #fff; border-radius: 16rpx; display: flex; flex-direction: row; align-items: center; padding: 20rpx; min-width: 500rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06); border-width: 1rpx; border-style: solid; border-color: #f0f0f0; }
.pc-thumb { width: 96rpx; height: 96rpx; background-color: #f0f7ff; border-radius: 14rpx; display: flex; align-items: center; justify-content: center; margin-right: 20rpx; flex-shrink: 0; }
.pc-thumb-emoji { font-size: 56rpx; }
.pc-info { flex: 1; }
.pc-name { font-size: 28rpx; color: #1a1a1a; font-weight: bold; display: block; margin-bottom: 6rpx; }
.pc-price { font-size: 32rpx; color: #e84040; font-weight: bold; display: block; margin-bottom: 4rpx; }
.pc-tag { font-size: 22rpx; color: #888; display: block; }

.order-card { background-color: #fff; border-radius: 16rpx; padding: 20rpx 24rpx; min-width: 500rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.06); border-width: 1rpx; border-style: solid; border-color: #f0f0f0; }
.oc-row1 { display: flex; flex-direction: row; align-items: center; margin-bottom: 10rpx; }
.oc-label { font-size: 20rpx; color: #999; background-color: #f5f5f5; border-radius: 4rpx; padding: 2rpx 10rpx; margin-right: 12rpx; flex-shrink: 0; }
.oc-no { font-size: 22rpx; color: #555; flex: 1; }
.oc-status-tag { border-radius: 6rpx; padding: 4rpx 14rpx; flex-shrink: 0; }
.oc-pending { background-color: #fff3e0; }
.oc-pending .oc-status-text { color: #ff8c00; font-size: 22rpx; }
.oc-active { background-color: #e8f5e9; }
.oc-active .oc-status-text { color: #388e3c; font-size: 22rpx; }
.oc-done { background-color: #f5f5f5; }
.oc-done .oc-status-text { color: #888; font-size: 22rpx; }
.oc-amount { font-size: 36rpx; color: #e84040; font-weight: bold; display: block; margin-bottom: 4rpx; }
.oc-items { font-size: 24rpx; color: #888; display: block; }

.chat-input-area { background-color: #fff; border-top-width: 1rpx; border-top-style: solid; border-top-color: #e8e8e8; flex-shrink: 0; }
.quick-reply-panel { background-color: #f8f9fc; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #eee; padding: 16rpx 20rpx; }
.qr-header { display: flex; flex-direction: row; align-items: center; justify-content: space-between; margin-bottom: 14rpx; }
.qr-title { font-size: 24rpx; color: #555; font-weight: bold; }
.qr-close { font-size: 28rpx; color: #aaa; padding: 8rpx; }
.qr-scroll { max-height: 240rpx; }
.qr-item { background-color: #fff; border-radius: 10rpx; padding: 14rpx 20rpx; margin-bottom: 10rpx; border-width: 1rpx; border-style: solid; border-color: #e8e8e8; }
.qr-item:active { background-color: #E3F7ED; }
.qr-text { font-size: 26rpx; color: #333; line-height: 1.5; }

.chat-toolbar { display: flex; flex-direction: row; padding: 16rpx 20rpx 8rpx; gap: 20rpx; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f0f0f0; }
.toolbar-btn { display: flex; flex-direction: column; align-items: center; padding: 10rpx 24rpx; border-radius: 12rpx; background-color: #f5f7fa; }
.toolbar-btn:active { background-color: #e0ecff; }
.toolbar-btn-active { background-color: #e8f0fe; }
.toolbar-icon { font-size: 40rpx; }
.toolbar-label { font-size: 20rpx; color: #555; margin-top: 4rpx; }

.input-row { display: flex; flex-direction: row; align-items: flex-end; padding: 12rpx 20rpx 16rpx; gap: 16rpx; }
.chat-textarea { flex: 1; background-color: #f5f7fa; border-radius: 16rpx; padding: 16rpx 20rpx; font-size: 30rpx; min-height: 80rpx; max-height: 200rpx; color: #333; border-width: 1rpx; border-style: solid; border-color: #e8e8e8; }
.send-btn { background-color: #ccc; border-radius: 16rpx; padding: 18rpx 28rpx; flex-shrink: 0; }
.send-btn-active { background-color: #09C39D; }
.send-btn-text { font-size: 30rpx; color: #fff; font-weight: bold; }

/* ====== 模块三：用户资料 ====== */
.module-info { flex: 1; overflow: hidden; }
.info-scroll { height: 100%; }

.info-user-card { background-color: #09C39D; padding: 40rpx 30rpx 30rpx; display: flex; flex-direction: row; align-items: center; }
.info-big-avatar { font-size: 100rpx; margin-right: 24rpx; }
.info-user-main { flex: 1; }
.info-user-name { font-size: 36rpx; font-weight: bold; color: #fff; display: block; margin-bottom: 16rpx; }
.info-tags-row { display: flex; flex-direction: row; flex-wrap: wrap; gap: 10rpx; }
.info-tag { background-color: rgba(255,255,255,0.2); border-radius: 20rpx; padding: 6rpx 18rpx; }
.info-tag-text { font-size: 22rpx; color: #fff; }

.info-section { background-color: #fff; margin: 16rpx; border-radius: 16rpx; overflow: hidden; }
.info-section-header { display: flex; flex-direction: row; align-items: center; padding: 20rpx 24rpx; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f5f5f5; }
.info-section-icon { font-size: 32rpx; margin-right: 10rpx; }
.info-section-title { font-size: 28rpx; font-weight: bold; color: #333; }
.info-kv { display: flex; flex-direction: row; align-items: center; padding: 18rpx 24rpx; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f5f5f5; }
.info-key { font-size: 28rpx; color: #888; width: 180rpx; flex-shrink: 0; }
.info-val { font-size: 28rpx; color: #333; flex: 1; }
.info-val-red { color: #e84040; font-weight: bold; }

.consult-product { display: flex; flex-direction: row; align-items: center; padding: 20rpx 24rpx; }
.cp-big-emoji { font-size: 60rpx; margin-right: 20rpx; }
.cp-detail { flex: 1; }
.cp-pname { font-size: 30rpx; color: #1a1a1a; font-weight: bold; display: block; margin-bottom: 8rpx; }
.cp-pprice { font-size: 32rpx; color: #e84040; font-weight: bold; display: block; }

.recent-row { display: flex; flex-direction: row; align-items: center; padding: 16rpx 24rpx; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f5f5f5; }
.recent-emoji { font-size: 40rpx; margin-right: 16rpx; }
.recent-detail { flex: 1; }
.recent-name { font-size: 28rpx; color: #333; display: block; margin-bottom: 4rpx; }
.recent-price { font-size: 26rpx; color: #e84040; display: block; }

.order-mini-card { padding: 20rpx 24rpx; border-bottom-width: 1rpx; border-bottom-style: solid; border-bottom-color: #f5f5f5; }
.omc-row1 { display: flex; flex-direction: row; align-items: center; margin-bottom: 8rpx; }
.omc-no { font-size: 22rpx; color: #888; flex: 1; }
.omc-status-tag { border-radius: 6rpx; padding: 4rpx 14rpx; }
.omc-pending { background-color: #fff3e0; }
.omc-pending .omc-status-text { color: #ff8c00; font-size: 22rpx; }
.omc-active { background-color: #e8f5e9; }
.omc-active .omc-status-text { color: #388e3c; font-size: 22rpx; }
.omc-done { background-color: #f5f5f5; }
.omc-done .omc-status-text { color: #888; font-size: 22rpx; }
.omc-row2 { display: flex; flex-direction: row; align-items: center; justify-content: space-between; }
.omc-items { font-size: 26rpx; color: #555; flex: 1; }
.omc-amount { font-size: 28rpx; color: #e84040; font-weight: bold; }

.info-actions { display: flex; flex-direction: row; gap: 20rpx; padding: 24rpx; }
.info-action-btn { flex: 1; background-color: #f5f5f5; border-radius: 20rpx; padding: 22rpx 0; display: flex; align-items: center; justify-content: center; }
.info-action-btn:active { opacity: 0.8; }
.info-action-btn.primary { background-color: #09C39D; }
.info-action-btn.primary .info-action-text { color: #fff; }
.info-action-text { font-size: 30rpx; color: #555; font-weight: bold; }

.info-safe-bottom { height: 140rpx; }

/* 聊天模块底部 TabBar 占位 */
.chat-tabbar-spacer {
	height: 120rpx;
	flex-shrink: 0;
	background-color: #fff;
}
</style>
