feat(platform): add customer history export wizard

This commit is contained in:
lingniu
2026-07-06 05:58:05 +08:00
parent 8b7614d2d6
commit 55a65d2bc6
3 changed files with 190 additions and 0 deletions

View File

@@ -1684,6 +1684,13 @@ export function History({
const evidenceDateFrom = filters.dateFrom?.trim()
|| dateOnly(rawFieldRows[0]?.deviceTime || rawItems[0]?.deviceTime || firstLocation?.deviceTime || firstLocation?.serverTime);
const evidenceDateTo = filters.dateTo?.trim() || (evidenceDateFrom ? nextDate(evidenceDateFrom) : '');
const exportWizardEvidenceLabel = rawFieldRows.length > 0
? '字段证据'
: validLocations.length > 0
? '轨迹报告'
: (rawFrames.total ?? 0) > 0
? '明细证据'
: '待查询证据';
const copyDeliveryCover = () => {
copyText(
deliveryCoverText({
@@ -1700,6 +1707,65 @@ export function History({
'客户数据交付封面包'
);
};
const copyExportWizardPackage = () => {
const evidenceFilters = {
...(evidenceDateFrom ? { dateFrom: evidenceDateFrom } : {}),
...(evidenceDateTo ? { dateTo: evidenceDateTo } : {})
};
const fieldFilters = {
tab: 'fields',
...evidenceFilters,
includeFields: 'true',
...(filters.fields?.trim() ? { fields: filters.fields.trim() } : {})
};
const lines = [
'【客户导出向导包】',
`步骤1 锁定范围:${currentVehicleKeyword || '全部车辆'} / ${currentProtocol || '全部来源证据'} / ${evidenceDateFrom || '-'}${evidenceDateTo || '-'}`,
`步骤2 选择证据:${exportWizardEvidenceLabel}`,
`步骤3 质量复核:${deliveryState}`,
'步骤4 导出交付:复制交付包',
`位置历史:${appURL(buildAppHash({ page: 'history-query', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: { ...evidenceFilters, tab: 'location' } }))}`,
`明细证据:${appURL(buildAppHash({ page: 'history-query', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`,
`字段裁剪:${appURL(buildAppHash({ page: 'history-query', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: fieldFilters }))}`,
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: evidenceFilters }))}`,
`统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: evidenceFilters }))}`
];
copyText(lines.join('\n'), '客户导出向导包');
};
const exportWizardSteps = [
{
step: '1',
title: '锁定范围',
value: `${currentVehicleKeyword || '全部车辆'} / ${currentProtocol || '全部来源证据'}`,
detail: `${evidenceDateFrom || '-'}${evidenceDateTo || '-'},先确认客户要查的车辆和时间窗。`,
color: currentVehicleKeyword ? 'green' as const : 'orange' as const,
onClick: () => document.querySelector<HTMLInputElement>('input[name="keyword"]')?.focus()
},
{
step: '2',
title: '选择证据',
value: exportWizardEvidenceLabel,
detail: rawFieldRows.length > 0 ? `${rawFieldRows.length.toLocaleString()} 个字段可按客户口径导出。` : `${validLocations.length.toLocaleString()} 个有效坐标,${(rawFrames.total ?? 0).toLocaleString()} 帧明细。`,
color: rawFieldRows.length > 0 || validLocations.length > 0 ? 'blue' as const : 'orange' as const,
onClick: () => rawFieldRows.length > 0 ? openQueryTab('fields') : validLocations.length > 0 ? openQueryTab('location') : openQueryTab('raw')
},
{
step: '3',
title: '质量复核',
value: deliveryState,
detail: anomalyTotal > 0 ? `存在 ${anomalyTotal.toLocaleString()} 项质量提示,交付时附说明。` : '当前范围可生成客户可读交付说明。',
color: deliveryStateColor,
onClick: () => copyDeliveryCover()
},
{
step: '4',
title: '导出交付',
value: '复制交付包',
detail: '把位置、明细、字段、轨迹和统计链接打包给客户或内部复核。',
color: 'blue' as const,
onClick: () => copyExportWizardPackage()
}
];
const copyScheduledHistoryReportPlan = () => {
copyText(
scheduledHistoryReportPlanText({
@@ -2295,6 +2361,40 @@ export function History({
<Tag color={currentProtocol ? 'blue' : 'green'}>{currentProtocol || '全部来源证据'}</Tag>
<Typography.Text type="tertiary">{scopeDescription}</Typography.Text>
</div>
{mode === 'query' ? (
<section className="vp-history-export-wizard" aria-label="客户导出向导">
<div className="vp-history-export-wizard-copy">
<Space wrap>
<Tag color="blue"></Tag>
<Tag color={deliveryStateColor}>{deliveryState}</Tag>
<Tag color={rawFieldRows.length > 0 ? 'green' : 'orange'}>{exportWizardEvidenceLabel}</Tag>
</Space>
<Typography.Title heading={5} style={{ margin: 0 }}>
</Typography.Title>
<Typography.Text type="secondary">
</Typography.Text>
<Button size="small" theme="solid" type="primary" icon={<IconCopy />} onClick={copyExportWizardPackage}></Button>
</div>
<div className="vp-history-export-wizard-steps">
{exportWizardSteps.map((item) => (
<button
key={item.step}
type="button"
className="vp-history-export-wizard-step"
onClick={item.onClick}
aria-label={`客户导出向导 ${item.step} ${item.title} ${item.value}`}
>
<Tag color={item.color}>{item.step}</Tag>
<strong>{item.title}</strong>
<span>{item.value}</span>
<small>{item.detail}</small>
</button>
))}
</div>
</section>
) : null}
{mode === 'query' ? (
<section className="vp-history-delivery-conclusion-strip" aria-label="客户数据交付封面">
<div className="vp-history-delivery-conclusion-copy">