Files
xj-admin/src/views/archivesManage/institution/timeService/environment/environment.vue
T
2025-06-27 17:42:38 +08:00

605 lines
24 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="outer-d">
<div class="top-title"> 长庆油田环境监测设备 </div>
<div class="map-d">
<template v-if="!loading">
<service-map
ref="serviceMap"
:map-list="mapList"
:marker-content="null"
:label-content="labelContent"
@get-marker-info="getMarkerInfo"
@get-detail="getDetail"
id="meterId"
/>
<div class="search-d">
所属单位
<ApiSelect
:value="orgCode"
:api="allSecondaryDepartsNew"
@change="
(v) => {
orgCode = v;
}
"
resultField="result"
labelField="departName"
valueField="orgCode"
:after-fetch="
(data) => {
data.unshift({
orgCode: '1',
departName: '全部单位',
});
return data;
}
"
:allowClear="true"
:show-default-value="false"
:immediate="true"
:showSearch="true"
:filterOption="
(input: string, option: any): boolean => {
const str: string = input.toLowerCase();
return option.label.toLowerCase().indexOf(str) >= 0;
}"
style="width: 260px"
/>
<a-button type="primary" @click="searchB">查询</a-button>
<a-button style="background-color: #a4adb3; color: #ffffff" @click="resetB">重置</a-button>
</div>
<div class="z" v-if="radioValue !== '3'">
<div class="inner" v-if="radioValue === '0'"></div>
<div class="outer" v-if="radioValue === '1'"></div>
<div class="water" v-if="radioValue === '3'"></div>
<div class="pollen" v-if="radioValue === '2'"></div>
<div class="z-d">
<div v-for="(item, index) in describe[radioValue]" :key="`describe${index}`">
{{ item }}
</div>
</div>
</div>
<div class="z" style="height: 100px; flex-direction: column; justify-content: space-around" v-else>
<div style="display: flex; color: #ffffff; font-weight: bold">
<div style="background-color: #00ff1a; width: 20px; height: 20px; border-radius: 6px; margin-right: 10px"></div>
<div>达标</div>
</div>
<div style="display: flex; color: #ffffff; font-weight: bold">
<div style="background-color: #ec0808; width: 20px; height: 20px; border-radius: 6px; margin-right: 10px"></div>
<div>不达标</div>
</div>
</div>
<a-radio-group v-model:value="radioValue" button-style="solid" class="radio-group-d" @change="initList">
<a-radio-button value="0">室内环境</a-radio-button>
<a-radio-button value="1">室外环境</a-radio-button>
<a-radio-button value="3">水质监测</a-radio-button>
<a-radio-button value="2">过敏源监测</a-radio-button>
</a-radio-group>
<div class="bottom-d">
<div
class="bottom-d-item"
v-for="(item, index) in deviceInfo"
:key="`bottom-d-item-${index}`"
:style="{ margin: index === 1 ? '0 25px 0 50px' : index === 2 ? '0 50px 0 25px' : 0 }"
>
<div>
<span>运行正常:{{ item.working }}台</span>
<span
style="color: red; cursor: pointer"
@click="
() => {
openModalA(true, {
type: item?.value,
title: item?.name,
orgCode: orgCode === '1' ? '' : orgCode,
});
}
"
>异常列表</span
>
</div>
<div style="font-size: 30px; font-weight: bold; display: flex; justify-content: center">
<div style="position: relative">
{{ item.sum }}
<span style="font-size: 16px; margin-left: -7px">台</span>
</div>
</div>
<div style="display: flex; justify-content: center; align-items: center">
<div style="position: relative">
<div style="display: flex; align-items: center; position: absolute; top: 0; height: 100%; left: -30px">
<img :src="imgInfos[index]" alt="" style="width: 25px; height: 23px" />
</div>
{{ item?.name }}
</div>
</div>
</div>
</div>
</template>
<template v-else>
<div style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center">
<a-spin size="large" />
</div>
</template>
</div>
</div>
<environment-modal
@register="registerModal"
@close-modal="
() => {
count++;
}
"
/>
<environment-abnormal-modal @register="registerModalA" />
</template>
<script setup lang="ts">
import ServiceMap from '/@/views/archivesManage/institution/timeService/components/serviceMap.vue';
import { nextTick, onMounted, ref, onBeforeUnmount } from 'vue';
import { listApi, statisticsApi } from '/@/views/archivesManage/institution/timeService/environment/environment.api';
import { getName } from '/@/views/interveneNew/compoents/utils';
import ApiSelect from '/@/components/Form/src/components/ApiSelect.vue';
import { allSecondaryDepartsNew } from '/@/utils/orgSearchInfo';
import EnvironmentModal from '/@/views/archivesManage/institution/timeService/components/environmentModal.vue';
import { useModal } from '/@/components/Modal';
import innerPng from '/@/assets/images/enviroment/institution/inner.png';
import outerPng from '/@/assets/images/enviroment/institution/outer.png';
import waterPng from '/@/assets/images/enviroment/institution/water.png';
import pollenPng from '/@/assets/images/enviroment/institution/pollen.png';
import innerPngS from '/@/assets/images/enviroment/institution/inner-s.png';
import outerPngS from '/@/assets/images/enviroment/institution/outer-s.png';
import waterPngS from '/@/assets/images/enviroment/institution/water-s.png';
import pollenPngS from '/@/assets/images/enviroment/institution/pollen-s.png';
import EnvironmentAbnormalModal from '/@/views/archivesManage/institution/timeService/environment/components/environmentAbnormalModal.vue';
const [registerModal, { openModal }] = useModal();
const [registerModalA, { openModal: openModalA }] = useModal();
const imgInfo = ref({
'0': innerPng,
'1': outerPng,
'3': waterPng,
'2': pollenPng,
});
const imgInfos = ref({
0: innerPngS,
1: outerPngS,
2: waterPngS,
3: pollenPngS,
});
const describe = ref({
'0': ['清洁', '未污染', '轻污染', '中污染', '重污染'],
'1': ['优', '良', '轻度污染', '中度污染', '重度污染', '严重污染'],
'3': ['达标', '不达标'],
'2': ['很低', '低', '中等', '高', '很高'],
});
const colorInfo = ref({
'0': [
{ value: 1, label: '#66c706' },
{ value: 2, label: '#f5cc27' },
{ value: 3, label: '#fe8700' },
{ value: 4, label: '#e60707' },
{ value: 5, label: '#940654' },
],
'1': [
{ value: 1, label: '#66c706' },
{ value: 2, label: '#f5cc27' },
{ value: 3, label: '#fe8700' },
{ value: 4, label: '#e60707' },
{ value: 5, label: '#65001c' },
{ value: 6, label: '#65001c' },
],
'3': [
{ value: 0, label: '#ec0808' },
{ value: 1, label: '#66c706' },
],
'2': [
{ value: 1, label: '#66c706' },
{ value: 2, label: '#f5cc27' },
{ value: 3, label: '#fe8700' },
{ value: 4, label: '#e60707' },
{ value: 5, label: '#65001c' },
],
});
const level = ref({
'0': [
{ value: 1, label: 'I级' },
{ value: 2, label: 'II级' },
{ value: 3, label: 'III级' },
{ value: 4, label: 'IV级' },
{ value: 5, label: 'V级' },
],
'1': [
{ value: 1, label: '一级' },
{ value: 2, label: '二级' },
{ value: 3, label: '三级' },
{ value: 4, label: '四级' },
{ value: 5, label: '五级' },
{ value: 5, label: '六级' },
],
'3': [
{ value: 0, label: '不合格' },
{ value: 1, label: '合格' },
],
});
const loading = ref(true);
const radioValue = ref('0');
const serviceMap = ref();
const mapList = ref<any[]>([]);
const labelContent = ref('');
const deviceInfo = ref({});
const orgCode = ref('1');
const count = ref(0);
function getMarkerInfo(e) {
let color = e.newData ? getName(e.newData.score, colorInfo.value[radioValue.value]) : 'red';
switch (radioValue.value) {
case '0':
labelContent.value = innerDoor(e, color);
break;
case '1':
labelContent.value = outerDoor(e, color);
break;
case '3':
labelContent.value = water(e, color);
break;
case '2':
labelContent.value = pollen(e, color);
break;
}
serviceMap.value.setLabel(labelContent.value);
}
function innerDoor(e, color) {
return `
<div style="background-color: #ffffff; padding: 10px; border-radius: 10px;z-index: 999">
<div style="display: flex; align-items: center">
<div>
<div style="font-size: 18px; font-weight: bold">${e.meterName}</div>
<div style="margin-top: 10px">单位名称:${e.orgName || '-'}</div>
<div style="margin-top: 10px">综合指数:${e.newData ? Math.round(e.newData.compositeIndex * 100) / 100 : '-'}</div>
<div style="margin-top: 10px;">空气质量级别:${e.newData ? getName(e.newData.score, level.value[radioValue.value]) : '-'}</div>
<div style="margin-top: 10px;">更新时间:${e.lastMonitorDate || '-'}</div>
</div>
<div style="margin-left: 10px">
<div style="padding: 30px; border-radius: 50%; border: 5px solid ${color}">
<div style="text-align: center; font-size: 12px">空气质量</div>
<div style="text-align: center; font-size: 19px; font-weight: bold; color: green;margin-top: 10px">
${e.newData?.score_dictText || '-'}
</div>
</div>
</div>
</div>
<div style="padding: 5px 0 0;
border-top: 1px dashed #cecece;
margin: 5px 0 0;">
设备地址:${e?.meterAddress || '-'}
</div>
<div style="text-align: center;height: 30px;line-height: 30px;" onclick="getDetail('${e.meterCode}')">
<span style="cursor: pointer;color: #2189ff">查看监测数据></span>
</div>
</div>
`;
}
function outerDoor(e, color) {
return `
<div style="background-color: #ffffff; padding: 10px; border-radius: 10px;z-index: 999">
<div style="display: flex; align-items: center">
<div>
<div style="font-size: 18px; font-weight: bold">${e.meterName}</div>
<div style="margin-top: 10px">单位名称:${e.orgName || '-'}</div>
<div style="margin-top: 10px">空气质量指数(AQI)${e?.newData?.compositeIndex || '-'}</div>
<div style="margin-top: 10px;">空气质量级别:${e.newData ? getName(e.newData.score, level.value[radioValue.value]) : '-'}</div>
<div style="margin-top: 10px;">更新时间:${e.lastMonitorDate || '-'}</div>
</div>
<div style="margin-left: 10px">
<div style="padding: 30px; border-radius: 50%; border: 5px solid ${color}">
<div style="text-align: center; font-size: 12px">空气质量评价</div>
<div style="text-align: center; font-size: 19px; font-weight: bold; color: green;margin-top: 10px">
${e.newData?.score_dictText || '-'}
</div>
</div>
</div>
</div>
<div style="padding: 5px 0 0;
border-top: 1px dashed #cecece;
margin: 5px 0 0;">
设备地址:${e?.meterAddress || '-'}
</div>
<div style="text-align: center;height: 30px;line-height: 30px;" onclick="getDetail('${e.meterCode}')">
<span style="cursor: pointer;color: #2189ff">查看监测数据></span>
</div>
</div>
`;
}
function water(e, color) {
return `
<div style="background-color: #ffffff; padding: 10px; border-radius: 10px;z-index: 999">
<div style="display: flex; align-items: center">
<div>
<div style="font-size: 18px; font-weight: bold">${e.meterName}</div>
<div style="margin-top: 10px">单位名称:${e.orgName || '-'}</div>
<div style="margin-top: 10px">TDS${e.newData?.tds || '-'}</div>
<div style="margin-top: 10px;">PH${e.newData?.ph || '-'}</div>
<div style="margin-top: 10px;">电导率:${e.newData?.conductivity || '-'}</div>
<div style="margin-top: 10px;">更新时间:${e.lastMonitorDate || '-'}</div>
</div>
<div style="margin-left: 10px">
<div style="padding: 30px; border-radius: 50%; border: 5px solid ${color}">
<div style="text-align: center; font-size: 12px">空气质量评价</div>
<div style="text-align: center; font-size: 19px; font-weight: bold; color: green;margin-top: 10px">
${e.newData?.score_dictText || '-'}
</div>
</div>
</div>
</div>
<div style="padding: 5px 0 0;
border-top: 1px dashed #cecece;
margin: 5px 0 0;">
设备地址:${e?.meterAddress || '-'}
</div>
<div style="text-align: center;height: 30px;line-height: 30px;" onclick="getDetail('${e.meterCode}')">
<span style="cursor: pointer;color: #2189ff">查看监测数据></span>
</div>
</div>
`;
}
function pollen(e, color) {
return `
<div style="background-color: #ffffff; padding: 10px; border-radius: 10px;z-index: 999">
<div style="display: flex; align-items: center">
<div>
<div style="font-size: 18px; font-weight: bold">${e.meterName}</div>
<div style="margin-top: 10px">单位名称:${e.orgName || '-'}</div>
<div style="margin-top: 10px">花粉浓度:${e.newData?.totalPollen || '-'}</div>
<div style="margin-top: 10px;">主要过敏源:${e.newData?.majorAllergens || '-'}</div>
<div style="margin-top: 10px;">更新时间:${e.lastMonitorDate || '-'}</div>
</div>
<div style="margin-left: 10px">
<div style="padding: 30px; border-radius: 50%; border: 5px solid ${color}">
<div style="text-align: center; font-size: 12px">空气质量评价</div>
<div style="text-align: center; font-size: 19px; font-weight: bold; color: green;margin-top: 10px">
${e.newData?.score_dictText || '-'}
</div>
</div>
</div>
</div>
<div style="padding: 5px 0 0;
border-top: 1px dashed #cecece;
margin: 5px 0 0;">
设备地址:${e?.meterAddress || '-'}
</div>
<div style="text-align: center;height: 30px;line-height: 30px;" onclick="getDetail('${e.meterCode}')">
<span style="cursor: pointer;color: #2189ff">查看监测数据></span>
</div>
</div>
`;
}
function getDetail(e) {
openModal(true, {
typeId: radioValue.value,
meterCode: e.meterCode,
});
}
onMounted(async () => {
await initList();
loading.value = false;
await nextTick(() => {
serviceMap.value.initMap(mapList.value);
});
await getStatistics();
});
onBeforeUnmount(() => {
serviceMap.value.destroyMap();
});
async function getStatistics() {
try {
const res = await statisticsApi({ orgCode: orgCode.value === '1' ? '' : orgCode.value });
deviceInfo.value = [
{
sum: res?.indoorMeterSum || 0,
working: res?.indoorMeterWorking || 0,
name: '室内环境',
value: '0',
},
{
sum: res?.outdoorMeterSum || 0,
working: res?.outdoorMeterWorking || 0,
name: '室外环境',
value: '1',
},
{
sum: res?.waterQualityMeterSum || 0,
working: res?.waterQualityMeterWorking || 0,
name: '水质监测设备',
value: '3',
},
{
sum: res?.pollenMeterSum || 0,
working: res?.pollenMeterWorking || 0,
name: '过敏源监测设备',
value: '2',
},
];
} catch (e) {
console.log(e);
}
}
async function initList() {
try {
mapList.value = (await listApi({ type: radioValue.value, orgCode: orgCode.value === '1' ? '' : orgCode.value })).map((item) => {
let color = item.newData ? getName(item.newData.score, colorInfo.value[radioValue.value]) : 'red';
item['img'] = imgInfo.value[radioValue.value];
item[
'markerContent'
] = `<div style="white-space: nowrap;display: flex;background-color: ${color};padding: 5px 10px;border-radius: 10px">
<img src="${imgInfo.value[radioValue.value]}" alt="" style="width: 20px;height: 20px; margin-right: 5px"/>
<span style="color: #ffffff">${
item.newData
? item.newData.score_dictText +
(radioValue.value !== '3' ? '(' + item.newData[radioValue.value !== '2' ? 'compositeIndex' : 'totalPollen'] + ')' : '')
: '暂无数据'
}</span>
</div>`;
return item;
});
} catch (e) {
mapList.value = [];
console.log(e);
}
}
async function searchB() {
await initList();
await getStatistics();
}
async function resetB() {
orgCode.value = '1';
await searchB();
}
</script>
<style scoped lang="less">
.outer-d {
position: relative;
width: 100%;
height: 100%;
}
.top-title {
padding: 10px;
text-align: center;
font-size: 20px;
}
.search-d {
box-shadow: 2px 2px 0 0 rgba(0, 0, 0, 0.35);
border-radius: 5px;
background-color: #ffffff;
padding: 10px 20px;
position: absolute;
top: 10px;
left: 10px;
z-index: 99;
> :nth-child(n + 1) {
margin-left: 10px;
}
}
.radio-group-d {
position: absolute;
top: 20px;
right: 10px;
z-index: 99;
}
.bottom-d {
border-radius: 5px;
width: 100%;
position: absolute;
bottom: 8%;
left: 0;
z-index: 99;
display: flex;
align-items: center;
justify-content: center;
.bottom-d-item {
width: 200px;
border-radius: 5px;
box-shadow: 2px 2px 4px 1px rgba(0, 0, 0, 0.35);
background-color: #ffffff;
> div {
width: 100%;
text-align: center;
&:nth-child(1) {
color: green;
text-align: left;
padding: 5px 15px 0;
display: flex;
justify-content: space-between;
}
&:nth-child(2) {
font-size: 18px;
font-weight: bold;
padding: 3px 0 3px 0;
}
&:nth-child(3) {
font-size: 18px;
font-weight: bold;
padding: 0 0 10px 0;
}
}
}
}
.map-d {
position: absolute;
width: calc(100% - 20px);
height: calc(100% - 70px);
top: 50px;
left: 10px;
}
.z {
position: absolute;
top: 100px;
right: 50px;
background-color: rgba(#8c8c8c, 0.5);
border-radius: 10px;
padding: 10px 30px 10px 10px;
display: flex;
height: 300px;
.inner {
width: 15px;
height: 100%;
border-radius: 7px;
background: linear-gradient(#02fb1b 0, #2ab539 25%, #f7e303 50%, #fe8a02 75%, #ed1507 100%);
}
.outer {
width: 15px;
height: 100%;
border-radius: 7px;
background: linear-gradient(#0efe19 0, #fed302 20%, #fe8702 40%, #ef1b07 60%, #962e91 80%, #3d095f 100%);
}
.pollen {
width: 15px;
height: 100%;
border-radius: 7px;
background: linear-gradient(#01fbe2 0, #36ce20 25%, #f3df04 50%, #fe8902 75%, #ed1008 100%);
}
.z-d {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-left: 8px;
color: #ffffff;
font-weight: bold;
}
}
:deep(.ant-radio-button-wrapper) {
color: #1684fc !important;
border-color: #1684fc !important;
&:before {
background-color: #1684fc !important;
}
}
:deep(.ant-radio-button-wrapper-checked) {
color: #ffffff !important;
}
</style>