完成consumer端同步
This commit is contained in:
@@ -1,67 +1,66 @@
|
||||
<template>
|
||||
<template>
|
||||
<view class="chat-page">
|
||||
<!-- 鑱婂ぉ澶撮儴 -->
|
||||
<!-- 聊天顶部 -->
|
||||
<view class="chat-header" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||
<view class="header-content">
|
||||
<view class="header-back" @click="goBack">
|
||||
<text class="back-icon">鈥?/text>
|
||||
<text class="back-icon">‹</text>
|
||||
</view>
|
||||
<view class="header-info">
|
||||
<text class="chat-title">{{ merchantName || '鍦ㄧ嚎瀹㈡湇' }}</text>
|
||||
<text class="chat-status">鍦ㄧ嚎</text>
|
||||
<text class="chat-title">{{ getDisplayMerchantName() }}</text>
|
||||
<text class="chat-status">在线</text>
|
||||
</view>
|
||||
<view class="header-actions">
|
||||
<text class="action-icon" @click="showMoreActions">鈰?/text>
|
||||
<text class="action-icon" @click="showMoreActions">⋯</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 鑱婂ぉ鍐呭 -->
|
||||
<!-- 聊天内容 -->
|
||||
<scroll-view
|
||||
scroll-y
|
||||
direction="vertical"
|
||||
class="chat-content"
|
||||
:scroll-into-view="scrollToView"
|
||||
scroll-with-animation
|
||||
@scrolltoupper="loadMoreHistory"
|
||||
>
|
||||
<!-- 鍗犱綅锛岄槻姝㈠唴瀹硅澶撮儴閬尅 -->
|
||||
<!-- 顶部占位:用于状态栏与标题栏留白 -->
|
||||
<view :style="{ height: (statusBarHeight + 44) + 'px' }"></view>
|
||||
|
||||
<!-- 鑱婂ぉ娑堟伅鍒楄〃 -->
|
||||
<!-- 聊天消息列表 -->
|
||||
<view class="chat-messages">
|
||||
<!-- 绯荤粺鎻愮ず -->
|
||||
<!-- 系统提示 -->
|
||||
<view class="message-item system">
|
||||
<text class="system-text">宸茶繛鎺ュ埌鍟嗗锛屽紑濮嬭亰澶╁惂</text>
|
||||
<text class="system-text">已连接到商家,开始会话</text>
|
||||
</view>
|
||||
|
||||
<!-- 娑堟伅椤?-->
|
||||
<!-- 消息项 -->
|
||||
<view
|
||||
v-for="(message, index) in messages"
|
||||
:key="message.id"
|
||||
:class="['message-item', message.type]"
|
||||
:id="'msg-' + message.id"
|
||||
>
|
||||
<!-- 鏃堕棿鏄剧ず閫昏緫锛氭瘡5鍒嗛挓鏄剧ず涓€娆℃椂闂?-->
|
||||
<view v-if="shouldShowTime(index)" class="time-divider">
|
||||
<text>{{ formatTime(message.rawTime) }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 瀵规柟娑堟伅 -->
|
||||
<!-- 对方消息 -->
|
||||
<view v-if="message.type === 'received'" class="message-wrapper">
|
||||
<image
|
||||
class="avatar"
|
||||
:src="merchantLogo || '/static/logo.png'"
|
||||
:src="getDisplayMerchantLogo()"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view class="message-content-wrapper">
|
||||
<!-- <text class="sender-name">{{ merchantName }}</text> -->
|
||||
|
||||
<view class="message-bubble">
|
||||
<text class="message-text">{{ message.content }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 鎴戠殑娑堟伅 -->
|
||||
<!-- 我的消息 -->
|
||||
<view v-else class="message-wrapper me">
|
||||
<view class="message-content-wrapper">
|
||||
<view class="message-bubble me">
|
||||
@@ -70,29 +69,26 @@
|
||||
</view>
|
||||
<image
|
||||
class="avatar me"
|
||||
:src="userAvatar || '/static/images/default-product.png'"
|
||||
:src="userAvatar !== '' ? userAvatar : '/static/images/default.png'"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 搴曢儴濉厖锛岄槻姝㈣杈撳叆妗嗛伄鎸?-->
|
||||
<!-- 底部填充,避免输入框遮挡 -->
|
||||
<view style="height: 20px;"></view>
|
||||
<view id="bottom-anchor" style="height: 1px;"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 鑱婂ぉ杈撳叆鍖?-->
|
||||
<view class="chat-input-area">
|
||||
<view class="input-tools">
|
||||
<text class="tool-icon" @click="toggleEmoji">馃槉</text>
|
||||
<!-- <text class="tool-icon" @click="chooseImage">馃摲</text> -->
|
||||
<text class="tool-icon" @click="toggleEmoji">😊</text>
|
||||
</view>
|
||||
|
||||
<view class="input-wrapper">
|
||||
<input
|
||||
class="message-input"
|
||||
v-model="inputMessage"
|
||||
placeholder="璇疯緭鍏ユ秷鎭?.."
|
||||
placeholder="请输入要发送的消息..."
|
||||
:adjust-position="true"
|
||||
confirm-type="send"
|
||||
@confirm="sendMessage"
|
||||
@@ -102,12 +98,12 @@
|
||||
:class="{ active: inputMessage.trim().length > 0 }"
|
||||
@click="sendMessage"
|
||||
>
|
||||
鍙戦€?
|
||||
发送
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 琛ㄦ儏閫夋嫨鍣?(绠€鍖栫増) -->
|
||||
<scroll-view scroll-y v-if="showEmoji" class="emoji-picker">
|
||||
<!-- 消息选择器(例如表情) -->
|
||||
<scroll-view direction="vertical" v-if="showEmoji" class="emoji-picker">
|
||||
<view class="emoji-grid">
|
||||
<text
|
||||
v-for="emoji in emojiList"
|
||||
@@ -124,32 +120,198 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
import { ref, onUnmounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import supabaseService from '@/utils/supabaseService.uts'
|
||||
import type { ChatMessage } from '@/utils/supabaseService.uts'
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
// import { getCurrentUser } from '@/utils/store.uts'
|
||||
import type { AkSupaRealtimeChannel } from '@/components/supadb/aksupa.uts'
|
||||
|
||||
// 鐣岄潰鐘舵€?
|
||||
const statusBarHeight = ref(0)
|
||||
const scrollToView = ref('')
|
||||
const showEmoji = ref(false)
|
||||
const inputMessage = ref('')
|
||||
type ChatViewMessage = {
|
||||
id: string
|
||||
type: string
|
||||
content: string
|
||||
rawTime: string
|
||||
senderId: string
|
||||
}
|
||||
|
||||
// 涓氬姟鏁版嵁
|
||||
const merchantId = ref('')
|
||||
const merchantName = ref('')
|
||||
const merchantLogo = ref('')
|
||||
const userAvatar = ref('')
|
||||
const currentUserId = ref('')
|
||||
const messages = ref<any[]>([])
|
||||
// 界面状态
|
||||
const statusBarHeight = ref<number>(0)
|
||||
const scrollToView = ref<string>('')
|
||||
const showEmoji = ref<boolean>(false)
|
||||
const inputMessage = ref<string>('')
|
||||
|
||||
const emojiList = ['馃槉', '馃槀', '馃憤', '馃憣', '鉂わ笍', '馃尮', '馃檹', '馃帀', '馃槨', '馃槶', '馃', '馃憢', '馃', '馃拪', '馃彞']
|
||||
let realtimeChannel: any | null = null
|
||||
// 业务数据
|
||||
const merchantId = ref<string>('')
|
||||
const merchantName = ref<string>('')
|
||||
const merchantLogo = ref<string>('')
|
||||
const userAvatar = ref<string>('')
|
||||
const currentUserId = ref<string>('')
|
||||
const messages = ref<ChatViewMessage[]>([])
|
||||
|
||||
onLoad((options: any) => {
|
||||
// 鑾峰彇鐘舵€佹爮楂樺害
|
||||
const emojiList = ['😊','🙂','😂','😍','😢','👍','👏','😄','😁','😜','😭','😮','🤔','😎','😅']
|
||||
let realtimeChannel: AkSupaRealtimeChannel | null = null
|
||||
|
||||
function loadMoreHistory(): void {
|
||||
// TODO: 实现下拉加载更多历史
|
||||
}
|
||||
|
||||
function scrollToBottom(): void {
|
||||
// 延时滚动以确保视图更新
|
||||
setTimeout(() => {
|
||||
scrollToView.value = 'bottom-anchor'
|
||||
// Hack: 重置再设置以强制触发
|
||||
setTimeout(() => {
|
||||
const lastId = messages.value.length > 0 ? messages.value[messages.value.length - 1].id : ''
|
||||
scrollToView.value = lastId != '' ? ('msg-' + lastId) : 'bottom-anchor'
|
||||
}, 50)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
function emptyChatMessages(): ChatViewMessage[] {
|
||||
return [] as ChatViewMessage[]
|
||||
}
|
||||
|
||||
function formatMessage(m: ChatMessage): ChatViewMessage {
|
||||
let isMe = false
|
||||
if (currentUserId.value != '') {
|
||||
isMe = m.sender_id === currentUserId.value
|
||||
} else {
|
||||
isMe = m.is_from_user === true
|
||||
}
|
||||
|
||||
const rawTime = m.created_at != null && m.created_at != '' ? m.created_at : new Date().toISOString()
|
||||
const content = m.content != null ? m.content.toString() : ''
|
||||
const senderId = m.sender_id != null ? m.sender_id.toString() : ''
|
||||
|
||||
return {
|
||||
id: m.id,
|
||||
type: isMe ? 'sent' : 'received',
|
||||
content: content,
|
||||
rawTime: rawTime,
|
||||
senderId: senderId
|
||||
}
|
||||
}
|
||||
|
||||
function getDisplayMerchantName(): string {
|
||||
const name = merchantName.value != null ? merchantName.value.toString() : ''
|
||||
return name !== '' ? name : '在线客服'
|
||||
}
|
||||
|
||||
function getDisplayMerchantLogo(): string {
|
||||
const logo = merchantLogo.value != null ? merchantLogo.value.toString() : ''
|
||||
return logo !== '' ? logo : '/static/logo.png'
|
||||
}
|
||||
|
||||
async function loadHistory(): Promise<void> {
|
||||
let rawMsgs: ChatMessage[] = []
|
||||
|
||||
if (merchantId.value != '') {
|
||||
rawMsgs = await supabaseService.getChatMessages(merchantId.value)
|
||||
} else {
|
||||
rawMsgs = await supabaseService.getUserChatMessages()
|
||||
}
|
||||
|
||||
const formatted = rawMsgs.reverse().map((m: ChatMessage) => formatMessage(m))
|
||||
messages.value = formatted
|
||||
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
function startRealtimeSubscription(): void {
|
||||
if (currentUserId.value == '') return
|
||||
|
||||
console.log('启动实时订阅')
|
||||
const filterObj = ({
|
||||
event: 'INSERT',
|
||||
schema: 'public',
|
||||
table: 'ml_chat_messages'
|
||||
} as UTSJSONObject)
|
||||
|
||||
realtimeChannel = supa.channel(`chat_${currentUserId.value}`)
|
||||
.on(
|
||||
'postgres_changes',
|
||||
filterObj,
|
||||
(payload: UTSJSONObject) => {
|
||||
console.log('收到变更事件', payload)
|
||||
const newAny = payload.get('new')
|
||||
if (newAny == null) return
|
||||
const newMsg = (newAny instanceof UTSJSONObject) ? (newAny as UTSJSONObject) : (JSON.parse(JSON.stringify(newAny)) as UTSJSONObject)
|
||||
const senderId = newMsg.getString('sender_id') ?? ''
|
||||
if (senderId === merchantId.value || merchantId.value == '') {
|
||||
const realtimeMessage = {
|
||||
id: newMsg.getString('id') ?? '',
|
||||
content: newMsg.getString('content') ?? '',
|
||||
msg_type: newMsg.getString('msg_type') ?? '',
|
||||
sender_id: senderId,
|
||||
receiver_id: newMsg.getString('receiver_id') ?? '',
|
||||
is_from_user: false,
|
||||
created_at: newMsg.getString('created_at') ?? ''
|
||||
} as ChatMessage
|
||||
const formatted = formatMessage(realtimeMessage)
|
||||
|
||||
messages.value.push(formatted)
|
||||
scrollToBottom()
|
||||
}
|
||||
}
|
||||
)
|
||||
.subscribe((_status) => {})
|
||||
}
|
||||
|
||||
function goBack(): void {
|
||||
uni.navigateBack({})
|
||||
}
|
||||
|
||||
function formatTime(isoString: string): string {
|
||||
const date = new Date(isoString)
|
||||
const now = new Date()
|
||||
|
||||
if (date.toDateString() === now.toDateString()) {
|
||||
const h = date.getHours().toString().padStart(2, "0")
|
||||
const m = date.getMinutes().toString().padStart(2, "0")
|
||||
return `${h}:${m}`
|
||||
}
|
||||
|
||||
const mo = (date.getMonth() + 1).toString().padStart(2, "0")
|
||||
const d = date.getDate().toString().padStart(2, "0")
|
||||
const h = date.getHours().toString().padStart(2, "0")
|
||||
const m = date.getMinutes().toString().padStart(2, "0")
|
||||
return `${mo}-${d} ${h}:${m}`
|
||||
}
|
||||
|
||||
function shouldShowTime(index: number): boolean {
|
||||
if (index === 0) return true
|
||||
const prev = messages.value[index - 1]
|
||||
const curr = messages.value[index]
|
||||
const t1 = new Date(prev.rawTime).getTime()
|
||||
const t2 = new Date(curr.rawTime).getTime()
|
||||
return (t2 - t1) > 300000
|
||||
}
|
||||
|
||||
function toggleEmoji(): void {
|
||||
showEmoji.value = !showEmoji.value
|
||||
if (showEmoji.value) {
|
||||
scrollToBottom()
|
||||
}
|
||||
}
|
||||
|
||||
function insertEmoji(emoji: string): void {
|
||||
inputMessage.value += emoji
|
||||
}
|
||||
|
||||
function showMoreActions(): void {
|
||||
uni.showActionSheet({
|
||||
itemList: ['清空记录', '联系客服'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
messages.value = emptyChatMessages()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
// 获取状态栏高度
|
||||
const sys = uni.getSystemInfoSync()
|
||||
statusBarHeight.value = sys.statusBarHeight ?? 0
|
||||
|
||||
@@ -158,128 +320,41 @@ onLoad((options: any) => {
|
||||
const mid = optObj.getString('merchantId') ?? ''
|
||||
if (mid !== '') {
|
||||
merchantId.value = mid
|
||||
merchantName.value = optObj.getString('merchantName') ?? '鍟嗗'
|
||||
merchantLogo.value = optObj.getString('merchantLogo') ?? ''
|
||||
console.log('寮€濮嬭亰澶╋紝鍟嗗ID:', merchantId.value)
|
||||
merchantName.value = optObj.getString('merchantName') ?? '商家'
|
||||
merchantLogo.value = optObj.getString('merchantLogo') ?? '/static/logo.png'
|
||||
console.log('已初始化会话,商家ID:', merchantId.value)
|
||||
} else {
|
||||
merchantName.value = '骞冲彴瀹㈡湇'
|
||||
merchantName.value = '平台客服'
|
||||
}
|
||||
|
||||
// 鑾峰彇褰撳墠鐢ㄦ埛
|
||||
// 获取当前用户
|
||||
const uid = supabaseService.getCurrentUserId()
|
||||
if (uid != null) {
|
||||
currentUserId.value = uid
|
||||
// 绠€鍗曡幏鍙栦竴涓嬪ご鍍忥紝瀹為檯搴旇浠嶱rofile鑾峰彇
|
||||
userAvatar.value = 'https://picsum.photos/100'
|
||||
// 简单获取一下头像,实际应该从 Profile 获取
|
||||
userAvatar.value = '/static/logo.png'
|
||||
}
|
||||
|
||||
// 鍔犺浇鍘嗗彶娑堟伅
|
||||
// 加载历史消息
|
||||
loadHistory()
|
||||
|
||||
// 寮€鍚疄鏃惰闃?
|
||||
// 启动实时订阅
|
||||
startRealtimeSubscription()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (realtimeChannel != null) {
|
||||
supa.removeChannel(realtimeChannel!)
|
||||
supa.removeChannel(realtimeChannel as AkSupaRealtimeChannel)
|
||||
}
|
||||
})
|
||||
|
||||
// 鍔犺浇鍘嗗彶璁板綍
|
||||
const loadHistory = async () => {
|
||||
let rawMsgs: ChatMessage[] = []
|
||||
|
||||
if (merchantId.value) {
|
||||
// 鑾峰彇涓庣壒瀹氬晢瀹剁殑鑱婂ぉ
|
||||
rawMsgs = await supabaseService.getChatMessages(merchantId.value)
|
||||
} else {
|
||||
// 鑾峰彇鎵€鏈夛紙姣斿瀹㈡湇锛?
|
||||
rawMsgs = await supabaseService.getUserChatMessages()
|
||||
}
|
||||
|
||||
const formatted = rawMsgs.reverse().map((m: ChatMessage) => formatMessage(m))
|
||||
messages.value = formatted
|
||||
|
||||
scrollToBottom()
|
||||
}
|
||||
|
||||
const loadMoreHistory = () => {
|
||||
// TODO: 瀹炵幇涓嬫媺鍔犺浇鏇村鍘嗗彶
|
||||
}
|
||||
|
||||
// 寮€鍚疄鏃惰闃?
|
||||
const startRealtimeSubscription = () => {
|
||||
if (currentUserId.value == '') return
|
||||
|
||||
console.log('寮€鍚秷鎭洃鍚?..')
|
||||
const filterObj = ({
|
||||
event: 'INSERT',
|
||||
schema: 'public',
|
||||
table: 'ml_chat_messages'
|
||||
} as UTSJSONObject)
|
||||
realtimeChannel = supa.channel(`chat_${currentUserId.value}`)
|
||||
.on(
|
||||
'postgres_changes',
|
||||
filterObj,
|
||||
(payload: any) => {
|
||||
console.log('鏀跺埌鏂版秷鎭?', payload)
|
||||
const payloadObj = (payload instanceof UTSJSONObject) ? (payload as UTSJSONObject) : (JSON.parse(JSON.stringify(payload ?? {})) as UTSJSONObject)
|
||||
const newAny = payloadObj.get('new')
|
||||
if (newAny == null) return
|
||||
const newMsg = (newAny instanceof UTSJSONObject) ? (newAny as UTSJSONObject) : (JSON.parse(JSON.stringify(newAny)) as UTSJSONObject)
|
||||
// 鍙湁鏉ヨ嚜褰撳墠鑱婂ぉ鐨勫晢瀹剁殑娑堟伅鎵嶆樉绀猴紝鎴栬€呭鏋滄槸鍏ㄥ眬瀹㈡湇妯″紡
|
||||
const senderId = newMsg.getString('sender_id') ?? ''
|
||||
if (senderId === merchantId.value || merchantId.value == '') {
|
||||
const formatted = formatMessage({
|
||||
id: newMsg.getString('id') ?? '',
|
||||
content: newMsg.getString('content') ?? '',
|
||||
msg_type: newMsg.getString('msg_type') ?? '',
|
||||
sender_id: senderId,
|
||||
receiver_id: newMsg.getString('receiver_id') ?? '',
|
||||
is_from_user: false, // 鏀跺埌鐨勪竴瀹氫笉鏄嚜宸卞彂鐨?
|
||||
created_at: newMsg.getString('created_at') ?? ''
|
||||
} as ChatMessage)
|
||||
|
||||
messages.value.push(formatted)
|
||||
scrollToBottom()
|
||||
|
||||
// 闇囧姩鎻愮ず
|
||||
uni.vibrateShort({})
|
||||
}
|
||||
}
|
||||
)
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
// 鏍煎紡鍖栨秷鎭?
|
||||
const formatMessage = (m: ChatMessage): any => {
|
||||
// 濡傛灉 sender_id 鏄嚜宸憋紝灏辨槸 'sent'锛屽惁鍒?'received'
|
||||
// 娉ㄦ剰锛氭暟鎹簱瀛楁 is_from_user 鏈夋椂鍙兘鍙槸鏍囪鏄惁鐢盋绔敤鎴峰彂璧凤紝
|
||||
// 鏈€鍑嗙‘鐨勬槸瀵规瘮 id
|
||||
let isMe = false
|
||||
if (currentUserId.value) {
|
||||
isMe = m.sender_id === currentUserId.value
|
||||
} else {
|
||||
isMe = m.is_from_user === true
|
||||
}
|
||||
|
||||
return {
|
||||
id: m.id,
|
||||
type: isMe ? 'sent' : 'received',
|
||||
content: m.content,
|
||||
rawTime: m.created_at || new Date().toISOString(),
|
||||
senderId: m.sender_id
|
||||
}
|
||||
}
|
||||
|
||||
const sendMessage = async () => {
|
||||
const text = inputMessage.value.trim()
|
||||
if (text == '') return
|
||||
|
||||
// 涔愯鏇存柊 UI
|
||||
// 乐观更新 UI
|
||||
const tempId = 'temp_' + Date.now()
|
||||
const tempMsg = {
|
||||
const tempMsg: ChatViewMessage = {
|
||||
id: tempId,
|
||||
type: 'sent',
|
||||
content: text,
|
||||
@@ -291,87 +366,23 @@ const sendMessage = async () => {
|
||||
scrollToBottom()
|
||||
showEmoji.value = false
|
||||
|
||||
// 鍙戦€佽姹?
|
||||
// 娉ㄦ剰锛氬鏋?merchantId 涓虹┖锛宻endChatMessage 绗簩涓弬鏁颁紶 null锛屼細鍙樻垚鏃犱富娑堟伅
|
||||
const success = await supabaseService.sendChatMessage(text, merchantId.value ? merchantId.value : null)
|
||||
// 发送请求
|
||||
// 注意:如果 merchantId 为空,sendChatMessage 第二个参数传 null,会变成无主消息
|
||||
const targetMerchantId = merchantId.value != '' ? merchantId.value : null
|
||||
const success = await supabaseService.sendChatMessage(text, targetMerchantId)
|
||||
|
||||
if (!success) {
|
||||
uni.showToast({ title: '鍙戦€佸け璐?, icon: 'none' })
|
||||
// 杩欓噷鍙互鍔犱竴涓噸璇曟寜閽垨绉婚櫎娑堟伅
|
||||
uni.showToast({ title: '发送失败', icon: 'none' })
|
||||
// 这里可以重试或删除临时消息
|
||||
}
|
||||
}
|
||||
|
||||
const scrollToBottom = () => {
|
||||
// 寤舵椂婊氬姩浠ョ‘淇濊鍥炬洿鏂?
|
||||
setTimeout(() => {
|
||||
scrollToView.value = 'bottom-anchor'
|
||||
// Hack: 閲嶇疆鍐嶈缃互寮哄埗瑙﹀彂
|
||||
setTimeout(() => {
|
||||
scrollToView.value = 'msg-' + (messages.value.length > 0 ? messages.value[messages.value.length-1].id : '')
|
||||
}, 50)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack({})
|
||||
}
|
||||
|
||||
const formatTime = (isoString: string): string => {
|
||||
const date = new Date(isoString)
|
||||
const now = new Date()
|
||||
|
||||
// 濡傛灉鏄粖澶╋紝鏄剧ず HH:mm
|
||||
if (date.toDateString() === now.toDateString()) {
|
||||
const h = date.getHours().toString().padStart(2, '0')
|
||||
const m = date.getMinutes().toString().padStart(2, '0')
|
||||
return `${h}:${m}`
|
||||
}
|
||||
// 鍚﹀垯鏄剧ず MM-DD HH:mm
|
||||
const mo = (date.getMonth() + 1).toString().padStart(2, '0')
|
||||
const d = date.getDate().toString().padStart(2, '0')
|
||||
const h = date.getHours().toString().padStart(2, '0')
|
||||
const m = date.getMinutes().toString().padStart(2, '0')
|
||||
return `${mo}-${d} ${h}:${m}`
|
||||
}
|
||||
|
||||
const shouldShowTime = (index: number): boolean => {
|
||||
if (index === 0) return true
|
||||
const prev = messages.value[index - 1]
|
||||
const curr = messages.value[index]
|
||||
const t1 = new Date(prev.rawTime).getTime()
|
||||
const t2 = new Date(curr.rawTime).getTime()
|
||||
// 闂撮殧瓒呰繃5鍒嗛挓(300000ms)鏄剧ず鏃堕棿
|
||||
return (t2 - t1) > 300000
|
||||
}
|
||||
|
||||
const toggleEmoji = () => {
|
||||
showEmoji.value = !showEmoji.value
|
||||
if (showEmoji.value) {
|
||||
scrollToBottom()
|
||||
}
|
||||
}
|
||||
|
||||
const insertEmoji = (emoji: string) => {
|
||||
inputMessage.value += emoji
|
||||
}
|
||||
|
||||
const showMoreActions = () => {
|
||||
uni.showActionSheet({
|
||||
itemList: ['娓呯┖璁板綍', '鎶曡瘔鍟嗗'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
messages.value = [] // 浠呮湰鍦版竻绌?
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.chat-page {
|
||||
background-color: #f5f5f5;
|
||||
height: 100vh;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -620,4 +631,3 @@ const showMoreActions = () => {
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user