import { defineStore } from 'pinia' import { computed, ref } from 'vue' import { renamePart as apiRenamePart } from '../api/models' import { getViewer } from '../three/instance' import type { PartMeta, PartStatus } from '../types' import { useModelStore } from './model' export const usePartsStore = defineStore('parts', () => { const parts = ref([]) const selected = ref>(new Set()) const queryOpen = ref(false) const search = ref('') const pendingSelectLabel = ref(null) const selectedParts = computed(() => parts.value.filter((p) => selected.value.has(p.id))) const selectedCount = computed(() => selected.value.size) function byId(id: string): PartMeta | undefined { return parts.value.find((p) => p.id === id) } function setParts(list: PartMeta[]): void { parts.value = list selected.value = new Set() } function syncViewerSelection(): void { getViewer()?.setSelectedIds([...selected.value]) } function selectOnly(id: string | null): void { selected.value = new Set(id ? [id] : []) syncViewerSelection() } function toggle(id: string, additive: boolean): void { if (!additive) { selectOnly(id); return } const next = new Set(selected.value) if (next.has(id)) next.delete(id) else next.add(id) selected.value = next syncViewerSelection() } function clearSelection(): void { selected.value = new Set() syncViewerSelection() } function setColor(id: string, hex: string, status: PartStatus | null): void { const part = byId(id) if (!part) return part.colorHex = hex part.status = status getViewer()?.setPartColor(id, hex, status) } function resetColor(id: string): void { const part = byId(id) if (!part) return part.colorHex = null part.status = null getViewer()?.resetPart(id) } function applyPreset(hex: string, status: PartStatus | null): void { if (!selected.value.size) return selected.value.forEach((id) => setColor(id, hex, status)) } function resetSelected(): void { if (!selected.value.size) return selected.value.forEach((id) => resetColor(id)) } function resetAll(): void { parts.value.forEach((p) => resetColor(p.id)) } /** 重命名部件(写回 .glb 并同步映射表),随后重载模型并按新名重新选中。 */ async function renamePart(label: string, newName: string): Promise { const modelStore = useModelStore() const result = await apiRenamePart(modelStore.current, label, newName) pendingSelectLabel.value = result.new_label modelStore.requestReload() } return { parts, selected, queryOpen, search, pendingSelectLabel, selectedParts, selectedCount, byId, setParts, selectOnly, toggle, clearSelection, setColor, resetColor, applyPreset, resetSelected, resetAll, renamePart, } })