From f83404f0eed8fddf0e365f69a5eace3b425e9b2a Mon Sep 17 00:00:00 2001 From: Timi Date: Thu, 20 Aug 2026 14:57:50 +0800 Subject: [PATCH] support tag for customer create --- src/components/BodyAreaSelector.vue | 1 - src/pages/customer/CustomerEdit.vue | 147 +++++++++++++----- .../customer/component/CustomerTagCard.vue | 2 +- src/types/Customer.ts | 2 + 4 files changed, 111 insertions(+), 41 deletions(-) diff --git a/src/components/BodyAreaSelector.vue b/src/components/BodyAreaSelector.vue index 26a2096..59b303d 100644 --- a/src/components/BodyAreaSelector.vue +++ b/src/components/BodyAreaSelector.vue @@ -103,7 +103,6 @@ function toggle(code: string): void { align-items: center; flex-direction: column; justify-content: center; - background: #f8fbff; border-radius: 1.25rem; .figure { diff --git a/src/pages/customer/CustomerEdit.vue b/src/pages/customer/CustomerEdit.vue index 80991bc..836838b 100644 --- a/src/pages/customer/CustomerEdit.vue +++ b/src/pages/customer/CustomerEdit.vue @@ -103,6 +103,18 @@ @status-change="handleScanStatusChange" /> + +
+ + + + - -
- +
{ // ---------- 表单 ---------- -const photoInputRef = ref(); -const photoAddActions = [ - { - icon: "user-avatar", - text: "拍照片", - emit: "add-photo", - theme: "primary" - }, - { - icon: "cardmembership", - text: "拍积分卡", - emit: "add-point-card", - theme: "primary" - }, - { - icon: "file-attachment", - text: "其他文件", - emit: "add-other", - theme: "default" - } -] as const; -const photoPickerTarget = ref("PHOTO"); -const isPhotoUploading = ref(false); -const photoItemList = ref([]); -const photoList = computed({ - get() { - return photoItemList.value.map(item => item.url); - }, - set(value) { - const urlSet = new Set(value); - photoItemList.value = photoItemList.value.filter(item => urlSet.has(item.url)); - } +const formData = reactive({ }); + +// ---------- 标签 ---------- + +const canReadTag = computed(() => userStore.hasPermissions(corePermissionCodes.tag.read)); +const canApplyTag = computed(() => userStore.hasPermissions(corePermissionCodes.tag.apply)); +const canEditTag = computed(() => canReadTag.value && canApplyTag.value); +const customerTagList = ref([]); +const selectedTagIdList = ref([]); +const tagSelectorVisible = ref(false); + +async function loadCustomerTags(customerId: string): Promise { + if (!customerId || !canReadTag.value) { + customerTagList.value = []; + selectedTagIdList.value = []; + return; + } + + customerTagList.value = await TagAPI.listByBizType("GAO_CUSTOMER", customerId); + selectedTagIdList.value = customerTagList.value.map(item => item.id || "").filter(Boolean); +} + +function openTagSelector(): void { + if (!canEditTag.value) { + return; + } + selectedTagIdList.value = customerTagList.value.map(item => item.id || "").filter(Boolean); + tagSelectorVisible.value = true; +} + +function handleTagSelected(tagList: Tag[]): void { + customerTagList.value = tagList; + selectedTagIdList.value = tagList.map(item => item.id || "").filter(Boolean); +} + +// ---------- 调理部位 ---------- + const selectedAreas = ref({ selectedCodeList: [] }); @@ -325,9 +349,6 @@ const bodyAreaPickerVisible = ref(false); const bodyAreaDraft = ref({ selectedCodeList: [] }); -const formData = reactive({ -}); - const selectedAreaText = computed(() => { const selectedLabelList = selectedAreas.value.selectedCodeList.map(item => bodyAreaLabelMap.get(item) || item); return selectedLabelList.length ? `${selectedLabelList.join("、")}` : "选择调理部位"; @@ -412,11 +433,14 @@ async function loadDetail() { await prepareStoreScope(); const id = String(route.params.id || ""); if (!id) { + customerTagList.value = []; + selectedTagIdList.value = []; return; } try { const customer = await CustomerAPI.detail(id); Object.assign(formData, customer); + await loadCustomerTags(id); formData.storeId = customer.storeId || formData.storeId; photoItemList.value = (customer.attachmentList || []) .filter(item => !!item.id) @@ -458,6 +482,40 @@ watch(() => formData.birthdate, (value) => { // ---------- 照片 ---------- +const photoInputRef = ref(); +const photoAddActions = [ + { + icon: "user-avatar", + text: "拍照片", + emit: "add-photo", + theme: "primary" + }, + { + icon: "cardmembership", + text: "拍积分卡", + emit: "add-point-card", + theme: "primary" + }, + { + icon: "file-attachment", + text: "其他文件", + emit: "add-other", + theme: "default" + } +] as const; +const photoPickerTarget = ref("PHOTO"); +const isPhotoUploading = ref(false); +const photoItemList = ref([]); +const photoList = computed({ + get() { + return photoItemList.value.map(item => item.url); + }, + set(value) { + const urlSet = new Set(value); + photoItemList.value = photoItemList.value.filter(item => urlSet.has(item.url)); + } +}); + function normalizeAttachmentType(attachType?: string): CustomerAttachmentType { if (attachType === "POINT_CARD" || attachType === "OTHER") { return attachType; @@ -505,6 +563,14 @@ async function doSubmit(): Promise { payload.conditioningPart = selectedAreas.value; payload.introducerCustomerId = introducerCustomerId.value || ""; payload.attachmentList = buildAttachmentList(); + delete payload.tagApply; + if (canEditTag.value) { + payload.tagApply = { + bizType: "GAO_CUSTOMER", + bizId: payload.id || "", + tagIdList: [...selectedTagIdList.value] + }; + } delete payload.introducerCustomer; if (isCreateMode.value) { @@ -546,7 +612,10 @@ function buildAttachmentList(): Attachment[] {