add point

This commit is contained in:
Timi
2026-08-11 22:25:30 +08:00
parent e612cfd382
commit 9f60a36c6c
21 changed files with 2928 additions and 36 deletions
+95 -9
View File
@@ -8,9 +8,9 @@
readonly
borderless
placeholder="选择或扫码客户"
@click="openSelectedCustomerList"
@click="!isEditMode && openSelectedCustomerList()"
>
<template #suffix-icon>
<template v-if="!isEditMode" #suffix-icon>
<div class="actions">
<t-button
theme="primary"
@@ -47,9 +47,20 @@
v-model="selectedEventIdList"
class="registration-event-selector"
:event-list="eventList"
:disabled="isEditMode"
required-mark
/>
<t-form-item label="登记时间" content-align="right">
<div v-if="isEditMode" class="edit-point-tip">已产生积分的登记记录不会因修改客户、事件或时间而重算;如需修改这些事实,请删除后重新创建。</div>
<t-form-item v-if="showSourceValueInput" label="自定义积分" required-mark>
<t-input
v-model.trim="pointValueText"
type="number"
align="right"
borderless
:placeholder="sourceValuePlaceholder"
/>
</t-form-item>
<t-form-item v-if="!isEditMode" label="登记时间" content-align="right">
<div class="time-actions">
<t-button
theme="primary"
@@ -68,6 +79,9 @@
/>
</div>
</t-form-item>
<t-form-item v-else label="登记时间" content-align="right">
<span class="readonly-time" v-text="registeredAtText || '此刻'" />
</t-form-item>
<t-form-item label="登记备注">
<t-textarea
v-model.trim="note"
@@ -103,6 +117,7 @@
</t-cell-group>
<div v-else class="empty">当前客户暂无事件记录</div>
<customer-selector
v-if="!isEditMode"
v-model="selectedCustomerIdList"
v-model:visible="selectorVisible"
:selection-mode="isEditMode ? 'single' : 'multiple'"
@@ -151,7 +166,7 @@
</template>
<script setup lang="ts">
import { AttachmentAPI, Time, type Attachment } from "timi-web";
import { AttachmentAPI, Time, type Attachment, useUserStore } from "timi-web";
import { Toast } from "tdesign-mobile-vue";
import CustomerAPI from "@/api/CustomerAPI";
import EventAPI from "@/api/EventAPI";
@@ -168,6 +183,7 @@ import type { EventItem } from "@/types/EventItem";
import type { EventRecord } from "@/types/EventRecord";
import { getEventRecordPhotoURL } from "@/utils/eventRecord";
import { permissionCodes } from "@/utils/permission";
import { loadSourceValueRange } from "@/utils/point";
import { compressUploadImageList } from "@/utils/imageCompression";
defineOptions({
@@ -177,6 +193,7 @@ defineOptions({
const router = useRouter();
const route = useRoute();
const settingStore = useSettingStore();
const userStore = useUserStore();
type EditablePhoto = {
attachment?: Partial<Attachment>;
@@ -375,6 +392,45 @@ function appendRecordEvent(record: EventRecord): void {
eventList.value = [record.event, ...eventList.value];
}
// ---------- 积分规则联动 ----------
const pointValueText = ref("");
const sourceValueRange = ref<[number, number]>();
let sourceValueLoadToken = 0;
const showSourceValueInput = computed(() => (
!isEditMode.value
&& userStore.hasPermissions(permissionCodes.point.sourceValue)
&& !!sourceValueRange.value
));
const sourceValuePlaceholder = computed(() => {
const range = sourceValueRange.value;
return range ? `请输入 ${range[0]}-${range[1]} 的正整数` : "请输入积分";
});
async function loadSourceValueRule(): Promise<void> {
const token = sourceValueLoadToken + 1;
sourceValueLoadToken = token;
sourceValueRange.value = undefined;
if (isEditMode.value || !userStore.hasPermissions(permissionCodes.point.sourceValue) || !selectedEventIdList.value.length) {
return;
}
try {
sourceValueRange.value = await loadSourceValueRange(selectedEventIdList.value);
if (token !== sourceValueLoadToken) {
return;
}
} catch {
sourceValueRange.value = undefined;
}
}
function resolveSourceValue(): number | undefined {
const value = Number(pointValueText.value);
return Number.isSafeInteger(value) && 0 < value ? value : undefined;
}
// ---------- 照片 ----------
const recordPhotoInputRef = ref<HTMLInputElement>();
@@ -484,6 +540,7 @@ async function submitRecord(): Promise<void> {
customerIdList,
remark: note.value || "客户现场登记",
registeredAt: buildRegisteredAt(),
pointValue: showSourceValueInput.value ? resolveSourceValue() : undefined,
attachmentList: buildTempFileIdList().map(tempFileId => ({
tempFileId,
attachType: "PHOTO"
@@ -493,6 +550,7 @@ async function submitRecord(): Promise<void> {
selectedCustomerList.value = [];
selectedCustomerIdList.value = [];
note.value = "";
pointValueText.value = "";
photoItemList.value = [];
await loadRecentRecordList();
await settingStore.playRegisterSuccessSound();
@@ -512,23 +570,30 @@ function validateForm(): boolean {
Toast.warning("请至少选择一个登记事件");
return false;
}
if (showSourceValueInput.value) {
const pointValue = resolveSourceValue();
const range = sourceValueRange.value;
if (!pointValue || !range || pointValue < range[0] || range[1] < pointValue) {
Toast.warning(`自定义积分必须是 ${range?.[0] || 1}-${range?.[1] || 0} 的正整数`);
return false;
}
}
return true;
}
async function updateRecord(): Promise<void> {
const submitCustomer = selectedCustomer.value;
if (!editingRecord.value?.id || !submitCustomer?.id) {
if (!editingRecord.value?.id || !editingRecord.value.customerId || !editingRecord.value.eventId) {
Toast.warning("登记事件记录不存在");
return;
}
await EventRecordAPI.update({
...editingRecord.value,
customerId: submitCustomer.id,
eventId: selectedEventIdList.value[0],
customerId: editingRecord.value.customerId,
eventId: editingRecord.value.eventId,
remark: note.value,
registeredAt: buildRegisteredAt(),
registeredAt: editingRecord.value.registeredAt,
attachmentList: buildPhotoAttachmentList()
});
Toast.success("记录已保存");
@@ -574,6 +639,7 @@ async function loadRecordForEdit(): Promise<void> {
selectedEventIdList.value = record.eventId ? [record.eventId] : [];
registeredAtText.value = record.registeredAt ? Time.formatDateTime(new Date(record.registeredAt)) : "";
note.value = record.remark || "";
pointValueText.value = "";
photoItemList.value = (record.attachmentList || [])
.filter(item => item.attachType === "PHOTO" || !item.attachType)
.filter(item => !!item.id)
@@ -586,6 +652,10 @@ async function loadRecordForEdit(): Promise<void> {
onMounted(loadPageData);
watch(selectedEventIdList, async () => {
await loadSourceValueRule();
}, { deep: true });
watch(customerCode, async (value) => {
if (!value) {
return;
@@ -647,6 +717,17 @@ watch(customerCode, async (value) => {
align-items: center;
justify-content: flex-end;
}
.edit-point-tip {
color: #9a3412;
padding: 0 1rem 1rem;
font-size: .8125rem;
line-height: 1.5;
}
.readonly-time {
color: #52607a;
}
}
.record-photo {
@@ -730,6 +811,11 @@ watch(customerCode, async (value) => {
.selector-action {
color: #93c5fd;
}
.edit-point-tip,
.readonly-time {
color: #fbbf24;
}
}
}
</style>