367 lines
11 KiB
Vue
367 lines
11 KiB
Vue
<template>
|
||
<!-- 详情页参考截图:顶部蓝条显示创建信息,支持编辑/删除;黄底提示不渲染 -->
|
||
<view class="page">
|
||
<view class="topbar">
|
||
<view class="topbar-text">{{ topText }}</view>
|
||
</view>
|
||
|
||
<view class="content">
|
||
<view class="section">
|
||
<view class="row">
|
||
<view class="label">病历类型</view>
|
||
<view class="value">{{ typeLabel }}</view>
|
||
</view>
|
||
<view class="row">
|
||
<view class="label">就诊日期</view>
|
||
<view class="value">{{ visitDate || '--' }}</view>
|
||
</view>
|
||
<view class="row">
|
||
<view class="label">诊断</view>
|
||
<view class="value">{{ diagnosisText }}</view>
|
||
</view>
|
||
<view v-if="templateType === 'inhospital' && record.surgeryName" class="row">
|
||
<view class="label">手术名称</view>
|
||
<view class="value">{{ record.surgeryName }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view v-for="(s, idx) in sections" :key="idx" class="section">
|
||
<view class="h2">{{ s.title }}</view>
|
||
<view class="p">{{ s.value }}</view>
|
||
</view>
|
||
|
||
<view class="section">
|
||
<view class="h2">文件上传</view>
|
||
<view v-if="files.length" class="files">
|
||
<view v-for="(f, idx) in files" :key="idx" class="file" @click="preview(idx)">
|
||
<image class="thumb" :src="f.url" mode="aspectFill" />
|
||
</view>
|
||
</view>
|
||
<view v-else class="files-empty">暂无附件</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="footer">
|
||
<button class="btn danger" @click="remove">删除</button>
|
||
<button class="btn primary" @click="edit">编辑</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, ref } from 'vue';
|
||
import { onLoad } from '@dcloudio/uni-app';
|
||
import dayjs from 'dayjs';
|
||
import api from '@/utils/api';
|
||
import { loading, hideLoading, toast } from '@/utils/widget';
|
||
import { getVisitRecordTemplate } from '@/components/archive-detail/templates';
|
||
|
||
const archiveId = ref('');
|
||
const id = ref('');
|
||
const medicalType = ref('');
|
||
const record = ref({});
|
||
|
||
const files = computed(() => {
|
||
const arr = record.value?.files;
|
||
return Array.isArray(arr) ? arr.filter((i) => i && i.url) : [];
|
||
});
|
||
|
||
const templateType = computed(() => record.value?.templateType || record.value?.medicalType || '');
|
||
|
||
const typeLabel = computed(() => record.value?.tempName || getVisitRecordTemplate(templateType.value || medicalType.value)?.templateName || '病历');
|
||
|
||
function normalizeText(v) {
|
||
if (Array.isArray(v)) return v.filter((i) => i !== null && i !== undefined && String(i).trim()).join(',');
|
||
if (v === 0) return '0';
|
||
return v ? String(v) : '';
|
||
}
|
||
|
||
function formatPositiveFind(v, { withOpinion = false } = {}) {
|
||
if (Array.isArray(v)) {
|
||
const list = v
|
||
.map((i) => (i && typeof i === 'object' ? { category: i.category, opinion: i.opinion } : null))
|
||
.filter((i) => i && (i.category || i.opinion));
|
||
if (!list.length) return '';
|
||
if (!withOpinion) return list.map((i) => String(i.category || '').trim()).filter(Boolean).join(':');
|
||
return list
|
||
.map((i) => {
|
||
const c = String(i.category || '').trim();
|
||
const o = String(i.opinion || '').trim();
|
||
if (c && o) return `${c}:${o}`;
|
||
return c || o;
|
||
})
|
||
.filter(Boolean)
|
||
.join('\n');
|
||
}
|
||
return normalizeText(v);
|
||
}
|
||
|
||
function getCorpId() {
|
||
const team = uni.getStorageSync('ykt_case_current_team') || {};
|
||
return team?.corpId ? String(team.corpId) : '';
|
||
}
|
||
|
||
const visitDate = computed(() => {
|
||
const t = templateType.value;
|
||
if (t === 'outpatient') return record.value?.visitTime || '';
|
||
if (t === 'inhospital') return record.value?.inhosDate || '';
|
||
if (t === 'preConsultation') return record.value?.consultDate || '';
|
||
if (t === 'physicalExaminationTemplate') return record.value?.inspectDate || '';
|
||
return record.value?.dateStr || '';
|
||
});
|
||
|
||
const diagnosisText = computed(() => {
|
||
const t = templateType.value;
|
||
if (t === 'preConsultation') return normalizeText(record.value?.chiefComplaint) || normalizeText(record.value?.summary) || '--';
|
||
if (t === 'physicalExaminationTemplate') return formatPositiveFind(record.value?.positiveFind) || normalizeText(record.value?.summary) || '--';
|
||
if (t === 'outpatient' || t === 'inhospital') return normalizeText(record.value?.diagnosisName || record.value?.diagnosis) || normalizeText(record.value?.summary) || '--';
|
||
return normalizeText(record.value?.diagnosisName || record.value?.diagnosis || record.value?.summary) || '--';
|
||
});
|
||
|
||
const sections = computed(() => {
|
||
const t = templateType.value;
|
||
const push = (title, value) => {
|
||
const v = value === 0 ? '0' : value ? String(value) : '';
|
||
if (!v.trim()) return;
|
||
return { title, value: v };
|
||
};
|
||
const list = [];
|
||
if (t === 'outpatient') {
|
||
const corp = push('就诊机构', record.value?.corpName);
|
||
const dept = push('科室', record.value?.deptName);
|
||
const doctor = push('医生', record.value?.doctor);
|
||
const treatment = push('治疗方案', record.value?.treatmentPlan);
|
||
const dispose = push('处置计划', record.value?.disposePlan);
|
||
const summary = push('备注/摘要', record.value?.summary);
|
||
[corp, dept, doctor, treatment, dispose, summary].forEach((i) => i && list.push(i));
|
||
return list;
|
||
}
|
||
if (t === 'inhospital') {
|
||
const corp = push('住院机构', record.value?.corpName);
|
||
const summary = push('摘要', record.value?.summary);
|
||
[corp, summary].forEach((i) => i && list.push(i));
|
||
return list;
|
||
}
|
||
if (t === 'preConsultation') {
|
||
const illness = push('现病史', record.value?.presentIllness);
|
||
const past = push('既往史', record.value?.pastHistory);
|
||
const allergy = push('过敏史', record.value?.allergyHistory);
|
||
const summary = push('摘要', record.value?.summary);
|
||
[illness, past, allergy, summary].forEach((i) => i && list.push(i));
|
||
return list;
|
||
}
|
||
if (t === 'physicalExaminationTemplate') {
|
||
const corp = push('体检机构', record.value?.corpName);
|
||
const pkg = push('体检套餐', record.value?.inspectPakageName);
|
||
const positive = push('阳性发现及处理意见', formatPositiveFind(record.value?.positiveFind, { withOpinion: true }));
|
||
const summary = push('摘要', record.value?.summary);
|
||
[corp, pkg, positive, summary].forEach((i) => i && list.push(i));
|
||
return list;
|
||
}
|
||
const summary = push('摘要', record.value?.summary);
|
||
if (summary) list.push(summary);
|
||
return list;
|
||
});
|
||
|
||
const topText = computed(() => {
|
||
const time = record.value?.createTime ? dayjs(record.value.createTime).format('YYYY-MM-DD HH:mm') : '';
|
||
const rawName = record.value?.creatorName ? String(record.value.creatorName) : '';
|
||
const cleanName = ['-', '—', '--'].includes(rawName.trim()) ? '' : rawName.trim();
|
||
const byCustomer = record.value?.ignore === 'checkIn';
|
||
const suffix = byCustomer ? '患者自建' : cleanName ? `${cleanName}代建` : record.value?.creator ? '员工代建' : '';
|
||
return suffix ? `${time || '--'} ${suffix}` : `${time || '--'}`;
|
||
});
|
||
|
||
onLoad(async (opt) => {
|
||
archiveId.value = opt?.archiveId ? String(opt.archiveId) : '';
|
||
id.value = opt?.id ? String(opt.id) : '';
|
||
medicalType.value = opt?.type ? String(opt.type) : '';
|
||
if (!archiveId.value || !id.value || !medicalType.value) {
|
||
toast('参数缺失');
|
||
setTimeout(() => uni.navigateBack(), 300);
|
||
return;
|
||
}
|
||
|
||
// 使用真实 API 获取病历记录
|
||
loading('加载中...');
|
||
try {
|
||
const corpId = getCorpId();
|
||
if (!corpId) {
|
||
hideLoading();
|
||
toast('缺少 corpId');
|
||
setTimeout(() => uni.navigateBack(), 300);
|
||
return;
|
||
}
|
||
|
||
const res = await api('getMedicalRecordById', {
|
||
_id: id.value,
|
||
corpId,
|
||
memberId: archiveId.value,
|
||
medicalType: medicalType.value,
|
||
});
|
||
hideLoading();
|
||
const r = res?.record || res?.data?.record || null;
|
||
if (!res?.success || !r) {
|
||
toast('记录不存在');
|
||
setTimeout(() => uni.navigateBack(), 300);
|
||
return;
|
||
}
|
||
|
||
// 兼容模板字段:wxapp 使用 diagnosis,但接口通常返回 diagnosisName
|
||
if ((r.medicalType === 'outpatient' || r.medicalType === 'inhospital') && !r.diagnosis && r.diagnosisName) {
|
||
r.diagnosis = r.diagnosisName;
|
||
}
|
||
|
||
record.value = r;
|
||
uni.setNavigationBarTitle({ title: String(typeLabel.value || '病历详情') });
|
||
} catch (error) {
|
||
hideLoading();
|
||
console.error('获取病历记录失败:', error);
|
||
toast('加载失败');
|
||
setTimeout(() => uni.navigateBack(), 300);
|
||
}
|
||
});
|
||
|
||
function preview(idx) {
|
||
const urls = files.value.map((i) => i.url);
|
||
uni.previewImage({ urls, current: urls[idx] });
|
||
}
|
||
|
||
function edit() {
|
||
const type = record.value?.templateType || record.value?.medicalType || '';
|
||
uni.navigateTo({
|
||
url: `/pages/case/visit-record-detail?archiveId=${encodeURIComponent(archiveId.value)}&id=${encodeURIComponent(id.value)}&type=${encodeURIComponent(type)}`,
|
||
});
|
||
}
|
||
|
||
function remove() {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确定删除当前记录?',
|
||
success: async (res) => {
|
||
if (!res.confirm) return;
|
||
|
||
loading('删除中...');
|
||
try {
|
||
const corpId = getCorpId();
|
||
if (!corpId) {
|
||
hideLoading();
|
||
return toast('缺少 corpId');
|
||
}
|
||
await api('removeMedicalRecord', { corpId, memberId: archiveId.value, medicalType: medicalType.value, _id: id.value });
|
||
hideLoading();
|
||
uni.$emit('archive-detail:visit-record-changed');
|
||
toast('已删除');
|
||
setTimeout(() => uni.navigateBack(), 300);
|
||
} catch (error) {
|
||
hideLoading();
|
||
console.error('删除病历记录失败:', error);
|
||
toast('删除失败');
|
||
}
|
||
},
|
||
});
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page {
|
||
min-height: 100vh;
|
||
background: #fff;
|
||
padding-bottom: calc(76px + env(safe-area-inset-bottom));
|
||
}
|
||
.topbar {
|
||
background: #5d6df0;
|
||
padding: 10px 14px;
|
||
}
|
||
.topbar-text {
|
||
color: #fff;
|
||
font-size: 14px;
|
||
text-align: center;
|
||
}
|
||
.content {
|
||
padding: 14px 14px 0;
|
||
}
|
||
.section {
|
||
margin-bottom: 14px;
|
||
}
|
||
.row {
|
||
display: flex;
|
||
padding: 10px 0;
|
||
}
|
||
.label {
|
||
width: 90px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #111827;
|
||
}
|
||
.value {
|
||
flex: 1;
|
||
font-size: 14px;
|
||
color: #111827;
|
||
word-break: break-all;
|
||
}
|
||
.h2 {
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
color: #111827;
|
||
padding: 8px 0;
|
||
}
|
||
.p {
|
||
font-size: 14px;
|
||
color: #111827;
|
||
line-height: 20px;
|
||
white-space: pre-wrap;
|
||
}
|
||
.files {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
.file {
|
||
width: 90px;
|
||
height: 70px;
|
||
border: 1px solid #d1d5db;
|
||
background: #f9fafb;
|
||
}
|
||
.thumb {
|
||
width: 90px;
|
||
height: 70px;
|
||
}
|
||
.files-empty {
|
||
font-size: 13px;
|
||
color: #9aa0a6;
|
||
padding: 8px 0;
|
||
}
|
||
.footer {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: #fff;
|
||
padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 14px;
|
||
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.06);
|
||
}
|
||
.btn {
|
||
width: 120px;
|
||
height: 44px;
|
||
line-height: 44px;
|
||
border-radius: 6px;
|
||
font-size: 15px;
|
||
}
|
||
.btn::after {
|
||
border: none;
|
||
}
|
||
.btn.danger {
|
||
background: #fff;
|
||
color: #ff4d4f;
|
||
border: 1px solid #ff4d4f;
|
||
}
|
||
.btn.primary {
|
||
background: #4f6ef7;
|
||
color: #fff;
|
||
}
|
||
</style>
|