370【住院护士站站-》进入“三测单”模块报错
371 【业务配置】住院医生站-“呼吸内科病房”未在西药房取药规则中维护配置
This commit is contained in:
@@ -116,4 +116,12 @@ public interface IDoctorStationAdviceAppService {
|
||||
* @return 检查url相关参数
|
||||
*/
|
||||
R<?> getTestResult(Long encounterId);
|
||||
|
||||
/**
|
||||
* 获取当前科室已配置的药品类别列表
|
||||
*
|
||||
* @param organizationId 科室id
|
||||
* @return 已配置的药品类别编码列表
|
||||
*/
|
||||
R<?> getConfiguredCategories(Long organizationId);
|
||||
}
|
||||
|
||||
@@ -155,6 +155,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
String safePricingFlag = pricingFlag != null ? pricingFlag.toString() : "";
|
||||
String safePageNo = pageNo != null ? pageNo.toString() : "";
|
||||
String safePageSize = pageSize != null ? pageSize.toString() : "";
|
||||
String safeCategoryCode = categoryCode != null ? categoryCode : "";
|
||||
|
||||
// 设置默认科室:仅当前端/调用方未传 organizationId 时才回退到登录人科室
|
||||
// 否则会导致门诊划价等场景(按患者挂号科室查询)返回空
|
||||
@@ -169,7 +170,7 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
String cacheKey = null;
|
||||
if (useCache) {
|
||||
// 生成缓存 key:无搜索关键字时按科室缓存
|
||||
cacheKey = ADVICE_BASE_INFO_CACHE_PREFIX + organizationId + ":" + safeAdviceTypesStr + ":" + safePageNo + ":" + safePageSize;
|
||||
cacheKey = ADVICE_BASE_INFO_CACHE_PREFIX + organizationId + ":" + safeAdviceTypesStr + ":" + safeCategoryCode + ":" + safePageNo + ":" + safePageSize;
|
||||
|
||||
// 先清除可能存在的无效缓存(JSONObject类型)
|
||||
if (redisCache.hasKey(cacheKey)) {
|
||||
@@ -281,6 +282,8 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
}
|
||||
String unitCode = ""; // 包装单位
|
||||
Long chargeItemDefinitionId; // 费用定价主表ID
|
||||
// 检查是否有取药科室配置(用于药品类型)
|
||||
boolean hasPharmacyConfig = medLocationConfig != null && !medLocationConfig.isEmpty();
|
||||
for (AdviceBaseDto baseDto : adviceBaseDtoList) {
|
||||
String tableName = baseDto.getAdviceTableName();
|
||||
if (CommonConstants.TableName.MED_MEDICATION_DEFINITION.equals(tableName)) { // 药品
|
||||
@@ -290,6 +293,9 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
// 是否为注射药物
|
||||
baseDto.setInjectFlag_enumText(EnumUtils.getInfoByValue(Whether.class, baseDto.getInjectFlag()));
|
||||
|
||||
// 设置是否缺少取药科室配置标志
|
||||
baseDto.setPharmacyConfigMissing(!hasPharmacyConfig);
|
||||
|
||||
// fallthrough to 耗材处理逻辑(保持原有逻辑)
|
||||
// 每一条医嘱的库存集合信息 , 包装单位库存前端计算
|
||||
List<AdviceInventoryDto> inventoryList = adviceInventory
|
||||
@@ -2148,4 +2154,23 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
return searchKey.matches("[a-zA-Z]+");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前科室已配置的药品类别列表
|
||||
*
|
||||
* @param organizationId 科室id
|
||||
* @return 已配置的药品类别编码列表
|
||||
*/
|
||||
@Override
|
||||
public R<?> getConfiguredCategories(Long organizationId) {
|
||||
// 查询取药科室配置
|
||||
List<AdviceInventoryDto> medLocationConfig = doctorStationAdviceAppMapper.getMedLocationConfig(organizationId);
|
||||
// 提取不重复的 categoryCode
|
||||
List<String> categoryCodes = medLocationConfig.stream()
|
||||
.map(AdviceInventoryDto::getCategoryCode)
|
||||
.filter(code -> code != null && !code.isEmpty())
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
return R.ok(categoryCodes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,9 +50,10 @@ public class DoctorStationAdviceController {
|
||||
@RequestParam(value = "organizationId", required = false) Long organizationId,
|
||||
@RequestParam(value = "adviceTypes", defaultValue = "1,2,3") List<Integer> adviceTypes,
|
||||
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
|
||||
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
|
||||
@RequestParam(value = "categoryCode", required = false) String categoryCode) {
|
||||
return R.ok(iDoctorStationAdviceAppService.getAdviceBaseInfo(adviceBaseDto, searchKey, locationId,
|
||||
adviceDefinitionIdParamList, organizationId, pageNo, pageSize, Whether.NO.getValue(), adviceTypes, null, null));
|
||||
adviceDefinitionIdParamList, organizationId, pageNo, pageSize, Whether.NO.getValue(), adviceTypes, null, categoryCode));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,4 +187,15 @@ public class DoctorStationAdviceController {
|
||||
return iDoctorStationAdviceAppService.getTestResult(encounterId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前科室已配置的药品类别列表
|
||||
*
|
||||
* @param organizationId 科室id
|
||||
* @return 已配置的药品类别编码列表
|
||||
*/
|
||||
@GetMapping(value = "/configured-categories")
|
||||
public R<?> getConfiguredCategories(@RequestParam(value = "organizationId", required = false) Long organizationId) {
|
||||
return iDoctorStationAdviceAppService.getConfiguredCategories(organizationId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -242,4 +242,9 @@ public class AdviceBaseDto {
|
||||
@Dict(dictCode = "chrgitm_lv")
|
||||
private String chrgitmLv;
|
||||
private String chrgitmLv_dictText;
|
||||
|
||||
/**
|
||||
* 是否缺少取药科室配置(仅药品类型使用)
|
||||
*/
|
||||
private Boolean pharmacyConfigMissing;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
abi.chrgitm_lv
|
||||
FROM (
|
||||
<!-- 确保至少有一个查询被执行以避免语法错误 -->
|
||||
<if test="adviceTypes != null and !adviceTypes.isEmpty() and (adviceTypes.contains(1) or adviceTypes.contains(2) or adviceTypes.contains(3))">
|
||||
<if test="adviceTypes != null and !adviceTypes.isEmpty() and (adviceTypes.contains(1) or adviceTypes.contains(2) or adviceTypes.contains(3) or adviceTypes.contains(6))">
|
||||
<!-- 如果有有效的adviceTypes,则执行对应的查询 -->
|
||||
<if test="adviceTypes.contains(1)">
|
||||
(SELECT
|
||||
@@ -95,14 +95,29 @@
|
||||
AND T2.delete_flag = '0' AND T2.status_enum = #{statusEnum}
|
||||
LEFT JOIN adm_supplier AS T3 ON T3.ID = t1.supply_id AND T3.delete_flag = '0'
|
||||
LEFT JOIN adm_charge_item_definition AS T5 ON T5.instance_id = t1.ID AND T5.delete_flag = '0' AND T5.status_enum = #{statusEnum}
|
||||
LEFT JOIN adm_organization_location AS T6 ON T6.distribution_category_code = t1.category_code AND T6.delete_flag = '0' AND T6.item_code = '1' AND T6.organization_id = #{organizationId} AND (CURRENT_TIME :: time (6) BETWEEN T6.start_time AND T6.end_time)
|
||||
INNER JOIN adm_organization_location AS T6 ON T6.distribution_category_code = t1.category_code AND T6.delete_flag = '0' AND T6.item_code = '1' AND T6.organization_id = #{organizationId} AND (CURRENT_TIME :: time (6) BETWEEN T6.start_time AND T6.end_time)
|
||||
WHERE t1.delete_flag = '0'
|
||||
AND T2.status_enum = #{statusEnum}
|
||||
<if test="pricingFlag == 1">
|
||||
AND 1 = 2
|
||||
</if>
|
||||
<if test="categoryCode != null and categoryCode != ''">
|
||||
AND t1.category_code = #{categoryCode}
|
||||
<!-- 🔧 BugFix: 支持两种匹配方式 -->
|
||||
<!-- 1. 直接匹配:distribution_category_code = category_code(都是数字代码) -->
|
||||
<!-- 2. 字典转换匹配:通过 sys_dict_data 表将 distribution_category_code(中文)转换为 category_code(数字代码) -->
|
||||
AND (
|
||||
-- 方式1:直接匹配
|
||||
t1.category_code = #{categoryCode}
|
||||
OR
|
||||
-- 方式2:通过字典转换匹配(当 distribution_category_code 存储的是中文时)
|
||||
EXISTS (
|
||||
SELECT 1 FROM sys_dict_data sdd
|
||||
WHERE sdd.dict_type = 'med_category_code'
|
||||
AND sdd.status = '0'
|
||||
AND sdd.dict_label = T6.distribution_category_code
|
||||
AND sdd.dict_value = #{categoryCode}
|
||||
)
|
||||
)
|
||||
</if>
|
||||
<if test="searchKey != null and searchKey != ''">
|
||||
AND (t1.name ILIKE '%' || #{searchKey} || '%' OR t1.py_str ILIKE '%' || #{searchKey} || '%')
|
||||
@@ -185,11 +200,15 @@
|
||||
<if test="adviceTypes.contains(3)">UNION ALL</if>
|
||||
</if>
|
||||
|
||||
<if test="adviceTypes.contains(3)">
|
||||
<if test="adviceTypes.contains(3) or adviceTypes.contains(6)">
|
||||
(SELECT
|
||||
DISTINCT ON (T1.ID)
|
||||
T1.tenant_id,
|
||||
3 AS advice_type,
|
||||
<choose>
|
||||
<when test="adviceTypes.contains(3) and adviceTypes.contains(6)">CASE T1.category_code WHEN '手术' THEN 6 WHEN '24' THEN 6 ELSE 3 END</when>
|
||||
<when test="adviceTypes.contains(6)">6</when>
|
||||
<otherwise>3</otherwise>
|
||||
</choose> AS advice_type,
|
||||
T1.bus_no AS bus_no,
|
||||
T1.category_code AS category_code,
|
||||
'' AS pharmacology_category_code,
|
||||
@@ -213,7 +232,7 @@
|
||||
WHEN '检验' THEN 1
|
||||
WHEN '检查' THEN 2
|
||||
WHEN '护理' THEN 3
|
||||
WHEN '手术' THEN 4
|
||||
WHEN '手术' THEN 4 WHEN '24' THEN 4
|
||||
WHEN '其他' THEN 5
|
||||
ELSE 0
|
||||
END AS activity_type,
|
||||
@@ -250,6 +269,14 @@
|
||||
<if test="pricingFlag != null">
|
||||
AND (t1.pricing_flag = #{pricingFlag} OR t1.pricing_flag IS NULL)
|
||||
</if>
|
||||
<!-- 如果只选择手术(adviceType=6),过滤 category_code = '手术' 或 '24' -->
|
||||
<if test="adviceTypes.contains(6) and !adviceTypes.contains(3)">
|
||||
AND (T1.category_code = '手术' OR T1.category_code = '24')
|
||||
</if>
|
||||
<!-- 如果只选择诊疗(adviceType=3),排除手术 -->
|
||||
<if test="adviceTypes.contains(3) and !adviceTypes.contains(6)">
|
||||
AND T1.category_code != '手术' AND T1.category_code != '24'
|
||||
</if>
|
||||
<if test="searchKey != null and searchKey != ''">
|
||||
AND (t1.name ILIKE '%' || #{searchKey} || '%' OR t1.py_str ILIKE '%' || #{searchKey} || '%')
|
||||
</if>
|
||||
@@ -263,7 +290,7 @@
|
||||
</if>
|
||||
</if>
|
||||
<!-- 如果没有有效的adviceTypes,提供一个空的默认查询以避免语法错误 -->
|
||||
<if test="adviceTypes == null or adviceTypes.isEmpty() or (!adviceTypes.contains(1) and !adviceTypes.contains(2) and !adviceTypes.contains(3))">
|
||||
<if test="adviceTypes == null or adviceTypes.isEmpty() or (!adviceTypes.contains(1) and !adviceTypes.contains(2) and !adviceTypes.contains(3) and !adviceTypes.contains(6))">
|
||||
SELECT
|
||||
mmd.tenant_id,
|
||||
CAST(0 AS INTEGER) AS advice_type,
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
T2.start_time AS admissionDate, --入院日期
|
||||
T3.ward_admission_date AS wardAdmissionDate, --入科日期
|
||||
T3.location_id AS ward_location_id, --病区
|
||||
T3.ward_admission_date AS wardAdmissionDate, --病区入院日期
|
||||
T4.location_id AS bed_location_id --床号
|
||||
FROM adm_patient AS T1
|
||||
INNER JOIN adm_encounter AS T2
|
||||
|
||||
@@ -23,26 +23,20 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {computed, nextTick, ref, watch} from 'vue';
|
||||
import {computed, nextTick, onMounted, ref} from 'vue';
|
||||
import {throttle} from 'lodash-es';
|
||||
import Table from '@/components/TableLayout/Table.vue';
|
||||
import {getAdviceBaseInfo} from './api';
|
||||
import type {TableColumn} from '@/components/types/TableLayout.d';
|
||||
import type {TableColumn} from '@/components/types/TableLayout';
|
||||
|
||||
interface Props {
|
||||
adviceQueryParams?: {
|
||||
searchKey?: string;
|
||||
adviceType?: string;
|
||||
};
|
||||
patientInfo: {
|
||||
inHospitalOrgId?: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
adviceQueryParams: () => ({}),
|
||||
});
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
selectAdviceBase: [row: any];
|
||||
@@ -56,14 +50,14 @@ const currentIndex = ref<number>(0);
|
||||
const currentSelectRow = ref<any>({});
|
||||
const queryParams = ref({
|
||||
pageSize: 100,
|
||||
pageNum: 1,
|
||||
adviceTypes: '1,3',
|
||||
pageNo: 1,
|
||||
adviceTypes: '1,2,3,6',
|
||||
searchKey: '',
|
||||
organizationId: '',
|
||||
categoryCode: '',
|
||||
});
|
||||
const adviceBaseList = ref<any[]>([]);
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = computed<TableColumn[]>(() => [
|
||||
{ label: '名称', prop: 'adviceName', align: 'center', width: 200 },
|
||||
{ label: '类型', prop: 'activityType_enumText', align: 'center' },
|
||||
@@ -84,50 +78,53 @@ const tableColumns = computed<TableColumn[]>(() => [
|
||||
slot: 'useScope',
|
||||
},
|
||||
]);
|
||||
// 节流函数
|
||||
const throttledGetList = throttle(
|
||||
() => {
|
||||
getList();
|
||||
},
|
||||
300,
|
||||
{ leading: true, trailing: true }
|
||||
);
|
||||
watch(
|
||||
() => props.adviceQueryParams,
|
||||
(newValue) => {
|
||||
queryParams.value.searchKey = newValue.searchKey;
|
||||
// queryParams.value.adviceType = newValue.adviceType;
|
||||
queryParams.value.adviceTypes = [newValue.adviceType].join(',');
|
||||
throttledGetList();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* 父组件主动调用此方法刷新列表
|
||||
* @param adviceType 医嘱类型(1=药品, 3=诊疗, 6=手术, ''=全部)
|
||||
* @param categoryCode 药品分类编码('1'=中成药, '2'=西药, '4'=中草药, ''=不限)
|
||||
* @param searchKey 搜索关键词
|
||||
*/
|
||||
function refresh(adviceType: any, categoryCode: string, searchKey: string) {
|
||||
queryParams.value.adviceTypes =
|
||||
adviceType !== undefined && adviceType !== '' ? String(adviceType) : '1,2,3,6';
|
||||
queryParams.value.categoryCode = categoryCode || '';
|
||||
queryParams.value.searchKey = searchKey || '';
|
||||
getList();
|
||||
}
|
||||
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
queryParams.value.organizationId = props.patientInfo?.inHospitalOrgId || '';
|
||||
// organizationId 必须为有效数字或 undefined,空字符串会导致后端 Long 类型转换失败(400)
|
||||
const orgId = props.patientInfo?.inHospitalOrgId;
|
||||
queryParams.value.organizationId = orgId ? orgId : undefined;
|
||||
// 空字符串参数不发送,避免后端类型转换错误
|
||||
if (!queryParams.value.searchKey) {
|
||||
queryParams.value.searchKey = undefined;
|
||||
}
|
||||
if (!queryParams.value.categoryCode) {
|
||||
queryParams.value.categoryCode = undefined;
|
||||
}
|
||||
|
||||
getAdviceBaseInfo(queryParams.value)
|
||||
.then((res) => {
|
||||
console.log(res.data.records);
|
||||
if (res.data.records.length > 0) {
|
||||
adviceBaseList.value = res.data.records.filter((item) => {
|
||||
const records = res.data?.records || [];
|
||||
|
||||
// 药品/耗材需要有库存才显示,诊疗/手术直接显示
|
||||
adviceBaseList.value = records.filter((item: any) => {
|
||||
if (item.adviceType == 1 || item.adviceType == 2) {
|
||||
return handleQuantity(item) != 0;
|
||||
} else {
|
||||
return true;
|
||||
return handleQuantity(item) !== '0';
|
||||
}
|
||||
return true;
|
||||
});
|
||||
total.value = res.data.total;
|
||||
|
||||
total.value = res.data?.total || 0;
|
||||
nextTick(() => {
|
||||
if (adviceBaseList.value.length > 0) {
|
||||
currentIndex.value = 0;
|
||||
setCurrentRow(adviceBaseList.value[0]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
adviceBaseList.value = [];
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
adviceBaseList.value = [];
|
||||
@@ -141,23 +138,22 @@ function getList() {
|
||||
const handleKeyDown = (event: KeyboardEvent): void => {
|
||||
const key = event.key;
|
||||
const data = adviceBaseList.value;
|
||||
|
||||
switch (key) {
|
||||
case 'ArrowUp': // 上箭头
|
||||
case 'ArrowUp':
|
||||
event.preventDefault();
|
||||
if (currentIndex.value > 0) {
|
||||
currentIndex.value--;
|
||||
setCurrentRow(data[currentIndex.value]);
|
||||
}
|
||||
break;
|
||||
case 'ArrowDown': // 下箭头
|
||||
case 'ArrowDown':
|
||||
event.preventDefault();
|
||||
if (currentIndex.value < data.length - 1) {
|
||||
currentIndex.value++;
|
||||
setCurrentRow(data[currentIndex.value]);
|
||||
}
|
||||
break;
|
||||
case 'Enter': // 回车键
|
||||
case 'Enter':
|
||||
event.preventDefault();
|
||||
if (currentSelectRow.value && Object.keys(currentSelectRow.value).length > 0) {
|
||||
emit('selectAdviceBase', currentSelectRow.value);
|
||||
@@ -177,17 +173,14 @@ function handleQuantity(row: any): string {
|
||||
return '0';
|
||||
}
|
||||
|
||||
// 设置选中行(带滚动)
|
||||
const setCurrentRow = (row: any) => {
|
||||
if (adviceBaseRef.value?.tableRef) {
|
||||
adviceBaseRef.value.tableRef.setCurrentRow(row);
|
||||
// 滚动到选中行
|
||||
nextTick(() => {
|
||||
const tableEl = adviceBaseRef.value?.tableRef?.$el;
|
||||
if (tableEl) {
|
||||
const tableBody = tableEl.querySelector('.el-table__body-wrapper');
|
||||
const currentRowEl = tableEl.querySelector('.current-row');
|
||||
if (tableBody && currentRowEl) {
|
||||
if (currentRowEl) {
|
||||
currentRowEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
}
|
||||
@@ -195,31 +188,20 @@ const setCurrentRow = (row: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 行点击事件
|
||||
const handleRowClick = (row: any): void => {
|
||||
currentIndex.value = adviceBaseList.value.findIndex((item) => item === row);
|
||||
currentSelectRow.value = row;
|
||||
emit('selectAdviceBase', row);
|
||||
};
|
||||
|
||||
// 监听表格当前行变化(通过 el-table 的 current-change 事件)
|
||||
watch(
|
||||
() => adviceBaseRef.value?.tableRef,
|
||||
(tableRef) => {
|
||||
if (tableRef) {
|
||||
// 通过 $el 访问原生 el-table 并监听 current-change
|
||||
const elTable = tableRef.$el?.querySelector('.el-table');
|
||||
if (elTable) {
|
||||
// 使用 MutationObserver 或直接监听 DOM 变化来检测当前行变化
|
||||
// 或者通过 watch 监听 currentSelectRow 的变化
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
handleKeyDown,
|
||||
refresh,
|
||||
});
|
||||
|
||||
// 组件挂载时自动加载数据(el-popover 懒渲染,父组件 refresh 可能因时序问题未生效,onMounted 最可靠)
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -234,8 +216,4 @@ defineExpose({
|
||||
outline: 2px solid #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-table-wrapper:focus {
|
||||
outline: 2px solid #409eff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -170,6 +170,22 @@ export function getAdviceBaseInfo(queryParams) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前科室已配置的药品类别列表
|
||||
*/
|
||||
export function getConfiguredCategories(organizationId) {
|
||||
// organizationId 为空时不发送该参数,避免后端 Long 类型转换 400 错误
|
||||
const params = {};
|
||||
if (organizationId !== undefined && organizationId !== null && organizationId !== '') {
|
||||
params.organizationId = organizationId;
|
||||
}
|
||||
return request({
|
||||
url: '/doctor-station/advice/configured-categories',
|
||||
method: 'get',
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存处方(单条)
|
||||
*/
|
||||
|
||||
@@ -145,28 +145,40 @@
|
||||
<template v-if="getRowDisabled(scope.row)">
|
||||
<el-select
|
||||
style="width: 35%; margin-right: 8px"
|
||||
v-model="scope.row.adviceType"
|
||||
:model-value="getRowSelectValue(scope.row)"
|
||||
:ref="'adviceTypeRef' + scope.$index"
|
||||
:disabled="!isCategoryLoaded"
|
||||
@change="
|
||||
(value) => {
|
||||
expandOrder = [];
|
||||
filterPrescriptionList[scope.$index].adviceName = undefined;
|
||||
adviceQueryParams.adviceType = value;
|
||||
// 根据选中的医嘱类型,设置对应的 categoryCode
|
||||
const selectedItem = adviceTypeList.find(item => item.value === value);
|
||||
const newCategoryCode = selectedItem ? selectedItem.categoryCode : '';
|
||||
const newAdviceType = selectedItem ? selectedItem.adviceType : value;
|
||||
// 更新行的 adviceType(数字)和 categoryCode
|
||||
filterPrescriptionList[scope.$index].adviceType = newAdviceType;
|
||||
filterPrescriptionList[scope.$index].categoryCode = newCategoryCode;
|
||||
// 更新 adviceQueryParams(备用)
|
||||
adviceQueryParams.value = {
|
||||
adviceType: newAdviceType,
|
||||
categoryCode: newCategoryCode,
|
||||
searchKey: adviceQueryParams.value.searchKey || '',
|
||||
};
|
||||
// 直接调用子组件 refresh 方法,立即刷新列表(用 scope.$index 找到当前行的子组件)
|
||||
const tableRef = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[scope.$index] : adviceTableRef.value;
|
||||
if (tableRef && tableRef.refresh) {
|
||||
tableRef.refresh(newAdviceType, newCategoryCode, '');
|
||||
}
|
||||
}
|
||||
"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in adviceTypeList"
|
||||
:key="item.value"
|
||||
:key="item.label + '-' + item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
@click="
|
||||
() => {
|
||||
filterPrescriptionList[scope.$index].adviceType = item.value;
|
||||
filterPrescriptionList[scope.$index].adviceType_dictText = item.label;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</el-select>
|
||||
<el-popover
|
||||
@@ -177,8 +189,6 @@
|
||||
>
|
||||
<adviceBaseList
|
||||
ref="adviceTableRef"
|
||||
:popoverVisible="scope.row.showPopover"
|
||||
:adviceQueryParams="adviceQueryParams"
|
||||
:patientInfo="patientInfo"
|
||||
@selectAdviceBase="(row) => selectAdviceBase(scope.row.uniqueKey, row)"
|
||||
/>
|
||||
@@ -198,7 +208,8 @@
|
||||
if (['ArrowUp', 'ArrowDown', 'Enter'].includes(e.key)) {
|
||||
e.preventDefault();
|
||||
// 传递事件到弹窗容器
|
||||
adviceTableRef.handleKeyDown(e);
|
||||
const tableRef = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[scope.$index] : adviceTableRef.value;
|
||||
if (tableRef && tableRef.handleKeyDown) tableRef.handleKeyDown(e);
|
||||
}
|
||||
}
|
||||
"
|
||||
@@ -346,6 +357,7 @@ import {
|
||||
singOut,
|
||||
stopAdvice,
|
||||
updateGroupId,
|
||||
getConfiguredCategories,
|
||||
} from '../api';
|
||||
import adviceBaseList from '../adviceBaseList';
|
||||
import {calculateQuantityByDays} from '@/utils/his';
|
||||
@@ -360,7 +372,7 @@ import LeaveHospitalDialog from './applicationForm/leaveHospitalDialog.vue';
|
||||
import TransferOrganizationDialog from './applicationForm/transferOrganizationDialog.vue';
|
||||
import NursingStatus from '@/views/inpatientDoctor/home/components/applicationShow/nursingStatus.vue';
|
||||
import OrderForm from './OrderForm.vue';
|
||||
import {computed, watch} from 'vue';
|
||||
// Vue API (ref, computed, watch, nextTick, onMounted, etc.) are auto-imported by unplugin-auto-import
|
||||
|
||||
const emit = defineEmits(['selectDiagnosis']);
|
||||
const total = ref(0);
|
||||
@@ -369,7 +381,11 @@ const prescriptionList = ref([]);
|
||||
const form = ref({
|
||||
prescriptionList: prescriptionList.value,
|
||||
});
|
||||
const adviceQueryParams = ref({});
|
||||
const adviceQueryParams = ref({
|
||||
adviceType: 1,
|
||||
categoryCode: '', // 初始为空,等待加载配置后动态设置
|
||||
searchKey: '',
|
||||
});
|
||||
const rowIndex = ref(-1);
|
||||
const groupIndex = ref(1);
|
||||
const groupIndexList = ref([]);
|
||||
@@ -436,24 +452,65 @@ const { method_code, unit_code, rate_code, distribution_category_code, drord_doc
|
||||
const openDrawer = ref(false);
|
||||
const orderClassCode = ref('');
|
||||
const orderStatus = ref('');
|
||||
// 医嘱类型 - 使用 drord_doctor_type 字典
|
||||
// 已配置的药品类别列表
|
||||
const configuredCategoryCodes = ref([]);
|
||||
// 当前选择的药品 categoryCode(用于后端过滤)
|
||||
const currentCategoryCode = ref('');
|
||||
// 标记是否已显示过配置警告(整个生命周期只提示一次)
|
||||
const hasShownPharmacyConfigWarning = ref(false);
|
||||
// 标记配置是否已加载完成
|
||||
const isCategoryLoaded = ref(false);
|
||||
|
||||
// 医嘱类型 - 根据取药科室配置动态过滤
|
||||
const adviceTypeList = computed(() => {
|
||||
// 如果字典已加载,使用字典数据(过滤掉全部选项)
|
||||
if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
|
||||
const list = drord_doctor_type.value.map(item => ({
|
||||
label: item.label,
|
||||
value: parseInt(item.value) || item.value
|
||||
}));
|
||||
// 添加全部选项
|
||||
return [...list, { label: '全部', value: '' }];
|
||||
// 如果配置还未加载完成,返回空列表(等待配置加载)
|
||||
if (!isCategoryLoaded.value) {
|
||||
return [];
|
||||
}
|
||||
// 默认返回值
|
||||
|
||||
// 如果没有配置类别,只显示诊疗和手术,隐藏所有药品分类
|
||||
if (configuredCategoryCodes.value.length === 0) {
|
||||
// 只显示警告(整个生命周期只提示一次)
|
||||
if (!hasShownPharmacyConfigWarning.value) {
|
||||
ElMessage.warning('当前科室并未在取药配置室配置');
|
||||
hasShownPharmacyConfigWarning.value = true;
|
||||
}
|
||||
|
||||
// 只返回不需要取药科室配置的类别(诊疗、手术)
|
||||
return [
|
||||
{ label: '西药中成药', value: 1 },
|
||||
{ label: '诊疗', value: 3 },
|
||||
{ label: '手术', value: 6 },
|
||||
{ label: '全部', value: '' },
|
||||
{ label: '诊疗', value: 3, adviceType: 3, categoryCode: '' },
|
||||
{ label: '手术', value: 6, adviceType: 6, categoryCode: '' },
|
||||
{ label: '全部', value: '', adviceType: '', categoryCode: '' },
|
||||
];
|
||||
}
|
||||
|
||||
// 根据已配置的 categoryCode 动态构建医嘱类型列表
|
||||
// 重要:药品子分类使用复合值 'adviceType-categoryCode'(如 '1-2'),确保 el-select 能区分同 adviceType 的不同分类
|
||||
const typeList = [];
|
||||
|
||||
// 如果配置了西药(categoryCode='2'),添加西药选项
|
||||
if (configuredCategoryCodes.value.includes('2')) {
|
||||
typeList.push({ label: '西药', value: '1-2', adviceType: 1, categoryCode: '2' });
|
||||
}
|
||||
|
||||
// 如果配置了中成药(categoryCode='1'),添加中成药选项
|
||||
if (configuredCategoryCodes.value.includes('1')) {
|
||||
typeList.push({ label: '中成药', value: '1-1', adviceType: 1, categoryCode: '1' });
|
||||
}
|
||||
|
||||
// 如果配置了中草药(categoryCode='4'),添加中草药选项
|
||||
if (configuredCategoryCodes.value.includes('4')) {
|
||||
typeList.push({ label: '中草药', value: '1-4', adviceType: 1, categoryCode: '4' });
|
||||
}
|
||||
|
||||
// 始终添加诊疗和手术(它们不受取药配置限制)
|
||||
typeList.push({ label: '诊疗', value: 3, adviceType: 3, categoryCode: '' });
|
||||
typeList.push({ label: '手术', value: 6, adviceType: 6, categoryCode: '' });
|
||||
|
||||
// 添加全部选项
|
||||
typeList.push({ label: '全部', value: '', adviceType: '', categoryCode: '' });
|
||||
|
||||
return typeList;
|
||||
});
|
||||
// 医嘱状态
|
||||
const statusOption = [
|
||||
@@ -564,6 +621,75 @@ function getListInfo(addNewRow) {
|
||||
contractList.value = res.data;
|
||||
});
|
||||
accountId.value = patientInfo.value.accountId;
|
||||
|
||||
// 加载已配置的药品类别
|
||||
loadConfiguredCategories();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载已配置的药品类别
|
||||
*/
|
||||
function loadConfiguredCategories() {
|
||||
const orgId = patientInfo.value?.inHospitalOrgId;
|
||||
if (!orgId) {
|
||||
isCategoryLoaded.value = true; // 标记已加载(即使没有科室ID)
|
||||
return;
|
||||
}
|
||||
|
||||
getConfiguredCategories(orgId).then((res) => {
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
configuredCategoryCodes.value = res.data;
|
||||
// 如果没有配置任何类别,只显示警告并隐藏药品分类
|
||||
if (configuredCategoryCodes.value.length === 0) {
|
||||
if (!hasShownPharmacyConfigWarning.value) {
|
||||
ElMessage.warning('当前科室并未在取药配置室配置');
|
||||
hasShownPharmacyConfigWarning.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 根据配置动态设置默认的 categoryCode
|
||||
// 优先级:西药(2) > 中成药(1) > 中草药(4) > 第一个配置的类别
|
||||
const priorityOrder = ['2', '1', '4'];
|
||||
let defaultCategoryCode = '';
|
||||
|
||||
for (const code of priorityOrder) {
|
||||
if (configuredCategoryCodes.value.includes(code)) {
|
||||
defaultCategoryCode = code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有匹配到优先级类别,使用第一个配置的类别
|
||||
if (!defaultCategoryCode && configuredCategoryCodes.value.length > 0) {
|
||||
defaultCategoryCode = configuredCategoryCodes.value[0];
|
||||
}
|
||||
|
||||
// 设置默认的 categoryCode
|
||||
if (defaultCategoryCode) {
|
||||
// 使用 nextTick 确保配置更新后触发 watch
|
||||
nextTick(() => {
|
||||
// 创建新对象触发响应式更新
|
||||
adviceQueryParams.value = {
|
||||
adviceType: 1,
|
||||
categoryCode: defaultCategoryCode,
|
||||
searchKey: '',
|
||||
};
|
||||
});
|
||||
} else if (configuredCategoryCodes.value.length === 0) {
|
||||
// 如果没有配置任何类别,清空 categoryCode
|
||||
nextTick(() => {
|
||||
adviceQueryParams.value = {
|
||||
adviceType: '',
|
||||
categoryCode: '',
|
||||
searchKey: '',
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
isCategoryLoaded.value = true; // 标记已加载完成
|
||||
}).catch((err) => {
|
||||
isCategoryLoaded.value = true; // 即使失败也标记已加载
|
||||
});
|
||||
}
|
||||
// 数据过滤
|
||||
const filterPrescriptionList = computed(() => {
|
||||
@@ -595,8 +721,24 @@ function getRowDisabled(row) {
|
||||
return row.isEdit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将行的 adviceType + categoryCode 映射为 el-select 的选中值
|
||||
* 药品子分类使用复合值如 '1-2'(adviceType-categoryCode),诊疗/手术/全部使用原始值
|
||||
*/
|
||||
function getRowSelectValue(row) {
|
||||
if (row.adviceType == 1 && row.categoryCode) {
|
||||
return '1-' + row.categoryCode;
|
||||
}
|
||||
return row.adviceType;
|
||||
}
|
||||
|
||||
// 新增医嘱
|
||||
function handleAddPrescription() {
|
||||
// 校验是否选中患者
|
||||
if (!patientInfo.value || !patientInfo.value.encounterId) {
|
||||
proxy.$modal.msgWarning('请先选择患者');
|
||||
return;
|
||||
}
|
||||
if (isAdding.value) {
|
||||
proxy.$modal.msgWarning('请先保存当前医嘱');
|
||||
return;
|
||||
@@ -697,6 +839,32 @@ function handleDiagnosisChange(item) {
|
||||
function handleFocus(row, index) {
|
||||
rowIndex.value = index;
|
||||
row.showPopover = true;
|
||||
// el-popover 懒渲染,需要等两帧组件才会挂载
|
||||
const adviceType = row.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType;
|
||||
// 用 adviceType + categoryCode 组合查找匹配的选项
|
||||
const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||
// 诊疗(3)和手术(6)没有categoryCode,传空字符串给refresh,由子组件转为undefined不发送
|
||||
// 药品(1)才有categoryCode(如'1'=中成药,'2'=西药,'4'=中草药)
|
||||
const categoryCode = selectedItem ? selectedItem.categoryCode : (adviceQueryParams.value.categoryCode || '');
|
||||
const searchKey = row.adviceName || '';
|
||||
|
||||
nextTick(() => {
|
||||
nextTick(() => {
|
||||
const tableRef = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[index] : adviceTableRef.value;
|
||||
if (tableRef && tableRef.refresh) {
|
||||
tableRef.refresh(adviceType, categoryCode, searchKey);
|
||||
} else {
|
||||
// fallback: 如果双重 nextTick 仍未挂载,延迟 100ms 再试
|
||||
setTimeout(() => {
|
||||
const tableRef2 = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[index] : adviceTableRef.value;
|
||||
if (tableRef2 && tableRef2.refresh) {
|
||||
tableRef2.refresh(adviceType, categoryCode, searchKey);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleBlur(row) {
|
||||
@@ -705,6 +873,21 @@ function handleBlur(row) {
|
||||
|
||||
function handleChange(value) {
|
||||
adviceQueryParams.value.searchKey = value;
|
||||
// 搜索词变化时,调用当前行子组件的 refresh 方法
|
||||
const index = rowIndex.value;
|
||||
if (index >= 0) {
|
||||
const tableRef = Array.isArray(adviceTableRef.value) ? adviceTableRef.value[index] : adviceTableRef.value;
|
||||
if (tableRef && tableRef.refresh) {
|
||||
const row = filterPrescriptionList.value[index];
|
||||
const adviceType = row?.adviceType !== undefined ? row.adviceType : adviceQueryParams.value.adviceType;
|
||||
// 用 adviceType + categoryCode 组合查找匹配的选项
|
||||
const selectValue = (adviceType == 1 && row?.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||
// 诊疗/手术的categoryCode为空字符串,由子组件转为undefined不发送
|
||||
const categoryCode = selectedItem ? selectedItem.categoryCode : (adviceQueryParams.value.categoryCode || '');
|
||||
tableRef.refresh(adviceType, categoryCode, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
28
openhis-ui-vue3/tsconfig.json
Normal file
28
openhis-ui-vue3/tsconfig.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
"noEmit": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"types": ["vite/client"]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue"
|
||||
],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user