fix require photo event
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-bind="$attrs" class="photo-scroller">
|
<div v-bind="$attrs" class="photo-scroller">
|
||||||
<div class="t-form__label" v-text="title" />
|
<div class="t-form__label" :class="{ required }">
|
||||||
|
<slot name="title">
|
||||||
|
<span v-text="title" />
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
<div class="photo-shell" :class="{ 'without-add': !showAdd }">
|
<div class="photo-shell" :class="{ 'without-add': !showAdd }">
|
||||||
<div class="items">
|
<div class="items">
|
||||||
<div v-if="!displayPhotoList.length" class="empty" v-text="emptyText" />
|
<div v-if="!displayPhotoList.length" class="empty" v-text="emptyText" />
|
||||||
@@ -157,6 +161,7 @@ interface Props {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
modelValue: string[];
|
modelValue: string[];
|
||||||
photoItems?: readonly PhotoItem[];
|
photoItems?: readonly PhotoItem[];
|
||||||
|
required?: boolean;
|
||||||
showViewerActions?: boolean;
|
showViewerActions?: boolean;
|
||||||
showAdd?: boolean;
|
showAdd?: boolean;
|
||||||
showRemove?: boolean;
|
showRemove?: boolean;
|
||||||
@@ -188,6 +193,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
editMode: false,
|
editMode: false,
|
||||||
emptyText: "暂无照片",
|
emptyText: "暂无照片",
|
||||||
loading: false,
|
loading: false,
|
||||||
|
required: false,
|
||||||
showAdd: true,
|
showAdd: true,
|
||||||
showRemove: true,
|
showRemove: true,
|
||||||
showViewerActions: true
|
showViewerActions: true
|
||||||
@@ -412,6 +418,14 @@ function normalizePhotoItem(item: PhotoItem): PhotoItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.t-form__label {
|
||||||
|
&.required::before {
|
||||||
|
color: var(--td-error-color, #e34d59);
|
||||||
|
content: "*";
|
||||||
|
margin-right: .25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.add-trigger {
|
.add-trigger {
|
||||||
--td-popover-padding: 0 .5rem;
|
--td-popover-padding: 0 .5rem;
|
||||||
width: 5.5rem;
|
width: 5.5rem;
|
||||||
|
|||||||
@@ -114,6 +114,8 @@
|
|||||||
|
|
||||||
<div class="photo-part">
|
<div class="photo-part">
|
||||||
<photo-scroller
|
<photo-scroller
|
||||||
|
title="登记事件照片"
|
||||||
|
:required="selectedRequiredPhotoEventList.length > 0"
|
||||||
v-model="photoList"
|
v-model="photoList"
|
||||||
v-model:photo-items="photoItemList"
|
v-model:photo-items="photoItemList"
|
||||||
:edit-mode="true"
|
:edit-mode="true"
|
||||||
@@ -209,7 +211,7 @@ import type { EventItem } from "@/types/EventItem";
|
|||||||
import type { EventRecord } from "@/types/EventRecord";
|
import type { EventRecord } from "@/types/EventRecord";
|
||||||
import type { PointAction } from "@/types/Point";
|
import type { PointAction } from "@/types/Point";
|
||||||
import { getAttachmentReadURL } from "@/utils/attachment";
|
import { getAttachmentReadURL } from "@/utils/attachment";
|
||||||
import { getEventRecordPhotoURL } from "@/utils/eventRecord";
|
import { getEventRecordPhotoURL, hasPhotoAttachment } from "@/utils/eventRecord";
|
||||||
import { getEventNumberValuePlaceholder, resolveEventNumberValue } from "@/utils/eventValue";
|
import { getEventNumberValuePlaceholder, resolveEventNumberValue } from "@/utils/eventValue";
|
||||||
import { permissionCodes } from "@/utils/permission";
|
import { permissionCodes } from "@/utils/permission";
|
||||||
import { loadSourceValueConfig, type SourceValueConfig } from "@/utils/point";
|
import { loadSourceValueConfig, type SourceValueConfig } from "@/utils/point";
|
||||||
@@ -408,6 +410,9 @@ const numberValueTextMap = reactive<Record<string, string>>({});
|
|||||||
const selectedNumberEventList = computed(() => selectedEventIdList.value
|
const selectedNumberEventList = computed(() => selectedEventIdList.value
|
||||||
.map(eventId => eventList.value.find(item => item.id === eventId))
|
.map(eventId => eventList.value.find(item => item.id === eventId))
|
||||||
.filter((item): item is EventItem => item?.valueType === "NUMBER"));
|
.filter((item): item is EventItem => item?.valueType === "NUMBER"));
|
||||||
|
const selectedRequiredPhotoEventList = computed(() => selectedEventIdList.value
|
||||||
|
.map(eventId => eventList.value.find(item => item.id === eventId))
|
||||||
|
.filter((item): item is EventItem => item?.requirePhoto === true));
|
||||||
|
|
||||||
const eventNameMap = computed(() => {
|
const eventNameMap = computed(() => {
|
||||||
const map = new Map<string, string>();
|
const map = new Map<string, string>();
|
||||||
@@ -604,6 +609,10 @@ async function submitRecord(): Promise<void> {
|
|||||||
if (isSaving.value) {
|
if (isSaving.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (isPhotoUploading.value) {
|
||||||
|
Message.warning("照片正在上传,请稍候");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!validateForm()) {
|
if (!validateForm()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -616,21 +625,19 @@ async function submitRecord(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const customerIdList = selectedCustomerList.value.map(customer => customer.id).filter((item): item is string => !!item);
|
const customerIdList = selectedCustomerList.value.map(customer => customer.id).filter((item): item is string => !!item);
|
||||||
// 多个事件按选择顺序逐条提交,避免把有累计积分顺序依赖的事件混入同一批次。
|
// 后端批量接口仍按选择顺序逐条处理,并为重复临时附件生成副本。
|
||||||
for (const eventId of selectedEventIdList.value) {
|
await EventRecordAPI.createBatch(selectedEventIdList.value.map(eventId => ({
|
||||||
await EventRecordAPI.create({
|
eventId,
|
||||||
eventId,
|
customerIdList,
|
||||||
customerIdList,
|
remark: note.value || "客户现场登记",
|
||||||
remark: note.value || "客户现场登记",
|
registeredAt: buildRegisteredAt(),
|
||||||
registeredAt: buildRegisteredAt(),
|
pointValue: showSourceValueInput.value ? resolveSourceValue() : undefined,
|
||||||
pointValue: showSourceValueInput.value ? resolveSourceValue() : undefined,
|
numberValue: resolveNumberValue(eventId),
|
||||||
numberValue: resolveNumberValue(eventId),
|
attachmentList: buildTempFileIdList().map(tempFileId => ({
|
||||||
attachmentList: buildTempFileIdList().map(tempFileId => ({
|
tempFileId,
|
||||||
tempFileId,
|
attachType: "PHOTO"
|
||||||
attachType: "PHOTO"
|
}))
|
||||||
}))
|
})));
|
||||||
});
|
|
||||||
}
|
|
||||||
selectedCustomerList.value = [];
|
selectedCustomerList.value = [];
|
||||||
selectedCustomerIdList.value = [];
|
selectedCustomerIdList.value = [];
|
||||||
note.value = "";
|
note.value = "";
|
||||||
@@ -657,6 +664,9 @@ function validateForm(): boolean {
|
|||||||
Message.warning("请至少选择一个登记事件");
|
Message.warning("请至少选择一个登记事件");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!validateRequiredPhotoList()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!isEditMode.value && !validateNumberValueList()) {
|
if (!isEditMode.value && !validateNumberValueList()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -672,6 +682,15 @@ function validateForm(): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateRequiredPhotoList(): boolean {
|
||||||
|
const event = selectedRequiredPhotoEventList.value[0];
|
||||||
|
if (event && !hasPhotoAttachment(photoItemList.value)) {
|
||||||
|
Message.warning(`请上传${event.name || "当前事件"}照片`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
async function updateRecord(): Promise<void> {
|
async function updateRecord(): Promise<void> {
|
||||||
if (!editingRecord.value?.id || !editingRecord.value.customerId || !editingRecord.value.eventId) {
|
if (!editingRecord.value?.id || !editingRecord.value.customerId || !editingRecord.value.eventId) {
|
||||||
Message.warning("登记事件记录不存在");
|
Message.warning("登记事件记录不存在");
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
<div class="photo-part">
|
<div class="photo-part">
|
||||||
<photo-scroller
|
<photo-scroller
|
||||||
title="登记事件照片"
|
title="登记事件照片"
|
||||||
|
:required="selectedRequiredPhotoEventList.length > 0"
|
||||||
v-model="recordPhotoList"
|
v-model="recordPhotoList"
|
||||||
v-model:photo-items="recordPhotoItemList"
|
v-model:photo-items="recordPhotoItemList"
|
||||||
:edit-mode="true"
|
:edit-mode="true"
|
||||||
@@ -156,6 +157,7 @@ import type { EventItem } from "@/types/EventItem";
|
|||||||
import type { PointAction } from "@/types/Point";
|
import type { PointAction } from "@/types/Point";
|
||||||
import { getEventNumberValuePlaceholder, resolveEventNumberValue } from "@/utils/eventValue";
|
import { getEventNumberValuePlaceholder, resolveEventNumberValue } from "@/utils/eventValue";
|
||||||
import { getAttachmentReadURL } from "@/utils/attachment";
|
import { getAttachmentReadURL } from "@/utils/attachment";
|
||||||
|
import { hasPhotoAttachment } from "@/utils/eventRecord";
|
||||||
import { permissionCodes } from "@/utils/permission";
|
import { permissionCodes } from "@/utils/permission";
|
||||||
import { loadSourceValueConfig, type SourceValueConfig } from "@/utils/point";
|
import { loadSourceValueConfig, type SourceValueConfig } from "@/utils/point";
|
||||||
import { compressUploadImage, compressUploadImageList } from "@/utils/imageCompression";
|
import { compressUploadImage, compressUploadImageList } from "@/utils/imageCompression";
|
||||||
@@ -180,6 +182,9 @@ const numberValueTextMap = reactive<Record<string, string>>({});
|
|||||||
const selectedNumberEventList = computed(() => selectedEventIdList.value
|
const selectedNumberEventList = computed(() => selectedEventIdList.value
|
||||||
.map(eventId => eventList.value.find(item => item.id === eventId))
|
.map(eventId => eventList.value.find(item => item.id === eventId))
|
||||||
.filter((item): item is EventItem => item?.valueType === "NUMBER"));
|
.filter((item): item is EventItem => item?.valueType === "NUMBER"));
|
||||||
|
const selectedRequiredPhotoEventList = computed(() => selectedEventIdList.value
|
||||||
|
.map(eventId => eventList.value.find(item => item.id === eventId))
|
||||||
|
.filter((item): item is EventItem => item?.requirePhoto === true));
|
||||||
const pointValueText = ref("");
|
const pointValueText = ref("");
|
||||||
const sourceValueConfig = ref<SourceValueConfig>();
|
const sourceValueConfig = ref<SourceValueConfig>();
|
||||||
const sourceValueAction = ref<PointAction>("EARN");
|
const sourceValueAction = ref<PointAction>("EARN");
|
||||||
@@ -674,10 +679,12 @@ async function saveRecord(): Promise<void> {
|
|||||||
}
|
}
|
||||||
// 记录照片
|
// 记录照片
|
||||||
if (Toolkit.isNotEmpty(customer.eventRecordList)) {
|
if (Toolkit.isNotEmpty(customer.eventRecordList)) {
|
||||||
customer.eventRecordList![0].attachmentList = recordPhotoItemList.value.map(item => ({
|
for (const record of customer.eventRecordList || []) {
|
||||||
tempFileId: item.tempFileId,
|
record.attachmentList = recordPhotoItemList.value.map(item => ({
|
||||||
attachType: item.attachType || "PHOTO"
|
tempFileId: item.tempFileId,
|
||||||
}));
|
attachType: item.attachType || "PHOTO"
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await EventRecordAPI.createWithCustomer(customer);
|
await EventRecordAPI.createWithCustomer(customer);
|
||||||
resetFormAfterSubmit();
|
resetFormAfterSubmit();
|
||||||
@@ -745,6 +752,9 @@ function validateForm(): string {
|
|||||||
if (!validateCustomerPhotoList()) {
|
if (!validateCustomerPhotoList()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
if (!validateRequiredPhotoList()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
if (!validateNumberValueList()) {
|
if (!validateNumberValueList()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -759,6 +769,15 @@ function validateForm(): string {
|
|||||||
return customerCode;
|
return customerCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateRequiredPhotoList(): boolean {
|
||||||
|
const event = selectedRequiredPhotoEventList.value[0];
|
||||||
|
if (event && !hasPhotoAttachment(recordPhotoItemList.value)) {
|
||||||
|
Message.warning(`请上传${event.name || "当前事件"}照片`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- 初始化 ----------
|
// ---------- 初始化 ----------
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
|||||||
@@ -15,6 +15,17 @@
|
|||||||
<t-button size="small" theme="primary" variant="text" @click="loadActions">重试</t-button>
|
<t-button size="small" theme="primary" variant="text" @click="loadActions">重试</t-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="showRecordPhotoInput" class="input-form photo-form">
|
||||||
|
<photo-scroller
|
||||||
|
title="登记事件照片"
|
||||||
|
:required="selectedRequiredPhotoEventList.length > 0"
|
||||||
|
v-model="recordPhotoList"
|
||||||
|
v-model:photo-items="recordPhotoItemList"
|
||||||
|
:edit-mode="true"
|
||||||
|
:loading="recordPhotoUploading"
|
||||||
|
@add="capturePhoto"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<code-scanner
|
<code-scanner
|
||||||
visible
|
visible
|
||||||
:session-key="scannerSessionKey"
|
:session-key="scannerSessionKey"
|
||||||
@@ -103,6 +114,14 @@
|
|||||||
</template>
|
</template>
|
||||||
</t-cell>
|
</t-cell>
|
||||||
</t-cell-group>
|
</t-cell-group>
|
||||||
|
<input
|
||||||
|
ref="recordPhotoInputRef"
|
||||||
|
class="file-input"
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
multiple
|
||||||
|
@change="handleRecordPhotoSelected"
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -113,16 +132,19 @@ import EventAPI from "@/api/EventAPI";
|
|||||||
import EventRecordAPI from "@/api/EventRecordAPI";
|
import EventRecordAPI from "@/api/EventRecordAPI";
|
||||||
import CodeScanner from "@/components/CodeScanner.vue";
|
import CodeScanner from "@/components/CodeScanner.vue";
|
||||||
import CustomerProfileCard from "@/components/CustomerProfileCard.vue";
|
import CustomerProfileCard from "@/components/CustomerProfileCard.vue";
|
||||||
|
import PhotoScroller from "@/components/PhotoScroller.vue";
|
||||||
import { useSettingStore } from "@/store/settingStore";
|
import { useSettingStore } from "@/store/settingStore";
|
||||||
import type { Customer } from "@/types/Customer";
|
import type { Customer } from "@/types/Customer";
|
||||||
import type { EventItem } from "@/types/EventItem";
|
import type { EventItem } from "@/types/EventItem";
|
||||||
import type { EventRecord } from "@/types/EventRecord";
|
import type { EventRecord } from "@/types/EventRecord";
|
||||||
|
import type { PhotoItem } from "@/types/Photo";
|
||||||
import type { PointAction } from "@/types/Point";
|
import type { PointAction } from "@/types/Point";
|
||||||
import { getEventNumberValuePlaceholder, resolveEventNumberValue } from "@/utils/eventValue";
|
import { getEventNumberValuePlaceholder, resolveEventNumberValue } from "@/utils/eventValue";
|
||||||
import { permissionCodes } from "@/utils/permission";
|
import { permissionCodes } from "@/utils/permission";
|
||||||
import { getEventRecordPhotoURL } from "@/utils/eventRecord";
|
import { getEventRecordPhotoURL, hasPhotoAttachment } from "@/utils/eventRecord";
|
||||||
|
import { compressUploadImageList } from "@/utils/imageCompression";
|
||||||
import { Storage, Time } from "timi-web";
|
import { Storage, Time } from "timi-web";
|
||||||
import { useUserStore } from "timi-web-api";
|
import { AttachmentAPI, useUserStore, type Attachment } from "timi-web-api";
|
||||||
import { loadSourceValueConfig, type SourceValueConfig } from "@/utils/point";
|
import { loadSourceValueConfig, type SourceValueConfig } from "@/utils/point";
|
||||||
import EventSelector from "@/components/EventSelector.vue";
|
import EventSelector from "@/components/EventSelector.vue";
|
||||||
import { Space } from "timi-tdesign-mobile";
|
import { Space } from "timi-tdesign-mobile";
|
||||||
@@ -146,6 +168,7 @@ const selectedEventList = computed(() => selectedEventIdList.value
|
|||||||
.map(eventId => eventList.value.find(item => normalizeEventId(item) === eventId))
|
.map(eventId => eventList.value.find(item => normalizeEventId(item) === eventId))
|
||||||
.filter((item): item is EventItem => !!item));
|
.filter((item): item is EventItem => !!item));
|
||||||
const selectedNumberEventList = computed(() => selectedEventList.value.filter(item => item.valueType === "NUMBER"));
|
const selectedNumberEventList = computed(() => selectedEventList.value.filter(item => item.valueType === "NUMBER"));
|
||||||
|
const selectedRequiredPhotoEventList = computed(() => selectedEventList.value.filter(item => item.requirePhoto === true));
|
||||||
let sourceValueRequestNo = 0;
|
let sourceValueRequestNo = 0;
|
||||||
|
|
||||||
function normalizeEventId(item?: EventItem): string {
|
function normalizeEventId(item?: EventItem): string {
|
||||||
@@ -347,6 +370,68 @@ function validateNumberValueList(): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- 照片 ----------
|
||||||
|
|
||||||
|
const recordPhotoInputRef = ref<HTMLInputElement>();
|
||||||
|
const recordPhotoItemList = ref<PhotoItem[]>([]);
|
||||||
|
const recordPhotoUploading = ref(false);
|
||||||
|
const showRecordPhotoInput = computed(() => selectedRequiredPhotoEventList.value.length > 0 || recordPhotoItemList.value.length > 0);
|
||||||
|
const recordPhotoList = computed<string[]>({
|
||||||
|
get() {
|
||||||
|
return recordPhotoItemList.value.map(item => item.url);
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
const urlSet = new Set(value);
|
||||||
|
recordPhotoItemList.value = recordPhotoItemList.value.filter(item => urlSet.has(item.url));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function capturePhoto(): void {
|
||||||
|
recordPhotoInputRef.value?.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleRecordPhotoSelected(event: Event): Promise<void> {
|
||||||
|
const input = event.target as HTMLInputElement;
|
||||||
|
const fileList = Array.from(input.files || []);
|
||||||
|
if (!fileList.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
recordPhotoUploading.value = true;
|
||||||
|
try {
|
||||||
|
const compressedFileList = await compressUploadImageList(fileList);
|
||||||
|
const tempFileList = await AttachmentAPI.upload(compressedFileList);
|
||||||
|
for (const item of tempFileList) {
|
||||||
|
if (!item.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
recordPhotoItemList.value.push({
|
||||||
|
tempFileId: item.id,
|
||||||
|
attachType: "PHOTO",
|
||||||
|
url: AttachmentAPI.getTempReadURL(item.id)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
recordPhotoUploading.value = false;
|
||||||
|
input.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateRequiredPhotoList(): boolean {
|
||||||
|
const event = selectedRequiredPhotoEventList.value[0];
|
||||||
|
if (event && !hasPhotoAttachment(recordPhotoItemList.value)) {
|
||||||
|
Message.warning(`请上传${event.name || "当前事件"}照片`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPhotoAttachmentList(): Array<Partial<Attachment>> {
|
||||||
|
return recordPhotoItemList.value.map(item => ({
|
||||||
|
tempFileId: item.tempFileId,
|
||||||
|
attachType: item.attachType || "PHOTO"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
async function doSubmit(): Promise<void> {
|
async function doSubmit(): Promise<void> {
|
||||||
const customer = matchedCustomer.value;
|
const customer = matchedCustomer.value;
|
||||||
if (!customer) {
|
if (!customer) {
|
||||||
@@ -356,6 +441,13 @@ async function doSubmit(): Promise<void> {
|
|||||||
Message.warning("请至少选择一个登记事件");
|
Message.warning("请至少选择一个登记事件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (recordPhotoUploading.value) {
|
||||||
|
Message.warning("照片正在上传,请稍候");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!validateRequiredPhotoList()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!validateNumberValueList()) {
|
if (!validateNumberValueList()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -367,19 +459,19 @@ async function doSubmit(): Promise<void> {
|
|||||||
}
|
}
|
||||||
submitting.value = true;
|
submitting.value = true;
|
||||||
try {
|
try {
|
||||||
for (const eventId of selectedEventIdList.value) {
|
await EventRecordAPI.createBatch(selectedEventIdList.value.map(eventId => ({
|
||||||
await EventRecordAPI.create({
|
eventId,
|
||||||
eventId,
|
customerId: customer.id,
|
||||||
customerId: customer.id,
|
pointValue: showSourceValueInput.value ? pointValue : undefined,
|
||||||
pointValue: showSourceValueInput.value ? pointValue : undefined,
|
numberValue: resolveNumberValue(eventId),
|
||||||
numberValue: resolveNumberValue(eventId),
|
remark: "客户快速扫码登记",
|
||||||
remark: "客户快速扫码登记"
|
attachmentList: buildPhotoAttachmentList()
|
||||||
});
|
})));
|
||||||
}
|
|
||||||
scanStatus.value = `登记成功:${customer.name || customer.code || scanCode.value}。`;
|
scanStatus.value = `登记成功:${customer.name || customer.code || scanCode.value}。`;
|
||||||
scanCode.value = "";
|
scanCode.value = "";
|
||||||
matchedCustomer.value = undefined;
|
matchedCustomer.value = undefined;
|
||||||
pointValueText.value = "";
|
pointValueText.value = "";
|
||||||
|
recordPhotoItemList.value = [];
|
||||||
for (const eventId of Object.keys(numberValueTextMap)) {
|
for (const eventId of Object.keys(numberValueTextMap)) {
|
||||||
delete numberValueTextMap[eventId];
|
delete numberValueTextMap[eventId];
|
||||||
}
|
}
|
||||||
@@ -421,6 +513,10 @@ async function doSubmit(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.file-input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.empty-block,
|
.empty-block,
|
||||||
.event-load-error {
|
.event-load-error {
|
||||||
color: #52607a;
|
color: #52607a;
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
import type { EventRecord } from "@/types/EventRecord";
|
import type { EventRecord } from "@/types/EventRecord";
|
||||||
import { getAttachmentReadURL } from "@/utils/attachment";
|
import { getAttachmentReadURL } from "@/utils/attachment";
|
||||||
|
|
||||||
|
type EventRecordAttachment = {
|
||||||
|
attachType?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 判断登记记录附件列表中是否包含照片。未指定类型时按历史默认值 PHOTO 处理。 */
|
||||||
|
export function hasPhotoAttachment(attachmentList?: readonly EventRecordAttachment[]): boolean {
|
||||||
|
return !!attachmentList?.some(item => !item.attachType || item.attachType === "PHOTO");
|
||||||
|
}
|
||||||
|
|
||||||
export function getEventRecordPhotoURL(record?: EventRecord, thumbnailSize?: number): string {
|
export function getEventRecordPhotoURL(record?: EventRecord, thumbnailSize?: number): string {
|
||||||
const attachment = record?.attachmentList?.find(item => item.attachType === "PHOTO") || record?.attachmentList?.[0];
|
const attachment = record?.attachmentList?.find(item => item.attachType === "PHOTO") || record?.attachmentList?.[0];
|
||||||
if (!attachment?.id) {
|
if (!attachment?.id) {
|
||||||
|
|||||||
Reference in New Issue
Block a user