This commit is contained in:
Your Name
2026-03-18 14:53:09 +08:00
parent 338b104d50
commit 7832514f28
315 changed files with 7071 additions and 1136 deletions
+10
View File
@@ -40,6 +40,11 @@ export function checkIdCard(params: any) {
return request.post({ url: '/tcm.diagnosis/checkIdCard', params })
}
// 补全身份证号(自动更新年龄)
export function fillIdCard(params: { id: number; id_card: string }) {
return request.post({ url: '/tcm.diagnosis/fillIdCard', params })
}
// 指派医助
export function tcmDiagnosisAssign(params: any) {
return request.post({ url: '/tcm.diagnosis/assign', params })
@@ -164,3 +169,8 @@ export function prescriptionListByDiagnosis(params: { diagnosis_id: number }) {
export function prescriptionGetByAppointment(params: { appointment_id: number }) {
return request.get({ url: '/tcm.prescription/getByAppointment', params })
}
// 作废处方
export function prescriptionVoid(params: { id: number }) {
return request.post({ url: '/tcm.prescription/void', params })
}
+10 -10
View File
@@ -190,8 +190,8 @@ const open = async (data: { patientId: number; patientName: string; diagnosisId?
visible.value = true
posX.value = 100
posY.value = 80
callKitX.value = Math.max(0, (window.innerWidth - 600) / 2)
callKitY.value = Math.max(0, (window.innerHeight - 436) / 2)
callKitX.value = Math.max(0, (window.innerWidth - 375) / 2)
callKitY.value = Math.max(0, (window.innerHeight - 667) / 2)
patientName.value = data.patientName
patientId.value = data.patientId
diagnosisId.value = data.diagnosisId || null
@@ -549,15 +549,15 @@ defineExpose({ open })
align-items: center;
}
/* TUICallKit 可拖动容器 */
/* TUICallKit 可拖动容器 - 手机尺寸 (375x667) */
.chat-dialog-call-kit-wrapper {
position: fixed;
width: 600px;
height: 436px;
width: 375px;
height: 667px;
max-width: 90vw;
z-index: 300000;
background: #1a1a1a;
border-radius: 12px;
border-radius: 24px;
overflow: hidden;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
display: flex;
@@ -565,8 +565,8 @@ defineExpose({ open })
}
.call-kit-drag-handle {
height: 36px;
padding: 0 16px;
height: 32px;
padding: 0 12px;
background: #2a2a2a;
display: flex;
align-items: center;
@@ -576,7 +576,7 @@ defineExpose({ open })
flex-shrink: 0;
.drag-handle-text {
font-size: 14px;
font-size: 13px;
color: #fff;
}
@@ -603,7 +603,7 @@ defineExpose({ open })
transform: none !important;
max-width: none !important;
max-height: none !important;
border-radius: 0 0 12px 12px;
border-radius: 0 0 24px 24px;
}
</style>
+5
View File
@@ -57,6 +57,7 @@ const emit = defineEmits<{
const editorRef = shallowRef()
const materialPickerRef = shallowRef<InstanceType<typeof MaterialPicker>>()
const fileType = ref('')
const isReady = ref(false)
let insertFn: any
@@ -88,6 +89,7 @@ const valueHtml = computed({
return props.modelValue
},
set(value) {
if (!isReady.value) return
emit('update:modelValue', value)
}
})
@@ -107,6 +109,9 @@ onBeforeUnmount(() => {
const handleCreated = (editor: any) => {
editorRef.value = editor // 记录 editor 实例,重要!
nextTick(() => {
isReady.value = true
})
}
</script>
+127 -34
View File
@@ -43,8 +43,8 @@
<div class="section-title">诊断信息</div>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="象" prop="pulse">
<el-input v-model="formData.pulse" placeholder="象" />
<el-form-item label="象" prop="pulse">
<el-input v-model="formData.pulse" placeholder="象" />
</el-form-item>
</el-col>
<el-col :span="12">
@@ -109,12 +109,17 @@
<div class="info-section">
<el-row :gutter="16">
<el-col :span="8">
<el-form-item label="数" prop="dose_count">
<el-input-number v-model="formData.dose_count" :min="1" :max="30" />
<el-col :span="12">
<el-form-item label="数量规格" prop="dose_count">
<div class="flex gap-2 items-center">
<el-input-number v-model="formData.dose_count" :min="1" :max="999" class="!w-28" />
<el-select v-model="formData.dose_unit" placeholder="单位" class="!w-24">
<el-option v-for="u in doseUnitOptions" :key="u" :label="u" :value="u" />
</el-select>
</div>
</el-form-item>
</el-col>
<el-col :span="16">
<el-col :span="12">
<el-form-item label="用法" prop="usage_instruction">
<el-input v-model="formData.usage_instruction" placeholder="如:水煎服一日二次" />
</el-form-item>
@@ -158,26 +163,36 @@
<div class="prescription-header">
<h2 class="prescription-title">{{ templateConfig.stationName }}处方笺</h2>
<div class="prescription-type">
<div>普通处方</div>
<div class="text-sm">当日有效</div>
<el-tag v-if="savedPrescription.void_status === 1" type="danger" size="small">已作废</el-tag>
<template v-else>
<div>普通处方</div>
<div class="text-sm">当日有效</div>
</template>
</div>
</div>
<div class="prescription-meta">
<span>日期: {{ savedPrescription.prescription_date }}</span>
<span class="ml-4">门诊号: {{ savedPrescription.visit_no }}</span>
<div v-if="savedPrescription.void_status === 1" class="prescription-void-info">
作废人{{ savedPrescription.void_by_name || '' }}作废时间{{ formatVoidTime(savedPrescription.void_time) }}
</div>
<div class="prescription-patient">
<span>姓名: {{ savedPrescription.patient_name }}</span>
<span>性别: {{ savedPrescription.gender_desc }}</span>
<span>年龄: {{ savedPrescription.age }}</span>
<span>电话: {{ savedPrescription.phone }}</span>
</div>
<div class="prescription-patient">
<span>脉象: {{ savedPrescription.pulse || '—' }}</span>
<span>舌象: {{ savedPrescription.tongue || '—' }}</span>
</div>
<div class="prescription-patient">
<span>临床诊断: {{ savedPrescription.clinical_diagnosis }}</span>
<div class="prescription-info">
<div class="info-row">
<span class="info-item"><em>日期</em>{{ savedPrescription.prescription_date }}</span>
<span class="info-item"><em>电话</em>{{ savedPrescription.phone }}</span>
<span class="info-item"><em>门诊号</em>{{ savedPrescription.visit_no }}</span>
</div>
<div class="info-row">
<span class="info-item"><em>姓名</em>{{ savedPrescription.patient_name }}</span>
<span class="info-item"><em>性别</em>{{ savedPrescription.gender_desc }}</span>
<span class="info-item"><em>年龄</em>{{ savedPrescription.age != null ? savedPrescription.age + '岁' : '—' }}</span>
</div>
<div class="info-row">
<span class="info-item" v-if="savedPrescription.pulse"><em>面象</em>{{ savedPrescription.pulse || '—' }}</span>
<span class="info-item" v-if="savedPrescription.tongue"><em>舌象</em>{{ savedPrescription.tongue || '—' }}</span>
</div>
<div class="info-row info-row-full">
<span class="info-item"><em>临床诊断</em>{{ savedPrescription.clinical_diagnosis }}</span>
</div>
</div>
<div class="prescription-rp">
<div class="rp-label">RP</div>
@@ -197,7 +212,7 @@
<div class="prescription-footer">
<div class="footer-left">
<div class="footer-dosage">
{{ savedPrescription.dose_count }} , {{ savedPrescription.usage_instruction }}
{{ savedPrescription.dose_count }}{{ savedPrescription.dose_unit || '剂' }}, {{ savedPrescription.usage_instruction }}
</div>
<div class="footer-amount">金额 {{ savedPrescription.amount }}</div>
</div>
@@ -212,7 +227,7 @@
/>
<span v-else>{{ savedPrescription.doctor_name || '医师' }}</span>
</span>
<span>核对发药</span>
<!-- <span>核对发药</span> -->
</div>
</div>
</div>
@@ -226,6 +241,15 @@
<el-icon><Document /></el-icon>
下载PDF
</el-button>
<el-button
v-if="savedPrescription.void_status !== 1"
type="danger"
plain
:loading="voiding"
@click="handleVoid"
>
作废处方
</el-button>
<el-button @click="handleNewPrescription">新建处方</el-button>
<el-button @click="handleClose">关闭</el-button>
</div>
@@ -242,7 +266,7 @@
<script setup lang="ts">
import feedback from '@/utils/feedback'
import { prescriptionAdd, prescriptionDetail, prescriptionGetByAppointment } from '@/api/tcm'
import { prescriptionAdd, prescriptionDetail, prescriptionGetByAppointment, prescriptionVoid } from '@/api/tcm'
import { getDictData } from '@/api/app'
import html2canvas from 'html2canvas'
import { jsPDF } from 'jspdf'
@@ -269,6 +293,7 @@ interface PrescriptionForm {
clinical_diagnosis: string
herbs: Herb[]
dose_count: number
dose_unit: string
usage_instruction: string
amount: number
doctor_name: string
@@ -280,13 +305,14 @@ const emit = defineEmits(['success'])
const visible = ref(false)
const formRef = ref()
const saving = ref(false)
const voiding = ref(false)
const prescriptionPrintRef = ref<HTMLElement>()
const signatureCanvasRef = ref<HTMLCanvasElement>()
const isDrawing = ref(false)
const savedPrescription = ref<any>(null)
const templateConfig = reactive({
stationName: '卫生服务站',
stationName: '成都双流甄养堂互联网医院',
showDisclaimer: true,
disclaimer: ''
})
@@ -306,6 +332,7 @@ const formData = reactive<PrescriptionForm>({
clinical_diagnosis: '',
herbs: [],
dose_count: 1,
dose_unit: '剂',
usage_instruction: '水煎服一日二次',
amount: 0,
doctor_name: '',
@@ -314,6 +341,8 @@ const formData = reactive<PrescriptionForm>({
const userStore = useUserStore()
const doseUnitOptions = ['剂', '丸', '袋', '盒', '瓶', '膏', '贴', '包', '片', '粒']
const diagnosisTypeOptions = ref<any[]>([])
const syndromeTypeOptions = ref<any[]>([])
@@ -381,6 +410,7 @@ const open = async (data: any, options?: { templateId?: number; stationName?: st
formData.clinical_diagnosis = buildClinicalDiagnosis(diagnosis)
formData.herbs = []
formData.dose_count = 1
formData.dose_unit = '剂'
formData.usage_instruction = '水煎服一日二次'
formData.amount = 0
formData.doctor_name = userStore.userInfo?.name || ''
@@ -527,6 +557,7 @@ const handleSave = async () => {
clinical_diagnosis: formData.clinical_diagnosis,
herbs: formData.herbs,
dose_count: formData.dose_count,
dose_unit: formData.dose_unit || '剂',
usage_instruction: formData.usage_instruction,
amount: formData.amount,
doctor_name: formData.doctor_name,
@@ -547,6 +578,30 @@ const handleSave = async () => {
}
}
const formatVoidTime = (ts: number | null | undefined) => {
if (!ts) return '—'
const d = new Date(ts * 1000)
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`
}
const handleVoid = async () => {
const id = savedPrescription.value?.id
if (!id) return
try {
await feedback.confirm('确定要作废该处方吗?作废后不可恢复。')
voiding.value = true
await prescriptionVoid({ id })
feedback.msgSuccess('作废成功')
const detail = await prescriptionDetail({ id })
savedPrescription.value = detail
emit('success')
} catch (e: any) {
if (e !== 'cancel' && e?.message !== 'cancel') feedback.msgError(e?.msg || '作废失败')
} finally {
voiding.value = false
}
}
const handleNewPrescription = () => {
const saved = savedPrescription.value
if (saved) {
@@ -564,6 +619,7 @@ const handleNewPrescription = () => {
formData.tongue = saved.tongue || ''
formData.clinical_diagnosis = saved.clinical_diagnosis || ''
formData.dose_count = 1
formData.dose_unit = saved.dose_unit || '剂'
formData.usage_instruction = '水煎服一日二次'
formData.amount = 0
formData.doctor_name = userStore.userInfo?.name || saved.doctor_name || ''
@@ -682,9 +738,18 @@ defineExpose({
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 16px;
margin-bottom: 12px;
padding-bottom: 12px;
border-bottom: 1px solid #ddd;
}
.prescription-void-info {
font-size: 13px;
color: var(--el-color-danger);
margin-bottom: 12px;
padding: 8px 12px;
background: #fef0f0;
border-radius: 4px;
.prescription-title {
font-size: 20px;
@@ -698,15 +763,43 @@ defineExpose({
}
}
.prescription-meta {
margin-bottom: 8px;
.prescription-info {
margin-bottom: 16px;
padding: 12px 0;
border-bottom: 1px solid #eee;
}
.prescription-patient {
margin-bottom: 6px;
.info-row {
display: flex;
margin-bottom: 10px;
span {
margin-right: 16px;
&:last-child {
margin-bottom: 0;
}
.info-item {
flex: 1;
min-width: 0;
}
}
.info-row-full {
.info-item {
flex: 1;
min-width: 100%;
}
}
.info-item {
display: inline-flex;
align-items: baseline;
gap: 6px;
font-size: 14px;
em {
font-style: normal;
color: #909399;
min-width: 56px;
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
<template>
<main class="main-wrap h-full bg-page">
<el-scrollbar>
<div class="p-4">
<div class="px-2 py-4">
<router-view v-if="isRouteShow" v-slot="{ Component, route }">
<keep-alive :include="includeList" :max="20">
<component :is="Component" :key="route.fullPath" />
+11 -2
View File
@@ -108,7 +108,9 @@
<!-- 所属科室 -->
<el-form-item label="所属科室" prop="department">
<el-input v-model="formData.department" placeholder="如:中医科、内科" clearable />
<el-select v-model="formData.department" placeholder="请选择所属科室" clearable class="flex-1">
<el-option v-for="item in departmentOptions" :key="item.value" :label="item.name" :value="item.value" />
</el-select>
</el-form-item>
<!-- 擅长领域 -->
@@ -209,6 +211,7 @@ import type { FormInstance } from 'element-plus'
import { adminAdd, adminDetail, adminEdit } from '@/api/perms/admin'
import { deptAll } from '@/api/org/department'
import { jobsAll } from '@/api/org/post'
import { getDictData } from '@/api/app'
import { useDictOptions } from '@/hooks/useDictOptions'
import feedback from '@/utils/feedback'
@@ -218,6 +221,12 @@ const visible = ref(false)
const mode = ref('add')
const loading = ref(false)
const departmentOptions = ref<any[]>([])
const fetchDepartmentOptions = async () => {
const data = await getDictData({ type: 'department' })
departmentOptions.value = data?.department || []
}
const drawerTitle = computed(() => {
return mode.value == 'edit' ? '编辑医助' : '新增医助'
})
@@ -345,7 +354,7 @@ const handleSubmit = async () => {
const open = (type = 'add') => {
mode.value = type
visible.value = true
fetchDepartmentOptions()
// 重置表单
if (type === 'add') {
Object.assign(formData, {
+11 -1
View File
@@ -137,7 +137,9 @@
<!-- 所属科室 -->
<el-form-item label="所属科室" prop="department">
<el-input v-model="formData.department" placeholder="如:中医科、内科" clearable />
<el-select v-model="formData.department" placeholder="请选择所属科室" clearable class="flex-1">
<el-option v-for="item in departmentOptions" :key="item.value" :label="item.name" :value="item.value" />
</el-select>
</el-form-item>
<!-- 擅长领域 -->
@@ -238,6 +240,7 @@ import type { FormInstance } from 'element-plus'
import { adminAdd, adminDetail, adminEdit } from '@/api/perms/admin'
import { deptAll } from '@/api/org/department'
import { jobsAll } from '@/api/org/post'
import { getDictData } from '@/api/app'
import { useDictOptions } from '@/hooks/useDictOptions'
import feedback from '@/utils/feedback'
@@ -247,6 +250,12 @@ const visible = ref(false)
const mode = ref('add')
const loading = ref(false)
const departmentOptions = ref<any[]>([])
const fetchDepartmentOptions = async () => {
const data = await getDictData({ type: 'department' })
departmentOptions.value = data?.department || []
}
const drawerTitle = computed(() => {
return mode.value == 'edit' ? '编辑医生' : '新增医生'
})
@@ -377,6 +386,7 @@ const handleSubmit = async () => {
const open = (type = 'add') => {
mode.value = type
visible.value = true
fetchDepartmentOptions()
// 重置表单
if (type === 'add') {
+23 -3
View File
@@ -24,13 +24,28 @@
<editor class="mb-10" v-model="formData.privacy_content" height="500"></editor>
</el-card>
</div>
<div class="xl:flex">
<el-card class="!border-none flex-1 mb-4" shadow="never">
<template #header>
<span class="font-medium">卫健委备案信息</span>
</template>
<el-form :model="formData" label-width="80px">
<el-form-item label="协议名称">
<el-input v-model="formData.health_title" />
</el-form-item>
</el-form>
<editor class="mb-10" v-model="formData.health_content" height="500"></editor>
</el-card>
</div>
<footer-btns v-perms="['setting.web.web_setting/setAgreement']">
<el-button type="primary" @click="handleProtocolEdit">保存</el-button>
</footer-btns>
</template>
<script setup lang="ts" naem="webProtocol">
<script setup lang="ts" name="webProtocol">
import { getProtocol, setProtocol } from '@/api/setting/website'
interface formDataObj {
@@ -38,15 +53,20 @@ interface formDataObj {
service_content: string
privacy_title: string
privacy_content: string
health_title: string
health_content: string
}
const formData = ref<formDataObj>({
service_title: '',
service_content: '',
privacy_title: '',
privacy_content: ''
privacy_content: '',
health_title: '',
health_content: ''
})
const protocolGet = async () => {
formData.value = await getProtocol()
const data = await getProtocol()
Object.assign(formData.value, data)
}
const handleProtocolEdit = async (): Promise<void> => {
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,95 @@
<template>
<div class="case-record-list">
<el-table :data="caseList" border v-loading="loading">
<el-table-column prop="prescription_date" label="就诊日期" width="120" />
<el-table-column prop="visit_no" label="门诊号" width="120" />
<el-table-column prop="clinical_diagnosis" label="临床诊断" min-width="160" show-overflow-tooltip />
<el-table-column label="处方摘要" min-width="180">
<template #default="{ row }">
<span v-if="row.herbs && row.herbs.length">
{{ row.herbs.slice(0, 3).map((h: any) => `${h.name}${h.dosage}`).join('、') }}{{ row.herbs.length > 3 ? '...' : '' }}
</span>
<span v-else class="text-gray-400"></span>
</template>
</el-table-column>
<el-table-column prop="doctor_name" label="医师" width="90" show-overflow-tooltip />
<el-table-column label="状态" width="140" align="center">
<template #default="{ row }">
<template v-if="row.void_status === 1">
<el-tag type="danger" size="small">已作废</el-tag>
<div class="void-detail text-xs text-gray-500 mt-1">
{{ row.void_by_name || '—' }} {{ formatVoidTime(row.void_time) }}
</div>
</template>
<el-tag v-else type="success" size="small">正常</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button link type="primary" size="small" @click="handleView(row)">
查看
</el-button>
</template>
</el-table-column>
</el-table>
<el-empty v-if="!loading && caseList.length === 0" description="暂无病例记录,开方后会自动显示" class="mt-4" />
</div>
</template>
<script setup lang="ts">
import { prescriptionListByDiagnosis } from '@/api/tcm'
const props = defineProps({
diagnosisId: {
type: Number,
default: 0
}
})
const emit = defineEmits(['view'])
const caseList = ref<any[]>([])
const loading = ref(false)
const getCases = async () => {
if (!props.diagnosisId) return
loading.value = true
try {
const data = await prescriptionListByDiagnosis({ diagnosis_id: props.diagnosisId })
caseList.value = Array.isArray(data) ? data : []
} catch (error) {
console.error('获取病例记录失败:', error)
caseList.value = []
} finally {
loading.value = false
}
}
const formatVoidTime = (ts: number | null | undefined) => {
if (!ts) return ''
const d = new Date(ts * 1000)
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
}
const handleView = (row: any) => {
emit('view', row)
}
onMounted(() => {
getCases()
})
watch(() => props.diagnosisId, () => {
getCases()
})
defineExpose({
refresh: getCases
})
</script>
<style lang="scss" scoped>
.case-record-list {
padding: 20px;
}
</style>
+132 -28
View File
@@ -79,19 +79,7 @@
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="诊断日期" prop="diagnosis_date">
<el-date-picker
v-model="formData.diagnosis_date"
type="date"
placeholder="请选择诊断日期"
value-format="YYYY-MM-DD"
class="w-full"
:popper-options="{ strategy: 'fixed' }"
popper-class="high-z-index"
/>
</el-form-item>
</el-col>
</el-row>
@@ -257,6 +245,19 @@
<el-divider content-position="left">主诉</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="线下诊断日期" prop="diagnosis_date">
<el-date-picker
v-model="formData.diagnosis_date"
type="date"
placeholder="请选择诊断日期"
value-format="YYYY-MM-DD"
class="w-full"
:popper-options="{ strategy: 'fixed' }"
popper-class="high-z-index"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发现糖尿病就患病史" prop="diabetes_discovery_year">
<el-input-number
@@ -289,15 +290,13 @@
<el-divider content-position="left">现病史</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="口腔感觉" class="compact-form-item">
<el-radio-group v-model="formData.appetite">
<el-radio-button v-for="item in appetiteOptions" :key="item.value" :label="item.value">
{{ item.name }}
</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-form-item label="口腔感觉" class="checkbox-form-item">
<el-checkbox-group v-model="formData.appetite">
<el-checkbox-button v-for="item in appetiteOptions" :key="item.value" :label="item.value">
{{ item.name }}
</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
</el-row>
<el-row :gutter="20">
@@ -413,7 +412,7 @@
</el-checkbox-button>
</el-checkbox-group>
</el-form-item>
<el-form-item label="病逝补充" prop="symptoms">
<el-form-item label="其他补充" prop="symptoms">
<el-input
v-model="formData.symptoms"
type="textarea"
@@ -508,7 +507,7 @@
</el-form-item>
<el-row :gutter="20">
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="舌苔" prop="tongue_coating">
<el-input
@@ -552,7 +551,7 @@
:rows="3"
placeholder="请输入医嘱"
/>
</el-form-item>
</el-form-item> -->
<el-form-item label="备注" prop="remark">
<el-input
@@ -574,7 +573,56 @@
/>
<el-empty v-else description="请先保存诊单后再添加血糖血压记录" />
</el-tab-pane>
<!-- 病例记录标签页开方后自动显示 -->
<el-tab-pane label="病例" name="bingli" :disabled="!formData.id">
<div v-if="formData.id" class="bingli-tab-content">
<!-- 诊断信息舌苔照片检查报告 -->
<div class="bingli-diagnosis-section">
<el-divider content-position="left">诊断信息</el-divider>
<el-row :gutter="24">
<el-col :span="12">
<div class="bingli-label">舌苔照片</div>
<div v-if="formData.tongue_images?.length" class="bingli-images">
<el-image
v-for="(img, idx) in formData.tongue_images"
:key="idx"
:src="getImageUrl(img)"
:preview-src-list="(formData.tongue_images || []).map((u: string) => getImageUrl(u))"
class="bingli-img"
fit="cover"
/>
</div>
<span v-else class="bingli-empty">暂无</span>
</el-col>
<el-col :span="12">
<div class="bingli-label">检查报告</div>
<div v-if="formData.report_files?.length" class="bingli-images">
<el-image
v-for="(file, idx) in formData.report_files"
:key="idx"
:src="getImageUrl(file)"
:preview-src-list="(formData.report_files || []).map((u: string) => getImageUrl(u))"
class="bingli-img"
fit="cover"
/>
</div>
<span v-else class="bingli-empty">暂无</span>
</el-col>
</el-row>
</div>
<!-- 病例记录列表 -->
<case-record-list
ref="caseRecordListRef"
:diagnosis-id="Number(formData.id)"
@view="handleViewCase"
/>
</div>
<el-empty v-else description="请先保存诊单开方后病例将在此显示" />
</el-tab-pane>
</el-tabs>
<!-- 处方详情(查看病例) -->
<tcm-prescription ref="prescriptionRef" @success="caseRecordListRef?.refresh?.()" />
<template #footer>
<div class="flex justify-end gap-3 px-4 pb-4">
@@ -599,11 +647,18 @@ import { tcmDiagnosisAdd, tcmDiagnosisEdit, tcmDiagnosisDetail, checkPhone, chec
import { getDictData } from '@/api/app'
import feedback from '@/utils/feedback'
import useUserStore from '@/stores/modules/user'
import useAppStore from '@/stores/modules/app'
import { ElMessage } from 'element-plus'
import { QuestionFilled } from '@element-plus/icons-vue'
import BloodRecordList from './components/BloodRecordList.vue'
import CaseRecordList from './components/CaseRecordList.vue'
import TcmPrescription from '@/components/tcm-prescription/index.vue'
const emit = defineEmits(['success'])
const appStore = useAppStore()
const getImageUrl = (url: string) => (url?.indexOf?.('http') === 0 ? url : appStore.getImageUrl(url || ''))
const caseRecordListRef = ref()
const prescriptionRef = ref()
const visible = ref(false)
const formRef = ref()
@@ -634,7 +689,7 @@ const formData = ref({
systolic_pressure: undefined as number | undefined,
diastolic_pressure: undefined as number | undefined,
fasting_blood_sugar: undefined as number | undefined,
appetite: '',
appetite: [] as string[],
water_intake: '',
diet_condition: [],
weight_change: '',
@@ -811,6 +866,18 @@ const handleIdCardBlur = async () => {
if (!formData.value.id_card || !/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(formData.value.id_card)) {
return
}
// 从身份证提取出生日期计算年龄
const id = formData.value.id_card
const birthYear = parseInt(id.substring(6, 10))
const birthMonth = parseInt(id.substring(10, 12))
const birthDay = parseInt(id.substring(12, 14))
const today = new Date()
let age = today.getFullYear() - birthYear
if (today.getMonth() + 1 < birthMonth || (today.getMonth() + 1 === birthMonth && today.getDate() < birthDay)) {
age--
}
formData.value.age = age
try {
const result = await checkIdCard({
@@ -876,6 +943,10 @@ const handleSubmit = async () => {
}
}
const handleViewCase = (row: any) => {
prescriptionRef.value?.openById(row.id)
}
const handleClose = () => {
formRef.value?.resetFields()
formData.value = {
@@ -896,7 +967,7 @@ const handleClose = () => {
diabetes_discovery_year: undefined as number | undefined,
local_hospital_diagnosis: [],
local_hospital_name: '',
appetite: '',
appetite: [] as string[],
water_intake: '',
diet_condition: [],
weight_change: '',
@@ -932,7 +1003,8 @@ const handleClose = () => {
}
defineExpose({
open
open,
refreshCaseList: () => caseRecordListRef.value?.refresh?.()
})
</script>
@@ -1042,6 +1114,38 @@ defineExpose({
line-height: 1.5;
}
/* 病例 tab 诊断信息 */
.bingli-tab-content {
padding: 0 4px;
}
.bingli-diagnosis-section {
margin-bottom: 24px;
padding: 16px;
background: #f5f7fa;
border-radius: 6px;
}
.bingli-label {
font-size: 13px;
font-weight: 500;
color: #606266;
margin-bottom: 10px;
}
.bingli-images {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.bingli-img {
width: 80px;
height: 80px;
border-radius: 4px;
cursor: pointer;
}
.bingli-empty {
font-size: 13px;
color: #909399;
}
// 输入框样式优化
:deep(.el-input__inner),
:deep(.el-textarea__inner) {
File diff suppressed because it is too large Load Diff