1.新需求2025.9.19新需求:
去掉"健康监测"副屏, 修改后健康终端报警点击查看详情弹出告警记录分页列表;
去掉【体检人数统计】【体检数据】【健康打卡数据】,增加【心血管监测】模块功能,【心血管监测】功能将原心血管监测大屏上的内容整理并移动到急救服务平台大屏中;
员工求助时,地图中推荐两个医院、两个健康小屋、两个AED坐标信息,并按距离排序,体现距离远近顺序;
地图中油田医院、健康小屋等各个图例,显示总数信息;
救护车坐标信息维护,并在大屏上标记;
右上角"增加【救助信息】板块, 当出现应急弹窗后或从今日应急选中应急事件 , 该板块需展示应急事件的相关信息(开发中);
This commit is contained in:
2025-09-24 20:53:28 +08:00
parent a97d9c64aa
commit c7abcf1f67
29 changed files with 1783 additions and 175 deletions
@@ -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>