mirror of
https://git.hmsn.ink/kospo/svcm/dmz.git
synced 2026-03-20 04:32:22 +09:00
179 lines
4.1 KiB
TypeScript
179 lines
4.1 KiB
TypeScript
/**
|
|
* This is a store that hold the messaging-v1 state
|
|
* It uses the useFetch composition component to make the api calls
|
|
*
|
|
* @see /src/pages/messaging-v1.vue
|
|
* @see /src/composable/useFetch.ts
|
|
* @see /src/components/partials/chat/*.vue
|
|
* @see /src/utils/api/chat
|
|
*/
|
|
|
|
import { acceptHMRUpdate, defineStore } from 'pinia'
|
|
import type { $Fetch } from 'ofetch'
|
|
|
|
export interface Conversation {
|
|
id: number
|
|
name: string
|
|
lastMessage: string
|
|
unreadMessages: boolean
|
|
avatar: string
|
|
}
|
|
export interface Message {
|
|
id: number
|
|
conversationId: number
|
|
messageId: number
|
|
type: 'msg' | 'image' | 'imagelink' | 'system'
|
|
sender: string | null
|
|
avatar: string | null
|
|
content: {
|
|
time: string | null
|
|
text?: string
|
|
subtext?: string
|
|
image_url?: string
|
|
link_image?: string
|
|
link_badge?: string
|
|
}
|
|
}
|
|
|
|
const defaultConversation: Conversation = {
|
|
id: 0,
|
|
name: '',
|
|
lastMessage: '',
|
|
unreadMessages: false,
|
|
avatar: '/images/avatars/placeholder.jpg',
|
|
}
|
|
|
|
export const useChat = defineStore('chat', () => {
|
|
const $fetch = useApiFetch()
|
|
const conversations = ref<Conversation[]>([])
|
|
const messages = ref<Message[]>([])
|
|
const selectedConversationId = ref(0)
|
|
const addConversationOpen = ref(false)
|
|
const mobileConversationDetailsOpen = ref(false)
|
|
const loading = ref(false)
|
|
|
|
const selectedConversation = computed(() => {
|
|
const conversation = conversations.value?.find(
|
|
item => item.id === selectedConversationId.value,
|
|
)
|
|
|
|
if (!conversation) {
|
|
return defaultConversation
|
|
}
|
|
else {
|
|
return conversation
|
|
}
|
|
})
|
|
|
|
async function loadConversations(start = 0, limit = 10) {
|
|
if (loading.value) return
|
|
|
|
loading.value = true
|
|
|
|
try {
|
|
const response = await fetchConversations($fetch, start, limit)
|
|
conversations.value = response.conversations ?? []
|
|
}
|
|
finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function selectConversastion(conversationId: number) {
|
|
if (loading.value) return
|
|
|
|
loading.value = true
|
|
|
|
try {
|
|
const response = await fetchMessages($fetch, conversationId)
|
|
selectedConversationId.value = conversationId
|
|
messages.value = response.messages
|
|
}
|
|
finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function unselectConversation() {
|
|
selectedConversationId.value = 0
|
|
messages.value = []
|
|
}
|
|
|
|
function setAddConversationOpen(value: boolean) {
|
|
addConversationOpen.value = value
|
|
}
|
|
|
|
function setMobileConversationDetailsOpen(value: boolean) {
|
|
mobileConversationDetailsOpen.value = value
|
|
}
|
|
|
|
return {
|
|
conversations,
|
|
messages,
|
|
selectedConversation,
|
|
selectedConversationId,
|
|
addConversationOpen,
|
|
mobileConversationDetailsOpen,
|
|
loading,
|
|
loadConversations,
|
|
setAddConversationOpen,
|
|
setMobileConversationDetailsOpen,
|
|
selectConversastion,
|
|
unselectConversation,
|
|
} as const
|
|
})
|
|
|
|
async function fetchConversations(
|
|
$fetch: $Fetch,
|
|
start = 0,
|
|
limit = 20,
|
|
): Promise<{ conversations: Conversation[], count: number }> {
|
|
let count = 0
|
|
|
|
const { _data: conversations = [], headers } = await $fetch.raw<Conversation[]>(
|
|
`/api/conversations`,
|
|
{
|
|
query: {
|
|
_start: start,
|
|
_limit: limit,
|
|
},
|
|
},
|
|
)
|
|
|
|
if (headers.has('X-Total-Count')) {
|
|
count = parseInt(headers.get('X-Total-Count') ?? '0')
|
|
}
|
|
|
|
return { conversations, count }
|
|
}
|
|
|
|
async function fetchMessages(
|
|
$fetch: $Fetch,
|
|
conversationId: number,
|
|
start = 0,
|
|
limit = 20,
|
|
): Promise<{ messages: Message[], count: number }> {
|
|
let count = 0
|
|
|
|
const { _data: messages = [], headers } = await $fetch.raw<Message[]>(
|
|
`/api/conversations/${conversationId}/messages?_start=${start}&_limit=${limit}`,
|
|
)
|
|
|
|
if (headers.has('X-Total-Count')) {
|
|
count = parseInt(headers.get('X-Total-Count') ?? '0')
|
|
}
|
|
|
|
return { messages, count }
|
|
}
|
|
|
|
/**
|
|
* Pinia supports Hot Module replacement so you can edit your stores and
|
|
* interact with them directly in your app without reloading the page.
|
|
*
|
|
* @see https://pinia.esm.dev/cookbook/hot-module-replacement.html
|
|
* @see https://vitejs.dev/guide/api-hmr.html
|
|
*/
|
|
if (import.meta.hot) {
|
|
import.meta.hot.accept(acceptHMRUpdate(useChat, import.meta.hot))
|
|
}
|