first
This commit is contained in:
271
user-app/src/stores/appraisal.ts
Normal file
271
user-app/src/stores/appraisal.ts
Normal file
@@ -0,0 +1,271 @@
|
||||
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<ExtraState> | 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",
|
||||
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,
|
||||
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();
|
||||
},
|
||||
setDraft(id: number) {
|
||||
this.draftId = id;
|
||||
this.persist();
|
||||
},
|
||||
setCurrentStep(step: number) {
|
||||
this.currentStep = step;
|
||||
this.persist();
|
||||
},
|
||||
setProduct(payload: Partial<ProductState>) {
|
||||
this.product = {
|
||||
...this.product,
|
||||
...payload,
|
||||
};
|
||||
this.persist();
|
||||
},
|
||||
setExtra(payload: Partial<ExtraState>) {
|
||||
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<ReturnAddressState>) {
|
||||
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.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();
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user