From 200737d7c5fee9de223a92bd1a4aaeb05733a27f Mon Sep 17 00:00:00 2001 From: web <candymxq888@outlook.com> Date: 星期四, 20 三月 2025 17:31:24 +0800 Subject: [PATCH] feat:添加报表,监控功能 --- src/assets/styles/index.scss | 4 src/views/screen/flow/shebei/index.vue | 350 ++++++++++++++++ src/views/screen/flow/report/index.vue | 109 +++++ src/components/Table/index.vue | 127 ++++++ src/api/facility/parameter.js | 2 src/assets/styles/ruoyi.css | 27 - src/api/configuration/warning/alarmScheme.js | 69 +++ src/components/Pagination/index.vue | 24 src/assets/styles/index.css | 31 - src/assets/styles/ruoyi.scss | 27 - src/views/screen/flow/ecology/index.vue | 7 src/main.js | 9 src/views/configuration/warning/index.vue | 264 ++++++++++++ index.html | 4 src/views/screen/flow/warning/index.vue | 166 +++++++ src/views/screen/flow/graphic/index.vue | 4 16 files changed, 1,107 insertions(+), 117 deletions(-) diff --git a/index.html b/index.html index 8fb942e..e6a3153 100644 --- a/index.html +++ b/index.html @@ -17,6 +17,10 @@ height: 100%; margin: 0; padding: 0; + //控制初始字体大小 + @media(min-width: 1921px) and (max-width: 3840px) { + font-size: 32px; + } } .chromeframe { diff --git a/src/api/configuration/warning/alarmScheme.js b/src/api/configuration/warning/alarmScheme.js new file mode 100644 index 0000000..985755a --- /dev/null +++ b/src/api/configuration/warning/alarmScheme.js @@ -0,0 +1,69 @@ +/* + * @Author: elkers + * @Date: 2024-08-09 14:29:49 + * @LastEditors: hqs elkers@163.com + * @LastEditTime: 2024-08-10 08:57:04 + * @FilePath: \water-qinghe-web\src\api\alarmApi\alarmHistory.js + * @Description: 历史记录api + */ +import { publicRequest } from '@/utils/request' +export default function alarmSchemeApi() { + return { + create: (data) => { + return publicRequest({ + url: '/alarmScheme/create', + method: 'post', + data, + }); + }, + modify: (data) => { + return publicRequest({ + url: '/alarmScheme/modify', + method: 'post', + data, + }); + }, + remove: (data) => { + return publicRequest({ + url: `/alarmScheme/remove?id=${data}`, + method: 'post', + data, + }); + }, + stop: (data) => { + return publicRequest({ + url: `/alarmScheme/stop?id=${data}`, + method: 'post', + data, + }); + }, + enable: (data) => { + return publicRequest({ + url: `/alarmScheme/enable?id=${data}`, + method: 'post', + data, + }); + }, + search: (data) => { + return publicRequest({ + url: '/alarmScheme/search', + method: 'post', + data, + }); + }, + get: (data) => { + return publicRequest({ + url: `/alarmScheme/get?id=${data}`, + method: 'get', + data, + }); + }, + setSort: (data) => { + return publicRequest({ + url: `/alarmScheme/setSort`, + method: 'post', + data, + }); + } + }; +} diff --git a/src/api/facility/parameter.js b/src/api/facility/parameter.js index 0bae0e4..1982161 100644 --- a/src/api/facility/parameter.js +++ b/src/api/facility/parameter.js @@ -9,7 +9,7 @@ import { publicRequest } from '@/utils/request.js' -//公司配置信息 +//配置信息 export default function waterFacilityParameter() { return { create: (data) => { diff --git a/src/assets/styles/index.css b/src/assets/styles/index.css index 1831e37..3580123 100644 --- a/src/assets/styles/index.css +++ b/src/assets/styles/index.css @@ -646,19 +646,6 @@ padding-bottom: 5px; } -/** 表格布局 **/ -.pagination-container { - position: relative; - height: 25px; - margin-bottom: 10px; - margin-top: 15px; - padding: 10px 20px !important; -} - -.el-dialog .pagination-container { - position: static !important; -} - /* tree border */ .tree-border { margin-top: 5px; @@ -666,20 +653,6 @@ background: #FFFFFF none; border-radius: 4px; width: 100%; -} - -.pagination-container .el-pagination { - right: 0; - position: absolute; -} - -@media (max-width: 768px) { - .pagination-container .el-pagination > .el-pagination__jump { - display: none !important; - } - .pagination-container .el-pagination > .el-pagination__sizes { - display: none !important; - } } .el-table .fixed-width .el-button--small { @@ -946,10 +919,6 @@ .components-container { margin: 30px 50px; position: relative; -} - -.pagination-container { - margin-top: 30px; } .text-center { diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss index 0e39618..50ba487 100644 --- a/src/assets/styles/index.scss +++ b/src/assets/styles/index.scss @@ -131,10 +131,6 @@ position: relative; } -.pagination-container { - margin-top: 30px; -} - .text-center { text-align: center } diff --git a/src/assets/styles/ruoyi.css b/src/assets/styles/ruoyi.css index c9afbd4..2c6cb29 100644 --- a/src/assets/styles/ruoyi.css +++ b/src/assets/styles/ruoyi.css @@ -107,19 +107,6 @@ padding-bottom: 5px; } -/** 表格布局 **/ -.pagination-container { - position: relative; - height: 25px; - margin-bottom: 10px; - margin-top: 15px; - padding: 10px 20px !important; -} - -.el-dialog .pagination-container { - position: static !important; -} - /* tree border */ .tree-border { margin-top: 5px; @@ -127,20 +114,6 @@ background: #FFFFFF none; border-radius: 4px; width: 100%; -} - -.pagination-container .el-pagination { - right: 0; - position: absolute; -} - -@media (max-width: 768px) { - .pagination-container .el-pagination > .el-pagination__jump { - display: none !important; - } - .pagination-container .el-pagination > .el-pagination__sizes { - display: none !important; - } } .el-table .fixed-width .el-button--small { diff --git a/src/assets/styles/ruoyi.scss b/src/assets/styles/ruoyi.scss index 64bf930..9099a0a 100644 --- a/src/assets/styles/ruoyi.scss +++ b/src/assets/styles/ruoyi.scss @@ -100,19 +100,6 @@ padding-bottom:5px } -/** 表格布局 **/ -.pagination-container { - position: relative; - height: 25px; - margin-bottom: 10px; - margin-top: 15px; - padding: 10px 20px !important; -} - -.el-dialog .pagination-container { - position: static !important; -} - /* tree border */ .tree-border { margin-top: 5px; @@ -120,20 +107,6 @@ background: #FFFFFF none; border-radius:4px; width: 100%; -} - -.pagination-container .el-pagination { - right: 0; - position: absolute; -} - -@media ( max-width : 768px) { - .pagination-container .el-pagination > .el-pagination__jump { - display: none !important; - } - .pagination-container .el-pagination > .el-pagination__sizes { - display: none !important; - } } .el-table .fixed-width .el-button--small { diff --git a/src/components/Pagination/index.vue b/src/components/Pagination/index.vue index 38de953..03fa929 100644 --- a/src/components/Pagination/index.vue +++ b/src/components/Pagination/index.vue @@ -1,16 +1,16 @@ <template> <div :class="{ 'hidden': hidden }" class="pagination-container"> - <el-pagination - :background="background" - v-model:current-page="currentPage" - v-model:page-size="pageSize" - :layout="layout" - :page-sizes="pageSizes" - :pager-count="pagerCount" - :total="total" - @size-change="handleSizeChange" - @current-change="handleCurrentChange" - /> + <el-pagination + :background="background" + v-model:current-page="currentPage" + v-model:page-size="pageSize" + :layout="layout" + :page-sizes="pageSizes" + :pager-count="pagerCount" + :total="total" + @size-change="handleSizeChange" + @current-change="handleCurrentChange" + /> </div> </template> @@ -98,6 +98,8 @@ .pagination-container { background: #fff; padding: 32px 16px; + display: flex; + justify-content: flex-end; } .pagination-container.hidden { display: none; diff --git a/src/components/Table/index.vue b/src/components/Table/index.vue new file mode 100644 index 0000000..1c3c1b5 --- /dev/null +++ b/src/components/Table/index.vue @@ -0,0 +1,127 @@ +<script setup> +/** + * getList 获取列表 + * headList 列定义 + * order 是否排序 + * orderFun: function (a, b){ return Number(a.code) > Number(b.code) ? 1 : -1 } 排序函数 + * fixed 是否固定列 + * filters 列过滤 + * filterFun 过滤函数 + * slot 自定义列, row为当前列插槽传参, 接收 <template #code="scope"> </template>, code为插槽名 + * select 是否可选择 + * + */ +import {onMounted, ref} from "vue"; + +const props = defineProps({ + getList: { + type: Function, + default: () => {}, + required: true + }, + headList: { + type: Array, + default: [], + required: true + }, + select: { + type: Boolean, + default: false + } +}) + +const state = reactive({ + page: 1, + limit: 10, + total: 0, + list: [] +}) +const loading = ref(false); + +const getData = (data) => { + const pagedata = { limit: state.limit, page: data.page} + loading.value = true; + props.getList(pagedata).then(res => { + state.list = res.list + state.total = res.total + }).finally(() => { + loading.value = false; + }) +} + +onMounted(() =>{ + getData({ page: state.page }) +}) +</script> + +<template> + <div style="width: 100%; height: 100%"> + <el-table :data="state.list" + v-loading="loading" + ref="multipleTable" + style="width: 100%; height: 85%"> + <el-table-column v-if="props.select" type="selection"></el-table-column> + <el-table-column + type="index" + label="序号" + align="center" + width="80px" + ></el-table-column> + <template v-for="item in props.headList"> + <!-- 排序列 --> + <el-table-column + v-if="item.order" + :prop="item.prop" + :label="item.label" + :sortable="item?.order" + :sort-method="item?.orderFun" + /> + <!-- 正常列 --> + <el-table-column + v-else + :prop="item.prop" + :label="item.label" + :fixed="item?.fixed" + :filters="item?.filters" + :filter-method="item?.filterFun" + > + <template #default="scope"> + <!-- 自定义列 --> + <template v-if="item?.slot"> + <slot :name="item.prop" :row="scope.row"></slot> + </template> + </template> + </el-table-column> + </template> + </el-table> + <div class="pagination"> + <div class="pagination-total">共{{state.total}}条</div> + <pagination + v-show="state.total > 0" + layout="prev, pager, next, jumper" + :total="state.total" + :page="state.current" + :limit="state.limit" + @pagination="getData" + /> + <!-- 页面右侧自定义插槽,可以加自定义按钮 --> + <slot name="pagination"></slot> + </div> + </div> +</template> + +<style scoped lang="scss"> +.pagination{ + display: flex; + align-items: center; + justify-content: flex-end; + .pagination-total{ + color: #fff; + } +} +:deep(.pagination-container){ + background-color: transparent; + margin: 0; + padding: 20px; +} +</style> \ No newline at end of file diff --git a/src/main.js b/src/main.js index bfb5348..8786be8 100644 --- a/src/main.js +++ b/src/main.js @@ -34,6 +34,15 @@ import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, selectDictLabels } from '@/utils/ruoyi' +// 按需引入echarts +import * as echarts from 'echarts/core'; +import { GridComponent, ToolboxComponent, TooltipComponent, TitleComponent } from 'echarts/components'; +import { LineChart, BarChart } from 'echarts/charts'; +import { UniversalTransition } from 'echarts/features'; +import { CanvasRenderer } from 'echarts/renderers'; + +echarts.use([GridComponent, LineChart, BarChart, CanvasRenderer, UniversalTransition, ToolboxComponent, TooltipComponent, TitleComponent]); + // 分页组件 import Pagination from '@/components/Pagination' // 自定义树选择组件 diff --git a/src/views/configuration/warning/index.vue b/src/views/configuration/warning/index.vue new file mode 100644 index 0000000..640b144 --- /dev/null +++ b/src/views/configuration/warning/index.vue @@ -0,0 +1,264 @@ +<template> + <div class="app-container"> + <el-form :model="queryParams" ref="queryRef" :inline="true"> + <el-form-item prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入内容" + clearable + style="width: 200px" + @keyup.enter="handleQuery" + /> + </el-form-item> + <el-form-item> + <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> + <el-button icon="Refresh" @click="resetQuery">重置</el-button> + </el-form-item> + </el-form> + + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button + type="primary" + plain + icon="Plus" + @click="handleAdd" + >新增</el-button> + </el-col> + </el-row> + <!--表格及分页--> + <el-table v-loading="loading" :data="tableData"> + <el-table-column + v-for="(item, key, index) of tableHeader" + :prop="key.toString()" + :label="item" + :key="index" + align="center" + > + </el-table-column> + <el-table-column label="操作" width="auto" align="center" class-name="small-padding fixed-width"> + <template #default="scope"> + <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button> + <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button> + </template> + </el-table-column> + </el-table> + <pagination + :total="pageParam.total" + v-model:page="pageParam.page" + v-model:limit="pageParam.limit" + :page-sizes="[10,20,30]" + @pagination="getList" + /> + <!-- 添加或修改对话框 --> + <el-dialog :title="title" v-model="open" append-to-body center> + <el-form class="form-box" ref="formRef" :model="form" :rules="rules" label-width='auto'> + <el-form-item label="选择设备" prop="facilityId"> + <el-select v-model="form.facilityId" placeholder="请选择设备" @change="getFacityCodeList"> + <el-option + v-for="(item,index) in facityList" + :label="item.facilityName" + :value="item.id" + :key="index" + ></el-option> + </el-select> + </el-form-item> + <el-form-item label="设备参数" prop="columnsCode"> + <el-select v-model="form.columnsCode" placeholder="请选择设备参数"> + <el-option + v-for="(item,index) in facityCodeList" + :label="item.columnsShow" + :value="item.columnsCode" + :key="index" + ></el-option> + </el-select> + </el-form-item> + <el-form-item label="方案名称" prop="schemeName"> + <el-input v-model="form.schemeName" placeholder="请输入方案名称" /> + </el-form-item> + <el-form-item label="低报警值" prop="lowAlarm"> + <el-input v-model="form.lowAlarm" placeholder="请输入低报警值" /> + </el-form-item> + <el-form-item label="高报警值" prop="tallAlarm"> + <el-input v-model="form.tallAlarm" placeholder="请输入高报警值" /> + </el-form-item> + <el-form-item label="备注" prop="remark"> + <el-input v-model="form.remark" placeholder="请输入备注" /> + </el-form-item> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button type="primary" @click="submitForm">确 定</el-button> + <el-button @click="cancel">取 消</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup name="Menu"> +import facilityApi from '@/api/facility/index.js' +import waterFacilityParameter from '@/api/facility/parameter.js' +import alarmSchemeApi from '@/api/configuration/warning/alarmScheme.js' +import setPostParams from "@/utils/searchParams.js"; +import {onMounted} from "vue"; +const { proxy } = getCurrentInstance(); + + +const pageParam = ref({ + total:0, + limit:0, + page:0, +}) +const tableData = ref([]); +let tableHeader = ref({ + schemeName: '方案名称', + facilityName: '设备名称', + columnsName: '参数名称', + lowAlarm: '低报警值', + tallAlarm: '高报警值', + remark: '备注', + createTimeView: '创建时间', +}) + +const open = ref(false); +const loading = ref(false); +const title = ref(""); + +const data = reactive({ + form:{}, + queryParams: { + name: undefined, + }, + rules: { + facilityId: [{ required: true, message: "请选择设备", trigger: "blur" }], + columnsCode: [{ required: true, message: "请选择设备参数", trigger: "blur" }], + schemeName: [{ required: true, message: "请输入方案名称", trigger: "blur" }], + lowAlarm: [{ required: true, message: "请输入低报警值", trigger: "blur" }], + tallAlarm: [{ required: true, message: "请输入高报警值", trigger: "blur" }], + remark: [{ required: false, message: "请输入备注信息", trigger: "blur" }], + }, +}); +const { queryParams, form, rules } = toRefs(data); +const facityList = ref([]); //设备列表 +const facityCodeList = ref([]); //设备参数列表 + +/** + * 搜索相关 + */ +/** 搜索按钮操作 */ +function handleQuery() { + getList({keywords:queryParams.value.name,page:1}) +} + +/** 重置按钮操作 */ +function resetQuery() { + proxy.resetForm("queryRef"); + handleQuery(); +} + +/** 获取列表 */ +async function getList(val) { + loading.value = true; + let postParam = setPostParams(val) + await alarmSchemeApi().search(postParam).then((res) =>{ + tableData.value = res.data.list + pageParam.value.total = res.data.total + pageParam.value.limit = res.data.limit + pageParam.value.page = res.data.page + }) + loading.value = false; +} + +// 获取设备 +const getFacityList = () => { + let postParam = setPostParams() + facilityApi().search(postParam).then(res => { + facityList.value = res.data.list + }) +} + +// 获取设备参数 +const getFacityCodeList = (id) => { + const code = id ? id : form.value.facilityId + waterFacilityParameter().getParam(code).then(res => { + facityCodeList.value = res.data + }) +} + +/** 新增按钮操作 */ +async function handleAdd() { + reset(); + open.value = true; + title.value = "新增方案配置"; +} +/** 修改按钮操作 */ +async function handleUpdate(row) { + reset(); + getFacityCodeList(row.facilityId) + form.value = Object.assign({},row) + open.value = true; + title.value = "修改方案配置"; +} +/** 删除按钮操作 */ +function handleDelete(row) { + proxy.$modal.confirm('是否确认删除名称为"' + row.name + '"的数据项?').then(function() { + return alarmSchemeApi().remove(row.id); + }).then(() => { + getList(); + proxy.$modal.msgSuccess("删除成功"); + }).catch(() => {}); +} + +/** 提交按钮 */ +async function submitForm() { + proxy.$refs["formRef"].validate( async valid => { + if (valid) { + form.value.lowAlarm = Number(form.value.lowAlarm) + form.value.tallAlarm = Number(form.value.tallAlarm) + if (form.value.id != undefined) { + await alarmSchemeApi().modify(form.value).then(res => { + proxy.$modal.msgSuccess("修改成功"); + open.value = false; + getList(); + }).catch(() =>{ + open.value = false; + proxy.$modal.msgError("修改失败"); + }); + } else { + await alarmSchemeApi().create(form.value).then(res => { + proxy.$modal.msgSuccess("新增成功"); + open.value = false; + getList(); + }).catch(() =>{ + open.value = false; + proxy.$modal.msgError("新增失败"); + }); + } + } + }); +} + +/** 取消按钮 */ +function cancel() { + open.value = false; + reset(); +} +/** 表单重置 */ +function reset() { + form.value = { + facilityId:'', + columnsCode:'', + schemeName:'', + lowAlarm:'', + tallAlarm:'', + remark:'', + }; + proxy.resetForm("formRef"); +} + +onMounted(() => { + getList(); + getFacityList() +}) +</script> diff --git a/src/views/screen/flow/ecology/index.vue b/src/views/screen/flow/ecology/index.vue index 08b2146..08f293d 100644 --- a/src/views/screen/flow/ecology/index.vue +++ b/src/views/screen/flow/ecology/index.vue @@ -1,12 +1,6 @@ <script setup> import {onMounted, reactive} from 'vue' import * as echarts from 'echarts/core'; -import { GridComponent, ToolboxComponent, TooltipComponent, TitleComponent } from 'echarts/components'; -import { LineChart, BarChart } from 'echarts/charts'; -import { UniversalTransition } from 'echarts/features'; -import { CanvasRenderer } from 'echarts/renderers'; - -echarts.use([GridComponent, LineChart, BarChart, CanvasRenderer, UniversalTransition, ToolboxComponent, TooltipComponent, TitleComponent]); const state = reactive({ zhakouVal: 1, @@ -287,6 +281,7 @@ height: 96%; background: rgba(23,108,229,0.3); border: 1px solid #176CE5; + border-radius: 8px; .item-t{ height: 10%; padding: 0 30px; diff --git a/src/views/screen/flow/graphic/index.vue b/src/views/screen/flow/graphic/index.vue index 6bf1245..d1d2653 100644 --- a/src/views/screen/flow/graphic/index.vue +++ b/src/views/screen/flow/graphic/index.vue @@ -68,7 +68,7 @@ :value="item.value" /> </el-select> - <el-input v-model="searchVal" style="width: 20rem" /> + <el-input v-model="searchVal" style="width: 20rem" placeholder="请输入监测点名称" /> <el-button><el-icon><Search /></el-icon>搜索</el-button> <el-button style="margin-left: 0" v-if="userType === '1'"><el-icon><Plus /></el-icon>新增</el-button> </div> @@ -252,6 +252,7 @@ background: rgba(23,108,229,0.3); border: 1px solid #176CE5; padding: 20px; + border-radius: 8px; .title{ height: 12%; text-align: center; @@ -262,6 +263,7 @@ width: 100%; height: 60%; background: url("@/assets/images/login_icon.png") no-repeat; + background-size: 100% 100%; } .info{ width: 100%; diff --git a/src/views/screen/flow/report/index.vue b/src/views/screen/flow/report/index.vue index 678bffa..b33bbe8 100644 --- a/src/views/screen/flow/report/index.vue +++ b/src/views/screen/flow/report/index.vue @@ -1,13 +1,116 @@ <script setup> +import {ref} from "vue"; +import Table from '@/components/Table/index.vue' + +const selectType = ref(1); +const typeOption = ref([ + { label: '水电站流量监测点', value: 1 }, + { label: '新扎口流量监测点', value: 2 }, +]) +const time = ref() +let tableHead = [ + { prop: 'code', label: '报警代码' }, + { prop: 'shebei', label: '报警设备', }, + { prop: 'content', label: '报警内容' }, + { prop: 'time', label: '报警时间' }, + { prop: 'sure', label: '报警确认', slot: true }, +] + +const getTableData = () => { + return new Promise(resolve => { + let arr = { + list: [ + { code: '201', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '202', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 2 }, + { code: '203', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 3 }, + { code: '204', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '205', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '206', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '207', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '208', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 2 }, + { code: '209', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 3 }, + { code: '2010', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 3 }, + ], + total: 30, + } + resolve(arr) + }) +} </script> <template> - <div> - 报表管理 + <div class="report"> + <div class="report-tool"> + <el-select + v-model="selectType" + class="tool-select" + size="large" + placeholder="Select" + style="width: 20rem" + > + <el-option + v-for="item in typeOption" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + <el-select + v-model="selectType" + class="tool-select" + size="large" + placeholder="Select" + style="width: 20rem" + > + <el-option + v-for="item in typeOption" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + <el-date-picker + v-model="time" + type="datetimerange" + size="large" + style="width: 30rem" + range-separator="至" + start-placeholder="开始时间" + end-placeholder="结束时间" + /> + <el-button type="success" size="large" style="width: 6rem">一键导出</el-button> + </div> + <div class="report-table"> + <Table :getList="getTableData" :headList="tableHead"></Table> + </div> </div> </template> <style scoped lang="scss"> - +.report{ + height: 100%; + background: linear-gradient( 180deg, #91BDDB 0%, rgba(102, 102, 102, 0.5) 100%); + display: flex; + flex-direction: column; + align-items: center; + &-tool{ + padding: 10px 0; + display: flex; + justify-content: center; + align-items: center; + gap: 30px; + :deep(.el-date-editor){ + flex-grow: 0; + } + } + &-table{ + width: 96%; + height: 90%; + background: rgba(23,108,229,0.3); + border: 1px solid #176CE5; + border-radius: 8px; + padding: 20px; + } +} </style> \ No newline at end of file diff --git a/src/views/screen/flow/shebei/index.vue b/src/views/screen/flow/shebei/index.vue index 2ccc251..a588778 100644 --- a/src/views/screen/flow/shebei/index.vue +++ b/src/views/screen/flow/shebei/index.vue @@ -1,13 +1,357 @@ <script setup> +import {ref} from "vue"; +import {getUserType} from '@/utils/auth.js' + +const userType = ref(getUserType()) +const monitorRef = ref() +const searchVal = ref('') +const selectNum = ref(6); +const numOption = ref([ + { label: '6个', value: 6 }, + { label: '2个', value: 2 }, + { label: '1个', value: 1 }, +]) + +const shebeiData = ref([ + { name: '雷达水位计', code: 'SWY001', image: '', online: true, time: '2025-02-15', address: '上游灌木丛' }, + { name: '雷达水位计', code: 'SWY001', image: '', online: true, time: '2025-02-15', address: '上游灌木丛' }, + { name: '雷达水位计', code: 'SWY001', image: '', online: true, time: '2025-02-15', address: '上游灌木丛' }, + { name: '雷达水位计', code: 'SWY001', image: '', online: true, time: '2025-02-15', address: '上游灌木丛' }, + { name: '雷达水位计', code: 'SWY001', image: '', online: true, time: '2025-02-15', address: '上游灌木丛' }, + { name: '雷达水位计', code: 'SWY001', image: '', online: true, time: '2025-02-15', address: '上游灌木丛' }, + { name: '雷达水位计', code: 'SWY001', image: '', online: true, time: '2025-02-15', address: '上游灌木丛' }, + { name: '雷达水位计', code: 'SWY001', image: '', online: true, time: '2025-02-15', address: '上游灌木丛' }, +]) + +// 全屏操作 +const handleFullScreen = () => { + monitorRef.value.requestFullscreen() +} </script> <template> - <div> - 设备管理 + <div class="shebei"> + <div class="shebei-menu"> + <div class="menu-t">设备列表</div> + <el-menu class="el-menu"> + <el-sub-menu index="1"> + <template #title> + <span>雷达水位计</span> + </template> + <el-menu-item index="1-1">SWY001</el-menu-item> + <el-menu-item index="1-2">SWY002</el-menu-item> + </el-sub-menu> + <el-sub-menu index="2"> + <template #title> + <span>雷达测速仪</span> + </template> + <el-menu-item index="2-1">CY001</el-menu-item> + <el-menu-item index="2-2">CY002</el-menu-item> + </el-sub-menu> + <el-sub-menu index="3"> + <template #title> + <span>雷达流量计</span> + </template> + <el-menu-item index="3-1">LJL001</el-menu-item> + <el-menu-item index="3-2">LJL002</el-menu-item> + </el-sub-menu> + </el-menu> + </div> + <div class="shebei-monitor"> + <div class="monitor-tool"> + <div class="tool-l"> + <div class="name">展示数量</div> + <el-select + v-model="selectNum" + class="tool-select" + placeholder="Select" + style="width: 15rem" + > + <el-option + v-for="item in numOption" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> + <el-input v-model="searchVal" style="width: 20rem" placeholder="请输入监测点名称" /> + <el-button><el-icon><Search /></el-icon>搜索</el-button> + <el-button style="margin-left: 0" v-if="userType === '1'"><el-icon><Plus /></el-icon>新增</el-button> + </div> + <div class="tool-r" @click="handleFullScreen"> + <img src="@/assets/images/flow/fullscreen.png" /> + 全屏 + </div> + </div> + <div class="monitor-box" ref="monitorRef"> + <div class="list-six list" v-if="selectNum === 6"> + <div class="item" v-for="(item, index) in shebeiData" :key="index"> + <div class="item-t"> + <div>{{item.name}}</div> + <div>{{item.code}}</div> + </div> + <div class="item-img"> + <img v-if="item.image" :src="item.image" /> + </div> + <div class="item-info"> + <div class="online">设备在线状态: <span :style="{color: item.online ? '#56d12c' : '#bababa'}">{{item.online ? '在线' : '掉线'}}</span></div> + <div class="time">安装时间: <span>{{item.time}}</span></div> + <div class="address">安装位置: <span>{{item.address}}</span></div> + </div> + </div> + </div> + <div class="list-two list" v-else-if="selectNum === 2"> + <div class="item" v-for="(item, index) in shebeiData" :key="index"> + <div class="item-t"> + <div>{{item.name}}</div> + <div>{{item.code}}</div> + </div> + <div class="item-img"> + <img v-if="item.image" :src="item.image" /> + </div> + <div class="item-info"> + <div class="online">设备在线状态: <span :style="{color: item.online ? '#56d12c' : '#bababa'}">{{item.online ? '在线' : '掉线'}}</span></div> + <div class="time">安装时间: <span>{{item.time}}</span></div> + <div class="address">安装位置: <span>{{item.address}}</span></div> + </div> + </div> + </div> + <div class="list-one list" v-else-if="selectNum === 1"> + <div class="item" v-for="(item, index) in shebeiData" :key="index"> + <div class="item-t"> + <div>{{item.name}}</div> + <div>{{item.code}}</div> + </div> + <div class="item-img"> + <img v-if="item.image" :src="item.image" /> + </div> + <div class="item-info"> + <div class="online">设备在线状态: <span :style="{color: item.online ? '#56d12c' : '#bababa'}">{{item.online ? '在线' : '掉线'}}</span></div> + <div class="time">安装时间: <span>{{item.time}}</span></div> + <div class="address">安装位置: <span>{{item.address}}</span></div> + </div> + </div> + </div> + <div class="list-single" v-else></div> + </div> + </div> </div> </template> <style scoped lang="scss"> - +.shebei{ + height: 100%; + display: flex; + &-menu{ + flex-shrink: 0; + width: 20%; + height: 100%; + padding: 10px 0; + background: linear-gradient( 135deg, #91BDDB 0%, #9EC2DB 99%); + overflow-y: scroll; + &::-webkit-scrollbar { + display: none; + } + .menu-t{ + height: 40px; + line-height: 40px; + padding-left: 20px; + font-size: 26px; + color: #fff; + background: url("@/assets/images/flow/monitor-title-bg.png") no-repeat; + background-size: 100% 100%; + } + .el-menu{ + background-color: transparent; + border-right: none; + :deep(.el-menu){ + background-color: transparent; + } + :deep(.el-sub-menu__title:hover) { + background-color: rgba(0, 0, 0, 0.06); + } + :deep(.el-menu-item.is-active) { + color: #fff; + } + } + } + &-monitor{ + flex-shrink: 0; + width: 80%; + height: 100%; + background: linear-gradient( 180deg, #91BDDB 0%, rgba(102, 102, 102, 0.5) 100%); + .monitor-tool{ + width: 100%; + height: 60px; + padding: 0 30px; + background: linear-gradient( 90deg, #91BDDB 0%, #DADFE3 100%); + display: flex; + align-items: center; + justify-content: space-between; + .tool-l{ + display: flex; + align-items: center; + gap: 1rem; + .name{ + font-size: 1.1rem; + } + } + .tool-r{ + display: flex; + align-items: center; + img{ + width: 25px; + margin-right: 10px; + } + } + } + .monitor-box{ + height: calc(100% - 60px); + padding-top: 10px; + .list{ + height: 100%; + padding: 0 30px; + overflow-y: scroll; + &::-webkit-scrollbar { + display: none; + } + .item{ + flex-shrink: 0; + background: rgba(23,108,229,0.3); + border: 1px solid #176CE5; + border-radius: 8px; + } + } + .list-six{ + display: flex; + flex-wrap: wrap; + gap: 20px; + .item{ + width: 32%; + height: 48%; + padding: 10px 20px; + .item-t{ + height: 10%; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 28px; + color: #fff; + } + .item-img{ + margin-top: 10px; + width: 100%; + height: 68%; + background-color: #000; + img{ + width: 100%; + height: 100%; + } + } + .item-info{ + height: 18%; + display: flex; + flex-wrap: wrap; + color: #fff; + font-size: 1.2rem; + .online, + .time{ + width: 50%; + padding: 6px 0; + } + .address{ + width: 100%; + } + } + } + } + .list-two{ + display: flex; + flex-wrap: wrap; + gap: 20px; + .item{ + width: 49%; + height: 99%; + padding: 30px; + .item-t{ + height: 10%; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 36px; + color: #fff; + } + .item-img{ + margin-top: 10px; + width: 100%; + height: 68%; + background-color: #000; + img{ + width: 100%; + height: 100%; + } + } + .item-info{ + display: flex; + flex-wrap: wrap; + color: #fff; + font-size: 1.5rem; + .online, + .time{ + width: 50%; + padding: 20px 0; + } + .address{ + width: 100%; + } + } + } + } + .list-one{ + display: flex; + flex-direction: column; + align-items: center; + .item{ + width: 70%; + height: 99%; + padding: 30px; + margin-bottom: 30px; + .item-t{ + height: 10%; + display: flex; + align-items: center; + justify-content: space-between; + font-size: 36px; + color: #fff; + } + .item-img{ + margin-top: 10px; + width: 100%; + height: 75%; + background-color: #000; + img{ + width: 100%; + height: 100%; + } + } + .item-info{ + display: flex; + flex-wrap: wrap; + color: #fff; + font-size: 1.5rem; + .online, + .time{ + width: 50%; + padding: 20px 0; + } + .address{ + width: 100%; + } + } + } + } + } + } +} </style> \ No newline at end of file diff --git a/src/views/screen/flow/warning/index.vue b/src/views/screen/flow/warning/index.vue index e80b3ed..4ee3228 100644 --- a/src/views/screen/flow/warning/index.vue +++ b/src/views/screen/flow/warning/index.vue @@ -1,13 +1,173 @@ <script setup> +import {onMounted, ref} from "vue"; +import * as echarts from 'echarts/core'; +import Table from '@/components/Table/index.vue' +const timeType = ref(0) +const warnChartRef = ref() +let warnCharts = null; +let tableHead = [ + { prop: 'code', label: '报警代码' }, + { prop: 'shebei', label: '报警设备', }, + { prop: 'content', label: '报警内容' }, + { prop: 'time', label: '报警时间' }, + { prop: 'sure', label: '报警确认', slot: true }, +] + +const initWarnChart = () => { + if(warnChartRef.value) { + warnCharts = echarts.init(warnChartRef.value); + const options = { + tooltip: { + trigger: 'axis', + }, + grid: { + top: 80, + left: 60, + right: 60, + bottom: 60 + }, + xAxis: { + type: 'category', + data: ['设备离线', '水位异常', '流量异常', '流速异常', '其他异常'], + axisLabel: { + color: '#fff', + fontSize: '1.2rem' + } + }, + yAxis: { + type: 'value', + name: '次', + nameTextStyle: { + color: '#fff', + fontSize: '1.2rem' + }, + axisLabel: { + color: '#fff', + fontSize: '1.2rem' + } + }, + series: [ + { + data: [36, 44, 38, 24, 63], + type: 'bar', + itemStyle: { + color: 'rgba(187,207,255,0.6)' + } + } + ] + } + warnCharts.setOption(options); + } +} + +const getTableData = () => { + return new Promise(resolve => { + let arr = { + list: [ + { code: '201', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '202', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 2 }, + { code: '203', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 3 }, + { code: '204', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '205', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '206', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '207', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 1 }, + { code: '208', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 2 }, + { code: '209', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 3 }, + { code: '2010', shebei: '雷达水位计', content: '设备离线', time: '2025-02-08', sure: 3 }, + ], + total: 30, + } + resolve(arr) + }) +} + +onMounted(() => { + initWarnChart() +}) </script> <template> - <div> - 预警管理 + <div class="warn"> + <div class="warn-l item"> + <div class="item-t"> + <div class="name">报警分析</div> + <div class="select"> + <el-radio-group v-model="timeType"> + <el-radio :value="1">日</el-radio> + <el-radio :value="2">月</el-radio> + <el-radio :value="3">年</el-radio> + </el-radio-group> + </div> + </div> + <div class="charts" ref="warnChartRef"></div> + </div> + <div class="warn-r item"> + <div class="item-t"> + <div class="name">报警记录</div> + </div> + <div class="warn-table"> + <Table :getList="getTableData" :headList="tableHead"> + <template #sure="scope"> + <div v-if="scope.row.sure === 1" style="color: #1ab394">已处理</div> + <div v-else-if="scope.row.sure === 2" style="color: #e8ab04">未处理</div> + <div v-else style="color: #f30101">待确认</div> + </template> + <template v-slot:pagination> + <el-button type="success" style="width: 6rem">导出</el-button> + </template> + </Table> + </div> + </div> </div> </template> <style scoped lang="scss"> - +.warn{ + height: 100%; + background: linear-gradient( 180deg, #91BDDB 0%, rgba(102, 102, 102, 0.5) 100%); + display: flex; + justify-content: center; + align-items: center; + gap: 30px; + .item{ + width: 48%; + height: 96%; + background: rgba(23,108,229,0.3); + border: 1px solid #176CE5; + border-radius: 8px; + .item-t{ + height: 10%; + padding: 0 30px; + display: flex; + justify-content: space-between; + align-items: center; + .name{ + font-size: 36px; + color: #fff; + } + .select{ + :deep(.el-radio){ + color: #fff; + } + :deep(.el-radio__label){ + font-size: 20px; + } + :deep(.el-radio__input.is-checked+.el-radio__label){ + color: #00ff00; + } + :deep(.el-radio__input.is-checked .el-radio__inner){ + background-color: #00ff00; + } + } + } + .charts{ + height: 90%; + } + .warn-table{ + padding: 0 20px; + height: 90%; + } + } +} </style> \ No newline at end of file -- Gitblit v1.9.3