import { computed, ref, watch, watchEffect, watchPostEffect } from 'vue' import { autoSetModeCallback, unSetModelUpdate, createTemploraryID } from './sys' import { custom } from '@/env' import { fetchFuseModels, postAddFuseModel, postDeleteFuseModel, postUpdateFuseModels, SceneType } from '@/api' import { deleteStoreItem, addStoreItem, updateStoreItem, fetchStoreItems, saveStoreItems, recoverStoreItems, deepIsRevise } from '@/utils' import { initialTaggings } from './tagging' import { initialMeasures } from './measure' import type { FuseModel as SModel, FuseModelAttrs } from '@/api' export type FuseModel = SModel & { loaded: boolean, error: boolean, progress: number } export type FuseModels = FuseModel[] export type { FuseModelAttrs } from '@/api' export const fuseModels = ref([]) export const defaultFuseModelAttrs: FuseModelAttrs = { show: true, scale: 100, opacity: 100, bottom: 0, position: {x: 0, y: 0, z: 0}, rotation: {x: 0, y: 0, z: 0} } export const createFuseModels = (model: Partial = {}): FuseModel => serviceToLocal({ id: createTemploraryID(), modelId: 0, fusionNumId: 0, url: '', fusionId: 0, title: '', type: SceneType.SWMX, size: 0, time: new Date().toString(), ...defaultFuseModelAttrs, ...model }) export const getFuseModel = (modelId: FuseModel['id']) => fuseModels.value.find(model => model.id === modelId) export const getFuseModelShowVariable = (model: FuseModel) => computed({ get: () => custom.modelsChangeStore ? model.show : custom.showModelsMap.get(model) || false, set: (show: boolean) => { if (custom.modelsChangeStore) { model.show = show } else { custom.showModelsMap.set(model, show) } } }) export const fuseModelsLoaded = ref(false) watchPostEffect(() => { const loaded = fuseModels.value .filter(model => getFuseModelShowVariable(model).value) .every(model => model.loaded || model.error) fuseModelsLoaded.value = loaded }) let bcModels: FuseModels = [] export const getBackupFuseModels = () => bcModels export const backupFuseModels = () => { bcModels = fuseModels.value.map(model => ({ ...model, rotation: {...model.rotation}, position: {...model.position}, })) } watchEffect(() => { for (const model of bcModels) { const newModel = getFuseModel(model.id) if (newModel) { model.progress = newModel.progress model.error = newModel.error model.loaded = newModel.loaded } } }) const serviceToLocal = (model: SModel): FuseModel => ({ ...model, error: false, loaded: false, progress: 0, }) const initFuseModel = (model: FuseModel) => { custom.showModelsMap.set(model, model.show) } export const recoverFuseModels = () => { const backupItems = getBackupFuseModels() fuseModels.value = backupItems.map(oldItem => { const model = fuseModels.value.find(item => item.id === oldItem.id) return model ? Object.assign(model, oldItem) : serviceToLocal(oldItem) }) } export const updateFuseModel = updateStoreItem(fuseModels, postUpdateFuseModels) export const deleteFuseModel = deleteStoreItem(fuseModels, postDeleteFuseModel) export const addFuseModel = async (model: FuseModel) => { const addModel = serviceToLocal(await postAddFuseModel(model)) initFuseModel(addModel) unSetModelUpdate(() => fuseModels.value.push(addModel)) } export const initialFuseModels = fetchStoreItems( fuseModels, fetchFuseModels, () => { for (const model of fuseModels.value) { initFuseModel(model) } backupFuseModels() }, smodels => smodels.map(serviceToLocal), ) export const saveFuseModels = saveStoreItems( fuseModels, getBackupFuseModels, { update: updateFuseModel, delete: deleteFuseModel } ) export const autoSaveFuseModels = autoSetModeCallback(fuseModels, { isUpdate: (fuseModels) => deepIsRevise( fuseModels.map(item => ({...item, loaded: true, error: true, progress: 0})), getBackupFuseModels().map(item => ({...item, loaded: true, error: true, progress: 0})) ), backup: backupFuseModels, recovery: recoverFuseModels, save: async () => { await saveFuseModels() for (const model of bcModels) { const currentModel = getFuseModel(model.id) if (currentModel && currentModel.show !== model.show) { custom.showModelsMap.set(currentModel, currentModel.show) } } await Promise.all([ initialTaggings(), initialMeasures() ]) }, })