feat(sprint11): 修复5个住院管理壳子页面 — 审核原有代码后升级完善
铁律9: 开发前审核原有代码,在已有基础上完善 - 手术管理(surgeryManage): 修正API URL→/surgery-page, 新增增删改弹窗+状态流转 - 医嘱管理(orderManage): 重构为左右布局(患者列表+医嘱), 接入advice-manage API - 入院诊断(inpatientDiagnosis): 新建InpatientDiagnosisController, 封装EncounterDiagnosis Service - 病案管理(medicalRecord): 接入inpatient-charge API, 增加费用概览+状态标签 - 费用清单(listFee): 重构为左右布局, 接入patient-prescription, 增加合计行 后端: 1个新Controller (InpatientDiagnosisController) 前端: 5个页面全部升级(1.6KB-3KB → 4.4KB-11.5KB) 编译: BUILD SUCCESS + 前端构建通过
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package com.healthlink.his.web.inhospitalmanage.controller;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import com.healthlink.his.administration.domain.EncounterDiagnosis;
|
||||
import com.healthlink.his.administration.service.IEncounterDiagnosisService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 入院诊断管理 Controller
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/inpatient-manage/diagnosis")
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class InpatientDiagnosisController {
|
||||
|
||||
private final IEncounterDiagnosisService encounterDiagnosisService;
|
||||
|
||||
@GetMapping(value = "/list")
|
||||
public R<List<EncounterDiagnosis>> getDiagnosisList(@RequestParam Long encounterId) {
|
||||
return R.ok(encounterDiagnosisService.getDiagnosisList(encounterId));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/add")
|
||||
public R<?> addDiagnosis(@RequestBody EncounterDiagnosis diagnosis) {
|
||||
boolean result = encounterDiagnosisService.save(diagnosis);
|
||||
return result ? R.ok("新增成功") : R.fail("新增失败");
|
||||
}
|
||||
|
||||
@PutMapping(value = "/update")
|
||||
public R<?> updateDiagnosis(@RequestBody EncounterDiagnosis diagnosis) {
|
||||
boolean result = encounterDiagnosisService.updateById(diagnosis);
|
||||
return result ? R.ok("修改成功") : R.fail("修改失败");
|
||||
}
|
||||
|
||||
@DeleteMapping(value = "/delete")
|
||||
public R<?> deleteDiagnosis(@RequestParam Long id) {
|
||||
boolean result = encounterDiagnosisService.removeById(id);
|
||||
return result ? R.ok("删除成功") : R.fail("删除失败");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,17 @@
|
||||
import request from '@/utils/request'
|
||||
export function getList(params) {
|
||||
return request({ url: '/clinical-manage/surgery/page', method: 'get', params })
|
||||
|
||||
export function getDiagnosisList(encounterId) {
|
||||
return request({ url: '/inpatient-manage/diagnosis/list', method: 'get', params: { encounterId } })
|
||||
}
|
||||
export function getDetail(id) {
|
||||
return request({ url: '/clinical-manage/surgery/' + id, method: 'get' })
|
||||
|
||||
export function addDiagnosis(data) {
|
||||
return request({ url: '/inpatient-manage/diagnosis/add', method: 'post', data })
|
||||
}
|
||||
|
||||
export function updateDiagnosis(data) {
|
||||
return request({ url: '/inpatient-manage/diagnosis/update', method: 'put', data })
|
||||
}
|
||||
|
||||
export function deleteDiagnosis(id) {
|
||||
return request({ url: '/inpatient-manage/diagnosis/delete', method: 'delete', params: { id } })
|
||||
}
|
||||
|
||||
@@ -1,38 +1,138 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card shadow="never">
|
||||
<template #header><span class="card-title">入院诊断</span></template>
|
||||
<el-form :inline="true" :model="queryParams">
|
||||
<el-form-item label="患者">
|
||||
<el-input v-model="queryParams.patientName" placeholder="患者姓名" clearable @keyup.enter="handleQuery" />
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">入院诊断</span>
|
||||
<el-button type="primary" icon="Plus" @click="handleAdd">新增诊断</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form :inline="true" :model="queryParams" label-width="80px">
|
||||
<el-form-item label="就诊ID">
|
||||
<el-input v-model="queryParams.encounterId" placeholder="就诊ID" clearable @keyup.enter="handleQuery" style="width: 160px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<vxe-table :data="tableData" border height="calc(100vh - 280px)">
|
||||
|
||||
<vxe-table :data="tableData" border height="calc(100vh - 300px)" v-loading="loading">
|
||||
<vxe-column type="seq" title="序号" width="60" />
|
||||
<vxe-column field="patientName" title="患者姓名" />
|
||||
<vxe-column field="medicalNo" title="住院号" />
|
||||
<vxe-column field="diagnosisName" title="诊断名称" />
|
||||
<vxe-column field="diagnosisCode" title="诊断编码" />
|
||||
<vxe-column field="doctorName" title="诊断医生" />
|
||||
<vxe-column field="diagnosisDate" title="诊断日期" />
|
||||
<vxe-column field="name" title="诊断名称" min-width="180" show-overflow />
|
||||
<vxe-column field="diagnosisDesc" title="诊断描述" min-width="200" show-overflow />
|
||||
<vxe-column field="classification" title="分类" width="100" />
|
||||
<vxe-column field="maindiseFlag" title="主诊断" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.maindiseFlag === 1" type="danger" size="small">主诊断</el-tag>
|
||||
<el-tag v-else type="info" size="small">次要</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="doctor" title="诊断医生" width="100" />
|
||||
<vxe-column field="diagnosisTime" title="诊断日期" width="120" />
|
||||
<vxe-column title="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link icon="Edit" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" link icon="Delete" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="formVisible" :title="formTitle" width="600px" append-to-body>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="诊断名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="诊断名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="诊断描述">
|
||||
<el-input v-model="form.diagnosisDesc" type="textarea" :rows="3" placeholder="诊断描述" />
|
||||
</el-form-item>
|
||||
<el-form-item label="分类">
|
||||
<el-select v-model="form.classification" placeholder="选择分类" clearable style="width: 100%">
|
||||
<el-option label="入院诊断" value="入院诊断" />
|
||||
<el-option label="出院诊断" value="出院诊断" />
|
||||
<el-option label="术前诊断" value="术前诊断" />
|
||||
<el-option label="术后诊断" value="术后诊断" />
|
||||
<el-option label="门诊诊断" value="门诊诊断" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="主诊断">
|
||||
<el-switch v-model="form.maindiseFlag" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="诊断医生">
|
||||
<el-input v-model="form.doctor" placeholder="诊断医生" />
|
||||
</el-form-item>
|
||||
<el-form-item label="诊断日期">
|
||||
<el-date-picker v-model="form.diagnosisTime" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="formVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { getList } from './components/api'
|
||||
const queryParams = ref({ patientName: '', pageNum: 1, pageSize: 20 })
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getDiagnosisList, addDiagnosis, updateDiagnosis, deleteDiagnosis } from './components/api'
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref([])
|
||||
const handleQuery = async () => {
|
||||
try {
|
||||
const res = await getList(queryParams.value)
|
||||
tableData.value = res.data?.records || res.data || []
|
||||
} catch (e) { tableData.value = [] }
|
||||
const queryParams = ref({ encounterId: '' })
|
||||
const formVisible = ref(false)
|
||||
const formTitle = ref('新增诊断')
|
||||
const isEdit = ref(false)
|
||||
const formRef = ref()
|
||||
|
||||
const form = ref({ id: null, encounterId: null, name: '', diagnosisDesc: '', classification: '', maindiseFlag: 0, doctor: '', diagnosisTime: '' })
|
||||
const rules = { name: [{ required: true, message: '请输入诊断名称', trigger: 'blur' }] }
|
||||
|
||||
function handleQuery() {
|
||||
if (!queryParams.value.encounterId) { ElMessage.warning('请输入就诊ID'); return }
|
||||
loading.value = true
|
||||
getDiagnosisList(queryParams.value.encounterId).then(res => {
|
||||
tableData.value = res.data || []
|
||||
}).finally(() => { loading.value = false })
|
||||
}
|
||||
onMounted(() => handleQuery())
|
||||
|
||||
function handleAdd() {
|
||||
isEdit.value = false; formTitle.value = '新增诊断'
|
||||
form.value = { id: null, encounterId: Number(queryParams.value.encounterId) || null, name: '', diagnosisDesc: '', classification: '', maindiseFlag: 0, doctor: '', diagnosisTime: '' }
|
||||
formVisible.value = true
|
||||
}
|
||||
|
||||
function handleEdit(row) {
|
||||
isEdit.value = true; formTitle.value = '编辑诊断'
|
||||
form.value = { ...row }
|
||||
formVisible.value = true
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
formRef.value.validate(valid => {
|
||||
if (!valid) return
|
||||
const action = isEdit.value ? updateDiagnosis(form.value) : addDiagnosis(form.value)
|
||||
action.then(res => {
|
||||
if (res.code === 200) { ElMessage.success(isEdit.value ? '修改成功' : '新增成功'); formVisible.value = false; handleQuery() }
|
||||
else ElMessage.error(res.msg || '操作失败')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function handleDelete(row) {
|
||||
ElMessageBox.confirm('确认删除该诊断?', '提示', { type: 'warning' }).then(() => {
|
||||
deleteDiagnosis(row.id).then(res => {
|
||||
if (res.code === 200) { ElMessage.success('删除成功'); handleQuery() }
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
onMounted(() => {})
|
||||
</script>
|
||||
<style scoped>.card-title { font-weight: bold; font-size: 16px; }</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-header { display: flex; justify-content: space-between; align-items: center; }
|
||||
.card-title { font-weight: bold; font-size: 16px; }
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
export function getList(params) {
|
||||
return request({ url: '/charge-manage/inpatient-charge/page', method: 'get', params })
|
||||
|
||||
export function getPatientPage(params) {
|
||||
return request({ url: '/charge-manage/inpatient-charge/encounter-patient-page', method: 'get', params })
|
||||
}
|
||||
export function getDetail(id) {
|
||||
return request({ url: '/charge-manage/inpatient-charge/' + id, method: 'get' })
|
||||
|
||||
export function getPatientPrescription(encounterId) {
|
||||
return request({ url: '/charge-manage/inpatient-charge/patient-prescription', method: 'get', params: { encounterId } })
|
||||
}
|
||||
|
||||
@@ -1,43 +1,98 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card shadow="never">
|
||||
<template #header><span class="card-title">费用清单</span></template>
|
||||
<el-form :inline="true" :model="queryParams">
|
||||
<el-form-item label="患者">
|
||||
<el-input v-model="queryParams.patientName" placeholder="患者姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<vxe-table :data="tableData" border height="calc(100vh - 280px)">
|
||||
<div class="list-fee-container">
|
||||
<!-- 左侧患者列表 -->
|
||||
<el-card class="patient-panel" shadow="never">
|
||||
<template #header>
|
||||
<span class="card-title">住院患者</span>
|
||||
</template>
|
||||
<el-input v-model="searchKey" placeholder="搜索患者(姓名/住院号)" clearable @keyup.enter="loadPatients" style="margin-bottom: 10px">
|
||||
<template #append><el-button icon="Search" @click="loadPatients" /></template>
|
||||
</el-input>
|
||||
<vxe-table :data="patientList" border height="calc(100vh - 260px)" :row-config="{ isCurrent: true }" @cell-click="handlePatientClick">
|
||||
<vxe-column field="patientName" title="姓名" width="80" />
|
||||
<vxe-column field="encounterNo" title="住院号" width="130" show-overflow />
|
||||
<vxe-column field="deptName" title="科室" width="100" show-overflow />
|
||||
<vxe-column field="bedNo" title="床号" width="50" />
|
||||
</vxe-table>
|
||||
<pagination v-show="patientTotal > 0" v-model:page="pageNo" v-model:limit="pageSize" :total="patientTotal" @pagination="loadPatients" />
|
||||
</el-card>
|
||||
|
||||
<!-- 右侧费用清单 -->
|
||||
<el-card class="fee-panel" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">费用清单</span>
|
||||
<span v-if="currentPatient" class="patient-tag">{{ currentPatient.patientName }} - {{ currentPatient.encounterNo }}</span>
|
||||
<span v-if="feeTotal > 0" class="fee-total">合计: ¥{{ feeTotal.toFixed(2) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<vxe-table :data="feeItems" border height="calc(100vh - 320px)" v-loading="feeLoading" show-footer :footer-data="footerData">
|
||||
<vxe-column type="seq" title="序号" width="60" />
|
||||
<vxe-column field="patientName" title="患者姓名" />
|
||||
<vxe-column field="medicalNo" title="住院号" />
|
||||
<vxe-column field="deptName" title="科室" />
|
||||
<vxe-column field="bedNo" title="床号" />
|
||||
<vxe-column field="admissionDate" title="入院日期" />
|
||||
<vxe-column title="操作" width="120">
|
||||
<vxe-column field="itemName" title="项目名称" min-width="180" show-overflow />
|
||||
<vxe-column field="itemType_dictText" title="类型" width="90" />
|
||||
<vxe-column field="specification" title="规格" width="100" show-overflow />
|
||||
<vxe-column field="quantity" title="数量" width="70" align="center" />
|
||||
<vxe-column field="unitPrice" title="单价" width="90" align="right">
|
||||
<template #default="{ row }">{{ row.unitPrice ? row.unitPrice.toFixed(2) : '-' }}</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="totalAmount" title="金额" width="100" align="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleDetail(row)">详情</el-button>
|
||||
<span :class="{ 'refund-amount': row.totalAmount < 0 }">{{ row.totalAmount ? '¥' + row.totalAmount.toFixed(2) : '-' }}</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="doctorName" title="开单医生" width="100" />
|
||||
<vxe-column field="enterTime" title="录入时间" width="150" />
|
||||
</vxe-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { getList } from './components/api'
|
||||
const queryParams = ref({ patientName: '', pageNum: 1, pageSize: 20 })
|
||||
const tableData = ref([])
|
||||
const handleQuery = async () => {
|
||||
try {
|
||||
const res = await getList(queryParams.value)
|
||||
tableData.value = res.data?.records || res.data || []
|
||||
} catch (e) { tableData.value = [] }
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { getPatientPage, getPatientPrescription } from './components/api'
|
||||
|
||||
const searchKey = ref('')
|
||||
const patientList = ref([])
|
||||
const patientTotal = ref(0)
|
||||
const pageNo = ref(1)
|
||||
const pageSize = ref(20)
|
||||
const currentPatient = ref(null)
|
||||
const feeItems = ref([])
|
||||
const feeLoading = ref(false)
|
||||
|
||||
const feeTotal = computed(() => feeItems.value.reduce((sum, item) => sum + (item.totalAmount || 0), 0))
|
||||
|
||||
const footerData = computed(() => {
|
||||
if (!feeItems.value.length) return []
|
||||
return [{ itemName: '合计', totalAmount: feeTotal.value }]
|
||||
})
|
||||
|
||||
function loadPatients() {
|
||||
getPatientPage({ searchKey: searchKey.value, pageNo: pageNo.value, pageSize: pageSize.value }).then(res => {
|
||||
patientList.value = res.data?.records || []
|
||||
patientTotal.value = res.data?.total || 0
|
||||
})
|
||||
}
|
||||
const handleDetail = (row) => { ElMessage.info('查看详情') }
|
||||
onMounted(() => handleQuery())
|
||||
|
||||
function handlePatientClick({ row }) {
|
||||
currentPatient.value = row
|
||||
feeLoading.value = true
|
||||
getPatientPrescription(row.encounterId).then(res => {
|
||||
feeItems.value = res.data || []
|
||||
}).finally(() => { feeLoading.value = false })
|
||||
}
|
||||
|
||||
onMounted(() => loadPatients())
|
||||
</script>
|
||||
<style scoped>.card-title { font-weight: bold; font-size: 16px; }</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list-fee-container { display: flex; height: calc(100vh - 84px); gap: 12px; padding: 12px; background: #f0f2f5; }
|
||||
.patient-panel { width: 460px; flex-shrink: 0; }
|
||||
.fee-panel { flex: 1; }
|
||||
.card-header { display: flex; justify-content: space-between; align-items: center; }
|
||||
.card-title { font-weight: bold; font-size: 15px; }
|
||||
.patient-tag { font-size: 13px; color: #409eff; font-weight: normal; }
|
||||
.fee-total { font-size: 14px; color: #f56c6c; font-weight: bold; }
|
||||
.refund-amount { color: #f56c6c; }
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
export function getList(params) {
|
||||
return request({ url: '/charge-manage/inpatient-charge/page', method: 'get', params })
|
||||
|
||||
export function getPatientPage(params) {
|
||||
return request({ url: '/charge-manage/inpatient-charge/encounter-patient-page', method: 'get', params })
|
||||
}
|
||||
export function getDetail(id) {
|
||||
return request({ url: '/charge-manage/inpatient-charge/' + id, method: 'get' })
|
||||
|
||||
export function getPatientPrescription(encounterId) {
|
||||
return request({ url: '/charge-manage/inpatient-charge/patient-prescription', method: 'get', params: { encounterId } })
|
||||
}
|
||||
|
||||
@@ -1,43 +1,123 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card shadow="never">
|
||||
<template #header><span class="card-title">病案管理</span></template>
|
||||
<el-form :inline="true" :model="queryParams">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">病案管理</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form :inline="true" :model="queryParams" label-width="80px">
|
||||
<el-form-item label="患者">
|
||||
<el-input v-model="queryParams.patientName" placeholder="患者姓名" clearable @keyup.enter="handleQuery" />
|
||||
<el-input v-model="queryParams.searchKey" placeholder="患者姓名/住院号" clearable @keyup.enter="handleQuery" style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="科室">
|
||||
<el-input v-model="queryParams.deptName" placeholder="科室" clearable style="width: 140px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<vxe-table :data="tableData" border height="calc(100vh - 280px)">
|
||||
|
||||
<vxe-table :data="tableData" border height="calc(100vh - 300px)" v-loading="loading">
|
||||
<vxe-column type="seq" title="序号" width="60" />
|
||||
<vxe-column field="patientName" title="患者姓名" />
|
||||
<vxe-column field="medicalNo" title="住院号" />
|
||||
<vxe-column field="deptName" title="科室" />
|
||||
<vxe-column field="bedNo" title="床号" />
|
||||
<vxe-column field="admissionDate" title="入院日期" />
|
||||
<vxe-column title="操作" width="120">
|
||||
<vxe-column field="patientName" title="患者姓名" width="100" />
|
||||
<vxe-column field="genderEnum_enumText" title="性别" width="60" />
|
||||
<vxe-column field="age" title="年龄" width="50" />
|
||||
<vxe-column field="encounterNo" title="住院号" width="140" show-overflow />
|
||||
<vxe-column field="deptName" title="科室" width="120" show-overflow />
|
||||
<vxe-column field="bedNo" title="床号" width="60" />
|
||||
<vxe-column field="admissionDate" title="入院日期" width="120" />
|
||||
<vxe-column field="dischargeDate" title="出院日期" width="120" />
|
||||
<vxe-column field="status" title="状态" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleDetail(row)">详情</el-button>
|
||||
<el-tag v-if="row.dischargeDate" type="info" size="small">已出院</el-tag>
|
||||
<el-tag v-else type="success" size="small">在院</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="操作" width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link icon="View" @click="handleDetail(row)">病案详情</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
|
||||
<pagination v-show="total > 0" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize" :total="total" @pagination="handleQuery" />
|
||||
</el-card>
|
||||
|
||||
<!-- 病案详情抽屉 -->
|
||||
<el-drawer v-model="detailVisible" title="病案详情" size="650px">
|
||||
<div v-if="detailData" class="detail-content">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="患者姓名">{{ detailData.patientName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="住院号">{{ detailData.encounterNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="科室">{{ detailData.deptName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="床号">{{ detailData.bedNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="入院日期">{{ detailData.admissionDate }}</el-descriptions-item>
|
||||
<el-descriptions-item label="出院日期">{{ detailData.dischargeDate || '在院' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<div class="section-title">费用概览</div>
|
||||
<vxe-table :data="prescriptionItems" border size="small" max-height="300">
|
||||
<vxe-column type="seq" title="序号" width="60" />
|
||||
<vxe-column field="itemName" title="项目名称" min-width="160" show-overflow />
|
||||
<vxe-column field="itemType_dictText" title="类型" width="90" />
|
||||
<vxe-column field="specification" title="规格" width="100" show-overflow />
|
||||
<vxe-column field="quantity" title="数量" width="70" />
|
||||
<vxe-column field="unitPrice" title="单价" width="90" align="right">
|
||||
<template #default="{ row }">{{ row.unitPrice ? row.unitPrice.toFixed(2) : '-' }}</template>
|
||||
</vxe-column>
|
||||
<vxe-column field="totalAmount" title="金额" width="90" align="right">
|
||||
<template #default="{ row }">
|
||||
<span :class="{ 'refund-amount': row.totalAmount < 0 }">{{ row.totalAmount ? row.totalAmount.toFixed(2) : '-' }}</span>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { getList } from './components/api'
|
||||
const queryParams = ref({ patientName: '', pageNum: 1, pageSize: 20 })
|
||||
import { getPatientPage, getPatientPrescription } from './components/api'
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref([])
|
||||
const handleQuery = async () => {
|
||||
try {
|
||||
const res = await getList(queryParams.value)
|
||||
tableData.value = res.data?.records || res.data || []
|
||||
} catch (e) { tableData.value = [] }
|
||||
const total = ref(0)
|
||||
const queryParams = ref({ searchKey: '', deptName: '', pageNo: 1, pageSize: 20 })
|
||||
const detailVisible = ref(false)
|
||||
const detailData = ref(null)
|
||||
const prescriptionItems = ref([])
|
||||
|
||||
function handleQuery() {
|
||||
loading.value = true
|
||||
getPatientPage(queryParams.value).then(res => {
|
||||
tableData.value = res.data?.records || []
|
||||
total.value = res.data?.total || 0
|
||||
}).finally(() => { loading.value = false })
|
||||
}
|
||||
const handleDetail = (row) => { ElMessage.info('查看详情') }
|
||||
|
||||
function resetQuery() {
|
||||
queryParams.value = { searchKey: '', deptName: '', pageNo: 1, pageSize: 20 }
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
function handleDetail(row) {
|
||||
detailData.value = row
|
||||
detailVisible.value = true
|
||||
getPatientPrescription(row.encounterId).then(res => {
|
||||
prescriptionItems.value = res.data || []
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => handleQuery())
|
||||
</script>
|
||||
<style scoped>.card-title { font-weight: bold; font-size: 16px; }</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-header { display: flex; justify-content: space-between; align-items: center; }
|
||||
.card-title { font-weight: bold; font-size: 16px; }
|
||||
.section-title { font-size: 14px; font-weight: bold; margin: 16px 0 8px; padding-left: 8px; border-left: 3px solid #409eff; }
|
||||
.refund-amount { color: #f56c6c; }
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
import request from '@/utils/request'
|
||||
export function getOrderList(params) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/page', method: 'get', params })
|
||||
|
||||
export function getPatientList(params) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/reg-patient-zk', method: 'get', params })
|
||||
}
|
||||
export function getOrderDetail(id) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/' + id, method: 'get' })
|
||||
|
||||
export function getAdviceBaseInfo(encounterId) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/reg-request-base-info', method: 'get', params: { encounterId } })
|
||||
}
|
||||
export function cancelOrder(id) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/cancel/' + id, method: 'put' })
|
||||
|
||||
export function getAdviceHistoryInfo(patientId, encounterId) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/reg-request-history-info', method: 'get', params: { patientId, encounterId } })
|
||||
}
|
||||
|
||||
export function saveAdvice(data) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/save-reg-advice', method: 'post', data })
|
||||
}
|
||||
|
||||
export function signAdvice(data) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/sign-reg-advice', method: 'post', data })
|
||||
}
|
||||
|
||||
export function stopAdvice(data) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/stop-reg-advice', method: 'post', data })
|
||||
}
|
||||
|
||||
export function cancelStopAdvice(data) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/cancel-stop-reg-advice', method: 'post', data })
|
||||
}
|
||||
|
||||
export function signOffAdvice(data) {
|
||||
return request({ url: '/reg-doctorstation/advice-manage/sign-off-reg', method: 'post', data })
|
||||
}
|
||||
|
||||
@@ -1,65 +1,137 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card shadow="never">
|
||||
<template #header><span class="card-title">医嘱管理</span></template>
|
||||
<el-form :inline="true" :model="queryParams">
|
||||
<el-form-item label="患者">
|
||||
<el-input v-model="queryParams.patientName" placeholder="患者姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="医嘱状态">
|
||||
<el-select v-model="queryParams.status" placeholder="全部" clearable>
|
||||
<el-option label="执行中" value="0" />
|
||||
<el-option label="已停止" value="1" />
|
||||
<el-option label="已完成" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<vxe-table :data="tableData" border height="calc(100vh - 280px)">
|
||||
<div class="order-manage-container">
|
||||
<!-- 左侧患者列表 -->
|
||||
<el-card class="patient-panel" shadow="never">
|
||||
<template #header>
|
||||
<span class="card-title">住院患者</span>
|
||||
</template>
|
||||
<el-input v-model="searchKey" placeholder="搜索患者(姓名/住院号)" clearable @keyup.enter="loadPatients" style="margin-bottom: 10px">
|
||||
<template #append><el-button icon="Search" @click="loadPatients" /></template>
|
||||
</el-input>
|
||||
<vxe-table :data="patientList" border height="calc(100vh - 260px)" :row-config="{ isCurrent: true }" @cell-click="handlePatientClick">
|
||||
<vxe-column field="patientName" title="姓名" width="80" />
|
||||
<vxe-column field="genderEnum_enumText" title="性别" width="50" />
|
||||
<vxe-column field="age" title="年龄" width="50" />
|
||||
<vxe-column field="encounterNo" title="住院号" width="130" show-overflow />
|
||||
<vxe-column field="deptName" title="科室" width="100" show-overflow />
|
||||
<vxe-column field="bedNo" title="床号" width="60" />
|
||||
</vxe-table>
|
||||
</el-card>
|
||||
|
||||
<!-- 右侧医嘱内容 -->
|
||||
<el-card class="advice-panel" shadow="never">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">医嘱列表</span>
|
||||
<span v-if="currentPatient" class="patient-tag">{{ currentPatient.patientName }} - {{ currentPatient.encounterNo }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
|
||||
<el-tab-pane label="当前医嘱" name="current" />
|
||||
<el-tab-pane label="历史医嘱" name="history" />
|
||||
</el-tabs>
|
||||
|
||||
<vxe-table :data="adviceList" border height="calc(100vh - 360px)" v-loading="adviceLoading">
|
||||
<vxe-column type="seq" title="序号" width="60" />
|
||||
<vxe-column field="patientName" title="患者姓名" />
|
||||
<vxe-column field="medicalNo" title="住院号" />
|
||||
<vxe-column field="adviceContent" title="医嘱内容" show-overflow-tooltip />
|
||||
<vxe-column field="doctorName" title="开嘱医生" />
|
||||
<vxe-column field="startTime" title="开始时间" />
|
||||
<vxe-column field="status" title="状态">
|
||||
<vxe-column field="adviceContent" title="医嘱内容" min-width="200" show-overflow />
|
||||
<vxe-column field="adviceType_dictText" title="类型" width="90" />
|
||||
<vxe-column field="frequency" title="频次" width="80" />
|
||||
<vxe-column field="dosage" title="剂量" width="80" />
|
||||
<vxe-column field="route" title="途径" width="80" />
|
||||
<vxe-column field="doctorName" title="开嘱医生" width="100" />
|
||||
<vxe-column field="startTime" title="开始时间" width="150" />
|
||||
<vxe-column field="adviceStatus_dictText" title="状态" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === '0' ? 'success' : row.status === '1' ? 'info' : 'warning'">
|
||||
{{ row.status === '0' ? '执行中' : row.status === '1' ? '已停止' : '已完成' }}
|
||||
</el-tag>
|
||||
<el-tag :type="adviceStatusType(row.adviceStatus)" size="small">{{ row.adviceStatus_dictText || '未知' }}</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="操作" width="120">
|
||||
<vxe-column v-if="activeTab === 'current'" title="操作" width="180" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleDetail(row)">详情</el-button>
|
||||
<el-button v-if="row.status === '0'" type="danger" link @click="handleCancel(row)">停止</el-button>
|
||||
<el-button v-if="row.adviceStatus === '0'" type="warning" link @click="handleStop(row)">停止</el-button>
|
||||
<el-button v-if="row.adviceStatus === '1'" type="success" link @click="handleCancelStop(row)">恢复</el-button>
|
||||
<el-button v-if="row.adviceStatus === '2'" type="info" link @click="handleSignOff(row)">签退</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getOrderList, cancelOrder } from './components/api'
|
||||
const queryParams = ref({ patientName: '', status: '', pageNum: 1, pageSize: 20 })
|
||||
const tableData = ref([])
|
||||
const handleQuery = async () => {
|
||||
try {
|
||||
const res = await getOrderList(queryParams.value)
|
||||
tableData.value = res.data?.records || res.data || []
|
||||
} catch (e) { tableData.value = [] }
|
||||
import { getPatientList, getAdviceBaseInfo, getAdviceHistoryInfo, stopAdvice, cancelStopAdvice, signOffAdvice } from './components/api'
|
||||
|
||||
const searchKey = ref('')
|
||||
const patientList = ref([])
|
||||
const currentPatient = ref(null)
|
||||
const adviceList = ref([])
|
||||
const adviceLoading = ref(false)
|
||||
const activeTab = ref('current')
|
||||
|
||||
const adviceStatusType = (s) => ({ '0': 'success', '1': 'warning', '2': 'info', '3': 'danger' }[s] || 'info')
|
||||
|
||||
function loadPatients() {
|
||||
getPatientList({ searchKey: searchKey.value, pageNo: 1, pageSize: 50 }).then(res => {
|
||||
patientList.value = res.data?.records || res.data || []
|
||||
})
|
||||
}
|
||||
const handleDetail = (row) => { ElMessage.info('查看详情: ' + row.adviceContent) }
|
||||
const handleCancel = async (row) => {
|
||||
await ElMessageBox.confirm('确认停止该医嘱?', '提示', { type: 'warning' })
|
||||
await cancelOrder(row.id)
|
||||
ElMessage.success('医嘱已停止')
|
||||
handleQuery()
|
||||
|
||||
function handlePatientClick({ row }) {
|
||||
currentPatient.value = row
|
||||
activeTab.value = 'current'
|
||||
loadAdvice()
|
||||
}
|
||||
onMounted(() => handleQuery())
|
||||
|
||||
function handleTabChange() {
|
||||
loadAdvice()
|
||||
}
|
||||
|
||||
function loadAdvice() {
|
||||
if (!currentPatient.value) return
|
||||
adviceLoading.value = true
|
||||
const action = activeTab.value === 'history'
|
||||
? getAdviceHistoryInfo(currentPatient.value.patientId, currentPatient.value.encounterId)
|
||||
: getAdviceBaseInfo(currentPatient.value.encounterId)
|
||||
action.then(res => {
|
||||
adviceList.value = res.data || []
|
||||
}).finally(() => { adviceLoading.value = false })
|
||||
}
|
||||
|
||||
function handleStop(row) {
|
||||
ElMessageBox.confirm('确认停止该医嘱?', '提示', { type: 'warning' }).then(() => {
|
||||
stopAdvice([{ adviceId: row.adviceId }]).then(res => {
|
||||
if (res.code === 200) { ElMessage.success('医嘱已停止'); loadAdvice() }
|
||||
else ElMessage.error(res.msg || '操作失败')
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
function handleCancelStop(row) {
|
||||
ElMessageBox.confirm('确认恢复该医嘱?', '提示', { type: 'info' }).then(() => {
|
||||
cancelStopAdvice([{ adviceId: row.adviceId }]).then(res => {
|
||||
if (res.code === 200) { ElMessage.success('医嘱已恢复'); loadAdvice() }
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
function handleSignOff(row) {
|
||||
ElMessageBox.confirm('确认签退该医嘱?', '提示', { type: 'warning' }).then(() => {
|
||||
signOffAdvice([{ adviceId: row.adviceId }]).then(res => {
|
||||
if (res.code === 200) { ElMessage.success('医嘱已签退'); loadAdvice() }
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
onMounted(() => loadPatients())
|
||||
</script>
|
||||
<style scoped>.card-title { font-weight: bold; font-size: 16px; }</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.order-manage-container { display: flex; height: calc(100vh - 84px); gap: 12px; padding: 12px; background: #f0f2f5; }
|
||||
.patient-panel { width: 480px; flex-shrink: 0; }
|
||||
.advice-panel { flex: 1; }
|
||||
.card-header { display: flex; justify-content: space-between; align-items: center; }
|
||||
.card-title { font-weight: bold; font-size: 15px; }
|
||||
.patient-tag { font-size: 13px; color: #409eff; font-weight: normal; }
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,29 @@
|
||||
import request from '@/utils/request'
|
||||
export function getList(params) {
|
||||
return request({ url: '/clinical-manage/surgery/page', method: 'get', params })
|
||||
|
||||
export function getSurgeryPage(params) {
|
||||
return request({ url: '/clinical-manage/surgery/surgery-page', method: 'get', params })
|
||||
}
|
||||
export function getDetail(id) {
|
||||
return request({ url: '/clinical-manage/surgery/' + id, method: 'get' })
|
||||
|
||||
export function getSurgeryDetail(id) {
|
||||
return request({ url: '/clinical-manage/surgery/surgery-detail', method: 'get', params: { id } })
|
||||
}
|
||||
export function add(data) {
|
||||
return request({ url: '/clinical-manage/surgery', method: 'post', data })
|
||||
|
||||
export function addSurgery(data) {
|
||||
return request({ url: '/clinical-manage/surgery/surgery', method: 'post', data })
|
||||
}
|
||||
export function update(data) {
|
||||
return request({ url: '/clinical-manage/surgery', method: 'put', data })
|
||||
|
||||
export function updateSurgery(data) {
|
||||
return request({ url: '/clinical-manage/surgery/surgery', method: 'put', data })
|
||||
}
|
||||
|
||||
export function deleteSurgery(id) {
|
||||
return request({ url: '/clinical-manage/surgery/surgery', method: 'delete', params: { id } })
|
||||
}
|
||||
|
||||
export function updateSurgeryStatus(id, statusEnum) {
|
||||
return request({ url: '/clinical-manage/surgery/surgery-status', method: 'put', params: { id, statusEnum } })
|
||||
}
|
||||
|
||||
export function getEncounterList(patientId) {
|
||||
return request({ url: '/clinical-manage/surgery/encounter-list', method: 'get', params: { patientId } })
|
||||
}
|
||||
|
||||
@@ -1,57 +1,260 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-card shadow="never">
|
||||
<template #header><span class="card-title">手术管理</span></template>
|
||||
<el-form :inline="true" :model="queryParams">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">手术管理</span>
|
||||
<el-button type="primary" icon="Plus" @click="handleAdd">新增手术</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-form :inline="true" :model="queryParams" label-width="80px">
|
||||
<el-form-item label="患者">
|
||||
<el-input v-model="queryParams.patientName" placeholder="患者姓名" clearable @keyup.enter="handleQuery" />
|
||||
<el-input v-model="queryParams.patientName" placeholder="患者姓名" clearable @keyup.enter="handleQuery" style="width: 160px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手术状态">
|
||||
<el-select v-model="queryParams.status" placeholder="全部" clearable>
|
||||
<el-option label="待手术" value="0" />
|
||||
<el-option label="手术中" value="1" />
|
||||
<el-option label="已完成" value="2" />
|
||||
<el-select v-model="queryParams.statusEnum" placeholder="全部" clearable style="width: 120px">
|
||||
<el-option label="待手术" :value="0" />
|
||||
<el-option label="手术中" :value="1" />
|
||||
<el-option label="已完成" :value="2" />
|
||||
<el-option label="已取消" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="手术日期">
|
||||
<el-date-picker v-model="dateRange" type="daterange" start-placeholder="开始" end-placeholder="结束" value-format="YYYY-MM-DD" style="width: 240px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<vxe-table :data="tableData" border height="calc(100vh - 280px)">
|
||||
|
||||
<vxe-table ref="tableRef" :data="tableData" border height="calc(100vh - 320px)" v-loading="loading">
|
||||
<vxe-column type="seq" title="序号" width="60" />
|
||||
<vxe-column field="patientName" title="患者姓名" />
|
||||
<vxe-column field="medicalNo" title="住院号" />
|
||||
<vxe-column field="surgeryName" title="手术名称" />
|
||||
<vxe-column field="surgeonName" title="手术医生" />
|
||||
<vxe-column field="surgeryDate" title="手术日期" />
|
||||
<vxe-column field="status" title="状态">
|
||||
<vxe-column field="patientName" title="患者姓名" width="100" />
|
||||
<vxe-column field="encounterNo" title="住院号" width="140" />
|
||||
<vxe-column field="surgeryName" title="手术名称" min-width="180" show-overflow />
|
||||
<vxe-column field="surgeonName" title="手术医生" width="100" />
|
||||
<vxe-column field="anesthesiologistName" title="麻醉医生" width="100" />
|
||||
<vxe-column field="plannedTime" title="计划时间" width="160" />
|
||||
<vxe-column field="statusEnum" title="状态" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === '0' ? 'warning' : row.status === '1' ? 'danger' : 'success'">
|
||||
{{ row.status === '0' ? '待手术' : row.status === '1' ? '手术中' : '已完成' }}
|
||||
</el-tag>
|
||||
<el-tag :type="statusTagType(row.statusEnum)" size="small">{{ statusText(row.statusEnum) }}</el-tag>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column title="操作" width="120">
|
||||
<vxe-column title="操作" width="200" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" link @click="handleDetail(row)">详情</el-button>
|
||||
<el-button type="primary" link icon="View" @click="handleDetail(row)">详情</el-button>
|
||||
<el-button type="warning" link icon="Edit" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button v-if="row.statusEnum === 0" type="success" link icon="Check" @click="handleStart(row)">开始</el-button>
|
||||
<el-button v-if="row.statusEnum === 1" type="info" link icon="CircleCheck" @click="handleComplete(row)">完成</el-button>
|
||||
<el-button v-if="row.statusEnum === 0" type="danger" link icon="Delete" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</vxe-column>
|
||||
</vxe-table>
|
||||
|
||||
<pagination v-show="total > 0" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList" />
|
||||
</el-card>
|
||||
|
||||
<!-- 新增/编辑弹窗 -->
|
||||
<el-dialog v-model="formVisible" :title="formTitle" width="700px" append-to-body>
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="患者姓名" prop="patientName">
|
||||
<el-input v-model="form.patientName" placeholder="患者姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="住院号" prop="encounterNo">
|
||||
<el-input v-model="form.encounterNo" placeholder="住院号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="手术名称" prop="surgeryName">
|
||||
<el-input v-model="form.surgeryName" placeholder="手术名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="手术医生" prop="surgeonName">
|
||||
<el-input v-model="form.surgeonName" placeholder="手术医生" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="麻醉医生" prop="anesthesiologistName">
|
||||
<el-input v-model="form.anesthesiologistName" placeholder="麻醉医生" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<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-col :span="12">
|
||||
<el-form-item label="手术等级">
|
||||
<el-select v-model="form.surgeryLevel" placeholder="选择等级" clearable 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-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="手术备注">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="3" placeholder="手术备注信息" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="formVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 详情抽屉 -->
|
||||
<el-drawer v-model="detailVisible" title="手术详情" size="600px">
|
||||
<el-descriptions :column="2" border v-if="detailData">
|
||||
<el-descriptions-item label="患者姓名">{{ detailData.patientName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="住院号">{{ detailData.encounterNo }}</el-descriptions-item>
|
||||
<el-descriptions-item label="手术名称" :span="2">{{ detailData.surgeryName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="手术医生">{{ detailData.surgeonName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="麻醉医生">{{ detailData.anesthesiologistName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="计划时间" :span="2">{{ detailData.plannedTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="手术等级">{{ detailData.surgeryLevel }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="statusTagType(detailData.statusEnum)" size="small">{{ statusText(detailData.statusEnum) }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">{{ detailData.remark || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { getList } from './components/api'
|
||||
const queryParams = ref({ patientName: '', status: '', pageNum: 1, pageSize: 20 })
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getSurgeryPage, getSurgeryDetail, addSurgery, updateSurgery, deleteSurgery, updateSurgeryStatus } from './components/api'
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref([])
|
||||
const handleQuery = async () => {
|
||||
try {
|
||||
const res = await getList(queryParams.value)
|
||||
tableData.value = res.data?.records || res.data || []
|
||||
} catch (e) { tableData.value = [] }
|
||||
const total = ref(0)
|
||||
const dateRange = ref([])
|
||||
const tableRef = ref()
|
||||
const formRef = ref()
|
||||
|
||||
const queryParams = ref({ patientName: '', statusEnum: undefined, pageNo: 1, pageSize: 20 })
|
||||
|
||||
const formVisible = ref(false)
|
||||
const formTitle = ref('新增手术')
|
||||
const detailVisible = ref(false)
|
||||
const detailData = ref(null)
|
||||
const isEdit = ref(false)
|
||||
|
||||
const form = ref({ id: null, patientName: '', encounterNo: '', surgeryName: '', surgeonName: '', anesthesiologistName: '', plannedTime: '', surgeryLevel: '', remark: '' })
|
||||
|
||||
const rules = {
|
||||
patientName: [{ required: true, message: '请输入患者姓名', trigger: 'blur' }],
|
||||
surgeryName: [{ required: true, message: '请输入手术名称', trigger: 'blur' }],
|
||||
surgeonName: [{ required: true, message: '请输入手术医生', trigger: 'blur' }],
|
||||
}
|
||||
const handleDetail = (row) => { ElMessage.info('手术详情: ' + row.surgeryName) }
|
||||
onMounted(() => handleQuery())
|
||||
|
||||
const statusText = (s) => ({ 0: '待手术', 1: '手术中', 2: '已完成', 3: '已取消' }[s] || '未知')
|
||||
const statusTagType = (s) => ({ 0: 'warning', 1: 'danger', 2: 'success', 3: 'info' }[s] || 'info')
|
||||
|
||||
function getList() {
|
||||
const params = { ...queryParams.value }
|
||||
if (dateRange.value && dateRange.value.length === 2) {
|
||||
params.createTimeStart = dateRange.value[0] + ' 00:00:00'
|
||||
params.createTimeEnd = dateRange.value[1] + ' 23:59:59'
|
||||
}
|
||||
loading.value = true
|
||||
getSurgeryPage(params).then(res => {
|
||||
tableData.value = res.data?.records || []
|
||||
total.value = res.data?.total || 0
|
||||
}).finally(() => { loading.value = false })
|
||||
}
|
||||
|
||||
function handleQuery() { queryParams.value.pageNo = 1; getList() }
|
||||
function resetQuery() { queryParams.value = { patientName: '', statusEnum: undefined, pageNo: 1, pageSize: 20 }; dateRange.value = []; getList() }
|
||||
|
||||
function handleAdd() {
|
||||
isEdit.value = false
|
||||
formTitle.value = '新增手术'
|
||||
form.value = { id: null, patientName: '', encounterNo: '', surgeryName: '', surgeonName: '', anesthesiologistName: '', plannedTime: '', surgeryLevel: '', remark: '' }
|
||||
formVisible.value = true
|
||||
}
|
||||
|
||||
function handleEdit(row) {
|
||||
isEdit.value = true
|
||||
formTitle.value = '编辑手术'
|
||||
getSurgeryDetail(row.id).then(res => {
|
||||
form.value = { ...res.data }
|
||||
formVisible.value = true
|
||||
})
|
||||
}
|
||||
|
||||
function handleDetail(row) {
|
||||
getSurgeryDetail(row.id).then(res => {
|
||||
detailData.value = res.data
|
||||
detailVisible.value = true
|
||||
})
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
formRef.value.validate(valid => {
|
||||
if (!valid) return
|
||||
const action = isEdit.value ? updateSurgery(form.value) : addSurgery(form.value)
|
||||
action.then(res => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(isEdit.value ? '修改成功' : '新增成功')
|
||||
formVisible.value = false
|
||||
getList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '操作失败')
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function handleDelete(row) {
|
||||
ElMessageBox.confirm('确认删除该手术记录?', '提示', { type: 'warning' }).then(() => {
|
||||
deleteSurgery(row.id).then(res => {
|
||||
if (res.code === 200) { ElMessage.success('删除成功'); getList() }
|
||||
else ElMessage.error(res.msg || '删除失败')
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
function handleStart(row) {
|
||||
ElMessageBox.confirm('确认开始该手术?', '提示', { type: 'info' }).then(() => {
|
||||
updateSurgeryStatus(row.id, 1).then(res => {
|
||||
if (res.code === 200) { ElMessage.success('手术已开始'); getList() }
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
function handleComplete(row) {
|
||||
ElMessageBox.confirm('确认完成该手术?', '提示', { type: 'success' }).then(() => {
|
||||
updateSurgeryStatus(row.id, 2).then(res => {
|
||||
if (res.code === 200) { ElMessage.success('手术已完成'); getList() }
|
||||
})
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
onMounted(() => getList())
|
||||
</script>
|
||||
<style scoped>.card-title { font-weight: bold; font-size: 16px; }</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-header { display: flex; justify-content: space-between; align-items: center; }
|
||||
.card-title { font-weight: bold; font-size: 16px; }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user