final
This commit is contained in:
1 parent
398fca9265
commit
f4f6e5c618
6 files changed
+207
-71
No files matched your search
+76
-4
@@ -20,6 +20,11 @@ import {
|
||||
AlertDialogRoot,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
ToastDescription,
|
||||
ToastProvider,
|
||||
ToastRoot,
|
||||
ToastTitle,
|
||||
ToastViewport,
|
||||
} from 'reka-ui'
|
||||
import { decodeZwArchive, encodeZwArchive, ZW_FILE_EXTENSION } from '@/lib/zwArchive'
|
||||
import { addNumbers, roundTo } from '@/lib/decimal'
|
||||
@@ -62,6 +67,7 @@ interface ScaleRowLike {
|
||||
id: string
|
||||
amount: number | null
|
||||
landArea: number | null
|
||||
isGroupRow?: boolean
|
||||
}
|
||||
|
||||
interface XmInfoStorageLike extends XmInfoLike {
|
||||
@@ -457,6 +463,10 @@ const pendingImportPayload = shallowRef<DataPackage | null>(null)
|
||||
const pendingImportFileName = ref('')
|
||||
const userGuideOpen = ref(false)
|
||||
const userGuideStepIndex = ref(0)
|
||||
const reportExportToastOpen = ref(false)
|
||||
const reportExportProgress = ref(0)
|
||||
const reportExportStatus = ref<'running' | 'success' | 'error'>('running')
|
||||
const reportExportText = ref('')
|
||||
const tabItemElMap = new Map<string, HTMLElement>()
|
||||
const tabTitleElMap = new Map<string, HTMLElement>()
|
||||
const tabPanelElMap = new Map<string, HTMLElement>()
|
||||
@@ -468,6 +478,7 @@ const isTabDragging = ref(false)
|
||||
const tabTitleOverflowMap = ref<Record<string, boolean>>({})
|
||||
let tabStripViewportEl: HTMLElement | null = null
|
||||
let tabTitleOverflowRafId: number | null = null
|
||||
let reportExportToastTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
const tabsModel = computed({
|
||||
get: () => tabStore.tabs,
|
||||
@@ -502,6 +513,31 @@ const closeMenus = () => {
|
||||
dataMenuOpen.value = false
|
||||
}
|
||||
|
||||
const clearReportExportToastTimer = () => {
|
||||
if (!reportExportToastTimer) return
|
||||
clearTimeout(reportExportToastTimer)
|
||||
reportExportToastTimer = null
|
||||
}
|
||||
|
||||
const showReportExportProgress = (progress: number, text: string) => {
|
||||
clearReportExportToastTimer()
|
||||
reportExportStatus.value = 'running'
|
||||
reportExportProgress.value = Math.max(0, Math.min(100, progress))
|
||||
reportExportText.value = text
|
||||
reportExportToastOpen.value = true
|
||||
}
|
||||
|
||||
const finishReportExportProgress = (success: boolean, text: string) => {
|
||||
clearReportExportToastTimer()
|
||||
reportExportStatus.value = success ? 'success' : 'error'
|
||||
reportExportProgress.value = 100
|
||||
reportExportText.value = text
|
||||
reportExportToastOpen.value = true
|
||||
reportExportToastTimer = setTimeout(() => {
|
||||
reportExportToastOpen.value = false
|
||||
}, success ? 1200 : 1800)
|
||||
}
|
||||
|
||||
const markGuideCompleted = () => {
|
||||
try {
|
||||
localStorage.setItem(USER_GUIDE_COMPLETED_KEY, '1')
|
||||
@@ -1016,6 +1052,16 @@ const toExportScaleRows = (rows: ScaleRowLike[] | undefined): ExportScaleRow[] =
|
||||
.filter((item): item is ExportScaleRow => Boolean(item))
|
||||
}
|
||||
|
||||
const sumLeafScaleCost = (rows: ScaleRowLike[] | undefined) => {
|
||||
if (!Array.isArray(rows)) return 0
|
||||
return sumNumbers(
|
||||
rows.map(row => {
|
||||
if (row?.isGroupRow === true) return null
|
||||
return toFiniteNumber(row?.amount)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const buildMethod1 = (rows: ScaleMethodRowLike[] | undefined): ExportMethod1 | null => {
|
||||
@@ -1365,9 +1411,8 @@ const buildExportReportPayload = async (): Promise<ExportReportPayload> => {
|
||||
|
||||
const projectInfo = projectInfoRaw || {}
|
||||
const projectScaleSource = projectScaleRaw || {}
|
||||
|
||||
const projectScale = projectScaleSource.roughCalcEnabled ? [] : toExportScaleRows(projectScaleSource.detailRows)
|
||||
const projectScaleCost = toFiniteNumber(projectScaleSource.totalAmount) ?? sumNumbers(projectScale.map(item => item.cost))
|
||||
const projectScaleCost = toFiniteNumber(projectScaleSource.totalAmount) ?? sumLeafScaleCost(projectScaleSource.detailRows)
|
||||
projectScale.push({
|
||||
major: -1, cost: projectScaleCost,
|
||||
area: null
|
||||
@@ -1572,14 +1617,17 @@ const exportData = async () => {
|
||||
|
||||
const exportReport = async () => {
|
||||
try {
|
||||
showReportExportProgress(10, '正在准备报表导出...')
|
||||
const now = new Date()
|
||||
showReportExportProgress(40, '正在汇总报表数据...')
|
||||
const payload = await buildExportReportPayload()
|
||||
showReportExportProgress(80, '正在生成并写出报表文件...')
|
||||
const fileName = `${sanitizeFileNamePart(payload.name)}-报表-${formatExportTimestamp(now)}`
|
||||
console.log(payload)
|
||||
await exportFile(fileName, payload)
|
||||
finishReportExportProgress(true, '报表导出完成')
|
||||
} catch (error) {
|
||||
console.error('export report failed:', error)
|
||||
// window.alert('导出报表失败,请重试。')
|
||||
finishReportExportProgress(false, '报表导出失败,请重试')
|
||||
} finally {
|
||||
dataMenuOpen.value = false
|
||||
}
|
||||
@@ -1710,6 +1758,7 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearReportExportToastTimer()
|
||||
window.removeEventListener('mousedown', handleGlobalMouseDown)
|
||||
window.removeEventListener('keydown', handleGlobalKeyDown)
|
||||
window.removeEventListener('resize', scheduleUpdateTabTitleOverflow)
|
||||
@@ -1761,6 +1810,7 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ToastProvider>
|
||||
<TooltipProvider>
|
||||
<div class="flex flex-col w-full h-screen bg-background overflow-hidden">
|
||||
<div class="grid grid-cols-[minmax(0,1fr)_auto] items-start gap-2 border-b bg-muted/30 px-2 pt-1 h-15 flex-none">
|
||||
@@ -1966,8 +2016,30 @@ watch(
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ToastRoot
|
||||
:open="reportExportToastOpen"
|
||||
:duration="0"
|
||||
class="pointer-events-auto rounded-xl border border-border bg-card px-4 py-3 text-foreground shadow-lg"
|
||||
>
|
||||
<ToastTitle class="text-sm font-semibold text-foreground">
|
||||
{{ reportExportStatus === 'running' ? '导出报表' : (reportExportStatus === 'success' ? '导出成功' : '导出失败') }}
|
||||
</ToastTitle>
|
||||
<ToastDescription class="mt-1 text-xs text-muted-foreground">{{ reportExportText }}</ToastDescription>
|
||||
<div class="mt-2 h-1.5 w-full overflow-hidden rounded-full bg-muted">
|
||||
<div
|
||||
class="h-full transition-all duration-300"
|
||||
:class="reportExportStatus === 'error'
|
||||
? 'bg-red-500'
|
||||
: (reportExportStatus === 'success' ? 'bg-foreground/70' : 'bg-foreground')"
|
||||
:style="{ width: `${reportExportProgress}%` }"
|
||||
/>
|
||||
</div>
|
||||
</ToastRoot>
|
||||
<ToastViewport class="fixed bottom-5 right-5 z-[85] flex w-[380px] max-w-[92vw] flex-col gap-2 outline-none" />
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</ToastProvider>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in new issue
Block a user