Files
opencloud/src/stores/encyclopedia.ts
T
2026-07-18 20:49:09 +08:00

105 lines
3.1 KiB
TypeScript

import { computed, ref } from 'vue'
import { defineStore } from 'pinia'
import { apiRequest } from '@/lib/api'
import { useAuthStore } from '@/stores/auth'
import type { ApiCollection } from '@/types/api'
import type { CloudType, UserCollection } from '@/types/database'
export interface CollectionPreviewCloud {
id: string
image_url: string
thumbnail_url: string | null
captured_at: string | null
created_at: string
location_name: string | null
}
export interface CollectionEntry extends UserCollection {
firstCloud: CollectionPreviewCloud | null
}
function getErrorMessage(error: unknown) {
return error instanceof Error ? error.message : '图鉴收藏加载失败'
}
export const useEncyclopediaStore = defineStore('encyclopedia', () => {
const authStore = useAuthStore()
const cloudTypes = ref<CloudType[]>([])
const myCollection = ref<CollectionEntry[]>([])
const loadingCloudTypes = ref(false)
const loadingCollection = ref(false)
const cloudTypesLoaded = ref(false)
const collectionLoadedForUserId = ref<string | null>(null)
const collectionError = ref('')
const collectionMap = computed(() => new Map(myCollection.value.map(item => [item.cloud_type_id, item])))
const unlockedCount = computed(() => myCollection.value.length)
const unlockProgress = computed(() => `${unlockedCount.value}/${cloudTypes.value.length || 10}`)
const unlockPercent = computed(() => cloudTypes.value.length
? Math.round(unlockedCount.value / cloudTypes.value.length * 100)
: 0)
async function fetchCloudTypes(force = false) {
if (cloudTypesLoaded.value && !force) return
loadingCloudTypes.value = true
try {
cloudTypes.value = await apiRequest<CloudType[]>('/cloud-types', { auth: false })
cloudTypesLoaded.value = true
} finally {
loadingCloudTypes.value = false
}
}
async function fetchMyCollection(force = false) {
const userId = authStore.user?.id ?? null
if (!userId) {
myCollection.value = []
collectionLoadedForUserId.value = null
collectionError.value = ''
return
}
if (!force && collectionLoadedForUserId.value === userId) return
loadingCollection.value = true
collectionError.value = ''
try {
const rows = await apiRequest<ApiCollection[]>('/collections/me')
myCollection.value = rows.map(({ first_cloud, cloud_type: _cloudType, ...collection }) => ({
...collection,
firstCloud: first_cloud,
}))
collectionLoadedForUserId.value = userId
} catch (error) {
myCollection.value = []
collectionLoadedForUserId.value = userId
collectionError.value = getErrorMessage(error)
} finally {
loadingCollection.value = false
}
}
function isUnlocked(cloudTypeId: number) {
return collectionMap.value.has(cloudTypeId)
}
function getCollectionEntry(cloudTypeId: number) {
return collectionMap.value.get(cloudTypeId) ?? null
}
return {
cloudTypes,
myCollection,
loadingCloudTypes,
loadingCollection,
collectionError,
unlockedCount,
unlockProgress,
unlockPercent,
fetchCloudTypes,
fetchMyCollection,
isUnlocked,
getCollectionEntry,
}
})