import { defineStore } from 'pinia' import { ref, computed } from 'vue' import type { BulletinPost, BulletinRead } from '@/types' import { listBulletins, listMyReads, markBulletinAsRead, createBulletin, updateBulletin, deleteBulletin, } from '@/api/bulletins' export const useBulletinStore = defineStore('bulletin', () => { const posts = ref([]) const reads = ref([]) const loading = ref(false) const now = computed(() => new Date()) const activePosts = computed(() => { return posts.value.filter((p) => { if (!p.expiresAt) return true return new Date(p.expiresAt) > now.value }) }) const pinnedPosts = computed(() => activePosts.value .filter((p) => p.pinned) .sort((a, b) => { const prioOrder = { urgent: 0, high: 1, normal: 2, low: 3 } return prioOrder[a.priority] - prioOrder[b.priority] }) ) const normalPosts = computed(() => activePosts.value .filter((p) => !p.pinned) .sort((a, b) => { const prioOrder = { urgent: 0, high: 1, normal: 2, low: 3 } const prioDiff = prioOrder[a.priority] - prioOrder[b.priority] if (prioDiff !== 0) return prioDiff return new Date(b.created).getTime() - new Date(a.created).getTime() }) ) const readPostIds = computed(() => new Set(reads.value.map((r) => r.post))) function isRead(postId: string): boolean { return readPostIds.value.has(postId) } function unreadCount(groupId: string): number { return activePosts.value.filter( (p) => p.group === groupId && !isRead(p.id) ).length } async function loadPosts(groupId: string) { try { loading.value = true const [fetchedPosts, fetchedReads] = await Promise.all([ listBulletins(groupId), listMyReads(), ]) posts.value = fetchedPosts reads.value = fetchedReads } catch (error) { console.error('加载公告列表失败:', error) } finally { loading.value = false } } async function markAsRead(postId: string) { if (isRead(postId)) return try { const record = await markBulletinAsRead(postId) if (record) { reads.value.push(record) } } catch (error) { console.error('标记已读失败:', error) } } async function markAllAsRead(groupId: string) { const unread = activePosts.value.filter( (p) => p.group === groupId && !isRead(p.id) ) await Promise.all(unread.map((p) => markAsRead(p.id))) } async function create(data: { group: string title: string content: string priority: 'low' | 'normal' | 'high' | 'urgent' pinned: boolean expiresAt?: string }) { try { const post = await createBulletin(data) posts.value.unshift(post) return post } catch (error: any) { console.error('创建公告失败:', error) throw error } } async function update( postId: string, data: { title?: string content?: string priority?: 'low' | 'normal' | 'high' | 'urgent' pinned?: boolean expiresAt?: string } ) { try { const post = await updateBulletin(postId, data) const index = posts.value.findIndex((p) => p.id === postId) if (index !== -1) { posts.value[index] = { ...posts.value[index], ...post } } return post } catch (error: any) { console.error('更新公告失败:', error) throw error } } async function remove(postId: string) { try { await deleteBulletin(postId) posts.value = posts.value.filter((p) => p.id !== postId) reads.value = reads.value.filter((r) => r.post !== postId) } catch (error: any) { console.error('删除公告失败:', error) throw error } } function clear() { posts.value = [] reads.value = [] loading.value = false } return { posts, reads, loading, activePosts, pinnedPosts, normalPosts, readPostIds, isRead, unreadCount, loadPosts, markAsRead, markAllAsRead, create, update, remove, clear, } })