diff --git a/src/pages/customer/CustomerDetail.vue b/src/pages/customer/CustomerDetail.vue index 46d2999..2c46393 100644 --- a/src/pages/customer/CustomerDetail.vue +++ b/src/pages/customer/CustomerDetail.vue @@ -26,6 +26,16 @@ + + + import { DialogPlugin, Toast } from "tdesign-mobile-vue"; -import { PassTimeLabel, Text, useUserStore } from "timi-web"; +import { AttachmentAPI, PassTimeLabel, Text, useUserStore } from "timi-web"; import CustomerAPI from "@/api/CustomerAPI"; import PointAPI from "@/api/PointAPI"; import TagAPI from "@/api/TagAPI"; @@ -179,6 +189,7 @@ import BodyAreaSelector from "@/components/BodyAreaSelector.vue"; import CodeScanner from "@/components/CodeScanner.vue"; import CustomerProfileCard from "@/components/CustomerProfileCard.vue"; import CustomerSelector from "@/components/CustomerSelector.vue"; +import PhotoScroller from "@/components/PhotoScroller.vue"; import TagSelector from "@/components/TagSelector.vue"; import CustomerTagCard from "@/pages/customer/component/CustomerTagCard.vue"; import { useSettingStore } from "@/store/settingStore"; @@ -213,6 +224,9 @@ const isLunarBirthdate = computed(() => customer.value?.birthdateCalendar === "L const solarBirthdateText = computed(() => formatSolarBirthdate(customer.value)); const birthdateText = computed(() => showSolarBirthdate.value && isLunarBirthdate.value ? solarBirthdateText.value : formatBirthdate(customer.value)); const ageText = computed(() => customer.value?.age === undefined || customer.value?.age === null ? "" : `${customer.value.age} 岁`); +const photoList = computed(() => (customer.value?.attachmentList || []) + .filter(item => !!item.id) + .map(item => AttachmentAPI.getReadURL(item.id || ""))); const selectedAreas = computed({ get() { return normalizeBodyAreaValue(customer.value?.conditioningPart); diff --git a/src/pages/customer/CustomerEdit.vue b/src/pages/customer/CustomerEdit.vue index 339650f..bda28df 100644 --- a/src/pages/customer/CustomerEdit.vue +++ b/src/pages/customer/CustomerEdit.vue @@ -58,10 +58,21 @@ alt-text="客户照片" :loading="isPhotoUploading" :preview="false" - @add="openPhotoPicker" + @add="openPhotoPicker('photo')" @clear="handlePhotoClear" /> + + + 男 @@ -178,7 +189,7 @@ import PhotoField from "@/components/PhotoField.vue"; import { useCurrentStoreStore } from "@/store/currentStoreStore"; import { useSettingStore } from "@/store/settingStore"; import type { BodyAreaValue, Customer } from "@/types/Customer"; -import { createBodyAreaValue, getCustomerPhotoURL, normalizeBodyAreaValue } from "@/utils/customer"; +import { createBodyAreaValue, getCustomerPhotoURL, getCustomerPointCardURL, normalizeBodyAreaValue } from "@/utils/customer"; import { gaoRoleCodes, permissionCodes } from "@/utils/permission"; import { compressUploadImage } from "@/utils/imageCompression"; @@ -276,16 +287,23 @@ async function handleIntroducerChange(id: string): Promise { // ---------- 表单 ---------- const photoInputRef = ref(); +type PhotoPickerTarget = "photo" | "pointCard"; +const photoPickerTarget = ref("photo"); const photoTempFileId = ref(""); const isPhotoUploading = ref(false); const photoURL = ref(); +const pointCardTempFileId = ref(""); +const isPointCardUploading = ref(false); +const pointCardURL = ref(""); const originalAttachmentList = ref([]); const photoChanged = ref(false); +const pointCardChanged = ref(false); const selectedAreas = ref(createBodyAreaValue()); const formData = reactive({ }); -function openPhotoPicker(): void { +function openPhotoPicker(target: PhotoPickerTarget): void { + photoPickerTarget.value = target; photoInputRef.value?.click(); } @@ -352,9 +370,12 @@ async function loadDetail() { Object.assign(formData, customer); formData.storeId = customer.storeId || formData.storeId; photoURL.value = getCustomerPhotoURL(customer); + pointCardURL.value = getCustomerPointCardURL(customer); originalAttachmentList.value = [...(customer.attachmentList || [])]; photoTempFileId.value = ""; + pointCardTempFileId.value = ""; photoChanged.value = false; + pointCardChanged.value = false; selectedAreas.value = normalizeBodyAreaValue(customer.conditioningPart); introducerCustomerId.value = customer.introducerCustomerId || customer.introducerCustomer?.id || ""; } catch (err) { @@ -394,15 +415,30 @@ async function handlePhotoSelected(event: Event): Promise { if (!file) { return; } - isPhotoUploading.value = true; + const isPointCard = photoPickerTarget.value === "pointCard"; + if (isPointCard) { + isPointCardUploading.value = true; + } else { + isPhotoUploading.value = true; + } try { const compressedFile = await compressUploadImage(file); const [tempFile] = await AttachmentAPI.upload(compressedFile); - photoTempFileId.value = tempFile.id; - photoURL.value = AttachmentAPI.getTempReadURL(tempFile.id); - photoChanged.value = true; + if (isPointCard) { + pointCardTempFileId.value = tempFile.id; + pointCardURL.value = AttachmentAPI.getTempReadURL(tempFile.id); + pointCardChanged.value = true; + } else { + photoTempFileId.value = tempFile.id; + photoURL.value = AttachmentAPI.getTempReadURL(tempFile.id); + photoChanged.value = true; + } } finally { - isPhotoUploading.value = false; + if (isPointCard) { + isPointCardUploading.value = false; + } else { + isPhotoUploading.value = false; + } input.value = ""; } } @@ -412,6 +448,11 @@ function handlePhotoClear(): void { photoChanged.value = true; } +function handlePointCardClear(): void { + pointCardTempFileId.value = ""; + pointCardChanged.value = true; +} + // ---------- 保存 ---------- const isSubmitting = ref(false); @@ -427,12 +468,7 @@ async function doSubmit(): Promise { const payload: Customer = { ...formData }; payload.conditioningPart = selectedAreas.value; payload.introducerCustomerId = introducerCustomerId.value || ""; - payload.attachmentList = photoChanged.value - ? (photoTempFileId.value ? [{ - attachType: "PHOTO", - tempFileId: photoTempFileId.value - }] : []) - : [...originalAttachmentList.value]; + payload.attachmentList = buildAttachmentList(); delete payload.introducerCustomer; if (isCreateMode.value) { @@ -455,6 +491,22 @@ async function doSubmit(): Promise { isSubmitting.value = false; } } + +function buildAttachmentList(): Attachment[] { + let attachmentList = [...originalAttachmentList.value]; + if (photoChanged.value) { + attachmentList = replaceAttachment(attachmentList, "PHOTO", photoTempFileId.value); + } + if (pointCardChanged.value) { + attachmentList = replaceAttachment(attachmentList, "POINT_CARD", pointCardTempFileId.value); + } + return attachmentList; +} + +function replaceAttachment(attachmentList: Attachment[], attachType: "PHOTO" | "POINT_CARD", tempFileId: string): Attachment[] { + const preservedList = attachmentList.filter(item => item.attachType !== attachType); + return tempFileId ? [...preservedList, { attachType, tempFileId }] : preservedList; +}