refactor(documents): 文档库改用本地真实文书内容

This commit is contained in:
yelan
2026-09-08 14:16:00 +08:00
parent f45864e817
commit 7bea008680
6 changed files with 577 additions and 523 deletions
@@ -98,11 +98,7 @@ const statusLabel = computed(() => {
<footer class="dialog-footer">
<p>
{{
template.contentHtml
? '模板内容来自服务端,预览区域已限制脚本执行。'
: '占位符由系统在签署时自动填充,当前仅用于原型演示。'
}}
文书版式取自科室真实知情同意书原件,{占位符}与勾选项在发起签署时由系统自动填充。
</p>
<button type="button" class="footer-button secondary" @click="emit('close')">关闭</button>
<button
@@ -2,9 +2,8 @@
import { computed, reactive, watch } from 'vue'
import type { CampusRecord, DepartmentRecord } from '@/api/management/types'
import type { TemplateVersionAction } from '@/api/management/documents'
import type { DocumentTemplate, TemplateEditorForm } from '../types'
import type { DocumentTemplate, TemplateEditorForm, TemplateVersionAction } from '../types'
const props = defineProps<{
visible: boolean
@@ -0,0 +1,467 @@
// 文档库真实文书内容:按 2025 年在各科室采集的知情同意书原件 1:1 重建。
// {占位符}在发起签署时由系统按患者与就诊信息自动填充;勾选表格由签署端渲染为签署域。
interface GeneProjectItem {
name: string
price: string
chargeType: string
thirdParty: string
}
interface GeneConsentConfig {
title: string
intro: string[]
risks: string[]
acknowledgements: string[]
tableHeader: string
projects: GeneProjectItem[]
conclusion: string
}
const PAGE_STYLE = `
body {
margin: 0;
padding: 26px 32px 40px;
color: #1c2b33;
font-family: 'SimSun', 'Songti SC', 'STSong', serif;
font-size: 13.5px;
line-height: 1.95;
background: #fff;
}
h1 {
margin: 4px 0 14px;
font-size: 18px;
letter-spacing: 2px;
text-align: center;
}
.org-name {
margin: 0 0 2px;
font-size: 14.5px;
font-weight: 700;
text-align: center;
letter-spacing: 1px;
}
.patient-header {
margin: 0 0 4px;
font-size: 13px;
}
.header-note {
margin: 0 0 12px;
color: #6b7c85;
font-size: 12px;
}
.notice-box {
margin: 10px 0 14px;
padding: 8px 14px;
border: 1.5px solid #1c2b33;
font-weight: 700;
text-align: center;
}
.section-title {
margin: 16px 0 6px;
font-size: 14px;
font-weight: 700;
text-align: center;
}
.sub-title {
margin: 14px 0 4px;
font-size: 13.5px;
font-weight: 700;
}
p {
margin: 0 0 6px;
text-align: justify;
}
ol {
margin: 4px 0 10px;
padding-left: 26px;
}
li {
margin-bottom: 3px;
text-align: justify;
}
.em {
font-weight: 700;
}
.underline {
text-decoration: underline;
}
table {
width: 100%;
margin: 8px 0 14px;
border-collapse: collapse;
font-size: 12.5px;
line-height: 1.6;
}
th,
td {
padding: 5px 7px;
border: 1px solid #52646e;
text-align: center;
vertical-align: middle;
}
th {
font-weight: 700;
background: #f2f6f8;
}
td.item-name {
text-align: left;
}
.page-break {
margin: 26px 0;
border-top: 1.5px dashed #90a4ae;
}
.page-break-label {
margin: -14px 0 14px;
color: #6b7c85;
font-size: 11.5px;
text-align: center;
}
.signature-block {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px 32px;
margin-top: 18px;
padding-top: 10px;
}
.signature-block span {
border-bottom: 1px solid #1c2b33;
min-height: 22px;
display: inline-block;
min-width: 140px;
padding: 0 8px;
}
.signature-line {
white-space: nowrap;
}
.contact {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 6px;
margin-top: 18px;
font-size: 12.5px;
}
`
function wrapDocument(bodyHtml: string): string {
return `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8" /><style>${PAGE_STYLE}</style></head><body>${bodyHtml}</body></html>`
}
function patientHeader(visitNoLabel = '住院号/门诊号'): string {
return `
<p class="patient-header">患者姓名:<span>{患者姓名}</span>&#12288;性别:<span>{性别}</span>&#12288;年龄:<span>{年龄}</span>&#12288;${visitNoLabel}:<span>{就诊号}</span></p>
<p class="header-note">住院患者基本信息由电子病历系统以页眉形式自动带入,签署时自动填充。</p>
`
}
function buildProjectTable(headerCells: string[], projects: GeneProjectItem[]): string {
const rows = projects
.map(
(item, index) =>
`<tr><td>☐</td><td>${index + 1}</td><td class="item-name">${item.name}</td><td>${item.price}</td><td>${item.chargeType}</td><td>${item.thirdParty}</td></tr>`,
)
.join('')
return `<table><thead><tr><th style="width:44px">勾选</th><th>序号</th>${headerCells
.map((cell) => `<th>${cell}</th>`)
.join('')}</tr></thead><tbody>${rows}</tbody></table>`
}
function buildSelfPaidGeneConsent(config: GeneConsentConfig): string {
return wrapDocument(`
${patientHeader()}
<h1>${config.title}</h1>
${config.intro.map((paragraph) => `<p>${paragraph}</p>`).join('')}
<p class="sub-title">【局限性与潜在风险】</p>
<ol>${config.risks.map((risk) => `<li>${risk}</li>`).join('')}</ol>
<p class="sub-title">【受检者知情】</p>
<ol>${config.acknowledgements.map((item) => `<li>${item}</li>`).join('')}</ol>
<p>${config.tableHeader}</p>
${buildProjectTable(['检测项目', '金额(元/例)', '收费类别', '是否第三方合作'], config.projects)}
<p>${config.conclusion}</p>
<div class="signature-block">
<div class="signature-line">患者(或委托人/监护人)意见:<span></span></div>
<div class="signature-line">医师签名:<span></span></div>
<div class="signature-line">患者(或委托人/监护人)签字:<span>{患者签名}</span></div>
<div class="signature-line">日期:<span>{签署日期}</span></div>
<div class="signature-line">委托人/监护人与患者关系:<span>{与患者关系}</span></div>
</div>
`)
}
const infectionGeneConsent = buildSelfPaidGeneConsent({
title: '感染基因高通量测序自费项目知情同意书',
intro: [
'感染基因高通量测序是不依赖病原传统分离、无需预设可疑病原体,直接提取临床样本中全部微生物+宿主游离核酸,通过高通量二代测序批量读取所有核酸序列,和已知微生物参考数据库比对,一次性识别样本内细菌、真菌、病毒、寄生虫、人体微生态菌群等广谱病原检测技术,同时可以附带耐药基因、耐药突变位点、毒力基因分析。',
'检测结果有助于医生快速制定调整的治疗方案,缩短确诊时间,降低重症感染病死率,减少广谱抗菌药物使用,助力抗菌药物管控,填补传统检测难培养、未知病原的诊断空白。',
],
risks: [
'本次检测仅对该次送检样本负责,检测结果需结合具体的临床症状以及患者的个体情况,由临床医生提供临床处理及治疗方案。',
'受检样本报告时间为收到检测样本后 1-2 个工作日发报告。如遇检测失败需要进行重复实验可能导致报告周期延迟。奉贤院区因物流原因报告可能会延迟 12-24 小时。',
'受检者样本如没有严格按照送检要求提供,会对检测结果有不良影响;若分析结果提示质控不合格或怀疑标本污染等情况,需要配合重新采样复测。',
'受检样本的病原核酸检测结果受多重因素影响,阴性不能完全排除感染,仅仅作为排除线索,需要结合培养、影像、炎症指标综合判断。阳性无法明确区分污染、定植、感染,中枢、关节、胸腹水等无菌体液参考价值更大。耐药基因检测不能替代药物敏感性试验。',
'本检测所涉及个人身份有关的信息,将在法律规定的范围内确保保密性,本单位承诺不会透露任何与受检者身份相关的资料给第三方。',
],
acknowledgements: [
'我已经充分理解该知情同意书所列局限性与潜在风险。',
'我自愿本次基因检测,并承诺送检申请单提供的个人资料真实可靠。',
'我充分理解感染基因检测受送检样本的条件限制所造成的结果局限性。',
'我同意对我个人信息及资料的保护;并且同意在去掉所有个人信息后,检测数据可供医学研究,授权医院对检测涉及的样本进行处理。',
'该检测项目尚未纳入上海市医保目录,属于自费项目。',
],
tableHeader: '因疾病诊疗所需,我们拟为您检测以下感染基因自费检测项目(选项):',
projects: [
{ name: '病原微生物宏基因组检测', price: '3040', chargeType: '自费', thirdParty: '否' },
{ name: '多种病原微生物核酸测序', price: '1500', chargeType: '自费', thirdParty: '否' },
{ name: '消化道多种病原检测', price: '620', chargeType: '自费', thirdParty: '否' },
],
conclusion: '本人知晓上述所有内容,愿意进行感染基因检测(高通量测序法)。',
})
const tumorGeneConsent = buildSelfPaidGeneConsent({
title: '肿瘤基因高通量测序自费项目知情同意书',
intro: [
'肿瘤基因高通量测序采用二代测序技术对肿瘤基因的变异进行分子检测(肿瘤基因的变异包括突变/融合/重排/扩增)。通过采集受检者蜡块/组织切片/胸水/血液/DNA 等样本,针对采集到的样本对提取的 DNA 或 RNA 等遗传物质进行高通量测序,通过生物信息学分析受检者的测序数据,得出肿瘤基因的变异情况及异常频率。',
'检测结果有助于医生制定相应的治疗方案,从而实现肿瘤个体化治疗,更精准地为患者提供不同用药方案的分子检测依据,可能会有效提高临床的治疗效果,并可能使受检者拥有较好的生活质量。',
],
risks: [
'本检测仅对该次送检样本负责,检测结果需结合具体的临床症状以及患者的个体情况由临床医生提供临床处理及治疗方案。',
'受检样本报告时间为收到检测样本后 10 个工作日发报告。如遇检测失败需要进行重复实验可能导致报告周期延迟。',
'受检者样本如没有严格按照送检要求提供,会对检测结果有不良影响。',
'受检样本的 DNA/RNA 序列分析是为了说明检测基因的变异情况,如未检出特定基因的基因变异情况(即阴性结果)并不能排除其他未知基因或没检测的基因的关系。',
'本检测方法不适于检测染色体数目及结构异常及其他特殊类型基因突变等变异类型。',
'本检测所涉及个人身份有关的信息,将在法律规定的范围内确保保密性,本单位承诺不会透露任何与受检者身份相关的资料给第三方。',
],
acknowledgements: [
'我已经充分理解该知情同意书所列局限性与潜在风险。',
'我自愿本次基因检测,并承诺送检申请单提供的个人资料真实可靠。',
'我充分理解肿瘤基因检测受送检样本的条件限制所造成的结果局限性。',
'我同意对我个人信息及资料的保护;并且同意在去掉所有个人信息后,检测数据可供医学研究,授权医院对检测涉及的样本进行处理。',
'该检测项目尚未纳入上海市医保目录,属于自费项目。',
],
tableHeader: '因疾病诊疗所需,我们拟为您检测以下肿瘤基因检测项目(选项):',
projects: [
{ name: 'BRCA1/2', price: '3250', chargeType: '自费', thirdParty: '否' },
{ name: 'NGS(小 panel)', price: '5950', chargeType: '自费', thirdParty: '否' },
{ name: 'NGS(中 panel)', price: '7300', chargeType: '自费', thirdParty: '否' },
{ name: 'NGS(大 panel)', price: '9900', chargeType: '自费', thirdParty: '否' },
],
conclusion: '本人知晓上述所有内容,愿意进行肿瘤基因检测(高通量测序法)。',
})
// 对外合作或自费基因检测项目知情同意书:60 项检测项目目录(原件 2025.6.24 版)。
const cooperativeProjects: GeneProjectItem[] = [
{ name: 'HCV 亚型扩增', price: '600', chargeType: '医保', thirdParty: '是' },
{ name: 'HBV 病毒基因测序', price: '600', chargeType: '医保', thirdParty: '是' },
{ name: '乳汁 CMV-DNA 扩增', price: '80', chargeType: '医保', thirdParty: '是' },
{ name: 'BRCA 基因突变检测', price: '1800', chargeType: '医保', thirdParty: '是' },
{ name: '金域多种呼吸道病原体核酸检测', price: '960', chargeType: '医保', thirdParty: '是' },
{ name: '乙肝病毒 HBV 耐药突变检测', price: '600', chargeType: '医保', thirdParty: '是' },
{ name: 'Xpert 结核分枝杆菌', price: '450', chargeType: '医保', thirdParty: '是' },
{ name: '白血病残留病灶 PML-RARa', price: '450', chargeType: '医保', thirdParty: '是' },
{ name: '全套白血病基因筛查组合', price: '450', chargeType: '医保', thirdParty: '是' },
{ name: '白血病残留病灶 TEL-AML1', price: '450', chargeType: '医保', thirdParty: '是' },
{ name: '白血病残留病灶 BCR-ABL 190', price: '450', chargeType: '医保', thirdParty: '是' },
{ name: '白血病残留病灶 BCR-ABL 210', price: '450', chargeType: '医保', thirdParty: '是' },
{ name: '脆性 X 综合征基因片段', price: '550', chargeType: '医保', thirdParty: '是' },
{ name: 'JAK2/V617F', price: '450', chargeType: '医保', thirdParty: '是' },
{ name: 'WT1', price: '600', chargeType: '医保', thirdParty: '是' },
{ name: 'FLT3-ITD', price: '600', chargeType: '医保', thirdParty: '是' },
{ name: 'FIP1L1-PDGFRA', price: '450', chargeType: '医保', thirdParty: '是' },
{ name: 'NPM1', price: '600', chargeType: '医保', thirdParty: '是' },
{ name: '地中海贫血基因检测', price: '800', chargeType: '医保', thirdParty: '是' },
{ name: '肿瘤 BRCA1/2 基因', price: '3600', chargeType: '自费', thirdParty: '是' },
{ name: '多种病原微生物核酸', price: '1500', chargeType: '自费', thirdParty: '是' },
{ name: '全外测序-外周血(检验)', price: '3000', chargeType: '自费', thirdParty: '是' },
{ name: '消化道多种病原体检测', price: '620', chargeType: '自费', thirdParty: '是' },
{ name: '肠道菌群多样性检测', price: '1200', chargeType: '自费', thirdParty: '是' },
{ name: '病原微生物宏基因组检测', price: '3040', chargeType: '自费', thirdParty: '是' },
{ name: '胚胎植入前染色体非整倍体检测(PGT-A)', price: '3600', chargeType: '自费', thirdParty: '是' },
{ name: '胚胎植入前染色体结构变异检测(PGT-SR)', price: '4200', chargeType: '自费', thirdParty: '是' },
{ name: 'PGTM-ChromSwift® 单基因病分子遗传检测(预实验)-样本', price: '4200', chargeType: '自费', thirdParty: '是' },
{ name: 'PGTM-ChromSwift® 单基因病分子遗传检测(胚胎检测)', price: '4200', chargeType: '自费', thirdParty: '是' },
{ name: '200+ 种单基因病无创产前检测', price: '3600', chargeType: '自费', thirdParty: '是' },
{ name: '全因 3.0-胎儿染色体异常和 200+ 种单基因病无创产前检测', price: '4800', chargeType: '自费', thirdParty: '是' },
{ name: '单基因遗传病扩展性携带者筛查 10 种', price: '1800', chargeType: '自费', thirdParty: '是' },
{ name: '单基因遗传病扩展性携带者筛查 155 种', price: '2400', chargeType: '自费', thirdParty: '是' },
{ name: '地中海贫血基因检测(α+β)508 Plus', price: '600', chargeType: '自费', thirdParty: '是' },
{ name: '临床全外显子组检测-家系(VIP)', price: '12000', chargeType: '自费', thirdParty: '是' },
{ name: '全基因组检测-家系(VIP)', price: '12600', chargeType: '自费', thirdParty: '是' },
{ name: '康孕-染色体检测-1M', price: '1800', chargeType: '自费', thirdParty: '是' },
{ name: '康孕-染色体检测-100K', price: '2400', chargeType: '自费', thirdParty: '是' },
{ name: 'PMseq-DNA Pro 高敏局灶感染病原微生物高通量基因检测', price: '3600', chargeType: '自费', thirdParty: '是' },
{ name: 'PMseq-RNA 局灶感染病原微生物高通量基因检测', price: '1800', chargeType: '自费', thirdParty: '是' },
{ name: 'PMseq-DR 局灶感染病原微生物高通量基因检测', price: '3600', chargeType: '自费', thirdParty: '是' },
{ name: '数字定量 PCR 监测-现成位点', price: '600', chargeType: '自费', thirdParty: '是' },
{ name: '泛实体肿瘤基因检测(DNA+RNA Panel)', price: '12600', chargeType: '自费', thirdParty: '是' },
{ name: '数字定量 PCR 监测-定制位点', price: '1200', chargeType: '自费', thirdParty: '是' },
{ name: '脑肿瘤分子分型(甲基化版)', price: '6600', chargeType: '自费', thirdParty: '是' },
{ name: '实体瘤全基因芯片检测', price: '6600', chargeType: '自费', thirdParty: '是' },
{ name: '实体肿瘤全转录测序分析', price: '6600', chargeType: '自费', thirdParty: '是' },
{ name: '无创产前 DNA 监测', price: '1250', chargeType: '自费', thirdParty: '是' },
{ name: 'NIPT-plus', price: '3600', chargeType: '自费', thirdParty: '是' },
{ name: '携带者筛查-紫管', price: '2400', chargeType: '自费', thirdParty: '是' },
{ name: '携带者筛查(夫妻双方)', price: '3600', chargeType: '自费', thirdParty: '是' },
{ name: '脆性 X 综合征基因片段分析', price: '550', chargeType: '自费', thirdParty: '是' },
{ name: '线粒体检测(线粒体环基因全长测序)', price: '2400', chargeType: '自费', thirdParty: '是' },
{ name: 'BRCA1/2 基因突变检测', price: '3600', chargeType: '自费', thirdParty: '是' },
{ name: '泛癌种 NGS 检测', price: '16000', chargeType: '自费', thirdParty: '是' },
{ name: '肠癌 NGS 检测', price: '6400', chargeType: '自费', thirdParty: '是' },
{ name: '肺癌 NGS 检测', price: '9600', chargeType: '自费', thirdParty: '是' },
{ name: '组织细胞荧光定量聚合酶链反应检诊断(肺癌多基因突变检测)', price: '6400', chargeType: '自费', thirdParty: '' },
{ name: '组织细胞荧光定量聚合酶链反应检诊断(ALK/ROS1 基因检测)', price: '3200', chargeType: '自费', thirdParty: '' },
{ name: '组织细胞荧光定量聚合酶链反应检诊断(KRAS/NRAS 基因突变检测)', price: '1400', chargeType: '自费', thirdParty: '' },
]
// 各项目执行科室(按原件顺序分段:1-25 检验科、26-29 生殖医学中心、30-41 宫内儿科疾病诊治中心、
// 42-53 临床遗传中心、54-60 病理科),同段执行科室在表格中纵向合并展示。
const cooperativeExecutorGroups = [
{ count: 25, name: '医学检验科' },
{ count: 4, name: '生殖医学中心' },
{ count: 12, name: '宫内儿科疾病诊治中心' },
{ count: 12, name: '临床遗传中心' },
{ count: 7, name: '病理科' },
]
function buildCooperativeConsent(): string {
let projectCursor = 0
const bodyRows = cooperativeProjects.map((item, index) => {
let executorCell = ''
const group = cooperativeExecutorGroups[0]
if (group) {
if (projectCursor === 0) {
executorCell = `<td rowSpan="${group.count}">${group.name}</td>`
}
projectCursor += 1
if (projectCursor >= group.count) {
cooperativeExecutorGroups.shift()
projectCursor = 0
}
}
return `<tr><td>☐</td><td>${index + 1}</td><td class="item-name">${item.name}</td><td>${item.price}</td><td>${item.chargeType}</td><td>${item.thirdParty}</td>${executorCell}</tr>`
})
return wrapDocument(`
${patientHeader('住院号')}
<h1>对外合作或自费基因检测项目知情同意书</h1>
<p>尊敬的{患者姓名}:因疾病诊疗所需,我们拟为您检测以下检验项目(选项):</p>
<table>
<thead>
<tr>
<th style="width:40px">勾选</th>
<th style="width:40px">序号</th>
<th>基因检测项目</th>
<th style="width:70px">收费金额(元/例)</th>
<th style="width:56px">收费类别</th>
<th style="width:64px">是否对外合作</th>
<th style="width:110px">执行科室</th>
</tr>
</thead>
<tbody>${bodyRows}</tbody>
</table>
<p>以上项目或由我院同第三方医学检验机构合作检测,或为自费检测项目。检测结果的准确性、及时性、保密性和可追溯性由本院向您负责,特此向您进行告知。</p>
<div class="signature-block">
<div class="signature-line">告知医师签名:<span></span></div>
<div class="signature-line">签名日期:<span>{签署日期}</span></div>
<div class="signature-line">患方签名:<span>{患者签名}</span></div>
<div class="signature-line">与患者关系:<span>{与患者关系}</span></div>
<div class="signature-line">签名日期:<span>{签署日期}</span></div>
<div class="signature-line">患方意见:<span>同意 / 不同意(请书写)</span></div>
</div>
`)
}
function buildMriConsent(): string {
return wrapDocument(`
<p class="org-name">上海交通大学医学院附属新华医院医学影像科</p>
<h1>MRI 检查预约单暨知情同意书(此单背面)</h1>
${patientHeader('MRI 号')}
<p class="notice-box">请预先填好知情同意书(此单背面)</p>
<p>定于{预约日期}&#12288;时&#12288;&#12288;请到 1. <span class="em underline">医技楼一楼 MRI 吧台登记</span></p>
<p style="text-indent:6.5em">2. <span class="em underline">医疗保健综合楼 B1 护士站登记</span></p>
<p style="text-indent:6.5em">3. <span class="em underline">儿科综合楼 3 楼窗口登记</span></p>
<p class="section-title">病人检查准备及注意事项</p>
<ol>
<li><span class="em">安装心脏起搏器、心脏瓣膜术后、早期妊娠及动脉夹闭术后的病人是不能进行 MRI 检查的</span>,如有上述任何情况必须及时说明;体内有其他金属植入物者,请说明是何种材料,只有 MRI 相容的安全性材料才能进行 MRI 检查。</li>
<li><span class="em">金属物品可能导致危及医务人员人身伤害、磁共振机器故障、金属制品本身损坏等,故</span><span class="em underline">严禁携带</span>如:钥匙、硬币、磁卡、手机、手表、助听器、活动假牙、发夹、金属带扣、眼镜、金银首饰(项链、耳环、手镯、手链、戒指等)、玉石挂件、玉镯子等各种含有金属的物件进入检查机房,若违犯此条例而产生不良后果,将严厉追究相关人员责任。由此产生的电子器件损坏,责任自负。</li>
<li><span class="em underline">纹身</span>在检查过程中可能导致局部皮肤严重灼伤,请有纹身患者及时告知。</li>
<li>检查当日请带磁卡,病人请勿携带贵重物品,请勿穿戴附有任何金属物质的衣物或饰品。</li>
<li>★ 年幼老龄以及需 <span class="em">MRI 增强的患者,须有家属陪同</span>。</li>
<li><span class="em underline">检查前请提前 15 分钟到场(包括门诊及住院病人)。凡预约后不能按时前来者,需提前一天到预约中心办理更改手续,另行预约检查时间。</span></li>
<li>MRI 检查用时较长,请根据预约登记的时间,依次排队等候检查,请耐心配合。</li>
<li><span class="em underline">检查完成后,请在隔二个工作日后(不含检查当日)至医技楼一楼 3 号窗口或自助机取正式报告;周末及节假日休息,取报告时间顺延。</span></li>
</ol>
<p class="notice-box">请按时领取报告,逾期未取者,相关责任/后果将自行承担。</p>
<p class="section-title">婴幼儿患者检查特殊要求</p>
<ol>
<li><span class="em underline">婴幼儿 MRI 检查请于检查当日根据预约时间提前 15 分钟办理登记。</span></li>
<li><span class="em underline">患儿检查前一晚 22:00 以后睡觉,检查当天早晨 6:00 前起床。(检查前不可再让患儿睡觉,因为如果睡眠太充分会影响镇静剂效果!!!)</span></li>
<li><span class="em">患儿登记检查前请禁食、禁水 4 小时</span>,检查当日请携带小毛毯(检查机房内为患儿保暖用)。</li>
<li><span class="em">患儿家属请事先配好镇静剂,并在检查当天带来,交予磁共振成像(MRI)吧台。</span></li>
<li>MRI 检查时间较长,一般需要 10~20 分钟左右,若患儿不合作或者未熟睡则会影响到图像质量。<span class="em">所以要保证患儿熟睡状态才能进入机房进行检查。</span></li>
<li>患儿检查时,身上不能穿带有金属扣的衣物,<span class="em">并且需要一名家属在旁陪护</span>,以防患儿惊醒摔倒。陪护家属也须取走身上的金属物件如钥匙、硬币、磁卡、手机、手表以及发夹等。</li>
<li><span class="em">患儿家属若曾接受心脏起搏器、脑部动脉瘤夹、心脏人工瓣膜、人工电子耳等手术,眼眶内有金属异物,或体内有其金属含铁磁性物质装置装置,</span><span class="em underline">严禁进入磁共振扫描室</span>。</li>
<li><span class="em underline">如患儿有感冒、咳嗽、发热症状,不能使用镇静剂</span>,请提前到预约中心办理更改手续,另行预约检查时间。</li>
</ol>
<div class="contact">
<span>电话:19 号楼 2507 7049 / 28 号楼 2507 7065</span>
<span>预约中心电话:2507 6213 / 2507 6217</span>
<span>新华医院放射科 地址:控江路 1665 号医技楼一楼(电话:2507 7053〔5 号楼〕)</span>
</div>
<div class="page-break"></div>
<p class="page-break-label">以 下 为 单 张 背 面 内 容</p>
<h1>磁共振成像(MRI)检查知情同意书</h1>
<ol>
<li>MRI 为非侵袭性、无辐射损害的检查,所使用的对比剂安全性很高,是目前较先进的优质的影像检查技术。</li>
<li>MRI 增强用对比剂是一种顺磁性对比剂,不良反应极少。个别患者有过敏、喉头水肿、休克等反应,如有严重肾损害、哮喘等及其它过敏史的患者请检查前及时告知检查技师。</li>
<li>如有以下情形,请告知医护人员,再确定是否可以做磁共振成像检查:<span class="em underline">曾接受心脏起搏器、脑部动脉瘤夹、心脏人工瓣膜、人工电子耳等手术,眼眶内有金属异物,或体内有其他含铁磁性物质的装置</span>。</li>
<li>为使检查安全正确,请于检查之前,如实填写以下表格。</li>
</ol>
<table>
<tbody>
<tr>
<td style="width:88px">姓名</td><td>{患者姓名}</td>
<td style="width:56px">性别</td><td>{性别}</td>
<td style="width:56px">年龄</td><td>{年龄}</td>
<td style="width:70px">体重(Kg)</td><td></td>
</tr>
<tr><td>手机号</td><td>{联系电话}</td><td>预约日期</td><td colSpan="5">{预约日期}</td></tr>
</tbody>
</table>
<table>
<thead>
<tr><th>您是否曾接受下列手术:</th><th>您是否有下列情况:</th></tr>
</thead>
<tbody>
<tr><td class="item-name">1. 安装人工心脏起搏器&#12288;&#12288;☐ 否&#12288;☐ 是</td><td class="item-name">1. 有任何药物过敏记录&#12288;&#12288;☐ 否&#12288;☐ 是</td></tr>
<tr><td class="item-name">2. 安装人工心脏瓣膜&#12288;&#12288;&#12288;☐ 否&#12288;☐ 是</td><td class="item-name">2. 是否有铁屑溅入眼球&#12288;&#12288;☐ 否&#12288;☐ 是</td></tr>
<tr><td class="item-name">3. 植入金属节育器&#12288;&#12288;&#12288;&#12288;☐ 否&#12288;☐ 是</td><td class="item-name">3. 活动性假牙或金属牙套&#12288;☐ 否&#12288;☐ 是</td></tr>
<tr><td class="item-name">4. 化疗泵/胰岛素泵&#12288;&#12288;&#12288; ☐ 否&#12288;☐ 是</td><td class="item-name">4. 肾功能不全或慢性肾病&#12288;☐ 否&#12288;☐ 是</td></tr>
<tr><td class="item-name">5. 脑内动脉瘤手术&#12288;&#12288;&#12288;&#12288;☐ 否&#12288;☐ 是</td><td class="item-name">您是否有下列情况(女性):</td></tr>
<tr><td class="item-name">6. 体内血管夹/内支架&#12288;&#12288; ☐ 否&#12288;☐ 是</td><td class="item-name">1. 怀孕&#12288;&#12288;☐ 否&#12288;☐ 是-孕周:</td></tr>
<tr><td class="item-name">7. 胃肠镜后不锈钢夹植入史 ☐ 否&#12288;☐ 是</td><td class="item-name">2. 末次月经时间:<br />一个月经期时间:</td></tr>
<tr><td class="item-name">8. 电子耳蜗/助听器&#12288;&#12288;&#12288; ☐ 否&#12288;☐ 是</td><td class="item-name">本人完全理解检查方案和风险,愿意承担各项风险带来的后果,并配合医护人员共同完成检查。</td></tr>
<tr><td class="item-name">9. 体内装置金属内固定器&#12288; ☐ 否&#12288;☐ 是</td><td class="item-name">☐ 是&#12288;&#12288;☐ 否</td></tr>
<tr><td class="item-name">10. 人工关节及假体&#12288;&#12288;&#12288;&#12288;☐ 否&#12288;☐ 是</td><td class="item-name">请患者(或家属)签名:<span>{患者签名}</span></td></tr>
<tr><td class="item-name">11. 纹身&#12288;&#12288;&#12288;&#12288;&#12288;&#12288;&#12288;&#12288;&#12288;☐ 否&#12288;☐ 是</td><td class="item-name">日期:<span>{签署日期}</span></td></tr>
<tr><td class="item-name">12. 其他特殊说明:</td><td></td></tr>
</tbody>
</table>
`)
}
export const documentContentHtml: Record<string, string> = {
'doc-img-mri-001': buildMriConsent(),
'doc-lab-infection-gene-001': infectionGeneConsent,
'doc-lab-coop-gene-001': buildCooperativeConsent(),
'doc-gen-onco-gene-001': tumorGeneConsent,
}
@@ -2,20 +2,9 @@
import { computed, onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { getCampuses, getDepartments } from '@/api/management/organization'
import {
createTemplate,
createTemplateVersion,
getDocumentDetail,
getDocuments,
getTemplateVersionDetail,
isDocumentMockEnabled,
updateTemplateVersionStatus,
} from '@/api/management/documents'
import type { TemplateVersionAction } from '@/api/management/documents'
import type { CampusRecord, DepartmentRecord, DocumentRecord } from '@/api/management/types'
import NewSigningTaskDialog from '@/components/signing/NewSigningTaskDialog.vue'
import type { SigningTemplate } from '@/api/workbench/types'
import type { CampusRecord, DepartmentRecord } from '@/api/management/types'
import DocumentFilterTabs from './components/DocumentFilterTabs.vue'
import DocumentLibraryHeader from './components/DocumentLibraryHeader.vue'
@@ -23,6 +12,7 @@ import DocumentPreviewDialog from './components/DocumentPreviewDialog.vue'
import DocumentTemplateCard from './components/DocumentTemplateCard.vue'
import TemplateEditorDialog from './components/TemplateEditorDialog.vue'
import { documentLibrary, documentStatusOptions } from './mock'
import type { TemplateVersionAction } from './types'
import type {
DepartmentTab,
DocumentStatus,
@@ -33,41 +23,33 @@ import type {
TemplateEditorForm,
} from './types'
const loading = ref(true)
// 原型阶段:文档库数据与文书内容全部来自本地真实附件(mock.ts + contents.ts),暂不调用后端接口。
// 后续接入时,仅需将 loadLibrary / saveTemplate / handleWorkflow 中的本地数据操作替换为文档模板接口。
const library = ref<DocumentDepartment[]>([])
const selectedTemplate = ref<DocumentTemplate | null>(null)
const signingTemplate = ref<SigningTemplate | null>(null)
const editorTemplate = ref<DocumentTemplate | null>(null)
const campuses = ref<CampusRecord[]>([])
const departments = ref<DepartmentRecord[]>([])
const signingDialogVisible = ref(false)
const editorVisible = ref(false)
const editorSaving = ref(false)
const workflowSaving = ref(false)
const previewLoading = ref(false)
const previewError = ref(false)
let previewRequestId = 0
const mockCampuses: CampusRecord[] = [
{ id: 'mock-main', code: 'MAIN', name: '本部院区', status: 'ENABLED', sortNo: 1 },
{ id: 'mock-east', code: 'EAST', name: '东院区', status: 'ENABLED', sortNo: 2 },
{ id: 'mock-west', code: 'WEST', name: '西院区', status: 'ENABLED', sortNo: 3 },
const campuses: CampusRecord[] = [
{ id: 'campus-main', code: 'MAIN', name: '本部院区', status: 'ENABLED', sortNo: 1 },
{ id: 'campus-fengxian', code: 'FENGXIAN', name: '奉贤院区', status: 'ENABLED', sortNo: 2 },
]
const mockDepartments: DepartmentRecord[] = [
'放射科',
'心内科',
'骨科',
'健康管理中心',
'全院通用',
].map((name, index) => ({
id: `mock-template-department-${index + 1}`,
campusId: index === 3 ? 'mock-east' : 'mock-main',
code: `MOCK-TPL-${index + 1}`,
name,
status: 'ENABLED',
sortNo: index + 1,
}))
const departments: DepartmentRecord[] = ['医学影像科', '医学检验科', '临床遗传中心'].map(
(name, index) => ({
id: `template-department-${index + 1}`,
campusId: 'campus-main',
code: `TPL-DEPT-${index + 1}`,
name,
status: 'ENABLED',
sortNo: index + 1,
}),
)
const filters = reactive<DocumentFilterForm>({
keyword: '',
@@ -119,169 +101,26 @@ const filteredTemplates = computed(() => {
})
})
async function loadLibrary() {
loading.value = true
try {
if (isDocumentMockEnabled) {
campuses.value = mockCampuses.map((campus) => ({ ...campus }))
departments.value = mockDepartments.map((department) => ({ ...department }))
library.value = documentLibrary.map((department) => ({
...department,
categories: department.categories.map((category) => ({
...category,
documents: category.documents.map((document) => ({ ...document })),
})),
}))
return
}
const [documentsResult, campusesResult, departmentsResult] = await Promise.allSettled([
getDocuments({ page: 1, pageSize: 200, status: 'all' }),
getCampuses(),
getDepartments(),
])
if (documentsResult.status === 'rejected') {
throw documentsResult.reason
}
campuses.value = campusesResult.status === 'fulfilled' ? campusesResult.value : []
departments.value = departmentsResult.status === 'fulfilled' ? departmentsResult.value : []
library.value = buildDocumentLibrary(
documentsResult.value.records,
new Map(departments.value.map((department) => [department.id, department.name])),
new Map(campuses.value.map((campus) => [campus.id, campus.name])),
)
} catch {
library.value = []
ElMessage.error('文档模板加载失败,请稍后重试')
} finally {
loading.value = false
}
function cloneLibrary(): DocumentDepartment[] {
return documentLibrary.map((department) => ({
...department,
categories: department.categories.map((category) => ({
...category,
documents: category.documents.map((document) => ({ ...document })),
})),
}))
}
function mapDocumentStatus(status: DocumentRecord['status']): DocumentStatus {
if (status === 'published') {
return 'enabled'
}
if (status === 'archived') {
return 'archived'
}
if (status === 'review') {
return 'review'
}
return 'draft'
function loadLibrary() {
library.value = cloneLibrary()
}
function buildDocumentLibrary(
records: DocumentRecord[],
departmentNames = new Map<string, string>(),
campusNames = new Map<string, string>(),
): DocumentDepartment[] {
const departments = new Map<string, DocumentDepartment>()
records.forEach((record) => {
const departmentName =
record.departmentName || departmentNames.get(record.departmentId ?? '') || '全院通用'
const departmentKey = record.departmentId || departmentName
const campusName = record.campusName || campusNames.get(record.campusId ?? '')
const department = departments.get(departmentKey) ?? {
key: departmentKey,
name: departmentName,
campus:
campusName === '本部院区' || campusName === '东院区' || campusName === '西院区'
? campusName
: 'all',
categories: [],
}
const category =
department.categories.find((item) => item.name === record.category) ??
(() => {
const nextCategory = { name: record.category, documents: [] }
department.categories.push(nextCategory)
return nextCategory
})()
category.documents.push({
id: record.id,
name: record.name,
code: record.code ?? record.id,
version: record.version,
status: mapDocumentStatus(record.status),
backendStatus: record.backendStatus,
description: record.description ?? '',
versionId: record.versionId,
departmentId: record.departmentId,
campusId: record.campusId,
contentHtml: record.contentHtml,
contentSha256: record.contentSha256,
})
departments.set(departmentKey, department)
})
return [...departments.values()]
}
async function handlePreview(template: DocumentTemplate) {
function handlePreview(template: DocumentTemplate) {
selectedTemplate.value = template
previewError.value = false
if (isDocumentMockEnabled) {
previewLoading.value = false
return
}
const requestId = ++previewRequestId
previewLoading.value = true
try {
const detail = await getDocumentDetail(template.id)
if (!detail) {
throw new Error('模板不存在')
}
let contentHtml = detail.contentHtml
const versionId = detail.versionId ?? template.versionId
if (!contentHtml && versionId) {
const version = await getTemplateVersionDetail(template.id, versionId)
contentHtml = version?.contentHtml ?? version?.content ?? undefined
}
if (requestId !== previewRequestId) {
return
}
selectedTemplate.value = {
...template,
code: detail.code ?? template.code,
version: detail.version || template.version,
versionId,
description: detail.description ?? template.description,
contentHtml,
contentSha256: detail.contentSha256,
}
} catch {
if (requestId === previewRequestId) {
previewError.value = true
ElMessage.error('模板内容加载失败,请稍后重试')
}
} finally {
if (requestId === previewRequestId) {
previewLoading.value = false
}
}
}
function closePreview() {
previewRequestId += 1
selectedTemplate.value = null
previewLoading.value = false
previewError.value = false
}
function showAddMessage() {
@@ -293,35 +132,9 @@ function showExportMessage() {
ElMessage.info('原型演示:导出模板包(ZIP)')
}
async function showEditMessage(template: DocumentTemplate) {
function showEditMessage(template: DocumentTemplate) {
editorTemplate.value = template
editorVisible.value = true
if (isDocumentMockEnabled || template.contentHtml) {
return
}
try {
const detail = await getDocumentDetail(template.id)
const versionId = detail?.versionId ?? template.versionId
let contentHtml = detail?.contentHtml
if (!contentHtml && versionId) {
const version = await getTemplateVersionDetail(template.id, versionId)
contentHtml = version?.contentHtml ?? version?.content ?? undefined
}
if (editorVisible.value && editorTemplate.value?.id === template.id) {
editorTemplate.value = {
...template,
versionId,
description: detail?.description ?? template.description,
contentHtml,
}
}
} catch {
ElMessage.warning('模板内容加载失败,可先关闭后重试')
}
}
function closeEditor() {
@@ -329,10 +142,10 @@ function closeEditor() {
editorTemplate.value = null
}
function addMockTemplate(form: TemplateEditorForm) {
const department = departments.value.find((item) => item.id === form.departmentId)
function addLocalTemplate(form: TemplateEditorForm) {
const department = departments.find((item) => item.id === form.departmentId)
const departmentName = department?.name ?? '全院通用'
const departmentKey = department?.id ?? 'mock-general'
const departmentKey = department?.id ?? 'local-general'
let departmentGroup = library.value.find((item) => item.key === departmentKey)
if (!departmentGroup) {
@@ -354,59 +167,37 @@ function addMockTemplate(form: TemplateEditorForm) {
const timestamp = Date.now()
category.documents.push({
id: `mock-template-${timestamp}`,
id: `local-template-${timestamp}`,
name: form.name,
code: form.templateCode,
version: form.versionNo || 'v1',
status: 'draft',
description: form.description,
versionId: `mock-version-${timestamp}`,
versionId: `local-version-${timestamp}`,
departmentId: form.departmentId || null,
campusId: form.campusId,
contentHtml: form.contentHtml,
})
}
async function saveTemplate(form: TemplateEditorForm) {
function saveTemplate(form: TemplateEditorForm) {
editorSaving.value = true
try {
if (isDocumentMockEnabled) {
if (form.id) {
library.value.forEach((department) =>
department.categories.forEach((category) =>
category.documents.forEach((document) => {
if (document.id === form.id) {
document.version = form.versionNo || document.version
document.contentHtml = form.contentHtml
document.description = form.description
}
}),
),
)
} else {
addMockTemplate(form)
}
} else if (form.id) {
await createTemplateVersion(form.id, {
versionNo: form.versionNo || undefined,
contentHtml: form.contentHtml,
})
await loadLibrary()
if (form.id) {
library.value.forEach((department) =>
department.categories.forEach((category) =>
category.documents.forEach((document) => {
if (document.id === form.id) {
document.version = form.versionNo || document.version
document.contentHtml = form.contentHtml
document.description = form.description
}
}),
),
)
} else {
const template = await createTemplate({
templateCode: form.templateCode,
name: form.name,
description: form.description || undefined,
campusId: form.campusId,
departmentId: form.departmentId || null,
category: form.category || undefined,
})
await createTemplateVersion(template.id, {
versionNo: form.versionNo || undefined,
contentHtml: form.contentHtml,
})
await loadLibrary()
addLocalTemplate(form)
}
closeEditor()
@@ -418,8 +209,8 @@ async function saveTemplate(form: TemplateEditorForm) {
}
}
function updateMockTemplateStatus(templateId: string, action: TemplateVersionAction) {
const nextStatus =
function updateLocalTemplateStatus(templateId: string, action: TemplateVersionAction) {
const nextStatus: DocumentStatus =
action === 'submit-review' || action === 'reject'
? 'review'
: action === 'disable' || action === 'archive'
@@ -437,11 +228,11 @@ function updateMockTemplateStatus(templateId: string, action: TemplateVersionAct
)
}
async function handleWorkflow(action: TemplateVersionAction, comment?: string) {
function handleWorkflow(action: TemplateVersionAction) {
const template = editorTemplate.value
const versionId = template?.versionId
if (!template || (!versionId && !isDocumentMockEnabled)) {
if (!template || !versionId) {
ElMessage.error('当前模板没有可操作的版本')
return
}
@@ -449,19 +240,9 @@ async function handleWorkflow(action: TemplateVersionAction, comment?: string) {
workflowSaving.value = true
try {
if (isDocumentMockEnabled) {
updateMockTemplateStatus(template.id, action)
} else if (versionId) {
await updateTemplateVersionStatus(template.id, versionId, action, comment)
await loadLibrary()
} else {
throw new Error('当前模板没有可操作的版本')
}
updateLocalTemplateStatus(template.id, action)
closeEditor()
ElMessage.success('模板版本状态已更新')
} catch {
ElMessage.error('模板版本操作失败,请稍后重试')
} finally {
workflowSaving.value = false
}
@@ -522,17 +303,7 @@ onMounted(loadLibrary)
:statuses="statusTabs"
/>
<div v-if="loading" class="template-grid" aria-label="正在加载文档模板">
<div v-for="index in 8" :key="index" class="template-skeleton">
<span class="skeleton-title" />
<span class="skeleton-line wide" />
<span class="skeleton-line" />
<span class="skeleton-line short" />
<span class="skeleton-footer" />
</div>
</div>
<div v-else-if="filteredTemplates.length" class="template-grid">
<div v-if="filteredTemplates.length" class="template-grid">
<DocumentTemplateCard
v-for="template in filteredTemplates"
:key="template.id"
@@ -559,8 +330,8 @@ onMounted(loadLibrary)
<DocumentPreviewDialog
:visible="Boolean(selectedTemplate)"
:template="selectedTemplate"
:loading="previewLoading"
:error="previewError"
:loading="false"
:error="false"
@close="closePreview"
@use="useTemplate"
/>
@@ -596,59 +367,6 @@ onMounted(loadLibrary)
gap: 16px;
}
.template-skeleton {
display: flex;
flex-direction: column;
gap: 12px;
min-height: 206px;
padding: 16px;
background: var(--card);
border-radius: var(--r);
box-shadow: var(--sh);
}
.template-skeleton span {
display: block;
background: linear-gradient(90deg, #edf3f5 25%, #f7fafb 37%, #edf3f5 63%);
background-size: 400% 100%;
border-radius: 6px;
animation: skeleton-shimmer 1.4s ease infinite;
}
.skeleton-title {
width: 70%;
height: 20px;
}
.skeleton-line {
width: 90%;
height: 12px;
}
.skeleton-line.wide {
width: 100%;
}
.skeleton-line.short {
width: 62%;
}
.skeleton-footer {
width: 100%;
height: 26px;
margin-top: auto;
}
@keyframes skeleton-shimmer {
0% {
background-position: 100% 0;
}
100% {
background-position: -100% 0;
}
}
.empty-state {
padding: 56px 24px;
color: var(--mut);
@@ -1,5 +1,7 @@
import type { DocumentDepartment, DocumentStatus, LibraryDocument } from './types'
import { documentContentHtml } from './contents'
const documentStatusLabels: Record<DocumentStatus, string> = {
enabled: '启用中',
draft: '草稿',
@@ -22,216 +24,79 @@ function createDocument(
description: string,
status: DocumentStatus = 'enabled',
): LibraryDocument {
return { id, name, code, version, description, status }
return {
id,
name,
code,
version,
description,
status,
contentHtml: documentContentHtml[id],
}
}
// 文书内容以 2025 年在各科室采集的真实知情同意书原件为准(见 ./contents.ts)。
// 各科室版式差异较大:勾选项目表、安全筛查问卷、多签署人等,均为真实业务结构。
export const documentLibrary: DocumentDepartment[] = [
{
key: 'radiology',
name: '放射科',
key: 'medical-imaging',
name: '医学影像科',
campus: 'all',
categories: [
{
name: '核磁相关',
name: '磁共振检查',
documents: [
createDocument(
'doc-rad-mri-001',
'MRI磁共振检查知情同意书',
'TPL-RAD-MRI-001',
'v2.3.1',
'适用于 MRI 检查前风险告知,含幽闭恐惧症、金属植入物、造影剂过敏等注意事项。',
),
createDocument(
'doc-rad-mri-002',
'磁共振安全风险告知书',
'TPL-RAD-MRI-002',
'v1.8.0',
'磁共振室安全筛查及禁忌证告知,适用于所有进入磁体间人员。',
),
createDocument(
'doc-rad-mri-003',
'造影剂注射知情同意书',
'TPL-RAD-CM-001',
'v2.1.0',
'含碘、钆造影剂使用风险、过敏史询问及肾功能评估要求。',
),
],
},
{
name: 'CT相关',
documents: [
createDocument(
'doc-rad-ct-001',
'CT增强检查知情同意书',
'TPL-RAD-CT-001',
'v2.0.1',
'CT 增强扫描造影剂风险、注意事项及不良反应处理告知。',
),
createDocument(
'doc-rad-ct-002',
'CT检查辐射告知书',
'TPL-RAD-CT-002',
'v1.5.0',
'CT 检查电离辐射风险说明,覆盖孕妇、儿童等特殊人群注意事项。',
'review',
),
],
},
{
name: '普放相关',
documents: [
createDocument(
'doc-rad-xr-001',
'X线检查告知书',
'TPL-RAD-XR-001',
'v1.2.0',
'普通 X 线检查注意事项及辐射防护告知。',
'doc-img-mri-001',
'MRI 检查预约单暨知情同意书',
'TPL-IMG-MRI-001',
'v1.0.0',
'含检查预约登记、病人检查准备及注意事项、婴幼儿检查特殊要求,背面为 MRI 安全筛查表(起搏器、金属植入物、孕产史等逐项勾选),需患者或家属签名确认。',
),
],
},
],
},
{
key: 'cardiology',
name: '心内科',
key: 'medical-laboratory',
name: '医学检验科',
campus: 'all',
categories: [
{
name: '介入手术',
name: '基因检测告知',
documents: [
createDocument(
'doc-cvd-iv-001',
'心脏介入手术知情同意书',
'TPL-CVD-IV-001',
'v2.4.0',
'冠状动脉造影、PCI 等介入操作风险、并发症及替代方案告知。',
'doc-lab-infection-gene-001',
'感染基因高通量测序自费项目知情同意书',
'TPL-LAB-IGT-001',
'v1.0.0',
'感染基因 mNGS 检测原理、局限性与潜在风险、受检者知情确认,附 3 项自费检测项目勾选表,自费项目需患者签字确认。',
),
createDocument(
'doc-cvd-cag-001',
'冠状动脉造影知情同意书',
'TPL-CVD-CAG-001',
'v2.2.1',
'冠脉造影检查适应证、禁忌证、术中术后风险及造影剂相关风险。',
),
],
},
{
name: '常规诊疗',
documents: [
createDocument(
'doc-cvd-pc-001',
'心包穿刺知情同意书',
'TPL-CVD-PC-001',
'v1.9.0',
'心包穿刺操作风险、可能并发症及配合事项告知。',
'draft',
'doc-lab-coop-gene-001',
'对外合作或自费基因检测项目知情同意书',
'TPL-LAB-CGT-001',
'v2025.06',
'2025.6.24 版,覆盖医学检验科、生殖医学中心、宫内儿科疾病诊治中心、临床遗传中心、病理科共 60 项对外合作或自费检测项目,含收费金额、收费类别与执行科室,患方勾选后签署。',
),
],
},
],
},
{
key: 'orthopedics',
name: '骨科',
campus: '本部院区',
categories: [
{
name: '手术相关',
documents: [
createDocument(
'doc-ort-op-001',
'骨科手术知情同意书',
'TPL-ORT-OP-001',
'v2.1.0',
'骨科手术麻醉方式、术中术后风险、内固定材料及术后康复说明。',
),
createDocument(
'doc-ort-ane-001',
'麻醉知情同意书',
'TPL-ORT-ANE-001',
'v1.7.0',
'麻醉方式选择、麻醉风险、术后镇痛及可能出现的不良反应。',
'draft',
),
createDocument(
'doc-ort-bt-001',
'输血治疗同意书',
'TPL-ORT-BT-001',
'v1.4.0',
'输血适应证、输血反应及经血传播疾病风险告知。',
),
],
},
],
},
{
key: 'health-management',
name: '健康管理中心',
campus: '东院区',
categories: [
{
name: '体检告知',
documents: [
createDocument(
'doc-pe-rpt-001',
'体检报告发放及知情同意书',
'TPL-PE-RPT-001',
'v1.6.0',
'体检报告领取方式、隐私保护、异常结果随访告知。',
),
createDocument(
'doc-pe-pre-001',
'检前告知书',
'TPL-PE-PRE-001',
'v1.3.0',
'体检前准备事项、空腹要求及特殊检查注意事项。',
),
],
},
],
},
{
key: 'general',
name: '全院通用',
key: 'clinical-genetics',
name: '临床遗传中心',
campus: 'all',
categories: [
{
name: '入院告知',
name: '肿瘤基因检测',
documents: [
createDocument(
'doc-gen-adm-001',
'住院须知及告知书',
'TPL-GEN-ADM-001',
'v2.0.0',
'住院期间权利义务、探视制度、费用结算及安全注意事项。',
),
createDocument(
'doc-gen-crit-001',
'病危通知书签收单',
'TPL-GEN-CRIT-001',
'v1.5.0',
'病危、病重病情告知、家属签收及医患沟通记录。',
'review',
),
],
},
{
name: '授权委托',
documents: [
createDocument(
'doc-gen-pow-001',
'患者授权委托书',
'TPL-GEN-POW-001',
'v2.1.0',
'患者授权委托代理人办理医疗相关事务及签署文件的授权书。',
'archived',
),
createDocument(
'doc-gen-ref-001',
'拒绝检查治疗告知书',
'TPL-GEN-REF-001',
'v1.8.0',
'患者或代理人拒绝推荐检查、治疗时的风险告知及签字确认。',
'doc-gen-onco-gene-001',
'肿瘤基因高通量测序自费项目知情同意书',
'TPL-GEN-OGT-001',
'v1.0.0',
'肿瘤基因 NGS 分子检测原理、局限性与潜在风险、受检者知情确认,附 BRCA1/2 及 NGS 小/中/大 panel 共 4 项检测项目勾选表。',
),
],
},
@@ -1,5 +1,14 @@
export type DocumentStatus = 'enabled' | 'draft' | 'archived' | 'review'
// 模板版本工作流动作。原型阶段在页面内本地消化;接入后端后与文档模板版本状态接口对齐。
export type TemplateVersionAction =
| 'submit-review'
| 'reject'
| 'approve'
| 'publish'
| 'disable'
| 'archive'
export type DocumentFilterStatus = 'all' | DocumentStatus
export type DocumentCampus = 'all' | '本部院区' | '东院区' | '西院区'