fix toast Style issue

This commit is contained in:
wintsa 2026-03-18 10:42:42 +08:00
parent 083c8f1886
commit 55e133852e
4 changed files with 80 additions and 13 deletions

View File

@ -11,7 +11,10 @@
"Bash(bun run:*)", "Bash(bun run:*)",
"Bash(grep:*)", "Bash(grep:*)",
"mcp__context7__resolve-library-id", "mcp__context7__resolve-library-id",
"mcp__context7__query-docs" "mcp__context7__query-docs",
"mcp__ag-mcp__detect_version",
"WebSearch",
"WebFetch(domain:reka-ui.com)"
] ]
} }
} }

View File

@ -1756,21 +1756,21 @@ watch(budgetRefreshSignature, (next, prev) => {
<ToastRoot <ToastRoot
v-model:open="toastOpen" v-model:open="toastOpen"
:duration="1800" :duration="1800"
class="group pointer-events-auto flex items-center gap-3 rounded-xl border border-slate-800/90 bg-slate-900 px-4 py-3 text-white shadow-xl" class="group pointer-events-auto flex items-center gap-3 rounded-xl border border-border bg-card px-4 py-3 text-foreground shadow-lg"
> >
<div class="grid gap-1"> <div class="grid gap-1">
<ToastTitle class="text-sm font-semibold text-white">{{ toastTitle }}</ToastTitle> <ToastTitle class="text-sm font-semibold text-foreground">{{ toastTitle }}</ToastTitle>
<ToastDescription class="text-xs text-slate-100">{{ toastText }}</ToastDescription> <ToastDescription class="text-xs text-muted-foreground">{{ toastText }}</ToastDescription>
</div> </div>
<ToastAction <ToastAction
alt-text="知道了" alt-text="知道了"
class="ml-auto inline-flex h-7 items-center rounded-md border border-white/30 bg-white/10 px-2 text-xs text-white hover:bg-white/20" class="ml-auto cursor-pointer inline-flex h-7 items-center rounded-md border border-border bg-muted px-2 text-xs text-foreground hover:bg-muted/80"
@click="toastOpen = false" @click="toastOpen = false"
> >
知道了 知道了
</ToastAction> </ToastAction>
</ToastRoot> </ToastRoot>
<ToastViewport class="fixed bottom-5 right-5 z-[80] flex w-[380px] max-w-[92vw] flex-col gap-2 outline-none" /> <ToastViewport class="fixed bottom-5 right-5 z-[85] flex w-[380px] max-w-[92vw] flex-col gap-2 outline-none" />
</TooltipProvider> </TooltipProvider>
</ToastProvider> </ToastProvider>
</template> </template>

View File

@ -20,6 +20,11 @@ import {
AlertDialogRoot, AlertDialogRoot,
AlertDialogTitle, AlertDialogTitle,
AlertDialogTrigger, AlertDialogTrigger,
ToastDescription,
ToastProvider,
ToastRoot,
ToastTitle,
ToastViewport
} from 'reka-ui' } from 'reka-ui'
import { decodeZwArchive, encodeZwArchive, ZW_FILE_EXTENSION } from '@/lib/zwArchive' import { decodeZwArchive, encodeZwArchive, ZW_FILE_EXTENSION } from '@/lib/zwArchive'
import { PROJECT_TAB_ID, QUICK_TAB_ID, readWorkspaceMode } from '@/lib/workspace' import { PROJECT_TAB_ID, QUICK_TAB_ID, readWorkspaceMode } from '@/lib/workspace'
@ -470,6 +475,37 @@ const tabTitleOverflowMap = ref<Record<string, boolean>>({})
let tabStripViewportEl: HTMLElement | null = null let tabStripViewportEl: HTMLElement | null = null
let tabTitleOverflowRafId: number | null = null let tabTitleOverflowRafId: number | null = null
const reportExportToastOpen = ref(false)
const reportExportProgress = ref(0)
const reportExportStatus = ref<'running' | 'success' | 'error'>('running')
const reportExportText = ref('')
let reportExportToastTimer: ReturnType<typeof setTimeout> | null = null
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 tabsModel = computed({ const tabsModel = computed({
get: () => tabStore.tabs, get: () => tabStore.tabs,
set: (value) => { set: (value) => {
@ -1575,11 +1611,15 @@ const exportReport = async () => {
const now = new Date() const now = new Date()
const payload = await buildExportReportPayload() const payload = await buildExportReportPayload()
const fileName = `${sanitizeFileNamePart(payload.name)}-报表-${formatExportTimestamp(now)}` const fileName = `${sanitizeFileNamePart(payload.name)}-报表-${formatExportTimestamp(now)}`
console.log(payload) await exportFile(fileName, payload, () => {
await exportFile(fileName, payload) showReportExportProgress(30, '正在生成报表文件...')
})
finishReportExportProgress(true, '报表导出完成')
} catch (error) { } catch (error) {
console.error('export report failed:', error) console.error('export report failed:', error)
// window.alert('') if (reportExportToastOpen.value) {
finishReportExportProgress(false, '报表导出失败,请重试')
}
} finally { } finally {
dataMenuOpen.value = false dataMenuOpen.value = false
} }
@ -1760,6 +1800,7 @@ watch(
</script> </script>
<template> <template>
<ToastProvider>
<TooltipProvider> <TooltipProvider>
<div class="flex flex-col w-full h-screen bg-background overflow-hidden"> <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"> <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">
@ -1967,7 +2008,31 @@ watch(
</div> </div>
</div> </div>
</div> </div>
<ToastRoot
v-model: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 flex items-center gap-2">
<div class="h-1.5 flex-1 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>
<span class="shrink-0 text-[11px] tabular-nums text-muted-foreground">{{ reportExportProgress }}%</span>
</div>
</ToastRoot>
<ToastViewport class="fixed bottom-5 right-5 z-[85] flex w-[380px] max-w-[92vw] flex-col gap-2 outline-none" />
</TooltipProvider> </TooltipProvider>
</ToastProvider>
</template> </template>
<style scoped> <style scoped>

View File

@ -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): Promise<void> { export async function exportFile(fileName: string, data: any, onSaveConfirmed?: () => void): Promise<void> {
if (window.showSaveFilePicker) { if (window.showSaveFilePicker) {
const handle = await window.showSaveFilePicker({ const handle = await window.showSaveFilePicker({
suggestedName: fileName, suggestedName: fileName,
@ -697,10 +697,9 @@ export async function exportFile(fileName: string, data: any): Promise<void> {
accept: { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [".xlsx"] } accept: { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": [".xlsx"] }
}] }]
}); });
// ecCom.WeaLoadingGlobal.start({
// tip: "下载中,结束前请勿打开文件...",
// });
try { try {
onSaveConfirmed?.()
const workbook = await generateTemplate(data); const workbook = await generateTemplate(data);
const buffer = await workbook.xlsx.writeBuffer(); const buffer = await workbook.xlsx.writeBuffer();
const writable = await handle.createWritable(); const writable = await handle.createWritable();