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[] {