signal event selector

This commit is contained in:
Timi
2026-09-12 17:01:27 +08:00
parent 194a55a03f
commit 584fbfadf5
2 changed files with 61 additions and 59 deletions
+61 -58
View File
@@ -1,26 +1,25 @@
<template> <template>
<div v-can="permissionCodes.eventRecord.create" class="quick-sign-in-page"> <div v-can="permissionCodes.eventRecord.create" class="quick-sign-in-page">
<space class="content-margin" direction="vertical" v-entrance-transition> <t-cell-group v-if="!isEventLoading && !eventLoadFailed" theme="card">
<div class="event-panel"> <t-cell
<event-selector title="登记事件"
v-if="!isEventLoading && !eventLoadFailed" :note="selectedEventName"
:model-value="selectedEventIdList" arrow
:event-list="eventList" @click="eventPopupVisible = true"
required-mark >
@update:model-value="handleEventSelectionChange" <template #left-icon>
/> <t-icon name="task-setting" />
<div v-else-if="isEventLoading" class="empty-block">正在加载登记事件</div> </template>
<div v-else class="event-load-error"> </t-cell>
<span>登记事件加载失败</span> </t-cell-group>
<t-button size="small" theme="primary" variant="text" @click="loadActions">重试</t-button> <div v-else-if="isEventLoading" class="center-tips">正在加载登记事件</div>
</div> <div v-else class="center-tips">登记事件加载失败</div>
<div class="tips red">事件可多选,请注意勾选的登记事件</div> <event-option-selector
</div> v-model="selectedOptionSelectionMap"
<event-option-selector :event-list="eventList"
v-model="selectedOptionSelectionMap" :selected-event-id-list="selectedEventIdList"
:event-list="eventList" />
:selected-event-id-list="selectedEventIdList" <div class="content-margin">
/>
<code-scanner <code-scanner
visible visible
:session-key="scannerSessionKey" :session-key="scannerSessionKey"
@@ -29,7 +28,7 @@
@decode="handleDecodedText" @decode="handleDecodedText"
@status-change="handleScanStatusChange" @status-change="handleScanStatusChange"
/> />
</space> </div>
<t-cell-group class="auto-register-setting" theme="card" v-entrance-transition="55"> <t-cell-group class="auto-register-setting" theme="card" v-entrance-transition="55">
<t-cell title="识别成功自动登记"> <t-cell title="识别成功自动登记">
<template #right-icon> <template #right-icon>
@@ -46,7 +45,7 @@
:disabled="!canSubmitRegister" :disabled="!canSubmitRegister"
:loading="submitting" :loading="submitting"
v-entrance-transition="70" v-entrance-transition="70"
@click="doSubmit" @click="doSubmit()"
>登记</t-button> >登记</t-button>
<customer-profile-card <customer-profile-card
v-if="matchedCustomer" v-if="matchedCustomer"
@@ -120,6 +119,29 @@
@change="handleRecordPhotoSelected" @change="handleRecordPhotoSelected"
> >
</div> </div>
<bottom-popup
v-model="eventPopupVisible"
title="选择登记事件"
left-button-text="关闭"
right-button-text=""
@left-button-click="eventPopupVisible = false"
>
<div class="event-popup">
<event-selector
v-if="!isEventLoading && !eventLoadFailed"
:model-value="selectedEventIdList"
:event-list="eventList"
selection-mode="single"
label=""
@update:model-value="handleEventSelectionChange"
/>
<div v-else-if="isEventLoading" class="empty-block">正在加载登记事件</div>
<div v-else class="event-load-error">
<span>登记事件加载失败</span>
<t-button size="small" theme="primary" variant="text" @click="loadActions">重试</t-button>
</div>
</div>
</bottom-popup>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -145,7 +167,7 @@ import { compressUploadImageList } from "@/utils/imageCompression";
import { Storage, Time } from "timi-web"; import { Storage, Time } from "timi-web";
import { AttachmentAPI, type Attachment } from "timi-web-api"; import { AttachmentAPI, type Attachment } from "timi-web-api";
import EventSelector from "@/components/EventSelector.vue"; import EventSelector from "@/components/EventSelector.vue";
import { Space } from "timi-tdesign-mobile"; import { BottomPopup, Space } from "timi-tdesign-mobile";
defineOptions({ defineOptions({
name: "QuickSignInPage" name: "QuickSignInPage"
@@ -164,9 +186,11 @@ const eventList = ref<EventItem[]>([]);
const selectedOptionSelectionMap = reactive<EventOptionSelectionMap>({}); const selectedOptionSelectionMap = reactive<EventOptionSelectionMap>({});
const isEventLoading = ref(false); const isEventLoading = ref(false);
const eventLoadFailed = ref(false); const eventLoadFailed = ref(false);
const eventPopupVisible = ref(false);
const selectedEventList = computed(() => selectedEventIdList.value 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 selectedEventName = computed(() => selectedEventList.value[0]?.name || "请选择登记事件");
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)); const selectedRequiredPhotoEventList = computed(() => selectedEventList.value.filter(item => item.requirePhoto === true));
@@ -212,12 +236,13 @@ function buildInitialSelectedEventIdList(): string[] {
function normalizeSelectedEventIdList(eventIdList: string[]): string[] { function normalizeSelectedEventIdList(eventIdList: string[]): string[] {
const validEventIdSet = new Set(eventList.value.map(normalizeEventId).filter(Boolean)); const validEventIdSet = new Set(eventList.value.map(normalizeEventId).filter(Boolean));
return [...new Set(eventIdList.map(String))].filter(eventId => validEventIdSet.has(eventId)); return [...new Set(eventIdList.map(String))].filter(eventId => validEventIdSet.has(eventId)).slice(0, 1);
} }
async function handleEventSelectionChange(eventIdList: string[]): Promise<void> { async function handleEventSelectionChange(eventIdList: string[]): Promise<void> {
selectedEventIdList.value = normalizeSelectedEventIdList(eventIdList); selectedEventIdList.value = normalizeSelectedEventIdList(eventIdList);
syncStoredEventId(); syncStoredEventId();
eventPopupVisible.value = false;
} }
function resolveRecordOptionGroupList(eventId: string) { function resolveRecordOptionGroupList(eventId: string) {
@@ -279,7 +304,7 @@ async function handleDecodedText(rawText: string): Promise<void> {
} }
scanStatus.value = `已识别 ${normalizedText},可直接登记`; scanStatus.value = `已识别 ${normalizedText},可直接登记`;
if (autoRegisterEnabled.value) { if (autoRegisterEnabled.value) {
await doSubmit(); await doSubmit(true);
} }
return; return;
} }
@@ -424,7 +449,7 @@ function buildPhotoAttachmentList(): Array<Partial<Attachment>> {
})); }));
} }
async function doSubmit(): Promise<void> { async function doSubmit(isAutoRegister = false): Promise<void> {
const customer = matchedCustomer.value; const customer = matchedCustomer.value;
if (!customer) { if (!customer) {
return; return;
@@ -465,7 +490,11 @@ async function doSubmit(): Promise<void> {
attachmentList: buildPhotoAttachmentList() attachmentList: buildPhotoAttachmentList()
}))); })));
registeredCustomerIdSet.add(customerId); registeredCustomerIdSet.add(customerId);
scanStatus.value = `登记成功:${customer.name || customer.code || scanCode.value}。`; const customerText = customer.name || customer.code || scanCode.value || "客户";
scanStatus.value = `登记成功:${customerText}。`;
if (isAutoRegister) {
Message.success(`自动登记成功:${customerText}`);
}
scanCode.value = ""; scanCode.value = "";
matchedCustomer.value = undefined; matchedCustomer.value = undefined;
recordPhotoItemList.value = []; recordPhotoItemList.value = [];
@@ -493,18 +522,6 @@ async function doSubmit(): Promise<void> {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.event-panel {
padding: .75rem 1rem;
background: rgba(255, 255, 255, .94);
box-shadow: 0 .75rem 2rem rgba(15, 23, 42, .08);
border-radius: .875rem;
.tips {
margin-top: .5rem;
text-align: center;
}
}
.input-form { .input-form {
padding: .5rem 0; padding: .5rem 0;
background: rgba(255, 255, 255, .94); background: rgba(255, 255, 255, .94);
@@ -526,24 +543,6 @@ async function doSubmit(): Promise<void> {
display: none; display: none;
} }
.empty-block,
.event-load-error {
color: #52607a;
min-height: 4rem;
align-items: center;
justify-content: center;
}
.empty-block {
display: flex;
}
.event-load-error {
gap: .5rem;
display: grid;
text-align: center;
}
.code-box { .code-box {
padding: .875rem; padding: .875rem;
background: #f7faff; background: #f7faff;
@@ -581,6 +580,10 @@ async function doSubmit(): Promise<void> {
} }
} }
.event-popup {
padding: 1rem;
}
:global(html.theme-dark) { :global(html.theme-dark) {
.quick-sign-in-page { .quick-sign-in-page {
.panel, .panel,
-1
View File
@@ -208,7 +208,6 @@ onUnmounted(() => {
.tips { .tips {
font-size: .875rem; font-size: .875rem;
margin-top: 1rem;
text-indent: 2em; text-indent: 2em;
} }
} }