Files
xh-medical-sign-web/clinical-web/src/views/management/documents/components/DocumentHistoryDialog.vue
T

311 lines
6.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed } from 'vue'
import { readLibraryStatus } from '../library'
import type { DocumentHistoryRow, DocumentTemplate } from '../types'
const props = defineProps<{
visible: boolean
template: DocumentTemplate | null
rows: DocumentHistoryRow[]
loading: boolean
error: boolean
/** 演示文库只保存当前版本,弹窗要如实说明,别让科室以为这就是全部历史 */
isMock: boolean
}>()
const emit = defineEmits<{
close: []
/** 查看某个历史版本的正文(只读) */
'view-version': [versionId: string]
}>()
const sub = computed(() => {
if (!props.template) {
return ''
}
const status = readLibraryStatus(props.template)
return `${props.template.name} · ${props.template.code || '未编号'} · 当前 ${props.template.version}(${status})`
})
</script>
<template>
<Teleport to="body">
<div v-if="visible && template" class="dialog-mask" @click.self="emit('close')">
<section
class="dialog-card history-dialog"
role="dialog"
aria-modal="true"
aria-labelledby="history-dialog-title"
>
<header class="dialog-header">
<div class="dialog-heading">
<strong id="history-dialog-title">📄 文档历史记录</strong>
<span>{{ sub }}</span>
</div>
<button type="button" class="dialog-close" aria-label="关闭" @click="emit('close')">
×
</button>
</header>
<div class="dialog-body">
<p v-if="loading" class="history-state">正在加载历史记录…</p>
<p v-else-if="error" class="history-state history-state--error">
历史记录加载失败,请确认后端模板版本接口可访问后重试。
</p>
<template v-else-if="rows.length">
<div class="table-scroll">
<table class="history-table">
<thead>
<tr>
<th class="col-version">版本</th>
<th class="col-operator">操作人</th>
<th class="col-time">时间</th>
<th>操作</th>
<th>说明</th>
<th class="col-action">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="row in rows" :key="row.id">
<td><b>{{ row.version }}</b></td>
<td>{{ row.operator }}</td>
<td>{{ row.operatedAt || '—' }}</td>
<td>{{ row.action }}</td>
<td class="cell-note">{{ row.note }}</td>
<td>
<span v-if="row.isCurrent" class="current-badge">当前</span>
<button
v-else
type="button"
class="row-button"
title="只读查看该版本的正文"
@click="emit('view-version', row.id)"
>
查看
</button>
</td>
</tr>
</tbody>
</table>
</div>
<p v-if="isMock" class="history-hint">
演示文库只保留当前版本,因此这里只有一条。真实模式下会列出该文书的全部历史版本。
</p>
</template>
<p v-else class="history-state">该文书还没有版本记录。</p>
</div>
<footer class="dialog-footer">
<span>
每次保存 / 发布自动生成一条版本记录(版本号 · 操作人 · 时间 · 说明),全程可追溯、不可删除;
已发布版本按任务固化,历史任务仍按当时版本渲染。
</span>
<button type="button" class="action-button" @click="emit('close')">关闭</button>
</footer>
</section>
</div>
</Teleport>
</template>
<style scoped>
.dialog-mask {
position: fixed;
z-index: 20;
inset: 0;
display: flex;
padding: 16px;
overflow-y: auto;
background: rgb(9 40 52 / 45%);
}
.dialog-card {
display: flex;
width: 760px;
max-width: 96vw;
max-height: calc(100vh - 32px);
flex-direction: column;
margin: auto;
background: #fff;
border-radius: 14px;
box-shadow: var(--sh-modal);
}
.dialog-header {
display: flex;
gap: 10px;
align-items: flex-start;
padding: 12px 18px;
border-bottom: 1px solid var(--line);
}
.dialog-heading {
display: flex;
min-width: 0;
flex-direction: column;
gap: 3px;
}
.dialog-heading strong {
color: var(--ink);
font-size: 15px;
}
.dialog-heading span {
overflow: hidden;
color: var(--mut);
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.dialog-close {
flex-shrink: 0;
padding: 0;
margin-left: auto;
color: var(--mut);
font-size: 20px;
line-height: 1;
background: transparent;
}
.dialog-close:hover {
color: var(--ink);
}
.dialog-body {
flex: 1;
padding: 14px 18px;
overflow-y: auto;
}
.table-scroll {
overflow-x: auto;
}
.history-table {
width: 100%;
border-collapse: collapse;
font-size: 12.5px;
}
.history-table th,
.history-table td {
padding: 8px 10px;
text-align: left;
border-bottom: 1px solid var(--line);
}
.history-table th {
color: var(--mut);
font-size: 11.5px;
font-weight: 700;
white-space: nowrap;
background: #f8fbfc;
}
.history-table td {
color: var(--ink);
vertical-align: top;
}
.cell-note {
color: var(--mut);
}
.col-version {
width: 90px;
}
.col-operator {
width: 170px;
}
.col-time {
width: 140px;
}
.col-action {
width: 80px;
}
.current-badge {
padding: 2px 8px;
color: var(--ok);
font-size: 11px;
font-weight: 700;
white-space: nowrap;
background: var(--ok-l);
border-radius: 10px;
}
.row-button {
padding: 3px 10px;
color: var(--brand);
font-size: 11.5px;
background: #fff;
border: 1px solid var(--brand);
border-radius: 5px;
}
.row-button:hover {
background: var(--brand-l);
}
.history-state {
padding: 28px 0;
margin: 0;
color: var(--mut);
font-size: 13px;
text-align: center;
}
.history-state--error {
color: var(--err);
}
.history-hint {
margin: 12px 0 0;
color: var(--mut);
font-size: 11.5px;
line-height: 1.7;
}
.dialog-footer {
display: flex;
gap: 10px;
align-items: center;
padding: 10px 18px;
color: var(--mut);
font-size: 11.5px;
background: #f8fbfc;
border-top: 1px solid var(--line);
border-radius: 0 0 14px 14px;
}
.dialog-footer span {
flex: 1;
line-height: 1.7;
}
.action-button {
flex-shrink: 0;
padding: 8px 16px;
color: #fff;
font-size: 13px;
font-weight: 700;
background: var(--brand);
border-radius: 7px;
}
.action-button:hover {
background: var(--brand-d);
}
</style>