拎壶冲 6 месяцев назад
Родитель
Сommit
e59bcc00cb

+ 16 - 0
src/api/check/chkc.js

@@ -1,5 +1,21 @@
 import request from '@/utils/request'
 
+export function chkcCheck(){
+    return request({
+        url: '/check/chkc/check',
+        method: 'post'
+    })
+}
+
+
+export function chkcResult(crId){
+    return request({
+        url: `/check/chkc/result/${crId}`,
+        method: 'get'
+    })
+}
+
+
 // 查询自动巡检指标配置列表
 export function listChkc(query) {
     return request({

+ 153 - 140
src/views/hl/check/index.vue

@@ -4,9 +4,9 @@
       <div class="site-row">
         <div class="site-progress" :style="`width: ${currentProgress}%`"></div>
         <div class="site-label">
-          <div class="site-node" v-for="(item,index) in checkList" :key="item.modelId">
-            <div :class="['site',index<=cIndex && cIndex!=null?'normal':'un-info ']" />
-            <div :class="['site-name',{'active-site-name':index<=cIndex && cIndex!=null}]">{{item.modelName}}</div>
+          <div class="site-node" v-for="(item,index) in checkList" :key="item.ccId">
+            <div :class="['site',index<=cIndex && cIndex!=null?'normal':'un-info ']"/>
+            <div :class="['site-name',{'active-site-name':index<=cIndex && cIndex!=null}]">{{ item.className }}</div>
           </div>
         </div>
       </div>
@@ -14,65 +14,58 @@
 
     <div class="site-content mt10">
       <div class="check-status">
-        <el-button type="primary" :loading="cLoading" @click="handleNowCheck(checkList.length)" style="padding:16px 22px;">
+        <el-button type="primary" :loading="cLoading" @click="onNowCheck"
+                   style="padding:16px 22px;">
           立即巡检
         </el-button>
-        <span class="check-progress">
-          <span class="t-span">巡检进度:</span>
-          <el-progress type="circle" :percentage="currentProgress" width="50" stroke-width="4" :color="colors">
-            <template #default="{ percentage }">
-              <span class="percentage-value">{{ percentage }}%</span>
-            </template>
-          </el-progress>
+        <span class="check-progress" v-if="cLoading">
+            <span class="t-span">巡检进度:</span>
+            <el-progress type="circle" :percentage="currentProgress" width="50" stroke-width="4" :color="colors">
+              <template #default="{ percentage }">
+                <span class="percentage-value">{{ percentage }}%</span>
+              </template>
+            </el-progress>
+        </span>
+        <span class="check-progress" v-else>
+            <span class="t-span" style="font-size: 14px;font-weight: 400" v-show="nowCheck.checkResult">
+              {{ nowCheck.checkResult }}
+            </span>
         </span>
         <span>
           <span v-show="checkTime" class="check-time">
+            <span v-if="checkFlag" style="margin-right: 10px">
+              <el-button  size="small" @click="handleDialog('setting')" icon="Setting">巡检记录配置</el-button>
+              <el-button  size="small" @click="handleDialog('report')" icon="Document">
+                巡查报告查看
+              </el-button>
+            </span>
             <span class="t-span">巡检时间:</span>
-            <span class="check-time">{{parseTime(checkTime, '{y}-{m}-{d} {h}:{mi}:{s}')}}</span>
+            <span class="check-time">{{ parseTime(checkTime, '{y}-{m}-{d} {h}:{mi}:{s}') }}</span>
           </span>
         </span>
       </div>
-      <div class="progress-bar">
-        <div class="progress-bar-inner" :style="`width: ${currentProgress}%`"/>
-      </div>
 
-      <div class="check-info">
-        <div class="sub-col">
-          <el-icon :size="46" color="#409EFF"><Timer /></el-icon>
-          <div class="s-c-text">
-            {{cIndex!=null?cIndex+1:0}}/{{checkList.length}}<br/>已检测模型</div>
-        </div>
-        <div class="sub-col">
-          <el-icon :size="46" color="#409EFF"><Compass /></el-icon>
-          <div class="s-c-text">{{cIndex!=null?Math.ceil((totalErrorCount/checkList.length)*(cIndex+1)):0}}/{{totalErrorCount}}<br/>已检测指标</div>
-        </div>
-        <div class="sub-col">
-          <el-icon :size="46" color="#409EFF"><Warning /></el-icon>
-          <div class="s-c-text">
-            <span class="s-c-num">{{totalError}}</span>
-            <br/>已发现问题</div>
-        </div>
-      </div>
-      <el-table :data="listData" style="width: 100%" border class="mt20">
-        <el-table-column prop="class" label="分类" width="180" />
-        <el-table-column prop="option" label="巡检项" />
-        <el-table-column label="巡检进度" align="center" width="180">
+      <el-table :data="listData" style="width: 100%" border class="mt20" :span-method="spanMethod">
+        <el-table-column prop="className" label="分类" width="180" align="center"/>
+        <el-table-column prop="checkName" label="巡检项"/>
+        <el-table-column label="巡检结果" width="160" align="center">
           <template #default="{row}">
             <span v-if="checkTime">
-              <el-icon size="25" color="#90a4ae" class="rotate" v-if="row.checkProess!=='done'"><Loading /></el-icon>
-              <el-icon size="25" color="#388e3c" v-else><CircleCheck /></el-icon>
+              <span v-if="row.resultL">
+                {{ row.resultL }}
+              </span>
+              <el-icon size="25" color="#388e3c" class="rotate" v-else><Loading/></el-icon>
             </span>
             <span v-else>-</span>
           </template>
         </el-table-column>
-        <el-table-column label="巡检结果" align="center" width="180">
+        <el-table-column prop="remark" label="备注" align="center" width="160">
           <template #default="{row}">
             <span v-if="checkTime">
-              <el-icon size="25" color="#90a4ae" class="rotate" v-if="!row.checkResult"><Loading /></el-icon>
-              <span v-else class="check-result">
-                <el-icon size="20" color="#e43"><WarnTriangleFilled /></el-icon>
-                <span class="res-text">{{row.checkResult}} 项</span>
+              <span v-if="row.resultR" :style="`color:${row.resultR === '正常'?'#1ab43f':'#e43'}`">
+                {{ row.resultR }}
               </span>
+              <el-icon size="25" color="#388e3c" class="rotate" v-else><Loading/></el-icon>
             </span>
             <span v-else>-</span>
           </template>
@@ -80,138 +73,158 @@
       </el-table>
     </div>
 
-    <div class="btn-center-row"  v-if="checkFlag">
-      <el-button type="primary" plain @click="visible=true">巡查报告查看</el-button>
-    </div>
-
-    <el-dialog v-model="visible" width="1000" title="巡检报告查看">
-      <check-history />
+    <el-dialog v-model="isComponent.visible" width="1000" :title="isComponent.title" style="margin-top:2vh!important">
+      <component :is="isComponent.component" :crId="nowCheck.crId" :spanMethod="spanMethod"/>
     </el-dialog>
+
   </div>
 </template>
 <script setup lang="ts">
-import {getCheckList,getCheckModel} from "@/api/hl/bm"
+import {chkcCheck, listChkc} from "@/api/check/chkc"
 import {onMounted} from "vue";
-import {Timer,Compass,Warning,Loading,CircleCheck,WarnTriangleFilled} from "@element-plus/icons-vue"
-import checkHistory from "./widget/checkHistory.vue"
-import {useRoute,useRouter} from "vue-router"
+import {Loading} from "@element-plus/icons-vue";
+import nCheckReport from "./widget/nCheckReport.vue"
+import nCheckList from "./widget/nCheckList.vue"
+
 const checkList = ref([])
-const cLoading = ref(false)
-const currentProgress = ref(0)
-const cIndex=ref(null)
 const listData = ref([])
+const currentProgress = ref(0)
+const cIndex = ref(null)
+const cLoading = ref(false)
 const checkTime = ref(null)
-const totalError=ref(0)
-const totalErrorCount = ref(0)
+const nowCheck = ref({})
 const checkFlag = ref(false)
-const visible = ref(false)
-
-const route = useRoute()
-const router = useRouter()
+const isComponent = ref({
+  visible: false,
+  title: "",
+  component: nCheckReport
+})
 
 const colors = [
-  { color: '#bbdefb', percentage: 20 },
-  { color: '#90caf9', percentage: 40 },
-  { color: '#64b5f6', percentage: 60 },
-  { color: '#2196f3', percentage: 80 },
-  { color: '#1e88e5', percentage: 100 },
+  {color: '#bbdefb', percentage: 20},
+  {color: '#90caf9', percentage: 40},
+  {color: '#64b5f6', percentage: 60},
+  {color: '#2196f3', percentage: 80},
+  {color: '#1e88e5', percentage: 100},
 ]
 
-onMounted( ()=>{
-  if(!route.query.check && localStorage.getItem("listData")){
+onMounted(() => {
+  if (localStorage.getItem("listData")) {
     return restoreCache()
   }
-  getListData()
+  getListChkc()
 })
 
+const handleDialog = (action) => {
+  if (action === 'report') {
+    isComponent.value = {
+      visible: true,
+      title: "巡检报告查看",
+      component: nCheckReport
+    }
+  } else {
+    isComponent.value = {
+      visible: true,
+      title: "巡检记录配置",
+      component: nCheckList
+    }
+  }
+}
 
-async function getListData(){
-  const res = await getCheckList();
-  checkList.value = res.data
-  listData.value = res.data[0].classList
-  route.query.check && handleNowCheck(checkList.value.length)
+const restoreCache = () => {
+  listData.value = JSON.parse(localStorage.getItem("listData"))
+  nowCheck.value = JSON.parse(localStorage.getItem("nowCheck"))
+  checkList.value = uniqueByKey(listData.value, 'className')
+  checkFlag.value = true
+  // cIndex.value = listData.value.length - 1
+  checkTime.value = nowCheck.value.checkTime
+  currentProgress.value = 100
 }
 
-function convertTime(milliseconds) {
-  // 将毫秒转换为秒
-  let seconds = Math.floor(milliseconds / 1000);
+const spanMethod = ({row, column, rowIndex}) => {
+  if (column.property === "className") {
+    const currentClass = listData.value[rowIndex].className;
+    const prevClass = listData.value[rowIndex - 1]?.className;
+    if (currentClass !== prevClass) {
+      let rowspan = 1;
+      for (let i = rowIndex + 1; i < listData.value.length; i++) {
+        if (listData.value[i].className === currentClass) {
+          rowspan++;
+        } else {
+          break;
+        }
+      }
+      return {rowspan, colspan: 1};
+    } else {
+      return {rowspan: 0, colspan: 0};
+    }
+  }
+}
 
-  // 计算小时、分钟和秒
-  let hours = Math.floor(seconds / 3600);
-  let minutes = Math.floor((seconds % 3600) / 60);
-  let remainingSeconds = seconds % 60;
+const uniqueByKey = (array, key) => {
+  const map = new Map();
+  array.forEach(item => map.set(item[key], item));
+  return Array.from(map.values());
+}
 
-  // 格式化为00:00:00的形式
-  return padZero(hours) + ":" + padZero(minutes) + ":" + padZero(remainingSeconds);
+const getListChkc = async () => {
+  const {rows} = await listChkc({pageSize: 100})
+  listData.value = rows
+  checkList.value = uniqueByKey(rows, 'className')
 }
 
-// 在数字前面补零,确保两位数的格式
-function padZero(number) {
+const padZero = (number) => {
   return (number < 10 ? "0" : "") + number;
 }
 
-function getRandomInt(min, max) {
-  // Math.random() 生成一个 0 到 1 之间的随机数
-  // max - min + 1 是生成随机数的范围
-  // Math.floor() 向下取整,确保生成的是整数
+const getRandomInt = (min, max) => {
   return Math.floor(Math.random() * (max - min + 1)) + min;
 }
 
-function handleNowCheck(sub){
-  if(!cLoading.value){
-    checkFlag.value = false
-    if(localStorage.getItem("listData")){
-      removeCache()
-      !route.query.check && getListData()
-    }
+const onNowCheck = async () => {
+  const {data} = await chkcCheck()
+  nowCheck.value = data
+  handleCheck(0)
+}
+
+const handleCheck = (i) => {
+  if (!cLoading.value) {
     cLoading.value = true;
     cIndex.value = null;
-    totalError.value = 0;
-    totalErrorCount.value=0;
+    currentProgress.value = 0;
     checkTime.value = new Date();
+    checkFlag.value = false
+    if (localStorage.getItem("listData")) {
+      localStorage.removeItem("listData")
+      localStorage.removeItem("nowCheck")
+    }
   }
-  let index = checkList.value.length-sub
-  currentProgress.value = Number(Number(index / checkList.value.length * 100).toFixed(2))
-  if(index > checkList.value.length-1) {
-    saveCache()
-    return cLoading.value = false
-  }
-  setTimeout(async ()=>{
-    await getCheckModel(checkList.value[index].modelId)
-    totalErrorCount.value= 413
-    listData.value[index].checkProess = 'done'
-    let e = Math.ceil(Math.random()*100)
-    totalError.value += e
-    listData.value[index].checkResult = e
-    cIndex.value = index
-    handleNowCheck(sub-1)
-  }, getRandomInt(500, 500))
-}
-
-function saveCache(){
-  localStorage.setItem("listData", JSON.stringify(listData.value))
-  localStorage.setItem("errorInfo",JSON.stringify({totalErrorCount:totalErrorCount.value,totalError:totalError.value,checkTime:checkTime.value}))
-  localStorage.setItem("checkList",JSON.stringify(checkList.value))
-  checkFlag.value = true
-  router.replace({path:"/hl/check"})
-}
 
-function removeCache(){
-  localStorage.removeItem("listData")
-  localStorage.removeItem("errorInfo")
-  localStorage.removeItem("checkList")
-}
-
-function restoreCache(){
-  listData.value = JSON.parse(localStorage.getItem("listData"))
-  checkList.value = JSON.parse(localStorage.getItem("checkList"))
-  const errorInfo = JSON.parse(localStorage.getItem("errorInfo"))
-  cIndex.value = checkList.value.length-1
-  totalErrorCount.value = errorInfo.totalErrorCount
-  totalError.value = errorInfo.totalError
-  checkTime.value = errorInfo.checkTime
-  currentProgress.value = 100
-  checkFlag.value = true
+  const randomStep = getRandomInt(2, 5);
+  const index = Math.min(i + randomStep, listData.value.length - 1);
+
+  if (i < listData.value.length) {
+    setTimeout(() => {
+      currentProgress.value = Number(((index + 1) / listData.value.length * 100).toFixed(1));
+
+      for (let j = i; j <= index; j++) {
+        const item = listData.value[j];
+        const detail = nowCheck.value.detailList.find(cItem => cItem.ccId === item.ccId);
+
+        if (detail) {
+          const {resultL, resultR, remark} = detail;
+          listData.value[j] = {...item, resultL, resultR, remark};
+        }
+      }
+      handleCheck(index + 1);
+    }, getRandomInt(1000, 3000));
+  } else {
+    cLoading.value = false;
+    currentProgress.value = 100;
+    checkFlag.value = true
+    localStorage.setItem("nowCheck", JSON.stringify(nowCheck.value))
+    localStorage.setItem("listData", JSON.stringify(listData.value))
+  }
 }
 
 

+ 239 - 0
src/views/hl/check/index_old.vue

@@ -0,0 +1,239 @@
+<template>
+  <div class="check-body">
+    <div class="site-content">
+      <div class="site-row">
+        <div class="site-progress" :style="`width: ${currentProgress}%`"></div>
+        <div class="site-label">
+          <div class="site-node" v-for="(item,index) in checkList" :key="item.modelId">
+            <div :class="['site',index<=cIndex && cIndex!=null?'normal':'un-info ']"/>
+            <div :class="['site-name',{'active-site-name':index<=cIndex && cIndex!=null}]">{{ item.modelName }}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="site-content mt10">
+      <div class="check-status">
+        <el-button type="primary" :loading="cLoading" @click="handleNowCheck(checkList.length)"
+                   style="padding:16px 22px;">
+          立即巡检
+        </el-button>
+        <span class="check-progress">
+          <span class="t-span">巡检进度:</span>
+          <el-progress type="circle" :percentage="currentProgress" width="50" stroke-width="4" :color="colors">
+            <template #default="{ percentage }">
+              <span class="percentage-value">{{ percentage }}%</span>
+            </template>
+          </el-progress>
+        </span>
+        <span>
+          <span v-show="checkTime" class="check-time">
+            <span class="t-span">巡检时间:</span>
+            <span class="check-time">{{ parseTime(checkTime, '{y}-{m}-{d} {h}:{mi}:{s}') }}</span>
+          </span>
+        </span>
+      </div>
+      <div class="progress-bar">
+        <div class="progress-bar-inner" :style="`width: ${currentProgress}%`"/>
+      </div>
+
+      <div class="check-info">
+        <div class="sub-col">
+          <el-icon :size="46" color="#409EFF">
+            <Timer/>
+          </el-icon>
+          <div class="s-c-text">
+            {{ cIndex != null ? cIndex + 1 : 0 }}/{{ checkList.length }}<br/>已检测模型
+          </div>
+        </div>
+        <div class="sub-col">
+          <el-icon :size="46" color="#409EFF">
+            <Compass/>
+          </el-icon>
+          <div class="s-c-text">
+            {{ cIndex != null ? Math.ceil((totalErrorCount / checkList.length) * (cIndex + 1)) : 0 }}/{{
+              totalErrorCount
+            }}<br/>已检测指标
+          </div>
+        </div>
+        <div class="sub-col">
+          <el-icon :size="46" color="#409EFF">
+            <Warning/>
+          </el-icon>
+          <div class="s-c-text">
+            <span class="s-c-num">{{ totalError }}</span>
+            <br/>已发现问题
+          </div>
+        </div>
+      </div>
+      <el-table :data="listData" style="width: 100%" border class="mt20">
+        <el-table-column prop="class" label="分类" width="180"/>
+        <el-table-column prop="option" label="巡检项"/>
+        <el-table-column label="巡检进度" align="center" width="180">
+          <template #default="{row}">
+            <span v-if="checkTime">
+              <el-icon size="25" color="#90a4ae" class="rotate" v-if="row.checkProess!=='done'"><Loading/></el-icon>
+              <el-icon size="25" color="#388e3c" v-else><CircleCheck/></el-icon>
+            </span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="巡检结果" align="center" width="180">
+          <template #default="{row}">
+            <span v-if="checkTime">
+              <el-icon size="25" color="#90a4ae" class="rotate" v-if="!row.checkResult"><Loading/></el-icon>
+              <span v-else class="check-result">
+                <el-icon size="20" color="#e43"><WarnTriangleFilled/></el-icon>
+                <span class="res-text">{{ row.checkResult }} 项</span>
+              </span>
+            </span>
+            <span v-else>-</span>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <div class="btn-center-row" v-if="checkFlag">
+      <el-button type="primary" plain @click="visible=true">巡查报告查看</el-button>
+    </div>
+
+    <el-dialog v-model="visible" width="1000" title="巡检报告查看">
+      <check-history/>
+    </el-dialog>
+  </div>
+</template>
+<script setup lang="ts">
+import {getCheckList, getCheckModel} from "@/api/hl/bm"
+import {onMounted} from "vue";
+import {CircleCheck, Compass, Loading, Timer, Warning, WarnTriangleFilled} from "@element-plus/icons-vue"
+import checkHistory from "./widget/checkHistory.vue"
+import {useRoute, useRouter} from "vue-router"
+
+const checkList = ref([])
+const cLoading = ref(false)
+const currentProgress = ref(0)
+const cIndex = ref(null)
+const listData = ref([])
+const checkTime = ref(null)
+const totalError = ref(0)
+const totalErrorCount = ref(0)
+const checkFlag = ref(false)
+const visible = ref(false)
+
+const route = useRoute()
+const router = useRouter()
+
+const colors = [
+  {color: '#bbdefb', percentage: 20},
+  {color: '#90caf9', percentage: 40},
+  {color: '#64b5f6', percentage: 60},
+  {color: '#2196f3', percentage: 80},
+  {color: '#1e88e5', percentage: 100},
+]
+
+onMounted(() => {
+  if (!route.query.check && localStorage.getItem("listData")) {
+    return restoreCache()
+  }
+  getListData()
+})
+
+
+async function getListData() {
+  const res = await getCheckList();
+  checkList.value = res.data
+  listData.value = res.data[0].classList
+  route.query.check && handleNowCheck(checkList.value.length)
+}
+
+function convertTime(milliseconds) {
+  // 将毫秒转换为秒
+  let seconds = Math.floor(milliseconds / 1000);
+
+  // 计算小时、分钟和秒
+  let hours = Math.floor(seconds / 3600);
+  let minutes = Math.floor((seconds % 3600) / 60);
+  let remainingSeconds = seconds % 60;
+
+  // 格式化为00:00:00的形式
+  return padZero(hours) + ":" + padZero(minutes) + ":" + padZero(remainingSeconds);
+}
+
+// 在数字前面补零,确保两位数的格式
+function padZero(number) {
+  return (number < 10 ? "0" : "") + number;
+}
+
+function getRandomInt(min, max) {
+  // Math.random() 生成一个 0 到 1 之间的随机数
+  // max - min + 1 是生成随机数的范围
+  // Math.floor() 向下取整,确保生成的是整数
+  return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+function handleNowCheck(sub) {
+  if (!cLoading.value) {
+    checkFlag.value = false
+    if (localStorage.getItem("listData")) {
+      removeCache()
+      !route.query.check && getListData()
+    }
+    cLoading.value = true;
+    cIndex.value = null;
+    totalError.value = 0;
+    totalErrorCount.value = 0;
+    checkTime.value = new Date();
+  }
+  let index = checkList.value.length - sub
+  currentProgress.value = Number(Number(index / checkList.value.length * 100).toFixed(2))
+  if (index > checkList.value.length - 1) {
+    saveCache()
+    return cLoading.value = false
+  }
+  setTimeout(async () => {
+    await getCheckModel(checkList.value[index].modelId)
+    totalErrorCount.value = 413
+    listData.value[index].checkProess = 'done'
+    let e = Math.ceil(Math.random() * 100)
+    totalError.value += e
+    listData.value[index].checkResult = e
+    cIndex.value = index
+    handleNowCheck(sub - 1)
+  }, getRandomInt(500, 500))
+}
+
+function saveCache() {
+  localStorage.setItem("listData", JSON.stringify(listData.value))
+  localStorage.setItem("errorInfo", JSON.stringify({
+    totalErrorCount: totalErrorCount.value,
+    totalError: totalError.value,
+    checkTime: checkTime.value
+  }))
+  localStorage.setItem("checkList", JSON.stringify(checkList.value))
+  checkFlag.value = true
+  router.replace({path: "/hl/check"})
+}
+
+function removeCache() {
+  localStorage.removeItem("listData")
+  localStorage.removeItem("errorInfo")
+  localStorage.removeItem("checkList")
+}
+
+function restoreCache() {
+  listData.value = JSON.parse(localStorage.getItem("listData"))
+  checkList.value = JSON.parse(localStorage.getItem("checkList"))
+  const errorInfo = JSON.parse(localStorage.getItem("errorInfo"))
+  cIndex.value = checkList.value.length - 1
+  totalErrorCount.value = errorInfo.totalErrorCount
+  totalError.value = errorInfo.totalError
+  checkTime.value = errorInfo.checkTime
+  currentProgress.value = 100
+  checkFlag.value = true
+}
+
+
+</script>
+<style scoped lang="scss">
+@import "./css/style.scss";
+</style>

+ 108 - 0
src/views/hl/check/widget/nCheckList.vue

@@ -0,0 +1,108 @@
+<template>
+  <div style="margin-top: -20px">
+    <el-table :data="listData" style="width: 100%;" border :span-method="spanMethod">
+      <el-table-column prop="className" label="分类" width="180" align="center"/>
+      <el-table-column prop="checkName" label="巡检项"/>
+      <el-table-column label="映射关系" width="140" align="center">
+        <template #default="{row}">
+          <el-select v-model="row.metricsId" filterable placeholder="请选择..." size="small" style="width: 100%"
+                     @change="changeMetricsId(row)">
+            <el-option v-for="item in metricsData" :key="item.metricsId" :label="item.metricsName"
+                       :value="item.metricsId"/>
+          </el-select>
+        </template>
+      </el-table-column>
+      <el-table-column label="计算方法" align="center" width="140">
+        <template #default="{row}">
+          <el-select v-model="row.checkMethod" placeholder="请选择..." size="small" style="width: 100%"
+                     @change="()=>update(row)">
+            <el-option v-for="item in check_method" :key="item.value" :label="item.label" :value="item.value"/>
+          </el-select>
+        </template>
+      </el-table-column>
+      <el-table-column label="异常规则" align="center" width="140">
+        <template #default="{row}">
+          <el-input v-model="row.checkRule" @change="()=>checkInput(row)" size="small" placeholder="示例:[50,70)"/>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+<script setup lang="ts">
+import {listChkc,updateChkc} from "@/api/check/chkc"
+import {listModelMs} from "@/api/risk/r2";
+import {onMounted, ref} from "vue";
+
+const listData = ref([])
+const metricsData = ref([])
+const {proxy} = getCurrentInstance()
+const {check_method} = proxy.useDict("check_method")
+const passValidate = ref(true)
+
+const props = defineProps({
+  spanMethod: {
+    type: Function
+  }
+})
+
+const checkInput = (row) => {
+  if (row) {
+    passValidate.value = validateRange(row.checkRule);
+    if (!passValidate.value) {
+      return proxy.$message.error("请输入正确的区间格式!")
+    }
+    update(row)
+  }
+}
+const validateRange = (range) => {
+  // 正则表达式匹配各种区间的格式
+  const regex = /^(\[|\()\s*([0-9]+(\.[0-9]+)?|)\s*,\s*([0-9]+(\.[0-9]+)?|)\s*(\]|\))$/;
+  const match = range.match(regex);
+
+  if (!match) {
+    return false; // 如果格式不正确,则返回false
+  }
+
+  // 提取括号类型和两个数值
+  const openBracket = match[1];// 开始的括号
+  const num1Str = match[2]; // 第一个数
+  const num2Str = match[4]; // 第二个数
+  const closeBracket = match[7]; // 结束的括号
+
+  let num1 = num1Str ? parseFloat(num1Str) : -Infinity;
+  let num2 = num2Str ? parseFloat(num2Str) : Infinity;
+
+  // 检查区间的有效性
+  if (openBracket === '[' && num1 > num2) return false; // [x,y] 要求 x <= y
+  if (openBracket === '(' && num1 >= num2) return false; // (x,y) 要求 x < y
+  if (closeBracket === ']' && num1 > num2) return false; // (x,y] 要求 x < y
+  if (closeBracket === ')' && num1 >= num2) return false; // [x,y) 要求 x < y
+
+  return true;
+}
+
+const getListData = async () => {
+  const res = await listChkc({pageSize: 100})
+  listData.value = res.rows
+  getMetricsList().then()
+}
+
+function changeMetricsId(row) {
+  row.metricsName = metricsData.value.find(item => item.metricsId === row.metricsId).metricsName
+  update(row)
+}
+
+async function getMetricsList() {
+  const res = await listModelMs()
+  metricsData.value = res.data
+}
+
+const update = async (row) => {
+  await updateChkc(row)
+}
+
+onMounted(() => {
+  getListData()
+})
+
+</script>

+ 63 - 0
src/views/hl/check/widget/nCheckReport.vue

@@ -0,0 +1,63 @@
+<template>
+  <div style="margin-top: -20px">
+    <div style="margin-bottom:10px;text-align: right">
+      <el-button icon="Download" @click="exportReport">导出报告</el-button>
+    </div>
+    <el-table :data="reportData" style="width: 100%;" border :span-method="spanMethod">
+      <el-table-column prop="className" label="分类" width="180" align="center"/>
+      <el-table-column prop="checkName" label="巡检项"/>
+      <el-table-column label="巡检结果" width="160" align="center" prop="resultL" />
+      <el-table-column prop="remark" label="备注" align="center" width="160">
+        <template #default="{row}">
+        <span :style="`color:${row.resultR === '正常'?'#1ab43f':'#e43'}`">
+          {{ row.resultR || "-" }}
+        </span>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+<script setup lang="ts">
+import {chkcResult} from "@/api/check/chkc"
+import axios from "axios";
+import {onMounted} from "vue";
+import { getToken } from '@/utils/auth'
+const props = defineProps({
+  crId: {
+    type: Number,
+    default: 0
+  },
+  spanMethod:{
+    type:Function
+  }
+})
+const reportData = ref([])
+
+const exportReport=async ()=>{
+  const response = await axios({
+    url: import.meta.env.VITE_APP_BASE_API+'/check/chkc/export/' + props.crId,
+    method: 'GET',
+    responseType: 'blob',
+    headers: { 'Authorization': 'Bearer ' + getToken() }
+  });
+  const url = window.URL.createObjectURL(new Blob([response.data]));
+  const link = document.createElement('a');
+  link.href = url;
+  link.setAttribute('download', 'report.docx');
+  document.body.appendChild(link);
+  link.click();
+  link.parentNode.removeChild(link);
+}
+
+const getReport = async () => {
+  const res = await chkcResult(props.crId)
+  reportData.value = res.data.detailList
+}
+
+onMounted(()=>{
+  getReport()
+})
+
+</script>
+<style scoped lang="scss">
+</style>

+ 1 - 1
vite.config.js

@@ -31,7 +31,7 @@ export default defineConfig(({ mode, command }) => {
       proxy: {
         // https://cn.vitejs.dev/config/#server-proxy
         '/dev-api': {
-          target: 'http://localhost:18081',
+          target: 'http://localhost:8080',
           changeOrigin: true,
           rewrite: (p) => p.replace(/^\/dev-api/, '')
         }