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