Files
his/sql/迁移记录-DB变更记录/手术管理页面代码修正方案.md

19 KiB
Raw Blame History

手术管理页面代码修正方案

根据详细设计文档,以下是手术管理页面的完整修正方案。

一、表格列定义修正

修改前:

<el-table v-loading="loading" :data="surgeryList" row-key="id">
  <el-table-column label="手术编号" align="center" prop="surgeryNo" width="150" />
  <el-table-column label="患者姓名" align="center" prop="patientName" width="100" />
  <el-table-column label="性别" align="center" prop="patientGender" width="60" />
  <el-table-column label="年龄" align="center" prop="patientAge" width="60" />
  <el-table-column label="手术名称" align="center" prop="surgeryName" min-width="150" show-overflow-tooltip />
  <el-table-column label="手术类型" align="center" prop="surgeryTypeEnum_dictText" width="100" />
  <el-table-column label="手术等级" align="center" prop="surgeryLevel_dictText" width="100" />
  <el-table-column label="手术状态" align="center" prop="statusEnum_dictText" width="100">
    <template #default="scope">
      <el-tag :type="getStatusType(scope.row.statusEnum)">
        {{ scope.row.statusEnum_dictText }}
      </el-tag>
    </template>
  </el-table-column>
  <el-table-column label="计划时间" align="center" prop="plannedTime" width="160" />
  <el-table-column label="主刀医生" align="center" prop="mainSurgeonName" width="100" />
  <el-table-column label="麻醉医生" align="center" prop="anesthetistName" width="100" />
  <el-table-column label="手术室" align="center" prop="operatingRoomName" width="120" />
  <el-table-column label="执行科室" align="center" prop="orgName" width="120" show-overflow-tooltip />
  <el-table-column label="操作" align="center" width="200" fixed="right">
    <template #default="scope">
      <el-button link type="primary" @click="handleView(scope.row)">查看</el-button>
      <el-button link type="primary" @click="handleEdit(scope.row)" v-if="scope.row.statusEnum === 0 || scope.row.statusEnum === 1">编辑</el-button>
      <el-button link type="primary" @click="handleStart(scope.row)" v-if="scope.row.statusEnum === 1">开始</el-button>
      <el-button link type="primary" @click="handleComplete(scope.row)" v-if="scope.row.statusEnum === 2">完成</el-button>
      <el-button link type="danger" @click="handleDelete(scope.row)" v-if="scope.row.statusEnum === 0 || scope.row.statusEnum === 1">删除</el-button>
    </template>
  </el-table-column>
</el-table>

修改后:

<!-- 添加 row-class-name 属性 -->
<el-table 
  v-loading="loading" 
  :data="surgeryList" 
  row-key="id"
  :row-class-name="getRowClassName"
>
  <!-- 申请日期datetime - 2025-09-19 14:15:00 - 不可操作 -->
  <el-table-column label="申请日期" align="center" prop="createTime" width="180">
    <template #default="scope">
      {{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}
    </template>
  </el-table-column>
  
  <!-- 手术单号string - OP2025092003 - 可查看详情 -->
  <el-table-column label="手术单号" align="center" prop="surgeryNo" width="150" show-overflow-tooltip />
  
  <!-- 患者姓名string - 张小明 - 不可操作 -->
  <el-table-column label="患者姓名" align="center" prop="patientName" width="100" />
  
  <!-- 申请医生string - 张医生 - 不可操作 -->
  <el-table-column label="申请医生" align="center" prop="applyDoctorName" width="100" />
  
  <!-- 申请科室string - 普外科 - 不可操作 -->
  <el-table-column label="申请科室" align="center" prop="applyDeptName" width="120" show-overflow-tooltip />
  
  <!-- 手术名称string - 腹腔镜胆囊切除术 - 不可操作 -->
  <el-table-column label="手术名称" align="center" prop="surgeryName" min-width="150" show-overflow-tooltip />
  
  <!-- 手术等级string - 三级手术 - 不可操作 -->
  <el-table-column label="手术等级" align="center" prop="surgeryLevel_dictText" width="100" />
  
  <!-- 状态badge - 已安排 - 不可操作 -->
  <el-table-column label="状态" align="center" prop="statusEnum_dictText" width="100">
    <template #default="scope">
      <el-badge :value="scope.row.statusEnum_dictText" :type="getStatusBadgeType(scope.row.statusEnum)" />
    </template>
  </el-table-column>
  
  <!-- 操作action - 查看/编辑/删除 - 可操作 -->
  <el-table-column label="操作" align="center" width="200" fixed="right">
    <template #default="scope">
      <!-- 查看显示手术申请详情只读模式 -->
      <el-button link type="primary" @click="handleView(scope.row)">查看</el-button>
      
      <!-- 编辑修改手术申请信息只有状态为新开的能修改 -->
      <el-button link type="primary" @click="handleEdit(scope.row)" v-if="scope.row.statusEnum === 0">编辑</el-button>
      
      <!-- 删除取消手术申请作废 -->
      <el-button link type="danger" @click="handleDelete(scope.row)" v-if="scope.row.statusEnum === 0 || scope.row.statusEnum === 1">删除</el-button>
    </template>
  </el-table-column>
</el-table>

二、操作按钮逻辑修正

修改 handleEdit 函数:

function handleEdit(row) {
  // 检查状态只有状态为新开0时才允许编辑
  if (row.statusEnum !== 0) {
    proxy.$modal.msgWarning('当前状态不允许编辑手术,仅新开状态可编辑')
    return
  }
  
  title.value = '编辑手术'
  open.value = true
  // 设置为编辑模式
  isEditMode.value = true
  
  getSurgeryDetail(row.id).then(res => {
    if (res.code === 200) {
      Object.assign(form.value, res.data)
    }
  }).catch(error => {
    console.error('获取手术信息失败:', error)
    proxy.$modal.msgError('获取手术信息失败')
  })
}

修改 handleDelete 函数:

function handleDelete(row) {
  // 检查状态
  if (row.statusEnum === 0) {
    // 新开状态 - 直接删除
    proxy.$modal.confirm('是否确认删除手术"' + row.surgeryName + '"?').then(() => {
      return deleteSurgery(row.id)
    }).then(() => {
      getPageList()
      proxy.$modal.msgSuccess('删除成功')
    }).catch(error => {
      console.error('删除手术失败:', error)
      proxy.$modal.msgError('删除失败')
    })
  } else if (row.statusEnum === 1) {
    // 已排期状态 - 更新为已取消
    proxy.$modal.confirm('是否确认取消手术"' + row.surgeryName + '"?').then(() => {
      return updateSurgeryStatus(row.id, 4) // 4 = 已取消
    }).then(() => {
      getPageList()
      proxy.$modal.msgSuccess('手术已取消')
    }).catch(error => {
      console.error('取消手术失败:', error)
      proxy.$modal.msgError('取消失败')
    })
  } else {
    // 其他状态 - 不允许操作
    proxy.$modal.msgWarning('当前状态不允许取消手术')
  }
}

添加 getRowClassName 函数:

// 获取表格行样式
function getRowClassName({ row }) {
  return row.statusEnum === 4 ? 'cancelled-row' : ''
}

修改 submitForm 函数:

function submitForm() {
  proxy.$refs['surgeryRef'].validate((valid) => {
    if (valid) {
      if (form.value.id == undefined) {
        // 新增手术
        addSurgery(form.value).then((res) => {
          proxy.$modal.msgSuccess('新增成功')
          open.value = false
          getPageList()
        }).catch(error => {
          console.error('新增手术失败:', error)
          // 显示红色 toast 提示
          proxy.$message.error('新增手术失败,请检查表单信息')
        })
      } else {
        // 修改手术
        updateSurgery(form.value).then((res) => {
          proxy.$modal.msgSuccess('修改成功')
          open.value = false
          getPageList()
        }).catch(error => {
          console.error('更新手术失败:', error)
          // 显示红色 toast 提示
          proxy.$message.error('更新手术失败,请检查表单信息')
        })
      }
    } else {
      // 表单校验失败 - 显示红色 toast 提示
      proxy.$message.error('请检查表单信息,标红字段为必填项')
    }
  })
}

修改 handleRefresh 函数:

function handleRefresh() {
  getPageList()
  proxy.$modal.msgSuccess('刷新成功')
}

移除不需要的函数:

// 删除这些函数(在新设计中不需要):
// - handleStart()
// - handleComplete()

三、表单字段调整(根据设计文档)

根据设计文档,表单应该包含:

1. 患者基本信息区:

<el-divider content-position="left">患者基本信息</el-divider>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="手术单号" prop="surgeryNo">
      <el-input v-model="form.surgeryNo" disabled placeholder="系统自动生成" />
    </el-form-item>
  </el-col>
  <el-col :span="12">
    <el-form-item label="患者姓名" prop="patientName">
      <el-input v-model="form.patientName" disabled placeholder="系统自动获取" />
    </el-form-item>
  </el-col>
</el-row>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="就诊卡号" prop="encounterNo">
      <el-input v-model="form.encounterNo" disabled placeholder="系统自动获取" />
    </el-form-item>
  </el-col>
  <el-col :span="12">
    <el-form-item label="性别" prop="patientGender">
      <el-select v-model="form.patientGender" disabled placeholder="系统自动获取">
        <el-option label="男" value="1" />
        <el-option label="女" value="2" />
        <el-option label="其他" value="9" />
      </el-select>
    </el-form-item>
  </el-col>
</el-row>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="年龄" prop="patientAge">
      <el-input-number v-model="form.patientAge" disabled placeholder="系统自动获取" />
    </el-form-item>
  </el-col>
</el-row>

2. 手术信息区:

<el-divider content-position="left">手术信息</el-divider>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="手术类型" prop="surgeryTypeEnum">
      <el-select v-model="form.surgeryTypeEnum" placeholder="请选择手术类型" style="width: 100%">
        <el-option label="门诊手术" :value="1" />
        <el-option label="日间手术" :value="2" />
        <el-option label="急诊手术" :value="3" />
      </el-select>
    </el-form-item>
  </el-col>
  <el-col :span="12">
    <el-form-item label="手术名称" prop="surgeryName">
      <!-- 带搜索的手术字典库 -->
      <el-input v-model="form.surgeryName" placeholder="请选择手术名称">
        <template #append>
          <el-button icon="Search" />
        </template>
      </el-input>
    </el-form-item>
  </el-col>
</el-row>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="拟实施手术日期" prop="plannedTime">
      <el-date-picker
        v-model="form.plannedTime"
        type="datetime"
        placeholder="选择日期时间"
        value-format="YYYY-MM-DD HH:mm:ss"
        style="width: 100%"
      />
    </el-form-item>
  </el-col>
</el-row>

3. 医疗信息区:

<el-divider content-position="left">医疗信息</el-divider>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="手术等级" prop="surgeryLevel">
      <el-select v-model="form.surgeryLevel" placeholder="请选择手术等级" style="width: 100%">
        <el-option label="一级手术" :value="1" />
        <el-option label="二级手术" :value="2" />
        <el-option label="三级手术" :value="3" />
        <el-option label="四级手术" :value="4" />
      </el-select>
    </el-form-item>
  </el-col>
  <el-col :span="12">
    <el-form-item label="切口类型" prop="incisionLevel">
      <el-select v-model="form.incisionLevel" placeholder="请选择切口类型" style="width: 100%">
        <el-option label="I类切口" :value="1" />
        <el-option label="II类切口" :value="2" />
        <el-option label="III类切口" :value="3" />
        <el-option label="IV类切口" :value="4" />
      </el-select>
    </el-form-item>
  </el-col>
</el-row>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="麻醉方式" prop="anesthesiaTypeEnum">
      <el-select v-model="form.anesthesiaTypeEnum" placeholder="请选择麻醉方式" style="width: 100%">
        <el-option label="局麻" :value="1" />
        <el-option label="全麻" :value="3" />
      </el-select>
    </el-form-item>
  </el-col>
</el-row>

4. 人员信息区:

<el-divider content-position="left">人员信息</el-divider>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="申请医生" prop="applyDoctorName">
      <el-input v-model="form.applyDoctorName" disabled placeholder="系统自动获取" />
    </el-form-item>
  </el-col>
  <el-col :span="12">
    <el-form-item label="主刀医生" prop="mainSurgeonId">
      <!-- 带搜索的医生字典库 -->
      <el-select v-model="form.mainSurgeonId" filterable placeholder="请选择主刀医生" style="width: 100%">
        <el-option
          v-for="item in doctorList"
          :key="item.id"
          :label="item.name"
          :value="item.id"
        />
      </el-select>
    </el-form-item>
  </el-col>
</el-row>

<el-row :gutter="20">
  <el-col :span="12">
    <el-form-item label="手术助手" prop="assistantId">
      <!-- 带搜索的医生字典库 -->
      <el-select v-model="form.assistantId" filterable clearable placeholder="请选择手术助手" style="width: 100%">
        <el-option
          v-for="item in doctorList"
          :key="item.id"
          :label="item.name"
          :value="item.id"
        />
      </el-select>
    </el-form-item>
  </el-col>
  <el-col :span="12">
    <el-form-item label="申请科室" prop="applyDeptName">
      <el-input v-model="form.applyDeptName" disabled placeholder="系统自动获取" />
    </el-form-item>
  </el-col>
</el-row>

5. 其他信息区:

<el-divider content-position="left">其他信息</el-divider>

<el-form-item label="术前诊断" prop="preoperativeDiagnosis">
  <el-input 
    v-model="form.preoperativeDiagnosis" 
    disabled 
    placeholder="自动获取门诊诊断的主要诊断名称" 
    type="textarea" 
    :rows="3" 
  />
</el-form-item>

<el-form-item label="手术指征" prop="surgeryIndication">
  <el-input 
    v-model="form.surgeryIndication" 
    placeholder="请输入手术指征" 
    type="textarea" 
    :rows="3" 
  />
</el-form-item>

6. 操作按钮区:

<el-row :gutter="20" justify="center">
  <el-col :span="24">
    <el-button type="default" @click="cancel" style="width: 120px">取消</el-button>
    <el-button type="primary" @click="submitForm" style="width: 120px">提交申请</el-button>
    <el-button type="success" icon="Plus" @click="addAppendSurgery">添加次要手术</el-button>
  </el-col>
</el-row>

四、样式添加

<style scoped lang="scss">
/* 顶部操作栏样式 */
.top-operation-bar {
  height: 60px;
  display: flex;
  align-items: center;
  margin-bottom: 16px;
}

.add-button {
  background-color: #5b8fb9;
  color: white;
  border-radius: 8px;
  padding: 0 20px;
  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(91, 143, 185, 0.3);
  }
}

.refresh-button {
  background-color: transparent;
  border: 1px solid #dcdfe6;
  color: #606266;
  border-radius: 8px;
  padding: 0 20px;
  &:hover {
    background-color: #f5f7fa;
  }
}

/* 表格样式 */
.surgery-table {
  width: 100%;
  
  ::v-deep(.el-badge__content) {
    background-color: #f0f2f5;
    border: 1px solid #e4e7ed;
    color: #606266;
    padding: 4px 12px;
    border-radius: 4px;
  }
}

/* 已取消状态的行样式 */
.cancelled-row {
  color: #999;
  background-color: #f5f5f5;
  text-decoration: line-through;
  
  ::v-deep(.cell) {
    opacity: 0.6;
  }
}

/* 对话框样式 */
.el-dialog {
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}

.dialog-footer {
  text-align: center;
  padding: 20px 0;
}
</style>

五、添加辅助函数

// 获取状态 badge 类型
function getStatusBadgeType(status) {
  const typeMap = {
    0: 'info',      // 新开
    1: 'warning',   // 已安排
    2: 'primary',   // 手术中
    3: 'success',   // 已完成
    4: 'danger',    // 已取消
    5: 'info'       // 暂停
  }
  return typeMap[status] || 'info'
}

// 添加次要手术
function addAppendSurgery() {
  // 打开次要手术选择弹窗
  proxy.$modal.msgInfo('请选择次要手术')
  // TODO: 实现次要手术选择逻辑
}

// 生成手术单号
function generateSurgeryNo() {
  const now = new Date()
  const year = now.getFullYear()
  const month = String(now.getMonth() + 1).padStart(2, '0')
  const day = String(now.getDate()).padStart(2, '0')
  const random = String(Math.floor(Math.random() * 10000)).padStart(4, '0')
  return `OP${year}${month}${day}${random}`
}

六、完整修正步骤总结

步骤1修改表格结构

  1. 调整表格列顺序和内容
  2. 添加 row-class-name 属性
  3. 修改操作列的条件判断

步骤2修改 JavaScript 函数

  1. 修改 handleEdit() - 添加状态检查
  2. 修改 handleDelete() - 区分删除和取消
  3. 修改 submitForm() - 改进错误提示
  4. 添加 getRowClassName() - 行样式判断
  5. 修改 handleRefresh() - 添加成功提示
  6. 移除 handleStart()handleComplete() - 新设计不需要

步骤3修改表单结构

  1. 调整表单分组(添加 divider
  2. 添加患者基本信息区(大部分字段禁用)
  3. 添加手术信息区
  4. 添加医疗信息区
  5. 添加人员信息区
  6. 添加其他信息区
  7. 修改操作按钮(添加次要手术按钮)

步骤4添加样式

  1. 顶部操作栏样式
  2. 表格样式
  3. 已取消状态行样式
  4. 对话框样式

步骤5添加辅助函数

  1. getStatusBadgeType() - 状态 badge 类型
  2. addAppendSurgery() - 添加次要手术
  3. generateSurgeryNo() - 生成手术单号

七、后端接口需求

根据设计文档,提交手术申请时需要:

  1. 插入 outp_surgery_apply门诊手术申请主表
  2. 通过系统自动插入一条手术申请医嘱
  3. 关联收费项目明细,系统自动插入预收费明细表

后端修改建议:

需要在后端实现一个事务性的接口:

@Transactional
public R<?> submitSurgeryApply(SurgeryApplyDto dto) {
    // 1. 插入门诊手术申请主表
    // 2. 自动生成手术单号OP+年月日+4位随机数
    // 3. 自动插入手术申请医嘱
    // 4. 关联收费项目明细
    // 5. 插入预收费明细表
    return R.ok();
}

八、测试要点

  1. 新增手术申请

    • 检查手术单号是否自动生成
    • 检查患者信息是否自动填充
    • 检查医生信息是否自动获取
  2. 编辑手术申请

    • 只允许新开状态编辑
    • 其他状态应提示不可编辑
  3. 删除/取消手术申请

    • 新开状态应直接删除
    • 已安排状态应更新为已取消
    • 取消后行样式应变灰
  4. 查看手术详情

    • 显示所有字段
    • 提交按钮变为关闭
  5. 错误处理

    • 表单校验失败显示红色 toast
    • 数据加载失败显示"数据加载失败"