| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- 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<PartMeta[]>([])
- const selected = ref<Set<string>>(new Set())
- const queryOpen = ref(false)
- const search = ref('')
- const pendingSelectLabel = ref<string | null>(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<void> {
- 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,
- }
- })
|