1 Commits

30 changed files with 391 additions and 490 deletions

View File

@@ -147,8 +147,8 @@ public class OrganizationLocationAppServiceImpl implements IOrganizationLocation
for (OrganizationLocation organizationLocation : organizationLocationList)
if (DateTimeUtils.isOverlap(organizationLocation.getStartTime(), organizationLocation.getEndTime(),
orgLoc.getStartTime(), orgLoc.getEndTime())) {
Organization org = organizationService.getById(organizationLocation.getOrganizationId());
String organizationName = org != null ? org.getName() : "未知科室";
String organizationName =
organizationService.getById(organizationLocation.getOrganizationId()).getName();
return R.fail("当前诊疗:" + activityName + CommonConstants.Common.DASH + orgLoc.getStartTime()
+ CommonConstants.Common.DASH + orgLoc.getEndTime() + "" + organizationName + "时间冲突");
}

View File

@@ -633,9 +633,9 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
Order updateOrder = new Order();
updateOrder.setId(appointmentOrder.getId());
updateOrder.setStatus(CommonConstants.AppointmentOrderStatus.RETURNED);
updateOrder.setPayStatus(0);
updateOrder.setCancelTime(now);
updateOrder.setCancelReason("门诊退号");
updateOrder.setCancelReason(
StringUtils.isNotEmpty(reason) ? reason : "门诊退号");
updateOrder.setUpdateTime(now);
orderService.updateById(updateOrder);
}

View File

@@ -418,7 +418,7 @@ public class SurgeryAppServiceImpl implements ISurgeryAppService {
// 清除相关缓存
clearSurgeryAppCache(surgery);
return R.ok(surgeryId, "手术申请提交成功!");
return R.ok(surgeryId, MessageUtils.createMessage(PromptMsgConstant.Common.M00001, new Object[]{"手术信息"}));
}
/**
@@ -497,7 +497,7 @@ public class SurgeryAppServiceImpl implements ISurgeryAppService {
// 清除相关缓存
clearSurgeryAppCache(surgery);
return R.ok(null, "手术申请修改成功!");
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"手术信息"}));
}
/**

View File

@@ -178,26 +178,22 @@ public class AdviceUtils {
// 生命提示信息集合
List<String> tipsList = new ArrayList<>();
for (MedicationRequestUseExe medicationRequestUseExe : medUseExeList) {
// 聚合同一位置所有批次的库存总量
List<AdviceInventoryDto> matchedInventories = adviceInventory.stream()
Optional<AdviceInventoryDto> matchedInventory = adviceInventory.stream()
.filter(inventoryDto -> medicationRequestUseExe.getMedicationId().equals(inventoryDto.getItemId())
&& CommonConstants.TableName.MED_MEDICATION_DEFINITION.equals(inventoryDto.getItemTable())
&& medicationRequestUseExe.getPerformLocation().equals(inventoryDto.getLocationId())
// 如果选择了具体的批次号,校验库存时需要加上批次号的匹配条件
&& (StringUtils.isEmpty(medicationRequestUseExe.getLotNumber())
|| medicationRequestUseExe.getLotNumber().equals(inventoryDto.getLotNumber())))
.collect(Collectors.toList());
.findFirst();
// 匹配到库存信息
if (!matchedInventories.isEmpty()) {
// 聚合所有批次的可用库存
BigDecimal totalQuantity = matchedInventories.stream()
.map(dto -> dto.getQuantity() != null ? dto.getQuantity() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal requestQuantity = medicationRequestUseExe.getExecuteTimesNum()
.multiply(medicationRequestUseExe.getMinUnitQuantity());
if (requestQuantity.compareTo(totalQuantity) > 0) {
if (matchedInventory.isPresent()) {
AdviceInventoryDto inventoryDto = matchedInventory.get();
if ((medicationRequestUseExe.getExecuteTimesNum()
.multiply(medicationRequestUseExe.getMinUnitQuantity()))
.compareTo(inventoryDto.getQuantity()) > 0) {
tipsList
.add("" + medicationRequestUseExe.getBusNo() + "】在" + matchedInventories.get(0).getLocationName() + "库存不足");
.add("" + medicationRequestUseExe.getBusNo() + "】在" + inventoryDto.getLocationName() + "库存不足");
}
} else {
tipsList.add("" + medicationRequestUseExe.getBusNo() + "】未匹配到库存信息");

View File

@@ -523,7 +523,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
// 处理长期已发放的药品
if (!longMedDispensedList.isEmpty()) {
// 生成退药单
this.creatRefundMedicationList(longMedDispensedList, procedureIdMap);
this.creatRefundMedicationList(tempMedDispensedList, procedureIdMap);
}
// 处理临时已发放药品
if (!tempMedDispensedList.isEmpty()) {
@@ -653,7 +653,7 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
if (!longMedUndispenseList.isEmpty()) {
// 排除已汇总的药品
List<MedicationDispense> medicationDispenseList
= longMedUndispenseList.stream().filter(x -> x.getSummaryNo() == null).toList();
= tempMedUndispenseList.stream().filter(x -> x.getSummaryNo() == null).toList();
medicationDispenseService
.removeByIds(medicationDispenseList.stream().map(MedicationDispense::getId).toList());
}

View File

@@ -511,9 +511,6 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
// 签发操作
boolean is_sign = AdviceOpType.SIGN_ADVICE.getCode().equals(adviceOpType);
// 收集已处理的requestId用于批量更新状态
List<Long> processedRequestIds = new ArrayList<>();
// 声明长期医嘱诊疗请求
ServiceRequest longServiceRequest;
// 新增 + 修改 (长期医嘱)
@@ -558,9 +555,6 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
}
}
iServiceRequestService.saveOrUpdate(longServiceRequest);
if (longServiceRequest.getId() != null) {
processedRequestIds.add(longServiceRequest.getId());
}
}
// 声明临时医嘱诊疗请求
@@ -609,9 +603,6 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
}
}
iServiceRequestService.saveOrUpdate(tempServiceRequest);
if (tempServiceRequest.getId() != null) {
processedRequestIds.add(tempServiceRequest.getId());
}
// 保存时,保存诊疗费用项
if (is_save) {
@@ -663,14 +654,6 @@ public class AdviceManageAppServiceImpl implements IAdviceManageAppService {
}
}
// 批量更新诊疗医嘱状态(使用 update 确保状态字段必定更新)
if (!processedRequestIds.isEmpty()) {
iServiceRequestService.update(null,
new LambdaUpdateWrapper<ServiceRequest>()
.set(ServiceRequest::getStatusEnum,
is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue())
.in(ServiceRequest::getId, processedRequestIds));
}
}
/**

View File

@@ -95,13 +95,6 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
prescriptionNo = assignSeqUtil.getSeq(AssignSeqEnum.ACTIVITY_PSYCHOTROPIC_NO.getPrefix(), 8);
}
// 诊疗执行科室配置校验(必须在数据库操作之前执行)
List<ActivityOrganizationConfigDto> activityOrganizationConfig =
requestFormManageAppMapper.getActivityOrganizationConfig(typeCode);
if (activityOrganizationConfig.isEmpty()) {
throw new ServiceException("请先配置当前时间段的执行科室");
}
// 当前时间
Date curDate = new Date();
// 请求类型
@@ -146,6 +139,12 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
// 诊疗集合
List<ActivitySaveDto> activityList = requestFormSaveDto.getActivityList();
log.info("保存申请单typeCode={}, activityListSize={}, encounterId={}", typeCode, activityList != null ? activityList.size() : 0, encounterId);
// 诊疗执行科室配置
List<ActivityOrganizationConfigDto> activityOrganizationConfig =
requestFormManageAppMapper.getActivityOrganizationConfig(typeCode);
if (activityOrganizationConfig.isEmpty()) {
throw new ServiceException("请先配置当前时间段的执行科室");
}
for (ActivitySaveDto activitySaveDto : activityList) {
serviceRequest = new ServiceRequest();

View File

@@ -331,10 +331,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) t
WHERE rn = 1
) pi ON s.patient_id = pi.patient_id
<!-- 关联服务请求表(仅用于数据关联,不再过滤) -->
<!-- 排除已生成医嘱的手术 -->
LEFT JOIN wor_service_request sr ON sr.activity_id = s.id AND sr.delete_flag = '0' AND sr.category_enum = 4
<where>
s.delete_flag = '0'
<!-- 只显示未生成医嘱的手术 -->
AND sr.id IS NULL
<if test="ew.sqlSegment != null and ew.sqlSegment != ''">
<!-- 补充 encounter_id 替换,修复多表关联时字段歧义。注释不能放进 OGNL 表达式内部。 -->
<![CDATA[

View File

@@ -38,6 +38,7 @@ export function listAdviceTypes(query) {
params: query
})
}
```
/**
* 查询手术室详细

View File

@@ -132,10 +132,6 @@ function onCancel() {
// 批量添加
async function onConfirm() {
if (!props.organizationId) {
proxy.$message.error('请先在左侧选择科室');
return;
}
if (!formEl) return;
formEl.value.validate(async (valid) => {
if (!valid) return;

View File

@@ -366,10 +366,6 @@ function handleBlur(row, index) {
// 编辑或 保存当前行
function openSaveImplementDepartment(row) {
if (!organizationId.value) {
proxy.$message.error('请先在左侧选择科室');
return;
}
const params = {
// 科室id
organizationId: organizationId.value,
@@ -456,12 +452,13 @@ function handleNodeClick(res, node) {
// 实际的节点点击处理逻辑
function continueHandleNodeClick(node) {
// 检查节点是否有子节点
if (node.data.children && node.data.children.length > 0) {
return;
}
// 新增按钮是否 disable
isAddDisable.value = false;
// 检查节点是否有子节点
if (node.data.children && node.data.children.length > 0) {
// proxy.$message.warning("不能选择父节点");
return;
}
// 选中科室id
organizationId.value = node.data.id;
// 获取 右侧 table 信息

View File

@@ -1146,13 +1146,7 @@ function calculateTotalPrice(row, index) {
});
}
function closeAllPopovers() {
prescriptionList.value.forEach(row => {
row.showPopover = false;
});
}
defineExpose({ getListInfo, closeAllPopovers });
defineExpose({ getListInfo });
</script>
<style lang="scss" scoped>

View File

@@ -41,9 +41,43 @@
</el-col>
</el-row>
<!-- 工作单位学校 -->
<!-- 性别出生日期实足年龄 -->
<el-row :gutter="16" class="form-row align-bottom">
<el-col :span="6" class="form-item">
<span class="form-label required">性别</span>
<el-radio-group v-model="form.sex">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
<el-radio label="未知">未知</el-radio>
</el-radio-group>
</el-col>
<el-col :span="10" class="form-item birth-date">
<span class="form-label required">出生日期</span>
<div class="date-inputs">
<el-input v-model="form.birthYear" class="underline-input small" maxlength="4" @change="calculateAge" />
<span></span>
<el-input v-model="form.birthMonth" class="underline-input small" maxlength="2" @change="calculateAge" />
<span></span>
<el-input v-model="form.birthDay" class="underline-input small" maxlength="2" @change="calculateAge" />
<span></span>
</div>
</el-col>
<el-col :span="8" class="form-item age-item">
<span class="form-label"> 实足年龄</span>
<div class="age-inputs">
<el-input v-model="form.age" class="underline-input small"/>
<el-select v-model="form.ageUnit" class="age-unit-select">
<el-option label="岁" value="岁" />
<el-option label="月" value="月" />
<el-option label="天" value="天" />
</el-select>
</div>
</el-col>
</el-row>
<!-- 工作单位 -->
<el-row :gutter="16" class="form-row">
<el-col :span="12" class="form-item">
<el-col :span="24" class="form-item full-width">
<span class="form-label">工作单位学校</span>
<el-input v-model="form.workplace" class="underline-input" />
</el-col>
@@ -488,7 +522,7 @@
<script setup>
import { ref, computed, getCurrentInstance, watch } from 'vue';
import pcas from 'china-division/dist/pcas-code.json';
import { saveInfectiousDiseaseReport, getNextCardNo } from '../api';
import { saveInfectiousDiseaseReport } from '../api';
import useUserStore from '@/store/modules/user';
import { useDict } from '@/utils/dict';
@@ -1203,7 +1237,7 @@ function calculateAge() {
* 显示对话框并初始化表单数据
* @param {Object} diagnosisData - 诊断数据,包含已选疾病和地址信息
*/
async function show(diagnosisData) {
function show(diagnosisData) {
dialogVisible.value = true;
// 重置地址选择器状态
@@ -1233,24 +1267,12 @@ async function show(diagnosisData) {
});
}
// 生成默认卡片编号:调用后端接口获取
// 生成默认卡片编号:医疗机构编码+当前年月日+4位流水
const orgCode = userStore.fixmedinsCode || '0000';
let cardNo = '';
try {
const res = await getNextCardNo(orgCode);
if (res.code === 200 && res.data) {
cardNo = res.data;
} else {
cardNo = 'TEMP_' + Date.now();
}
} catch (err) {
console.error('获取卡片编号失败:', err);
cardNo = 'TEMP_' + Date.now();
}
form.value = {
// 卡片编号:单位自编,与网络直报一致
cardNo: cardNo,
cardNo: '',
// 患者基本信息
patName: patientInfo.patientName || patientInfo.name || '', // 患者姓名

View File

@@ -246,8 +246,7 @@
<el-input-number :min="0" v-model="scope.row.doseQuantity" controls-position="right"
:controls="false" style="width: 70px; margin-right: 20px"
:ref="(el) => (inputRefs.doseQuantity = el)" @input="convertValues(scope.row, scope.$index)"
@keyup.enter.prevent="handleEnter('doseQuantity', scope.row, scope.$index)"
@change="calculateTotalAmount(scope.row, scope.$index)"/>
@keyup.enter.prevent="handleEnter('doseQuantity', scope.row, scope.$index)" />
</el-form-item>
<!-- 剂量单位 -->
<el-select v-model="scope.row.minUnitCode" style="width: 70px; margin-right: 20px" placeholder=" ">
@@ -295,8 +294,7 @@
}
// inputRefs.rateCode.blur();
}
" :ref="(el) => (inputRefs.rateCode = el)"
@change="calculateTotalAmount(scope.row, scope.$index)">
" :ref="(el) => (inputRefs.rateCode = el)">
<el-option v-for="dict in rate_code" @click="() => (scope.row.rateCode_dictText = dict.label)"
:key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
@@ -315,7 +313,6 @@
data-prop="dispensePerDuration">
<el-input-number v-model="scope.row.dispensePerDuration" style="width: 80px" :min="1"
controls-position="right" :controls="false" :ref="(el) => (inputRefs.dispensePerDuration = el)"
@change="calculateTotalAmount(scope.row, scope.$index)"
@keyup.enter.prevent="
handleEnter('dispensePerDuration', scope.row, scope.$index)
">

View File

@@ -56,6 +56,137 @@
<!-- 手术等级 -->
<el-table-column label="手术等级" align="center" prop="surgeryLevel_dictText" width="100" />
<!-- 手术室确认时间 -->
<el-table-column label="手术室确认时间" align="center" prop="confirmTime" width="180">
<template #default="scope">
{{ scope.row.confirmTime ? parseTime(scope.row.confirmTime, '{y}-{m}-{d} {h}:{i}:{s}') : '-' }}
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column label="操作" align="center" width="150" fixed="right">
<template #default="scope">
<el-button
type="primary"
link
size="small"
@click="handleView(scope.row)"
>
查看
</el-button>
<el-button
type="primary"
link
size="small"
@click="handleEdit(scope.row)"
:disabled="scope.row.status !== '0'"
>
修改
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { getSurgeryApplicationList, addSurgeryApplication, updateSurgeryApplication } from '@/api/doctorstation/surgery'
import { ElMessage, ElMessageBox } from 'element-plus'
const loading = ref(true)
const surgeryList = ref([])
// 查询手术申请列表
const getList = async () => {
try {
loading.value = true
const response = await getSurgeryApplicationList()
surgeryList.value = response.data || []
} catch (error) {
console.warn('获取手术申请列表失败', error)
surgeryList.value = []
} finally {
loading.value = false
}
}
// 新增手术申请
const handleAdd = () => {
// 跳转到新增页面或打开新增弹窗
// 这里需要根据实际路由配置调整
openSurgeryDialog()
}
// 编辑手术申请
const handleEdit = (row) => {
if(row.status !== '0') {
ElMessage.warning('该申请已提交,无法修改')
return
}
openSurgeryDialog(row)
}
// 查看手术申请详情
const handleView = (row) => {
openSurgeryDialog(row, true)
}
// 刷新列表
const handleRefresh = () => {
getList()
}
// 打开手术申请对话框
const openSurgeryDialog = (row, isView = false) => {
// 这里需要引入具体的对话框组件或跳转到详情页
// 示例代码,具体实现需要根据项目实际情况调整
console.log('打开手术申请对话框', row, isView)
}
// 获取行样式
const getRowClassName = ({ row }) => {
if (row.status === '1') {
return 'success-row'
} else if (row.status === '2') {
return 'warning-row'
}
return ''
}
onMounted(() => {
getList()
})
// 暴露方法给父组件调用,用于提交后刷新列表
defineExpose({
refreshList: getList
})
</script>
<style scoped>
.surgery-application-container {
padding: 20px;
}
.top-operation-bar {
margin-bottom: 16px;
}
.add-button,
.refresh-button {
margin-bottom: 10px;
}
/* 表格行状态样式 */
::v-deep(.success-row) {
background-color: #f0f9ff;
}
::v-deep(.warning-row) {
background-color: #fff7e6;
}
</style>
<el-table-column label="手术室确认时间" align="center" prop="operatingRoomConfirmTime" width="180">
<template #default="scope">
{{ scope.row.operatingRoomConfirmTime ? parseTime(scope.row.operatingRoomConfirmTime, '{y}-{m}-{d} {h}:{i}:{s}') : '-' }}
@@ -627,10 +758,10 @@ function getList() {
pageSize: 100,
encounterId: props.patientInfo.encounterId
}).then((res) => {
console.log('[手术申请] 列表查询 - encounterId:', props.patientInfo.encounterId, '返回记录数:', res.data?.records?.length || 0)
surgeryList.value = res.data.records || []
}).catch(error => {
console.warn('[手术申请] 列表加载失败(可能无权限或接口异常):', error?.message || error)
console.error('获取手术列表失败:', error)
proxy.$modal.msgError('数据加载失败,请稍后重试')
surgeryList.value = []
}).finally(() => {
loading.value = false
@@ -1127,39 +1258,35 @@ function submitForm() {
// 新增手术
addSurgery(form.value).then((res) => {
if (res.code === 200) {
proxy.$modal.msgSuccess('手术申请提交成功')
proxy.$modal.msgSuccess(res.msg || '新增成功')
// 保存麻醉方式
sessionStorage.setItem('anesthesiaType', form.value.anesthesiaTypeEnum)
open.value = false
// 延迟刷新列表,确保后端数据已提交
setTimeout(() => {
getList()
}, 300)
emit('saved') // 🔧 触发保存事件,通知父组件刷新医嘱列表
} else {
proxy.$modal.msgError(res.msg || '新增手术失败,请检查表单信息')
}
}).catch(error => {
console.warn('[手术申请] 新增接口异常:', error?.message || error)
console.error('新增手术失败:', error)
proxy.$modal.msgError('新增手术失败,请检查表单信息')
})
} else {
// 修改手术
updateSurgery(form.value).then((res) => {
if (res.code === 200) {
proxy.$modal.msgSuccess('手术申请修改成功')
proxy.$modal.msgSuccess(res.msg || '修改成功')
// 保存麻醉方式
sessionStorage.setItem('anesthesiaType', form.value.anesthesiaTypeEnum)
open.value = false
// 延迟刷新列表,确保后端数据已提交
setTimeout(() => {
getList()
}, 300)
emit('saved') // 🔧 触发保存事件,通知父组件刷新医嘱列表
} else {
proxy.$modal.msgError(res.msg || '更新手术失败,请检查表单信息')
}
}).catch(error => {
console.warn('[手术申请] 更新接口异常:', error?.message || error)
console.error('更新手术失败:', error)
proxy.$modal.msgError('更新手术失败,请检查表单信息')
})
}
} else {

View File

@@ -152,7 +152,7 @@
</el-tab-pane>
<el-tab-pane label="手术申请" name="surgery">
<surgeryApplication :patientInfo="patientInfo" :activeTab="activeTab" ref="surgeryRef"
@saved="() => { prescriptionRef?.getListInfo(); surgeryRef?.getList() }" />
@saved="() => prescriptionRef?.getListInfo()" />
</el-tab-pane>
<el-tab-pane label="电子处方" name="eprescription">
<eprescriptionlist :patientInfo="patientInfo" ref="eprescriptionRef" />

View File

@@ -86,13 +86,9 @@
</template>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="patientName" label="患者姓名" width="120" />
<el-table-column label="申请单名称" width="140">
<template #default="scope">
<span>{{ getItemName(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column prop="name" label="申请单名称" width="140" />
<el-table-column prop="createTime" label="创建时间" width="160" />
<el-table-column prop="prescriptionNo" label="申请单号" width="140" />
<el-table-column prop="prescriptionNo" label="处方号" width="140" />
<el-table-column prop="requesterId_dictText" label="申请者" width="120" />
<el-table-column label="申请单状态" width="120" align="center">
<template #default="scope">
@@ -163,7 +159,7 @@
currentDetail.patientName || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单名称">{{
getItemName(currentDetail)
currentDetail.name || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单状态">{{
parseStatus(currentDetail.status)
@@ -171,7 +167,7 @@
<el-descriptions-item label="创建时间">{{
currentDetail.createTime || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单号">{{
<el-descriptions-item label="处方号">{{
currentDetail.prescriptionNo || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请者">{{
@@ -227,47 +223,6 @@
<el-form-item label="申请单名称">
<el-input v-model="editForm.name" />
</el-form-item>
<el-form-item label="发往科室">
<el-tree-select
clearable
style="width: 100%"
v-model="editForm.targetDepartment"
filterable
:data="orgOptions"
:props="{
value: 'id',
label: 'name',
children: 'children',
}"
value-key="id"
check-strictly
placeholder="请选择科室"
/>
</el-form-item>
<el-form-item label="紧急程度">
<el-select v-model="editForm.urgencyLevel" placeholder="请选择紧急程度" clearable style="width: 100%">
<el-option label="普通" value="routine" />
<el-option label="急诊" value="emergency" />
</el-select>
</el-form-item>
<el-form-item label="过敏史">
<el-input v-model="editForm.allergyHistory" type="textarea" :rows="2" />
</el-form-item>
<el-form-item label="检查目的">
<el-input v-model="editForm.examinationPurpose" type="textarea" :rows="2" />
</el-form-item>
<el-form-item label="病史摘要">
<el-input v-model="editForm.medicalHistorySummary" type="textarea" :rows="2" />
</el-form-item>
<el-form-item label="期望检查时间">
<el-date-picker
v-model="editForm.expectedExaminationTime"
type="datetime"
placeholder="请选择期望检查时间"
style="width: 100%"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-form-item label="临床诊断">
<el-input v-model="editForm.clinicalDiagnosis" type="textarea" :rows="2" />
</el-form-item>
@@ -444,36 +399,9 @@ const parseStatus = (status) => {
return statusMap[String(status)] || '-';
};
/**
* 获取申请单展示名称:优先使用具体医嘱名称列表
*/
const getItemName = (row) => {
const items = row?.requestFormDetailList;
if (items && items.length > 0) {
return items.map(item => item.adviceName).filter(Boolean).join('、') || row.name || '-';
}
return row.name || '-';
};
/**
* 构建打印用项目名称字符串(同步函数,用于模板字符串)
*/
const buildItemNames = (row) => {
const items = row?.requestFormDetailList;
if (items && items.length > 0) {
return items.map(item => item.adviceName).filter(Boolean).join('、') || row.name || '';
}
return row.name || '';
};
const labelMap = {
categoryType: '项目类别',
targetDepartment: '发往科室',
urgencyLevel: '紧急程度',
allergyHistory: '过敏史',
examinationPurpose: '检查目的',
medicalHistorySummary: '病史摘要',
expectedExaminationTime: '期望检查时间',
symptom: '症状',
sign: '体征',
clinicalDiagnosis: '临床诊断',
@@ -503,27 +431,20 @@ const getLocationInfo = () => {
};
const recursionFun = (targetDepartment) => {
if (!targetDepartment) return '';
if (!Array.isArray(orgOptions.value) || orgOptions.value.length === 0) return '';
let name = '';
for (let index = 0; index < orgOptions.value.length; index++) {
const obj = orgOptions.value[index];
if (obj.id == targetDepartment) {
name = obj.name;
break;
}
const subObjArray = obj['children'];
if (Array.isArray(subObjArray)) {
for (let i = 0; i < subObjArray.length; i++) {
const item = subObjArray[i];
for (let index = 0; index < subObjArray.length; index++) {
const item = subObjArray[index];
if (item.id == targetDepartment) {
name = item.name;
break;
}
}
}
if (name) break;
}
return name;
};
@@ -535,15 +456,7 @@ const handleViewDetail = (row) => {
if (row.descJson) {
try {
const obj = JSON.parse(row.descJson);
if (obj.targetDepartment) {
const deptName = recursionFun(obj.targetDepartment);
obj.targetDepartment = deptName || obj.targetDepartment;
}
// 紧急程度转换为显示文本
const urgencyMap = { routine: '普通', emergency: '急诊' };
if (obj.urgencyLevel) {
obj.urgencyLevel = urgencyMap[obj.urgencyLevel] || obj.urgencyLevel;
}
obj.targetDepartment = recursionFun(obj.targetDepartment);
descJsonData.value = obj;
} catch (e) {
console.error('解析 descJson 失败:', e);
@@ -565,12 +478,6 @@ const handleEdit = (row) => {
if (row.descJson) {
try {
const desc = JSON.parse(row.descJson);
form.targetDepartment = desc.targetDepartment || '';
form.urgencyLevel = desc.urgencyLevel || '';
form.allergyHistory = desc.allergyHistory || '';
form.examinationPurpose = desc.examinationPurpose || '';
form.medicalHistorySummary = desc.medicalHistorySummary || '';
form.expectedExaminationTime = desc.expectedExaminationTime || '';
form.clinicalDiagnosis = desc.clinicalDiagnosis || '';
form.attention = desc.attention || '';
form.symptom = desc.symptom || '';
@@ -601,12 +508,6 @@ const handleSaveEdit = async () => {
name: editForm.value.name,
organizationId: editDetail.value.inHospitalOrgId || patientInfo.value?.inHospitalOrgId,
descJson: JSON.stringify({
targetDepartment: editForm.value.targetDepartment,
urgencyLevel: editForm.value.urgencyLevel,
allergyHistory: editForm.value.allergyHistory,
examinationPurpose: editForm.value.examinationPurpose,
medicalHistorySummary: editForm.value.medicalHistorySummary,
expectedExaminationTime: editForm.value.expectedExaminationTime,
clinicalDiagnosis: editForm.value.clinicalDiagnosis,
attention: editForm.value.attention,
symptom: editForm.value.symptom,
@@ -750,9 +651,9 @@ const buildPrintContent = (row) => {
return `
<h2>检查申请单</h2>
<div class="info-row"><span class="label">患者姓名:</span>${row.patientName || '-'}</div>
<div class="info-row"><span class="label">申请单名称:</span>${buildItemNames(row) || '-'}</div>
<div class="info-row"><span class="label">申请单名称:</span>${row.name || '-'}</div>
<div class="info-row"><span class="label">创建时间:</span>${row.createTime || '-'}</div>
<div class="info-row"><span class="label">申请单号:</span>${row.prescriptionNo || '-'}</div>
<div class="info-row"><span class="label">处方号:</span>${row.prescriptionNo || '-'}</div>
<div class="info-row"><span class="label">申请者:</span>${row.requesterId_dictText || '-'}</div>
<div class="info-row"><span class="label">申请单状态:</span>${parseStatus(row.status)}</div>
${descHtml ? `<h3>申请单描述</h3>${descHtml}` : ''}

View File

@@ -1,20 +0,0 @@
<!--
* 住院医生站 汇总发药申请复用药房发药汇总单能力
-->
<template>
<div class="summary-drug-application">
<MedicationSummary />
</div>
</template>
<script setup>
import MedicationSummary from '@/views/drug/inpatientMedicationDispensing/components/MedicationSummary.vue';
</script>
<style scoped>
.summary-drug-application {
height: 100%;
min-height: 400px;
overflow: auto;
}
</style>

View File

@@ -173,7 +173,7 @@ import {computed, getCurrentInstance, ref, watch} from 'vue';
import {Refresh, Search} from '@element-plus/icons-vue';
import {patientInfo} from '../../store/patient.js';
import {getInspection} from './api';
import {getDepartmentList} from '@/api/public.js';
import {getOrgList} from '@/views/doctorstation/components/api.js';
const { proxy } = getCurrentInstance();
@@ -332,8 +332,8 @@ const hasMatchedFields = computed(() => {
/** 查询科室 */
const getLocationInfo = () => {
getDepartmentList().then((res) => {
orgOptions.value = res.data || [];
getOrgList().then((res) => {
orgOptions.value = res.data.records;
});
};
@@ -345,15 +345,13 @@ const recursionFun = (targetDepartment) => {
name = obj.name;
}
const subObjArray = obj['children'];
if (subObjArray && subObjArray.length > 0) {
for (let i = 0; i < subObjArray.length; i++) {
const item = subObjArray[i];
for (let index = 0; index < subObjArray.length; index++) {
const item = subObjArray[index];
if (item.id == targetDepartment) {
name = item.name;
}
}
}
}
return name;
};

View File

@@ -42,40 +42,6 @@
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="紧急程度" prop="urgencyLevel" style="width: 100%">
<el-select v-model="form.urgencyLevel" placeholder="请选择紧急程度" clearable style="width: 100%">
<el-option label="普通" value="routine" />
<el-option label="急诊" value="emergency" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="过敏史" prop="allergyHistory" style="width: 100%">
<el-input v-model="form.allergyHistory" autocomplete="off" type="textarea" placeholder="如:造影剂过敏史等" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="检查目的" prop="examinationPurpose" style="width: 100%">
<el-input v-model="form.examinationPurpose" autocomplete="off" type="textarea" placeholder="请说明检查目的" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="病史摘要" prop="medicalHistorySummary" style="width: 100%">
<el-input v-model="form.medicalHistorySummary" autocomplete="off" type="textarea" placeholder="请简要描述患者病史" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="期望检查时间" prop="expectedExaminationTime" style="width: 100%">
<el-date-picker
v-model="form.expectedExaminationTime"
type="datetime"
placeholder="请选择期望检查时间"
style="width: 100%"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="症状" prop="symptom" style="width: 100%">
<el-input v-model="form.symptom" autocomplete="off" type="textarea" />
@@ -179,11 +145,6 @@ const transferValue = ref([]);
const form = reactive({
// categoryType: '', // 项目类别
targetDepartment: '', // 发往科室
urgencyLevel: '', // 紧急程度
allergyHistory: '', // 过敏史
examinationPurpose: '', // 检查目的
medicalHistorySummary: '', // 病史摘要
expectedExaminationTime: '', // 期望检查时间
symptom: '', // 症状
sign: '', // 体征
clinicalDiagnosis: '', // 临床诊断

View File

@@ -122,6 +122,7 @@
<el-table-column label="类型" align="center" prop="" width="120">
<template #default="scope">
{{ console.log(scope.row, 1111) }}
<el-radio-group
v-model="scope.row.therapyEnum"
size="small"
@@ -269,6 +270,7 @@
</el-table-column>
<el-table-column label="频次/用法" align="center" prop="" width="180">
<template #default="scope">
{{ console.log(scope.row) }}
<span v-if="!scope.row.isEdit && scope.row.adviceType == 1" style="text-align: right">
{{
[
@@ -1210,8 +1212,12 @@ function handleSave() {
getListInfo(false);
bindMethod.value = {};
nextId.value == 1;
// 处方保存成功后,自动将医嘱信息同步至患者处置记录
// handleEmrTreatment();
} else {
proxy.$modal.msgError(res.message);
conso;
isSaving.value = false;
}
})
@@ -1311,9 +1317,6 @@ function handleCancelEdit(row, index) {
function handleSaveSign(row, index) {
if (row.adviceType != 2) {
let itemNo = row.adviceType == 1 ? row.methodCode : row.adviceDefinitionId;
if (!itemNo) {
console.warn('绑定设备检查跳过itemNo为空adviceType=' + row.adviceType + ', adviceName=' + row.adviceName + '');
} else {
getBindDevice({ typeCode: row.adviceType, itemNo: itemNo }).then((res) => {
if (res.data.length == 0) {
return;
@@ -1331,7 +1334,6 @@ function handleSaveSign(row, index) {
}
});
}
}
// 更新UI状态
row.isEdit = false;

View File

@@ -17,11 +17,13 @@
</el-tab-pane>
<!-- <el-tab-pane label="医技报告" name="fourth">Task</el-tab-pane> -->
<el-tab-pane label="检验申请" name="test">
<TestApplication ref="testApplicationRef" :show-status-column="false" />
<TestApplication ref="testApplicationRef" :show-status-column="true" />
</el-tab-pane>
```vue
<el-tab-pane label="检查申请" name="examine">
<ExamineApplication ref="examineApplicationRef" />
</el-tab-pane>
```
<el-tab-pane label="汇总发药申请" name="summaryDrug">
<SummaryDrugApplication ref="summaryDrugApplicationRef" />
</el-tab-pane>
@@ -44,11 +46,10 @@
</div>
</template>
<script setup>
import { computed, onBeforeMount, onMounted, provide, reactive, ref, watch } from 'vue';
import {computed, onBeforeMount, onMounted, provide, reactive, ref, watch,} from 'vue';
import Emr from './emr/index.vue';
import inPatientBarDoctorFold from '@/components/patientBar/inPatientBarDoctorFold.vue';
import SummaryDrugApplication from './components/applicationShow/summaryDrugApplication.vue';
import PatientList from '@/components/PatientList/patient-list.vue';
import {localPatientInfo, updateLocalPatientInfo} from './store/localPatient';
import {patientInfo, updatePatientInfo} from './store/patient';
@@ -83,7 +84,6 @@ const currentPatientInfo = ref({});
const testApplicationRef = ref();
const examineApplicationRef = ref();
const surgeryApplicationRef = ref();
const summaryDrugApplicationRef = ref();
const bloodTtransfusionAapplicationRef = ref();
// 患者列表相关逻辑

View File

@@ -181,7 +181,7 @@
v-for="dept in getFilteredOptions(scope.row, 'departmentOptions')"
:key="dept.id"
:label="dept.name"
:value="String(dept.id)"
:value="dept.id"
/>
</el-select>
<el-select
@@ -197,7 +197,7 @@
v-for="dept in getFilteredOptions(scope.row, 'locationOptions')"
:key="dept.value"
:label="dept.label"
:value="String(dept.value)"
:value="dept.value"
/>
</el-select>
</template>
@@ -280,16 +280,8 @@
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="组套名称" min-width="180" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.name || scope.row.Name || '' }}
</template>
</el-table-column>
<el-table-column label="使用范围" width="100" align="center">
<template #default="scope">
{{ getRangeText(scope.row) }}
</template>
</el-table-column>
<el-table-column label="组套名称" prop="name" min-width="180" show-overflow-tooltip />
<el-table-column label="使用范围" prop="rangeCode_dictText" width="100" align="center" />
<el-table-column label="明细数量" width="100" align="center">
<template #default="scope">
{{ scope.row.detailList?.length || 0 }} 项
@@ -489,15 +481,10 @@ watch(
// 加载科室选项
function loadDepartmentOptions() {
getOrgList()
.then((res) => {
getOrgList().then((res) => {
if (res.data && res.data.records && res.data.records.length > 0) {
departmentOptions.value = res.data.records[0].children || [];
}
})
.catch(() => {
console.warn('科室列表加载失败(可能无权限)');
departmentOptions.value = [];
});
}
@@ -517,14 +504,9 @@ function getAdviceBaseInfos() {
});
}
function getDiseaseInitLoc() {
getDiseaseTreatmentInitLoc(16)
.then((response) => {
getDiseaseTreatmentInitLoc(16).then((response) => {
console.log('Disease Treatment Init Loc:', response);
locationOptions.value = response.data.locationOptions;
})
.catch(() => {
console.warn('位置列表加载失败(可能无权限)');
locationOptions.value = [];
});
}
// 下拉框模糊搜索过滤
@@ -621,23 +603,15 @@ function selectChange(row) {
const price = row.priceList?.[0]?.price || 0;
//获取大小单位
const uniqueUnitCodes = getUnitCodeOptions(row);
// 设置默认单位:优先使用 minUnitCode小单位回退到 unitCode大单位
let defaultUnitCode = '';
if (row.minUnitCode) {
defaultUnitCode = String(row.minUnitCode);
} else if (row.unitCode) {
defaultUnitCode = String(row.unitCode);
}
// 设置默认执行科室/位置(统一转为字符串,避免 el-select 类型不匹配)
// 设置默认执行科室/位置
let defaultPositionId = undefined;
if (row.adviceType === 3 && departmentOptions.value.length > 0) {
// 诊疗:优先使用患者所在科室,否则取第一个科室
const patientOrgId = props.patientInfo.organizationId;
const matched = departmentOptions.value.find(d => String(d.id) === String(patientOrgId));
defaultPositionId = matched ? String(matched.id) : String(departmentOptions.value[0].id);
defaultPositionId = departmentOptions.value.find(d => d.id === props.patientInfo.organizationId)?.id
|| departmentOptions.value[0]?.id;
} else if (row.adviceType === 2 && locationOptions.value.length > 0) {
// 耗材:默认取第一个药房/耗材房
defaultPositionId = String(locationOptions.value[0].value);
defaultPositionId = locationOptions.value[0]?.value;
}
//插入费用列表
feeItemsList.value.push({
@@ -645,8 +619,8 @@ function selectChange(row) {
uniqueUnitCodes: uniqueUnitCodes,
unitPrice: (price / (row.partPercent || 1)).toFixed(6), // 根据拆零比计算单价
quantity: 1,
positionId: defaultPositionId, // 默认执行科室/位置(字符串类型)
selectUnitCode: defaultUnitCode, // 默认选择小单位
positionId: defaultPositionId, // 默认执行科室/位置
selectUnitCode: String(row.minUnitCode || ''), // 默认选择小单位,确保字符串类型
});
}
@@ -771,7 +745,7 @@ function openGroupSetDialog() {
function loadGroupSets() {
groupSetLoading.value = true;
getOrderGroup({ organizationId: orgId.value })
getOrderGroup({ organizationId: orgId.value, searchKey: groupSetSearchText.value })
.then((res) => {
const data = res?.data || {};
if (groupSetRange.value === 1) {
@@ -791,13 +765,6 @@ function loadGroupSets() {
});
}
function getRangeText(row) {
// 后端未返回rangeCode根据当前选中的范围标签显示
const rangeMap = { 1: '个人', 2: '科室', 3: '全院' };
if (row.rangeCode_dictText) return row.rangeCode_dictText;
return rangeMap[groupSetRange.value] || '';
}
function handleGroupSetSelect(row) {
selectedGroupSet.value = row;
}

View File

@@ -273,9 +273,8 @@ function handleSearch() {
// 清除缓存(搜索时需要重新加载)
patientDataCache.value.clear();
// 通过递增 key 强制重新渲染树组件,触发重新加载所有病区患者列表
// 此时 searchKey 已有值,loadPatientList 会将 searchKey 传给后端进行过滤
treeKey.value += 1;
// 重新加载所有已展开病区患者列表
reloadAllPatients();
}
// 暴露方法供外部调用

View File

@@ -67,6 +67,9 @@
</el-button>
</div>
</div>
</div>
</template>
</div>
<div
style="padding: 10px; background-color: #eef9fd; height: 100%; overflow-y: auto"
v-loading="loading"
@@ -229,7 +232,7 @@ import {adviceCancel, adviceExecute, adviceNoExecute, getPrescriptionList} from
import {patientInfoList} from '../../components/store/patient.js';
import {lotNumberMatch} from '@/api/public';
import {formatDateStr} from '@/utils/index';
import {getCurrentInstance, nextTick, ref, provide} from 'vue';
import {getCurrentInstance, nextTick, ref} from 'vue';
const activeNames = ref([]);
const prescriptionList = ref([]);
@@ -239,8 +242,6 @@ const therapyEnum = ref(undefined);
const { proxy } = getCurrentInstance();
const loading = ref(false);
const chooseAll = ref(false);
// 独立维护选中行ID集合避免el-table内部selection状态异常导致联动全选
const selectedRowIds = ref(new Set());
const props = defineProps({
exeStatus: {
type: Number,
@@ -282,10 +283,9 @@ function handleGetPrescription() {
exeStatus: props.exeStatus,
requestStatus: props.requestStatus,
}).then((res) => {
try {
const records = res?.data?.records || [];
// try {
// 根据encounterId分组
const groupedPrescriptions = records.reduce((groups, prescription) => {
const groupedPrescriptions = res.data.records.reduce((groups, prescription) => {
// 获取当前医嘱全部执行频次
let rate;
let times;
@@ -430,26 +430,18 @@ function handleGetPrescription() {
// 将分组结果转换为数组形式
prescriptionList.value = Object.values(groupedPrescriptions);
loading.value = false;
// 默认选中全部行
nextTick(() => {
defaultSelectAllRows();
});
} catch (error) {
console.error('医嘱执行-获取处方列表数据处理失败:', error);
prescriptionList.value = [];
} finally {
loading.value = false;
}
}).catch((error) => {
console.error('医嘱执行-获取处方列表接口失败:', error);
prescriptionList.value = [];
loading.value = false;
// } catch {
// loading.value = false;
// }
});
chooseAll.value = false;
} else {
prescriptionList.value = [];
selectedRowIds.value.clear();
loading.value = false;
// proxy.$message.warning('请选择患者');
}
}
@@ -508,28 +500,23 @@ function handleCancel() {
let list = getSelectRows();
let producerIds = [];
list.forEach((item) => {
// 从 exePerformRecordList 直接提取 procedureId过滤空值避免后端SQL异常
const procedureIds = (item.exePerformRecordList || [])
.map((record) => record.procedureId)
.filter((id) => id != null && id !== '');
// 从 exePerformRecordList 直接提取 procedureId确保取消执行时数据完整
const procedureIds = (item.exePerformRecordList || []).map((record) => record.procedureId);
if (procedureIds.length === 0 && (!item.procedureIds || item.procedureIds.length === 0)) {
proxy.$modal.msgError('请选择已执行的医嘱记录');
return;
}
const ids = procedureIds.length > 0 ? procedureIds : item.procedureIds;
producerIds.push(
...ids
.filter((value) => value != null && value !== '')
.map((value) => {
...ids.map((value) => {
return {
procedureId: value,
therapyEnum: Number(item.therapyEnum),
therapyEnum: item.therapyEnum,
};
})
);
});
if (producerIds.length === 0) {
proxy.$modal.msgError('未找到有效的执行记录,无法取消执行');
return;
}
adviceCancel({ adviceExecuteDetailList: producerIds }).then((res) => {
@@ -539,20 +526,14 @@ function handleCancel() {
} else {
proxy.$modal.msgError(res.msg || '取消执行失败');
}
}).catch(() => {
proxy.$modal.msgError('取消执行失败,请稍后重试');
});
}
function getSelectRows() {
// 优先从独立维护的selectedRowIds集合中获取选中行避免el-table内部selection状态异常
const list = [];
prescriptionList.value.forEach((item) => {
item.forEach((row) => {
if (selectedRowIds.value.has(row.requestId)) {
list.push(row);
}
});
// 获取选中的医嘱信息
let list = [];
prescriptionList.value.forEach((item, index) => {
list = [...list, ...proxy.$refs['tableRef' + index][0].getSelectionRows()];
});
return list;
}
@@ -628,14 +609,12 @@ function handelSwicthChange(value) {
if (value) {
// 全选选中所有行并联动checkbox
item.forEach((row) => {
selectedRowIds.value.add(row.requestId);
tableRef[0].toggleRowSelection(row, true);
selectAllCheckboxesInRow(row);
});
} else {
// 取消全选取消选中所有行并联动checkbox
item.forEach((row) => {
selectedRowIds.value.delete(row.requestId);
tableRef[0].toggleRowSelection(row, false);
unselectAllCheckboxesInRow(row);
});
@@ -646,14 +625,11 @@ function handelSwicthChange(value) {
// 默认选中全部行
function defaultSelectAllRows() {
// 清空并重建选中集合
selectedRowIds.value.clear();
prescriptionList.value.forEach((item, index) => {
const tableRef = proxy.$refs['tableRef' + index];
if (tableRef && tableRef[0]) {
// 选中该表格的所有行
item.forEach((row) => {
selectedRowIds.value.add(row.requestId);
tableRef[0].toggleRowSelection(row, true);
// 同时选中该行内部的所有checkbox
selectAllCheckboxesInRow(row);
@@ -733,14 +709,13 @@ function checkAndToggleRowSelection(row) {
const tableRef = proxy.$refs['tableRef' + tableIndex];
if (tableRef && tableRef[0]) {
const isAllSelected = isAllCheckboxesSelected(row);
const isCurrentlySelected = selectedRowIds.value.has(row.requestId);
const selectedRows = tableRef[0].getSelectionRows();
const isCurrentlySelected = selectedRows.some((r) => r.requestId === row.requestId);
// 根据checkbox状态更新表格行选中状态
if (isAllSelected && !isCurrentlySelected) {
selectedRowIds.value.add(row.requestId);
tableRef[0].toggleRowSelection(row, true);
} else if (!isAllSelected && isCurrentlySelected) {
selectedRowIds.value.delete(row.requestId);
tableRef[0].toggleRowSelection(row, false);
}
}
@@ -753,11 +728,9 @@ function handleRowSelect(selection, row, tableIndex) {
const isSelected = selection.some((item) => item.requestId === row.requestId);
if (isSelected) {
selectedRowIds.value.add(row.requestId);
// 选中行时选中该行内部的所有checkbox
selectAllCheckboxesInRow(row);
} else {
selectedRowIds.value.delete(row.requestId);
// 取消选中行时取消选中该行内部的所有checkbox
unselectAllCheckboxesInRow(row);
}
@@ -774,13 +747,11 @@ function handleSelectAll(selection, tableIndex) {
if (selection.length > 0) {
// 全选时选中所有行内部的所有checkbox
tableData.forEach((row) => {
selectedRowIds.value.add(row.requestId);
selectAllCheckboxesInRow(row);
});
} else {
// 取消全选时取消选中所有行内部的所有checkbox
tableData.forEach((row) => {
selectedRowIds.value.delete(row.requestId);
unselectAllCheckboxesInRow(row);
});
}
@@ -792,12 +763,16 @@ function handleSelectAll(selection, tableIndex) {
// 更新全选开关状态
function updateChooseAllStatus() {
let allSelected = true;
prescriptionList.value.forEach((item) => {
item.forEach((row) => {
if (!selectedRowIds.value.has(row.requestId)) {
prescriptionList.value.forEach((item, index) => {
const tableRef = proxy.$refs['tableRef' + index];
if (tableRef && tableRef[0]) {
const selectedRows = tableRef[0].getSelectionRows();
if (selectedRows.length !== item.length) {
allSelected = false;
}
} else {
allSelected = false;
}
});
});
chooseAll.value = allSelected;
}

View File

@@ -51,7 +51,7 @@
</template>
<script setup>
import {getCurrentInstance, ref, nextTick, provide} from 'vue';
import {getCurrentInstance} from 'vue';
import PatientList from '../components/patientList.vue';
import PrescriptionList from './components/prescriptionList.vue';
import { RequestStatus } from '@/utils/medicalConstants';

View File

@@ -181,7 +181,7 @@ function handleGetPrescription() {
getPrescriptionList({
encounterIds: encounterIds,
requestStatus: props.requestStatus,
...(type.value !== undefined ? { therapyEnum: type.value } : {}),
therapyEnum: type.value === 1 ? undefined : type.value === 2 ? 1 : 2, // 1=全部(不传), 2=长期(1), 3=临时(2)
pageSize: 10000,
pageNo: 1,
}).then((res) => {

View File

@@ -112,19 +112,6 @@
<el-form ref="dynamicForm" :model="formData" label-width="100px" :rules="formRules">
<div class="page-bottom">
<el-row :gutter="24">
<el-col :span="8">
<el-form-item style="margin-top: 15px" label="录入日期">
<el-date-picker
v-model="formData.recordingDate"
type="date"
placeholder="请选择日期"
size="small"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item style="margin-top: 15px" label="录入时间">
<div class="input-time-inline">
@@ -779,7 +766,6 @@ const receptionTime = ref(null);
// 表单数据 - 体征录入
const formData = ref({
recordingDate: '',
timePoint: '',
temperature: '',
systolicPressure: '',
@@ -886,7 +872,6 @@ function getPatientDetial() {
// 默认查询今天的数据
const today = moment().format('YYYY-MM-DD');
receptionTime.value = [today, today];
formData.value.recordingDate = today;
// 自动加载数据
getPatientList();
listPatient(queryParams.value).then((res) => {
@@ -935,7 +920,6 @@ function handleRowClick(row) {
formData.value = {
...formData.value,
id: row.id,
recordingDate: row.recordingDate || '',
timePoint: convertTimePoint(row.timePoint) || '',
temperature: row.temperature || '',
systolicPressure: row.systolicPressure || '',
@@ -1054,7 +1038,7 @@ function confirmCharge() {
params.vitalSignsCode = vitalSignsCode;
params.vitalSignsValues = vitalSignsValues;
params.recordingDate = formData.value.recordingDate || moment(new Date()).format('YYYY-MM-DD');
params.recordingDate = moment(new Date()).format('YYYY-MM-DD');
addVitalSigns(params).then(res => {
console.log('保存成功:', res);
@@ -1063,7 +1047,6 @@ function confirmCharge() {
getPatientList();
// 清空表单
formData.value = {
recordingDate: '',
timePoint: '',
temperature: '',
systolicPressure: '',

View File

@@ -1404,10 +1404,6 @@ async function handleChargeCharge(row) {
// 关闭计费弹窗
function closeChargeDialog() {
// 先关闭子组件中所有悬浮的字典弹窗,避免主弹窗关闭后残留
if (prescriptionRef.value && prescriptionRef.value.closeAllPopovers) {
prescriptionRef.value.closeAllPopovers()
}
showChargeDialog.value = false
chargePatientInfo.value = {}
chargeSurgeryInfo.value = {}

View File

@@ -220,15 +220,15 @@
<!-- 底部控制面板 -->
<div class="footer-section">
<!-- 室快速过滤栏 -->
<!-- 就诊科室快速过滤栏 -->
<div class="filter-section">
<div class="filter-label">
室快速过滤栏
就诊科室快速过滤栏
</div>
<div class="filter-select-wrapper">
<el-select
v-model="selectedClinicRoom"
placeholder="请选择室"
v-model="selectedDept"
placeholder="请选择就诊科室"
clearable
filterable
style="width: 100%"
@@ -239,10 +239,10 @@
value="all"
/>
<el-option
v-for="room in clinicRoomList"
:key="room"
:label="room"
:value="room"
v-for="dept in departmentList"
:key="dept.id"
:label="dept.name"
:value="dept.id"
/>
</el-select>
</div>
@@ -648,6 +648,7 @@ import { Refresh } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import {
getCandidatePool,
getLocationTree,
getTriageQueueList,
addToQueue,
removeFromQueue,
@@ -680,10 +681,10 @@ const selectedCandidates = ref([])
// 显示选项
const showOnlyWaiting = ref(false)
// 室过滤(按诊室维度筛选
const selectedClinicRoom = ref('all')
// 诊室列表(从数据中动态提取)
const clinicRoomList = ref([])
// 室过滤(改为使用就诊科室
const selectedDept = ref('all')
// 就诊科室列表
const departmentList = ref([])
// 修复【#397】动态获取当前科室名称
const currentDeptName = computed(() => {
@@ -906,11 +907,13 @@ const mapFrontendStatusToBackend = (status) => {
// 从数据库加载队列
const loadQueueFromDb = async () => {
try {
// 使用当前登录人科室
// 如果选择了具体科室,就按科室加载;否则加载当前登录人科室(后端默认)
const organizationId = selectedDept.value !== 'all' ? selectedDept.value : undefined
// 只查询今天的患者
const today = new Date()
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`
console.log('【心内科】loadQueueFromDb 开始:date=', todayStr)
const res = await getTriageQueueList({ date: todayStr }).catch((err) => {
console.log('【心内科】loadQueueFromDb 开始:organizationId=', organizationId, 'date=', todayStr, 'selectedDept=', selectedDept.value)
const res = await getTriageQueueList({ organizationId, date: todayStr }).catch((err) => {
console.error('【心内科】loadQueueFromDb 请求异常:', err)
return { code: 500, msg: err?.message || '请求失败', data: null }
})
@@ -1138,8 +1141,6 @@ const loadDataFromApi = async () => {
// 同步当前呼叫(队列从 DB 加载后已同步;这里再兜底一次)
syncCurrentCallFromQueue()
// 提取诊室列表供过滤栏使用
extractClinicRooms()
console.log('【心内科】数据加载完成:候选池', originalCandidatePoolList.value.length, '条,队列', originalQueueList.value.length, '条')
ElMessage.success('【心内科】已从门诊挂号接口加载数据')
} catch (e) {
@@ -1151,37 +1152,56 @@ const loadDataFromApi = async () => {
totalSignedIn.value = originalCandidatePoolList.value.length
totalInQueue.value = originalQueueList.value.length
syncCurrentCallFromQueue()
extractClinicRooms()
}
}
// 原始数据存储(用于过滤)
const originalCandidatePoolList = ref(getInitialCandidatePoolList())
// 提取诊室列表(从队列和候选池数据中动态获取)
const extractClinicRooms = () => {
const roomSet = new Set()
// 从队列中提取
originalQueueList.value.forEach(item => {
if (item.room && item.room !== '-') {
roomSet.add(item.room)
// 辅助函数:扁平化科室树形结构
const flattenDepartmentTree = (tree, result = []) => {
if (!Array.isArray(tree)) return result
tree.forEach(node => {
if (node.id && node.name) {
result.push({ id: node.id, name: node.name })
}
if (node.children && Array.isArray(node.children)) {
flattenDepartmentTree(node.children, result)
}
})
// 从候选池中提取
originalCandidatePoolList.value.forEach(item => {
if (item.room && item.room !== '-') {
roomSet.add(item.room)
return result
}
// 加载就诊科室列表
const loadDepartmentList = async () => {
try {
const response = await getLocationTree()
if (response && response.data) {
// 扁平化树形结构
departmentList.value = flattenDepartmentTree(response.data)
console.log('【心内科】已加载就诊科室列表:', departmentList.value.length, '个科室')
}
})
clinicRoomList.value = Array.from(roomSet).sort()
} catch (error) {
console.error('【心内科】加载就诊科室列表失败:', error)
ElMessage.warning('加载就诊科室列表失败,使用默认数据')
}
}
// 获取选中科室的名称
const getSelectedDeptName = () => {
if (selectedDept.value === 'all') return null
const dept = departmentList.value.find(d => d.id === selectedDept.value)
return dept ? dept.name : null
}
// 过滤后的智能候选池数据
const filteredCandidatePoolList = computed(() => {
if (selectedClinicRoom.value === 'all') {
if (selectedDept.value === 'all') {
return originalCandidatePoolList.value
}
return originalCandidatePoolList.value.filter(item => item.room === selectedClinicRoom.value)
const deptName = getSelectedDeptName()
if (!deptName) return originalCandidatePoolList.value
return originalCandidatePoolList.value.filter(item => item.room === deptName)
})
// 原始队列数据存储(用于过滤)
@@ -1203,16 +1223,19 @@ const formatSecondsToMmSs = (totalSeconds) => {
return `${mm}:${ss}`
}
// 过滤后的智能队列数据(同时考虑室过滤和状态过滤)
// 过滤后的智能队列数据(同时考虑室过滤和状态过滤)
const filteredQueueList = computed(() => {
let filtered = originalQueueList.value
// 先过滤掉"已完成"状态的患者(无论什么情况都不显示)
filtered = filtered.filter(item => item.status !== '已完成')
// 再按室过滤
if (selectedClinicRoom.value !== 'all') {
filtered = filtered.filter(item => item.room === selectedClinicRoom.value)
// 再按室过滤
if (selectedDept.value !== 'all') {
const deptName = getSelectedDeptName()
if (deptName) {
filtered = filtered.filter(item => item.room === deptName)
}
}
// 再按状态过滤(只显示等待)
@@ -1724,9 +1747,9 @@ const handleNextPatient = async () => {
reqData.organizationId = selectedQueueRow.value.organizationId
} else {
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
// 全科模式:优先用"当前叫号中/第一个等待"所在科室
let orgId = null
{
let orgId = selectedDept.value !== 'all' ? selectedDept.value : undefined
// "全科"模式:优先用"当前叫号中/第一个等待"所在科室
if (orgId == null) {
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
const waiting = originalQueueList.value.find((i) => i.status === '等待')
console.log('【心内科】handleNextPatient 查找:叫号中=', calling?.patientName, '等待=', waiting?.patientName)
@@ -1762,9 +1785,9 @@ const handleSkip = async () => {
reqData.organizationId = selectedQueueRow.value.organizationId
} else {
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
// 全科模式:优先用”当前叫号中”所在科室
let orgId = null
{
let orgId = selectedDept.value !== 'all' ? selectedDept.value : undefined
// “全科”模式:优先用“当前叫号中”所在科室
if (orgId == null) {
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
orgId = calling?.organizationId
}
@@ -1796,9 +1819,9 @@ const handleComplete = async () => {
reqData.organizationId = selectedQueueRow.value.organizationId
} else {
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
// 全科模式:优先用”当前叫号中”所在科室
let orgId = null
{
let orgId = selectedDept.value !== 'all' ? selectedDept.value : undefined
// “全科”模式:优先用“当前叫号中”所在科室
if (orgId == null) {
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
orgId = calling?.organizationId
}
@@ -1830,9 +1853,9 @@ const handleRequeue = async () => {
reqData.organizationId = selectedQueueRow.value.organizationId
} else {
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
// 全科模式:优先用”当前叫号中”所在科室
let orgId = null
{
let orgId = selectedDept.value !== 'all' ? selectedDept.value : undefined
// “全科”模式:优先用“当前叫号中”所在科室
if (orgId == null) {
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
orgId = calling?.organizationId
}
@@ -2098,6 +2121,8 @@ const handleTestRule = () => {
// 组件挂载
onMounted(() => {
// 加载就诊科室列表
loadDepartmentList()
// 初始化:优先从后端加载,失败则回退本地假数据
loadDataFromApi()
startWaitingTimer()