Files
intc-vue3/src/views/health/doctorStatistic/index.vue
2024-12-19 16:08:27 +08:00

666 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<div class="search-con">
<div class="title">查询条件</div>
<el-form :model="queryParams" ref="queryRef" :inline="true" :rules="rules" label-width="100px">
<el-form-item label="人员姓名" prop="id">
<el-select v-model="queryParams.id" placeholder="请选择人员姓名" @change="handlePersonChange">
<el-option v-for="person in personList" :key="person.id" :label="person.name" :value="person.id" />
</el-select>
</el-form-item>
<el-form-item label="健康档案" prop="recordId">
<el-select v-model="queryParams.recordId" placeholder="请选择健康档案" @change="handleRecordChange" clearable>
<el-option v-for="health in healthRecordList" :key="health.id" :label="health.name" :value="health.id" />
</el-select>
</el-form-item>
<el-form-item label="就医日期" prop="time" v-if="queryParams.type === 1">
<el-date-picker
v-model="queryParams.time"
type="daterange"
range-separator="~"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD"
@calendar-change="calendarChange"
/>
</el-form-item>
<el-form-item label="" prop="time" v-if="queryParams.type === 2">
<el-date-picker
v-model="queryParams.time"
type="monthrange"
range-separator="~"
format="YYYY-MM"
start-placeholder="开始时间"
end-placeholder="结束时间"
:disabled-date="disabledDateFun"
@calendar-change="calendarChange"
/>
</el-form-item>
<el-form-item label="" prop="time" v-if="queryParams.type === 3">
<yearPicker
v-model="queryParams.time"
ref="statisticPicker"
labelText="选择年份"
:initYear="dateValue"
:showYear="showYearValue"
:maxLength="5"
sp="~"
@updateTimeRange="updateStatisticYear"
/>
</el-form-item>
</el-form>
<div class="search-btn-con">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button type="info" icon="Refresh" @click="resetQuery">重置</el-button>
</div>
</div>
<div class="main-con" style="height: calc(100% - 1.45rem)">
<div class="summary-con" style="height: 115px">
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">就医次数</div>
<div>
<span class="num">{{ doctor.doctorCount }}</span
><span class="unit"></span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">就医费用</div>
<div>
<span class="num">{{ doctor.doctorCost }}</span
><span class="unit"> </span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">常去医院</div>
<div>
<span class="num" style="font-size: 16px">{{ doctor.commonHospital }}</span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">常去科室</div>
<div>
<span style="font-size: 18px" class="num">{{ doctor.commonDepartments }}</span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">常看大夫</div>
<div>
<span class="num" style="font-size: 18px">{{ doctor.commonDoctor }}</span>
</div>
</div>
</div>
</div>
<div class="summary-con" style="height: 115px">
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">门诊次数</div>
<div>
<span class="num">{{ doctor.clinicCount }}</span
><span class="unit"></span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">急诊次数</div>
<div>
<span class="num">{{ doctor.emergencyCount }}</span
><span class="unit"> </span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">输液次数</div>
<div>
<span class="num">{{ doctor.infusionCount }}</span
><span class="unit"> </span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">住院次数</div>
<div>
<span class="num">{{ doctor.hospitalizedCount }}</span
><span class="unit"></span>
</div>
</div>
</div>
<div class="right-con">
<div class="img">
<img src="@/assets/images/average.png" alt="" />
</div>
<div class="item-wrap">
<div class="title">线上问诊次数</div>
<div>
<span class="num">{{ doctor.onlineCount }}</span
><span class="unit"></span>
</div>
</div>
</div>
</div>
<div class="title-con" style="margin-top: 18px">
<div class="title">就医统计</div>
<div class="operate-btn-con">
<el-radio-group v-model="radioVal" @change="handleRadioChange">
<el-radio-button label="就医明细统计" />
<el-radio-button label="就诊医院统计" />
<el-radio-button label="就诊科室统计" />
<el-radio-button label="就诊大夫统计" />
<el-radio-button label="就医费用柱状图" />
<el-radio-button label="就医费用折线图" />
</el-radio-group>
</div>
</div>
<div class="content-con">
<div v-show="radioVal === '就医费用柱状图'" class="chart" id="chartBar" style="height: calc(100% - 225px); margin-top: -10px"></div>
<div v-show="radioVal === '就医费用折线图'" class="chart" id="chartLine" style="height: calc(100% - 225px); margin-top: -10px"></div>
<el-table v-show="radioVal === '就诊医院统计'" v-loading="loading" :data="doctor.hospitalStaticList" height="calc(100% - 245px)">
<el-table-column label="序号" width="50" type="index" align="center">
<template #default="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="医院名称" align="center" prop="hospitalName" />
<el-table-column label="就诊次数" align="center" prop="count" />
</el-table>
<el-table v-show="radioVal === '就诊科室统计'" v-loading="loading" :data="doctor.departStaticList" height="calc(100% - 245px)">
<el-table-column label="序号" width="50" type="index" align="center">
<template #default="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="就诊科室" align="center" prop="departments" />
<el-table-column label="就诊次数" align="center" prop="count" />
</el-table>
<el-table v-show="radioVal === '就诊大夫统计'" v-loading="loading" :data="doctor.doctorStaticList" height="calc(100% - 245px)">
<el-table-column label="序号" width="50" type="index" align="center">
<template #default="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="就诊大夫" align="center" prop="doctor" />
<el-table-column label="所在医院" align="center" prop="hospitalName" />
<el-table-column label="就诊次数" align="center" prop="count" />
</el-table>
<el-table v-show="radioVal === '就医明细统计'" v-loading="loading" :data="doctor.doctorTableList" height="calc(100% - 245px)">
<el-table-column label="序号" width="50" type="index" align="center">
<template #default="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
<el-table-column label="就诊医院" align="center" width="250" prop="hospitalName" />
<el-table-column label="就医类型" align="center" width="150" prop="type">
<template #default="scope">
<dict-tag :options="doctor_type" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="就诊大夫" align="center" width="150" prop="doctor" />
<el-table-column label="就诊时间" align="center" width="160" prop="visitingTime" />
<el-table-column label="诊断结果" align="center" prop="diagnosis" />
<el-table-column label="就诊费用(元)" align="center" width="150" prop="totalCost" />
</el-table>
</div>
</div>
</div>
</template>
<script setup name="CreditAnalysis">
import dayjs from 'dayjs'
import * as echarts from 'echarts'
import { ElMessage } from 'element-plus'
import yearPicker from '@/components/YearPicker/index.vue'
import { getDoctorAnalysis } from '@/api/health/statisticAnalysis'
import { listPerson, getPerson } from '@/api/health/person'
import { listHealthRecord } from '@/api/health/healthRecord'
const { proxy } = getCurrentInstance()
const personList = ref([])
const healthRecordList = ref([])
const { doctor_type, cost_type, check_type, package_unit, nursing_type, mar_type } = proxy.useDict(
'doctor_type',
'cost_type',
'check_type',
'package_unit',
'nursing_type',
'mar_type'
)
const dateValue = ref({ startYear: 2000, endYear: new Date().getFullYear() })
const showYearValue = ref({ startShowYear: '', endShowYear: '' })
const updateStatisticYear = (startYear, endYear) => {
queryParams.value.time = [new Date(startYear, 0, 1), new Date(endYear, 0, 1)]
if (endYear - startYear > 5) {
ElMessage.warning('时间跨度不能大于5年默认选择开始日期的5年')
queryParams.value.time = [new Date(startYear, 0, 1), new Date(startYear + 5, 0, 1)]
}
}
const dates = [{ value: 1, label: '日' }]
const accountsList = ref([])
const loading = ref(true)
const total = ref(0)
const radioVal = ref('就医明细统计')
const dateValidate = (rules, value, callback) => {
const dateType = rules.dateType || 'days'
const num = rules.num || 31
const dateString = rules.dateString || '天'
const message = rules.message || `时间跨度不能超过${num}${dateString}`
if (value && value.length === 2) {
const start = value[0]
const end = value[1]
if (dayjs(end).diff(dayjs(start), dateType) > num) {
queryParams.value.time = [start, dayjs(start).add(23, 'months')]
ElMessage.warning(message)
}
}
}
const data = reactive({
queryParams: {
type: 1,
time: null,
id: null,
dataType: '1',
dealType: null,
dealCategory: null
},
queryPersonParams: {
pageNum: 1,
pageSize: 1000
},
queryHealthRecordParams: {
pageNum: 1,
personId: null,
state: '1',
pageSize: 1000
},
rules: {
time: [{ validator: dateValidate, dateType: 'months', num: 23, dateRange: '月', message: '时间跨度不能大于24个月默认选择开始日期的24个月' }]
}
})
const { queryParams, rules, queryPersonParams, queryHealthRecordParams } = toRefs(data)
const handleRecordChange = (recordId) => {
queryParams.value.recordId = recordId
getList()
}
const handlePersonChange = (personId) => {
queryHealthRecordParams.personId = personId
listHealthRecord(queryHealthRecordParams).then((response) => {
healthRecordList.value = response.rows
if (response.rows.length > 0) {
queryParams.value.recordId = response.rows[0].id
getList()
}
})
}
/** 查询成员管理列表 */
function getPersonList() {
listPerson(queryPersonParams.value).then((response) => {
personList.value = response.rows
if (response.rows.length > 0) {
queryParams.value.id = response.rows[0].id
queryHealthRecordParams.personId = response.rows[0].id
listHealthRecord(queryHealthRecordParams).then((res) => {
healthRecordList.value = res.rows
if (res.rows.length > 0) {
queryParams.value.recordId = res.rows[0].id
getList()
}
})
}
})
}
const today = new Date()
// const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2) + '-' + ('0' + today.getDate()).slice(-2)
// const start = dayjs(end).add(-60, 'day')
// queryParams.value.time = [start, end]
const handleTimeChange = (type) => {
queryParams.value.time = null
if (type === 1) {
const today = new Date()
const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2) + '-' + ('0' + today.getDate()).slice(-2)
const start = dayjs(end).add(-60, 'day')
queryParams.value.time = [start, end]
} else if (type === 2) {
const today = new Date()
const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2)
const start = dayjs(end).add(-11, 'months')
queryParams.value.time = [start, end]
} else if (type === 3) {
const today = new Date()
const endYear = today.getFullYear()
queryParams.value.time = [new Date(endYear - 2, 0, 1), new Date(endYear, 0, 1)]
showYearValue.value = { startShowYear: endYear - 2, endShowYear: endYear }
}
getList()
}
function formatMultiLineData(data) {
if (data != null) {
return data.replace(/<br\/>/g, '<br/>')
}
}
const disabledDateFun = (time) => {
const arr = [0, 30, 365, 365 * 5]
const days = arr[queryParams.value.type]
if (firstChooseDate.value) {
const one = days * 24 * 3600 * 1000
const minTime = firstChooseDate.value - one
const maxTime = firstChooseDate.value + one
const startTime = minTime
const endTime = maxTime > Date.now() - 8.64e7 ? Date.now() - 8.64e7 : maxTime
return time.getTime() > endTime || time.getTime() < startTime
} else {
return time.getTime() > Date.now() - 8.64e7
}
}
const firstChooseDate = ref('')
const calendarChange = (val) => {
firstChooseDate.value = val[0].getTime()
if (val[1]) firstChooseDate.value = ''
}
const doctor = ref({})
const chartData = ref({
name: [],
value1: []
})
function getList() {
loading.value = true
chartData.value = { name: [], value1: [] }
const { type, time, id, recordId } = queryParams.value
let formatValue = 'YYYY-MM-DD'
if (type === 1) {
formatValue = 'YYYY-MM-DD'
} else if (type === 2) {
formatValue = 'YYYY-MM'
} else {
formatValue = 'YYYY'
}
const params = {
type,
startTime: time && time.length > 0 ? dayjs(time[0]).format(formatValue) : '',
endTime: time && time.length > 0 ? dayjs(time[1]).format(formatValue) : '',
id,
recordId
}
getDoctorAnalysis(params).then((response) => {
loading.value = false
doctor.value = { ...response.data }
doctor.value.doctorCostList.map((item) => {
return {
name: item.time,
value: item.value
}
})
response.data.doctorCostList.map((item) => {
chartData.value.name.push(item.time)
chartData.value.value1.push(item.value)
})
handleRadioChange(currentType.value)
})
}
function handleQuery() {
getList()
}
function resetQuery() {
proxy.resetForm('queryRef')
queryParams.value.id = null
// const today = new Date()
// const end = today.getFullYear() + '-' + ('0' + (today.getMonth() + 1)).slice(-2) + '-' + ('0' + today.getDate()).slice(-2)
// const start = dayjs(end).add(-60, 'day')
// queryParams.value.time = [start, end]
total.value = 0
getPersonList()
}
const drawBar = (data) => {
if (document.getElementById('chartBar') === null) {
return
}
echarts.dispose(document.getElementById('chartBar'))
const myChart = echarts.init(document.getElementById('chartBar'))
const option = {
legend: {
// 图示例样式
show: true,
top: 50,
right: 50,
itemGap: 20
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
return params[0].name + '<br>' + '费用:' + params[0].value + '元'
}
},
grid: {
left: '5%',
right: '5%',
bottom: '5%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: data.name,
axisTick: {
alignWithLabel: true // 刻度线是否与标签对齐默认false
},
// 设置 X 轴线条粗细
axisLine: {
lineStyle: {
width: 1, // 根据需求调整数值大小,单位是像素
color: '#999'
}
}
}
],
yAxis: [
{
type: 'value',
// min: 1, // 设置 y 轴的最小值为 0
// max: 16, // 设置 y 轴的最大值为 100
// interval: 1, //设置y轴刻度间隔
axisTick: {
show: true // 默认为true如果要隐藏则改为 false
},
axisLine: {
show: true,
lineStyle: {
width: 1,
color: '#999'
}
}
}
],
series: [
{
data: data.value1,
type: 'bar',
barWidth: 10, // 根据需求调整数值大小,单位是像素
itemStyle: {
// 此处可以是一个固定颜色值,也可以是一个回调函数根据数据动态计算颜色
color: function (params) {
return '#2283cf' // 数据在50到99之间为蓝色
}
}
}
],
// 添加点击事件的处理函数
emphasis: {
// itemStyle: {
// color: '#2283cf',
// barWidth: 20 // 根据需求调整数值大小,单位是像素
// },
barWidth: 24 // 根据需求调整数值大小,单位是像素
}
}
myChart.setOption(option)
}
const drawLine = (data) => {
if (document.getElementById('chartLine') === null) {
return
}
echarts.dispose(document.getElementById('chartLine'))
const myChart = echarts.init(document.getElementById('chartLine'))
const option = {
grid: {
left: '5%',
right: '5%',
bottom: '5%',
containLabel: true
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
return params[0].name + '<br>' + '费用:' + params[0].value + '元'
}
},
xAxis: {
type: 'category',
data: data.name,
axisTick: {
alignWithLabel: true
},
axisLine: {
lineStyle: {
width: 1,
color: '#999'
}
}
},
yAxis: {
type: 'value',
// min: 1, // 设置 y 轴的最小值为 0
// // max: 16, // 设置 y 轴的最大值为 100
// interval: 1, //设置y轴刻度间隔
axisTick: {
show: true
},
axisLine: {
show: true,
lineStyle: {
width: 1,
color: '#999'
}
}
},
series: [
{
data: data.value1,
type: 'line',
lineStyle: {
color: '#4181c9'
},
itemStyle: {
// 此处可以是一个固定颜色值,也可以是一个回调函数根据数据动态计算颜色
color: function (params) {
return '#2283cf' // 数据在50到99之间为蓝色
}
},
smooth: true,
symbol: 'emptyCircle',
areaStyle: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: 'rgba(65,129,201, 0.70)'
},
{
offset: 1,
color: 'rgba(65,129,201, 0.10)'
}
],
false
),
shadowColor: 'rgba(65,129,201, 0.10)',
shadowBlur: 10
}
}
]
}
myChart.setOption(option)
}
const currentType = ref('就医费用柱状图')
const handleRadioChange = (type) => {
currentType.value = type
switch (type) {
case '就医费用柱状图':
drawBar(chartData.value)
break
case '就医费用折线图':
drawLine(chartData.value)
break
default:
break
}
}
getPersonList()
</script>