完成100需求,补充99需求追溯术中产生的费用新增费用项时向表中插入SourceBillNo和generate_source_enum字段值
This commit is contained in:
@@ -59,4 +59,13 @@ export function exportSurgerySchedule(query) {
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
//签名密码验证
|
||||
export function checkPassword(params) {
|
||||
return request({
|
||||
url: '/clinical-manage/surgery-schedule/checkPassword',
|
||||
method: 'POST',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
@@ -55,6 +55,9 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Money" @click="handleChargeCharge(selectedRow)" :disabled="!selectedRow"> 计费 </el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Document" @click="handleMedicalAdvice(selectedRow)" :disabled="!selectedRow"> 医嘱 </el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Download" @click="handleExport">导出表格</el-button>
|
||||
</el-col>
|
||||
@@ -62,7 +65,7 @@
|
||||
</el-row>
|
||||
|
||||
<!-- 中部表格区 -->
|
||||
<el-table v-loading="loading" :data="surgeryList" row-key="scheduleId" :row-class-name="getRowClassName" highlight-current-row @current-change="handleCurrentChange">
|
||||
<el-table v-loading="loading" :data="surgeryList" row-key="scheduleId" :row-class-name="getRowClassName" @current-change="handleCurrentChange">
|
||||
<el-table-column label="ID" align="center" width="80">
|
||||
<template #default="{ $index }">
|
||||
{{ (applyQueryParams.pageNo - 1) * applyQueryParams.pageSize + $index + 1 }}
|
||||
@@ -799,6 +802,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 临时医嘱弹窗 -->
|
||||
<el-dialog :title="temporaryMedicalTitle" v-model="showTemporaryMedical" width="80%" append-to-body :close-on-click-modal="false">
|
||||
<temporary-medical
|
||||
:patient-info="temporaryPatientInfo"
|
||||
:billing-medicines="temporaryBillingMedicines"
|
||||
v-model:temporary-advices="temporaryAdvices"
|
||||
@submit="handleTemporaryMedicalSubmit"
|
||||
@cancel="handleTemporaryMedicalCancel"
|
||||
@delete-advice="handleDeleteTemporaryAdvice"
|
||||
/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -810,6 +825,9 @@ import { useDict } from '@/utils/dict'
|
||||
import download from '@/plugins/download'
|
||||
import Prescriptionlist from '@/views/clinicmanagement/bargain/component/prescriptionlist.vue'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { ElMessage } from 'element-plus'
|
||||
// 导入计费相关接口
|
||||
import { getPrescriptionList } from '@/views/clinicmanagement/bargain/component/api'
|
||||
|
||||
// API 导入
|
||||
import { getSurgerySchedulePage, addSurgerySchedule, updateSurgerySchedule, deleteSurgerySchedule, getSurgeryScheduleDetail } from '@/api/surgicalschedule'
|
||||
@@ -820,6 +838,7 @@ import { getTestResultPage} from '@/views/inpatientDoctor/home/components/applic
|
||||
import { getTenantPage } from '@/api/system/tenant'
|
||||
import { getContract } from '@/views/inpatientDoctor/home/components/api.js'
|
||||
import SurgeryCharge from '../charge/surgerycharge/index.vue'
|
||||
import TemporaryMedical from './temporaryMedical.vue'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const userStore = useUserStore()
|
||||
@@ -947,6 +966,13 @@ const chargePatientInfo = ref({})
|
||||
const chargeSurgeryInfo = ref({})
|
||||
const prescriptionRef = ref()
|
||||
|
||||
// 临时医嘱弹窗
|
||||
const showTemporaryMedical = ref(false)
|
||||
const temporaryMedicalTitle = ref('门诊术中临时医嘱')
|
||||
const temporaryPatientInfo = ref({})
|
||||
const temporaryBillingMedicines = ref([])
|
||||
const temporaryAdvices = ref([])
|
||||
|
||||
// 下拉列表数据
|
||||
const orgList = ref([])
|
||||
const deptList = ref([])
|
||||
@@ -1026,8 +1052,7 @@ function loadOrgList() {
|
||||
orgList.value = []
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('加载卫生机构列表失败:', error)
|
||||
.catch(() => {
|
||||
proxy.$modal.msgError('获取卫生机构列表失败')
|
||||
orgList.value = []
|
||||
})
|
||||
@@ -1046,7 +1071,6 @@ function loadDeptList() {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('加载科室列表失败:', error)
|
||||
proxy.$modal.msgError('获取科室列表失败')
|
||||
deptList.value = []
|
||||
})
|
||||
@@ -1065,7 +1089,6 @@ function loadDoctorList() {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('加载医生列表失败:', error)
|
||||
proxy.$modal.msgError('获取医生列表失败')
|
||||
doctorList.value = []
|
||||
})
|
||||
@@ -1084,7 +1107,6 @@ function loadNurseList() {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('加载护士列表失败:', error)
|
||||
proxy.$modal.msgError('获取护士列表失败')
|
||||
nurseList.value = []
|
||||
})
|
||||
@@ -1103,7 +1125,6 @@ function loadOperatingRoomList() {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('加载手术室列表失败:', error)
|
||||
proxy.$modal.msgError('获取手术室列表失败')
|
||||
operatingRoomList.value = []
|
||||
})
|
||||
@@ -1116,7 +1137,6 @@ function getList() {
|
||||
surgeryList.value = res.data.records
|
||||
total.value = res.data.total
|
||||
}).catch(error => {
|
||||
console.error('获取手术安排列表失败:', error)
|
||||
proxy.$modal.msgError('获取手术安排列表失败,请稍后重试')
|
||||
surgeryList.value = []
|
||||
total.value = 0
|
||||
@@ -1170,8 +1190,7 @@ function handleEdit(row) {
|
||||
} else {
|
||||
proxy.$modal.msgError('获取手术安排详情失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取手术安排详情失败:', error)
|
||||
}).catch(() => {
|
||||
proxy.$modal.msgError('获取手术安排详情失败')
|
||||
})
|
||||
open.value = true
|
||||
@@ -1190,8 +1209,7 @@ function handleView(row) {
|
||||
} else {
|
||||
proxy.$modal.msgError('获取手术安排详情失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取手术安排详情失败:', error)
|
||||
}).catch(() => {
|
||||
proxy.$modal.msgError('获取手术安排详情失败')
|
||||
})
|
||||
open.value = true
|
||||
@@ -1215,7 +1233,8 @@ function handleDelete(row) {
|
||||
}).then(() => {
|
||||
getPageList()
|
||||
proxy.$modal.msgSuccess('手术安排已取消')
|
||||
}).catch(error => {
|
||||
}).catch(() => {
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1232,32 +1251,18 @@ async function handleChargeCharge(row) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log('计费按钮被点击,行数据:', row)
|
||||
|
||||
// 检查用户信息中的机构信息
|
||||
console.log('完整的用户信息:', JSON.stringify(userStore, null, 2))
|
||||
console.log('用户机构信息:', {
|
||||
organizationId: userStore.organizationId,
|
||||
orgId: userStore.orgId,
|
||||
tenantId: userStore.tenantId,
|
||||
userInfo: userStore.userInfo
|
||||
})
|
||||
|
||||
// 调用接口获取账户信息
|
||||
let accountId = null
|
||||
try {
|
||||
const contractResult = await getContract({ encounterId: row.visitId })
|
||||
console.log('账户信息接口返回:', contractResult)
|
||||
|
||||
if (contractResult.code === 200 && contractResult.data && contractResult.data.length > 0) {
|
||||
// 从返回数据中提取accountId - data是数组,取第一个元素的accountId
|
||||
accountId = contractResult.data[0].accountId || contractResult.data[0].id
|
||||
console.log('获取到的accountId:', accountId)
|
||||
} else {
|
||||
console.warn('获取账户信息失败:', contractResult.msg)
|
||||
proxy.$modal.msgError('获取账户信息失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('调用账户信息接口出错:', error)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置计费弹窗数据 - 直接复制划价页面的逻辑
|
||||
@@ -1279,7 +1284,9 @@ async function handleChargeCharge(row) {
|
||||
// 添加账户ID
|
||||
accountId: accountId,
|
||||
// 添加手术申请单号用于追溯
|
||||
sourceBillNo: row.applyId || row.operCode
|
||||
sourceBillNo: row.applyId,
|
||||
//添加计费标志手术计费
|
||||
generateSourceEnum: 6
|
||||
}
|
||||
|
||||
chargeSurgeryInfo.value = {
|
||||
@@ -1287,21 +1294,12 @@ async function handleChargeCharge(row) {
|
||||
surgeryNo: row.operCode
|
||||
}
|
||||
|
||||
console.log('计费弹窗数据设置完成:', {
|
||||
chargeDialogTitle: chargeDialogTitle.value,
|
||||
chargePatientInfo: chargePatientInfo.value,
|
||||
chargeSurgeryInfo: chargeSurgeryInfo.value
|
||||
})
|
||||
|
||||
// 打开计费弹窗
|
||||
showChargeDialog.value = true
|
||||
console.log('计费弹窗状态:', showChargeDialog.value)
|
||||
|
||||
// 延迟加载处方列表,确保组件已经渲染
|
||||
nextTick(() => {
|
||||
console.log('nextTick执行,prescriptionRef:', prescriptionRef.value)
|
||||
if (prescriptionRef.value && prescriptionRef.value.getListInfo) {
|
||||
console.log('调用prescriptionRef.getListInfo()')
|
||||
prescriptionRef.value.getListInfo()
|
||||
}
|
||||
})
|
||||
@@ -1314,6 +1312,114 @@ function closeChargeDialog() {
|
||||
chargeSurgeryInfo.value = {}
|
||||
}
|
||||
|
||||
// 处理医嘱按钮点击事件
|
||||
function handleMedicalAdvice(row) {
|
||||
// 如果没有传入行数据,使用选中的行
|
||||
if (!row && selectedRow.value) {
|
||||
row = selectedRow.value
|
||||
}
|
||||
|
||||
// 如果还是没有行数据,显示提示
|
||||
if (!row) {
|
||||
proxy.$modal.msgWarning('请先选择要开具医嘱的手术安排')
|
||||
return
|
||||
}
|
||||
|
||||
// 设置临时医嘱弹窗数据
|
||||
temporaryPatientInfo.value = {
|
||||
patientName: row.patientName,
|
||||
visitId: row.visitId,
|
||||
operCode: row.operCode,
|
||||
roomCode: row.roomCode,
|
||||
doctorName: userStore.nickName,
|
||||
role: userStore.roles[0],
|
||||
}
|
||||
|
||||
// 初始化临时医嘱列表
|
||||
temporaryAdvices.value = []
|
||||
|
||||
// 调用计费接口获取数据
|
||||
getPrescriptionList(row.visitId).then((res) => {
|
||||
if (res.code === 200 && res.data) {
|
||||
// 过滤数据,只保留 adviceType 值为 1 的药品
|
||||
const filteredItems = res.data.filter(item => {
|
||||
try {
|
||||
// 尝试从 contentJson 中解析数据
|
||||
const contentData = JSON.parse(item.contentJson)
|
||||
const adviceType = Number(contentData.adviceType)
|
||||
return adviceType === 3
|
||||
} catch (e) {
|
||||
// 如果解析失败,尝试使用顶层的 adviceType
|
||||
const adviceType = Number(item.adviceType)
|
||||
return adviceType === 3
|
||||
}
|
||||
})
|
||||
|
||||
// 将过滤后的数据转换为临时医嘱需要的格式
|
||||
temporaryBillingMedicines.value = filteredItems.map(item => {
|
||||
try {
|
||||
// 从 contentJson 中解析详细数据
|
||||
const contentData = JSON.parse(item.contentJson)
|
||||
return {
|
||||
medicineName: contentData.adviceName || item.adviceName || '',
|
||||
specification: contentData.volume || contentData.specification || '',
|
||||
quantity: contentData.quantity || item.quantity || 0,
|
||||
batchNumber: contentData.lotNumber || item.lotNumber || '',
|
||||
unitPrice: contentData.unitPrice || item.unitPrice || 0,
|
||||
subtotal: contentData.totalPrice || item.totalPrice || 0,
|
||||
insuranceType: contentData.insuranceType === 1 ? '医保' : '自费'
|
||||
}
|
||||
} catch (e) {
|
||||
// 如果解析失败,使用顶层数据
|
||||
return {
|
||||
medicineName: item.adviceName || '',
|
||||
specification: item.specification || '',
|
||||
quantity: item.quantity || 0,
|
||||
batchNumber: item.lotNumber || '',
|
||||
unitPrice: item.unitPrice || 0,
|
||||
subtotal: item.totalPrice || 0,
|
||||
insuranceType: item.insuranceType === 1 ? '医保' : '自费'
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 如果没有数据或接口调用失败,初始化空列表
|
||||
temporaryBillingMedicines.value = []
|
||||
}
|
||||
}).catch(() => {
|
||||
temporaryBillingMedicines.value = []
|
||||
})
|
||||
|
||||
// 打开临时医嘱弹窗
|
||||
showTemporaryMedical.value = true
|
||||
}
|
||||
|
||||
// 关闭临时医嘱弹窗
|
||||
function closeTemporaryMedical() {
|
||||
showTemporaryMedical.value = false
|
||||
temporaryPatientInfo.value = {}
|
||||
temporaryBillingMedicines.value = []
|
||||
temporaryAdvices.value = []
|
||||
}
|
||||
|
||||
// 处理临时医嘱提交
|
||||
function handleTemporaryMedicalSubmit(data) {
|
||||
// 这里可以调用后端API保存临时医嘱数据
|
||||
proxy.$modal.msgSuccess('临时医嘱提交成功')
|
||||
closeTemporaryMedical()
|
||||
}
|
||||
|
||||
// 处理临时医嘱取消
|
||||
function handleTemporaryMedicalCancel() {
|
||||
closeTemporaryMedical()
|
||||
}
|
||||
|
||||
// 处理删除临时医嘱
|
||||
function handleDeleteTemporaryAdvice(index) {
|
||||
temporaryAdvices.value.splice(index, 1)
|
||||
proxy.$modal.msgSuccess('临时医嘱已删除')
|
||||
}
|
||||
|
||||
// 格式化计费弹窗中的日期
|
||||
function formatChargeDate(date) {
|
||||
if (!date) return '-'
|
||||
@@ -1394,15 +1500,13 @@ function submitForm() {
|
||||
proxy.$refs['surgeryRef'].validate((valid) => {
|
||||
if (valid) {
|
||||
const submitData = { ...form }
|
||||
console.log("scheduleId:", form.scheduleId)
|
||||
if (!form.scheduleId) {
|
||||
// 新增手术安排
|
||||
addSurgerySchedule(submitData).then((res) => {
|
||||
proxy.$modal.msgSuccess('新增成功')
|
||||
open.value = false
|
||||
getPageList()
|
||||
}).catch(error => {
|
||||
console.error('新增手术安排失败:', error)
|
||||
}).catch(() => {
|
||||
proxy.$message.error('新增手术安排失败,请检查表单信息')
|
||||
})
|
||||
} else {
|
||||
@@ -1411,8 +1515,7 @@ function submitForm() {
|
||||
proxy.$modal.msgSuccess('修改成功')
|
||||
open.value = false
|
||||
getPageList()
|
||||
}).catch(error => {
|
||||
console.error('更新手术安排失败:', error)
|
||||
}).catch(() => {
|
||||
proxy.$message.error('更新手术安排失败,请检查表单信息')
|
||||
})
|
||||
}
|
||||
@@ -1455,8 +1558,7 @@ function getSurgicalScheduleList() {
|
||||
const responseData = res.data.data || res.data
|
||||
applyList.value = responseData.records || []
|
||||
applyTotal.value = responseData.total || 0
|
||||
}).catch(error => {
|
||||
console.error('获取手术申请列表失败:', error)
|
||||
}).catch(() => {
|
||||
proxy.$modal.msgError('获取手术申请列表失败,请稍后重试')
|
||||
applyList.value = []
|
||||
applyTotal.value = 0
|
||||
|
||||
673
openhis-ui-vue3/src/views/surgicalschedule/temporaryMedical.vue
Normal file
673
openhis-ui-vue3/src/views/surgicalschedule/temporaryMedical.vue
Normal file
@@ -0,0 +1,673 @@
|
||||
<template>
|
||||
<div class="temporary-medical-container">
|
||||
<!-- 患者信息区域 -->
|
||||
<div class="patient-info-section">
|
||||
<div class="patient-info-header">
|
||||
<h3>门诊术中临时医嘱</h3>
|
||||
</div>
|
||||
<div class="patient-info-content">
|
||||
<el-descriptions :column="3" border>
|
||||
<el-descriptions-item label="患者:">{{ patientInfo.patientName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="就诊卡号:">{{ patientInfo.visitId || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="手术单号:">{{ patientInfo.operCode || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="科室:">{{ patientInfo.roomCode || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="医师:">{{ patientInfo.doctorName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="角色:">{{ patientInfo.role || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 已引用计费药品区域 -->
|
||||
<div class="medicine-section">
|
||||
<h4>一、已引用计费药品(待生成医嘱)</h4>
|
||||
<el-table :data="billingMedicines" border style="width: 100%; margin-bottom: 16px" fit>
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="药品名称" prop="medicineName" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="规格" prop="specification" min-width="100" align="center" />
|
||||
<el-table-column label="数量" prop="quantity" width="80" align="center" />
|
||||
<el-table-column label="批号" prop="batchNumber" min-width="120" align="center" />
|
||||
<el-table-column label="单价" prop="unitPrice" min-width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.unitPrice ? `¥${row.unitPrice}` : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="小计" prop="subtotal" min-width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.subtotal ? `¥${row.subtotal}` : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="医保" prop="insuranceType" width="80" align="center" />
|
||||
</el-table>
|
||||
|
||||
<div class="medicine-summary">
|
||||
<div class="summary-item">医保内:¥{{ insuranceAmount }}</div>
|
||||
<div class="summary-item">自费:¥{{ selfPayAmount }}</div>
|
||||
<div class="summary-item total">总计:¥{{ totalAmount }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 临时医嘱预览区域 -->
|
||||
<div class="advice-section">
|
||||
<h4>二、临时医嘱预览(已生成)</h4>
|
||||
<el-table :data="displayAdvices" border style="width: 100%; margin-bottom: 16px" fit>
|
||||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||||
<el-table-column label="医嘱名称" prop="adviceName" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column label="剂量" prop="dosage" min-width="80" align="center" />
|
||||
<el-table-column label="单位" prop="unit" min-width="80" align="center" />
|
||||
<el-table-column label="用法" prop="usage" min-width="100" show-overflow-tooltip />
|
||||
<el-table-column label="频次" prop="frequency" min-width="80" align="center" />
|
||||
<el-table-column label="执行时间" prop="executeTime" min-width="120" align="center" />
|
||||
<el-table-column label="操作" min-width="120" align="center">
|
||||
<template #default="{ $index }">
|
||||
<el-button link type="primary" @click="handleEditAdvice($index)">编辑</el-button>
|
||||
<el-button link type="danger" @click="handleDeleteAdvice($index)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 医师电子签名区域 -->
|
||||
<div class="signature-section">
|
||||
<h4>三、医师电子签名</h4>
|
||||
<div class="signature-content">
|
||||
<div class="signature-info">
|
||||
<span>签名医师:</span>
|
||||
<span :class="{ 'unsigned': !isSigned }">{{ isSigned ? currentUser.name : '未签名' }}</span>
|
||||
</div>
|
||||
<div class="signature-info">
|
||||
<span>时间:</span>
|
||||
<span>{{ signatureTime || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部操作按钮 -->
|
||||
<div class="footer-actions">
|
||||
<el-button class="cancel-btn" @click="handleCancel">取消</el-button>
|
||||
<el-button
|
||||
class="sign-submit-btn"
|
||||
:class="{ 'signed': isSigned }"
|
||||
@click="handleSignAndSubmit"
|
||||
>
|
||||
{{ isSigned ? '提交' : '一键签名并生成医嘱' }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 签名密码弹窗 -->
|
||||
<el-dialog v-model="showSignDialog" title="弹窗-签名密码" width="400px" append-to-body>
|
||||
<div class="sign-dialog-content">
|
||||
<p>请输入账户密码:</p>
|
||||
<el-input
|
||||
v-model="signPassword"
|
||||
type="password"
|
||||
placeholder="请输入密码"
|
||||
style="margin-bottom: 16px"
|
||||
@keyup.enter="confirmSign"
|
||||
/>
|
||||
<div class="dialog-actions">
|
||||
<el-button @click="showSignDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmSign">确认</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 编辑医嘱弹窗 -->
|
||||
<el-dialog v-model="showEditDialog" title="编辑医嘱" width="500px" append-to-body>
|
||||
<div class="edit-dialog-content">
|
||||
<el-form :model="editForm" label-width="80px">
|
||||
<el-form-item label="药品名称">
|
||||
<el-input v-model="editForm.adviceName" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="剂量" required>
|
||||
<el-input v-model.number="editForm.dosage" placeholder="请输入剂量" />
|
||||
</el-form-item>
|
||||
<el-form-item label="单位">
|
||||
<el-input v-model="editForm.unit" placeholder="请输入单位" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用法" required>
|
||||
<el-select v-model="editForm.usage" placeholder="请选择用法" style="width: 100%">
|
||||
<el-option
|
||||
v-for="dict in method_code"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.label"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="频次">
|
||||
<el-input v-model="editForm.frequency" disabled />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="dialog-actions">
|
||||
<el-button @click="handleCancelEdit">取消</el-button>
|
||||
<el-button type="primary" @click="handleSaveEdit">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, getCurrentInstance } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import { checkPassword } from '@/api/surgicalschedule'
|
||||
import { savePrescription } from '@/views/clinicmanagement/bargain/component/api.js'
|
||||
|
||||
// 定义props
|
||||
const props = defineProps({
|
||||
// 患者和医生信息
|
||||
patientInfo: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
patientName: '',
|
||||
visitId: '',
|
||||
operCode: '',
|
||||
roomCode: '',
|
||||
doctorName: '',
|
||||
role: ''
|
||||
})
|
||||
},
|
||||
// 计费药品列表
|
||||
billingMedicines: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 临时医嘱列表
|
||||
temporaryAdvices: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
// 定义emit事件
|
||||
const emit = defineEmits(['submit', 'cancel', 'delete-advice', 'update:temporaryAdvices'])
|
||||
|
||||
// 用户store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 获取当前实例
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
// 获取字典数据(与门诊医生站保持一致)
|
||||
const { method_code } = proxy.useDict('method_code')
|
||||
|
||||
// 响应式数据
|
||||
const isSigned = ref(false)
|
||||
const signatureTime = ref('')
|
||||
const showSignDialog = ref(false)
|
||||
const signPassword = ref('')
|
||||
const showEditDialog = ref(false)
|
||||
const currentEditIndex = ref(-1)
|
||||
const editForm = ref({
|
||||
adviceName: '',
|
||||
dosage: '',
|
||||
unit: '',
|
||||
usage: '',
|
||||
frequency: '临时'
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
const currentUser = computed(() => ({
|
||||
name: userStore.name || '未知用户',
|
||||
id: userStore.id
|
||||
}))
|
||||
|
||||
const insuranceAmount = computed(() => {
|
||||
return props.billingMedicines
|
||||
.filter(med => med.insuranceType === '甲' || med.insuranceType === '乙')
|
||||
.reduce((sum, med) => sum + (med.subtotal || 0), 0)
|
||||
})
|
||||
|
||||
const selfPayAmount = computed(() => {
|
||||
return props.billingMedicines
|
||||
.filter(med => !med.insuranceType || med.insuranceType === '自费')
|
||||
.reduce((sum, med) => sum + (med.subtotal || 0), 0)
|
||||
})
|
||||
|
||||
const totalAmount = computed(() => {
|
||||
return insuranceAmount.value + selfPayAmount.value
|
||||
})
|
||||
|
||||
// 将计费药品转换为临时医嘱数据
|
||||
const convertedAdvices = computed(() => {
|
||||
return props.billingMedicines.map((medicine, index) => {
|
||||
// 解析规格中的数值和单位
|
||||
const specMatch = medicine.specification ? medicine.specification.match(/(\d+)(\D+)/) : null
|
||||
const specValue = specMatch ? parseInt(specMatch[1]) : 1
|
||||
const specUnit = specMatch ? specMatch[2] : 'ml'
|
||||
|
||||
// 计算剂量 = 规格数值 × 数量
|
||||
const dosage = specValue * (medicine.quantity || 1)
|
||||
|
||||
// 根据药品名称判断用法
|
||||
let usage = '静脉注射'
|
||||
if (medicine.medicineName && medicine.medicineName.includes('注射液')) {
|
||||
usage = '静脉注射'
|
||||
} else if (medicine.medicineName && medicine.medicineName.includes('片')) {
|
||||
usage = '口服'
|
||||
} else if (medicine.medicineName && medicine.medicineName.includes('胶囊')) {
|
||||
usage = '口服'
|
||||
}
|
||||
|
||||
return {
|
||||
id: index + 1,
|
||||
adviceName: medicine.medicineName || '',
|
||||
dosage: dosage,
|
||||
unit: specUnit,
|
||||
usage: usage,
|
||||
frequency: '临时',
|
||||
executeTime: new Date().toLocaleString('zh-CN'),
|
||||
originalMedicine: medicine
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 使用转换后的数据或传入的临时医嘱数据
|
||||
const displayAdvices = computed(() => {
|
||||
return props.temporaryAdvices.length > 0 ? props.temporaryAdvices : convertedAdvices.value
|
||||
})
|
||||
|
||||
// 方法
|
||||
const handleSign = () => {
|
||||
showSignDialog.value = true
|
||||
}
|
||||
|
||||
// 编辑医嘱
|
||||
const handleEditAdvice = (index) => {
|
||||
const advice = displayAdvices.value[index]
|
||||
currentEditIndex.value = index
|
||||
editForm.value = {
|
||||
adviceName: advice.adviceName,
|
||||
dosage: advice.dosage,
|
||||
unit: advice.unit,
|
||||
usage: advice.usage,
|
||||
frequency: advice.frequency
|
||||
}
|
||||
showEditDialog.value = true
|
||||
}
|
||||
|
||||
// 保存编辑
|
||||
const handleSaveEdit = () => {
|
||||
if (!editForm.value.dosage || !editForm.value.usage) {
|
||||
ElMessage.warning('请填写剂量和用法')
|
||||
return
|
||||
}
|
||||
|
||||
// 构建更新后的数据
|
||||
const updatedAdvice = {
|
||||
...displayAdvices.value[currentEditIndex.value],
|
||||
...editForm.value
|
||||
}
|
||||
|
||||
// 构建完整的更新后列表
|
||||
const updatedAdvices = [...displayAdvices.value]
|
||||
updatedAdvices[currentEditIndex.value] = updatedAdvice
|
||||
|
||||
// 通知父组件更新数据
|
||||
emit('update:temporaryAdvices', updatedAdvices)
|
||||
|
||||
showEditDialog.value = false
|
||||
ElMessage.success('编辑成功')
|
||||
}
|
||||
|
||||
// 取消编辑
|
||||
const handleCancelEdit = () => {
|
||||
showEditDialog.value = false
|
||||
currentEditIndex.value = -1
|
||||
editForm.value = {
|
||||
adviceName: '',
|
||||
dosage: '',
|
||||
unit: '',
|
||||
usage: '',
|
||||
frequency: '临时'
|
||||
}
|
||||
}
|
||||
|
||||
const confirmSign = async () => {
|
||||
if (!signPassword.value) {
|
||||
ElMessage.warning('请输入密码')
|
||||
return
|
||||
}
|
||||
|
||||
// 调用后端接口验证密码
|
||||
try {
|
||||
const response = await checkPassword({
|
||||
password: signPassword.value
|
||||
})
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
isSigned.value = true
|
||||
signatureTime.value = new Date().toLocaleString('zh-CN')
|
||||
showSignDialog.value = false
|
||||
signPassword.value = ''
|
||||
ElMessage.success('签名成功')
|
||||
|
||||
// 签名成功后自动提交
|
||||
handleSubmit()
|
||||
} else {
|
||||
ElMessage.error('密码错误,请重新输入')
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('签名失败,请重试')
|
||||
}
|
||||
}
|
||||
|
||||
const handleSignAndSubmit = () => {
|
||||
if (isSigned.value) {
|
||||
// 如果已经签名,直接提交
|
||||
handleSubmit()
|
||||
} else {
|
||||
// 如果未签名,打开签名弹窗
|
||||
handleSign()
|
||||
}
|
||||
}
|
||||
|
||||
const handleDeleteAdvice = (index) => {
|
||||
ElMessageBox.confirm('确定要删除这条医嘱吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
// 检查数据来源
|
||||
if (props.temporaryAdvices.length > 0) {
|
||||
// 如果使用的是传入的临时医嘱数据,通知父组件删除
|
||||
emit('delete-advice', index)
|
||||
} else {
|
||||
// 如果使用的是转换的数据,需要构建新的临时医嘱数据并通知父组件
|
||||
const updatedAdvices = [...displayAdvices.value]
|
||||
updatedAdvices.splice(index, 1)
|
||||
emit('update:temporaryAdvices', updatedAdvices)
|
||||
}
|
||||
ElMessage.success('删除成功')
|
||||
}).catch(() => {
|
||||
// 用户取消删除
|
||||
})
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!isSigned.value) {
|
||||
ElMessage.warning('请先进行电子签名')
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否有医嘱数据
|
||||
if (displayAdvices.value.length === 0) {
|
||||
ElMessage.warning('没有可保存的医嘱数据')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 构建保存医嘱的请求参数
|
||||
const saveData = {
|
||||
organizationId: props.patientInfo.organizationId || 1, // 默认科室ID
|
||||
adviceSaveList: displayAdvices.value.map((advice, index) => {
|
||||
// 获取原始药品数据
|
||||
const originalMedicine = advice.originalMedicine
|
||||
|
||||
// 解析contentJson
|
||||
let contentJsonData = {}
|
||||
if (originalMedicine && originalMedicine.contentJson) {
|
||||
try {
|
||||
contentJsonData = JSON.parse(originalMedicine.contentJson)
|
||||
} catch (e) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 构造请求参数(与门诊医生工作站完全一致)
|
||||
return {
|
||||
// 基础信息
|
||||
dbOpType: originalMedicine?.requestId ? '2' : '1', // 有请求ID则为修改,否则为新增
|
||||
adviceType: originalMedicine?.adviceType || 1, // 使用原始类型或默认3
|
||||
requestId: originalMedicine?.requestId,
|
||||
chargeItemId: originalMedicine?.chargeItemId,
|
||||
contentJson: originalMedicine?.contentJson,
|
||||
categoryCode: contentJsonData.categoryCode || originalMedicine?.categoryCode,
|
||||
positionId: originalMedicine?.positionId || contentJsonData.positionId,
|
||||
pharmacologyCategoryCode: contentJsonData.pharmacologyCategoryCode || originalMedicine?.pharmacologyCategoryCode,
|
||||
partPercent: originalMedicine?.partPercent || contentJsonData.partPercent || 1,
|
||||
partAttributeEnum: originalMedicine?.partAttributeEnum || contentJsonData.partAttributeEnum,
|
||||
executeNum: contentJsonData.executeNum || originalMedicine?.executeNum || 1,
|
||||
prescriptionNo: originalMedicine?.prescriptionNo,
|
||||
|
||||
// 数量和单位
|
||||
quantity: originalMedicine?.quantity || 1,
|
||||
dispensePerDuration: originalMedicine?.dispensePerDuration || contentJsonData.dispensePerDuration,
|
||||
unitCode: contentJsonData.unitCode || originalMedicine?.unitCode || advice.unit,
|
||||
unitPrice: originalMedicine?.unitPrice || contentJsonData.unitPrice || 0,
|
||||
totalPrice: originalMedicine?.totalPrice || contentJsonData.totalPrice || 0,
|
||||
definitionId: contentJsonData.definitionId || originalMedicine?.definitionId,
|
||||
definitionDetailId: contentJsonData.definitionDetailId || originalMedicine?.definitionDetailId,
|
||||
lotNumber: originalMedicine?.lotNumber || contentJsonData.lotNumber,
|
||||
|
||||
// 状态和类型
|
||||
statusEnum: originalMedicine?.statusEnum || 2, // 默认状态:已发送
|
||||
categoryEnum: originalMedicine?.categoryEnum || contentJsonData.categoryEnum,
|
||||
|
||||
// 药品/诊疗信息
|
||||
adviceDefinitionId: contentJsonData.adviceDefinitionId || originalMedicine?.adviceDefinitionId,
|
||||
adviceTableName: contentJsonData.adviceTableName || originalMedicine?.adviceTableName,
|
||||
adviceName: advice.adviceName,
|
||||
minUnitQuantity: originalMedicine?.minUnitQuantity || contentJsonData.minUnitQuantity,
|
||||
|
||||
// 患者和就诊信息
|
||||
patientId: props.patientInfo.patientId,
|
||||
practitionerId: currentUser.value.id || originalMedicine?.practitionerId, // 开方医生
|
||||
locationId: contentJsonData.locationId || originalMedicine?.locationId,
|
||||
performLocation: originalMedicine?.performLocation || contentJsonData.performLocation,
|
||||
founderOrgId: currentUser.value.id || originalMedicine?.founderOrgId, // 开方人科室
|
||||
encounterId: props.patientInfo.visitId || contentJsonData.encounterId || originalMedicine?.encounterId,
|
||||
accountId: contentJsonData.accountId || originalMedicine?.accountId,
|
||||
conditionId: contentJsonData.conditionId || originalMedicine?.conditionId,
|
||||
encounterDiagnosisId: originalMedicine?.encounterDiagnosisId || contentJsonData.encounterDiagnosisId,
|
||||
conditionDefinitionId: originalMedicine?.conditionDefinitionId || contentJsonData.conditionDefinitionId,
|
||||
|
||||
// 治疗信息
|
||||
therapyEnum: originalMedicine?.therapyEnum || contentJsonData.therapyEnum || 1, // 默认临时医嘱
|
||||
methodCode: advice.usage, // 用法(使用转换后的中文名称)
|
||||
rateCode: advice.frequency, // 频次
|
||||
dose: advice.dosage,
|
||||
firstDose: originalMedicine?.firstDose || contentJsonData.firstDose,
|
||||
doseUnitCode: contentJsonData.doseUnitCode || originalMedicine?.doseUnitCode || advice.unit,
|
||||
skinTestFlag: originalMedicine?.skinTestFlag || contentJsonData.skinTestFlag,
|
||||
injectFlag: originalMedicine?.injectFlag || contentJsonData.injectFlag,
|
||||
|
||||
// 分组信息
|
||||
groupId: originalMedicine?.groupId,
|
||||
packageId: originalMedicine?.packageId || contentJsonData.packageId,
|
||||
|
||||
// 诊疗活动信息
|
||||
activityId: contentJsonData.adviceDefinitionId || originalMedicine?.adviceDefinitionId, // 对于诊疗类型,使用 adviceDefinitionId 作为 activity_id
|
||||
|
||||
// 医保信息
|
||||
ybClassEnum: originalMedicine?.ybClassEnum || contentJsonData.ybClassEnum,
|
||||
|
||||
// 中药信息
|
||||
chineseHerbsDoseQuantity: originalMedicine?.chineseHerbsDoseQuantity || contentJsonData.chineseHerbsDoseQuantity || 1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 调用保存医嘱接口
|
||||
const response = await savePrescription(saveData)
|
||||
|
||||
if (response.code === 200) {
|
||||
ElMessage.success('临时医嘱保存成功')
|
||||
|
||||
// 构建提交数据
|
||||
const submitData = {
|
||||
patientInfo: props.patientInfo,
|
||||
billingMedicines: props.billingMedicines,
|
||||
temporaryAdvices: displayAdvices.value,
|
||||
signature: {
|
||||
doctorName: currentUser.value.name,
|
||||
signatureTime: signatureTime.value
|
||||
}
|
||||
}
|
||||
|
||||
// 通知父组件
|
||||
emit('submit', submitData)
|
||||
} else {
|
||||
ElMessage.error('保存医嘱失败:' + (response.msg || response.message || '未知错误'))
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('保存医嘱失败,请重试')
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
// 通知父组件关闭弹窗
|
||||
emit('cancel')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.temporary-medical-container {
|
||||
padding: 20px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.patient-info-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.patient-info-header h3 {
|
||||
margin: 0 0 16px 0;
|
||||
color: #333;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.medicine-section,
|
||||
.advice-section,
|
||||
.signature-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.medicine-section h4,
|
||||
.advice-section h4,
|
||||
.signature-section h4 {
|
||||
margin: 0 0 16px 0;
|
||||
color: #666;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.medicine-summary {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 20px;
|
||||
padding: 12px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.summary-item.total {
|
||||
font-weight: bold;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.signature-content {
|
||||
padding: 16px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.signature-info {
|
||||
margin-bottom: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.signature-info span:first-child {
|
||||
font-weight: bold;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.unsigned {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.signature-actions {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.footer-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
margin-top: 24px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #e4e7ed;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
width: 120px;
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
border: 1px solid #dcdfe6;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.cancel-btn:hover {
|
||||
border-color: #409eff;
|
||||
color: #409eff;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(64, 158, 255, 0.2);
|
||||
}
|
||||
|
||||
.sign-submit-btn {
|
||||
width: 200px;
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
|
||||
border: none;
|
||||
color: white;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 8px rgba(103, 194, 58, 0.3);
|
||||
}
|
||||
|
||||
.sign-submit-btn:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 12px rgba(103, 194, 58, 0.4);
|
||||
}
|
||||
|
||||
.sign-submit-btn:active {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(103, 194, 58, 0.4);
|
||||
}
|
||||
|
||||
.sign-submit-btn.signed {
|
||||
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
|
||||
box-shadow: 0 4px 8px rgba(64, 158, 255, 0.3);
|
||||
}
|
||||
|
||||
.sign-submit-btn.signed:hover {
|
||||
box-shadow: 0 6px 12px rgba(64, 158, 255, 0.4);
|
||||
}
|
||||
|
||||
.sign-dialog-content p {
|
||||
margin-bottom: 16px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.dialog-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-descriptions__label) {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user