feat:蓝牙绑定和在线客服

This commit is contained in:
李伊帆
2026-10-13 16:23:43 +08:00
parent d4b02745e1
commit e22ebd6bef
128 changed files with 10429 additions and 385 deletions

View File

@@ -0,0 +1,132 @@
import { onShow, onUnload } from '@dcloudio/uni-app'
import { computed, ref } from 'vue'
import { fetchMessagePage, markAllMessagesRead, markMessageRead } from '@/api/message'
import { refreshUnreadMessageCount } from '@/hooks/use-message-inbox'
import { getErrorMessage } from '@/utils/api-error'
import { onMessagePush } from '@/utils/message-socket'
import type { AppMessageVo } from '@/types/message'
import { formatNotifyTime, isUnreadMessage, normalizeMessageId } from './notify.utils'
const PAGE_SIZE = 20
export function useNotify() {
const messages = ref<AppMessageVo[]>([])
const loading = ref(false)
const loadingMore = ref(false)
const pageNum = ref(1)
const total = ref(0)
const sectionTitle = ref('全部家庭')
const hasMore = computed(() => messages.value.length < total.value)
let unsubscribePush: (() => void) | null = null
async function loadMessages(reset = false) {
if (loading.value || loadingMore.value) return
if (reset) {
pageNum.value = 1
loading.value = true
} else {
if (!hasMore.value && messages.value.length > 0) return
loadingMore.value = true
}
try {
const { rows, total: nextTotal } = await fetchMessagePage({
pageNum: pageNum.value,
pageSize: PAGE_SIZE,
})
total.value = nextTotal
if (reset) {
messages.value = rows
} else {
const map = new Map<string, AppMessageVo>()
for (const item of [...messages.value, ...rows]) {
const id = normalizeMessageId(item)
if (id) map.set(id, item)
}
messages.value = Array.from(map.values())
}
const homeName = rows.find((item) => item.homeName)?.homeName
if (homeName) sectionTitle.value = homeName
if (rows.length > 0) {
pageNum.value += 1
}
} catch (err) {
uni.showToast({ title: getErrorMessage(err, '加载通知失败'), icon: 'none' })
} finally {
loading.value = false
loadingMore.value = false
}
}
async function onRefresh() {
await loadMessages(true)
await refreshUnreadMessageCount()
}
async function onLoadMore() {
await loadMessages(false)
}
async function onItemTap(message: AppMessageVo) {
const messageId = normalizeMessageId(message)
if (!messageId) return
if (isUnreadMessage(message)) {
try {
await markMessageRead(messageId)
messages.value = messages.value.map((item) =>
normalizeMessageId(item) === messageId ? { ...item, readFlag: '1' } : item,
)
await refreshUnreadMessageCount()
} catch (err) {
uni.showToast({ title: getErrorMessage(err, '标记已读失败'), icon: 'none' })
}
}
const deviceId = message.deviceId
if (deviceId !== undefined && deviceId !== null && deviceId !== '') {
uni.navigateTo({
url: `/pages/device/detail/index?deviceId=${encodeURIComponent(String(deviceId))}`,
})
}
}
async function onMarkAllRead() {
try {
await markAllMessagesRead()
messages.value = messages.value.map((item) => ({ ...item, readFlag: '1' }))
await refreshUnreadMessageCount()
uni.showToast({ title: '已全部标为已读', icon: 'none' })
} catch (err) {
uni.showToast({ title: getErrorMessage(err, '操作失败'), icon: 'none' })
}
}
onShow(() => {
void onRefresh()
unsubscribePush = onMessagePush(() => {
void onRefresh()
})
})
onUnload(() => {
unsubscribePush?.()
unsubscribePush = null
})
return {
messages,
loading,
loadingMore,
hasMore,
sectionTitle,
formatNotifyTime,
isUnreadMessage,
onRefresh,
onLoadMore,
onItemTap,
onMarkAllRead,
}
}