<template>
|
<el-row class="control_rate_container">
|
<el-col :span="24" class="card_box card_box_search">
|
<el-form :model="searchForm" size="small" inline>
|
<el-form-item label="查询日期">
|
<el-date-picker
|
v-model="searchForm.dates"
|
type="daterange"
|
unlink-panels
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
:clearable="false"
|
/>
|
</el-form-item>
|
<el-form-item label="透析龄">
|
<el-select v-model="searchForm.medMonth" placeholder="透析龄">
|
<el-option label="全部" :value="0" />
|
<el-option label=">=三个月" :value="1" />
|
<el-option label="<三个月" :value="2" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="转归状态">
|
<el-select v-model="searchForm.isInState" placeholder="转归状态">
|
<el-option label="不限" :value="0" />
|
<el-option label="在院" :value="1" />
|
<el-option label="转出" :value="2" />
|
</el-select>
|
</el-form-item>
|
<el-form-item v-if="!isBloodPressure" label="标准值设定" prop="">
|
<el-row>
|
<span :span="8">
|
<el-input style="width: 150px" v-model="searchForm.limitBottom" @input="limitBottomInp"></el-input>
|
</span>
|
<span :span="8">≤标准值≤</span>
|
<span :span="8">
|
<el-input style="width: 150px" v-model="searchForm.limitTop" @input="limitTopInp"></el-input>
|
</span>
|
</el-row>
|
</el-form-item>
|
<template v-else>
|
<el-form-item label="收缩压标准值设定" prop="">
|
<el-row>
|
<span :span="8">
|
<el-input style="width: 150px" v-model="searchForm.limitBottom" @input="limitBottomInp"></el-input>
|
</span>
|
<span :span="8">≤标准值≤</span>
|
<span :span="8">
|
<el-input style="width: 150px" v-model="searchForm.limitTop" @input="limitTopInp"></el-input>
|
</span>
|
</el-row>
|
</el-form-item>
|
<el-form-item label="舒张压标准值设定" prop="">
|
<el-row>
|
<span :span="8">
|
<el-input style="width: 150px" v-model="searchForm.limitBplBottom" @input="limitBottomInp2"></el-input>
|
</span>
|
<span :span="8">≤标准值≤</span>
|
<span :span="8">
|
<el-input style="width: 150px" v-model="searchForm.limitBplTop" @input="limitTopInp2"></el-input>
|
</span>
|
</el-row>
|
</el-form-item>
|
</template>
|
<el-form-item label="年龄标准值设定" prop="">
|
<el-row>
|
<span :span="8">
|
<el-input style="width: 150px" v-model="searchForm.limitAgeBottom" type="number"></el-input>
|
</span>
|
<span :span="8">≤标准值≤</span>
|
<span :span="8">
|
<el-input style="width: 150px" v-model="searchForm.limitAgeTop" type="number"></el-input>
|
</span>
|
</el-row>
|
</el-form-item>
|
<el-form-item label="是否只展示最后一次结果">
|
<el-switch v-model="searchForm.是否只展示最后一次结果" :active-value="1" :inactive-value="0" />
|
</el-form-item>
|
<el-form-item>
|
<el-button size="small" :loading="loading" @click="onClickSearch" type="success">
|
<el-icon><Search /></el-icon>
|
查询</el-button
|
>
|
|
<slot name="right"></slot>
|
</el-form-item>
|
|
<el-form-item>
|
<el-button type="primary" :loading="loading" @click="onClickExportExcel" size="small">
|
<el-icon><Link /></el-icon>
|
导出</el-button
|
>
|
</el-form-item>
|
</el-form>
|
</el-col>
|
<el-col :span="24" v-loading="loading">
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<div class="container_l" :style="{ height: tableHeight + 'px', 'min-height': '520px' }">
|
<div v-loading="loading" ref="myEchartsRef" style="height: 500px; width: 100%; padding-top: 10px"></div>
|
</div>
|
</el-col>
|
<el-col :span="12">
|
<div class="container_r" :style="{ height: tableHeight + 'px', 'min-height': '520px' }">
|
<div class="untested_patients_box" v-if="untestedPatients.length > 0">
|
<div class="untested_patients_header">未检测人员</div>
|
<div class="untested_patients_conter">
|
{{ untestedPatients.join('、') }}
|
</div>
|
</div>
|
<div class="status_type_nav">
|
<span
|
v-for="(item, index) in statusTypeOptions"
|
:key="index"
|
:class="[statusType === item.value ? 'select_type' : '']"
|
@click="onClickByStatusChange(item)"
|
>
|
{{ item.label }}
|
</span>
|
</div>
|
<el-table
|
v-if="tableHeight > 0"
|
v-loading="loading"
|
id="exportTbale"
|
:row-class-name="rowClassName"
|
:data="patTableData"
|
:height="untestedPatients.length > 0 ? tableHeight - 210 : tableHeight"
|
border
|
style="width: 100%"
|
>
|
<el-table-column prop="sampleDate" label="检验日期">
|
<template #default="scope">
|
{{ scope.row.sampleDate.substring(0, 11) }}
|
</template>
|
</el-table-column>
|
<el-table-column prop="patientName" label="患者姓名" />
|
<el-table-column prop="itemResult" :label="defaultNameAndUnit" />
|
</el-table>
|
</div>
|
</el-col>
|
</el-row>
|
</el-col>
|
</el-row>
|
</template>
|
|
<script lang="ts">
|
import { ElMessage } from 'element-plus';
|
import { defineComponent, reactive, toRefs, ref, onMounted, getCurrentInstance, watch } from 'vue';
|
import { storeToRefs } from 'pinia';
|
import { useUserInfo } from '/@/stores/userInfo';
|
import { formatDate } from '/@/utils/formatTime';
|
import { doStatByResult } from '/@/api/QC';
|
import * as echarts from 'echarts';
|
import { exportTableToExcel } from '/@/utils/Export2';
|
const stores = useUserInfo();
|
const { userInfos } = storeToRefs(stores);
|
const end = new Date();
|
const start = new Date();
|
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
|
interface IDefDatas {
|
title: string;
|
itemName: string;
|
defaultNameAndUnit: string;
|
subTit: string;
|
whereFrom?: Partial<{
|
itemName: string;
|
medMonth: number;
|
isInState: number;
|
statType: number;
|
limitBottom: string | number;
|
limitTop: string | number;
|
filterStyle: number;
|
dates: [Date, Date];
|
attendingDoctor: '';
|
是否只展示最后一次结果: 0 | 1;
|
}>;
|
isBloodPressure?: boolean;
|
}
|
export default defineComponent({
|
name: 'ControlRate',
|
setup() {
|
const { proxy } = getCurrentInstance() as any;
|
const myEchartsRef = ref();
|
|
const state = reactive({
|
loading: false,
|
tableHeight: 0,
|
title: '',
|
itemName: '',
|
defaultNameAndUnit: '',
|
subTit: '',
|
patList: [],
|
untestedPatients: [],
|
dabaio: true,
|
budabaio: false,
|
searchForm: {
|
itemName: '',
|
medMonth: 0,
|
isInState: 1,
|
statType: 0,
|
limitBottom: '',
|
limitTop: '',
|
// filterStyle: 0,
|
dates: [start, end],
|
attendingDoctor: '', // 主治医师
|
是否只展示最后一次结果: 0,
|
limitBplBottom: null,
|
limitBplTop: null,
|
limitAgeBottom: null,
|
limitAgeTop: null,
|
},
|
patTableData: [],
|
statusType: 0,
|
statusTypeOptions: [
|
{ label: '全部', value: 0 },
|
{ label: '达标', value: 1 },
|
{ label: '不达标', value: 2 },
|
],
|
doctorOptions: [],
|
isBloodPressure: false, // 是否是血压
|
});
|
|
// 监听 searchForm.limitBottom 的变化,确保 Vue 的双向绑定正常工作
|
// watch(() => state.searchForm.limitBottom, (newValue) => {
|
// if (newValue === '' || Number(newValue) < 0) {
|
// state.searchForm.limitBottom = '';
|
// } else {
|
// // @ts-ignore
|
// state.searchForm.limitBottom = Number(newValue);
|
// }
|
// });
|
|
const onClickByStatusChange = (item: { label: string; value: number }) => {
|
state.statusType = item.value;
|
if (item.value === 0) {
|
state.patTableData = [...state.patList];
|
} else if (item.value === 1) {
|
state.patTableData = state.patList.filter((e) => e.是否达标);
|
} else if (item.value === 2) {
|
state.patTableData = state.patList.filter((e) => !e.是否达标);
|
}
|
};
|
|
/** 查询 */
|
const onClickSearch = async () => {
|
if (isNaN(+state.searchForm.limitBottom) || isNaN(+state.searchForm.limitTop)) return ElMessage.warning('标准值仅可为大于等于0的数值');
|
if (+state.searchForm.limitBottom < 0 || +state.searchForm.limitTop < 0) return ElMessage.warning('标准值不能小于0');
|
state.loading = true;
|
try {
|
await getDatas();
|
} finally {
|
state.loading = false;
|
}
|
};
|
|
/** 导出 */
|
const onClickExportExcel = () => {
|
exportTableToExcel('#exportTbale', state.title);
|
};
|
|
const setTableHeight = () => {
|
let height = document.documentElement.clientHeight;
|
|
const navDom = document.querySelector('.layout-header');
|
if (navDom) {
|
height -= navDom.scrollHeight;
|
}
|
|
const demoFormDom = document.querySelector('.card_box_search');
|
|
if (demoFormDom) {
|
height -= demoFormDom.scrollHeight;
|
}
|
|
height = height - 40;
|
state.tableHeight = height;
|
};
|
|
const initCompData = async (objData: IDefDatas) => {
|
state.loading = true;
|
try {
|
const { title, itemName, defaultNameAndUnit, subTit, whereFrom, isBloodPressure } = objData;
|
state.title = title;
|
state.itemName = itemName;
|
state.defaultNameAndUnit = defaultNameAndUnit;
|
state.subTit = subTit;
|
state.isBloodPressure = !!isBloodPressure;
|
if (whereFrom) {
|
Object.keys(whereFrom).forEach((k) => {
|
state.searchForm[k] = whereFrom[k];
|
});
|
}
|
const primaseFuns = [getDatas()];
|
await Promise.all(primaseFuns);
|
await getDatas();
|
} catch (error) {
|
// ElMessage.error('系统异常,请联系管理员:' + error);
|
console.error('xxxxxxxxxxx:', error);
|
} finally {
|
state.loading = false;
|
}
|
};
|
|
const getDatas = async () => {
|
const params = {
|
clientCode: userInfos.value.clientCode,
|
dateBegin: formatDate(state.searchForm.dates[0], 'YYYY-mm-dd') + ' 00:00:00',
|
dateEnd: formatDate(state.searchForm.dates[1], 'YYYY-mm-dd') + ' 23:59:59',
|
itemName: state.itemName,
|
medMonth: state.searchForm.medMonth,
|
isInState: state.searchForm.isInState,
|
statType: state.searchForm.statType,
|
limitBottom: state.searchForm.limitBottom,
|
limitTop: state.searchForm.limitTop,
|
// filterStyle: state.searchForm.filterStyle,
|
attendingDoctor: state.searchForm.attendingDoctor,
|
是否只展示最后一次结果: state.searchForm.是否只展示最后一次结果,
|
limitBplBottom: state.searchForm.limitBplBottom,
|
limitBplTop: state.searchForm.limitBplTop,
|
limitAgeBottom: state.searchForm.limitAgeBottom,
|
limitAgeTop: state.searchForm.limitAgeTop,
|
};
|
const { data } = await doStatByResult(params);
|
state.defaultNameAndUnit = data.itemUnit ? `${state.subTit}(${data.itemUnit})` : state.defaultNameAndUnit;
|
state.patList = data.statItemResults.slice().sort(compareDates);
|
if (state.statusType === 0) {
|
state.patTableData = [...state.patList];
|
} else if (state.statusType === 1) {
|
state.patTableData = state.patList.filter((e) => e.是否达标);
|
} else if (state.statusType === 2) {
|
state.patTableData = state.patList.filter((e) => !e.是否达标);
|
}
|
state.untestedPatients = data.未检测患者列表;
|
initEcharts(
|
data.statDetail.map((v) => {
|
v.tooltip = {
|
formatter: '{a}<br />{b}: ({c})({d}%)',
|
};
|
return v;
|
})
|
);
|
};
|
|
const initEcharts = (listdata: any) => {
|
//先获取Dom上的实例
|
if (echarts) {
|
let myChart = echarts?.getInstanceByDom(proxy.$refs.myEchartsRef as HTMLDivElement);
|
//然后判断实例是否存在,如果不存在,就创建新实例
|
if (myChart == null) {
|
myChart = echarts.init(proxy.$refs.myEchartsRef as HTMLDivElement);
|
}
|
const option = {
|
title: {
|
text: state.title,
|
subtext: `${formatDate(state.searchForm.dates[0], 'YYYY-mm-dd')}-${formatDate(state.searchForm.dates[1], 'YYYY-mm-dd')}`,
|
left: 'center',
|
},
|
tooltip: {
|
trigger: 'item',
|
},
|
legend: {
|
orient: 'vertical',
|
left: 'top',
|
},
|
color: ['#5470c6', '#fc8251', '#91cd77', '#ef6567', '#f9c956', '#75bedc'],
|
series: [
|
{
|
name: state.subTit,
|
type: 'pie',
|
radius: '70%',
|
// avoidLabelOverlap: false,
|
label: {
|
show: true,
|
overflow: 'break',
|
position: 'outer',
|
alignTo: 'none',
|
edgeDistance: '25%',
|
bleedMargin: 10,
|
distanceToLabelLine: 5,
|
formatter(param) {
|
return param.name + ' (' + param.value + ')' + ' (' + param.percent * 1 + '%)';
|
},
|
},
|
emphasis: {
|
itemStyle: {
|
shadowBlur: 10,
|
shadowOffsetX: 0,
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
},
|
},
|
labelLine: {
|
show: false,
|
},
|
data: listdata,
|
},
|
],
|
};
|
myChart.setOption(option);
|
myChart.on('legendselectchanged', function (event) {
|
// @ts-ignore
|
if (event.name === '不达标的患者人数') {
|
state.dabaio = !state.dabaio;
|
// @ts-ignore
|
} else if (event.name === '达标患者人数') {
|
state.budabaio = !state.budabaio;
|
}
|
// 在这里可以根据需要处理点击图例的逻辑
|
});
|
}
|
};
|
|
const compareDates = (a, b) => {
|
const dateA = new Date(a.sampleDate);
|
const dateB = new Date(b.sampleDate);
|
// @ts-ignore
|
return dateA - dateB; // 升序排序
|
};
|
|
const rowClassName = ({ row }) => {
|
if (row.是否达标 === state.dabaio && row.是否达标 === state.budabaio) {
|
return 'hidden-row';
|
}
|
return '';
|
};
|
|
const limitBottomInp = () => {
|
let newValue = state.searchForm.limitBottom;
|
|
// 过滤掉非法字符,允许数字和小数点
|
newValue = newValue.replace(/[^0-9.]/g, '');
|
|
// 确保第一个字符不是小数点
|
if (newValue.startsWith('.')) {
|
newValue = '0' + newValue;
|
}
|
|
// 确保只有一个小数点
|
newValue = newValue.replace(/(\..*)\./g, '$1');
|
|
// 如果值为空或小于等于0,清空输入框
|
if (newValue !== '' && parseFloat(newValue) < 0) {
|
newValue = '';
|
}
|
state.searchForm.limitBottom = newValue;
|
};
|
|
const limitTopInp = () => {
|
let newValue = state.searchForm.limitTop;
|
|
// 过滤掉非法字符,允许数字和小数点
|
newValue = newValue.replace(/[^0-9.]/g, '');
|
|
// 确保第一个字符不是小数点
|
if (newValue.startsWith('.')) {
|
newValue = '0' + newValue;
|
}
|
|
// 确保只有一个小数点
|
newValue = newValue.replace(/(\..*)\./g, '$1');
|
|
// 如果值为空或小于等于0,清空输入框
|
if (newValue !== '' && parseFloat(newValue) < 0) {
|
newValue = '';
|
}
|
state.searchForm.limitTop = newValue;
|
};
|
|
const limitBottomInp2 = () => {
|
let newValue = state.searchForm.limitBplBottom;
|
|
// 过滤掉非法字符,允许数字和小数点
|
newValue = newValue.replace(/[^0-9.]/g, '');
|
|
// 确保第一个字符不是小数点
|
if (newValue.startsWith('.')) {
|
newValue = '0' + newValue;
|
}
|
|
// 确保只有一个小数点
|
newValue = newValue.replace(/(\..*)\./g, '$1');
|
|
// 如果值为空或小于等于0,清空输入框
|
if (newValue !== '' && parseFloat(newValue) < 0) {
|
newValue = '';
|
}
|
state.searchForm.limitBplBottom = newValue;
|
};
|
|
const limitTopInp2 = () => {
|
let newValue = state.searchForm.limitBplTop;
|
|
// 过滤掉非法字符,允许数字和小数点
|
newValue = newValue.replace(/[^0-9.]/g, '');
|
|
// 确保第一个字符不是小数点
|
if (newValue.startsWith('.')) {
|
newValue = '0' + newValue;
|
}
|
|
// 确保只有一个小数点
|
newValue = newValue.replace(/(\..*)\./g, '$1');
|
|
// 如果值为空或小于等于0,清空输入框
|
if (newValue !== '' && parseFloat(newValue) < 0) {
|
newValue = '';
|
}
|
state.searchForm.limitBplTop = newValue;
|
};
|
|
onMounted(() => {
|
setTableHeight();
|
});
|
|
return {
|
...toRefs(state),
|
myEchartsRef,
|
rowClassName,
|
onClickSearch,
|
onClickExportExcel,
|
initCompData,
|
onClickByStatusChange,
|
limitBottomInp,
|
limitTopInp,
|
limitBottomInp2,
|
limitTopInp2,
|
};
|
},
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.control_rate_container {
|
.card_box {
|
padding: 15px;
|
background: #fff;
|
padding-bottom: 0;
|
&.card_box_search {
|
padding-bottom: 0;
|
margin-bottom: 10px;
|
}
|
}
|
.sum_count {
|
padding-right: 20px;
|
line-height: 40px;
|
font-size: 14px;
|
font-weight: bold;
|
text-align: right;
|
color: #67c23a;
|
}
|
|
.container_l,
|
.container_r {
|
background: #fff;
|
overflow-y: auto;
|
.untested_patients_box {
|
background-color: #fff;
|
padding: 10px;
|
.untested_patients_header {
|
text-align: center;
|
font-weight: bold;
|
background: #409eff;
|
color: #fff;
|
line-height: 40px;
|
}
|
.untested_patients_conter {
|
padding: 20px;
|
max-height: 200px;
|
overflow: hidden;
|
overflow-y: auto;
|
}
|
}
|
}
|
.status_type_nav {
|
display: flex;
|
align-items: center;
|
padding-top: 20px;
|
span {
|
background: #fff;
|
color: #333;
|
padding: 8px 14px;
|
font-size: 14px;
|
border-radius: 5px 5px 0 0;
|
box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.12);
|
transition: 0.3s;
|
&:hover {
|
cursor: pointer;
|
background: #92c3f5;
|
color: #fff;
|
}
|
&.select_type {
|
background-color: #409eff;
|
color: #fff;
|
}
|
}
|
}
|
}
|
.xuedanbai {
|
.el-table .hidden-row {
|
display: none;
|
}
|
.chaxun {
|
padding-left: 10px;
|
padding-top: 10px;
|
padding-bottom: -10px;
|
background: #ffffff;
|
box-shadow: -1px 1px 6px 1px rgba(207, 212, 218, 0.5);
|
border-radius: 0px 4px 4px 4px;
|
}
|
.bodyclass {
|
background: #ffffff;
|
box-shadow: -1px 1px 6px 1px rgba(207, 212, 218, 0.5);
|
border-radius: 0px 4px 4px 4px;
|
}
|
/*在谷歌下移除input[number]的上下箭头*/
|
.inputNumber input[type='number']::-webkit-outer-spin-button,
|
.inputNumber input[type='number']::-webkit-inner-spin-button {
|
-webkit-appearance: none !important;
|
margin: 0;
|
}
|
/*在firefox下移除input[number]的上下箭头*/
|
.inputNumber input[type='number'] {
|
-moz-appearance: textfield;
|
}
|
}
|
</style>
|