support tag for customer create
This commit is contained in:
@@ -103,6 +103,18 @@
|
||||
@status-change="handleScanStatusChange"
|
||||
/>
|
||||
</div>
|
||||
<t-form-item label="调理部位" arrow @click="openBodyAreaPicker">
|
||||
<div class="picker-text" v-text="selectedAreaText" />
|
||||
</t-form-item>
|
||||
</t-form>
|
||||
<customer-tag-card
|
||||
v-if="canReadTag"
|
||||
class="tag-card"
|
||||
:editable="canEditTag"
|
||||
:tag-list="customerTagList"
|
||||
@edit="openTagSelector"
|
||||
/>
|
||||
<t-form class="form" label-align="left" label-width="3rem">
|
||||
<t-form-item label="住址">
|
||||
<t-textarea
|
||||
class="textarea"
|
||||
@@ -119,9 +131,6 @@
|
||||
placeholder="病症"
|
||||
/>
|
||||
</t-form-item>
|
||||
<t-form-item label="调理部位" arrow @click="openBodyAreaPicker">
|
||||
<div class="picker-text" v-text="selectedAreaText" />
|
||||
</t-form-item>
|
||||
<t-form-item label="备注">
|
||||
<t-textarea
|
||||
class="textarea"
|
||||
@@ -155,6 +164,12 @@
|
||||
v-model:visible="selectorVisible"
|
||||
@change="handleIntroducerChange"
|
||||
/>
|
||||
<tag-selector
|
||||
v-if="canEditTag"
|
||||
v-model="selectedTagIdList"
|
||||
v-model:visible="tagSelectorVisible"
|
||||
@change="handleTagSelected"
|
||||
/>
|
||||
</div>
|
||||
<t-popup v-model="storePickerVisible" placement="bottom">
|
||||
<t-picker
|
||||
@@ -180,16 +195,20 @@
|
||||
import { type Attachment, AttachmentAPI, useUserStore } from "timi-web";
|
||||
import { Toast } from "tdesign-mobile-vue";
|
||||
import CustomerAPI from "@/api/CustomerAPI";
|
||||
import TagAPI from "@/api/TagAPI";
|
||||
import BodyAreaSelector from "@/components/BodyAreaSelector.vue";
|
||||
import CodeScanner from "@/components/CodeScanner.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 { useCurrentStoreStore } from "@/store/currentStoreStore";
|
||||
import { useSettingStore } from "@/store/settingStore";
|
||||
import type { BodyAreaValue, Customer, CustomerAttachmentType, EditableCustomerPhoto } from "@/types/Customer";
|
||||
import type { Tag } from "@/types/Tag";
|
||||
import { bodyAreaLabelMap } from "@/utils/bodyArea";
|
||||
import { normalizeBodyAreaValue } from "@/utils/customer";
|
||||
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
||||
import { corePermissionCodes, gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
||||
import { compressUploadImage } from "@/utils/imageCompression";
|
||||
|
||||
type PickerValue = string | number;
|
||||
@@ -285,39 +304,44 @@ async function handleIntroducerChange(id: string): Promise<void> {
|
||||
|
||||
// ---------- 表单 ----------
|
||||
|
||||
const photoInputRef = ref<HTMLInputElement>();
|
||||
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<CustomerAttachmentType>("PHOTO");
|
||||
const isPhotoUploading = ref(false);
|
||||
const photoItemList = ref<EditableCustomerPhoto[]>([]);
|
||||
const photoList = computed<string[]>({
|
||||
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<Customer>({
|
||||
});
|
||||
|
||||
// ---------- 标签 ----------
|
||||
|
||||
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<Tag[]>([]);
|
||||
const selectedTagIdList = ref<string[]>([]);
|
||||
const tagSelectorVisible = ref(false);
|
||||
|
||||
async function loadCustomerTags(customerId: string): Promise<void> {
|
||||
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<BodyAreaValue>({
|
||||
selectedCodeList: []
|
||||
});
|
||||
@@ -325,9 +349,6 @@ const bodyAreaPickerVisible = ref(false);
|
||||
const bodyAreaDraft = ref<BodyAreaValue>({
|
||||
selectedCodeList: []
|
||||
});
|
||||
const formData = reactive<Customer>({
|
||||
});
|
||||
|
||||
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<HTMLInputElement>();
|
||||
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<CustomerAttachmentType>("PHOTO");
|
||||
const isPhotoUploading = ref(false);
|
||||
const photoItemList = ref<EditableCustomerPhoto[]>([]);
|
||||
const photoList = computed<string[]>({
|
||||
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<void> {
|
||||
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[] {
|
||||
|
||||
<style scoped lang="less">
|
||||
.customer-edit {
|
||||
gap: 1rem;
|
||||
padding: calc(var(--app-nav-height) + 1rem) 0 4rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.form {
|
||||
padding: .5rem 0;
|
||||
|
||||
@@ -66,7 +66,7 @@ function emitEdit(): void {
|
||||
display: flex;
|
||||
padding: 1rem;
|
||||
overflow: hidden;
|
||||
border-radius: .75rem;
|
||||
border-radius: 1rem;
|
||||
flex-direction: column;
|
||||
|
||||
.header {
|
||||
|
||||
Reference in New Issue
Block a user