From 8f50c8203c8df64dd0a566b228bae7f69156e109 Mon Sep 17 00:00:00 2001 From: web <candymxq888@outlook.com> Date: 星期二, 15 四月 2025 17:34:08 +0800 Subject: [PATCH] fix:添加季度选择器 --- src/views/screen/temperature/home/index.vue | 46 +++- .env.development | 2 src/views/screen/flow/ecology/index.vue | 4 package-lock.json | 9 src/views/screen/flow/home/index.vue | 77 ++++--- package.json | 1 src/views/screen/flow/graphic/index.vue | 59 ++--- vite.config.js | 15 src/api/screen/home/index.js | 12 + src/components/Quarter/index.vue | 210 +++++++++++++++++++++ src/views/screen/temperature/graphic/index.vue | 127 ++++++++---- 11 files changed, 432 insertions(+), 130 deletions(-) diff --git a/.env.development b/.env.development index 540224b..1a20aaa 100644 --- a/.env.development +++ b/.env.development @@ -8,7 +8,5 @@ # 图片地址 VITE_APP_IMG_BASEURL='http://192.168.0.200:8036/upload' -# 金川接口 - # VITE_APP_PUBLIC_REQUEST_API = 'http://113.250.189.120:8036' #后端本地 VITE_APP_PUBLIC_REQUEST_API = 'http://192.168.0.200:8036' diff --git a/package-lock.json b/package-lock.json index 6c56ad2..4ccd443 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "html2canvas": "^1.4.1", "js-cookie": "3.0.5", "jsencrypt": "3.3.2", + "moment": "^2.30.1", "nprogress": "0.2.0", "pinia": "2.1.7", "pinia-plugin-persist": "^1.0.0", @@ -3421,6 +3422,14 @@ "ufo": "^1.5.3" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/package.json b/package.json index fced173..b323d65 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "html2canvas": "^1.4.1", "js-cookie": "3.0.5", "jsencrypt": "3.3.2", + "moment": "^2.30.1", "nprogress": "0.2.0", "pinia": "2.1.7", "pinia-plugin-persist": "^1.0.0", diff --git a/src/api/screen/home/index.js b/src/api/screen/home/index.js new file mode 100644 index 0000000..942d07c --- /dev/null +++ b/src/api/screen/home/index.js @@ -0,0 +1,12 @@ +import { publicRequest } from '@/utils/request' + + +/** + * 获取生态流量首页监测点 + */ +export const getHomePonit = () => { + return publicRequest({ + url: '/waterFlow/getPointDate', + method: 'get', + }) +} \ No newline at end of file diff --git a/src/components/Quarter/index.vue b/src/components/Quarter/index.vue new file mode 100644 index 0000000..a566bf3 --- /dev/null +++ b/src/components/Quarter/index.vue @@ -0,0 +1,210 @@ +<script setup> +import {onMounted, ref, watch} from 'vue' + +const props = defineProps({ + valueArr: { + default: () => { + return ['01-03', '04-06', '07-09', '10-12']; + }, + type: Array, + }, + getValue: { + default: () => { }, + type: Function, + }, + // 传入显示的时间 + defaultValue: { + default: "", + type: String, + }, + limitTime: { + type: String, + default: '' + }, + clearable: { + type: Boolean, + default: false + }, + placeholder: { + type: String, + default: '' + } +}) +const emit = defineEmits(['change']) + +const showSeason = ref(false) +const showValue = ref('') +const year = ref(new Date().getFullYear()) +const season = ref() + +watch(() => props.defaultValue, (value) => { + initDefaultValue(value) +}) + +const prev = () => { + year.value = year.value * 1 - 1; +} +const next = () => { + // 如果有时间限制的话会进行判断 + if (props.limitTime == "") { + year.value = year.value * 1 + 1; + } else if (props.limitTime != "" && year.value < props.limitTime) { + year.value = year.value * 1 + 1; + } +} + +const whitchQuarter = (month) => { + let quarter = ""; + month = Number(month); + switch (month) { + case 1: + case 2: + case 3: + quarter = "1"; + break; + case 4: + case 5: + case 6: + quarter = "2"; + break; + case 7: + case 8: + case 9: + quarter = "3"; + break; + case 10: + case 11: + case 12: + quarter = "4"; + break; + default: + console.error("The entered time is incorrect"); + } + return quarter; +} + +// 季度时间判定 +const InitialTime = (val) => { + let num = ""; + val = Number(val); + switch (val) { + case 1: + num = "01"; + break; + case 2: + num = "04"; + break; + case 3: + num = "07"; + break; + case 4: + num = "10"; + break; + default: + console.error("时间格式有误!"); + } + return num; +} + +const selectSeason = (i) => { + season.value = i + 1; + let arr = props.valueArr[i].split("-"); + props.getValue(year.value + arr[0] + "-" + year.value + arr[1]); + showSeason.value = false; + showValue.value = `${year.value}年${season.value}季度`; + var formatValue = `${year.value}-${InitialTime(season.value)}`; + emit("change", formatValue); +} + +const initDefaultValue = (value) => { + let arr = value.split("-"); + year.value = arr[0].slice(0, 4); + var myseason = arr[1]; + showValue.value = `${year.value}年${whitchQuarter(myseason)}季度`; +} + + +onMounted(() => { + if (props.defaultValue) { + console.log(props.defaultValue) + initDefaultValue(props.defaultValue); + } +}) +</script> + +<template> + <div class="quarter"> + <mark style="position:fixed;top:0;bottom:0;left:0;right:0;background:rgba(0,0,0,0);z-index:999;" v-show="showSeason" + @click.stop="showSeason = false"></mark> + <el-popover + :visible="showSeason" + placement="bottom" + trigger="click" + class="popover" + :width="300" + > + <template #reference> + <el-input :placeholder="props.placeholder" v-model="showValue" style="width:100%;" class="elWidth" :clearable="props.clearable" @click="showSeason = true" > + <template #prefix> + <el-icon class="el-input__icon"><Calendar /></el-icon> + </template> + </el-input> + </template> + <template #default> + <div class="box-card"> + <div class="yearBox"> + <el-button type="info" icon="DArrowLeft" @click="prev" link></el-button> + <span role="button" class="el-date-picker__header-label">{{ year }}年</span> + <el-button type="info" @click="next" :class="{ notallow: year === props.limitTime }" + icon="DArrowRight" link></el-button> + </div> + <div class="text"> + <div @click="selectSeason(0)" class="item">第一季度</div> + <div @click="selectSeason(1)" class="item">第二季度</div> + </div> + <div class="text"> + <div @click="selectSeason(2)" class="item">第三季度</div> + <div @click="selectSeason(3)" class="item">第四季度</div> + </div> + </div> + </template> + </el-popover> + </div> +</template> + +<style scoped lang="scss"> +.quarter{ + width: 100%; + .elWidth{ + width: 100%; + } +} +:deep(.el-popover .el-popper){ + width: 300px !important; +} +.notallow { + cursor: not-allowed; +} +.box-card { + width: 100%; + .yearBox{ + text-align:center; + padding:0; + display: flex; + justify-content: space-between; + align-items: center; + } + .text{ + margin-top: 1rem; + display: flex; + .item{ + width: 50%; + text-align: center; + &:hover{ + color: #409eff !important; + cursor: pointer; + } + } + } +} +</style> \ No newline at end of file diff --git a/src/views/screen/flow/ecology/index.vue b/src/views/screen/flow/ecology/index.vue index 1517ac2..d274b14 100644 --- a/src/views/screen/flow/ecology/index.vue +++ b/src/views/screen/flow/ecology/index.vue @@ -35,7 +35,7 @@ trigger: 'axis', }, grid: { - left: 60, + left: 100, right: 20, }, xAxis: { @@ -96,7 +96,7 @@ trigger: 'axis', }, grid: { - left: 60, + left: 100, right: 20, }, xAxis: { diff --git a/src/views/screen/flow/graphic/index.vue b/src/views/screen/flow/graphic/index.vue index bb71b1a..8d5a773 100644 --- a/src/views/screen/flow/graphic/index.vue +++ b/src/views/screen/flow/graphic/index.vue @@ -1,16 +1,13 @@ <script setup> -import {ref} from "vue"; +import {onMounted, ref} from "vue"; import {getUserType} from '@/utils/auth.js' import html2canvas from "html2canvas"; +import {getFlowPointList} from '@/api/screen/index' +const menuList = ref([]) const userType = ref(getUserType()) const monitorRef = ref() const searchVal = ref('') -const selectType = ref(1); -const typeOption = ref([ - { label: '水电站流量监测点', value: 1 }, - { label: '新扎口流量监测点', value: 2 }, -]) const video = ref() // 全屏操作 @@ -33,6 +30,19 @@ const handleSearch = async () => { } + +// 获取监控点 +const getMoitorList = () => { + getFlowPointList().then(res => { + menuList.value = res.data + }) +} + + +onMounted(() => { + getMoitorList() +}) + </script> <template> @@ -40,37 +50,26 @@ <div class="graphic-menu"> <div class="menu-t">监控点列表</div> <el-menu class="el-menu"> - <el-sub-menu index="1"> - <template #title> - <span>可移动监测点</span> + <template v-for="(item, index) in menuList" :key="index+1"> + <template v-if="item?.childrenList?.length === 0"> + <el-menu-item :index="item.id">{{ item.pointName }}</el-menu-item> </template> - <el-menu-item index="1-1">水电站流量监测点</el-menu-item> - </el-sub-menu> - <el-sub-menu index="2"> - <template #title> - <span>固定位监测点</span> + <template v-else> + <el-sub-menu :index="item.id"> + <template #title> + <span>{{ item.pointName }}</span> + </template> + <el-menu-item v-for="(child, cidx) in item.childrenList" :key="cidx" :index="child.id"> + {{ child.pointName }} + </el-menu-item> + </el-sub-menu> </template> - <el-menu-item index="2-1">新扎口流量监测点</el-menu-item> - </el-sub-menu> + </template> </el-menu> </div> <div class="graphic-monitor"> <div class="monitor-tool"> <div class="tool-l"> - <div class="name">监测点类型</div> - <el-select - v-model="selectType" - class="tool-select" - placeholder="Select" - style="width: 15rem" - > - <el-option - v-for="item in typeOption" - :key="item.value" - :label="item.label" - :value="item.value" - /> - </el-select> <el-input v-model="searchVal" style="width: 20rem" placeholder="请输入监测点名称" /> <el-button @click="handleSearch"><el-icon><Search /></el-icon>搜索</el-button> <el-button style="margin-left: 0" v-if="userType === '1'"><el-icon><Plus /></el-icon>新增</el-button> diff --git a/src/views/screen/flow/home/index.vue b/src/views/screen/flow/home/index.vue index 546c237..dfbc0b7 100644 --- a/src/views/screen/flow/home/index.vue +++ b/src/views/screen/flow/home/index.vue @@ -6,31 +6,31 @@ <div class="point-address" @click="handleShow(index)"></div> <div class="point-message" v-show="item.showMsg"> <div class="msg-box"> - <div class="video-box"> + <div class="video-box" :style="{backgroundImage: `url(${item.imageRul})`}"> <el-icon><VideoPlay /></el-icon> </div> <div class="info-box"> - <div class="info-t">{{ item.name }}</div> - <div class="info-sw">水位:<span>{{ item.shuiwei }}</span>m</div> - <div class="info-ls">流速:<span>{{item.liushu}}</span>m/s</div> - <div class="info-ssls">瞬时流速:<span>{{ item.ssls }}</span>m/s</div> + <div class="info-t">{{ item.pointName }}</div> + <div class="info-sw">水位:<span>{{ item.waterLevel }}</span>m</div> + <div class="info-ls">流速:<span>{{item.newFlow}}</span>m/s</div> + <div class="info-ssls">瞬时流速:<span>{{ item.flowVelocity }}</span>m/s</div> <div class="info-ljll"> 累计流量: <el-select - v-model="selectll" + v-model="selectll[index]" class="m-2" placeholder="Select" size="small" style="width: 240px" > <el-option - v-for="(item, idx) in item.liuliangOptions" + v-for="(item, idx) in liuliangOptions" :key="idx" :label="item.label" - :value="idx" + :value="item.value" /> </el-select> - <span>{{ item.liuliangOptions[selectll].value }}</span>m/s + <span>{{ item[selectll[index]] }}</span>m/s </div> </div> </div> @@ -42,34 +42,46 @@ <script setup> -import {ref} from "vue"; +import {ref, onMounted} from "vue"; +import {getHomePonit} from '@/api/screen/home/index.js' -const selectll = ref(0) +// 标点配置 +const config = [ + { left: '18%', top: '67%', showMsg: false }, + { left: '60%', top: '12.5%', showMsg: false }, +] +const liuliangOptions = [ + { label: '总计流量', value: 'totalFlow' }, + { label: '日累计流量', value: 'dayFlow' }, + { label: '周累计流量', value: 'weekFlow' }, + { label: '月累计流量', value: 'monthFlow' }, + { label: '年累计流量', value: 'yearFlow' }, +] -const pointList = reactive([ - { name: '新扎沟口流量监测点', liushu: 22, ssls: '38', shuiwei: 1000, device: 1, left: '18%', top: '67%', showMsg: false, - liuliangOptions: [ - { label: '总计流量', value: 500 }, - { label: '日累计流量', value: 1000 }, - { label: '周累计流量', value: 10000 }, - { label: '月累计流量', value: 300000 }, - { label: '年累计流量', value: 3600000 }, - ] - }, - { name: '电站尾水出口水温监测点', liushu: 22, ssls: '38', shuiwei: 1000, device: 2, left: '60%', top: '12.5%', showMsg: false, - liuliangOptions: [ - { label: '总计流量', value: 500 }, - { label: '日累计流量', value: 1000 }, - { label: '周累计流量', value: 10000 }, - { label: '月累计流量', value: 300000 }, - { label: '年累计流量', value: 3600000 }, - ] - }, -]) +const selectll = ref(['totalFlow', 'totalFlow']) +const pointList = ref([]) + + +const getPoint = () => { + getHomePonit().then(res => { + let data = res.data + if(data.length > 2) data = data.splice(0, 1) + pointList.value = data.map((item, index) => { + return { + ...item, + ...config[index] + } + }) + }) +} const handleShow = (index) => { - pointList[index].showMsg = !pointList[index].showMsg; + pointList.value[index].showMsg = !pointList.value[index].showMsg; } + +onMounted(() => { + getPoint() +}) </script> @@ -124,7 +136,6 @@ line-height: 138px; text-align: center; font-size: 38px; - background: #cccb40; } .info-box{ height: 100%; diff --git a/src/views/screen/temperature/graphic/index.vue b/src/views/screen/temperature/graphic/index.vue index 3fb2e77..2fc797e 100644 --- a/src/views/screen/temperature/graphic/index.vue +++ b/src/views/screen/temperature/graphic/index.vue @@ -2,16 +2,15 @@ import {ref, reactive, onMounted} from "vue"; import * as echarts from 'echarts/core'; import html2canvas from "html2canvas"; +import {getTemperaturePointList} from '@/api/screen/index.js' +import Quarter from "@/components/Quarter"; +import moment from "moment"; -const startTime = ref() -const endTime = ref() +const menuList = ref([]) +const timeType = ref('date') +const timeRange = ref() const searchVal = ref() -const selectType = ref(1); -const typeOption = ref([ - { label: '水电站流量监测点', value: 1 }, - { label: '新扎口流量监测点', value: 2 }, -]) const graphicRef = ref(null) const chartsRef = ref([]) //动态生成图表ref let charts = [] @@ -99,6 +98,10 @@ } } +const changeType = (type) => { + timeType.value = type; + timeRange.value = '' +} // 初始化图表 const initCharts = () => { @@ -118,7 +121,7 @@ // 一键导出 const handleExport = () => { - chartsRef.value?.forEach(item => { + chartsRef.value?.forEach((item, index) => { html2canvas(item, { scale: 2, // 提高渲染质量 useCORS: true, // 如果需要跨域资源 @@ -127,13 +130,27 @@ }).then(canvas => { const link = document.createElement("a"); link.href = canvas.toDataURL("image/png"); - link.download = '截图.png'; + link.download = `图表分析${index}.png`; link.click() }) }) } +// 获取水温监控点菜单 +const getTempMonitor = () => { + getTemperaturePointList().then(res => { + menuList.value = res.data + }) +} + +// 获取时间 +const getTime = (value) => { + const time = moment(value).format('YYYY-MM-DD') + console.log(time) +} + onMounted(() => { + getTempMonitor() initCharts() }) @@ -144,51 +161,75 @@ <div class="graphic-menu"> <div class="menu-t">监测点列表</div> <el-menu class="el-menu"> - <el-sub-menu index="1"> - <template #title> - <span>可移动监测点</span> + <template v-for="(item, index) in menuList" :key="index+1"> + <template v-if="item?.childrenList?.length === 0"> + <el-menu-item :index="item.id">{{ item.pointName }}</el-menu-item> </template> - <el-menu-item index="1-1">水电站流量监测点</el-menu-item> - </el-sub-menu> - <el-sub-menu index="2"> - <template #title> - <span>固定位监测点</span> + <template v-else> + <el-sub-menu :index="item.id"> + <template #title> + <span>{{ item.pointName }}</span> + </template> + <el-menu-item v-for="(child, cidx) in item.childrenList" :key="cidx" :index="child.id"> + {{ child.pointName }} + </el-menu-item> + </el-sub-menu> </template> - <el-menu-item index="2-1">新扎口流量监测点</el-menu-item> - </el-sub-menu> + </template> </el-menu> </div> <div class="graphic-info"> <div class="graphic-tool"> <div class="tool-l"> - <div class="name">开始时间</div> + <div class="name">类型</div> + <el-button-group class="ml-4"> + <el-button :type="timeType === 'date' ? 'primary' : ''" @click="changeType('date')">日</el-button> + <el-button :type="timeType === 'week' ? 'primary' : ''" @click="changeType('week')">周</el-button> + <el-button :type="timeType === 'month' ? 'primary' : ''" @click="changeType('month')">月</el-button> + <el-button :type="timeType === 'quarter' ? 'primary' : ''" @click="changeType('quarter')">季</el-button> + <el-button :type="timeType === 'year' ? 'primary' : ''" @click="changeType('year')">年</el-button> + </el-button-group> <el-date-picker - v-model="startTime" - type="datetime" - style="width: 12rem" - placeholder="请选择开始时间" + v-if="timeType === 'date'" + v-model="timeRange" + type="date" + placeholder="选择时间" + style="width: 15rem" + @change="getTime" /> - <div class="name">结束时间</div> <el-date-picker - v-model="endTime" - type="datetime" - style="width: 12rem" - placeholder="请选择结束时间" + v-if="timeType === 'week'" + v-model="timeRange" + type="week" + format="YYYY年 ww[周]" + placeholder="选择时间" + style="width: 15rem" + @change="getTime" /> - <div class="name">监测点区域</div> - <el-select - v-model="selectType" - class="tool-select" - placeholder="Select" - style="width: 10rem" - > - <el-option - v-for="item in typeOption" - :key="item.value" - :label="item.label" - :value="item.value" - /> - </el-select> + <el-date-picker + v-if="timeType === 'month'" + v-model="timeRange" + type="month" + placeholder="选择时间" + style="width: 15rem" + @change="getTime" + /> + <Quarter + v-if="timeType === 'quarter'" + placeholder="选择时间" + :default-value="timeRange" + clearable + style="width: 15rem" + @change="getTime" + /> + <el-date-picker + v-if="timeType === 'year'" + v-model="timeRange" + type="year" + placeholder="选择时间" + style="width: 15rem" + @change="getTime" + /> <el-input v-model="searchVal" style="width: 15rem" placeholder="请输入监测点名称" /> <el-button><el-icon><Search /></el-icon>搜索</el-button> <el-button type="success" @click="handleExport">一键导出</el-button> diff --git a/src/views/screen/temperature/home/index.vue b/src/views/screen/temperature/home/index.vue index dc0a0cb..9fa20bc 100644 --- a/src/views/screen/temperature/home/index.vue +++ b/src/views/screen/temperature/home/index.vue @@ -2,25 +2,25 @@ <div class="home"> <div class="home-bg"></div> <div class="home-c"> - <div class="point" v-for="(item, index) in pointList" :key="index" :style="{left: item.left, top: item.top}"> + <div class="point" v-for="(item, index) in monitorList" :key="index" :style="{left: item.left, top: item.top}"> <div class="point-address" @click="handleShow(index)"></div> <div class="point-message" v-show="item.showMsg"> <div class="msg-box"> - <div class="msg-t">{{ item.name }}</div> + <div class="msg-t">{{ item.pointName }}</div> <div class="num"> <div class="item"> <div class="item-t">水温:</div> - <div class="item-num"><span>{{item.temputer}}</span>°C</div> + <div class="item-num"><span>{{item.waterTemperature}}</span>°C</div> </div> <div class="item"> <div class="item-t">水位:</div> - <div class="item-num"><span>{{ item.shuiwei }}</span>m</div> + <div class="item-num"><span>{{ item.waterLevel }}</span>m</div> </div> </div> <div class="shebei"> 监测设备: - <span v-if="item.device === 1" style="color: #1ab394">监测设备运行正常(点击跳转)</span> - <span v-else style="color: #ff0a0a">设备异常</span> + <span v-if="item.isOnline === 1">设备运作正常</span> + <span v-else style="color: red">设备运作异常</span> </div> </div> </div> @@ -31,16 +31,38 @@ <script setup> +import pointApi from '@/api/facility/point.js' +import {ref, onMounted} from "vue"; -const pointList = reactive([ - { name: '电站尾水出口水温监测点', temputer: 22, shuiwei: 1000, device: 1, left: '15%', top: '53%', showMsg: false }, - { name: '电站尾水出口水温监测点', temputer: 22, shuiwei: 1000, device: 2, left: '12%', top: '68%', showMsg: false }, -]) +const monitorList = ref([]) -const handleShow = (index) => { - pointList[index].showMsg = !pointList[index].showMsg; +// 标点配置 +const config = [ + { left: '15%', top: '53%', showMsg: false }, + { left: '12%', top: '68%', showMsg: false }, +] + +// 获取监控点列表 +const getMonitorList = () => { + pointApi().search({type: 1, page: 1, limit: 3}).then(res => { + let data = res.data.list.filter(el => el.parentId !== 0) + if(data.length > 2) data = data.splice(0, 1) + monitorList.value = data.map((item, index) => { + return { + ...item, + ...config[index] + } + }) + }) } +const handleShow = (index) => { + monitorList.value[index].showMsg = !monitorList.value[index].showMsg; +} + +onMounted(() => { + getMonitorList() +}) </script> diff --git a/vite.config.js b/vite.config.js index b191f63..c41397c 100644 --- a/vite.config.js +++ b/vite.config.js @@ -28,14 +28,13 @@ port: 5036, host: true, open: true, - proxy: { - // https://cn.vitejs.dev/config/#server-proxy - '/dev-api': { - target: 'http://localhost:8080', - changeOrigin: true, - rewrite: (p) => p.replace(/^\/dev-api/, '') - } - } + // proxy: { + // '/api': { + // target: 'http://192.168.0.200:8036', + // changeOrigin: true, + // rewrite: (p) => p.replace(/^\/api/, '') + // } + // } }, //fix:error:stdin>:7356:1: warning: "@charset" must be the first rule in the file css: { -- Gitblit v1.9.3