1
This commit is contained in:
parent
55e133852e
commit
5a11b7431f
@ -479,6 +479,7 @@ const reportExportToastOpen = ref(false)
|
|||||||
const reportExportProgress = ref(0)
|
const reportExportProgress = ref(0)
|
||||||
const reportExportStatus = ref<'running' | 'success' | 'error'>('running')
|
const reportExportStatus = ref<'running' | 'success' | 'error'>('running')
|
||||||
const reportExportText = ref('')
|
const reportExportText = ref('')
|
||||||
|
const reportExportBlobUrl = ref<string | null>(null)
|
||||||
let reportExportToastTimer: ReturnType<typeof setTimeout> | null = null
|
let reportExportToastTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
|
|
||||||
const clearReportExportToastTimer = () => {
|
const clearReportExportToastTimer = () => {
|
||||||
@ -495,15 +496,32 @@ const showReportExportProgress = (progress: number, text: string) => {
|
|||||||
reportExportToastOpen.value = true
|
reportExportToastOpen.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const finishReportExportProgress = (success: boolean, text: string) => {
|
const finishReportExportProgress = (success: boolean, text: string, blobUrl?: string | null) => {
|
||||||
clearReportExportToastTimer()
|
clearReportExportToastTimer()
|
||||||
reportExportStatus.value = success ? 'success' : 'error'
|
reportExportStatus.value = success ? 'success' : 'error'
|
||||||
reportExportProgress.value = 100
|
reportExportProgress.value = 100
|
||||||
reportExportText.value = text
|
reportExportText.value = text
|
||||||
|
reportExportBlobUrl.value = success && blobUrl ? blobUrl : null
|
||||||
reportExportToastOpen.value = true
|
reportExportToastOpen.value = true
|
||||||
reportExportToastTimer = setTimeout(() => {
|
if (!success || !blobUrl) {
|
||||||
reportExportToastOpen.value = false
|
reportExportToastTimer = setTimeout(() => {
|
||||||
}, success ? 1200 : 1800)
|
reportExportToastOpen.value = false
|
||||||
|
}, success ? 1200 : 1800)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const openExportedReport = () => {
|
||||||
|
if (!reportExportBlobUrl.value) return
|
||||||
|
window.open(reportExportBlobUrl.value, '_blank')
|
||||||
|
reportExportToastOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const dismissReportToast = () => {
|
||||||
|
if (reportExportBlobUrl.value) {
|
||||||
|
URL.revokeObjectURL(reportExportBlobUrl.value)
|
||||||
|
reportExportBlobUrl.value = null
|
||||||
|
}
|
||||||
|
reportExportToastOpen.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabsModel = computed({
|
const tabsModel = computed({
|
||||||
@ -1609,12 +1627,13 @@ const exportData = async () => {
|
|||||||
const exportReport = async () => {
|
const exportReport = async () => {
|
||||||
try {
|
try {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const payload = await buildExportReportPayload()
|
const projectInfoRaw = await kvStore.getItem<XmInfoLike>(PROJECT_INFO_DB_KEY)
|
||||||
const fileName = `${sanitizeFileNamePart(payload.name)}-报表-${formatExportTimestamp(now)}`
|
const projectName = isNonEmptyString(projectInfoRaw?.projectName) ? sanitizeFileNamePart(projectInfoRaw.projectName) : '造价项目'
|
||||||
await exportFile(fileName, payload, () => {
|
const fileName = `${projectName}-报表-${formatExportTimestamp(now)}`
|
||||||
|
const blobUrl = await exportFile(fileName, () => buildExportReportPayload(), () => {
|
||||||
showReportExportProgress(30, '正在生成报表文件...')
|
showReportExportProgress(30, '正在生成报表文件...')
|
||||||
})
|
})
|
||||||
finishReportExportProgress(true, '报表导出完成')
|
finishReportExportProgress(true, '报表导出完成', blobUrl)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('export report failed:', error)
|
console.error('export report failed:', error)
|
||||||
if (reportExportToastOpen.value) {
|
if (reportExportToastOpen.value) {
|
||||||
@ -2012,12 +2031,21 @@ watch(
|
|||||||
v-model:open="reportExportToastOpen"
|
v-model:open="reportExportToastOpen"
|
||||||
:duration="0"
|
:duration="0"
|
||||||
class="pointer-events-auto rounded-xl border border-border bg-card px-4 py-3 text-foreground shadow-lg"
|
class="pointer-events-auto rounded-xl border border-border bg-card px-4 py-3 text-foreground shadow-lg"
|
||||||
|
@update:open="(val) => { if (!val) dismissReportToast() }"
|
||||||
>
|
>
|
||||||
<ToastTitle class="text-sm font-semibold text-foreground">
|
<ToastTitle class="text-sm font-semibold text-foreground">
|
||||||
{{ reportExportStatus === 'running' ? '导出报表' : (reportExportStatus === 'success' ? '导出成功' : '导出失败') }}
|
{{ reportExportStatus === 'running' ? '导出报表' : (reportExportStatus === 'success' ? '导出成功' : '导出失败') }}
|
||||||
</ToastTitle>
|
</ToastTitle>
|
||||||
<ToastDescription class="mt-1 text-xs text-muted-foreground">{{ reportExportText }}</ToastDescription>
|
<ToastDescription class="mt-1 text-xs text-muted-foreground">{{ reportExportText }}</ToastDescription>
|
||||||
<div class="mt-2 flex items-center gap-2">
|
<div v-if="reportExportStatus === 'success' && reportExportBlobUrl" class="mt-2 flex items-center gap-2">
|
||||||
|
<Button size="sm" class="h-7 rounded-md px-3 text-xs" @click="openExportedReport">
|
||||||
|
打开文件
|
||||||
|
</Button>
|
||||||
|
<Button variant="ghost" size="sm" class="h-7 rounded-md px-2 text-xs text-muted-foreground" @click="dismissReportToast">
|
||||||
|
关闭
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div v-else class="mt-2 flex items-center gap-2">
|
||||||
<div class="h-1.5 flex-1 overflow-hidden rounded-full bg-muted">
|
<div class="h-1.5 flex-1 overflow-hidden rounded-full bg-muted">
|
||||||
<div
|
<div
|
||||||
class="h-full transition-all duration-300"
|
class="h-full transition-all duration-300"
|
||||||
|
|||||||
18
src/sql.ts
18
src/sql.ts
@ -688,7 +688,7 @@ export function getBasicFeeFromScale(
|
|||||||
* 导出入口:生成 Excel 并触发保存(优先使用 File System Access API)。
|
* 导出入口:生成 Excel 并触发保存(优先使用 File System Access API)。
|
||||||
* @returns 导出流程完成后的 Promise
|
* @returns 导出流程完成后的 Promise
|
||||||
*/
|
*/
|
||||||
export async function exportFile(fileName: string, data: any, onSaveConfirmed?: () => void): Promise<void> {
|
export async function exportFile(fileName: string, data: any | (() => Promise<any>), onSaveConfirmed?: () => void): Promise<string | null> {
|
||||||
if (window.showSaveFilePicker) {
|
if (window.showSaveFilePicker) {
|
||||||
const handle = await window.showSaveFilePicker({
|
const handle = await window.showSaveFilePicker({
|
||||||
suggestedName: fileName,
|
suggestedName: fileName,
|
||||||
@ -699,25 +699,26 @@ export async function exportFile(fileName: string, data: any, onSaveConfirmed?:
|
|||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
onSaveConfirmed?.()
|
onSaveConfirmed?.()
|
||||||
|
const resolvedData = typeof data === 'function' ? await data() : data
|
||||||
const workbook = await generateTemplate(data);
|
const workbook = await generateTemplate(resolvedData);
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
const writable = await handle.createWritable();
|
const writable = await handle.createWritable();
|
||||||
await writable.write(buffer);
|
await writable.write(buffer);
|
||||||
await writable.close();
|
await writable.close();
|
||||||
|
// 返回 blob URL 供打开文件使用
|
||||||
|
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||||||
|
return URL.createObjectURL(blob);
|
||||||
// ecCom.WeaLoadingGlobal.destroy();
|
// ecCom.WeaLoadingGlobal.destroy();
|
||||||
// antd.notification['success']({
|
// antd.notification['success']({
|
||||||
// message: '下载成功!',
|
// message: '下载成功!',
|
||||||
// });
|
// });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err:' + err);
|
console.log('err:' + err);
|
||||||
// ecCom.WeaLoadingGlobal.destroy();
|
return null;
|
||||||
// antd.notification['error']({
|
|
||||||
// message: '下载失败!',
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const workbook = await generateTemplate(data);
|
const resolvedData = typeof data === 'function' ? await data() : data
|
||||||
|
const workbook = await generateTemplate(resolvedData);
|
||||||
const buffer = await workbook.xlsx.writeBuffer();
|
const buffer = await workbook.xlsx.writeBuffer();
|
||||||
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
||||||
const url1 = window.URL.createObjectURL(blob);
|
const url1 = window.URL.createObjectURL(blob);
|
||||||
@ -726,6 +727,7 @@ export async function exportFile(fileName: string, data: any, onSaveConfirmed?:
|
|||||||
a.download = `${fileName}.xlsx`;
|
a.download = `${fileName}.xlsx`;
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url1);
|
URL.revokeObjectURL(url1);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user