605 lines
24 KiB
Vue
605 lines
24 KiB
Vue
<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>
|