update AIChart, customer followup, media selector

This commit is contained in:
Timi
2026-09-18 17:38:55 +08:00
parent c6b398fa98
commit 57c4275a23
57 changed files with 3866 additions and 2071 deletions
+18 -4
View File
@@ -34,8 +34,8 @@
</t-cell>
</t-cell-group>
<card-container v-entrance-transition="140">
<photo-scroller
class="photo-scroller"
<media-selector
class="media-selector"
:model-value="photoList"
:photo-items="photoItemList"
:show-viewer-actions="canUpdateCustomer"
@@ -98,6 +98,9 @@
<t-cell-group theme="card">
<t-cell title="邀请客户" :note="inviteeCountText" arrow @click="toInviteeList" />
</t-cell-group>
<t-cell-group v-if="canReadFollowUpReminder" title="客户跟进" theme="card">
<t-cell title="跟进提醒" note="查看客户提醒" arrow @click="toFollowUpReminderList" />
</t-cell-group>
<t-button
v-can="permissionCodes.customer.delete"
class="delete-action"
@@ -142,7 +145,7 @@ import TagAPI from "@/api/TagAPI";
import BodyAreaSelector from "@/components/BodyAreaSelector.vue";
import CustomerRemoveDialog from "@/pages/customer/component/CustomerRemoveDialog.vue";
import CustomerProfileCard from "@/components/CustomerProfileCard.vue";
import PhotoScroller from "@/components/PhotoScroller.vue";
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
import TagSelector from "@/components/TagSelector.vue";
import CustomerTagCard from "@/pages/customer/component/CustomerTagCard.vue";
import { useNavBarStore } from "@/store/navBarStore";
@@ -177,6 +180,7 @@ const canReadSalesOrder = computed(() => userStore.hasPermissions(permissionCode
const canReadTag = computed(() => userStore.hasPermissions(corePermissionCodes.tag.read));
const canApplyTag = computed(() => userStore.hasPermissions(corePermissionCodes.tag.apply));
const canUpdateCustomer = computed(() => userStore.hasPermissions(permissionCodes.customer.update));
const canReadFollowUpReminder = computed(() => userStore.hasPermissions(permissionCodes.customerFollowUpReminder.read));
// ---------- 资料 ----------
@@ -389,6 +393,16 @@ async function toInviteeList(): Promise<void> {
await router.push(`/management/customers/${customer.value.id}/invitees`);
}
async function toFollowUpReminderList(): Promise<void> {
if (!customer.value?.id || !canReadFollowUpReminder.value) {
return;
}
await router.push({
name: "CustomerFollowUpReminderList",
query: { customerId: customer.value.id }
});
}
async function toEventRecordList(): Promise<void> {
if (!canReadEventRecord.value || !customer.value?.id) {
return;
@@ -531,7 +545,7 @@ onUnmounted(() => navBarStore.clearRight());
}
}
:deep(.photo-scroller) {
:deep(.media-selector) {
padding: 1rem;
}
+50 -16
View File
@@ -71,7 +71,7 @@
</t-form-item>
<t-form-item label-width="0">
<div class="photo">
<photo-scroller
<media-selector
v-model="photoList"
v-model:photo-items="photoItemList"
:edit-mode="true"
@@ -80,8 +80,10 @@
:show-viewer-actions="!isCustomerBound"
:add-actions="photoAddActions"
:loading="isPhotoUploading"
@add-photo="openPhotoPicker('PHOTO')"
@add-point-card="openPhotoPicker('POINT_CARD')"
@add="openPhotoPicker('OTHER')"
@capture-photo="capturePhoto"
@capture-video="captureVideo"
@add-point-card="capturePointCard"
@add-other="openPhotoPicker('OTHER')"
/>
<div class="tips orange" v-if="!hasCustomerDeletePermission">当前账户权限编辑客户需要上传照片和积分卡</div>
@@ -176,7 +178,23 @@
ref="photoInputRef"
class="file-input"
type="file"
accept="*/*"
@change="handlePhotoSelected"
>
<input
ref="photoCameraInputRef"
class="file-input"
type="file"
accept="image/*"
capture="environment"
@change="handlePhotoSelected"
>
<input
ref="videoInputRef"
class="file-input"
type="file"
accept="video/*"
capture="environment"
@change="handlePhotoSelected"
>
<customer-selector
@@ -213,7 +231,7 @@ import BodyAreaSelector from "@/components/BodyAreaSelector.vue";
import CodeScanner from "@/components/CodeScanner.vue";
import CustomerProfileCard from "@/components/CustomerProfileCard.vue";
import CustomerSelector from "@/components/CustomerSelector.vue";
import PhotoScroller from "@/components/PhotoScroller.vue";
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
import TagSelector from "@/components/TagSelector.vue";
import CustomerTagCard from "@/pages/customer/component/CustomerTagCard.vue";
import { useCurrentStoreStore } from "@/store/currentStoreStore";
@@ -442,6 +460,30 @@ function openPhotoPicker(target: CustomerAttachmentType): void {
photoInputRef.value?.click();
}
function capturePhoto(): void {
if (isCustomerBound.value) {
return;
}
photoPickerTarget.value = "PHOTO";
photoCameraInputRef.value?.click();
}
function capturePointCard(): void {
if (isCustomerBound.value) {
return;
}
photoPickerTarget.value = "POINT_CARD";
photoCameraInputRef.value?.click();
}
function captureVideo(): void {
if (isCustomerBound.value) {
return;
}
photoPickerTarget.value = "OTHER";
videoInputRef.value?.click();
}
watch(isCustomerBound, (value) => {
navBarStore.setRightDisabled(value);
if (!value) {
@@ -485,6 +527,7 @@ async function loadDetail() {
.map(item => ({
attachment: item,
attachType: normalizeAttachmentType(item.attachType),
mimeType: item.mimeType,
previewUrl: getAttachmentReadURL(item.id || ""),
url: getAttachmentReadURL(item.id || "", 90)
}));
@@ -531,24 +574,14 @@ watch(() => formData.birthdate, (value) => {
// ---------- 照片 ----------
const photoInputRef = ref<HTMLInputElement>();
const photoCameraInputRef = ref<HTMLInputElement>();
const videoInputRef = 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");
@@ -602,6 +635,7 @@ async function handlePhotoSelected(event: Event): Promise<void> {
if (tempFile?.id) {
photoItemList.value.push({
attachType: photoPickerTarget.value,
mimeType: file.type,
tempFileId: tempFile.id,
url: AttachmentAPI.getTempReadURL(tempFile.id)
});