yeg
4 天以前 f4d7007b89cf565746af4623623a294b82666ff1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<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>