import { defineStore } from "pinia"; import type { PreviewData, SubmitResult, UploadFileAsset, UploadItem } from "../api/appraisal"; type ProductState = { categoryId: number; categoryName: string; brandId: number; brandName: string; }; type ExtraState = { purchaseChannel: string; purchasePrice: string; purchaseDate: string; usageStatus: string; conditionDesc: string; accessories: string[]; remark: string; }; type ReturnAddressState = { id: number; consignee: string; mobile: string; province: string; city: string; district: string; detailAddress: string; fullAddress: string; isDefault: boolean; }; const storageKey = "anxinyan_appraisal_flow"; const legacyDemoExtra: ExtraState = { purchaseChannel: "专柜", purchasePrice: "8500", purchaseDate: "", usageStatus: "light_use", conditionDesc: "轻微使用痕迹", accessories: ["防尘袋", "包装盒"], remark: "", }; function initialProduct(): ProductState { return { categoryId: 0, categoryName: "", brandId: 0, brandName: "", }; } function initialExtra(): ExtraState { return { purchaseChannel: "", purchasePrice: "", purchaseDate: "", usageStatus: "", conditionDesc: "", accessories: [], remark: "", }; } function isLegacyDemoExtra(extra: Partial | undefined) { if (!extra) return false; const accessories = Array.isArray(extra.accessories) ? extra.accessories : []; return ( extra.purchaseChannel === legacyDemoExtra.purchaseChannel && extra.purchasePrice === legacyDemoExtra.purchasePrice && (extra.purchaseDate || "") === legacyDemoExtra.purchaseDate && extra.usageStatus === legacyDemoExtra.usageStatus && extra.conditionDesc === legacyDemoExtra.conditionDesc && (extra.remark || "") === legacyDemoExtra.remark && accessories.length === legacyDemoExtra.accessories.length && accessories.every((item, index) => item === legacyDemoExtra.accessories[index]) ); } function initialReturnAddress(): ReturnAddressState { return { id: 0, consignee: "", mobile: "", province: "", city: "", district: "", detailAddress: "", fullAddress: "", isDefault: false, }; } export const useAppraisalStore = defineStore("appraisal", { state: () => ({ draftId: 0, serviceProvider: "anxinyan", serviceMode: "physical", pricePackageId: 0, pricePackageName: "", pricePackageCode: "", pricePackagePrice: 0, currentStep: 1, product: initialProduct(), extra: initialExtra(), returnAddress: initialReturnAddress(), uploadTemplateId: 0, requiredItems: [] as UploadItem[], optionalItems: [] as UploadItem[], preview: null as PreviewData | null, submitResult: null as SubmitResult | null, }), actions: { hydrate() { const raw = uni.getStorageSync(storageKey); if (!raw) return; try { const parsed = JSON.parse(raw); Object.assign(this, parsed); if (isLegacyDemoExtra(this.extra)) { this.extra = initialExtra(); this.persist(); } } catch (error) { console.warn("hydrate appraisal store failed", error); } }, persist() { uni.setStorageSync( storageKey, JSON.stringify({ draftId: this.draftId, serviceProvider: this.serviceProvider, serviceMode: this.serviceMode, pricePackageId: this.pricePackageId, pricePackageName: this.pricePackageName, pricePackageCode: this.pricePackageCode, pricePackagePrice: this.pricePackagePrice, currentStep: this.currentStep, product: this.product, extra: this.extra, returnAddress: this.returnAddress, uploadTemplateId: this.uploadTemplateId, requiredItems: this.requiredItems, optionalItems: this.optionalItems, preview: this.preview, submitResult: this.submitResult, }), ); }, setServiceProvider(serviceProvider: string) { this.serviceProvider = serviceProvider; this.persist(); }, setPricePackage(payload: { id: number; packageName: string; packageCode: string; price: number; }) { this.pricePackageId = payload.id; this.pricePackageName = payload.packageName; this.pricePackageCode = payload.packageCode; this.pricePackagePrice = payload.price; this.persist(); }, setDraft(id: number) { this.draftId = id; this.persist(); }, setCurrentStep(step: number) { this.currentStep = step; this.persist(); }, setProduct(payload: Partial) { this.product = { ...this.product, ...payload, }; this.persist(); }, setExtra(payload: Partial) { this.extra = { ...this.extra, ...payload, }; this.persist(); }, resetExtra() { this.extra = initialExtra(); this.persist(); }, clearLegacyExtraDefaults() { if (!isLegacyDemoExtra(this.extra)) { return false; } this.extra = initialExtra(); this.persist(); return true; }, setReturnAddress(payload: Partial) { this.returnAddress = { ...this.returnAddress, ...payload, }; this.persist(); }, clearReturnAddress() { this.returnAddress = initialReturnAddress(); this.persist(); }, setUploadTemplate(templateId: number, requiredItems: UploadItem[], optionalItems: UploadItem[]) { const requiredMap = new Map(this.requiredItems.map((item) => [item.item_code, item.files || []])); const optionalMap = new Map(this.optionalItems.map((item) => [item.item_code, item.files || []])); this.uploadTemplateId = templateId; this.requiredItems = requiredItems.map((item) => ({ ...item, files: item.files || requiredMap.get(item.item_code) || [], })); this.optionalItems = optionalItems.map((item) => ({ ...item, files: item.files || optionalMap.get(item.item_code) || [], })); this.persist(); }, hydrateUploadItems(items: UploadItem[]) { const required = items.filter((item) => item.is_required); const optional = items.filter((item) => !item.is_required); this.requiredItems = required.map((item) => ({ ...item, files: item.files || [], })); this.optionalItems = optional.map((item) => ({ ...item, files: item.files || [], })); this.persist(); }, upsertUploadFile(itemCode: string, file: UploadFileAsset, isRequired: boolean) { const target = isRequired ? this.requiredItems : this.optionalItems; const index = target.findIndex((item) => item.item_code === itemCode); if (index >= 0) { const currentFiles = target[index].files || []; const nextFiles = [...currentFiles, file]; target[index] = { ...target[index], files: nextFiles, quality_status: nextFiles.length ? "uploaded" : "pending", quality_message: "", }; this.persist(); } }, removeUploadFile(itemCode: string, fileId: string, isRequired: boolean) { const target = isRequired ? this.requiredItems : this.optionalItems; const index = target.findIndex((item) => item.item_code === itemCode); if (index >= 0) { const nextFiles = (target[index].files || []).filter((item) => item.file_id !== fileId); target[index] = { ...target[index], files: nextFiles, quality_status: nextFiles.length ? "uploaded" : (target[index].is_required ? "pending" : "optional"), }; this.persist(); } }, setPreview(preview: PreviewData | null) { this.preview = preview; this.persist(); }, setSubmitResult(result: SubmitResult | null) { this.submitResult = result; this.persist(); }, resetForNewFlow() { this.serviceProvider = "anxinyan"; this.serviceMode = "physical"; this.pricePackageId = 0; this.pricePackageName = ""; this.pricePackageCode = ""; this.pricePackagePrice = 0; this.draftId = 0; this.currentStep = 1; this.product = initialProduct(); this.extra = initialExtra(); this.returnAddress = initialReturnAddress(); this.uploadTemplateId = 0; this.requiredItems = []; this.optionalItems = []; this.preview = null; this.submitResult = null; this.persist(); }, }, });