update
1.新需求2025.9.19新需求: 去掉"健康监测"副屏, 修改后健康终端报警点击查看详情弹出告警记录分页列表; 去掉【体检人数统计】【体检数据】【健康打卡数据】,增加【心血管监测】模块功能,【心血管监测】功能将原心血管监测大屏上的内容整理并移动到急救服务平台大屏中; 员工求助时,地图中推荐两个医院、两个健康小屋、两个AED坐标信息,并按距离排序,体现距离远近顺序; 地图中油田医院、健康小屋等各个图例,显示总数信息; 救护车坐标信息维护,并在大屏上标记; 右上角"增加【救助信息】板块, 当出现应急弹窗后或从今日应急选中应急事件 , 该板块需展示应急事件的相关信息(开发中);
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
<div v-show="false" id="panel"></div>
|
||||
<div class="map-legend">
|
||||
<div v-for="(item, i) in legendList" :key="i" class="legend-item">
|
||||
<div :style="{ color: item.color }"><img :src="item.img" alt="" class="legend-img" /> {{ item.text }} </div>
|
||||
<div :style="{ color: item.color }"><img :src="item.img" alt="" class="legend-img" /> {{ item.text }}({{ numList[i] }}) </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -64,38 +64,17 @@
|
||||
</div>
|
||||
|
||||
<div class="hospital-list" :class="[themeType]" v-if="showMapBottom">
|
||||
<!-- <div class="hospital-item" v-for="(item, index) in hospitalList" :key="index" @click.stop="showDrivingLine(item)">-->
|
||||
<!-- <div>{{ item?.name }}</div>-->
|
||||
<!-- <div>相距{{ item?.distance }}</div>-->
|
||||
<!-- <div>驾车大约{{ item?.driveTime }}</div>-->
|
||||
<!-- </div>-->
|
||||
<div class="map-bottom">
|
||||
<div>
|
||||
<div class="title">关爱联络员</div>
|
||||
<template v-if="mapBottomInfo?.careLiaisonName && mapBottomInfo?.careLiaisonPhone">
|
||||
<div>{{ mapBottomInfo?.careLiaisonName }}</div>
|
||||
<div>{{ mapBottomInfo?.careLiaisonPhone }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="no-data"> 该员工暂未设置关爱联络员 <img :src="pointPng" alt="" /></div>
|
||||
</template>
|
||||
</div>
|
||||
<div>
|
||||
<div class="title">急救人员</div>
|
||||
<template v-if="mapBottomInfo?.lifeguardName && mapBottomInfo?.lifeguardPhone">
|
||||
<div>{{ mapBottomInfo?.lifeguardName }}</div>
|
||||
<div>{{ mapBottomInfo?.lifeguardPhone }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="no-data"> 该员工暂未设置急救人员 <img :src="pointPng" alt="" /></div>
|
||||
</template>
|
||||
<img :src="noLocationPng" alt="" />
|
||||
</div>
|
||||
<div> 未获取到当前救助人员的位置信息 </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, ref, watch } from 'vue';
|
||||
import { nextTick, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { infoContent, infoContent1, infoContent4, legendList, tabList } from '/@/views/indexSun/indexSun.ts';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { innerLineLight, outerLineOption } from '/@/assets/mapUtils/mapConstant.ts';
|
||||
@@ -106,8 +85,11 @@
|
||||
import { earlyWarning } from '/@/utils/busConstant.ts';
|
||||
import { useTheme } from '/@/hooks/theme/useTheme.ts';
|
||||
import { RedoOutlined } from '@ant-design/icons-vue';
|
||||
import pointPng from '/@/assets/indexSun/point.png';
|
||||
import { useUserStore } from '/@/store/modules/user.ts';
|
||||
import noLocationPng from '/@/assets/images/map/noLocation.png';
|
||||
|
||||
const useDetail = useDetailStore();
|
||||
const useStore = useUserStore();
|
||||
const { themeType } = useTheme();
|
||||
const list = ref(tabList);
|
||||
const currentIndex = ref(0);
|
||||
@@ -116,6 +98,8 @@
|
||||
start: '',
|
||||
end: '',
|
||||
});
|
||||
// 1 aed 2 健康小屋 3 油田医院 4 救护车
|
||||
const numList = reactive([useStore.getTypeThree, useStore.getTypeOne, useStore.getTypeFive, useStore.getTypeFour]);
|
||||
const props = defineProps({
|
||||
//是否展示底部统计
|
||||
showFooter: {
|
||||
@@ -139,16 +123,11 @@
|
||||
return [];
|
||||
},
|
||||
},
|
||||
mapBottomInfo: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
showMapBottom: {
|
||||
type: Boolean,
|
||||
default: () => false,
|
||||
},
|
||||
});
|
||||
const useDetail = useDetailStore();
|
||||
const showRoutePanel = ref(false);
|
||||
const panelTitle = ref();
|
||||
const level = ref(0);
|
||||
@@ -312,6 +291,16 @@
|
||||
async function getMapData(type, params = { type: '' }) {
|
||||
try {
|
||||
const { code, result } = await mapApiSwitch(type, params);
|
||||
if (!params.type) {
|
||||
// aed
|
||||
useStore.setTypeFour(result ? result.filter((item: any) => item?.type === '4').length : 0);
|
||||
// 健康小屋
|
||||
useStore.setTypeThree(result ? result.filter((item: any) => item?.type === '3').length : 0);
|
||||
// 油田医院
|
||||
useStore.setTypeOne(result ? result.filter((item: any) => item?.type === '1').length : 0);
|
||||
// 救护车
|
||||
useStore.setTypeFive(result ? result.filter((item: any) => item?.type === '5').length : 0);
|
||||
}
|
||||
if (code == 200) {
|
||||
if (Array.isArray(result) && result.length > 0) {
|
||||
Map.createOverlay(
|
||||
@@ -403,6 +392,10 @@
|
||||
changeTab(list.value[currentIndex.value === 4 ? 0 : currentIndex.value], currentIndex.value);
|
||||
emits('showRestB');
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
resetMap,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@@ -767,31 +760,28 @@
|
||||
|
||||
.map-bottom {
|
||||
border-radius: 10px;
|
||||
background: #073148;
|
||||
width: 570px;
|
||||
height: 100px;
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
line-height: 30px;
|
||||
|
||||
> div {
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
.title {
|
||||
color: #45ffa1;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
|
||||
img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
&:nth-child(1) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0 0 12px;
|
||||
img {
|
||||
width: 100px;
|
||||
height: 70px;
|
||||
}
|
||||
}
|
||||
&:nth-child(2) {
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
text-align: center;
|
||||
background: rgba(242, 68, 57, 0.3);
|
||||
color: #f24439;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<Dialog class="index-modal" :openVis="visible" width="60%" :title="dialogTitle" @close="handleClose" :maskClosable="false">
|
||||
<template #container>
|
||||
<div v-if="useForm" class="form-container">
|
||||
<div v-if="useForm && firstForm.length > 0" class="form-container">
|
||||
<Form :model="formRecord" v-bind="formItemLayout">
|
||||
<slot name="searchFirst"></slot>
|
||||
<a-form-item v-for="(item, index) in firstForm" :label="item.label" :key="index">
|
||||
<a-input :placeholder="item.placeholder" v-if="item.type == 'input'" v-model:value="formRecord[item.field]" />
|
||||
<a-form-item v-for="(item, index) in firstForm" :label="item?.label" :key="index">
|
||||
<a-input :placeholder="item?.placeholder" v-if="item?.type == 'input'" v-model:value="formRecord[item?.field]" />
|
||||
<a-select
|
||||
v-if="item.type == 'select'"
|
||||
:placeholder="item.placeholder"
|
||||
v-model:value="formRecord[item.field]"
|
||||
:options="item.options"
|
||||
v-if="item?.type == 'select'"
|
||||
:placeholder="item?.placeholder"
|
||||
v-model:value="formRecord[item?.field]"
|
||||
:options="item?.options"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="单位" v-if="needDept">
|
||||
@@ -48,7 +48,11 @@
|
||||
:key="visible"
|
||||
:columns="props.column"
|
||||
:apiParams="formState"
|
||||
/>
|
||||
>
|
||||
<template #bodyCell="{ column, record, index, text }">
|
||||
<slot name="bodyCell" v-bind="{ column, record, index, text } || {}"></slot>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -60,6 +64,7 @@
|
||||
import BasicTable from '/@/components/secondaryScreen/secondMap/components/basicTable/BasicTable.vue';
|
||||
import { allSecondaryDepartsApi, getThreeDepartByOrgCodeApi } from '/@/views/indexSun/indexSun.api.ts';
|
||||
import dayjs from 'dayjs';
|
||||
import { isFunction } from '/@/utils/is.ts';
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
@@ -307,6 +312,7 @@
|
||||
}
|
||||
defineExpose({
|
||||
openDialog,
|
||||
closeDialog,
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -19,6 +19,8 @@ enum Api {
|
||||
getSecondaryDepartment = '/sys/sysDepart/allSecondaryDeparts',
|
||||
twoRN = '/health-emergency/emergency/LargeScreenNew/loveTrend',
|
||||
nearResources = '/health-emergency/emergency/LargeScreenNew/nearResources',
|
||||
todayEmergencyList = '/health-emergency/emergency/LargeScreenNew/todayEmergencyList',
|
||||
healthArchives = '/health-emergency/emergency/LargeScreenNew/healthArchives',
|
||||
}
|
||||
|
||||
export const statisticsNewApi = (params: any) => post(Api.statisticsNew, params);
|
||||
@@ -31,6 +33,8 @@ export const threeRApi = (params: any) => post(Api.threeR, params);
|
||||
export const twoRApi = (params: any) => post(Api.twoR, params);
|
||||
export const twoRNApi = (params: any) => get(Api.twoRN, params);
|
||||
export const nearResourcesApi = (params: any) => get(Api.nearResources, params);
|
||||
export const todayEmergencyListApi = (params: any) => post(Api.todayEmergencyList, params);
|
||||
export const healthArchivesApi = (params: any) => get(Api.healthArchives, params);
|
||||
|
||||
export const threeRModalApi = (params: any) => post(Api.threeRModal, params);
|
||||
export const twoRModal1Api = (params: any) => post(Api.twoRModal1, params);
|
||||
|
||||
@@ -816,3 +816,62 @@ export const twoRNewForm = [
|
||||
defaultValue: '',
|
||||
},
|
||||
];
|
||||
|
||||
export const oneRNewColumns = [
|
||||
{
|
||||
title: '单位',
|
||||
dataIndex: 'departName',
|
||||
key: 'departName',
|
||||
},
|
||||
{
|
||||
title: '部门',
|
||||
dataIndex: 'orgName',
|
||||
key: 'orgName',
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'realName',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '性别',
|
||||
dataIndex: 'sex',
|
||||
key: 'sex',
|
||||
customRender: ({ text }) => {
|
||||
if (text == '1') {
|
||||
return '女';
|
||||
} else {
|
||||
return '男';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
},
|
||||
{
|
||||
title: '应急方式',
|
||||
dataIndex: 'emergencyType',
|
||||
key: 'emergencyType',
|
||||
customRender: ({ text }) => {
|
||||
switch (text) {
|
||||
case '0':
|
||||
return '120';
|
||||
case '1':
|
||||
return '紧急求助';
|
||||
case '2':
|
||||
return '云坐席';
|
||||
case '3':
|
||||
return '终端报警';
|
||||
default:
|
||||
return '-';
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'cz',
|
||||
key: 'cz',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
<template>
|
||||
<div class="one-r-box">
|
||||
<div class="title">
|
||||
<div>救助信息</div>
|
||||
|
||||
<!-- <div class="top-button-d">-->
|
||||
<a-button size="small" class="title-button title-button-one" @click="handleView">今日应急</a-button>
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<template v-if="props.userData && Object.keys(props.userData).length > 0">
|
||||
<div class="basic-info">
|
||||
<span>{{ userData.realName }}</span>
|
||||
<a-button v-if="props.userData && Object.keys(props.userData).length > 0" size="small" class="title-button" @click="handleArchives"
|
||||
>健康档案</a-button
|
||||
>
|
||||
</div>
|
||||
<div class="emer-top-d-outer">
|
||||
<div class="emer-top-d">
|
||||
<div style="display: flex; color: #ffffff">
|
||||
<div class="emer-item-d">
|
||||
<div>性别/年龄:</div>
|
||||
<div class="emer-item-d-t">{{ getSex(userData.sex) }}/{{ userData.age || '-' }}</div>
|
||||
</div>
|
||||
<div class="emer-item-d">
|
||||
<div>应急方式:</div>
|
||||
<div class="emer-item-d-t">{{ getTypeName(userData.emergencyType) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; color: #ffffff">
|
||||
<div class="emer-item-d">
|
||||
<div>单位:</div>
|
||||
<div class="emer-item-d-t">{{ userData.departName }}</div>
|
||||
</div>
|
||||
<div class="emer-item-d">
|
||||
<div>手机号码:</div>
|
||||
<div class="emer-item-d-t">{{ userData.phone }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="emer-item-d">
|
||||
<div>当前位置:</div>
|
||||
<div class="emer-item-d-t" :style="{ color: !userData?.lon || !userData?.lat ? '#F24439' : '' }">
|
||||
{{ !userData?.lon || !userData?.lat ? '未获取到位置信息' : locationInfo }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title title-two">
|
||||
<span>联系人</span>
|
||||
<a-button size="small" class="title-button">紧急联系人</a-button>
|
||||
</div>
|
||||
<div class="emer-info-outer">
|
||||
<div class="emer-info">
|
||||
<div>
|
||||
<div class="emer-info-title">关爱联络员</div>
|
||||
<template v-if="props.userData?.careLiaisonName && props.userData?.careLiaisonPhone">
|
||||
<div style="color: #ffffff">{{ props.userData?.careLiaisonName }}</div>
|
||||
<div style="color: #ffffff">{{ props.userData?.careLiaisonPhone }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="no-data"> 该员工暂未设置关爱联络员 <img :src="pointPng" alt="" /></div>
|
||||
</template>
|
||||
</div>
|
||||
<div>
|
||||
<div class="emer-info-title">急救人员</div>
|
||||
<template v-if="props.userData?.lifeguardName && props.userData?.lifeguardPhone">
|
||||
<div style="color: #ffffff">{{ props.userData?.lifeguardName }}</div>
|
||||
<div style="color: #ffffff">{{ props.userData?.lifeguardPhone }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="no-data"> 该员工暂未设置急救人员 <img :src="pointPng" alt="" /></div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Empty class="empty-d" :description="'暂无救助人员'" />
|
||||
</template>
|
||||
|
||||
<Dialog :openVis="openInfo" width="30%" title="健康报警员工信息" @close="handlePoliceClose">
|
||||
<template #container>
|
||||
<div class="police-con" :class="[themeType]">
|
||||
<Row style="font-size: 14px; font-weight: bold"> 个人信息 </Row>
|
||||
<Row>
|
||||
<Col :span="8">姓名:{{ archives?.realName || '--' }}</Col>
|
||||
<Col :span="8">性别:{{ archives?.sex_dictText || '--' }}</Col>
|
||||
<Col :span="8">年龄:{{ archives?.age || '--' }}</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col :span="8">二级单位:{{ archives?.orgName2 || '--' }}</Col>
|
||||
<Col :span="8">部门:{{ archives?.orgName || '--' }}</Col>
|
||||
<Col :span="8">手机号码:{{ archives?.phone || '--' }}</Col>
|
||||
</Row>
|
||||
<Row style="font-size: 14px; font-weight: bold"> 健康信息 </Row>
|
||||
<Row> 异常事件:{{ archives?.eventType_dictText || '--' }} </Row>
|
||||
<Row>
|
||||
<Col :span="8">异常值:{{ archives?.dataValue || '--' }}</Col>
|
||||
<Col :span="16">发生时间:{{ archives?.warnTime || '--' }}</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import pointPng from '/@/assets/indexSun/point.png';
|
||||
import { Col, Empty, Row } from 'ant-design-vue';
|
||||
import { Map } from '/@/assets/mapUtils/map.ts';
|
||||
import { ref, watch } from 'vue';
|
||||
import Dialog from '/@/components/dialog/Dialog.vue';
|
||||
import { useTheme } from '/@/hooks/theme/useTheme.ts';
|
||||
import { healthArchivesApi } from '/@/views/indexSun/indexSun.api.ts';
|
||||
|
||||
const props = defineProps({
|
||||
userData: { type: Object, default: () => {} },
|
||||
});
|
||||
const { themeType } = useTheme();
|
||||
const locationInfo = ref<string>('');
|
||||
|
||||
const emit = defineEmits(['handleView']);
|
||||
const openInfo = ref<boolean>(false);
|
||||
const archives = ref<object>({});
|
||||
|
||||
watch(
|
||||
() => props.userData,
|
||||
(v) => {
|
||||
locationInfo.value = '';
|
||||
if (v && v?.lat && v?.lat) {
|
||||
getAddress();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function handleView() {
|
||||
emit('handleView');
|
||||
}
|
||||
function handleArchives() {
|
||||
healthArchivesApi({ userId: props.userData?.userId })
|
||||
.then((res) => {})
|
||||
.catch((err) => {});
|
||||
}
|
||||
|
||||
function handlePoliceClose() {
|
||||
archives.value = {};
|
||||
}
|
||||
|
||||
function getTypeName(type: string) {
|
||||
switch (type) {
|
||||
case '0':
|
||||
return '120';
|
||||
case '1':
|
||||
return '紧急求助';
|
||||
case '2':
|
||||
return '云坐席';
|
||||
case '3':
|
||||
return '终端报警';
|
||||
default:
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
function getSex(type: string) {
|
||||
switch (type) {
|
||||
case '1':
|
||||
return '女';
|
||||
case '2':
|
||||
return '男';
|
||||
default:
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
function getAddress() {
|
||||
Map.getAddressByPoint([props.userData?.lon, props.userData?.lat])
|
||||
.then((res: string) => {
|
||||
locationInfo.value = res;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
locationInfo.value = '';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.one-r-box {
|
||||
background: rgba(8, 75, 100, 0.2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
letter-spacing: 0px;
|
||||
.title {
|
||||
height: 40px;
|
||||
border-radius: 14px 14px 0 0;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
letter-spacing: 2px;
|
||||
color: #ffffff;
|
||||
line-height: 40px;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: linear-gradient(to right, rgba(8, 75, 100, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.title-two {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.title-button {
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
font-size: 10px !important;
|
||||
padding: 2px 10px;
|
||||
background: radial-gradient(ellipse at center, #082147 0%, #08254c 55%, #085faa 100%);
|
||||
border-radius: 8px;
|
||||
border: 1px solid #55d3ff;
|
||||
}
|
||||
|
||||
.title-button-one {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
//.top-button-d {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// button {
|
||||
// &:nth-child(1) {
|
||||
// margin-right: 10px;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
.basic-info {
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
padding: 3px 30px 0;
|
||||
justify-content: space-between;
|
||||
|
||||
span {
|
||||
color: #c9daff;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.emer-top-d-outer {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.emer-top-d {
|
||||
color: #ffffff;
|
||||
padding: 10px 10px;
|
||||
border-radius: 2px;
|
||||
background: #152657;
|
||||
|
||||
.emer-item-d {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 2px 0;
|
||||
|
||||
> div {
|
||||
&:nth-child(1) {
|
||||
color: #82a9ef;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
color: #c9daff;
|
||||
}
|
||||
}
|
||||
|
||||
.emer-item-d-t {
|
||||
white-space: wrap;
|
||||
word-break: break-all;
|
||||
flex: 1;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.emer-info-outer {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.emer-info {
|
||||
border-radius: 2px;
|
||||
background: #152657;
|
||||
height: 100px;
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
line-height: 30px;
|
||||
> div {
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
.emer-info-title {
|
||||
color: #45ffa1;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
color: #ffffff;
|
||||
|
||||
img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-d {
|
||||
padding: 10px 0;
|
||||
:deep(.ant-empty-image) {
|
||||
margin-top: 5px;
|
||||
height: 30px;
|
||||
}
|
||||
:deep(.ant-empty-description) {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,468 @@
|
||||
<template>
|
||||
<div class="two-l-box">
|
||||
<div class="title">
|
||||
<span>心血管监测</span>
|
||||
</div>
|
||||
<div style="flex: 1" class="content">
|
||||
<div class="content-search content-search-select">
|
||||
<a-select v-model:value="selectValue" class="type-select" :options="selectOptions" @change="getData">
|
||||
<a-select-option value="全部数据">全部数据</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-model:value="selectValue1" class="type-select" :options="selectOption1" @change="getData" />
|
||||
</div>
|
||||
<div class="content-search content-search-new">
|
||||
<div class="type-time">
|
||||
<div
|
||||
v-for="(item, index) in tabList"
|
||||
@click="clickChooseType(item.value)"
|
||||
:class="[chooseType === item.value ? 'selected' : 'no-selected']"
|
||||
:key="`tab-lef-list-key-${index}`"
|
||||
>
|
||||
{{ item.label }}
|
||||
<div>
|
||||
<div v-if="chooseType === item.value" class="triangle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; height: 100%; padding: 5px; justify-content: center">
|
||||
<div class="item-title" style="width: 99%">
|
||||
<div class="title chart-title" style="display: flex; font-weight: normal !important">
|
||||
<div> <img :src="imgList[chooseType]" alt="" />{{ tabList[chooseType].label }}</div>
|
||||
<div v-if="[0, 1].includes(chooseType)"> 参考范围: {{ tabList[chooseType].tips }} </div>
|
||||
</div>
|
||||
<div style="height: 210px">
|
||||
<div style="height: 100%" class="content-chart">
|
||||
<template v-if="[0, 1, 2, 3].includes(chooseType)">
|
||||
<three-left-new-item :choose-type="chooseType" />
|
||||
</template>
|
||||
<template v-if="[4].includes(chooseType)">
|
||||
<sleep-item :orgCode="selectValue" :type="selectValue1" style="height: 100%" />
|
||||
</template>
|
||||
<template v-if="[5].includes(chooseType)">
|
||||
<step-item :orgCode="selectValue" :type="selectValue1" style="height: 100%" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch, reactive, onBeforeUnmount, nextTick } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import { getClassCharts } from '/@/views/indexSun/indexSun.ts';
|
||||
import { allSecondaryDepartsApi, twoLApi } from '/@/views/indexSun/indexSun.api.ts';
|
||||
import { useUserStore } from '/@/store/modules/user.ts';
|
||||
import ThreeLeftNewItem from '/src/views/indexSun/threeLeftNewItem/threeLeftNewItem.vue';
|
||||
import SleepItem from '/@/views/indexSun/threeLeftNewItem/sleepItem.vue';
|
||||
import StepItem from '/@/views/indexSun/threeLeftNewItem/stepItem.vue';
|
||||
|
||||
import item0Png from '/@/assets/images/threeLeftNew/item0.png';
|
||||
import item1Png from '/@/assets/images/threeLeftNew/item1.png';
|
||||
import item2Png from '/@/assets/images/threeLeftNew/item2.png';
|
||||
import item3Png from '/@/assets/images/threeLeftNew/item3.png';
|
||||
import item4Png from '/@/assets/images/threeLeftNew/item4.png';
|
||||
import item5Png from '/@/assets/images/threeLeftNew/item5.png';
|
||||
import item6Png from '/@/assets/images/threeLeftNew/item6.png';
|
||||
|
||||
const { getCenterInfo } = useUserStore();
|
||||
const props = defineProps({
|
||||
bKey: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
});
|
||||
const imgList = reactive([item0Png, item1Png, item2Png, item3Png, item4Png, item5Png, item6Png]);
|
||||
const tabList = reactive([
|
||||
{
|
||||
label: '心率',
|
||||
value: 0,
|
||||
tips: '正常范围60~100次/分',
|
||||
},
|
||||
{
|
||||
label: '血氧',
|
||||
value: 1,
|
||||
tips: '血氧饱和度范围95%~100%',
|
||||
},
|
||||
{
|
||||
label: '血压',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '体温',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: '睡眠',
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
label: '步数',
|
||||
value: 5,
|
||||
},
|
||||
]);
|
||||
const chooseType = ref(0);
|
||||
const selectValue = ref<string>('');
|
||||
const timer = ref<any>(null);
|
||||
const selectOptions = ref([{ label: '全部数据', value: '' }]);
|
||||
const selectValue1 = ref('week');
|
||||
const selectOption1 = ref([
|
||||
{ label: '近一周', value: 'week' },
|
||||
{ label: '近一月', value: 'month' },
|
||||
{ label: '近一年', value: 'year' },
|
||||
]);
|
||||
const newChart = ref<HTMLElement>();
|
||||
function clickChooseType(type: any) {
|
||||
if (chooseType.value === type) return;
|
||||
chooseType.value = type;
|
||||
getData();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (selectOptions.value.length === 1) {
|
||||
getAllDepart();
|
||||
}
|
||||
setTimer();
|
||||
});
|
||||
watch(props, () => {
|
||||
selectValue.value = '';
|
||||
getData();
|
||||
});
|
||||
|
||||
function setTimer() {
|
||||
if (timer.value) {
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
chooseType.value = 0;
|
||||
getData();
|
||||
timer.value = setInterval(() => {
|
||||
if (chooseType.value !== 5) {
|
||||
chooseType.value += 1;
|
||||
} else {
|
||||
chooseType.value = 0;
|
||||
}
|
||||
getData();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
timer.value && clearInterval(timer.value);
|
||||
});
|
||||
|
||||
function getAllDepart() {
|
||||
allSecondaryDepartsApi({})
|
||||
.then((res: any) => {
|
||||
if (res.code === 200) {
|
||||
const op: any[] = res?.result
|
||||
? res.result.map((it: any) => {
|
||||
return {
|
||||
label: it.departName,
|
||||
value: it.orgCode,
|
||||
};
|
||||
})
|
||||
: [];
|
||||
selectOptions.value = selectOptions.value.concat(op);
|
||||
} else {
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
const myChart = ref();
|
||||
function getData() {
|
||||
twoLApi({
|
||||
sex: chooseType.value,
|
||||
depart: selectValue.value,
|
||||
centerId: getCenterInfo?.id,
|
||||
})
|
||||
.then((res: any) => {
|
||||
if (res.code == 200) {
|
||||
initChart(res.result);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
function initChart(value: any) {
|
||||
nextTick(() => {
|
||||
myChart.value = echarts.init(newChart.value!);
|
||||
const dx =
|
||||
value.map((item: any) => {
|
||||
return item.name;
|
||||
}) || [];
|
||||
const dy =
|
||||
value.map((item: any) => {
|
||||
return item.count;
|
||||
}) || [];
|
||||
|
||||
const max =
|
||||
value.sort((a: any, b: any) => b.count - a.count).length > 0 ? value.sort((a: any, b: any) => b.count - a.count)[0].count : [];
|
||||
const m = max % 25 === 0 ? max : (parseInt(max / 25) + 1) * 25;
|
||||
let option = getClassCharts(dx, dy, m);
|
||||
myChart.value.setOption(option);
|
||||
window.addEventListener('resize', () => {
|
||||
myChart.value.resize();
|
||||
});
|
||||
});
|
||||
}
|
||||
const emit = defineEmits(['handleView']);
|
||||
function handleView() {
|
||||
emit('handleView');
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.two-l-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgba(8, 75, 100, 0.2);
|
||||
.title {
|
||||
height: 40px;
|
||||
border-radius: 25px 25px 0 0;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
letter-spacing: 2px;
|
||||
color: #ffffff;
|
||||
line-height: 40px;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: linear-gradient(to right, rgba(8, 75, 100, 0.5) 0%, rgba(255, 255, 255, 0) 100%);
|
||||
.look-view {
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 28px;
|
||||
height: 24px;
|
||||
margin: 0 5px 2px 0;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
height: calc(100% - 40px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.content-search {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 5px 10px;
|
||||
.type-select {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.content-search-new {
|
||||
display: inline;
|
||||
.type-time {
|
||||
justify-content: space-between;
|
||||
margin: 7px 0 !important;
|
||||
font-size: 12px;
|
||||
> div {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-search-select {
|
||||
> div {
|
||||
margin-top: 5px;
|
||||
&:nth-child(1) {
|
||||
flex: 1;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
width: 100px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.type-time {
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
> div {
|
||||
cursor: pointer;
|
||||
padding: 3px 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
//width: 60px;
|
||||
}
|
||||
.selected {
|
||||
color: #00ccff;
|
||||
background: rgba(0, 204, 255, 0.2);
|
||||
position: relative;
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 8px; /* 线条宽度 */
|
||||
height: 8px; /* 线条高度 */
|
||||
border-top: 3px solid #00ccff; /* 顶部线条 */
|
||||
border-left: 3px solid #00ccff; /* 左侧线条 */
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 8px; /* 线条宽度 */
|
||||
height: 8px; /* 线条高度 */
|
||||
border-bottom: 3px solid #00ccff; /* 顶部线条 */
|
||||
border-right: 3px solid #00ccff; /* 左侧线条 */
|
||||
}
|
||||
> div {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 8px; /* 线条宽度 */
|
||||
height: 8px; /* 线条高度 */
|
||||
border-top: 3px solid #00ccff; /* 顶部线条 */
|
||||
border-right: 3px solid #00ccff; /* 左侧线条 */
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 8px; /* 线条宽度 */
|
||||
height: 8px; /* 线条高度 */
|
||||
border-bottom: 3px solid #00ccff; /* 顶部线条 */
|
||||
border-left: 3px solid #00ccff; /* 左侧线条 */
|
||||
}
|
||||
}
|
||||
}
|
||||
.no-selected {
|
||||
color: #b6b6b6;
|
||||
background: rgba(26, 69, 126, 0.2);
|
||||
position: relative;
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 8px; /* 线条宽度 */
|
||||
height: 8px; /* 线条高度 */
|
||||
border-top: 3px solid #1a457e; /* 顶部线条 */
|
||||
border-left: 3px solid #1a457e; /* 左侧线条 */
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 8px; /* 线条宽度 */
|
||||
height: 8px; /* 线条高度 */
|
||||
border-bottom: 3px solid #1a457e; /* 顶部线条 */
|
||||
border-right: 3px solid #1a457e; /* 左侧线条 */
|
||||
}
|
||||
> div {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 8px; /* 线条宽度 */
|
||||
height: 8px; /* 线条高度 */
|
||||
border-top: 3px solid #1a457e; /* 顶部线条 */
|
||||
border-right: 3px solid #1a457e; /* 左侧线条 */
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 8px; /* 线条宽度 */
|
||||
height: 8px; /* 线条高度 */
|
||||
border-bottom: 3px solid #1a457e; /* 顶部线条 */
|
||||
border-left: 3px solid #1a457e; /* 左侧线条 */
|
||||
}
|
||||
}
|
||||
}
|
||||
.triangle {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
transform: translateX(-50%);
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 5px solid transparent; /* 左边透明 */
|
||||
border-right: 5px solid transparent; /* 右边透明 */
|
||||
border-bottom: 6px solid #00ccff; /* 底部为黑色,形成三角形 */
|
||||
}
|
||||
}
|
||||
.server-container {
|
||||
color: #fff;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
margin-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
.spin {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
}
|
||||
}
|
||||
.server-item {
|
||||
// font-size: 16px;
|
||||
padding: 5px 3% 5px 5%;
|
||||
&.hasCursor {
|
||||
cursor: pointer;
|
||||
}
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.content-chart {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
flex: 1;
|
||||
.charts {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-title {
|
||||
background: url('/@/assets/images/threeLeftNew/item-bg.png') no-repeat !important;
|
||||
background-size: 100% 100% !important;
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div class="left-pie" style="height: 100%">
|
||||
<div class="inner" ref="healthChart"></div>
|
||||
<div class="count">
|
||||
<div class="t">总人数</div>
|
||||
<div class="v" style="text-align: center">{{ userCount }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { circleRing } from '/src/views/indexSun/threeLeftNewItem/pieCharts.ts';
|
||||
import { nextTick, onMounted, ref, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
color: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
tips: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
userCount: {
|
||||
type: Number,
|
||||
},
|
||||
themeType: {
|
||||
type: String,
|
||||
default: () => '',
|
||||
},
|
||||
});
|
||||
const healthChart = ref<HTMLElement>();
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
() => {
|
||||
init();
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
async function init() {
|
||||
initChart(props.data, props.userCount, props.color);
|
||||
}
|
||||
|
||||
function initChart(chartData, total, color) {
|
||||
nextTick(() => {
|
||||
let myChart = echarts.init(healthChart.value);
|
||||
let options = circleRing(chartData, total, color);
|
||||
myChart.setOption(options);
|
||||
window.addEventListener('resize', () => {
|
||||
myChart.resize();
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.inner {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.inner::after {
|
||||
//content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #051a2b;
|
||||
}
|
||||
|
||||
.left-pie {
|
||||
position: relative;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.count {
|
||||
position: absolute;
|
||||
//left: 41%;
|
||||
//top: 30%;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
|
||||
> div {
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,97 @@
|
||||
// 步数
|
||||
import { visibleChartLabel } from '/@/utils/utils.ts';
|
||||
|
||||
export function screenPie(chartData) {
|
||||
const data = visibleChartLabel(chartData).map((item) => {
|
||||
// item = { ...item, label: { show: item.value > 0 }, labelLine: { show: item.value > 0 } };
|
||||
return item;
|
||||
});
|
||||
return {
|
||||
color: ['#B750BE', '#6C63F0', '#3AACFF', '#ED589D', '#FB466C'],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
backgroundColor: 'rgba(50,50,50,0.7)',
|
||||
borderColor: '#1b7ef2',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['50%', '72%'],
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
formatter: function (params: any) {
|
||||
return `${params.name}\n占比:${params.percent}%\n人次:${params.value}次`;
|
||||
},
|
||||
color: '#ffffff',
|
||||
fontSize: 14,
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 2,
|
||||
length2: 30,
|
||||
minTurnAngle: 120,
|
||||
},
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
//左侧圆
|
||||
export function circleRing(chartData, total, color) {
|
||||
const data = visibleChartLabel(chartData);
|
||||
return {
|
||||
color: color,
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
backgroundColor: 'rgba(50,50,50,0.7)',
|
||||
borderColor: '#1b7ef2',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['50%', '75%'],
|
||||
center: ['50%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
// label: {
|
||||
// show: true,
|
||||
// // position: 'inner',
|
||||
// formatter: '{d}%',
|
||||
// color: '#ffffff',
|
||||
// fontSize: 14,
|
||||
// },
|
||||
// labelLine: {
|
||||
// show: false,
|
||||
// },
|
||||
label: {
|
||||
show: true,
|
||||
position: 'outside',
|
||||
// formatter: '{a}{d}%\n{c}人次',
|
||||
formatter: function (params: any) {
|
||||
return `${params.name}:${params.percent}%\n${params.value}次`;
|
||||
},
|
||||
color: '#ffffff',
|
||||
fontSize: 14,
|
||||
},
|
||||
labelLine: {
|
||||
show: true,
|
||||
length: 2,
|
||||
length2: 30,
|
||||
minTurnAngle: 120,
|
||||
},
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="terminal-container self">
|
||||
<div class="inner">
|
||||
<div class="title">
|
||||
<span class="lightSleep">平均睡眠 {{ nums.avg || 0 }} 深睡 {{ nums.avgLong || 0 }} 浅睡 {{ nums.avgShort || 0 }}</span>
|
||||
</div>
|
||||
<div class="sleepChart" ref="sleepChart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import * as echarts from 'echarts';
|
||||
import { ref, watch } from 'vue';
|
||||
import { formatStr, sleepCharts } from '/@/components/secondaryScreen/screen-right/screenRightHooks';
|
||||
import { getSleep } from '/@/components/secondaryScreen/commonApi.ts';
|
||||
import { useSession, caching } from '/@/hooks/autoRefresh/caching.ts';
|
||||
|
||||
const { setSession, getSession } = useSession();
|
||||
const { PAGE2_RIGHT1 } = caching;
|
||||
const props = defineProps({
|
||||
orgCode: String,
|
||||
type: String,
|
||||
themeType: String,
|
||||
});
|
||||
const sleepChart = ref<HTMLElement>();
|
||||
watch(
|
||||
props,
|
||||
() => {
|
||||
init();
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
const nums = ref({
|
||||
avgShort: '',
|
||||
avgLong: '',
|
||||
avg: '',
|
||||
});
|
||||
|
||||
async function init() {
|
||||
try {
|
||||
const params = {
|
||||
orgCode: props.orgCode,
|
||||
type: props.type,
|
||||
};
|
||||
const { code, result } = await getSleep(params);
|
||||
if (code == 200 && result.length > 0) {
|
||||
setSession(PAGE2_RIGHT1, JSON.stringify(result));
|
||||
setValue(result);
|
||||
}
|
||||
} catch {
|
||||
const result = JSON.parse(getSession(PAGE2_RIGHT1));
|
||||
setValue(result);
|
||||
}
|
||||
}
|
||||
|
||||
function setValue(result: any) {
|
||||
let time = result?.map((item: any) => item.dataDate);
|
||||
let short = result?.map((item: any) => item.avgShortDuration);
|
||||
let long = result?.map((item: any) => item.avgLongDuration);
|
||||
let awake = result?.map((item: any) => item.awakeDuration);
|
||||
let avg = result?.map((item: any) => item.averageDuration);
|
||||
initChart({ time, short, long, awake, type: props.type });
|
||||
const len = time.length;
|
||||
if (!len > 0) {
|
||||
return;
|
||||
}
|
||||
nums.value = {
|
||||
avgShort: formatStr({ list: short, len }),
|
||||
avgLong: formatStr({ list: long, len }),
|
||||
avg: formatStr({ list: avg, len }), //平均
|
||||
};
|
||||
}
|
||||
|
||||
function initChart({ time, short, long, awake, type }) {
|
||||
let myChart = echarts.init(sleepChart.value);
|
||||
let options = sleepCharts({ time, short, long, awake, type });
|
||||
myChart.setOption(options);
|
||||
window.addEventListener('resize', () => {
|
||||
myChart.resize();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.terminal-container.self {
|
||||
position: relative;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.inner {
|
||||
height: 100%;
|
||||
|
||||
.title {
|
||||
color: #cfcfcf;
|
||||
text-align: left;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
.count {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.lightSleep {
|
||||
padding: 3px 0 3px 2%;
|
||||
}
|
||||
}
|
||||
|
||||
.sleepChart {
|
||||
height: 90%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<div class="pie-container self">
|
||||
<div class="inner" ref="healthChart"></div>
|
||||
<div class="count">
|
||||
<div class="t">总人数</div>
|
||||
<div class="v">{{ total }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import { useStep } from '/@/components/secondaryScreen/screen-right/screenRightHooks.ts';
|
||||
import { screenPie } from '/@/views/indexSun/threeLeftNewItem/pieCharts.ts';
|
||||
import { getStepNew } from '/@/components/secondaryScreen/commonApi.ts';
|
||||
import { caching, useSession } from '/@/hooks/autoRefresh/caching.ts';
|
||||
|
||||
const props = defineProps({
|
||||
orgCode: String,
|
||||
type: String,
|
||||
themeType: String,
|
||||
});
|
||||
const { setSession, getSession } = useSession();
|
||||
const { PAGE2_RIGHT2 } = caching;
|
||||
watch(
|
||||
props,
|
||||
() => {
|
||||
init();
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
const healthChart = ref<HTMLElement>();
|
||||
const { total, setStep, getStepData } = useStep();
|
||||
|
||||
async function init() {
|
||||
try {
|
||||
const params = {
|
||||
orgCode: props.orgCode,
|
||||
type: props.type,
|
||||
};
|
||||
// const { code, result } = await getStep(params);
|
||||
const { code, result } = await getStepNew(params);
|
||||
if (code == 200) {
|
||||
setValue(result);
|
||||
setSession(PAGE2_RIGHT2, JSON.stringify(result));
|
||||
}
|
||||
} catch {
|
||||
const result = JSON.parse(getSession(PAGE2_RIGHT2));
|
||||
setValue(result);
|
||||
}
|
||||
}
|
||||
|
||||
function setValue(result: any) {
|
||||
setStep(result);
|
||||
initChart(getStepData());
|
||||
}
|
||||
|
||||
function initChart(chartData: any) {
|
||||
let myChart = echarts.init(healthChart.value);
|
||||
let options = screenPie(chartData);
|
||||
myChart.setOption(options);
|
||||
window.addEventListener('resize', () => {
|
||||
myChart.resize();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
.inner {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pie-container.self {
|
||||
position: relative;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.count {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
|
||||
> div {
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.t {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<item-d
|
||||
:themeType="themeType"
|
||||
:keu="spinning"
|
||||
:title="dataList[props.chooseType].title"
|
||||
:data="dataList[props.chooseType].data"
|
||||
:tips="dataList[props.chooseType].tips"
|
||||
:color="dataList[props.chooseType].color"
|
||||
:user-count="dataList[props.chooseType].userCount"
|
||||
/>
|
||||
</template>
|
||||
r
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { getWatchDataByOrgCodeNew } from '/@/components/secondaryScreen/commonApi.ts';
|
||||
import { useSpin } from '/@/components/body-d-left/bodyLeftHooks.ts';
|
||||
import ItemD from '/src/views/indexSun/threeLeftNewItem/item-d.vue';
|
||||
|
||||
const { spinning, setSpin } = useSpin();
|
||||
const dataList = ref([
|
||||
{
|
||||
title: '心率',
|
||||
data: [
|
||||
{ name: '正常', value: 0, key: 'normalCount' },
|
||||
{ name: '警戒', value: 0, key: 'warnCount' },
|
||||
{ name: '危险', value: 0, key: 'riskCount' },
|
||||
],
|
||||
type: '1',
|
||||
color: ['#0098FA', '#FF6648', '#FB466C'],
|
||||
tips: '正常范围60~100次/分',
|
||||
userCount: 0,
|
||||
},
|
||||
{
|
||||
title: '血氧',
|
||||
data: [
|
||||
{ name: '正常', value: 0, key: 'normalCount' },
|
||||
{ name: '警戒', value: 0, key: 'warnCount' },
|
||||
{ name: '危险', value: 0, key: 'riskCount' },
|
||||
],
|
||||
type: '2',
|
||||
color: ['#0098FA', '#FF6648', '#FB466C'],
|
||||
tips: '血氧饱和度范围95%~100%',
|
||||
userCount: 0,
|
||||
},
|
||||
{
|
||||
title: '压力',
|
||||
data: [
|
||||
{ name: '正常', value: 0, key: 'normalCount' },
|
||||
{ name: '放松', value: 0, key: 'unwindCount' },
|
||||
{ name: '中等', value: 0, key: 'warnCount' },
|
||||
{ name: '偏高', value: 0, key: 'riskCount' },
|
||||
],
|
||||
type: '3',
|
||||
color: ['#1DCC79', '#0098FA', '#0CD9B5', '#6C63F0'],
|
||||
tips: '',
|
||||
userCount: 0,
|
||||
},
|
||||
{
|
||||
title: '体温',
|
||||
data: [
|
||||
{ name: '<37.2', value: 0, key: 'normalCount' },
|
||||
{ name: '37.2-38', value: 0, key: 'warnCount' },
|
||||
{ name: '>38', value: 0, key: 'riskCount' },
|
||||
],
|
||||
type: '5',
|
||||
color: ['#0098FA', '#0CD9B5', '#3B72AD'],
|
||||
tips: '',
|
||||
userCount: 0,
|
||||
},
|
||||
]);
|
||||
|
||||
const props = defineProps({
|
||||
orgCode: String,
|
||||
type: String,
|
||||
themeType: String,
|
||||
refreshState: {
|
||||
type: Boolean,
|
||||
default: () => false,
|
||||
},
|
||||
chooseType: {
|
||||
type: Number,
|
||||
default: () => 0,
|
||||
},
|
||||
});
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
watch(props, () => {
|
||||
init();
|
||||
});
|
||||
|
||||
async function init() {
|
||||
setSpin(true);
|
||||
try {
|
||||
// const { code, result } = await getWatchDataByOrgCode(props);
|
||||
const { code, result } = await getWatchDataByOrgCodeNew(props);
|
||||
if (code == 200) {
|
||||
setValue(result);
|
||||
// setSession(PAGE2_LEFT, JSON.stringify(result));
|
||||
}
|
||||
} catch {
|
||||
// const result = JSON.parse(getSession(PAGE2_LEFT));
|
||||
// setValue(result);
|
||||
}
|
||||
}
|
||||
|
||||
function setValue(result) {
|
||||
setSpin(false);
|
||||
let data = cloneDeep(dataList.value);
|
||||
data.forEach((item) => {
|
||||
let resData = result.find((v) => v.type == item.type);
|
||||
item.userCount = resData.userCount;
|
||||
item.data = item.data.map((val) => {
|
||||
val.value = resData[val.key];
|
||||
val = { ...val, label: { show: val.value > 0 }, labelLine: { show: val.value > 0 } };
|
||||
return val;
|
||||
});
|
||||
});
|
||||
dataList.value = data;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
init,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -56,7 +56,7 @@
|
||||
import { twoRNApi } from '/@/views/indexSun/indexSun.api.ts';
|
||||
import dayjs from 'dayjs';
|
||||
import { Row, Col } from 'ant-design-vue';
|
||||
import { getName, list } from '/@/views/indexSun/rowNewR.data.ts';
|
||||
import { getName, list } from '/@/views/indexSun/twoNewR.data.ts';
|
||||
|
||||
const { themeType } = useTheme();
|
||||
const step = ref(0.2);
|
||||
Reference in New Issue
Block a user