feat(infection): 院感监测细化 — 科室感染率+感染趋势
- 新增 IInfectionDetailAppService + InfectionDetailAppServiceImpl - 新增 InfectionDetailController (GET /rate-by-dept, GET /trend) - 新增 V74 迁移脚本: hir_infection_case 加 department_id - 前端 InfectionDetailStats.vue 统计面板+趋势表格
This commit is contained in:
9
healthlink-his-ui/src/api/infection/detail.js
Normal file
9
healthlink-his-ui/src/api/infection/detail.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getInfectionRateByDept(params) {
|
||||
return request({ url: '/infection-detail/rate-by-dept', method: 'get', params })
|
||||
}
|
||||
|
||||
export function getInfectionTrend(params) {
|
||||
return request({ url: '/infection-detail/trend', method: 'get', params })
|
||||
}
|
||||
152
healthlink-his-ui/src/views/infection/detail/index.vue
Normal file
152
healthlink-his-ui/src/views/infection/detail/index.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div class="infection-detail-container">
|
||||
<div class="page-header">
|
||||
<span class="tab-title">院感监测统计</span>
|
||||
</div>
|
||||
|
||||
<el-card shadow="never" style="margin-bottom: 16px">
|
||||
<template #header>
|
||||
<span>查询条件</span>
|
||||
</template>
|
||||
<el-form :model="queryParams" inline>
|
||||
<el-form-item label="科室">
|
||||
<el-input v-model="queryParams.deptId" placeholder="科室ID" clearable style="width: 160px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开始日期">
|
||||
<el-date-picker v-model="queryParams.startDate" type="date" value-format="YYYY-MM-DD" placeholder="开始日期" />
|
||||
</el-form-item>
|
||||
<el-form-item label="结束日期">
|
||||
<el-date-picker v-model="queryParams.endDate" type="date" value-format="YYYY-MM-DD" placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="loadData" :loading="loading">查询</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-row :gutter="16" style="margin-bottom: 16px">
|
||||
<el-col :span="6">
|
||||
<el-card shadow="never">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" style="color: #409eff">{{ rateData.totalCases || 0 }}</div>
|
||||
<div class="stat-label">总病例数</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="never">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" style="color: #e6a23c">{{ rateData.reportedCases || 0 }}</div>
|
||||
<div class="stat-label">已上报</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="never">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" style="color: #67c23a">{{ rateData.confirmedCases || 0 }}</div>
|
||||
<div class="stat-label">已确认</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card shadow="never">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" style="color: #f56c6c">{{ rateData.infectionRate || 0 }}%</div>
|
||||
<div class="stat-label">感染率</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16" style="margin-bottom: 16px">
|
||||
<el-col :span="12">
|
||||
<el-card shadow="never">
|
||||
<template #header><span>按感染类型分布</span></template>
|
||||
<el-table :data="typeList" border stripe size="small">
|
||||
<el-table-column prop="type" label="感染类型" />
|
||||
<el-table-column prop="count" label="病例数" width="100" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card shadow="never">
|
||||
<template #header><span>按感染部位分布</span></template>
|
||||
<el-table :data="siteList" border stripe size="small">
|
||||
<el-table-column prop="site" label="感染部位" />
|
||||
<el-table-column prop="count" label="病例数" width="100" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header><span>感染趋势</span></template>
|
||||
<el-table :data="trendData" v-loading="loading" border stripe style="width: 100%">
|
||||
<el-table-column prop="date" label="日期" width="120" />
|
||||
<el-table-column prop="total" label="总计" width="80" />
|
||||
<el-table-column prop="REPORTED" label="已上报" width="80" />
|
||||
<el-table-column prop="CONFIRMED" label="已确认" width="80" />
|
||||
<el-table-column prop="REJECTED" label="已驳回" width="80" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getInfectionRateByDept, getInfectionTrend } from '@/api/infection/detail'
|
||||
|
||||
const loading = ref(false)
|
||||
const queryParams = reactive({
|
||||
deptId: '',
|
||||
startDate: '',
|
||||
endDate: ''
|
||||
})
|
||||
|
||||
const rateData = ref({})
|
||||
const trendData = ref([])
|
||||
|
||||
const typeList = computed(() => {
|
||||
const byType = rateData.value.byType || {}
|
||||
return Object.entries(byType).map(([type, count]) => ({ type, count }))
|
||||
})
|
||||
|
||||
const siteList = computed(() => {
|
||||
const bySite = rateData.value.bySite || {}
|
||||
return Object.entries(bySite).map(([site, count]) => ({ site, count }))
|
||||
})
|
||||
|
||||
const loadData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {}
|
||||
if (queryParams.deptId) params.deptId = queryParams.deptId
|
||||
if (queryParams.startDate) params.startDate = queryParams.startDate
|
||||
if (queryParams.endDate) params.endDate = queryParams.endDate
|
||||
|
||||
const [rateRes, trendRes] = await Promise.all([
|
||||
getInfectionRateByDept(params),
|
||||
getInfectionTrend({ startDate: queryParams.startDate, endDate: queryParams.endDate })
|
||||
])
|
||||
rateData.value = rateRes.data || {}
|
||||
trendData.value = trendRes.data || []
|
||||
} catch (e) {
|
||||
ElMessage.error('加载失败: ' + (e.message || '未知错误'))
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => loadData())
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.infection-detail-container { padding: 16px; }
|
||||
.page-header { margin-bottom: 16px; }
|
||||
.tab-title { font-size: 18px; font-weight: bold; }
|
||||
.stat-card { text-align: center; padding: 12px 0; }
|
||||
.stat-value { font-size: 28px; font-weight: bold; }
|
||||
.stat-label { font-size: 13px; color: #909399; margin-top: 4px; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user