feat(login): 添加租户名称获取功能并优化前端布局

- 在登录控制器中注入租户服务并获取租户名称信息
- 添加租户名称到登录响应结果中
- 更新样式变量定义侧边栏宽度和Logo高度
- 重构公告面板组件统一公告通知显示逻辑
- 简化公告类型图标和样式映射关系
- 更新侧边栏为垂直菜单布局并添加折叠功能
- 优化Logo组件显示租户名称和系统标题
- 调整导航栏布局结构和响应式样式
- 重构主应用容器样式和标签页显示逻辑
This commit is contained in:
2025-12-31 10:28:52 +08:00
parent 10e738edd9
commit 4d4828ea71
54 changed files with 3510 additions and 754 deletions

View File

@@ -1,287 +1,154 @@
<template>
<div class="container">
<div class="awaitingBtn">
<el-button @click="awaitingMedicineBtn">
效期预警
<span>{{ total }}</span>
</el-button>
<!-- <el-select v-model="selectValue" @change="handelChange" @keyup.enter="handelEnter">
<el-option label="测试1" value="1"/>
<el-option label="测试2" value="2 "/>
</el-select> -->
<!-- 首页内容为空只显示欢迎信息 -->
<div class="welcome-content">
<div class="welcome-card">
<h1 class="welcome-title">欢迎使用</h1>
<p class="welcome-subtitle">医院管理系统</p>
<div class="quick-actions">
<div class="action-item" @click="handleExpiryWarning">
<el-icon :size="32" color="#e6a23c">
<Warning />
</el-icon>
<span>效期预警</span>
</div>
</div>
</div>
</div>
<!-- <div class="logo">
<img src="/src/assets/images/jlau.jpg" />
</div> -->
</div>
</template>
<script setup name="Index">
import {getproductReturnPage} from './medicationmanagement/statisticalManagement/statisticalManagent';
import {useStore} from '@/store/store';
import {Warning} from '@element-plus/icons-vue';
import {useRouter} from 'vue-router';
const store = useStore();
const router = useRouter();
const version = ref('3.8.7');
const total = ref(0);
const selectValue = ref('');
function awaitingMedicineBtn() {
store.setRemainingDays(180);
console.log(store.remainingDays);
function handleExpiryWarning() {
store.setRemainingDays(180);
router.push({
path: '/medicationmanagement/statisticalManagement/statisticalManagement',
});
}
function goTarget(url) {
window.open(url, '__blank');
}
function handelEnter() {
console.log('enter');
}
// function handelChange(val) {
// console.log(val);
// }
function getExpirationWarningCount() {
getproductReturnPage({ pageNo: 1, pageSize: 10, remainingDays: 180 }).then((res) => {
total.value = res.data.total || 0;
});
}
getExpirationWarningCount();
</script>
<style scoped lang="scss">
.dashboard-container {
.container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.welcome-content {
width: 100%;
max-width: 1200px;
padding: 40px 20px;
display: flex;
justify-content: center;
align-items: center;
}
.welcome-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 16px;
padding: 60px 80px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
text-align: center;
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.welcome-title {
font-size: 42px;
font-weight: 600;
color: #303133;
margin: 0 0 20px 0;
letter-spacing: 2px;
}
.welcome-subtitle {
font-size: 24px;
color: #909399;
margin: 0 0 50px 0;
font-weight: 300;
}
.quick-actions {
display: flex;
justify-content: center;
gap: 30px;
margin-top: 40px;
}
.action-item {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f7fa;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
padding: 0;
}
.awaitingBtn {
.el-button {
border: 1px #166773 solid;
span {
color: red;
margin-left: 5px;
}
}
.el-button:hover {
border: 1px #166773 solid;
color: #166773;
span {
color: red;
margin-left: 5px;
}
}
position: absolute;
top: 20px;
left: 20px;
}
.section-title {
font-size: 24px;
margin-bottom: 20px;
color: #333;
font-weight: 600;
}
.card {
background-color: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
}
.card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
.card-title {
font-size: 14px;
color: #606266;
margin-bottom: 12px;
}
.card-value {
font-size: 32px;
font-weight: 600;
color: #303133;
margin-bottom: 8px;
}
.card-stats {
display: flex;
align-items: center;
font-size: 12px;
color: #67c23a;
}
.card-stats.down {
color: #f56c6c;
}
.stats-icon {
margin-right: 4px;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.chart-container {
background-color: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
margin-bottom: 30px;
height: 300px;
canvas {
width: 100% !important;
height: 100% !important;
}
}
.bottom-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 30px;
}
.notification-container,
.todo-container {
background-color: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.notification-title,
.todo-title {
font-size: 18px;
font-weight: 600;
color: #303133;
margin-bottom: 16px;
}
.notification-list {
list-style: none;
padding: 0;
margin: 0;
}
.notification-item {
padding: 12px 0;
border-bottom: 1px solid #ebeef5;
&:last-child {
border-bottom: none;
}
}
.todo-list {
list-style: none;
padding: 0;
margin: 0;
margin-bottom: 20px;
}
.todo-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #ebeef5;
&:last-child {
border-bottom: none;
}
}
.todo-count {
color: #606266;
font-size: 14px;
}
.table-container {
background-color: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ebeef5;
}
th {
background-color: #f5f7fa;
font-weight: 600;
color: #303133;
}
tr:last-child td {
border-bottom: none;
}
.btn {
padding: 6px 12px;
border-radius: 4px;
font-size: 14px;
padding: 30px;
background: #fff;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
border: none;
outline: none;
}
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
min-width: 160px;
.btn-primary {
background-color: #1890ff;
color: #fff;
}
&:hover {
transform: translateY(-5px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
.btn-primary:hover {
background-color: #40a9ff;
}
span {
color: #409eff;
}
}
.btn-outline {
background-color: transparent;
border: 1px solid #dcdfe6;
color: #606266;
}
.btn-outline:hover {
border-color: #c6e2ff;
color: #40a9ff;
background-color: #ecf5ff;
span {
margin-top: 12px;
font-size: 16px;
color: #303133;
font-weight: 500;
transition: color 0.3s;
}
}
@media (max-width: 768px) {
.bottom-content {
grid-template-columns: 1fr;
.welcome-card {
padding: 40px 30px;
margin: 20px;
}
.dashboard-grid {
grid-template-columns: 1fr;
.welcome-title {
font-size: 32px;
}
.welcome-subtitle {
font-size: 20px;
}
.quick-actions {
flex-direction: column;
gap: 15px;
margin-top: 30px;
}
.action-item {
min-width: 100%;
padding: 20px;
}
}
</style>
</style>

View File

@@ -0,0 +1,759 @@
<template>
<div class="app-container">
<!-- 查询表单 -->
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" class="query-form">
<el-form-item label="手术编号" prop="surgeryNo">
<el-input
v-model="queryParams.surgeryNo"
placeholder="请输入手术编号"
clearable
@keyup.enter="handleQuery"
style="width: 200px"
/>
</el-form-item>
<el-form-item label="手术名称" prop="surgeryName">
<el-input
v-model="queryParams.surgeryName"
placeholder="请输入手术名称"
clearable
@keyup.enter="handleQuery"
style="width: 200px"
/>
</el-form-item>
<el-form-item label="患者姓名" prop="patientName">
<el-input
v-model="queryParams.patientName"
placeholder="请输入患者姓名"
clearable
@keyup.enter="handleQuery"
style="width: 200px"
/>
</el-form-item>
<el-form-item label="手术状态" prop="statusEnum">
<el-select v-model="queryParams.statusEnum" placeholder="请选择手术状态" clearable style="width: 200px">
<el-option
v-for="item in surgeryStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="手术类型" prop="surgeryTypeEnum">
<el-select v-model="queryParams.surgeryTypeEnum" placeholder="请选择手术类型" clearable style="width: 200px">
<el-option
v-for="item in surgeryTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="计划时间" prop="plannedTime">
<el-date-picker
v-model="queryParams.plannedTime"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 240px"
/>
</el-form-item>
<el-form-item class="search-buttons">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd"> 新增手术 </el-button>
</el-col>
<el-col :span="1.5">
<el-button type="" plain icon="Refresh" @click="getPageList">刷新</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<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>
<!-- 分页 -->
<div class="pagination-container">
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getPageList"
/>
</div>
<!-- 新增或修改手术对话框 -->
<el-dialog :title="title" v-model="open" width="800px" @close="cancel" append-to-body :close-on-click-modal="false">
<el-form ref="surgeryRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="id" prop="id" v-show="false">
<el-input v-model="form.id" />
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="患者" prop="patientId">
<el-select v-model="form.patientId" placeholder="请选择患者" filterable style="width: 100%" :disabled="form.id">
<el-option
v-for="item in patientList"
:key="item.id"
:label="item.name + ' (' + item.busNo + ')'"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="就诊流水号" prop="encounterId">
<el-input v-model="form.encounterNo" placeholder="请选择就诊" readonly>
<template #append>
<el-button icon="Search" @click="selectEncounter" />
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="手术名称" prop="surgeryName">
<el-input v-model="form.surgeryName" placeholder="请输入手术名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手术编码" prop="surgeryCode">
<el-input v-model="form.surgeryCode" placeholder="请输入手术编码" />
</el-form-item>
</el-col>
</el-row>
<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
v-for="item in surgeryTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="手术等级" prop="surgeryLevel">
<el-select v-model="form.surgeryLevel" placeholder="请选择手术等级" style="width: 100%">
<el-option
v-for="item in surgeryLevelOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</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-col :span="12">
<el-form-item label="手术部位" prop="bodySite">
<el-input v-model="form.bodySite" placeholder="请输入手术部位" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">手术团队</el-divider>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="主刀医生" prop="mainSurgeonId">
<el-select v-model="form.mainSurgeonId" placeholder="请选择主刀医生" filterable 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="anesthetistId">
<el-select v-model="form.anesthetistId" placeholder="请选择麻醉医生" filterable 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="助手1" prop="assistant1Id">
<el-select v-model="form.assistant1Id" placeholder="请选择助手1" filterable clearable 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="助手2" prop="assistant2Id">
<el-select v-model="form.assistant2Id" placeholder="请选择助手2" filterable clearable 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="scrubNurseId">
<el-select v-model="form.scrubNurseId" placeholder="请选择巡回护士" filterable clearable style="width: 100%">
<el-option
v-for="item in nurseList"
: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="anesthesiaTypeEnum">
<el-select v-model="form.anesthesiaTypeEnum" placeholder="请选择麻醉方式" style="width: 100%">
<el-option
v-for="item in anesthesiaTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="手术室" prop="operatingRoomId">
<el-input v-model="form.operatingRoomName" placeholder="请输入手术室">
<template #append>
<el-button icon="Search" />
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="执行科室" prop="orgId">
<el-tree-select
v-model="form.orgId"
:data="orgList"
:props="{ value: 'id', label: 'name', children: 'children' }"
placeholder="请选择执行科室"
check-strictly
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">诊断信息</el-divider>
<el-form-item label="术前诊断" prop="preoperativeDiagnosis">
<el-input v-model="form.preoperativeDiagnosis" type="textarea" placeholder="请输入术前诊断" :rows="3" />
</el-form-item>
<el-form-item label="术后诊断" prop="postoperativeDiagnosis">
<el-input v-model="form.postoperativeDiagnosis" type="textarea" placeholder="请输入术后诊断" :rows="3" />
</el-form-item>
<el-form-item label="手术经过描述" prop="surgeryDescription">
<el-input v-model="form.surgeryDescription" type="textarea" placeholder="请输入手术经过描述" :rows="5" />
</el-form-item>
<el-form-item label="术后医嘱" prop="postoperativeAdvice">
<el-input v-model="form.postoperativeAdvice" type="textarea" placeholder="请输入术后医嘱" :rows="3" />
</el-form-item>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="手术费用" prop="surgeryFee">
<el-input-number v-model="form.surgeryFee" :precision="2" :min="0" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="麻醉费用" prop="anesthesiaFee">
<el-input-number v-model="form.anesthesiaFee" :precision="2" :min="0" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="总费用" prop="totalFee">
<el-input-number v-model="form.totalFee" :precision="2" :min="0" style="width: 100%" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="切口等级" prop="incisionLevel">
<el-select v-model="form.incisionLevel" placeholder="请选择切口等级" style="width: 100%">
<el-option
v-for="item in incisionLevelOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="愈合等级" prop="healingLevel">
<el-select v-model="form.healingLevel" placeholder="请选择愈合等级" style="width: 100%">
<el-option
v-for="item in healingLevelOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="并发症描述" prop="complications">
<el-input v-model="form.complications" type="textarea" placeholder="请输入并发症描述" :rows="3" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注信息" :rows="2" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- 查看手术详情对话框 -->
<el-dialog title="手术详情" v-model="viewOpen" width="900px" append-to-body>
<el-descriptions :column="2" border>
<el-descriptions-item label="手术编号">{{ viewData.surgeryNo }}</el-descriptions-item>
<el-descriptions-item label="手术状态">
<el-tag :type="getStatusType(viewData.statusEnum)">{{ viewData.statusEnum_dictText }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="患者姓名">{{ viewData.patientName }}</el-descriptions-item>
<el-descriptions-item label="患者信息">{{ viewData.patientGender }} / {{ viewData.patientAge }}</el-descriptions-item>
<el-descriptions-item label="就诊流水号">{{ viewData.encounterNo }}</el-descriptions-item>
<el-descriptions-item label="手术名称">{{ viewData.surgeryName }}</el-descriptions-item>
<el-descriptions-item label="手术编码">{{ viewData.surgeryCode }}</el-descriptions-item>
<el-descriptions-item label="手术类型">{{ viewData.surgeryTypeEnum_dictText }}</el-descriptions-item>
<el-descriptions-item label="手术等级">{{ viewData.surgeryLevel_dictText }}</el-descriptions-item>
<el-descriptions-item label="麻醉方式">{{ viewData.anesthesiaTypeEnum_dictText }}</el-descriptions-item>
<el-descriptions-item label="计划时间">{{ viewData.plannedTime }}</el-descriptions-item>
<el-descriptions-item label="实际开始时间">{{ viewData.actualStartTime }}</el-descriptions-item>
<el-descriptions-item label="实际结束时间">{{ viewData.actualEndTime }}</el-descriptions-item>
<el-descriptions-item label="手术部位">{{ viewData.bodySite }}</el-descriptions-item>
<el-descriptions-item label="主刀医生">{{ viewData.mainSurgeonName }}</el-descriptions-item>
<el-descriptions-item label="麻醉医生">{{ viewData.anesthetistName }}</el-descriptions-item>
<el-descriptions-item label="助手1">{{ viewData.assistant1Name }}</el-descriptions-item>
<el-descriptions-item label="助手2">{{ viewData.assistant2Name }}</el-descriptions-item>
<el-descriptions-item label="手术室">{{ viewData.operatingRoomName }}</el-descriptions-item>
<el-descriptions-item label="执行科室">{{ viewData.orgName }}</el-descriptions-item>
<el-descriptions-item label="术前诊断" :span="2">{{ viewData.preoperativeDiagnosis }}</el-descriptions-item>
<el-descriptions-item label="术后诊断" :span="2">{{ viewData.postoperativeDiagnosis }}</el-descriptions-item>
<el-descriptions-item label="手术费用" :span="2">¥{{ viewData.surgeryFee }}</el-descriptions-item>
<el-descriptions-item label="麻醉费用" :span="2">¥{{ viewData.anesthesiaFee }}</el-descriptions-item>
<el-descriptions-item label="总费用" :span="2">¥{{ viewData.totalFee }}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{ viewData.remark }}</el-descriptions-item>
</el-descriptions>
</el-dialog>
</div>
</template>
<script setup name="SurgeryManage">
import { getSurgeryPage, addSurgery, updateSurgery, deleteSurgery, getSurgeryDetail, updateSurgeryStatus } from '@/api/surgerymanage'
const { proxy } = getCurrentInstance()
const loading = ref(true)
const showSearch = ref(true)
const surgeryList = ref([])
const queryParams = ref({
pageNo: 1,
pageSize: 10,
surgeryNo: undefined,
surgeryName: undefined,
patientName: undefined,
statusEnum: undefined,
surgeryTypeEnum: undefined,
plannedTime: undefined
})
const open = ref(false)
const viewOpen = ref(false)
const form = ref({
id: undefined,
patientId: undefined,
encounterId: undefined,
encounterNo: undefined,
surgeryName: undefined,
surgeryCode: undefined,
surgeryTypeEnum: undefined,
surgeryLevel: undefined,
plannedTime: undefined,
mainSurgeonId: undefined,
anesthetistId: undefined,
assistant1Id: undefined,
assistant2Id: undefined,
scrubNurseId: undefined,
anesthesiaTypeEnum: undefined,
bodySite: undefined,
operatingRoomId: undefined,
operatingRoomName: undefined,
orgId: undefined,
preoperativeDiagnosis: undefined,
postoperativeDiagnosis: undefined,
surgeryDescription: undefined,
postoperativeAdvice: undefined,
surgeryFee: undefined,
anesthesiaFee: undefined,
totalFee: undefined,
incisionLevel: undefined,
healingLevel: undefined,
complications: undefined,
remark: undefined
})
const surgeryRef = ref()
const viewData = ref({})
const total = ref(0)
const title = ref('')
// 字典选项
const surgeryStatusOptions = ref([
{ value: 0, label: '待排期' },
{ value: 1, label: '已排期' },
{ value: 2, label: '手术中' },
{ value: 3, label: '已完成' },
{ value: 4, label: '已取消' },
{ value: 5, label: '暂停' }
])
const surgeryTypeOptions = ref([
{ value: 1, label: '门诊手术' },
{ value: 2, label: '住院手术' },
{ value: 3, label: '急诊手术' },
{ value: 4, label: '择期手术' }
])
const surgeryLevelOptions = ref([
{ value: 1, label: '一级手术' },
{ value: 2, label: '二级手术' },
{ value: 3, label: '三级手术' },
{ value: 4, label: '四级手术' },
{ value: 5, label: '特级手术' }
])
const anesthesiaTypeOptions = ref([
{ value: 0, label: '无麻醉' },
{ value: 1, label: '局部麻醉' },
{ value: 2, label: '区域麻醉' },
{ value: 3, label: '全身麻醉' },
{ value: 4, label: '脊椎麻醉' },
{ value: 5, label: '硬膜外麻醉' },
{ value: 6, label: '表面麻醉' }
])
const incisionLevelOptions = ref([
{ value: 1, label: 'I级切口' },
{ value: 2, label: 'II级切口' },
{ value: 3, label: 'III级切口' },
{ value: 4, label: 'IV级切口' }
])
const healingLevelOptions = ref([
{ value: 1, label: '甲级愈合' },
{ value: 2, label: '乙级愈合' },
{ value: 3, label: '丙级愈合' }
])
// 下拉列表数据
const patientList = ref([])
const doctorList = ref([])
const nurseList = ref([])
const orgList = ref([])
const rules = ref({
patientId: [{ required: true, message: '请选择患者', trigger: 'change' }],
surgeryName: [{ required: true, message: '请输入手术名称', trigger: 'blur' }],
surgeryTypeEnum: [{ required: true, message: '请选择手术类型', trigger: 'change' }],
surgeryLevel: [{ required: true, message: '请选择手术等级', trigger: 'change' }],
plannedTime: [{ required: true, message: '请选择计划手术时间', trigger: 'change' }],
mainSurgeonId: [{ required: true, message: '请选择主刀医生', trigger: 'change' }],
anesthesiaTypeEnum: [{ required: true, message: '请选择麻醉方式', trigger: 'change' }],
bodySite: [{ required: true, message: '请输入手术部位', trigger: 'blur' }]
})
// 监听费用变化自动计算总费用
watch([() => form.value.surgeryFee, () => form.value.anesthesiaFee], ([newSurgeryFee, newAnesthesiaFee]) => {
const surgeryFee = Number(newSurgeryFee) || 0
const anesthesiaFee = Number(newAnesthesiaFee) || 0
form.value.totalFee = surgeryFee + anesthesiaFee
})
getPageList()
function getList() {
loading.value = true
const params = { ...queryParams.value }
// 处理时间范围
if (params.plannedTime && params.plannedTime.length === 2) {
params.plannedTimeStart = params.plannedTime[0]
params.plannedTimeEnd = params.plannedTime[1]
delete params.plannedTime
}
getSurgeryPage(params).then((res) => {
surgeryList.value = res.data.records
total.value = res.data.total
}).catch(error => {
console.error('获取手术列表失败:', error)
proxy.$modal.msgError('获取手术列表失败,请稍后重试')
surgeryList.value = []
total.value = 0
}).finally(() => {
loading.value = false
})
}
function getPageList() {
queryParams.value.pageNo = 1
getList()
}
function handleQuery() {
queryParams.value.pageNo = 1
getList()
}
function resetQuery() {
proxy.resetForm('queryRef')
queryParams.value = {
pageNo: 1,
pageSize: 10,
surgeryNo: undefined,
surgeryName: undefined,
patientName: undefined,
statusEnum: undefined,
surgeryTypeEnum: undefined,
plannedTime: undefined
}
getList()
}
function handleAdd() {
title.value = '新增手术'
open.value = true
reset()
}
function handleEdit(row) {
title.value = '编辑手术'
open.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('获取手术信息失败')
})
}
function handleView(row) {
viewOpen.value = true
getSurgeryDetail(row.id).then(res => {
if (res.code === 200) {
viewData.value = res.data
}
}).catch(error => {
console.error('获取手术信息失败:', error)
proxy.$modal.msgError('获取手术信息失败')
})
}
function cancel() {
open.value = false
reset()
}
function reset() {
form.value = {
id: undefined,
patientId: undefined,
encounterId: undefined,
encounterNo: undefined,
surgeryName: undefined,
surgeryCode: undefined,
surgeryTypeEnum: undefined,
surgeryLevel: undefined,
plannedTime: undefined,
mainSurgeonId: undefined,
anesthetistId: undefined,
assistant1Id: undefined,
assistant2Id: undefined,
scrubNurseId: undefined,
anesthesiaTypeEnum: undefined,
bodySite: undefined,
operatingRoomId: undefined,
operatingRoomName: undefined,
orgId: undefined,
preoperativeDiagnosis: undefined,
postoperativeDiagnosis: undefined,
surgeryDescription: undefined,
postoperativeAdvice: undefined,
surgeryFee: undefined,
anesthesiaFee: undefined,
totalFee: undefined,
incisionLevel: undefined,
healingLevel: undefined,
complications: undefined,
remark: undefined
}
if (surgeryRef.value) {
surgeryRef.value.resetFields()
}
}
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)
proxy.$modal.msgError('新增手术失败,请稍后重试')
})
} else {
updateSurgery(form.value).then((res) => {
proxy.$modal.msgSuccess('修改成功')
open.value = false
getPageList()
}).catch(error => {
console.error('更新手术失败:', error)
proxy.$modal.msgError('更新手术失败,请稍后重试')
})
}
}
})
}
function handleDelete(row) {
proxy.$modal.confirm('是否确认删除手术"' + row.surgeryName + '"?').then(() => {
return deleteSurgery(row.id)
}).then(() => {
getPageList()
proxy.$modal.msgSuccess('删除成功')
}).catch(error => {
console.error('删除手术失败:', error)
})
}
function handleStart(row) {
proxy.$modal.confirm('是否确认开始手术"' + row.surgeryName + '"?').then(() => {
return updateSurgeryStatus(row.id, 2)
}).then(() => {
getPageList()
proxy.$modal.msgSuccess('手术已开始')
}).catch(error => {
console.error('开始手术失败:', error)
})
}
function handleComplete(row) {
proxy.$modal.confirm('是否确认完成手术"' + row.surgeryName + '"?').then(() => {
return updateSurgeryStatus(row.id, 3)
}).then(() => {
getPageList()
proxy.$modal.msgSuccess('手术已完成')
}).catch(error => {
console.error('完成手术失败:', error)
})
}
function selectEncounter() {
// TODO: 实现选择就诊的功能
proxy.$modal.msgInfo('请选择就诊记录')
}
function getStatusType(status) {
const typeMap = {
0: 'info',
1: 'warning',
2: 'primary',
3: 'success',
4: 'danger',
5: 'info'
}
return typeMap[status] || 'info'
}
</script>