bug550\556569
This commit is contained in:
@@ -250,10 +250,11 @@ export function getContract(params) {
|
||||
/**
|
||||
* 获取科室列表
|
||||
*/
|
||||
export function getOrgTree() {
|
||||
export function getOrgTree(params = {}) {
|
||||
return request({
|
||||
url: '/base-data-manage/organization/organization',
|
||||
method: 'get',
|
||||
params: { pageNo: 1, pageSize: 5000, ...params },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -24,22 +24,20 @@
|
||||
</el-col> -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发往科室" prop="targetDepartment" style="width: 100%">
|
||||
<!-- <el-input v-model="form.targetDepartment" autocomplete="off" /> -->
|
||||
<el-tree-select
|
||||
clearable
|
||||
style="width: 100%"
|
||||
<el-select
|
||||
v-model="form.targetDepartment"
|
||||
filterable
|
||||
:data="orgOptions"
|
||||
:props="{
|
||||
value: 'id',
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
}"
|
||||
value-key="id"
|
||||
check-strictly
|
||||
clearable
|
||||
placeholder="请选择科室"
|
||||
/>
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in flatOrgOptions"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -78,18 +76,33 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup name="BloodTransfusion">
|
||||
import {getCurrentInstance, onBeforeMount, onMounted, reactive, ref} from 'vue';
|
||||
import {computed, getCurrentInstance, nextTick, onBeforeMount, onMounted, reactive, ref, watch} from 'vue';
|
||||
import {ElMessage} from 'element-plus';
|
||||
import {patientInfo} from '../../../store/patient.js';
|
||||
import {getDepartmentList} from '@/api/public.js';
|
||||
import request from '@/utils/request';
|
||||
import {getDiagnosisTreatmentOne} from '@/views/catalog/diagnosistreatment/components/diagnosistreatment';
|
||||
import {getEncounterDiagnosis} from '../../api.js';
|
||||
import {getApplicationList, saveBloodTransfusio} from './api';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
/** 科室树节点 id 统一为字符串,避免大整数精度丢失导致 tree-select 无法匹配 */
|
||||
const normalizeOrgTreeIds = (nodes) => {
|
||||
if (!Array.isArray(nodes)) return [];
|
||||
return nodes.map((node) => ({
|
||||
...node,
|
||||
id: node.id != null ? String(node.id) : node.id,
|
||||
children: node.children?.length ? normalizeOrgTreeIds(node.children) : undefined,
|
||||
}));
|
||||
};
|
||||
|
||||
// 递归查找树形科室节点
|
||||
const findTreeItem = (list, id) => {
|
||||
if (!list || list.length === 0) return null;
|
||||
if (!list || list.length === 0 || id == null || id === '') return null;
|
||||
const strId = String(id);
|
||||
for (const item of list) {
|
||||
if (item.id == id) return item;
|
||||
if (String(item.id) === strId) return item;
|
||||
if (item.children && item.children.length > 0) {
|
||||
const found = findTreeItem(item.children, id);
|
||||
if (found) return found;
|
||||
@@ -97,11 +110,149 @@ const findTreeItem = (list, id) => {
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/** 在科室树中解析 orgId(兼容 Long 转 Number 后的精度丢失) */
|
||||
const resolveOrgIdInTree = (rawOrgId) => {
|
||||
if (rawOrgId == null || rawOrgId === '') return '';
|
||||
const strOrgId = String(rawOrgId);
|
||||
const findInTree = (nodes) => {
|
||||
if (!nodes?.length) return null;
|
||||
for (const node of nodes) {
|
||||
if (String(node.id) === strOrgId) return String(node.id);
|
||||
if (
|
||||
typeof node.id === 'string' &&
|
||||
node.id.length >= 16 &&
|
||||
strOrgId.length >= 16 &&
|
||||
node.id.substring(0, 15) === strOrgId.substring(0, 15)
|
||||
) {
|
||||
return String(node.id);
|
||||
}
|
||||
if (node.children?.length) {
|
||||
const found = findInTree(node.children);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
return findInTree(orgOptions.value) || strOrgId;
|
||||
};
|
||||
|
||||
const resolveTargetDepartmentId = (rawId) => {
|
||||
if (rawId == null || rawId === '') return '';
|
||||
const resolved = resolveOrgIdInTree(rawId);
|
||||
const node = findTreeItem(orgOptions.value, resolved);
|
||||
return node ? String(node.id) : resolved;
|
||||
};
|
||||
|
||||
/** 诊疗目录「所属科室」→ AdviceBaseDto.orgId */
|
||||
const getBelongingOrgId = (item) => {
|
||||
if (!item) return null;
|
||||
return item.orgId ?? item.org_id ?? null;
|
||||
};
|
||||
|
||||
/** 诊疗目录所属科室名称(字典翻译字段) */
|
||||
const getBelongingOrgName = (item) => {
|
||||
if (!item) return '';
|
||||
return item.orgId_dictText || item.orgName || item.org_name || '';
|
||||
};
|
||||
|
||||
/** 按机构 ID 拉取科室名称(树中无节点时兜底) */
|
||||
const fetchOrgNameById = async (orgId) => {
|
||||
if (orgId == null || orgId === '') return '';
|
||||
const fromTree = findOrgName(orgId);
|
||||
if (fromTree) return fromTree;
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/base-data-manage/organization/organization-getById',
|
||||
method: 'get',
|
||||
params: { orgId },
|
||||
});
|
||||
if (res.code === 200 && res.data?.name) {
|
||||
return res.data.name;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('查询科室名称失败', e);
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
/** 从机构树解析科室名称 */
|
||||
const findOrgName = (orgId) => {
|
||||
if (orgId == null || orgId === '') return '';
|
||||
const node = findTreeItem(orgOptions.value, orgId);
|
||||
if (node?.name) return node.name;
|
||||
const resolved = resolveOrgIdInTree(orgId);
|
||||
const resolvedNode = findTreeItem(orgOptions.value, resolved);
|
||||
return resolvedNode?.name || '';
|
||||
};
|
||||
|
||||
/** 自动填充时缓存的科室名称 */
|
||||
const targetDepartmentName = ref('');
|
||||
|
||||
/** 扁平化科室选项,保证 el-select 能稳定显示 label */
|
||||
const flatOrgOptions = computed(() => {
|
||||
const options = [];
|
||||
const seen = new Set();
|
||||
const walk = (nodes) => {
|
||||
for (const node of nodes || []) {
|
||||
if (node?.id == null) continue;
|
||||
const value = String(node.id);
|
||||
if (seen.has(value)) continue;
|
||||
seen.add(value);
|
||||
options.push({ value, label: node.name || value });
|
||||
if (node.children?.length) walk(node.children);
|
||||
}
|
||||
};
|
||||
walk(orgOptions.value);
|
||||
const curId = form.targetDepartment;
|
||||
const curName = targetDepartmentName.value || findOrgName(curId);
|
||||
if (curId && curName && !seen.has(String(curId))) {
|
||||
options.unshift({ value: String(curId), label: curName });
|
||||
}
|
||||
return options;
|
||||
});
|
||||
|
||||
/** 从诊疗目录详情补全所属科室(医嘱下拉接口不带 orgId_dictText) */
|
||||
const resolveProjectOrgInfo = async (item) => {
|
||||
if (!item) return { orgId: null, orgName: '' };
|
||||
let orgId = getBelongingOrgId(item);
|
||||
let orgName = getBelongingOrgName(item);
|
||||
if ((!orgId || !orgName) && item.adviceDefinitionId) {
|
||||
try {
|
||||
const res = await getDiagnosisTreatmentOne(item.adviceDefinitionId);
|
||||
const detail = res?.data;
|
||||
if (detail) {
|
||||
orgId = orgId ?? detail.orgId ?? detail.org_id ?? null;
|
||||
orgName = orgName || detail.orgId_dictText || detail.orgName || '';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('查询诊疗目录所属科室失败', e);
|
||||
}
|
||||
}
|
||||
if (orgId && !orgName) {
|
||||
orgName = await fetchOrgNameById(orgId);
|
||||
}
|
||||
return { orgId, orgName };
|
||||
};
|
||||
|
||||
/** 写入发往科室 */
|
||||
const applyTargetDepartment = async (belongOrgId, nameHint = '') => {
|
||||
if (belongOrgId == null || belongOrgId === '') {
|
||||
form.targetDepartment = '';
|
||||
targetDepartmentName.value = '';
|
||||
return;
|
||||
}
|
||||
const resolvedDeptId = resolveTargetDepartmentId(belongOrgId);
|
||||
const deptName =
|
||||
nameHint || findOrgName(belongOrgId) || findOrgName(resolvedDeptId) || (await fetchOrgNameById(belongOrgId));
|
||||
targetDepartmentName.value = deptName;
|
||||
form.targetDepartment = resolvedDeptId;
|
||||
};
|
||||
const emits = defineEmits(['submitOk']);
|
||||
const props = defineProps({});
|
||||
const state = reactive({});
|
||||
const applicationListAll = ref();
|
||||
const applicationList = ref();
|
||||
const applicationListAll = ref([]);
|
||||
const applicationList = ref([]);
|
||||
const loading = ref(false);
|
||||
const orgOptions = ref([]); // 科室选项
|
||||
const getList = () => {
|
||||
@@ -118,29 +269,48 @@ const getList = () => {
|
||||
adviceTypes: [3], //1 药品 2耗材 3诊疗
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
applicationListAll.value = res.data.records;
|
||||
applicationList.value = res.data.records.map((item) => {
|
||||
if (res.code === 200 && Array.isArray(res.data?.records)) {
|
||||
const records = res.data.records.filter((item) => item.adviceDefinitionId != null);
|
||||
applicationListAll.value = records;
|
||||
applicationList.value = records.map((item) => {
|
||||
const priceInfo = item.priceList?.[0] || {};
|
||||
const price = priceInfo.price != null ? Number(priceInfo.price).toFixed(2) : '0.00';
|
||||
const unit = item.unitCode_dictText || item.unitCode || '';
|
||||
const id = item.adviceDefinitionId;
|
||||
return {
|
||||
adviceDefinitionId: item.adviceDefinitionId,
|
||||
adviceDefinitionId: id,
|
||||
orgId: item.orgId,
|
||||
label: item.adviceName + ' (¥' + price + '/' + unit + ')',
|
||||
key: item.adviceDefinitionId,
|
||||
key: id,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
proxy.$message.error(res.message);
|
||||
proxy.$message.error(res.message || '加载输血项目失败');
|
||||
applicationListAll.value = [];
|
||||
applicationList.value = [];
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
if (transferValue.value.length > 0) {
|
||||
nextTick(async () => {
|
||||
const valid = await validateTransferOrgConsistency(transferValue.value);
|
||||
if (valid) {
|
||||
lastValidTransferValue.value = [...transferValue.value];
|
||||
fillTargetDepartmentFromSelection(transferValue.value, 1);
|
||||
} else {
|
||||
transferValue.value = [];
|
||||
lastValidTransferValue.value = [];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
const transferValue = ref([]);
|
||||
/** 上一次通过校验的已选项目(科室不一致时回滚到此状态) */
|
||||
const lastValidTransferValue = ref([]);
|
||||
const isRevertingTransfer = ref(false);
|
||||
let transferValidateSeq = 0;
|
||||
const form = reactive({
|
||||
// categoryType: '', // 项目类别
|
||||
targetDepartment: '', // 发往科室
|
||||
@@ -157,86 +327,140 @@ const rules = reactive({});
|
||||
onBeforeMount(() => {});
|
||||
onMounted(() => {
|
||||
getList();
|
||||
getLocationInfo();
|
||||
});
|
||||
const collectSelectedProjects = (selectProjectIds) => {
|
||||
return (selectProjectIds || [])
|
||||
.map((element) =>
|
||||
applicationListAll.value.find((item) => String(item.adviceDefinitionId) === String(element))
|
||||
)
|
||||
.filter(Boolean);
|
||||
};
|
||||
|
||||
/** 校验已选项目的所属科室是否一致(超过 1 项时才校验) */
|
||||
const validateTransferOrgConsistency = async (selectProjectIds) => {
|
||||
const arr = collectSelectedProjects(selectProjectIds);
|
||||
if (arr.length <= 1) {
|
||||
return true;
|
||||
}
|
||||
const orgInfoList = await Promise.all(arr.map((item) => resolveProjectOrgInfo(item)));
|
||||
const firstOrgId = orgInfoList[0]?.orgId;
|
||||
return orgInfoList.every((info) => String(info?.orgId ?? '') === String(firstOrgId ?? ''));
|
||||
};
|
||||
|
||||
/**
|
||||
* type(1:watch监听类型 2:点击保存类型)
|
||||
* selectProjectIds(选中项目的id数组)
|
||||
* */
|
||||
const projectWithDepartment = (selectProjectIds, type) => {
|
||||
//1.获取选中的项目 2.判断项目的执行科室是否相同 3.判断执行科室是否配置 4.将项目的执行科室复值到执行科室下拉选位置
|
||||
let isRelease = true;
|
||||
// 选中项目的数组
|
||||
const arr = [];
|
||||
// 根据选中的项目id查找对应的项目
|
||||
selectProjectIds.forEach((element) => {
|
||||
const searchData = applicationList.value.find((item) => {
|
||||
return element == item.adviceDefinitionId;
|
||||
});
|
||||
arr.push(searchData);
|
||||
});
|
||||
// 清空科室
|
||||
form.targetDepartment = '';
|
||||
if (arr.length > 0) {
|
||||
const obj = arr[0];
|
||||
// 判断科室是否相同
|
||||
const isCompare = arr.every((item) => {
|
||||
return item.orgId == obj.orgId;
|
||||
});
|
||||
if (!isCompare) {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: '执行科室不同',
|
||||
});
|
||||
isRelease = false;
|
||||
}
|
||||
// 选中项目中的执行科室id与全部科室数据做匹配
|
||||
const findItem = findTreeItem(orgOptions.value, obj.orgId);
|
||||
*/
|
||||
const fillTargetDepartmentFromSelection = async (selectProjectIds, type) => {
|
||||
const manualDept = type === 2 && form.targetDepartment ? form.targetDepartment : '';
|
||||
const arr = collectSelectedProjects(selectProjectIds);
|
||||
|
||||
if (!findItem) {
|
||||
isRelease = false;
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: '未找到项目执行的科室',
|
||||
});
|
||||
}
|
||||
if (type == 1) {
|
||||
if (isRelease) {
|
||||
form.targetDepartment = findItem.id;
|
||||
}
|
||||
if (arr.length === 0) {
|
||||
// 项目列表尚未加载完时,已选 ID 存在则先不清空(避免误清发往科室)
|
||||
if ((selectProjectIds || []).length > 0 && applicationListAll.value.length === 0) {
|
||||
return type === 2 ? !!manualDept : true;
|
||||
}
|
||||
form.targetDepartment = '';
|
||||
targetDepartmentName.value = '';
|
||||
return type === 2 ? !!manualDept : true;
|
||||
}
|
||||
return isRelease;
|
||||
|
||||
const orgInfoList = await Promise.all(arr.map((item) => resolveProjectOrgInfo(item)));
|
||||
const firstOrg = orgInfoList[0];
|
||||
const belongOrgId = firstOrg?.orgId;
|
||||
const allSameOrg = orgInfoList.every((info) => String(info?.orgId ?? '') === String(belongOrgId ?? ''));
|
||||
if (!allSameOrg) {
|
||||
if (type === 2) {
|
||||
ElMessage.error('所选项目的所属科室不一致,请分开申请');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (belongOrgId == null || belongOrgId === '') {
|
||||
if (type === 2 && manualDept) {
|
||||
await applyTargetDepartment(manualDept, findOrgName(manualDept));
|
||||
return true;
|
||||
}
|
||||
if (type === 2) {
|
||||
ElMessage.warning('所选项目未在诊疗目录配置所属科室,请手动选择发往科室');
|
||||
return false;
|
||||
}
|
||||
form.targetDepartment = '';
|
||||
targetDepartmentName.value = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type === 2 && manualDept) {
|
||||
await applyTargetDepartment(manualDept, findOrgName(manualDept));
|
||||
return true;
|
||||
}
|
||||
|
||||
await applyTargetDepartment(belongOrgId, firstOrg?.orgName || '');
|
||||
return true;
|
||||
};
|
||||
// 监听选择项目变化
|
||||
|
||||
// 选中项目:先校验所属科室一致,不通过则回滚穿梭框,不允许进入「已选择」
|
||||
watch(
|
||||
() => transferValue.value,
|
||||
(newValue) => {
|
||||
projectWithDepartment(newValue, 1);
|
||||
async (newValue) => {
|
||||
if (isRevertingTransfer.value) return;
|
||||
|
||||
const seq = ++transferValidateSeq;
|
||||
const valid = await validateTransferOrgConsistency(newValue);
|
||||
if (seq !== transferValidateSeq) return;
|
||||
|
||||
if (!valid) {
|
||||
ElMessage.error('所选项目的所属科室不一致,请分开申请');
|
||||
isRevertingTransfer.value = true;
|
||||
transferValue.value = [...lastValidTransferValue.value];
|
||||
await nextTick();
|
||||
isRevertingTransfer.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
lastValidTransferValue.value = [...newValue];
|
||||
await fillTargetDepartmentFromSelection(newValue, 1);
|
||||
}
|
||||
);
|
||||
const submit = () => {
|
||||
|
||||
watch(
|
||||
() => orgOptions.value,
|
||||
() => {
|
||||
if (transferValue.value.length > 0) {
|
||||
nextTick(() => {
|
||||
fillTargetDepartmentFromSelection(transferValue.value, 1);
|
||||
});
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
const submit = async () => {
|
||||
if (transferValue.value.length == 0) {
|
||||
return proxy.$message.error('请选择申请单');
|
||||
}
|
||||
if (!projectWithDepartment(transferValue.value, 2)) {
|
||||
if (!(await fillTargetDepartmentFromSelection(transferValue.value, 2))) {
|
||||
return;
|
||||
}
|
||||
if (!form.targetDepartment) {
|
||||
return proxy.$message.error('请选择发往科室');
|
||||
}
|
||||
let applicationListAllFilter = applicationListAll.value.filter((item) => {
|
||||
return transferValue.value.includes(item.adviceDefinitionId);
|
||||
return transferValue.value.some((id) => String(id) === String(item.adviceDefinitionId));
|
||||
});
|
||||
applicationListAllFilter = applicationListAllFilter.map((item) => {
|
||||
const priceInfo = item.priceList?.[0] || {};
|
||||
return {
|
||||
adviceDefinitionId: item.adviceDefinitionId /** 诊疗定义id */,
|
||||
quantity: 1, // /** 请求数量 */
|
||||
unitCode: item.priceList[0].unitCode /** 请求单位编码 */,
|
||||
unitPrice: item.priceList[0].price /** 单价 */,
|
||||
totalPrice: item.priceList[0].price /** 总价 */,
|
||||
positionId: item.positionId, //执行科室id
|
||||
unitCode: priceInfo.unitCode /** 请求单位编码 */,
|
||||
unitPrice: priceInfo.price /** 单价 */,
|
||||
totalPrice: priceInfo.price /** 总价 */,
|
||||
positionId: form.targetDepartment || item.positionId, //执行科室id
|
||||
ybClassEnum: item.ybClassEnum, //类别医保编码
|
||||
conditionId: item.conditionId, //诊断ID
|
||||
encounterDiagnosisId: item.encounterDiagnosisId, //就诊诊断id
|
||||
adviceType: item.adviceType, ///** 医嘱类型 */
|
||||
definitionId: item.priceList[0].definitionId, //费用定价主表ID */
|
||||
definitionId: priceInfo.definitionId, //费用定价主表ID */
|
||||
definitionDetailId: item.definitionDetailId, //费用定价子表ID */
|
||||
accountId: patientInfo.value.accountId, // // 账户id
|
||||
};
|
||||
@@ -254,16 +478,22 @@ const submit = () => {
|
||||
if (res.code === 200) {
|
||||
proxy.$message.success(res.msg);
|
||||
applicationList.value = [];
|
||||
applicationListAll.value = [];
|
||||
transferValue.value = [];
|
||||
lastValidTransferValue.value = [];
|
||||
emits('submitOk');
|
||||
} else {
|
||||
proxy.$message.error(res.message);
|
||||
}
|
||||
});
|
||||
};
|
||||
/** 查询科室 */
|
||||
/** 查询科室(与检验申请单一致) */
|
||||
const getLocationInfo = () => {
|
||||
getDepartmentList().then((res) => {
|
||||
orgOptions.value = res.data || [];
|
||||
return getDepartmentList().then((res) => {
|
||||
orgOptions.value = normalizeOrgTreeIds(res?.data || []);
|
||||
if (transferValue.value.length > 0) {
|
||||
nextTick(() => fillTargetDepartmentFromSelection(transferValue.value, 1));
|
||||
}
|
||||
});
|
||||
};
|
||||
// 获取诊断目录
|
||||
@@ -300,7 +530,7 @@ function getDiagnosisList() {
|
||||
}
|
||||
});
|
||||
}
|
||||
defineExpose({ state, submit, getLocationInfo, getDiagnosisList });
|
||||
defineExpose({ state, submit, getLocationInfo, getDiagnosisList, getList });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.bloodTransfusion-container {
|
||||
@@ -312,8 +542,22 @@ defineExpose({ state, submit, getLocationInfo, getDiagnosisList });
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.el-transfer {
|
||||
:deep(.el-transfer) {
|
||||
--el-transfer-panel-width: 480px !important;
|
||||
display: flex !important;
|
||||
flex-direction: row !important;
|
||||
}
|
||||
|
||||
:deep(.el-transfer__buttons) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
:deep(.el-transfer__button) {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.bloodTransfusion-form {
|
||||
|
||||
Reference in New Issue
Block a user