add:新增验证视频可选上传功能

This commit is contained in:
2026-10-24 16:12:56 +08:00
parent 25756901cc
commit 0ee5554f57
28 changed files with 1588 additions and 51 deletions
@@ -1,4 +1,4 @@
import { ReloadOutlined } from '@ant-design/icons'
import { ReloadOutlined, VideoCameraOutlined } from '@ant-design/icons'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import {
App,
@@ -26,7 +26,12 @@ import {
repayAdminAfterSalesCaseDebt,
resolveAdminAfterSalesCase,
} from '@/services/admin'
import type { UploadedFile, WorkerAfterSalesCase, WorkOrder } from '@/types/worker-platform'
import type {
UploadedFile,
WorkerAcceptanceVideo,
WorkerAfterSalesCase,
WorkOrder,
} from '@/types/worker-platform'
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
import { formatAdminDateTime } from '@/utils/admin-time'
import { uniqueUploadedFiles } from '@/utils/image-identity'
@@ -259,6 +264,15 @@ const AfterSalesPanel = forwardRef<AfterSalesPanelHandle>(function AfterSalesPan
/>
</Space>
) : null}
{getAfterSalesSnapshotVideo(item) ? (
<a
href={getAfterSalesSnapshotVideo(item)?.url}
target="_blank"
rel="noreferrer"
>
<VideoCameraOutlined /> 查看固化验收视频
</a>
) : null}
</div>
),
},
@@ -570,4 +584,21 @@ function getAfterSalesSnapshotFiles(item: WorkerAfterSalesCase): UploadedFile[]
)
}
/** 售后固化快照里的验收视频(有则给出可点击链接)。 */
function getAfterSalesSnapshotVideo(item: WorkerAfterSalesCase): WorkerAcceptanceVideo | null {
const snapshot = asRecord(item.acceptanceSnapshot)
const acceptance = asRecord(snapshot.acceptance)
const video = asRecord(acceptance.video)
const url = String(video.url || '').trim()
if (!url) return null
return {
objectKey: String(video.objectKey || video.object_key || ''),
url,
filename: String(video.filename || ''),
contentType: String(video.contentType || video.content_type || ''),
size: Number(video.size || 0),
durationSeconds: Number(video.durationSeconds || video.duration_seconds || 0),
}
}
export default AfterSalesPanel
@@ -14,6 +14,7 @@ import {
UserAddOutlined,
WarningOutlined,
RollbackOutlined,
VideoCameraOutlined,
} from '@ant-design/icons'
import { useQuery, useQueryClient } from '@tanstack/react-query'
import {
@@ -28,6 +29,7 @@ import {
Input,
InputNumber,
Modal,
Popover,
Radio,
Select,
Space,
@@ -45,6 +47,7 @@ import JsonPreview from '@/components/admin/JsonPreview'
import WorkOrderEventTimeline from '@/components/WorkOrderEventTimeline'
import ImageUpload from '@/components/files/ImageUpload'
import ImagePreviewList from '@/components/files/ImagePreviewList'
import VideoPreview, { formatAcceptanceVideoDuration } from '@/components/files/VideoPreview'
import {
acceptAdminWorkOrder,
acceptAdminWorkOrderShare,
@@ -2603,6 +2606,11 @@ export default function WorkOrdersPanel() {
{getAcceptanceFiles(detailOrder).length +
getAcceptanceImageUrls(detailOrder).length || '-'}
</Descriptions.Item>
<Descriptions.Item label="验收视频">
{detailOrder.acceptance?.video
? formatAcceptanceVideoDuration(detailOrder.acceptance.video.durationSeconds)
: '未上传'}
</Descriptions.Item>
{detailOrder.acceptance?.reviewMode === 'vip_auto' ? (
<Descriptions.Item label="VIP 补图">
{detailOrder.acceptance.evidenceStatus === 'pending'
@@ -2626,6 +2634,11 @@ export default function WorkOrdersPanel() {
) : (
<Typography.Text type="secondary">暂无验收图</Typography.Text>
)}
<VideoPreview
video={detailOrder.acceptance?.video ?? null}
maxHeight={200}
emptyText="暂无验收视频(选填)"
/>
</div>
</Card>
@@ -3205,7 +3218,7 @@ export default function WorkOrdersPanel() {
loading={sharingQuery.isFetching}
pagination={false}
tableLayout="fixed"
scroll={{ x: 1528 }}
scroll={{ x: 1624 }}
rowClassName={(share) =>
share.problemMarked
? 'admin-share-row-problem'
@@ -3316,6 +3329,26 @@ export default function WorkOrdersPanel() {
/>
),
},
{
title: '验收视频',
width: 96,
render: (_, share) => {
const video = share.acceptance?.video
if (!video?.url) return '-'
return (
<Popover
trigger="click"
placement="left"
title="验收视频"
content={<VideoPreview video={video} maxHeight={240} showMeta />}
>
<Button size="small" icon={<VideoCameraOutlined />}>
查看
</Button>
</Popover>
)
},
},
{
title: '备注',
width: 120,