| | |
| | | <template> |
| | | <div class="home"> |
| | | {{ state.name }} |
| | | <div class="main_contain"> |
| | | <div class="ec_header"> |
| | | <div class="ec_header_left"> |
| | | <div class="ec_header_left_view">{{ pointName }}</div> |
| | | <div class="ec_header_left_view"> |
| | | <span class="ec_header_val">{{ |
| | | state.currentRecordParas.RecordValue |
| | | }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="ec_header_right"> |
| | | <div class="ec_header_right_view"> |
| | | <div>状态:{{ state.currentRecordParas.RecordStatusName }}</div> |
| | | <div>警报:{{ state.currentRecordParas.AlarmNumber }}</div> |
| | | </div> |
| | | <div class="ec_header_right_view"> |
| | | <div>{{ state.currentRecordParas.RecordTime }}</div> |
| | | <div>{{ lastRefreshTime }}s后刷新</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="container"> |
| | | <div id="chartMain" style="width: 100%; height: 418px"></div> |
| | | </div> |
| | | <!--先隐藏详情,目前接口返回值 |
| | | <div class="ykt-detail-wraper"> |
| | | <van-collapse v-model="state.activeNames"> |
| | | <van-collapse-item name="1"> |
| | | <template #title> |
| | | <div>详情</div> |
| | | </template> |
| | | <van-cell :value="state.MonitorPointID"> |
| | | <template #title> |
| | | <div class="custom-title">测点编号</div> |
| | | </template> |
| | | </van-cell> |
| | | <van-cell value="瞬时压力"> |
| | | <template #title> |
| | | <div class="custom-title">监控名称</div> |
| | | </template> |
| | | </van-cell> |
| | | <van-cell value="MPa"> |
| | | <template #title> |
| | | <div class="custom-title">单位</div> |
| | | </template> |
| | | </van-cell> |
| | | <van-cell value=""> |
| | | <template #title> |
| | | <div class="custom-title">上次报警</div> |
| | | </template> |
| | | </van-cell> |
| | | <van-cell> |
| | | <template #title> |
| | | <div class="custom-title">是否显示报警点</div> |
| | | </template> |
| | | <template #value> |
| | | <van-switch v-model="state.checked" size="24px" /> |
| | | </template> |
| | | </van-cell> |
| | | <van-cell value="阈值"> |
| | | <template #title> |
| | | <div class="custom-title">警报类型</div> |
| | | </template> |
| | | </van-cell> |
| | | </van-collapse-item> |
| | | </van-collapse> |
| | | </div> --> |
| | | <div class="ykt-detail-wrapers"> |
| | | <div class="hykt_header" style="margin-bottom: 5px"> |
| | | <div class="hykt_span">时间</div> |
| | | <div |
| | | class="hykt_span" |
| | | @click="changeMonitorStatus" |
| | | :style="state.isMonitorChange ? 'color:red;' : ''" |
| | | > |
| | | 状态 |
| | | </div> |
| | | <div class="hykt_span">监控值</div> |
| | | </div> |
| | | <div |
| | | class="hykt_li" |
| | | v-for="(monitor, index) in state.c_monitorList" |
| | | :key="index" |
| | | > |
| | | <div class="hykt_span">{{ monitor.RecordTime }}</div> |
| | | <div class="hykt_span"> |
| | | {{ |
| | | monitor.RecordStatusText.length > 0 && |
| | | monitor.RecordStatusText[0] == "BJ" |
| | | ? "中断" |
| | | : "正常" |
| | | }} |
| | | </div> |
| | | |
| | | <div class="hykt_span">{{ monitor.RecordValue }}</div> |
| | | </div> |
| | | </div> |
| | | <!-- 刷新 --> |
| | | <div style="bottom: 140px" class="icon_view"> |
| | | <van-icon name="revoke" size="20px" @click="onTapRefresh()" /> |
| | | </div> |
| | | <!-- 间隔 --> |
| | | <div style="bottom: 200px" class="icon_view" @click="onTapInterval"> |
| | | <van-icon |
| | | :name="state.isOnTapInterval ? 'exchange' : 'shrink'" |
| | | size="20px" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {reactive, onMounted } from "vue" |
| | | import { reactive, onMounted, ref, shallowRef, onBeforeUnmount } from "vue"; |
| | | import moment from "moment"; |
| | | import * as echarts from "echarts"; //引入echarts |
| | | import axios from "axios"; |
| | | import { useRouter } from "vue-router"; |
| | | const router = useRouter(); |
| | | const pointName = ref(""); |
| | | const myChart = shallowRef(null); |
| | | const lastRefreshTime = ref(120); |
| | | let times = ref(null); |
| | | const now = new Date(); |
| | | const minDate = new Date( |
| | | now.getFullYear(), |
| | | now.getMonth(), |
| | | now.getDate(), |
| | | 0, |
| | | 0, |
| | | 0 |
| | | ); |
| | | const maxDate = new Date( |
| | | now.getFullYear(), |
| | | now.getMonth(), |
| | | now.getDate(), |
| | | 23, |
| | | 59, |
| | | 59 |
| | | ); |
| | | let state = reactive({ |
| | | name:'Hello World' |
| | | }) |
| | | currentRecordParas: { |
| | | RecordValue: "", |
| | | RecordStatusName: "", |
| | | AlarmNumber: 0, |
| | | RecordTime: "", |
| | | }, |
| | | chartData: [], |
| | | x_yData: [], |
| | | activeNames: [""], |
| | | checked: false, //是否显示报警点 |
| | | loading: false, //加载状态 |
| | | isMonitorChange: false, //监测界面 --- 是否启用状态筛选 |
| | | isOnTapInterval: false, |
| | | monitorList: [], |
| | | c_monitorList: [], |
| | | // PointID: "1620681990539972608", |
| | | PointID: "", |
| | | // token: |
| | | // "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOjEsIkxvZ2luTmFtZSI6Inl3YWRtaW4iLCJMb2dpblB3ZCI6ImFkbWluIiwiQ29ycElEIjoxLCJJc0FkbWluIjp0cnVlLCJpYXQiOjE2ODkyMTg3NzEsIm5iZiI6MTY4OTIxODc3MSwiZXhwIjoxNjg5MzA1MTcxLCJpc3MiOiJpc3RhdGlvbiIsImF1ZCI6ImlzdGF0aW9uIn0.cUxpJbn8krlTpaHkmd_nTgzc6YQzPxBn6pCJ0mFHAS8", |
| | | token: "", |
| | | }); |
| | | onMounted(() => { |
| | | // console.log(router.currentRoute.value.query, 162); |
| | | state.PointID = router.currentRoute.value.query.PointID; |
| | | state.token = router.currentRoute.value.query.Token; |
| | | state.currentRecordParas.RecordTime = moment().format("YYYY-MM-DD"); |
| | | initialRealTimeRecord(); |
| | | getRecordDetail(); |
| | | }); |
| | | const countdown = () => { |
| | | if (lastRefreshTime.value === 0) { |
| | | onTapRefresh(); |
| | | lastRefreshTime.value = 120; |
| | | return; |
| | | } else { |
| | | lastRefreshTime.value--; |
| | | } |
| | | }; |
| | | onBeforeUnmount(() => { |
| | | console.log("mounted!", 307); |
| | | clearInterval(times.value); |
| | | times.value = null; |
| | | }); |
| | | |
| | | }) |
| | | //刷新 |
| | | const onTapRefresh = () => { |
| | | axios({ |
| | | url: "http://47.101.141.88:9019/Run/MonitorRealRecord/Mobile/GetLastRecordByMonitorPointID@V1.0", |
| | | method: "GET", |
| | | headers: { |
| | | Authorization: `Bearer ${state.token}`, |
| | | }, |
| | | params: { |
| | | CorpID: 14, |
| | | MonitorPointID: state.PointID, |
| | | }, |
| | | }) |
| | | .then((res) => { |
| | | if (res.data.Code != 0) { |
| | | return; |
| | | } |
| | | if (res.data.Data == null || res.data.Data == "") { |
| | | return; |
| | | } |
| | | var refreshData = res.data.Data; |
| | | var last_record = state.chartData[state.chartData.length - 1]; //获取最后一条数据 |
| | | refreshData.forEach((item) => { |
| | | let getStatus = DataStatusTextEmun(item.DataStatus); |
| | | state.currentRecordParas.RecordStatusName = getStatus; |
| | | state.currentRecordParas.RecordValue = item.DataValue; |
| | | if ( |
| | | item.DataValue != last_record.DataValue || |
| | | item.DataTime != last_record.DataTime |
| | | ) { |
| | | state.chartData.push(item); |
| | | } |
| | | }); |
| | | |
| | | setTimeout(() => { |
| | | drawBar(); |
| | | }, 200); |
| | | }) |
| | | .catch((error) => { |
| | | console.log(error); |
| | | }); |
| | | }; |
| | | //监控图标间隔 |
| | | const onTapInterval = () => { |
| | | if (!state.isOnTapInterval) { |
| | | myChart.value.setOption({ |
| | | yAxis: { |
| | | boundaryGap: ["0%", "0%"], |
| | | scale: true, |
| | | }, |
| | | }); |
| | | state.isOnTapInterval = true; |
| | | return; |
| | | } |
| | | if (state.isOnTapInterval) { |
| | | myChart.value.setOption({ |
| | | yAxis: { |
| | | boundaryGap: ["15%", "15%"], |
| | | scale: false, |
| | | }, |
| | | }); |
| | | state.isOnTapInterval = false; |
| | | return; |
| | | } |
| | | }; |
| | | //初始化获取数据 |
| | | const initialRealTimeRecord = () => { |
| | | axios({ |
| | | url: "http://47.101.141.88:9019/Run/MonitorRealRecord/Mobile/GetByMonitorPointIDOfDay@V1.0", |
| | | method: "GET", |
| | | headers: { |
| | | Authorization: `Bearer ${state.token}`, |
| | | }, |
| | | params: { |
| | | CorpID: 14, |
| | | MonitorPointID: state.PointID, |
| | | Day: state.currentRecordParas.RecordTime, |
| | | }, |
| | | }) |
| | | .then((res) => { |
| | | if (res.data.Code != 0) { |
| | | return; |
| | | } |
| | | if (res.data.Data == null || res.data.Data == "") { |
| | | return; |
| | | } |
| | | var data = res.data.Data || []; |
| | | state.chartData = data; |
| | | var last_record = state.chartData[state.chartData.length - 1]; //获取最后一条数据 |
| | | state.currentRecordParas.RecordStatusName = DataStatusTextEmun( |
| | | last_record.DataStatus |
| | | ); |
| | | state.currentRecordParas.RecordValue = last_record.DataValue; |
| | | let m_MonitorList = data.map((item) => { |
| | | let totalState = DataStatusTextEmun(item.DataStatus); |
| | | return { |
| | | RecordTime: subTime(item.DataTime, 11, 16), |
| | | RecordStatusText: totalState, |
| | | RecordValue: item.DataValue, |
| | | }; |
| | | }); |
| | | let monitor_List = data.map((item) => { |
| | | let normalState = DataStatusTextEmun(item.DataStatus); |
| | | if (normalState == "正常") { |
| | | return { |
| | | RecordTime: subTime(item.DataTime, 11, 16), |
| | | RecordStatusText: normalState, |
| | | RecordValue: item.DataValue, |
| | | }; |
| | | } |
| | | }); |
| | | state.monitorList = m_MonitorList; //源数据 |
| | | state.c_monitorList = monitor_List.reverse(); //切换数据 |
| | | |
| | | setTimeout(() => { |
| | | drawBar(); |
| | | }, 200); |
| | | }) |
| | | .catch((error) => { |
| | | console.log(error); |
| | | }); |
| | | }; |
| | | // 初始化echarts折线图 |
| | | const drawBar = () => { |
| | | //先获取Dom上的实例 |
| | | let chartDom = echarts.getInstanceByDom(document.getElementById("chartMain")); |
| | | //然后判断实例是否存在,如果不存在,就创建新实例 |
| | | if (chartDom == null) { |
| | | chartDom = echarts.init(document.getElementById("chartMain")); |
| | | myChart.value = chartDom; |
| | | } |
| | | let x_yData = []; |
| | | state.chartData.forEach((item) => { |
| | | x_yData.push({ value: [item.DataTime, item.DataValue] }); |
| | | }); |
| | | state.x_yData = x_yData; |
| | | let series_arr = []; |
| | | series_arr.push({ |
| | | type: "line", |
| | | showSymbol: false, |
| | | emphasis: { scale: false }, |
| | | data: state.x_yData, |
| | | itemStyle: { |
| | | color: "#4169E1", |
| | | }, |
| | | }); |
| | | let option = { |
| | | tooltip: { |
| | | trigger: "axis", |
| | | }, |
| | | legend: { |
| | | show: false, |
| | | fontSize: 12, |
| | | color: "#7e8390", |
| | | }, |
| | | grid: { |
| | | left: "5%", |
| | | right: "5%", |
| | | bottom: "10%", |
| | | top: "12%", |
| | | containLabel: true, |
| | | }, |
| | | xAxis: { |
| | | type: "time", |
| | | boundaryGap: false, |
| | | min: minDate, |
| | | max: maxDate, |
| | | axisLabel: { |
| | | showMaxLabel: true, |
| | | formatter: function (value) { |
| | | // 如果时间是 23:59:59 , 格式化为 24:00 |
| | | if ( |
| | | value === |
| | | new Date( |
| | | moment().endOf("day").format("YYYY-MM-DD HH:mm:ss") |
| | | ).getTime() |
| | | ) { |
| | | return moment(value).format("24:00"); |
| | | } else { |
| | | // 其他的时间返回格式化 00:00 |
| | | return moment(value).format("HH:mm"); |
| | | } |
| | | }, |
| | | }, |
| | | axisLine: { onZero: true, show: true }, |
| | | minorTick: { |
| | | show: false, |
| | | splitNumber: 2, |
| | | }, |
| | | splitLine: { |
| | | show: true, //是否显示分隔线 |
| | | interval: "auto", //坐标轴分隔线的显示间隔 |
| | | }, |
| | | }, |
| | | yAxis: { |
| | | boundaryGap: ["20%", "20%"], |
| | | |
| | | type: "value", |
| | | axisLabel: { |
| | | formatter: "{value}", |
| | | }, |
| | | // 整条y轴 |
| | | axisLine: { |
| | | show: true, |
| | | }, |
| | | }, |
| | | dataZoom: [ |
| | | { |
| | | type: "slider", //图表下方的伸缩条 |
| | | show: true, //是否显示 |
| | | realtime: true, // |
| | | start: 0, //伸缩条开始位置(1-100),可以随时更改 |
| | | end: 100, //伸缩条结束位置(1-100),可以随时更改 |
| | | left: 10, |
| | | right: 15, |
| | | bottom: 5, //底部的距离 |
| | | fillerColor: "rgba(22,181,203,0.4)", //选中范围的填充颜色。 |
| | | borderColor: "#ddd", //边框颜色。 |
| | | backgroundColor: "rgba(167,183,204,0.4)", //组件的背景颜色 |
| | | throttle: 100, //设置触发视图刷新的频率。单位为毫秒(ms)。 |
| | | handleIcon: |
| | | "path://M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z", |
| | | handleSize: "80%", // 控制手柄的尺寸,可以是像素大小,也可以是相对于 dataZoom 组件宽度的百分比,默认跟 dataZoom 宽度相同。 |
| | | handleStyle: { |
| | | color: "#16b5cb", |
| | | shadowBlur: 3, // shadowBlur图片阴影模糊值,shadowColor阴影的颜色 |
| | | shadowColor: "#77CCD8", |
| | | shadowOffsetX: 1, |
| | | shadowOffsetY: 1, |
| | | opacity: 0.6, |
| | | }, |
| | | }, |
| | | ], |
| | | series: series_arr, |
| | | }; |
| | | myChart.value.clear(); |
| | | myChart.value.setOption(option, true); |
| | | window.addEventListener("resize", selfAdaption); |
| | | times.value = setInterval(countdown, 1000); |
| | | }; |
| | | // 自适应 |
| | | const selfAdaption = () => { |
| | | if (!myChart.value) return; |
| | | myChart.value.resize(); |
| | | setTimeout(() => { |
| | | drawBar(); |
| | | }, 100); |
| | | }; |
| | | //获取详情 |
| | | const getRecordDetail = () => { |
| | | axios({ |
| | | url: "http://47.101.141.88:9019/Monitor/MonitorPoint/GetByID@V1.0", |
| | | method: "GET", |
| | | headers: { |
| | | Authorization: `Bearer ${state.token}`, |
| | | }, |
| | | params: { |
| | | CorpID: 14, |
| | | ID: state.PointID, |
| | | }, |
| | | }) |
| | | .then((res) => { |
| | | let getDetailData = res.data.Data || []; |
| | | if (res.data.Code != 0) { |
| | | return; |
| | | } |
| | | if (getDetailData == null || getDetailData == "") { |
| | | return; |
| | | } |
| | | pointName.value = getDetailData.Name; |
| | | }) |
| | | .catch((error) => { |
| | | console.log(error); |
| | | }); |
| | | }; |
| | | //切换状态(正常/中断) |
| | | const changeMonitorStatus = () => { |
| | | if (!state.isMonitorChange) { |
| | | let arr = []; |
| | | state.monitorList.forEach((item) => { |
| | | if (item.RecordStatusText != "正常") { |
| | | arr.push({ |
| | | RecordTime: item.RecordTime, |
| | | RecordStatusText: item.RecordStatusText, |
| | | RecordValue: item.RecordValue, |
| | | }); |
| | | } |
| | | }); |
| | | state.isMonitorChange = true; |
| | | state.c_monitorList = arr.reverse(); |
| | | return; |
| | | } else { |
| | | let arr = []; |
| | | state.monitorList.forEach((item) => { |
| | | if (item.RecordStatusText == "正常") { |
| | | arr.push({ |
| | | RecordTime: item.RecordTime, |
| | | RecordStatusText: item.RecordStatusText, |
| | | RecordValue: item.RecordValue, |
| | | }); |
| | | } |
| | | }); |
| | | state.isMonitorChange = false; |
| | | state.c_monitorList = arr.reverse(); |
| | | return; |
| | | } |
| | | }; |
| | | const DataStatusTextEmun = (value) => { |
| | | if (value.length == 0) return "正常"; |
| | | let text = ""; |
| | | if (value[0] == "GLSB") { |
| | | text = "过滤失败"; |
| | | } |
| | | if (value[0] == "SZGSCW") { |
| | | text = "数据格式错误"; |
| | | } |
| | | if (value[0] == "ZHSB") { |
| | | text = "转换失败"; |
| | | } |
| | | if (value[0] == "BJ") { |
| | | text = "报警"; |
| | | } |
| | | return text; |
| | | }; |
| | | //切割数字 |
| | | const subTime = (val, start, end) => { |
| | | var getVal = val.substring(start, end); |
| | | return getVal; |
| | | }; |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .main_contain { |
| | | background-color: #efeff4; |
| | | // overflow-y: unset; |
| | | .ec_header { |
| | | width: 100%; |
| | | font-size: 10px; |
| | | color: #fff; |
| | | display: flex; |
| | | |
| | | .ec_header_left { |
| | | width: 55%; |
| | | height: 82px; |
| | | background: linear-gradient(to left, #97d8e0, #16b5cb); |
| | | border-radius: 5px; |
| | | .ec_header_left_view { |
| | | height: 40px; |
| | | font-size: 20px; |
| | | font-weight: 600; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | .ec_header_name { |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | .ec_header_right { |
| | | width: 45%; |
| | | |
| | | font-size: 10px; |
| | | .ec_header_right_view { |
| | | height: 40px; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | background: linear-gradient(45deg, #97d8e0, #16b5cb); |
| | | border-radius: 3px; |
| | | margin: 1px 1px; |
| | | } |
| | | } |
| | | } |
| | | .container { |
| | | /* position: relative; */ |
| | | width: 100%; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | box-sizing: border-box; |
| | | background-color: #fff; |
| | | border-radius: 3px; |
| | | } |
| | | .ykt-detail-wraper { |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | margin: 10px auto; |
| | | background: #fff; |
| | | border-radius: 3px; |
| | | } |
| | | .ykt-detail-wrapers { |
| | | padding: 8px 0px 0px 0px; |
| | | // background: #fff; |
| | | width: 100%; |
| | | height: auto; |
| | | // height: calc(100vh - 60px); |
| | | // overflow-y: auto; |
| | | font-size: 12px; |
| | | justify-content: center; |
| | | } |
| | | .hykt_header { |
| | | width: 100%; |
| | | min-height: 25px; |
| | | background-color: #16b5cb; |
| | | color: #fff; |
| | | font-weight: 600; |
| | | border-radius: 50px; |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | justify-content: space-between; |
| | | .hykt_span { |
| | | font-size: 12px; |
| | | height: 100%; |
| | | min-width: 100px; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | } |
| | | |
| | | .hykt_li { |
| | | width: 100%; |
| | | min-height: 25px; |
| | | background-color: #fff; |
| | | color: #000; |
| | | font-weight: 500; |
| | | border-radius: 50px; |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | justify-content: space-between; |
| | | margin-bottom: 5px; |
| | | .hykt_span { |
| | | font-size: 12px; |
| | | height: 100%; |
| | | min-width: 100px; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | } |
| | | .custom-title { |
| | | text-align: left; |
| | | } |
| | | .icon_view { |
| | | font-size: 30px; |
| | | color: #fff; |
| | | width: 40px; |
| | | height: 40px; |
| | | position: fixed; |
| | | right: 10px; |
| | | z-index: 200; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #16b5cb; |
| | | border-radius: 5px; |
| | | box-shadow: 0 2px 6px 0 rgba(114, 124, 245, 0.5); |
| | | } |
| | | } |
| | | </style> |