ykt-wxapp/pages/case/visit-record-view.vue

764 lines
23 KiB
Vue
Raw Normal View History

2026-02-02 15:15:51 +08:00
<template>
2026-01-22 17:39:23 +08:00
<!-- 详情页参考截图顶部蓝条显示创建信息支持编辑/删除黄底提示不渲染 -->
<view class="page">
2026-02-11 17:45:09 +08:00
<scroll-view scroll-y class="scroll" :style="{ height: scrollHeight + 'px' }">
<view class="topbar">
<view class="topbar-text">{{ topText }}</view>
</view>
2026-01-22 17:39:23 +08:00
2026-02-11 17:45:09 +08:00
<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">{{ visitDateLabel }}</view>
<view class="value">{{ visitDate || '--' }}</view>
</view>
<view v-if="showDiagnosisRow" 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>
2026-01-22 17:39:23 +08:00
</view>
2026-02-11 17:45:09 +08:00
<view v-for="(s, idx) in sections" :key="idx" class="section">
<view class="h2">{{ s.title }}</view>
<view class="p">{{ s.value }}</view>
</view>
2026-01-22 17:39:23 +08:00
2026-02-11 17:45:09 +08:00
<view v-if="showFilesSection" 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>
2026-01-22 17:39:23 +08:00
</view>
2026-02-11 17:45:09 +08:00
<view v-else class="files-empty">暂无附件</view>
2026-01-22 17:39:23 +08:00
</view>
</view>
2026-02-11 17:45:09 +08:00
<view class="scroll-spacer" />
</scroll-view>
2026-01-22 17:39:23 +08:00
<view class="footer">
<button class="btn danger" @click="remove">删除</button>
<button class="btn primary" @click="edit">编辑</button>
</view>
</view>
</template>
<script setup>
2026-02-10 15:47:35 +08:00
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
2026-01-22 17:39:23 +08:00
import dayjs from 'dayjs';
2026-02-27 17:17:34 +08:00
import { storeToRefs } from 'pinia';
2026-01-27 16:46:36 +08:00
import api from '@/utils/api';
2026-02-27 17:17:34 +08:00
import useAccountStore from '@/store/account';
2026-01-27 16:46:36 +08:00
import { loading, hideLoading, toast } from '@/utils/widget';
2026-02-02 18:48:18 +08:00
import { getVisitRecordTemplate } from './components/archive-detail/templates';
2026-02-09 15:40:03 +08:00
import { normalizeVisitRecordFormData } from './utils/visit-record';
import { normalizeTemplate, unwrapTemplateResponse } from './utils/template';
import { normalizeFileUrl } from '@/utils/file';
2026-01-22 17:39:23 +08:00
2026-02-11 17:45:09 +08:00
const scrollHeight = ref(0);
2026-02-27 17:17:34 +08:00
const accountStore = useAccountStore();
const { account, doctorInfo } = storeToRefs(accountStore);
const { getDoctorInfo } = accountStore;
2026-01-22 17:39:23 +08:00
const archiveId = ref('');
const id = ref('');
2026-01-27 16:46:36 +08:00
const medicalType = ref('');
2026-02-09 15:40:03 +08:00
const rawType = ref('');
2026-01-22 17:39:23 +08:00
const record = ref({});
2026-02-09 15:40:03 +08:00
const temp = ref(null);
2026-02-10 15:47:35 +08:00
const needReload = ref(false);
let recordChangedHandler = null;
2026-01-22 17:39:23 +08:00
2026-02-11 17:49:44 +08:00
const userNameMap = ref({});
const loadedMembersTeamId = ref('');
2026-02-27 17:17:34 +08:00
const corpMemberNameInflight = new Map(); // userId -> Promise<string>
const corpMemberNameTried = new Set(); // avoid retry storms on failures
2026-02-11 17:49:44 +08:00
2026-01-22 17:39:23 +08:00
const files = computed(() => {
const arr = record.value?.files;
2026-02-09 15:40:03 +08:00
return Array.isArray(arr)
? arr
.filter((i) => i && i.url)
.map((i) => ({ ...i, url: normalizeFileUrl(i.url) }))
: [];
2026-01-22 17:39:23 +08:00
});
2026-02-09 15:40:03 +08:00
function normalizeMedicalType(raw) {
const s = String(raw || '').trim();
if (!s) return '';
const lower = s.toLowerCase();
2026-02-10 15:47:35 +08:00
if (lower.includes('preconsultationrecord')) return 'preConsultationRecord';
if (lower.includes('preconsult') || (lower.includes('pre') && lower.includes('consult'))) return 'preConsultationRecord';
2026-02-09 15:40:03 +08:00
if (lower === 'outpatient' || lower === 'out_patient' || lower === 'out-patient') return 'outpatient';
if (lower === 'inhospital' || lower === 'in_hospital' || lower === 'in-hospital' || lower === 'inpatient') return 'inhospital';
2026-02-10 15:47:35 +08:00
if (lower === 'preconsultation' || lower === 'pre_consultation' || lower === 'pre-consultation') return 'preConsultationRecord';
2026-02-09 15:40:03 +08:00
if (lower === 'physicalexaminationtemplate' || lower === 'physicalexamination' || lower === 'physical_examination') return 'physicalExaminationTemplate';
if (s === 'outPatient') return 'outpatient';
if (s === 'inHospital') return 'inhospital';
2026-02-12 15:54:50 +08:00
if (s === 'preConsultationRecord') return 'preConsultationRecord';
2026-02-10 15:47:35 +08:00
if (s === 'preConsultationRecord') return 'preConsultationRecord';
2026-02-09 15:40:03 +08:00
if (s === 'physicalExaminationTemplate') return 'physicalExaminationTemplate';
return s;
}
const templateType = computed(() => normalizeMedicalType(rawType.value || medicalType.value || record.value?.templateType || record.value?.medicalType || ''));
const typeLabel = computed(() => record.value?.tempName || temp.value?.name || getVisitRecordTemplate(templateType.value || medicalType.value)?.templateName || '病历');
2026-01-22 17:39:23 +08:00
2026-02-09 15:40:03 +08:00
function getDefaultTimeTitle(t) {
if (t === 'outpatient') return 'visitTime';
if (t === 'inhospital') return 'inhosDate';
2026-02-10 15:47:35 +08:00
if (t === 'preConsultationRecord') return 'consultationDate';
2026-02-09 15:40:03 +08:00
if (t === 'physicalExaminationTemplate') return 'inspectDate';
return '';
}
function getDefaultTimeName(t) {
if (t === 'outpatient') return '就诊日期';
if (t === 'inhospital') return '入院日期';
2026-02-10 15:47:35 +08:00
if (t === 'preConsultationRecord') return '问诊日期';
2026-02-09 15:40:03 +08:00
if (t === 'physicalExaminationTemplate') return '体检日期';
return '日期';
}
2026-01-27 16:46:36 +08:00
function normalizeText(v) {
if (Array.isArray(v)) return v.filter((i) => i !== null && i !== undefined && String(i).trim()).join('');
if (v === 0) return '0';
2026-02-09 15:40:03 +08:00
if (v && typeof v === 'object') {
const o = v;
const candidate = o.label ?? o.name ?? o.text ?? o.title ?? o.value ?? o.code ?? '';
return candidate ? String(candidate) : '';
}
2026-01-27 16:46:36 +08:00
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);
}
2026-02-27 17:17:34 +08:00
async function ensureDoctor() {
if (doctorInfo.value) return;
if (!account.value?.openid) return;
try {
await getDoctorInfo();
} catch {
// ignore
}
}
function extractDisplayNameFromAny(raw) {
const obj = raw && typeof raw === 'object' ? raw : {};
const candidate =
obj.anotherName ??
obj.name ??
obj.username ??
obj.userName ??
obj.nickname ??
obj.nickName ??
obj.realName ??
obj.memberName ??
obj.doctorName ??
obj.title ??
'';
return candidate ? String(candidate).trim() : '';
}
function extractDisplayNameFromCorpMember(row) {
const m = row && typeof row === 'object' ? row : {};
return String(m.anotherName || m.name || '').trim();
}
function getCorpIdForQuery() {
// 优先使用已拉取到的企业信息,其次用本地当前团队(最后兜底)
const d = doctorInfo.value || {};
const a = account.value || {};
2026-01-27 16:46:36 +08:00
const team = uni.getStorageSync('ykt_case_current_team') || {};
2026-02-27 17:17:34 +08:00
return String(d.corpId || a.corpId || team.corpId || '') || '';
}
function getCorpId() {
return getCorpIdForQuery();
2026-01-27 16:46:36 +08:00
}
2026-01-22 17:39:23 +08:00
2026-02-11 17:49:44 +08:00
function getTeamId() {
const team = uni.getStorageSync('ykt_case_current_team') || {};
return team?.teamId ? String(team.teamId) : '';
}
function normalizeUserId(value) {
if (value === null || value === undefined) return '';
if (typeof value === 'object') {
const obj = value;
const picked =
obj.userid ||
obj.userId ||
obj.userID ||
obj.corpUserId ||
obj.corpUserID ||
obj._id ||
obj.id ||
'';
return String(picked || '').trim();
}
return String(value || '').trim();
}
function isLikelyUserId(value) {
const id = normalizeUserId(value);
if (!id) return false;
if (/[-—]{1,2}/.test(id) && ['-', '—', '--'].includes(id.trim())) return false;
if (/\s/.test(id)) return false;
if (/[\u4e00-\u9fa5]/.test(id)) return false;
return true;
}
async function loadTeamMembers() {
const corpId = getCorpId();
const teamId = getTeamId();
if (!corpId || !teamId) return;
if (loadedMembersTeamId.value === teamId && Object.keys(userNameMap.value || {}).length > 0) return;
try {
const res = await api('getTeamData', { corpId, teamId });
if (!res?.success) return;
const t = res?.data && typeof res.data === 'object' ? res.data : {};
const members = Array.isArray(t.memberList) ? t.memberList : [];
const nextMap = {};
members.forEach((m) => {
if (!m || typeof m !== 'object') return;
const display = String(m?.anotherName || m?.name || m?.userid || m?.userId || m?.corpUserId || '').trim();
const keys = [m?.userid, m?.userId, m?.corpUserId].map(normalizeUserId).filter(Boolean);
keys.forEach((k) => {
nextMap[k] = display || nextMap[k] || k;
nextMap[String(k).toLowerCase()] = display || nextMap[String(k).toLowerCase()] || k;
});
});
userNameMap.value = nextMap;
loadedMembersTeamId.value = teamId;
} catch {
// ignore
}
}
2026-02-27 17:17:34 +08:00
async function prefetchCorpMemberName(userId) {
const id = normalizeUserId(userId);
if (!id || !isLikelyUserId(id)) return '';
const map = userNameMap.value || {};
const existing = String(map[id] || map[id.toLowerCase()] || '').trim();
if (existing && existing !== id) return existing;
if (corpMemberNameInflight.has(id)) return corpMemberNameInflight.get(id);
if (corpMemberNameTried.has(id)) return '';
const p = (async () => {
corpMemberNameTried.add(id);
await ensureDoctor();
const corpId = getCorpIdForQuery();
// 1) 首选:成员主页信息(更可能支持 userid 查询)
try {
const res = await api('getCorpMemberHomepageInfo', { corpId, corpUserId: id }, false);
if (res?.success) {
const name =
extractDisplayNameFromAny(res?.data) ||
extractDisplayNameFromAny(res?.data?.data) ||
extractDisplayNameFromAny(res?.data?.member) ||
'';
if (name) return name;
}
} catch {
// ignore
}
// 1.1) 部分环境参数名是 userId
try {
const res = await api('getCorpMemberHomepageInfo', { corpId, userId: id }, false);
if (res?.success) {
const name =
extractDisplayNameFromAny(res?.data) ||
extractDisplayNameFromAny(res?.data?.data) ||
extractDisplayNameFromAny(res?.data?.member) ||
'';
if (name) return name;
}
} catch {
// ignore
}
// 2) 兜底:成员数据接口
try {
const res = await api(
'getCorpMember',
{
corpId,
page: 1,
pageSize: 10,
params: {
corpId,
memberList: [id],
},
},
false
);
if (res?.success) {
const rows = Array.isArray(res?.data) ? res.data : Array.isArray(res?.data?.data) ? res.data.data : [];
const row = rows.find((m) => normalizeUserId(m?.userid || m?.userId || m?.corpUserId || '') === id) || rows[0] || null;
const name = extractDisplayNameFromCorpMember(row) || '';
if (name) return name;
}
} catch {
// ignore
}
return '';
})()
.then((name) => {
const display = String(name || '').trim();
if (display) {
const next = { ...(userNameMap.value || {}) };
next[id] = display;
next[id.toLowerCase()] = display;
userNameMap.value = next;
}
return display;
})
.finally(() => {
corpMemberNameInflight.delete(id);
});
corpMemberNameInflight.set(id, p);
return p;
}
2026-02-11 17:49:44 +08:00
function resolveUserName(userId) {
const id = normalizeUserId(userId);
if (!id) return '';
const map = userNameMap.value || {};
2026-02-27 17:17:34 +08:00
const resolved = String(map[id] || map[id.toLowerCase()] || '').trim();
if (resolved) return resolved;
// 无 teamId/未初始化 localStorage 时,尝试用企业成员接口补齐
void prefetchCorpMemberName(id);
return id;
2026-02-11 17:49:44 +08:00
}
2026-02-09 15:40:03 +08:00
function parseAnyTimeMs(v) {
if (v === null || v === undefined) return 0;
if (typeof v === 'number') {
// 10位秒级时间戳
if (v > 1e9 && v < 1e12) return v * 1000;
return v;
}
const s = String(v).trim();
if (!s) return 0;
if (/^\d{10,13}$/.test(s)) return Number(s.length === 10 ? `${s}000` : s);
const d = dayjs(s);
return d.isValid() ? d.valueOf() : 0;
}
function formatAnyDate(v, fmt = 'YYYY-MM-DD') {
const ms = parseAnyTimeMs(v);
if (!ms) return '';
const d = dayjs(ms);
return d.isValid() ? d.format(fmt) : '';
}
2026-01-22 17:39:23 +08:00
const visitDate = computed(() => {
const t = templateType.value;
2026-02-09 15:40:03 +08:00
const timeTitle = temp.value?.service?.timeTitle || getDefaultTimeTitle(t);
const raw = timeTitle ? record.value?.[timeTitle] : (record.value?.dateStr ?? record.value?.sortTime ?? '');
return formatAnyDate(raw) || normalizeText(raw) || '';
});
const visitDateLabel = computed(() => {
const t = templateType.value;
return String(temp.value?.service?.timeName || getDefaultTimeName(t) || '日期');
});
const showDiagnosisRow = computed(() => {
const list = Array.isArray(temp.value?.templateList)
? temp.value.templateList
: Array.isArray(getVisitRecordTemplate(templateType.value)?.templateList)
? getVisitRecordTemplate(templateType.value).templateList
: [];
return list.some((i) => i && (i.title === 'diagnosis' || i.title === 'diagnosisName'));
2026-01-22 17:39:23 +08:00
});
const diagnosisText = computed(() => {
const t = templateType.value;
2026-02-09 15:40:03 +08:00
if (!showDiagnosisRow.value) return '--';
2026-01-27 16:46:36 +08:00
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) || '--';
2026-01-22 17:39:23 +08:00
});
2026-02-09 15:40:03 +08:00
const showFilesSection = computed(() => {
if (files.value.length) return true;
const list = Array.isArray(temp.value?.templateList)
? temp.value.templateList
: Array.isArray(getVisitRecordTemplate(templateType.value)?.templateList)
? getVisitRecordTemplate(templateType.value).templateList
: [];
return list.some((i) => i && (i.type === 'files' || i.title === 'files'));
});
2026-01-22 17:39:23 +08:00
const sections = computed(() => {
const t = templateType.value;
2026-02-09 15:40:03 +08:00
const hiddenKeys = new Set(t === 'outpatient'
? ['corp', 'deptName', 'corpName', 'doctor']
: t === 'inhospital'
? ['corp', 'corpName']
2026-02-10 15:47:35 +08:00
: t === 'physicalExaminationTemplate'
? ['inspectPakageName']
: []);
2026-02-09 15:40:03 +08:00
const list = [];
const pushedNames = new Set();
const pushRow = (name, value) => {
const v = normalizeText(value);
2026-01-22 17:39:23 +08:00
if (!v.trim()) return;
2026-02-09 15:40:03 +08:00
if (pushedNames.has(name)) return;
pushedNames.add(name);
list.push({ title: name, value: v });
2026-01-22 17:39:23 +08:00
};
2026-02-09 15:40:03 +08:00
const resolveOptionLabel = (item, candidate) => {
const range = Array.isArray(item?.range) ? item.range : [];
if (!range.length) return normalizeText(candidate);
const isObjectRange = range[0] && typeof range[0] === 'object';
const toLabel = (v) => {
const s = normalizeText(v);
if (!s) return '';
if (!isObjectRange) return s;
const found = range.find((opt) => opt && typeof opt === 'object' && String(opt.value) === String(s));
return found ? String(found.label ?? found.value ?? s) : s;
};
if (Array.isArray(candidate)) return candidate.map(toLabel).filter((i) => String(i).trim()).join('');
return toLabel(candidate);
};
const templateList = Array.isArray(temp.value?.templateList)
? temp.value.templateList
: Array.isArray(getVisitRecordTemplate(t)?.templateList)
? getVisitRecordTemplate(t).templateList
: [];
const timeTitle = temp.value?.service?.timeTitle || getDefaultTimeTitle(t);
templateList.forEach((item) => {
const key = item?.title ? String(item.title) : '';
if (!key) return;
if (key === 'files') return;
if (key === 'diagnosis' || key === 'diagnosisName') return;
if (timeTitle && key === timeTitle) return;
if (hiddenKeys.has(key)) return;
const raw = record.value?.[key];
const display = key === 'positiveFind'
? formatPositiveFind(raw, { withOpinion: true })
: item?.type === 'date'
? (formatAnyDate(raw) || normalizeText(raw))
: resolveOptionLabel(item, raw);
pushRow(String(item?.name || key), display);
});
2026-01-22 17:39:23 +08:00
return list;
});
2026-02-09 15:40:03 +08:00
async function loadTemplate(t) {
2026-02-27 17:17:34 +08:00
if (!t) return null;
2026-02-09 15:40:03 +08:00
const corpId = getCorpId();
try {
const res = await api('getCurrentTemplate', { corpId, templateType: t });
if (!res?.success) return null;
const raw = unwrapTemplateResponse(res);
return normalizeTemplate(raw);
} catch (e) {
return null;
}
}
2026-01-22 17:39:23 +08:00
const topText = computed(() => {
const time = record.value?.createTime ? dayjs(record.value.createTime).format('YYYY-MM-DD HH:mm') : '';
2026-01-27 16:46:36 +08:00
const byCustomer = record.value?.ignore === 'checkIn';
2026-02-11 17:49:44 +08:00
if (byCustomer) return `${time || '--'} 患者自建`;
const nameFromApiRaw = record.value?.creatorName ? String(record.value.creatorName).trim() : '';
const nameFromApi = ['-', '—', '--'].includes(nameFromApiRaw) ? '' : nameFromApiRaw;
if (nameFromApi && !isLikelyUserId(nameFromApi)) {
return `${time || '--'} ${nameFromApi}代建`;
}
const creatorId = normalizeUserId(
record.value?.creator ||
record.value?.creatorUserId ||
record.value?.createUserId ||
record.value?.executor ||
record.value?.executorUserId ||
''
);
const fallbackId = !creatorId && nameFromApi && isLikelyUserId(nameFromApi) ? nameFromApi : '';
const display = (creatorId || fallbackId) ? resolveUserName(creatorId || fallbackId) : '';
const suffix = display ? `${display}代建` : '';
2026-01-27 16:46:36 +08:00
return suffix ? `${time || '--'} ${suffix}` : `${time || '--'}`;
2026-01-22 17:39:23 +08:00
});
2026-02-10 15:47:35 +08:00
async function fetchRecord({ silent = false } = {}) {
2026-02-27 17:17:34 +08:00
if (!archiveId.value || !id.value || !medicalType.value) return { ok: false, reason: 'request_failed' };
await ensureDoctor();
2026-02-10 15:47:35 +08:00
const corpId = getCorpId();
2026-01-27 16:46:36 +08:00
2026-02-10 15:47:35 +08:00
if (!silent) loading('加载中...');
try {
2026-01-27 16:46:36 +08:00
const res = await api('getMedicalRecordById', {
_id: id.value,
corpId,
memberId: archiveId.value,
medicalType: medicalType.value,
});
const r = res?.record || res?.data?.record || null;
2026-02-27 17:17:34 +08:00
if (res?.success && r) {
const raw = String(r?.templateType || r?.medicalType || medicalType.value || '');
rawType.value = raw;
const ui = normalizeMedicalType(raw);
record.value = normalizeVisitRecordFormData(ui, r);
temp.value = await loadTemplate(raw);
uni.setNavigationBarTitle({ title: String(typeLabel.value || '病历详情') });
return { ok: true, reason: '' };
}
const msg = String(res?.message || res?.msg || '').trim();
const isNotFound = (res?.success && !r) || /不存在|not\s*found|not\s*exist/i.test(msg);
return { ok: false, reason: isNotFound ? 'not_found' : 'request_failed' };
2026-01-27 16:46:36 +08:00
} catch (error) {
console.error('获取病历记录失败:', error);
2026-02-27 17:17:34 +08:00
return { ok: false, reason: 'request_failed' };
2026-02-10 15:47:35 +08:00
} finally {
if (!silent) hideLoading();
}
}
onLoad(async (opt) => {
2026-02-11 17:45:09 +08:00
try {
const { windowHeight } = uni.getSystemInfoSync();
scrollHeight.value = windowHeight || 0;
} catch {
scrollHeight.value = 0;
}
2026-02-10 15:47:35 +08:00
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;
}
2026-02-11 17:49:44 +08:00
// 异步加载团队成员映射用于展示“xx代建”的真实姓名
void loadTeamMembers();
2026-02-27 17:17:34 +08:00
const result = await fetchRecord();
if (!result?.ok) {
toast(result?.reason === 'not_found' ? '记录不存在' : '请求失败');
2026-01-22 17:39:23 +08:00
setTimeout(() => uni.navigateBack(), 300);
}
});
2026-02-10 15:47:35 +08:00
onMounted(() => {
recordChangedHandler = () => {
needReload.value = true;
};
// 页面在编辑页返回前可能收到事件:先标记,回到页面再刷新
uni.$on('archive-detail:visit-record-changed', recordChangedHandler);
});
onUnmounted(() => {
if (recordChangedHandler) uni.$off('archive-detail:visit-record-changed', recordChangedHandler);
recordChangedHandler = null;
});
onShow(async () => {
if (!needReload.value) return;
needReload.value = false;
await fetchRecord({ silent: true });
});
2026-01-22 17:39:23 +08:00
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: '确定删除当前记录?',
2026-01-27 16:46:36 +08:00
success: async (res) => {
2026-01-22 17:39:23 +08:00
if (!res.confirm) return;
2026-01-27 16:46:36 +08:00
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('删除失败');
}
2026-01-22 17:39:23 +08:00
},
});
}
</script>
<style scoped>
.page {
2026-02-11 17:45:09 +08:00
height: 100vh;
overflow: hidden;
2026-01-22 17:39:23 +08:00
background: #fff;
2026-02-11 17:45:09 +08:00
}
.scroll {
width: 100%;
2026-01-22 17:39:23 +08:00
}
.topbar {
background: #5d6df0;
2026-01-28 20:01:28 +08:00
padding: 20rpx 28rpx;
2026-01-22 17:39:23 +08:00
}
.topbar-text {
color: #fff;
2026-01-28 20:01:28 +08:00
font-size: 28rpx;
2026-01-22 17:39:23 +08:00
text-align: center;
}
.content {
2026-01-28 20:01:28 +08:00
padding: 28rpx 28rpx 0;
2026-01-22 17:39:23 +08:00
}
.section {
2026-01-28 20:01:28 +08:00
margin-bottom: 28rpx;
2026-01-22 17:39:23 +08:00
}
.row {
display: flex;
2026-01-28 20:01:28 +08:00
padding: 20rpx 0;
2026-01-22 17:39:23 +08:00
}
.label {
2026-01-28 20:01:28 +08:00
width: 180rpx;
font-size: 28rpx;
2026-01-22 17:39:23 +08:00
font-weight: 600;
color: #111827;
}
.value {
flex: 1;
2026-01-28 20:01:28 +08:00
font-size: 28rpx;
2026-01-22 17:39:23 +08:00
color: #111827;
word-break: break-all;
}
.h2 {
2026-01-28 20:01:28 +08:00
font-size: 28rpx;
2026-01-22 17:39:23 +08:00
font-weight: 700;
color: #111827;
2026-01-28 20:01:28 +08:00
padding: 16rpx 0;
2026-01-22 17:39:23 +08:00
}
.p {
2026-01-28 20:01:28 +08:00
font-size: 28rpx;
2026-01-22 17:39:23 +08:00
color: #111827;
2026-01-28 20:01:28 +08:00
line-height: 40rpx;
2026-01-22 17:39:23 +08:00
white-space: pre-wrap;
2026-02-11 17:49:44 +08:00
word-break: break-all;
word-wrap: break-word;
2026-01-22 17:39:23 +08:00
}
.files {
display: flex;
2026-01-28 20:01:28 +08:00
gap: 20rpx;
2026-01-22 17:39:23 +08:00
flex-wrap: wrap;
}
.file {
2026-01-28 20:01:28 +08:00
width: 180rpx;
height: 140rpx;
border: 2rpx solid #d1d5db;
2026-01-22 17:39:23 +08:00
background: #f9fafb;
}
.thumb {
2026-01-28 20:01:28 +08:00
width: 180rpx;
height: 140rpx;
2026-01-22 17:39:23 +08:00
}
.files-empty {
2026-01-28 20:01:28 +08:00
font-size: 26rpx;
2026-01-22 17:39:23 +08:00
color: #9aa0a6;
2026-01-28 20:01:28 +08:00
padding: 16rpx 0;
2026-01-22 17:39:23 +08:00
}
2026-02-11 17:45:09 +08:00
.scroll-spacer {
height: calc(152rpx + env(safe-area-inset-bottom));
}
2026-01-22 17:39:23 +08:00
.footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #fff;
2026-01-28 20:01:28 +08:00
padding: 24rpx 28rpx calc(24rpx + env(safe-area-inset-bottom));
2026-01-22 17:39:23 +08:00
display: flex;
justify-content: flex-end;
2026-01-28 20:01:28 +08:00
gap: 28rpx;
box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
2026-01-22 17:39:23 +08:00
}
.btn {
2026-01-28 20:01:28 +08:00
width: 240rpx;
height: 88rpx;
line-height: 88rpx;
border-radius: 12rpx;
font-size: 30rpx;
2026-01-22 17:39:23 +08:00
}
.btn::after {
border: none;
}
.btn.danger {
background: #fff;
color: #ff4d4f;
2026-01-28 20:01:28 +08:00
border: 2rpx solid #ff4d4f;
2026-01-22 17:39:23 +08:00
}
.btn.primary {
2026-02-02 15:15:51 +08:00
background: #0877F1;
2026-01-22 17:39:23 +08:00
color: #fff;
}
</style>