统计中心-》添加部门统计逻辑
This commit is contained in:
@@ -82,3 +82,15 @@ export function completeAppointment(params: any) {
|
||||
export function getDoctorStatistics(params: any) {
|
||||
return request.get({ url: '/doctor.statistics/lists', params })
|
||||
}
|
||||
|
||||
// ========== 部门统计 ==========
|
||||
|
||||
// 获取部门列表
|
||||
export function getDeptList() {
|
||||
return request.get({ url: '/dept.dept/all' })
|
||||
}
|
||||
|
||||
// 获取部门统计
|
||||
export function getDeptStatistics(params: any) {
|
||||
return request.get({ url: '/doctor.statistics/deptLists', params })
|
||||
}
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
<template>
|
||||
<div class="dept-statistics-page">
|
||||
<!-- 筛选区域卡片 -->
|
||||
<el-card class="mb-4" shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">筛选条件</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :inline="true" :model="queryParams" class="filter-form">
|
||||
<el-form-item label="部门">
|
||||
<el-select
|
||||
v-model="queryParams.dept_id"
|
||||
placeholder="全部部门"
|
||||
clearable
|
||||
filterable
|
||||
style="width: 200px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dept in deptList"
|
||||
:key="dept.id"
|
||||
:label="dept.name"
|
||||
:value="dept.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="时间范围">
|
||||
<el-radio-group v-model="queryParams.time_type" @change="handleTimeTypeChange">
|
||||
<el-radio-button label="today">今天</el-radio-button>
|
||||
<el-radio-button label="week">最近7天</el-radio-button>
|
||||
<el-radio-button label="month">最近30天</el-radio-button>
|
||||
<el-radio-button label="custom">自定义</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="queryParams.time_type === 'custom'">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 260px"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getStatistics" :loading="loading">查询</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 统计数据卡片 -->
|
||||
<el-card v-loading="loading" class="mb-4" shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span class="card-title">部门统计数据</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="statisticsList.length > 0">
|
||||
<el-table
|
||||
:data="statisticsList"
|
||||
style="width: 100%"
|
||||
:header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: '600' }"
|
||||
>
|
||||
<el-table-column prop="dept_name" label="部门名称" width="120" />
|
||||
|
||||
<!-- 状态明细 -->
|
||||
<el-table-column label="状态明细" min-width="700">
|
||||
<template #default="{ row }">
|
||||
<div class="status-overview">
|
||||
<div class="status-tags">
|
||||
<el-tag type="info" size="small" class="compact-tag">
|
||||
已挂号: {{ row.registered_count }}
|
||||
</el-tag>
|
||||
<el-tag type="success" size="small" class="compact-tag">
|
||||
已完成: {{ row.completed_count }}
|
||||
</el-tag>
|
||||
<el-tag type="danger" size="small" class="compact-tag">
|
||||
已取消: {{ row.canceled_count }}
|
||||
</el-tag>
|
||||
<el-tag type="warning" size="small" class="compact-tag">
|
||||
已过号: {{ row.expired_count }}
|
||||
</el-tag>
|
||||
<el-tag type="primary" size="small" class="compact-tag">
|
||||
总数量: {{ row.total_count }}
|
||||
</el-tag>
|
||||
<el-tag :type="getCompletionRateType(row.completion_rate)" size="small" class="compact-tag">
|
||||
完成率: {{ row.completion_rate }}%
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="time_range" label="统计时间" min-width="200" />
|
||||
</el-table>
|
||||
</div>
|
||||
<div v-else class="empty-data">
|
||||
<el-empty description="暂无统计数据" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getDeptStatistics, getDeptList } from '@/api/doctor'
|
||||
|
||||
const loading = ref(false)
|
||||
const deptList = ref<any[]>([])
|
||||
const statisticsList = ref<any[]>([])
|
||||
const dateRange = ref<string[]>([])
|
||||
|
||||
const queryParams = reactive({
|
||||
dept_id: '',
|
||||
time_type: 'today',
|
||||
start_date: '',
|
||||
end_date: ''
|
||||
})
|
||||
|
||||
const getDeptLists = async () => {
|
||||
try {
|
||||
const res = await getDeptList()
|
||||
// 将树形结构转换为扁平化列表
|
||||
const flattenDepts = (depts) => {
|
||||
let result = []
|
||||
depts.forEach(dept => {
|
||||
result.push({ id: dept.id, name: dept.name })
|
||||
if (dept.children && dept.children.length > 0) {
|
||||
result = result.concat(flattenDepts(dept.children))
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
deptList.value = flattenDepts(res) || []
|
||||
} catch (error) {
|
||||
console.error('获取部门列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const getStatistics = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: any = {
|
||||
time_type: queryParams.time_type
|
||||
}
|
||||
|
||||
if (queryParams.dept_id) {
|
||||
params.dept_id = queryParams.dept_id
|
||||
}
|
||||
|
||||
if (queryParams.time_type === 'custom' && dateRange.value && dateRange.value.length === 2) {
|
||||
params.start_date = dateRange.value[0]
|
||||
params.end_date = dateRange.value[1]
|
||||
}
|
||||
|
||||
const res = await getDeptStatistics(params)
|
||||
statisticsList.value = res.lists || []
|
||||
} catch (error: any) {
|
||||
console.error('获取统计数据错误:', error)
|
||||
ElMessage.error(error.msg || '获取统计数据失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleTimeTypeChange = () => {
|
||||
if (queryParams.time_type !== 'custom') {
|
||||
dateRange.value = []
|
||||
}
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
queryParams.dept_id = ''
|
||||
queryParams.time_type = 'today'
|
||||
dateRange.value = []
|
||||
getStatistics()
|
||||
}
|
||||
|
||||
// 获取完成率标签类型
|
||||
const getCompletionRateType = (rate: number) => {
|
||||
if (rate >= 80) {
|
||||
return 'success'
|
||||
} else if (rate >= 60) {
|
||||
return 'primary'
|
||||
} else {
|
||||
return 'warning'
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDeptLists()
|
||||
getStatistics()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dept-statistics-page {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
padding: 10px 0;
|
||||
:deep(.el-form-item) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.status-overview {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.status-section {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
padding-bottom: 4px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.status-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.compact-tag {
|
||||
font-size: 12px !important;
|
||||
padding: 4px 12px !important;
|
||||
margin: 0 !important;
|
||||
border-radius: 12px !important;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1) !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
.compact-tag:hover {
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
.empty-data {
|
||||
padding: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 表格样式优化 */
|
||||
:deep(.el-table) {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
:deep(.el-table:hover) {
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
:deep(.el-table th) {
|
||||
background-color: #f5f7fa !important;
|
||||
font-weight: 600 !important;
|
||||
color: #606266 !important;
|
||||
border-bottom: 1px solid #ebeef5 !important;
|
||||
}
|
||||
|
||||
:deep(.el-table tr:hover) {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
|
||||
:deep(.el-table__cell) {
|
||||
text-align: left !important;
|
||||
vertical-align: top !important;
|
||||
padding: 12px 15px !important;
|
||||
}
|
||||
|
||||
/* 卡片样式优化 */
|
||||
:deep(.el-card) {
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !important;
|
||||
margin-bottom: 16px !important;
|
||||
transition: box-shadow 0.3s ease;
|
||||
border: none !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.el-card:hover) {
|
||||
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
:deep(.el-card__header) {
|
||||
background-color: #ffffff !important;
|
||||
border-bottom: 1px solid #ebeef5 !important;
|
||||
padding: 15px 20px !important;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px !important;
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
|
||||
/* 按钮样式优化 */
|
||||
:deep(.el-button) {
|
||||
border-radius: 4px !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
:deep(.el-button:hover) {
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
/* 选择器样式优化 */
|
||||
:deep(.el-select) {
|
||||
border-radius: 4px !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
:deep(.el-select:hover) {
|
||||
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2) !important;
|
||||
}
|
||||
|
||||
/* 标签样式优化 */
|
||||
:deep(.el-tag) {
|
||||
border-radius: 4px !important;
|
||||
transition: all 0.3s ease !important;
|
||||
}
|
||||
|
||||
:deep(.el-tag:hover) {
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user