需求56 检查项目设置-》检查类型维护;在check_type表中增加一个parent_id字段用于父行与子行绑定;修改执行科室下拉字典的数据来源

This commit is contained in:
HuangShun
2026-01-30 15:31:01 +08:00
parent 28160e082c
commit 48309fcaa4
2 changed files with 273 additions and 88 deletions

View File

@@ -52,6 +52,9 @@ public class CheckType {
/** 更新时间 */ /** 更新时间 */
private LocalDateTime updateTime; private LocalDateTime updateTime;
/** 父级ID */
private Long parentId;
/** /**
* 禁用逻辑删除因为数据库表中没有delete_flag字段 * 禁用逻辑删除因为数据库表中没有delete_flag字段
*/ */

View File

@@ -84,10 +84,10 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr <tr
v-for="(item, index) in tableData" v-for="(item, index) in tableData"
:key="index" :key="index"
:class="{ 'editing-row': item.editing, 'child-row': item.row.includes('.') }" :class="{ 'editing-row': item.editing, 'child-row': !!item.parentId }"
@click="handleRowClick(index)" @click="handleRowClick(index)"
> >
<td>{{ item.row }}</td> <td>{{ item.row }}</td>
@@ -177,7 +177,7 @@
</button> </button>
<button <button
v-if="!item.row.includes('.')" v-if="!item.parentId"
class="btn btn-add" class="btn btn-add"
@click.stop="handleAdd(index)" @click.stop="handleAdd(index)"
title="添加子项" title="添加子项"
@@ -190,7 +190,7 @@
</button> </button>
<button <button
v-if="!item.row.includes('.')" v-if="!item.parentId"
class="btn btn-add" class="btn btn-add"
@click.stop="handleAdd(index)" @click.stop="handleAdd(index)"
title="添加子项" title="添加子项"
@@ -567,6 +567,7 @@
import {computed, onMounted, reactive, ref} from 'vue'; import {computed, onMounted, reactive, ref} from 'vue';
import {ElMessage, ElMessageBox} from 'element-plus'; import {ElMessage, ElMessageBox} from 'element-plus';
import {getDicts} from '@/api/system/dict/data'; import {getDicts} from '@/api/system/dict/data';
import {getList as getDeptList} from '@/views/basicmanage/organization/components/api';
import { import {
addCheckMethod, addCheckMethod,
addCheckPart, addCheckPart,
@@ -677,14 +678,105 @@ const currentSearchParams = computed(() => {
// 按钮悬停状态 // 按钮悬停状态
const hoverAddButton = ref(false); const hoverAddButton = ref(false);
// 排序函数:确保父行在前,子行在父行后面
function sortTableDataByParentChild(data) {
// 分离父行和子行
const parentRows = [];
const childRows = [];
data.forEach(item => {
// parentId 为 null/undefined/0 的都是父行
if (item.parentId) {
childRows.push(item);
} else {
parentRows.push(item);
}
});
// 按编码排序父行
parentRows.sort((a, b) => {
const codeA = a.code || '';
const codeB = b.code || '';
return codeA.localeCompare(codeB, undefined, { numeric: true });
});
// 构建最终排序结果
const sortedData = [];
let rowNum = 1;
parentRows.forEach(parent => {
// 添加父行
parent.row = String(rowNum);
sortedData.push(parent);
// 查找并添加该父行的所有子行
const children = childRows.filter(child => child.parentId === parent.id);
// 按子行编码排序
children.sort((a, b) => {
const codeA = a.code || '';
const codeB = b.code || '';
return codeA.localeCompare(codeB, undefined, { numeric: true });
});
// 添加子行,并设置子行行号
children.forEach((child, index) => {
child.row = parent.row + '.' + (index + 1);
sortedData.push(child);
});
rowNum++;
});
return sortedData;
}
// 从数据库获取所有检查相关数据 // 从数据库获取所有检查相关数据
onMounted(async () => { onMounted(async () => {
try { try {
// 获取科室字典数据 // 1. 获取科室分类字典,找到“医学影像科”对应的 value
const deptResponse = await getDicts('dept'); let imageClassValues = [];
if (deptResponse && deptResponse.data) { try {
// 保存完整的科室字典数据,包含编码和名称 const dictRes = await getDicts('organization_class');
departments.value = deptResponse.data; if (dictRes && dictRes.data) {
imageClassValues = dictRes.data
.filter(item => item.dictLabel.includes('医学影像科'))
.map(item => item.dictValue);
}
} catch (e) {
console.error('获取字典失败', e);
}
// 2. 获取科室列表
const deptResponse = await getDeptList({ pageNo: 1, pageSize: 1000 });
if (deptResponse && (deptResponse.data || deptResponse.records)) {
const records = deptResponse.data?.records || deptResponse.records || [];
// 3. 过滤
const filteredDepts = records.filter(item => {
// 匹配字典值
let matchClass = false;
if (item.classEnum && imageClassValues.length > 0) {
// classEnum 可能是 "1" 或 "1,2"
const itemClasses = String(item.classEnum).split(',');
matchClass = itemClasses.some(c => imageClassValues.includes(c));
}
// 匹配文本
const matchText = item.classEnum_dictText && item.classEnum_dictText.includes('医学影像科');
// 匹配名称 (保底) - 放宽匹配条件
const matchName = ['超声', '放射', '内镜', '心电'].some(k => item.name && item.name.includes(k));
return matchClass || matchText || matchName;
});
// 4. 赋值
departments.value = filteredDepts.map(item => ({
dictValue: item.name,
dictLabel: item.name
}));
} }
// 获取检查类型数据(从数据字典获取) // 获取检查类型数据(从数据字典获取)
@@ -713,19 +805,24 @@ onMounted(async () => {
if (typeTableResponse && typeTableResponse.data) { if (typeTableResponse && typeTableResponse.data) {
// 构建检查类型表格数据 // 构建检查类型表格数据
checkTypeData.splice(0, checkTypeData.length); checkTypeData.splice(0, checkTypeData.length);
typeTableResponse.data.forEach((item, index) => { const tempData = typeTableResponse.data.map((item) => ({
checkTypeData.push({ id: item.id, // 保存id字段用于判断是新增还是修改
id: item.id, // 保存id字段用于判断是新增还是修改 row: '', // 行号将在排序后重新分配
row: (index + 1).toString(), code: item.code,
code: item.code, name: item.name,
name: item.name, type: item.type,
type: item.type, selected: true,
selected: true, department: item.department || '',
department: item.department || '', number: item.number || '999999',
number: item.number || '999999', remark: item.remark || '',
remark: item.remark || '', parentId: item.parentId || null, // 父行的 parentId 保持为 null
actions: true actions: true
}); }));
// 排序数据,确保父行在前,子行在父行后
const sortedData = sortTableDataByParentChild(tempData);
sortedData.forEach(item => {
checkTypeData.push(item);
}); });
} }
@@ -820,29 +917,31 @@ async function loadMenuData(menu) {
case '检查类型': case '检查类型':
// 清空检查类型数据 // 清空检查类型数据
checkTypeData.splice(0, checkTypeData.length); checkTypeData.splice(0, checkTypeData.length);
const typeResponse = await listCheckType(); const typeResponse = await listCheckType();
if (typeResponse && typeResponse.data) { if (typeResponse && typeResponse.data) {
// 确保data是数组类型 // 确保data是数组类型
const typeData = Array.isArray(typeResponse.data) ? typeResponse.data : []; const typeData = Array.isArray(typeResponse.data) ? typeResponse.data : [];
// 获取所有不重复的检查类型值 // 获取所有不重复的检查类型值
checkTypes.value = [...new Set(typeData.map(item => item.type))]; checkTypes.value = [...new Set(typeData.map(item => item.type))];
// 构建临时数据
typeData.forEach((item, index) => { const tempData = typeData.map((item) => ({
// 直接使用数据库中的department值不进行转换 id: item.id, // 保存id字段用于判断是新增还是修改
checkTypeData.push({ row: '', // 行号将在排序后重新分配
id: item.id, // 保存id字段用于判断是新增还是修改 code: item.code,
row: (index + 1).toString(), name: item.name,
code: item.code, type: item.type,
name: item.name, selected: true,
type: item.type, department: item.department || '',
selected: true, number: item.number || '999999',
department: item.department || '', remark: item.remark || '',
number: item.number || '999999', parentId: item.parentId || null, // 父行的 parentId 保持为 null
remark: item.remark || '', actions: true
actions: true }));
});
// 排序数据,确保父行在前,子行在父行后
const sortedData = sortTableDataByParentChild(tempData);
sortedData.forEach(item => {
checkTypeData.push(item);
}); });
} }
break; break;
@@ -985,7 +1084,11 @@ function handleEdit(index) {
// 处理取消编辑按钮点击 // 处理取消编辑按钮点击
function handleCancelEdit(index) { function handleCancelEdit(index) {
const item = tableData.value[index]; const item = tableData.value[index];
item.editing = false; if (item.isNew) {
tableData.value.splice(index, 1);
} else {
item.editing = false;
}
} }
// 处理确认按钮点击 // 处理确认按钮点击
@@ -1038,11 +1141,24 @@ async function handleConfirm(index) {
orderNum: item.orderNum, orderNum: item.orderNum,
remark: item.remark remark: item.remark
}; };
console.log('准备新增检查方法:', addData); const response = await addCheckMethod(addData);
const newItem = await addCheckMethod(addData);
console.log('新增检查方法返回结果:', newItem); // 将新增的id赋值给本地数据兼容不同的返回格式
// 将新增的id赋值给本地数据 let newId = null;
item.id = newItem.id; if (response) {
// 尝试多种可能的返回格式
newId = response.id ||
response.data?.id ||
response.data?.data?.id ||
(typeof response.data === 'number' ? response.data : null) ||
(typeof response.data === 'string' ? response.data : null);
}
if (newId) {
item.id = newId;
} else {
ElMessage.warning('数据已保存但未能获取ID删除功能可能受影响');
}
} }
} else if (activeMenu.value === '检查部位') { } else if (activeMenu.value === '检查部位') {
// 检查部位的保存逻辑 // 检查部位的保存逻辑
@@ -1094,7 +1210,8 @@ async function handleConfirm(index) {
selected: item.selected, selected: item.selected,
department: item.department, department: item.department,
number: item.number, number: item.number,
remark: item.remark remark: item.remark,
parentId: item.parentId || null // 父行的 parentId 设为 null
}; };
await updateCheckType(updateData); await updateCheckType(updateData);
} else { } else {
@@ -1106,19 +1223,25 @@ async function handleConfirm(index) {
selected: item.selected, selected: item.selected,
department: item.department, department: item.department,
number: item.number, number: item.number,
remark: item.remark remark: item.remark,
parentId: item.parentId || null // 父行的 parentId 设为 null
}; };
console.log('准备新增检查类型:', addData); const response = await addCheckType(addData);
const newItem = await addCheckType(addData); // 将新增的id赋值给本地数据兼容不同的返回格式
console.log('新增检查类型返回结果:', newItem); const newItem = response.data || response;
// 将新增的id赋值给本地数据 item.id = newItem.id || newItem;
item.id = newItem.id; console.log('保存的ID:', item.id);
} }
} }
// 退出编辑状态 // 退出编辑状态
tableData.value[index].editing = false; tableData.value[index].editing = false;
if (item.isNew) {
item.isNew = false;
}
// 显示保存成功提示 // 显示保存成功提示
ElMessage.success(`${item.row} 行数据已保存`); ElMessage.success(`${item.row} 行数据已保存`);
// 保存成功后自动刷新列表
await loadMenuData(activeMenu.value);
} catch (error) { } catch (error) {
console.error('保存失败,错误信息:', error); console.error('保存失败,错误信息:', error);
console.error('保存失败,错误详情:', error.response ? error.response.data : error); console.error('保存失败,错误详情:', error.response ? error.response.data : error);
@@ -1128,26 +1251,72 @@ async function handleConfirm(index) {
// 处理删除按钮点击 // 处理删除按钮点击
async function handleDelete(index) { async function handleDelete(index) {
ElMessageBox.confirm('确定要删除这一行吗?', '系统提示', { const item = tableData.value[index];
// 如果是新增但未保存的行没有ID或标记为新增直接从列表中移除
// 注意:必须严格检查 ID 是否为有效值
const hasValidId = item.id &&
item.id !== null &&
item.id !== undefined &&
item.id !== '' &&
String(item.id).trim() !== '' &&
String(item.id) !== 'undefined' &&
String(item.id) !== 'null';
if (!hasValidId || item.isNew) {
ElMessageBox.confirm('该行数据尚未保存,确定要删除吗?', '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
tableData.value.splice(index, 1);
ElMessage.success('删除成功');
}).catch(() => {
console.log('用户取消删除操作');
});
return;
}
// 检查是否为父行
const isParentRow = activeMenu.value === '检查类型' && !item.parentId;
// 如果是父行,查找所有子行
let childRows = [];
if (isParentRow && item.id) {
childRows = tableData.value.filter(row => row.parentId === item.id);
}
// 构建确认消息
let confirmMessage = '确定要删除这一行吗?';
if (isParentRow && childRows.length > 0) {
confirmMessage = `确定要删除这一行吗?\n该操作将同时删除 ${childRows.length} 个子行数据。`;
}
ElMessageBox.confirm(confirmMessage, '系统提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(async () => { }).then(async () => {
const item = tableData.value[index];
try { try {
// 如果有id调用API删除数据库中的数据 // 确保 ID 是有效的数字或字符串
if (item.id) { const validId = String(item.id).trim();
if (activeMenu.value === '检查方法') { if (!validId || validId === 'undefined' || validId === 'null') {
await delCheckMethod(item.id); ElMessage.error('删除失败无效的ID');
} else if (activeMenu.value === '检查部位') { return;
await delCheckPart(item.id);
} else {
await delCheckType(item.id);
}
} }
// 从数组中删除该行数据
tableData.value.splice(index, 1); // 只需要删除当前行,数据库会通过外键级联自动删除子行
ElMessage.success('删除成功!'); if (activeMenu.value === '检查方法') {
await delCheckMethod(validId);
} else if (activeMenu.value === '检查部位') {
await delCheckPart(validId);
} else {
await delCheckType(validId);
}
// 删除成功,刷新列表数据
await loadMenuData(activeMenu.value);
ElMessage.success(`删除成功!${isParentRow && childRows.length > 0 ? `已删除 1 个父行和 ${childRows.length} 个子行` : ''}`);
} catch (error) { } catch (error) {
ElMessage.error('删除失败,请稍后重试'); ElMessage.error('删除失败,请稍后重试');
} }
@@ -1181,6 +1350,7 @@ function handleAddNewRow() {
department: '', department: '',
number: '999999', number: '999999',
remark: '', remark: '',
parentId: null, // 父行的 parentId 设为 null避免外键约束错误
editing: true, // 新行默认进入编辑状态 editing: true, // 新行默认进入编辑状态
isNew: true, // 标记为新增行 isNew: true, // 标记为新增行
actions: true actions: true
@@ -1240,37 +1410,49 @@ function handleAddNewRow() {
function handleAdd(index) { function handleAdd(index) {
const parentRow = tableData.value[index]; const parentRow = tableData.value[index];
if (!parentRow.id) {
ElMessage.warning('请先保存父行数据后再添加子行');
return;
}
// 查找该父行的所有现有子行,确定下一个子行号 // 查找该父行的所有现有子行,确定下一个子行号
const parentRowPrefix = parentRow.row + '.'; const children = tableData.value.filter(item => item.parentId === parentRow.id);
let maxChildNum = 0; const nextChildNum = children.length + 1;
tableData.value.forEach((item, idx) => { // 生成默认子行编码
if (item.row.startsWith(parentRowPrefix) && idx > index) { const childCode = parentRow.code ? `${parentRow.code}_${String(nextChildNum).padStart(2, '0')}` : '';
const childNum = parseInt(item.row.split('.').pop());
if (childNum > maxChildNum) { // 创建子行数据
maxChildNum = childNum;
}
}
});
const nextChildNum = maxChildNum + 1;
// 创建子行数据,继承父行的编码
const childRow = { const childRow = {
row: parentRow.row + '.' + nextChildNum, // 子行编号 row: parentRow.row + '.' + nextChildNum, // 子行行号显示
code: parentRow.code, // 继承父行编码 code: childCode,
name: '', name: '',
type: '', type: parentRow.type,
selected: false, selected: false,
department: '', department: parentRow.department,
number: '', number: '',
remark: '', remark: '',
parentId: parentRow.id,
editing: true, editing: true,
actions: false isNew: true,
actions: true
}; };
// 在父行后插入子行 // 找到父行的最后一个子行位置,在其后插入子行
tableData.value.splice(index + 1, 0, childRow); let insertIndex = index + 1;
for (let i = index + 1; i < tableData.value.length; i++) {
const item = tableData.value[i];
// 如果是该父行的子行,继续向后查找
if (item.parentId === parentRow.id) {
insertIndex = i + 1;
} else {
// 遇到非子行,停止查找
break;
}
}
// 在找到的位置插入子行
tableData.value.splice(insertIndex, 0, childRow);
} }
// 处理搜索功能 // 处理搜索功能