@@ -86,7 +86,7 @@
< / td >
< td >
< template v-if = "editingRowId === row.id" >
< input v-model = "row.sortOrder" type="text" :style="inputStyle" >
< input v-model = "row.sortOrder" type="text" :style="inputStyle" :disabled="isChildTypeRow(row)" >
< / template >
< template v-else >
{{ row.sortOrder }}
@@ -717,7 +717,7 @@ import {
listInspectionPackageDetails ,
saveInspectionPackageDetails
} from '@/api/system/inspectionPackage' ;
import { getLocationTree } from '@/views/charge/outpatientregistration/components/outpatientregistration ' ;
import { deptTreeSelect } from '@/api/system/user ' ;
// 获取当前登录用户信息
const userStore = useUserStore ( ) ;
@@ -807,7 +807,7 @@ const typePageButtons = computed(() => {
const total = typeTotalPages . value ;
return Array . from ( { length : total } , ( _ , i ) => i + 1 ) ;
} ) ;
// 按“大类编码(co de)”排序后再分页展示(不要按序号 sortOrder 排 )
// 按“序号(sortOr der )”排序后再分页展示(需求:不要按大类编码排序 )
function parseCodeParts ( code ) {
const s = ( code ? ? '' ) . toString ( ) . trim ( ) ;
// 支持 1、01、3-001、3_001 等:用 -/_ 分隔
@@ -827,33 +827,37 @@ function parseCodeParts(code) {
} ;
}
function isTempId ( id ) {
return typeof id === 'string' && id . startsWith ( 'temp_' ) ;
}
function isChildTypeRow ( row ) {
const p = parseCodeParts ( row ? . code ) ;
return ! ! p . subRaw ;
}
const sortedTypeRows = computed ( ( ) => {
// 需求:新增/编辑时不要“实时排序”,避免行在编辑过程中跳动;
// 仅在保存成功后(编辑结束、临时行消失/刷新数据)再按编码排序。
const hasTempRow = ( tableData . value || [ ] ) . some ( r => isTempId ( r ? . id ) ) ;
if ( activeNav . value === 0 && ( editingRowId . value || hasTempRow ) ) {
return [ ... tableData . value ] ;
}
return [ ... tableData . value ] . sort ( ( a , b ) => {
const aOrder = a ? . sortOrder === null || a ? . sortOrder === undefined ? Number . POSITIVE _INFINITY : Number ( a . sortOrder ) ;
const bOrder = b ? . sortOrder === null || b ? . sortOrder === undefined ? Number . POSITIVE _INFINITY : Number ( b . sortOrder ) ;
if ( aOrder !== bOrder ) return aOrder - bOrder ;
// 同序号:按编码保证稳定性(大类在子类之前,子类按后缀排序)
const pa = parseCodeParts ( a ? . code ) ;
const pb = parseCodeParts ( b ? . code ) ;
// 先按主编码:数字优先按数值,否则按字符串
if ( pa . mainIsNum && pb . mainIsNum ) {
if ( pa . mainNum !== pb . mainNum ) return pa . mainNum - pb . mainNum ;
} else {
const c = pa . mainRaw . localeCompare ( pb . mainRaw , 'zh-Hans-CN' , { numeric : true , sensitivity : 'base' } ) ;
if ( c !== 0 ) return c ;
if ( pa . mainRaw !== pb . mainRaw ) {
return pa . mainRaw . localeCompare ( pb . mainRaw , 'zh-Hans-CN' , { numeric : true , sensitivity : 'base' } ) ;
}
// 同主编码时:无子编码的排在前(大类在子类之前)
const aHasSub = ! ! pa . subRaw ;
const bHasSub = ! ! pb . subRaw ;
if ( aHasSub !== bHasSub ) return aHasSub ? 1 : - 1 ;
// 再按子编码
if ( pa . subIsNum && pb . subIsNum ) {
if ( pa . subNum !== pb . subNum ) return pa . subNum - pb . subNum ;
} else {
const c = pa . subRaw . localeCompare ( pb . subRaw , 'zh-Hans-CN' , { numeric : true , sensitivity : 'base' } ) ;
if ( c !== 0 ) return c ;
}
// 最后兜底:按原字符串
return pa . raw . localeCompare ( pb . raw , 'zh-Hans-CN' , { numeric : true , sensitivity : 'base' } ) ;
} ) ;
} ) ;
@@ -905,31 +909,53 @@ const editingRowId = ref(null);
const inputStyle = { width : '100%' , height : '28px' , padding : '0 4px' , border : '1px solid #d9d9d9' , borderRadius : '2px' } ;
const departments = ref ( [ ] ) ;
/** 查询就诊 科室 - 与门诊挂号页面保持一致 */
/** 查询执行 科室 - 与“科室管理”页面保持完全一致的过滤与展示口径 */
function getLocationInfo ( ) {
console . log ( '调用getLocationTree API... ' ) ;
getLocationTree ( ) . then ( ( response ) => {
console . log ( 'getLocationTree API完整返回:' , response ) ;
console . log ( 'getLocationTree API数据结构:' , JSON . stringify ( response . data , null , 2 ) ) ;
// 检查数据结构并转换为适合el-tree-select的格式
if ( Array . isArray ( response . data ) ) {
// 直接使用数组数据
departments . value = response . data ;
} else if ( response . data && response . data . records ) {
// 处理分页格式数据
departments . value = response . data . records ;
} else if ( response . data && response . data . rows ) {
// 处理另一种分页格式数据
departments . value = response . data . rows ;
} else {
console . error ( 'API返回数据格式不符合预期:' , response . data ) ;
departments . value = [ ] ;
console . log ( '========== 检验项目设置 - 获取执行科室 ========== ' ) ;
// 与科室管理页 queryParams 对齐: pageNo/pageSize/typeEnum/classEnum/name
// deptTreeSelect 内部默认 typeEnum=2( 科室) , 这里显式传入确保不会被外部覆盖
const queryParams = {
pageNo : 1 ,
pageSize : 1000 , // 获取足够多的数据
name : undefined ,
typeEnum : 2 ,
classEnum : undefined
} ;
console . log ( '请求参数:' , queryParams ) ;
deptTreeSelect ( queryParams ) . then ( ( response ) => {
console . log ( 'API 原始响应:' , response ) ;
let orgList = [ ] ;
// 处理分页响应格式
if ( response && response . data ) {
if ( response . data . records && Array . isArray ( response . data . records ) ) {
orgList = response . data . records ;
console . log ( '从 response.data.records 获取数据,数量:' , orgList . length ) ;
} else if ( Array . isArray ( response . data ) ) {
orgList = response . data ;
console . log ( '从 response.data 获取数据,数量:' , orgList . length ) ;
}
} else if ( Array . isArray ( response ) ) {
orgList = response ;
console . log ( '从 response 直接获取数据,数量:' , orgList . length ) ;
}
console . log ( '最终科室数据:' , JSON . stringify ( departments . value , null , 2 ) ) ;
console . log ( '处理前的原始科室列表(包含 children) :' , orgList ) ;
/**
* 关键:科室管理页面使用 el-table 展示的是 records( 顶层列表) , 并不会展示 children 子节点。
* 为了“完全一致”,这里也只使用 records 顶层数据,并移除 children, 避免出现科室管理页看不到的下级节点。
*/
const topLevel = ( orgList || [ ] ) . map ( n => {
const { children , ... rest } = ( n || { } ) ;
return rest ;
} ) ;
// 与科室管理页保持一致:即使 name 为空也保留该行(科室管理表格仍会显示一行)
departments . value = topLevel ;
console . log ( '========== 检验项目设置 - 执行科室加载完成 ==========' ) ;
} ) . catch ( ( error ) => {
console . error ( '获取科室数据 失败:' , error ) ;
console . error ( '获取执行 科室失败:' , error ) ;
departments . value = [ ] ;
} ) ;
}
@@ -1510,7 +1536,8 @@ const addNewRow = () => {
}
// department 在表格里是字符串(科室名称);这里不要直接塞对象,否则后续 trim/校验会异常
const defaultDeptName = departments . value ? . [ 0 ] ? . name || '' ;
const newRow = { id : Date . now ( ) , code : '' , name : '' , de partm ent: defaultDeptName , sortOrder : tableData . value . length + 1 , remark : '' } ;
// 新增大类时, parentId 为 null
const newRow = { id : ` temp_ ${ Date . now ( ) } ` , code : '' , name : '' , department : defaultDeptName , sortOrder : tableData . value . length + 1 , remark : '' , parentId : null } ;
tableData . value . push ( newRow ) ;
editingRowId . value = newRow . id ;
} ;
@@ -1524,6 +1551,16 @@ const handleEdit = (row) => {
} ;
const handleConfirm = ( row ) => {
// 子类序号必须与主类相同,且不可更改:保存时强制回填
const parts = parseCodeParts ( row ? . code ) ;
if ( parts . subRaw ) {
const parentCode = parts . mainRaw ;
const parent = tableData . value . find ( r => ( r ? . code ? ? '' ) . toString ( ) . trim ( ) === parentCode ) ;
if ( parent ) {
row . sortOrder = parent . sortOrder ;
}
}
// 准备提交给后端的数据, 保留sortOrder字段名, 后端会自动映射到数据库的order字段
const submitData = {
... row ,
@@ -1555,51 +1592,56 @@ const handleConfirm = (row) => {
return ;
}
// 检查是否是已知的重复编码
if ( submitData . code . trim ( ) === '21' ) {
alert ( '检验类型编码21已存在, 请使用其他编码' ) ;
return ;
}
// 输出调试信息
console . log ( '原始code值:' , submitData . code , '长度:' , submitData . code . length ) ;
// 注意:编码唯一性由后端统一校验;这里不做硬编码拦截(避免误判)
// 去除code字段的前后空格, 确保唯一性验证准确
submitData . code = submitData . code . trim ( ) ;
console . log ( '去除空格后的code值:' , submitData . code , '长度:' , submitData . code . length ) ;
console . log ( '准备提交的数据:' , submitData ) ;
// 区分新增和更新操作
if ( row . i d. toString ( ) . length > 10 ) { // 新增的临时ID
// 区分新增和更新操作:使用 temp_ 前缀的临时ID判断, 避免时间戳阈值在不同年份失效
if ( isTempId ( row . id ) ) { // 新增的临时ID
// 处理 parentId: 如果是子类且 parentId 是临时ID, 需要先找到父类的真实 id
let finalParentId = submitData . parentId ;
if ( finalParentId && isTempI d( finalParentId ) ) {
// parentId 是临时ID, 说明父类还没保存, 这种情况不应该出现( 因为要求先保存父类)
// 但为了容错,尝试通过 code 找到父类
const parts = parseCodeParts ( submitData . code ) ;
if ( parts . subRaw ) {
const parentCode = parts . mainRaw ;
const parent = tableData . value . find ( r =>
! isTempId ( r . id ) && ( r ? . code ? ? '' ) . toString ( ) . trim ( ) === parentCode
) ;
if ( parent ) {
finalParentId = parent . id ;
} else {
ElMessage . warning ( '请先保存父类,再保存子类' ) ;
return ;
}
}
}
// 新增数据时移除临时ID, 让后端自动生成主键
const { id , ... newData } = submitData ;
console . log ( '删除ID后的newData:' , newData ) ;
newData . parentId = finalParentId || null ; // 确保 parentId 正确设置(大类为 null, 子类为父类 id)
addInspectionType ( newData ) . then ( response => {
console . log ( '新增成功响应:' , response ) ;
ElMessage . success ( '新增成功' ) ;
getInspectionTypeList ( ) ;
} ) . catch ( error => {
console . error ( '新增检验类型失败:' , error ) ;
if ( error . response && error . response . data ) {
alert ( '新增失败: ' + error . response . data . msg ) ;
ElMessage . error ( error . response . data . msg || '新增失败' ) ;
} else {
alert ( '新增失败,请重试' ) ;
ElMessage . error ( '新增失败,请重试' ) ;
}
} ) ;
} else { // 更新操作
// 更新数据时保留ID
console . log ( '更新时的submitData:' , submitData ) ;
updateInspectionType ( submitData ) . then ( response => {
console . log ( '更新成功响应:' , response ) ;
ElMessage . success ( '保存成功' ) ;
getInspectionTypeList ( ) ;
} ) . catch ( error => {
console . error ( '更新检验类型失败:' , error ) ;
if ( error . response && error . response . data ) {
alert ( '更新失败: ' + error . response . data . msg ) ;
ElMessage . error ( error . response . data . msg || '保存失败' ) ;
} else {
alert ( '更新 失败,请重试' ) ;
ElMessage . error ( '保存 失败,请重试' ) ;
}
} ) ;
}
@@ -1637,14 +1679,16 @@ const handleAdd = (row, index) => {
const nextSeq = maxSeq + 1 ;
const childCode = ` ${ parentCode } - ${ String ( nextSeq ) . padStart ( 3 , '0' ) } ` ;
// 新增子类时, parentId 指向父类的 id( 如果父类已保存有真实 id, 否则先存父类的临时 id, 保存时再处理)
const newRow = {
id : Date . now ( ) ,
id : ` temp_ ${ Date . now ( ) } ` ,
code : childCode ,
name : '' ,
department : row . department ,
// 序号字段保持原逻辑:插入到父类下一行,默认沿用父类序号
sortOrder : row . sortOrder ,
remark : ''
remark : '' ,
parentId : row . id // 子类的 parentId 指向父类的 id( 可能是真实 id 或临时 id)
} ;
tableData . value . splice ( index + 1 , 0 , newRow ) ;
editingRowId . value = newRow . id ;
@@ -1662,9 +1706,8 @@ const handleAdd = (row, index) => {
const numericId = Number ( id ) ;
console . log ( '转换后的ID:' , numericId , '类型:' , typeof numericId ) ;
// 判断是否为临时ID( 临时ID是通过Date.now()生成的, 值很大, 通常大于2000000000000 )
const isTemporaryId = numericId > 2 e12 ;
console . log ( '是否为临时ID:' , isTemporaryId , '判断阈值:' , 2 e12 ) ;
// 判断是否为临时ID( 前端 temp_ 前缀 )
const isTemporaryId = isTempId ( id ) ;
if ( ! isTemporaryId ) { // 真实数据库ID
console . log ( '调用删除API, ID:' , numericId , 'API路径:' , ` /system/inspection-type/ ${ numericId } ` ) ;
@@ -1686,8 +1729,7 @@ const handleAdd = (row, index) => {
} ) ;
} else {
// 删除临时新增的行
console . log ( '删除临时行, ID:' , numericI d) ;
tableData . value = tableData . value . filter ( row => Number ( row . id ) !== numericId ) ;
tableData . value = tableData . value . filter ( row => row . id !== i d) ;
ElMessage . success ( '删除成功' ) ;
}
} ) . catch ( ( ) => {