ykt-wxapp/pages/case/medical-case-form.vue

278 lines
7.2 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.

<template>
<view class="page">
<view class="body">
<scroll-view scroll-y class="scroll">
<view class="header">
<view class="header-title">{{ pageTitle }}</view>
</view>
<view class="form-wrap">
<FormTemplate v-if="temp" ref="formRef" :items="showItems" :form="form" @change="onChange" />
</view>
<view style="height: 240rpx;"></view>
</scroll-view>
<view class="footer">
<button class="btn plain" @click="handleRegenerate">重新生成</button>
<button class="btn primary" @click="handleSave">保存至档案</button>
</view>
</view>
</view>
</template>
<script setup>
import { computed, reactive, ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import dayjs from 'dayjs';
import { storeToRefs } from 'pinia';
import FormTemplate from '@/components/form-template/index.vue';
import api from '@/utils/api.js';
import useAccountStore from '@/store/account';
import { toast, confirm, loading as uniLoading, hideLoading } from '@/utils/widget';
import { normalizeVisitRecordFormData } from './utils/visit-record';
import { normalizeTemplate, unwrapTemplateResponse } from './utils/template';
const caseType = ref('');
const customerId = ref('');
const groupId = ref('');
const accountStore = useAccountStore();
const { account, doctorInfo } = storeToRefs(accountStore);
const { getDoctorInfo } = accountStore;
async function ensureDoctor() {
if (doctorInfo.value) return;
if (!account.value?.openid) return;
try {
await getDoctorInfo();
} catch {
// ignore
}
}
function getUserId() {
const d = doctorInfo.value || {};
const a = account.value || {};
return String(d.userid || d.userId || d.corpUserId || a.userid || a.userId || '') || '';
}
function getCorpId() {
const d = doctorInfo.value || {};
const a = account.value || {};
const t = uni.getStorageSync('ykt_case_current_team') || {};
return String(d.corpId || a.corpId || t.corpId || '') || '';
}
const temp = ref(null);
const titleText = computed(() => {
const t = temp.value || {};
return String(t.name || t.templateName || t.templateTypeName || '').trim();
});
const pageTitle = computed(() => {
const name = titleText.value;
return name ? `添加${name}` : '添加病历';
});
const form = reactive({});
const forms = computed(() => form);
const showItems = computed(() => {
const list = temp.value?.templateList || [];
return list.filter((i) => {
if (i?.type === 'files') return false;
if (i && typeof i.referenceField === 'string') {
return forms.value[i.referenceField] === i.referenceValue;
}
return true;
});
});
const formRef = ref(null);
function onChange({ title, value }) {
form[title] = value;
const item = showItems.value.find((i) => i.title === title);
if (!item) return;
const relat = (temp.value?.templateList || []).filter((i) => i.referenceField === title);
relat.forEach((i) => (form[i.title] = ''));
}
function setDefaultDates() {
const timeKey = temp.value?.service?.timeTitle || '';
if (timeKey && !form[timeKey]) form[timeKey] = dayjs().format('YYYY-MM-DD');
}
function applyInitialFormData(raw) {
const normalized = normalizeVisitRecordFormData(caseType.value, raw);
Object.assign(form, normalized);
setDefaultDates();
}
async function loadTemplate(t) {
const corpId = getCorpId();
if (!corpId) return null;
try {
const res = await api('getCurrentTemplate', { corpId, templateType: t });
if (!res?.success) {
toast(res?.message || '获取模板失败');
return null;
}
const raw = unwrapTemplateResponse(res);
return normalizeTemplate(raw);
} catch (e) {
console.error('loadTemplate error:', e);
toast('获取模板失败');
return null;
}
}
onLoad(async (options) => {
caseType.value = options?.caseType || options?.type || '';
customerId.value = options?.patientId || options?.memberId || '';
groupId.value = options?.groupId || '';
if (!caseType.value) caseType.value = 'outpatient';
temp.value = await loadTemplate(caseType.value);
if (temp.value?.templateType) caseType.value = String(temp.value.templateType);
if (options?.formData) {
try {
const parsed = JSON.parse(decodeURIComponent(options.formData));
applyInitialFormData(parsed);
} catch (e) {
console.error('解析表单数据失败:', e);
applyInitialFormData({});
}
} else {
applyInitialFormData({});
}
uni.setNavigationBarTitle({ title: pageTitle.value });
});
async function handleRegenerate() {
try {
await confirm('确定要重新生成吗?当前编辑的内容将被覆盖');
} catch {
return;
}
uni.navigateBack({
success: () => {
uni.$emit('regenerateMedicalCase', {
caseType: caseType.value,
customerId: customerId.value,
groupId: groupId.value,
});
},
});
}
async function handleSave() {
if (!customerId.value) return toast('缺少患者信息');
await ensureDoctor();
const corpId = getCorpId();
const userId = getUserId();
if (!corpId || !userId) return toast('缺少用户信息');
if (formRef.value?.verify && !formRef.value.verify()) return;
const params = {
...form,
corpId,
memberId: customerId.value,
medicalType: caseType.value,
creator: userId,
};
// 门诊/住院与模板字段对齐diagnosisName
if ((caseType.value === 'outpatient' || caseType.value === 'inhospital') && form.diagnosis && !form.diagnosisName) {
params.diagnosisName = form.diagnosis;
}
const sortTimeKey = temp.value?.service?.timeTitle || '';
if (sortTimeKey && form[sortTimeKey] && dayjs(form[sortTimeKey]).isValid()) {
params.sortTime = dayjs(form[sortTimeKey]).valueOf();
} else {
params.sortTime = Date.now();
}
uniLoading('保存中...');
try {
const res = await api('addMedicalRecord', params);
hideLoading();
if (res.success) {
uni.$emit('archive-detail:visit-record-changed');
toast(res.message || '保存成功');
setTimeout(() => uni.navigateBack(), 300);
} else {
toast(res.message || '保存失败');
}
} catch (error) {
hideLoading();
console.error('保存病历失败:', error);
toast('保存失败,请重试');
}
}
</script>
<style scoped>
.page {
min-height: 100vh;
background: #f5f6f8;
padding-bottom: calc(152rpx + env(safe-area-inset-bottom));
}
.body {
height: 100vh;
display: flex;
flex-direction: column;
}
.scroll {
flex: 1;
}
.header {
background: #fff;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06);
}
.header-title {
padding: 28rpx 28rpx;
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.form-wrap {
background: #fff;
margin-top: 20rpx;
padding: 8rpx 0;
}
.footer {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #fff;
padding: 24rpx 28rpx calc(24rpx + env(safe-area-inset-bottom));
display: flex;
gap: 24rpx;
box-shadow: 0 -8rpx 24rpx rgba(0, 0, 0, 0.06);
}
.btn {
flex: 1;
height: 88rpx;
line-height: 88rpx;
border-radius: 12rpx;
font-size: 30rpx;
}
.btn::after {
border: none;
}
.btn.plain {
background: #fff;
color: #0877F1;
border: 2rpx solid #0877F1;
}
.btn.primary {
background: #0877F1;
color: #fff;
}
</style>