Files
his/openhis-ui-vue3/src/views/basicmanage/implementDepartment/index.vue
chenqi a3dce8de60 fix(inhospitalnurse): 优化住院护士站患者管理和床位分配功能
- 移除住院参与者更新失败时的异常返回,改为静默处理
- 更新床位分配提示信息,为用户提供更清晰的操作指导
- 实现实施科室下拉选择器的远程搜索功能,提升大数据量下的用户体验
- 添加节点切换时的未保存数据确认提醒,防止数据丢失
- 优化实施科室管理页面的选项过滤和加载状态管理
2026-01-19 23:18:38 +08:00

466 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-row :gutter="20">
<!--诊疗目录-->
<el-col :span="4" :xs="24">
<div class="head-title">执行科室配置</div>
<div class="head-container">
<el-tree
:data="organization"
:props="{ label: 'name', children: 'children' }"
:expand-on-click-node="true"
:filter-node-method="filterNode"
ref="treeRef"
node-key="id"
highlight-current
check-strictly
default-expand-all
@node-click="handleNodeClick"
/>
</div>
</el-col>
<!--诊疗目录-->
<el-col :span="20" :xs="24">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
:disabled="isAddDisable"
@click="handleAddItem"
v-hasPermi="['system:user:add']"
>添加新项目</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Plus"
:disabled="isAddDisable"
@click="handleBacthAddItem"
v-hasPermi="['system:user:add']"
>批量新增项目配置</el-button
>
</el-col>
</el-row>
<el-table
v-loading="loading"
:data="catagoryList"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="100" align="center" />
<el-table-column
label="诊疗目录"
width="150"
align="center"
:show-overflow-tooltip="true"
>
<template #default="scope">
<el-select
v-model="scope.row.activityCategoryCode"
placeholder="请选择"
ref="dropdown"
:class="{ 'error-border': scope.row.error }"
clearable
>
<el-option
v-for="dict in catagoryDicts"
:key="dict.value"
:label="dict.info"
:value="dict.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column label="项目名称" align="center" :show-overflow-tooltip="true">
<template #default="scope">
<el-select
v-model="scope.row.activityDefinitionId"
filterable
remote
:remote-method="(query) => handleRemoteQuery(query, scope.row)"
:loading="scope.row.loading"
placeholder="请输入并搜索项目"
style="width: 400px; max-width: 500px"
:class="{ 'error-border': scope.row.error }"
clearable
>
<el-option
v-for="item in scope.row.filteredOptions || []"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column
label="开始时间"
align="center"
key="startTime"
prop="startTime"
:show-overflow-tooltip="true"
>
<template #default="scope">
<el-time-picker
v-model="scope.row.startTime"
placeholder="选择时间"
format="HH:mm:ss"
value-format="HH:mm:ss"
>
</el-time-picker>
</template>
</el-table-column>
<el-table-column
label="结束时间"
align="center"
key="endTime"
prop="endTime"
show-overflow-tooltip
>
<template #default="scope">
<el-time-picker
v-model="scope.row.endTime"
placeholder="选择时间"
format="HH:mm:ss"
value-format="HH:mm:ss"
>
</el-time-picker>
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="150"
class-name="small-padding fixed-width"
fixed="right"
>
<template #default="scope">
<el-button
link
type="primary"
icon="Edit"
@click="openSaveImplementDepartment(scope.row, scope.$index)"
v-hasPermi="['system:user:edit']"
>保存</el-button
>
<el-button
type="danger"
link
icon="Delete"
:disabled="scope.row.id == ''"
@click="deleteSelectedRows(scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-col>
</el-row>
<BacthAddItemDialog
v-model:dialogVisible="bacthAddItemDialogVisible"
:organizationId="organizationId"
@submitOk="getList"
/>
</div>
</template>
<script setup name="implementDepartment">
import {ref} from 'vue';
import {
addImplementDepartment,
deleteImplementDepartment,
editImplementDepartment,
getAllTreatmentList,
getDiagnosisTreatmentList,
getDiseaseTreatmentInit,
getImplementDepartmentList,
} from './components/implementDepartment';
import BacthAddItemDialog from './components/batchAddDialog.vue';
const { proxy } = getCurrentInstance();
const organization = ref([]);
const loading = ref(true);
const ids = ref([]); // 存储选择的行数据
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const catagoryList = ref([]);
const catagoryDicts = ref([]);
const isAddDisable = ref(true);
const organizationId = ref('');
// 批量添加
const bacthAddItemDialogVisible = ref(false);
//默认传8(诊疗)
const distributionCategoryCode = ref('8');
const data = reactive({
form: {},
queryParams: {
pageNo: 1,
pageSize: 10,
},
tableRules: {
activityCategoryCode: [{ required: true, message: '诊疗目录不能为空', trigger: 'blur' }],
activityDefinitionId: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
},
isAdding: false,
});
const { queryParams, tableRules } = toRefs(data);
/** 查询表格数据列表 */
function getList() {
queryParams.value.organizationId = organizationId.value;
queryParams.value.distributionCategoryCode = distributionCategoryCode.value;
loading.value = true;
getDiagnosisTreatmentList(queryParams.value).then((res) => {
loading.value = false;
catagoryList.value = res.data.records;
total.value = res.data.total;
});
}
/** 通过条件过滤节点 */
const filterNode = (value, data) => {
if (!value) return true;
return data.name.indexOf(value) !== -1;
};
// 所有诊疗项目列表
const allImplementDepartmentList = ref([]);
function getAllImplementDepartment() {
loading.value = true;
getAllTreatmentList().then((res) => {
allImplementDepartmentList.value = res.data.map((item) => ({
value: item.activityDefinitionId,
label: item.activityDefinitionName,
}));
// 为所有现有行初始化过滤选项
catagoryList.value.forEach(row => {
if (!row.hasOwnProperty('filteredOptions')) {
row.filteredOptions = allImplementDepartmentList.value.slice(0, 100); // 限制为前100个
row.loading = false;
}
});
loading.value = false;
});
}
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
}
// 远程搜索处理函数
function handleRemoteQuery(query, row) {
if (query !== '') {
// 设置加载状态
row.loading = true;
// 模拟异步延迟
setTimeout(() => {
// 过滤选项
row.filteredOptions = allImplementDepartmentList.value.filter(item => {
return item.label.toLowerCase().includes(query.toLowerCase()) ||
item.value.toLowerCase().includes(query.toLowerCase());
});
row.loading = false;
}, 300); // 300ms 延迟,模拟网络请求
} else {
// 如果查询为空,显示所有选项(但限制数量以提高性能)
row.filteredOptions = allImplementDepartmentList.value.slice(0, 100); // 限制为前100个
}
}
// 新增项目
function handleAddItem() {
if (data.isAdding) {
proxy.$message.warning('请先保存当前行后再新增!');
return;
}
const newRow = {
startTime: '00:00:00',
endTime: '23:59:59',
loading: false, // 添加加载状态
filteredOptions: allImplementDepartmentList.value.slice(0, 100), // 初始化过滤选项,限制数量
};
catagoryList.value.push(newRow);
total.value = catagoryList.value.length; // 修正:使用实际数据列表长度,而不是组织结构长度
data.isAdding = true; // 设置标志位为 true表示有未保存的
}
// 批量添加
function handleBacthAddItem() {
// 批量添加显示对话框
bacthAddItemDialogVisible.value = true;
}
// 检验 编辑或 保存数据
function handleBlur(row, index) {
let hasError = false;
const fields = ['activityCategoryCode', 'activityDefinitionId', 'startTime', 'endTime'];
fields.forEach((field) => {
if (!row[field]) {
hasError = true;
const message = tableRules.value[field]?.[0]?.message;
if (message) {
proxy.$message.error(message);
} else {
proxy.$message.error(`检验未通过`);
}
}
});
row.error = hasError;
}
// 编辑或 保存当前行
function openSaveImplementDepartment(row) {
const params = {
// 科室id
organizationId: organizationId.value,
// 类别
distributionCategoryCode: distributionCategoryCode.value,
...row,
};
let hasError = false;
handleBlur(row);
if (row.error) {
hasError = true;
return;
}
const startTime = params.startTime;
const endTime = params.endTime;
if (startTime > endTime) {
proxy.$message.error('开始时间不能大于结束时间');
return;
}
if (hasError) {
proxy.$message.error('请填写完整信息');
return;
}
if (row.id) {
editImplementDepartment(params).then((res) => {
data.isAdding = false; // 允许新增下一行
proxy.$modal.msgSuccess('保存成功!');
});
} else {
delete params.id;
addImplementDepartment(params).then((res) => {
data.isAdding = false; // 允许新增下一行
proxy.$modal.msgSuccess('保存成功!');
});
}
}
// 删除当前所选行
function deleteSelectedRows(row) {
proxy.$modal.confirm('是否删除选中数据').then(() => {
if (row.id) {
deleteImplementDepartment({ orgLocId: row.id }).then((res) => {});
} else {
catagoryList.value.pop();
}
proxy.$modal.msgSuccess('删除成功');
data.isAdding = false;
getList();
});
}
/** 节点单击事件 */
function handleNodeClick(res, node) {
// 检查是否有未保存的数据
if (data.isAdding) {
proxy.$modal.confirm('当前有未保存的数据,切换节点将丢失未保存的数据,是否继续?').then(() => {
// 确认切换,重置状态
data.isAdding = false;
continueHandleNodeClick(node);
}).catch(() => {
// 取消切换,保持当前状态
return;
});
} else {
continueHandleNodeClick(node);
}
}
// 实际的节点点击处理逻辑
function continueHandleNodeClick(node) {
// 新增按钮是否 disable
if (node.parent === null || node.level === 1) {
isAddDisable.value = true;
} else {
isAddDisable.value = false;
}
// 检查节点是否有子节点
if (node.data.children && node.data.children.length > 0) {
// proxy.$message.warning("不能选择父节点");
return;
}
// 选中科室id
organizationId.value = node.data.id;
// 获取 右侧 table 信息
getList();
}
/** 目录分类查询 */
function getDiseaseTreatmentList() {
loading.value = true;
getDiseaseTreatmentInit().then(({ data }) => {
loading.value = false;
//分类目录初始化获取
catagoryDicts.value = data.diagnosisCategoryOptions.sort((a, b) => {
return parseInt(a.value) - parseInt(b.value);
});
});
// 诊疗目录分类查询下拉树结d构
loading.value = true;
// 诊疗目录分类查询下拉树结d构
getImplDepartList();
}
// 诊疗目录分类查询下拉树结d构
function getImplDepartList() {
loading.value = true;
getImplementDepartmentList().then((res) => {
loading.value = false;
if (res.code === 200) {
if (res.data.records.length > 0) {
organization.value = res.data.records.map((res) => {
return {
...res,
isEditing: false, // 标记当前行是否正在编辑
error: false, // 新增 error 字段
};
});
} else {
organization.value = [];
}
} else {
this.$modal.msgError(res.code);
}
});
}
onMounted(() => {
getAllImplementDepartment();
getDiseaseTreatmentList();
});
</script>
<style scoped>
.el-form--inline .el-form-item {
display: inline-flex;
vertical-align: middle;
margin-right: 10px !important;
}
.error-border {
border: 1px solid red;
}
</style>