<script setup lang="ts">
|
import { ref, watch } from 'vue'
|
import { useRouter } from 'vue-router'
|
import { ElMessage } from 'element-plus'
|
import { exportCompareVersions, listCompareVersions, type CompareVersionSummary } from '@/api/compareReports'
|
|
const props = defineProps<{ reportId: number | null; canExport: boolean }>()
|
const visible = defineModel<boolean>({ default: false })
|
const router = useRouter()
|
const versions = ref<CompareVersionSummary[]>([])
|
const loading = ref(false)
|
const error = ref('')
|
const exporting = ref(false)
|
|
// 切换报表或关闭弹窗后,旧请求不能覆盖下次打开的历史列表。
|
watch(() => [visible.value, props.reportId] as const, async ([open, id], _old, onCleanup) => {
|
let cancelled = false
|
onCleanup(() => { cancelled = true })
|
versions.value = []
|
error.value = ''
|
if (!open || !id) return
|
loading.value = true
|
try {
|
const result = await listCompareVersions(id)
|
if (!cancelled) versions.value = result
|
} catch (cause) {
|
if (!cancelled) error.value = cause instanceof Error ? cause.message : '历史版本加载失败'
|
} finally { if (!cancelled) loading.value = false }
|
})
|
|
function viewVersion(versionNo: number) {
|
visible.value = false
|
router.push({ path: `/report-compare/${props.reportId}/edit`, query: { mode: 'view', version: versionNo } })
|
}
|
|
async function exportRevisions() {
|
if (!props.reportId || exporting.value) return
|
const id = props.reportId
|
exporting.value = true
|
try {
|
const history = await exportCompareVersions(id)
|
// 文本单元格避免被表格软件解释为公式,CSV 只表达版本修订事实。
|
const cell = (value: string) => `"${(/^[=+@\-\t\r\n]/.test(value) ? `'${value}` : value).replace(/"/g, '""')}"`
|
const rows = history.map(version => [String(version.versionNo), version.operatorName,
|
new Date(version.createdAt).toLocaleString(), version.changeSummary].map(cell).join(','))
|
const url = URL.createObjectURL(new Blob(['\uFEFF版本号,操作人,时间,修改说明\r\n', rows.join('\r\n')], { type: 'text/csv;charset=utf-8' }))
|
const anchor = document.createElement('a')
|
anchor.href = url
|
anchor.download = `对比报表-${id}-修订记录.csv`
|
anchor.click()
|
window.setTimeout(() => URL.revokeObjectURL(url), 1000)
|
} catch (cause) { ElMessage.error(cause instanceof Error ? cause.message : '修订记录导出失败') }
|
finally { exporting.value = false }
|
}
|
</script>
|
|
<template>
|
<el-dialog v-model="visible" title="历史版本" width="820px" align-center class="compare-history-dialog">
|
<el-alert v-if="error" :title="error" type="error" :closable="false" show-icon />
|
<el-table :data="versions" v-loading="loading" empty-text="暂无历史版本" max-height="460">
|
<el-table-column prop="versionNo" label="版本号" width="80"><template #default="{ row }">V{{ row.versionNo }}</template></el-table-column>
|
<el-table-column prop="operatorName" label="操作人" min-width="100" />
|
<el-table-column label="时间" width="180"><template #default="{ row }">{{ new Date(row.createdAt).toLocaleString() }}</template></el-table-column>
|
<el-table-column prop="changeSummary" label="修改说明" min-width="210" />
|
<el-table-column label="操作" width="88" fixed="right"><template #default="{ row }"><el-button link type="primary" @click="viewVersion(row.versionNo)">查看版本</el-button></template></el-table-column>
|
</el-table>
|
<template #footer><el-button v-if="canExport" :loading="exporting" :disabled="loading || !!error" @click="exportRevisions"><el-icon><Download /></el-icon>导出修订 CSV</el-button></template>
|
</el-dialog>
|
</template>
|
|
<style>
|
.compare-history-dialog { max-width: calc(100vw - 28px); border-radius: 4px; }
|
.compare-history-dialog .cell { overflow-wrap: anywhere; }
|
</style>
|