liling преди 1 година
родител
ревизия
f1dec6723f

BIN
public/index_flow.jpg


+ 9 - 114
src/views/dashboard/index.vue

@@ -1,12 +1,8 @@
 <template>
   <div class="dashboard-editor-container">
     <el-row :gutter="20" type="flex" justify="space-between">
-      <el-col :xs="17" :sm="17" :lg="17" class="left">
+      <el-col :xs="7" :sm="7" :lg="7" class="left">
         <div class="left-row-1">
-          <!-- 未来7天检测计划 -->
-          <div class="next-7-days item">
-            <bar-chart />
-          </div>
           <!-- 点击创建新检测 -->
           <div ref="btn_crate_testdevice" data-controlCode="btn_index_newtest" class="creat-new-check item">
             <div class="img">
@@ -19,96 +15,6 @@
             </div>
           </div>
         </div>
-        <div class="left-row-2">
-          <!-- 最近检测 -->
-          <div class="recently item">
-            <div class="title">
-              最近检测
-              <span class="more">
-                <router-link to="/device">更多 ></router-link>
-              </span>
-            </div>
-            <div class="content">
-              <el-table
-                :data="tableData"
-                stripe
-              >
-                <el-table-column
-                  prop="serialNumber"
-                  label="设备编号"
-                  :show-overflow-tooltip="true"
-                />
-                <el-table-column
-                  prop="stateName"
-                  label="检测状态"
-                >
-                  <template slot-scope="scope">
-                    <el-tag :type="scope.row.state | formatState">{{ scope.row.stateName || '未知' }}</el-tag>
-                    <!-- <el-tag v-if="scope.row.deviceCheckStatus == null ||scope.row.deviceCheckStatus == 'NEW'" type="danger">未检测</el-tag>
-              <el-tag v-if="scope.row.deviceCheckStatus == 'RUNNING'">检测中</el-tag>
-              <el-tag v-if="scope.row.deviceCheckStatus == 'TERMINATED'" type="info">已结束</el-tag> -->
-                  </template>
-                </el-table-column>
-                <el-table-column
-                  prop="plans"
-                  label="检测方案"
-                  tooltip-effect="dark"
-                  :show-overflow-tooltip="true"
-                >
-                  <template slot-scope="scope">
-                    <!-- <el-link type="primary" @click="toBegin(scope.row)">{{ scope.row.deviceCheckProductType }}</el-link> -->
-                    <div v-for="item in scope.row.plans" :key="item.id">
-                      <el-link v-if="has_btn_devicetest_run" type="primary" style="color:#6e6eea" @click="toBegin(item)">{{ item.name }}</el-link>
-                      <div v-else>{{ item.name }}</div>
-                    </div>
-                  </template>
-                </el-table-column>
-                <!-- <el-table-column
-            prop="deviceCheckModelName"
-            label="测点模型"
-          >
-            <template slot-scope="scope">
-              <el-link type="primary" :index="scope.row.deviceCheckModelName">查看</el-link>
-            </template>
-          </el-table-column>
-                <el-table-column
-                  prop="reportDate"
-                  label="检测报告"
-                  width="150px"
-                  :show-overflow-tooltip="true"
-                >
-                  <template slot-scope="scope">
-                    <div v-if="scope.row.reportDate==null || scope.row.reportDate==''" style="color:#999">[未生成报告] <el-button :id="`btn_devicetest_makereport${scope.$index}`" :ref="`btn_devicetest_makereport${scope.$index}`" data-controlcode="btn_devicetest_makereport" class="table-act" type="text" size="small" @click="creatReportClick(scope.row.id)">生成报告</el-button></div>
-                    <div v-else :key="scope.row.id"><el-link type="primary" style="color:#6e6eea" @click="toSeeReport(scope.row)">{{ scope.row.reportName }}</el-link></div>
-                  </template>
-                </el-table-column>
-                <el-table-column
-                  prop="vendorName"
-                  label="送检厂家"
-                  width="150px"
-                  :show-overflow-tooltip="true"
-                />
-                <el-table-column
-                  prop="modelName"
-                  label="设备型号"
-                  width="150px"
-                />
-                 -->
-                <el-table-column
-                  prop="createDate"
-                  label="创建日期"
-                />
-                <!-- 隐藏 列 这里不用显示,但是在编辑的时候需要获取此数据 -->
-                <el-table-column
-                  v-if="false"
-                  prop="id"
-                  label="序号"
-                />
-                <!-- 隐藏 列 -->
-              </el-table>
-            </div>
-          </div>
-        </div>
         <div class="left-row-3">
           <!-- 检测状态分类统计 -->
           <div class="checkStatusChart item">
@@ -138,24 +44,16 @@
               </div>
             </div>
           </div>
-          <!-- 检测分月统计 -->
-          <div class="checkMonthlyChart item">
-            <div class="title">检测分月统计</div>
-            <div class="left"><check-monthly-chart /></div>
-            <div class="checkYear">
-              <!-- 下拉框位置预定 -->
-            </div>
-          </div>
         </div>
       </el-col>
-      <el-col :xs="7" :sm="7" :lg="7" class="right">
+      <el-col :xs="17" :sm="17" :lg="17" class="right">
         <!-- 检测流程指南 -->
         <div class="flow-chart item">
           <div class="title">
             检测流程指南
           </div>
           <div class="flow-img">
-            <el-image :src="require('@/assets/index/flowchart.png')" fit="contain" />
+            <el-image src="./index_flow.jpg" fit="contain" />
           </div>
         </div>
       </el-col>
@@ -165,16 +63,12 @@
 
 <script>
 import { mapGetters } from 'vuex'
-import BarChart from './components/BarChart'
 import CheckStatusChart from './components/CheckStatusChart'
-import CheckMonthlyChart from './components/CheckMonthlyChart'
 import { httpGet } from '@/api/common-action'
 export default {
   name: 'DashboardAdmin',
   components: {
-    BarChart,
-    CheckStatusChart,
-    CheckMonthlyChart
+    CheckStatusChart
   },
   filters: {
     formatState: function(params) {
@@ -314,7 +208,7 @@ export default {
 .dashboard-editor-container {
 
   // border: 1px #CCC solid;
-  padding: 30px;
+  padding: 100px 30px;
   background-color: #fff;
   position: relative;
   font-size: 18px;
@@ -328,10 +222,11 @@ export default {
     // border: 1px red solid;
     .left-row-1 {
       width: 100%;
+      // margin-bottom: 20px;
       display: flex;
       justify-content: space-between ;
       .item {
-        width: 50%;
+        width: 100%;
       }
       .next-7-days {
         margin-right:20px;
@@ -382,10 +277,10 @@ export default {
     .left-row-3 {
       width: 100%;
       display: flex;
+      margin-top: 20px;
       justify-content: space-between;
       .checkStatusChart {
-        width: 40%;
-        margin-right:20px;
+        width: 100%;
         padding: 20px;
         .title {
           font-weight: bolder;

+ 472 - 0
src/views/dashboard/index_2.0.vue

@@ -0,0 +1,472 @@
+<template>
+  <div class="dashboard-editor-container">
+    <el-row :gutter="20" type="flex" justify="space-between">
+      <el-col :xs="17" :sm="17" :lg="17" class="left">
+        <div class="left-row-1">
+          <!-- 未来7天检测计划 -->
+          <div class="next-7-days item">
+            <bar-chart />
+          </div>
+          <!-- 点击创建新检测 -->
+          <div ref="btn_crate_testdevice" data-controlCode="btn_index_newtest" class="creat-new-check item">
+            <div class="img">
+              <el-link href="#/device/save" target="_self" :underline="false">
+                <el-image :src="require('@/assets/index/creatnewcheck.png')" fit="contain" />
+              </el-link>
+            </div>
+            <div class="title">
+              <el-link href="#/device/save" target="_self" :underline="false"><span>点击</span> 创建新检测</el-link>
+            </div>
+          </div>
+        </div>
+        <div class="left-row-2">
+          <!-- 最近检测 -->
+          <div class="recently item">
+            <div class="title">
+              最近检测
+              <span class="more">
+                <router-link to="/device">更多 ></router-link>
+              </span>
+            </div>
+            <div class="content">
+              <el-table
+                :data="tableData"
+                stripe
+              >
+                <el-table-column
+                  prop="serialNumber"
+                  label="设备编号"
+                  :show-overflow-tooltip="true"
+                />
+                <el-table-column
+                  prop="stateName"
+                  label="检测状态"
+                >
+                  <template slot-scope="scope">
+                    <el-tag :type="scope.row.state | formatState">{{ scope.row.stateName || '未知' }}</el-tag>
+                    <!-- <el-tag v-if="scope.row.deviceCheckStatus == null ||scope.row.deviceCheckStatus == 'NEW'" type="danger">未检测</el-tag>
+              <el-tag v-if="scope.row.deviceCheckStatus == 'RUNNING'">检测中</el-tag>
+              <el-tag v-if="scope.row.deviceCheckStatus == 'TERMINATED'" type="info">已结束</el-tag> -->
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="plans"
+                  label="检测方案"
+                  tooltip-effect="dark"
+                  :show-overflow-tooltip="true"
+                >
+                  <template slot-scope="scope">
+                    <!-- <el-link type="primary" @click="toBegin(scope.row)">{{ scope.row.deviceCheckProductType }}</el-link> -->
+                    <div v-for="item in scope.row.plans" :key="item.id">
+                      <el-link v-if="has_btn_devicetest_run" type="primary" style="color:#6e6eea" @click="toBegin(item)">{{ item.name }}</el-link>
+                      <div v-else>{{ item.name }}</div>
+                    </div>
+                  </template>
+                </el-table-column>
+                <!-- <el-table-column
+            prop="deviceCheckModelName"
+            label="测点模型"
+          >
+            <template slot-scope="scope">
+              <el-link type="primary" :index="scope.row.deviceCheckModelName">查看</el-link>
+            </template>
+          </el-table-column>
+                <el-table-column
+                  prop="reportDate"
+                  label="检测报告"
+                  width="150px"
+                  :show-overflow-tooltip="true"
+                >
+                  <template slot-scope="scope">
+                    <div v-if="scope.row.reportDate==null || scope.row.reportDate==''" style="color:#999">[未生成报告] <el-button :id="`btn_devicetest_makereport${scope.$index}`" :ref="`btn_devicetest_makereport${scope.$index}`" data-controlcode="btn_devicetest_makereport" class="table-act" type="text" size="small" @click="creatReportClick(scope.row.id)">生成报告</el-button></div>
+                    <div v-else :key="scope.row.id"><el-link type="primary" style="color:#6e6eea" @click="toSeeReport(scope.row)">{{ scope.row.reportName }}</el-link></div>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  prop="vendorName"
+                  label="送检厂家"
+                  width="150px"
+                  :show-overflow-tooltip="true"
+                />
+                <el-table-column
+                  prop="modelName"
+                  label="设备型号"
+                  width="150px"
+                />
+                 -->
+                <el-table-column
+                  prop="createDate"
+                  label="创建日期"
+                />
+                <!-- 隐藏 列 这里不用显示,但是在编辑的时候需要获取此数据 -->
+                <el-table-column
+                  v-if="false"
+                  prop="id"
+                  label="序号"
+                />
+                <!-- 隐藏 列 -->
+              </el-table>
+            </div>
+          </div>
+        </div>
+        <div class="left-row-3">
+          <!-- 检测状态分类统计 -->
+          <div class="checkStatusChart item">
+            <div class="title">检测状态分类统计</div>
+            <div class="left"><check-status-chart ref="pie" /></div>
+            <div class="right">
+              <div class="check-item">
+                <div class="name">未检测</div>
+                <div class="value">
+                  <div class="value-before status-0" />
+                  <div class="value-text">{{ echartData.NEW?echartData.NEW:0 }}</div>
+                </div>
+              </div>
+              <div class="check-item">
+                <div class="name">检测中</div>
+                <div class="value">
+                  <div class="value-before status-1" />
+                  <div class="value-text">{{ echartData.RUNNING ?echartData.RUNNING:0 }}</div>
+                </div>
+              </div>
+              <div class="check-item">
+                <div class="name">已完成</div>
+                <div class="value">
+                  <div class="value-before status-2" />
+                  <div class="value-text">{{ echartData.TERMINATED? echartData.TERMINATED:0 }}</div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <!-- 检测分月统计 -->
+          <div class="checkMonthlyChart item">
+            <div class="title">检测分月统计</div>
+            <div class="left"><check-monthly-chart /></div>
+            <div class="checkYear">
+              <!-- 下拉框位置预定 -->
+            </div>
+          </div>
+        </div>
+      </el-col>
+      <el-col :xs="7" :sm="7" :lg="7" class="right">
+        <!-- 检测流程指南 -->
+        <div class="flow-chart item">
+          <div class="title">
+            检测流程指南
+          </div>
+          <div class="flow-img">
+            <el-image :src="require('@/assets/index/flowchart.png')" fit="contain" />
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import BarChart from './components/BarChart'
+import CheckStatusChart from './components/CheckStatusChart'
+import CheckMonthlyChart from './components/CheckMonthlyChart'
+import { httpGet } from '@/api/common-action'
+export default {
+  name: 'DashboardAdmin',
+  components: {
+    BarChart,
+    CheckStatusChart,
+    CheckMonthlyChart
+  },
+  filters: {
+    formatState: function(params) {
+      switch (params) {
+        // 已检测
+        case 'TERMINATED':
+          return 'info'
+        // 未检测
+        case 'NEW':
+          return 'warning'
+        // 检测中
+        case 'RUNNING':
+          return 'success'
+        default:
+          return 'info'
+      }
+    }
+  },
+  data() {
+    return {
+      // 是否有设备检测权限
+      has_btn_devicetest_run: false,
+      tableData: [],
+      echartData: {}
+    }
+  },
+  computed: {
+    ...mapGetters([
+      'roles'
+    ])
+  },
+  created() {
+  },
+  mounted() {
+    // 权限判断
+    this.has_btn_devicetest_run = this.common.userPurviewControl('btn_devicetest_run')
+    this.$nextTick(async() => {
+      // 网页加载完成后执行
+      this.common.ApplyElementPurviewByRef(this.$refs)
+      // 读取最近检测完设备
+      // /test/project/search?page=0&size=4&state=TERMINATED
+      const getUrl = `/test/project/search?page=0&size=4&state=TERMINATED`
+      await httpGet(getUrl).then(res => {
+        if (res == null || res.content == null) return
+        this.tableData = res.content
+        this.common.ApplyElementPurviewByRef(this.$refs)
+      })
+      const echartD = await httpGet('/home/project/state')
+      delete echartD.code
+      this.echartData = Object.assign({}, { ...echartD })
+      // console.log('echartData', this.echartData)
+      // const sum = (parseInt(this.echartData.NEW || 0) + parseInt(this.echartData.RUNNING || 0) + parseInt(this.echartData.TERMINATED || 0))
+      // console.log('11sum', sum)
+      this.$refs.pie.initData(this.echartData.NEW, this.echartData.RUNNING, this.echartData.TERMINATED)
+    })
+  },
+  methods: {
+    // 报告查看
+    toSeeReport(row) {
+      const par = { id: row.id }
+      this.$router.push({ path: `/testreport/index`, query: par })
+    },
+    // 去开始检测
+    async toBegin(row) {
+      // console.log(row)
+      const par = { deviceId: row.projectId, curPlanId: row.id, suiteId: row.suiteId }
+      this.$router.push({ path: `/device/check`, query: par })
+      // const resData = await httpGet(`/test/project/${par.deviceId}/plan/list`).then(
+      //   (res) => {
+      //     console.log('获取选择方案选项 getOptions rs=', res)
+      //     return res
+      //   }
+      // )
+      // if (resData.length) {
+      //   par.curPlanId = resData[0].id
+      //   par.suiteId = resData[0].suiteId
+      //   this.$router.push({ path: `/device/check`, query: par })
+      // } else {
+      //   this.$message({
+      //     type: 'error',
+      //     message: '请先添加检测方案',
+      //     offset: window.screen.height / 3
+      //   })
+      // }
+    },
+    /* 首页暂时不使用 编辑和删除功能
+    // 修改
+    editClick(row) {
+      // 跳转到设备基本信息页面
+      // console.log('editClick=', row)
+      this.$router.push({ path: `/device/save`, query: { deviceCheckId: row.id }})
+    },
+    // 删除记录
+    delClick(row, index) {
+      // /test/project/:id
+      console.log('delroe = ', row)
+      this.$confirm('此操作将永久删除该记录, 是否继续?', `删除:${row.name}`, {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        if (row.id > 0) {
+        // :id 检测设备id
+          delRecord(`/test/project/${row.id}`).then(response => {
+            // console.log('delRecord rs=', response)
+            this.$message({
+              message: '删除成功',
+              type: 'success',
+              offset: window.screen.height / 3
+            })
+            // 后端成功执行后,前端再删除选中行
+            this.tableData.splice(index, 1)
+          }).catch(err => {
+            console.log('delRecord err rs=', err)
+          })
+        } else {
+        // 如果是新增的临时行,直接删除选中行
+          this.tableData.splice(index, 1)
+        }
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除',
+          offset: window.screen.height / 3
+        })
+      })
+    },
+    */
+    // 跳转
+    routerGoto(goto_url) {
+      this.$router.push({ path: goto_url })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.dashboard-editor-container {
+
+  // border: 1px #CCC solid;
+  padding: 30px;
+  background-color: #fff;
+  position: relative;
+  font-size: 18px;
+
+  .item {
+    border: 1px #CCC solid;
+    background-color: #FFF;
+  }
+
+  .left {
+    // border: 1px red solid;
+    .left-row-1 {
+      width: 100%;
+      display: flex;
+      justify-content: space-between ;
+      .item {
+        width: 50%;
+      }
+      .next-7-days {
+        margin-right:20px;
+      }
+      .creat-new-check {
+        height: 280px;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        .img {
+          width: 100%;
+          text-align: center;
+          .el-image {
+            width: 60%;
+          }
+        }
+        .title {
+          width: 100%;
+          text-align: center;
+          .el-link {
+            padding-top: 25px;
+            // display: block;
+            font-size: 18px;
+            span{
+              color: #00706B;
+            }
+          }
+        }
+      }
+    }
+    .left-row-2 {
+      margin: 20px 0;
+      .recently {
+        // border: 1px #CCC solid;
+        padding: 20px;
+        .title {
+          padding-bottom: 20px;
+          span {
+            float: right;
+          }
+        }
+        .el-table th {
+          background-color: #00706B;
+        }
+      }
+    }
+    .left-row-3 {
+      width: 100%;
+      display: flex;
+      justify-content: space-between;
+      .checkStatusChart {
+        width: 40%;
+        margin-right:20px;
+        padding: 20px;
+        .title {
+          font-weight: bolder;
+        }
+        .left {
+          // border: 1px solid #f00;
+          float: left;
+          width: 70%;
+        }
+        .right {
+          // border: 1px solid #0F0;
+          height: 100%;
+          display: flex;
+          flex-wrap: wrap;
+          padding: 40px 0;
+          align-items: center;
+          text-align: center;
+          .check-item {
+            width: 100%;
+            .name {
+              font-size: 14px;
+              padding-bottom: 6px;
+            }
+            .value {
+              font-size: 20px;
+              font-weight: bolder;
+              padding-bottom: 24px;
+              display: flex;
+              justify-content: center;
+              .value-before { // 小圆点在这里
+                width: 10px;
+                height: 10px;
+                border-radius: 50%;
+                margin-right: 8px;
+                margin-left: 7px;
+                margin-top: 6px;
+              }
+              .status-0 {
+                border: 1px solid #111;
+                background-color: #111;
+              }
+              .status-1 {
+                border: 1px solid #00706B;
+                background-color: #00706B;
+              }
+              .status-2 {
+                border: 1px solid #0093a7;
+                background-color: #0093a7;
+              }
+            }
+          }
+        }
+      }
+      .checkMonthlyChart {
+        width: 60%;
+        padding: 20px;
+        .title {
+          font-weight: bolder;
+          padding-bottom: 30px;
+        }
+      }
+    }
+  }
+  .right {
+    // border: 1px blue solid;
+    .flow-chart {
+      padding: 20px;
+      height: 100%;
+      display: flex;
+      flex-flow: column;
+    }
+    .title {
+      margin-bottom: 40px;
+    }
+    .flow-img {
+      flex: 1;
+      text-align: center;
+      .el-image {
+        height: 100%;
+      }
+    }
+  }
+}
+</style>

+ 3 - 100
src/views/device/check.vue

@@ -351,12 +351,6 @@ export default {
         (response) => {
           // console.log('获取选择方案选项 getOptions rs=', response)
           this.deviceDetail.devicePlanOptions = response
-          // 通过传过来的 planId 获取 默认选择方案
-          // const optionsIndex = this.deviceDetail.devicePlanOptions.findIndex(item => {
-          //   if (item.id === this.deviceDetail.planId) {
-          //     return true
-          //   }
-          // })
           this.deviceDetail.devicePlanValue = this.deviceDetail.curPlanId
         }
       )
@@ -406,103 +400,12 @@ export default {
         // #TODO: 999 和 3200000217 都 返回的是空
         // 接口 步骤状态(高频刷新) /test/execute/:runner/progress
         // :runner 例 3200000217
-        let getUrl = `/test/execute/${this.deviceDetail.curPlanId}/progress`
-        httpGet(getUrl).then(res => {
-          this.deviceDetail.deviceCheckPlans.forEach(item => {
-            res.forEach(ritem => {
-              if (item.id === ritem.id) {
-                item.status = ritem.stateName
-                // item = ritem
-              }
-            })
-          })
-          this.deviceCheckPlanUpdate = 'steps' + new Date().getTime()
-          // console.log('getStatusLoop 步骤状态(高频刷新) res=', res)
-        })
+        // 刷新步骤
+        EventBus.$emit('refreshManualStep', false)
         // 刷新用例、采样表格状态
         EventBus.$emit('refreshManualFn', false)
         EventBus.$emit('refreshManualSample', false)
-
-        // 接口 用例状态(高频刷新) /test/execute/:runner/results
-        // :runner 例 3200000217
-        // getUrl = `/test/execute/${this.deviceDetail.curPlanId}/results`
-        getUrl = `/test/execute/${this.deviceDetail.curPlanId}/results`
-        httpGet(getUrl).then(res => {
-          // 用例返回数据示例:
-          // {
-          //   "units": [
-          //     {
-          //       "id": "999103",
-          //       "name": "读输入寄存器",
-          //       "ruleId": 103,
-          //       "ruleName": "读输入寄存器",
-          //       "value": 0,
-          //       "error": 0,
-          //       "state": null,
-          //       "stateName": null
-          //     }
-          //      ...
-          //   ],
-          //   "total": 5,
-          //   "successful": 0,
-          //   "failed": 0,
-          //   "aborted": 0
-          // }
-
-          // 遍历现有 用例数据,更新用例表格中的 测试状态
-          this.exampleStatus = res
-          // console.log('getStatusLoop exampleStatus=', this.exampleStatus)
-        })
-
-        // sampleStatus
-        // 接口 采样数据(高频刷新) /test/execute/:runner/values
-        // :runner 例 3200000217
-        // getUrl = `/test/execute/:runner/values`
-        getUrl = `/test/execute/${this.deviceDetail.curPlanId}/values`
-        httpGet(getUrl).then(res => {
-          // 返回数据示例:
-          // [
-          //   {
-          //     "id": "24577",
-          //     "name": "A相电压",
-          //     "offset": 0,
-          //     "value": null,
-          //     "occur": null,
-          //     "iec104": 24577,
-          //     "modbus": 40001,
-          //     "range": "HOLDING_REGISTER"
-          //   },
-          //   ...
-          // ]
-
-          // 遍历现有 采样数据,更新采样表格中的
-          // "value": null,
-          // "occur": null,
-          this.sampleStatus = res
-        })
-
-        // deviceDetail.deviceCheckPlans
-        // 接口 步骤状态(高频刷新)/test/execute/:runner/progress
-        getUrl = `/test/execute/${this.deviceDetail.curPlanId}/progress`
-        httpGet(getUrl).then(res => {
-          // 返回数据示例:
-          // [
-          //   {
-          //     "id": "123",
-          //     "name": "检测中",
-          //   },
-          //   ...
-          // ]
-
-          // 遍历现有 检测步骤 更新其中状态字段
-          if (this.deviceDetail.deviceCheckPlans) {
-            this.deviceDetail.deviceCheckPlans.forEach(item => {
-              if (res.id === item.id) {
-                item.status = res.name
-              }
-            })
-          }
-        })
+        EventBus.$emit('refreshManualReportMsg', false)
         this.getStatusLoop()
       }, this.deviceDetail.deviceRefreshValue * 1000)
     },

+ 5 - 0
src/views/device/components/CheckSteps.vue

@@ -186,6 +186,8 @@ export default {
     }
   },
   mounted() {
+    EventBus.$off('refreshManualStep')
+    EventBus.$on('refreshManualStep', this.refreshStep)
     // console.log('deviceStatus=', this.deviceStatus)
     // 首次打开获取步骤
     this.getSteps()
@@ -222,6 +224,9 @@ export default {
         this.getSteps()
       }).catch(() => {})
     },
+    refreshStep() {
+      this.stepActionClick('refresh')
+    },
     // 添加/编辑步骤后刷新步骤模块
     getSteps() {
       // 获取设备 - 检测步骤 数据

+ 49 - 3
src/views/device/components/ModelFormFileTransferOpt104.vue

@@ -35,11 +35,25 @@
                 <el-button style="float: right;" class="light-button" icon="el-icon-add" size="big" @click="addFileRecord()">添加文件信息</el-button>
               </el-col>
             </el-row>
+            <el-row>
+              <div class="buttons" style="text-align: left;">
+                <el-button
+                  class="dark-button"
+                  icon="el-icon-delete"
+                  size="small"
+                  :disabled="!showDel"
+                  @click="multDelete()"
+                >批量删除</el-button>
+              </div>
+            </el-row>
             <el-row type="flex" style="float:left;width: 100%;margin-top: 10px;">
               <el-col>
                 <div class="left-report">
                   <!-- 表格 -->
-                  <el-table v-loading="isLoading2" :data="dbFileList" :height="tableHeight">
+                  <el-table v-loading="isLoading2" :data="dbFileList" :height="tableHeight" @selection-change="handleSelectionChange">
+                    <el-table-column
+                      type="selection"
+                    />
                     <!-- id隐藏不显示,作为操作数据依据 -->
                     <el-table-column v-if="false" property="id" label="id" />
                     <el-table-column property="name" label="文件名" width="260px" />
@@ -104,7 +118,7 @@
                 >
                   <el-button
                     type="primary"
-                    class="light-button"
+                    class="dark-button"
                     icon="el-icon-upload2"
                     :disabled="isUploadFileIng"
                     size="big"
@@ -189,7 +203,10 @@ export default {
       dbFileList: [],
       uplaodHeader: { 'Authorization': 'Bearer ' + getToken() },
       tableHeight: window.innerHeight * 0.5,
-      fileUrl: ''
+      fileUrl: '',
+      multipleSelection: '',
+      // 批量删除显示控制
+      showDel: false
     }
   },
   computed: {
@@ -212,6 +229,15 @@ export default {
       // this.fileUrl = window.STATIC_CONFIG.proxyUrl
       this.getList()
     },
+    // 多选按钮状态改变 handleSelectionChange
+    handleSelectionChange(val) {
+      // 选中行存入临时变量中
+      this.multipleSelection = val
+      console.log('handleSelectionChange val', val)
+      // 批量删除按钮激活
+      if (val.length > 0) this.showDel = true
+      else this.showDel = false
+    },
     // 关闭model时执行
     modelOnClose() {
       this.$emit('toggleModel', 'ModelFormFileTransferOpt104', false)
@@ -346,6 +372,26 @@ export default {
       })
       this.getList()
     },
+    async multDelete() {
+      // 批量删除
+      for (let i = 0; i < this.multipleSelection.length; i++) {
+        const row = this.multipleSelection[i]
+        let isOk = true
+        await delRecord('/test/file/', row.id).then(res => {
+        }).catch(res => {
+          this.$message({
+            message: res.message,
+            type: 'error',
+            offset: window.screen.height / 3
+          })
+          isOk = false
+        })
+        if (!isOk) {
+          break
+        }
+      }
+      this.getList()
+    },
     deleteFile(row) {
       delRecord('/test/file/', row.id).then(res => {
         this.$message({

+ 4 - 0
src/views/device/components/ModelReport_master104.vue

@@ -100,6 +100,8 @@ import { mapGetters } from 'vuex'
 import { delRecord, download, httpGet } from '@/api/common-action'
 import clipboard from '@/directive/clipboard/index.js'
 import Pagination from '@/components/Pagination'
+// 导入总线
+import { EventBus } from '@/main.js'
 export default {
   name: 'ModelReport',
   directives: {
@@ -176,6 +178,8 @@ export default {
   },
   mounted() {
     this.comonentVar.deviceReportTitle = `[${this.reportParames.deviceName}]报文详情`
+    EventBus.$off('refreshManualReportMsg')
+    EventBus.$on('refreshManualReportMsg', this.refreshReport)
   },
   methods: {
     // 关闭model

+ 0 - 2
src/views/device/tables/Example.vue

@@ -283,8 +283,6 @@ export default {
     refreshManual(isHand) {
       // 接口 用例状态(高频刷新) /test/execute/:runner/results
       const getUrl = `/test/execute/${this.componentParames.curPlanId}/results`
-      // const getUrl = `/test/execute/${this.componentParames.curPlanId}/models`
-      // console.log('手动刷新 getUrl=', getUrl)
       httpGet(getUrl).then(res => {
         this.unitsData = res
         if (this.tableData.length > 0) {

+ 1 - 0
src/views/device/tables/Sample_master104.vue

@@ -182,6 +182,7 @@
                 @click="delRow(scope.$index)"
               >删除</el-button>
               <el-button
+                v-if="false"
                 class="table-act"
                 type="text"
                 icon="el-icon-data-line"

+ 104 - 52
src/views/plan/components/PlanCheckPoint_master104.vue

@@ -120,6 +120,7 @@
               v-model="scope.row.offset"
               class="table-column-input"
               type="number"
+              oninput="if(value.length>5) value=value.slice(0,5)"
               :disabled="Boolean(scope.row.id)"
             />
           </template>
@@ -225,7 +226,7 @@
           </template>
         </el-form-item>
         <el-form-item label="*点号" :label-width="formLabelWidth">
-          <el-input v-model="form.offset" maxlength="6" />
+          <el-input v-model="form.offset" disabled maxlength="6" />
         </el-form-item>
         <el-form-item v-if="false" label="关联遥信点号 (仅遥控可关联)" :label-width="formLabelWidth">
           <el-input v-if="form.range=='COIL_STATUS'" v-model="form.relationTag" maxlength="6" placeholder="请输入遥信点号" />
@@ -236,10 +237,10 @@
           <el-input v-else v-model="form.relationTag" disabled />
         </el-form-item>
         <el-form-item label="倍率" :label-width="formLabelWidth">
-          <el-input v-model="form.scaling" maxlength="5" />
+          <el-input v-model="form.scaling" type="number" maxlength="5" oninput="if(value.length>5)value=value.slice(0,5)" />
         </el-form-item>
         <el-form-item label="偏移量" :label-width="formLabelWidth">
-          <el-input v-model="form.adjust" maxlength="6" />
+          <el-input v-model="form.adjust" type="number" maxlength="6" oninput="if(value.length>6)value=value.slice(0,6)" />
         </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
@@ -303,7 +304,7 @@ export default {
       tmpCheckPointId: 0,
       tmpTableData: [],
       // 每页显示多少条
-      pageLimit: 20,
+      pageLimit: 50,
       paginationNumber: 1,
       // 一共多少条
       paginationTotalElements: 0,
@@ -329,7 +330,9 @@ export default {
       stepIndex: '',
       tableHeight: '',
       // 多选框选中数据
-      multipleSelection: ''
+      multipleSelection: '',
+      // 数据提交状态
+      iscommitstate: false
     }
   },
   watch: {
@@ -360,6 +363,7 @@ export default {
     this.tableHeight = window.innerHeight - marginBottom
   },
   mounted() {
+    this.initFunctions()
     this.$nextTick(() => {
       // 网页加载完成后执行
       this.importCsvActionStr = `/product/model/0/models.csv`
@@ -368,7 +372,6 @@ export default {
         this.getPlanCheckPoint()
         this.importCsvActionStr = `/product/model/${this.currentPlanData.product}/models.csv`
       }
-      this.initFunctions()
     })
   },
   methods: {
@@ -455,6 +458,9 @@ export default {
       // console.log('planClear 清除')
       this.tableData = []
     },
+    checkNotSavePoint() {
+      return true
+    },
     // 获取测点表格数据
     async getPlanCheckPoint(pageObj) {
       this.vloading = true
@@ -506,6 +512,8 @@ export default {
         this.paginationTotalPages = response.totalPages
         this.paginationTotalElements = parseInt(response.totalElements)
         this.paginationNumber = response.number * 1 + 1
+      }).catch((res) => {
+        this.vloading = false
       })
     },
     // 表格重排
@@ -527,7 +535,7 @@ export default {
     //   // editRow(editPath, editData)
 
     // },
-    async saveClick(row, index) {
+    async saveClick(row, index, ishint) {
       // if (row.offset > 65535) {
       //   this.$message({
       //     type: 'error',
@@ -547,15 +555,43 @@ export default {
       if (v === '') {
         isNotPassMesage = '必填项(测点名称)不能为空'
       }
-      v = editData.range == null ? '' : editData.range
-      v = v.toString().replace(/ /gi, '')
-      if (v === '') {
-        isNotPassMesage = '必填项(点号类型)不能为空'
+      const names = {}
+      for (let i = 0; i < this.tableData.length; i++) {
+        const v = this.tableData[i].name
+        if (names[v] != null) {
+          isNotPassMesage = '测点名称' + v + '已经存在'
+          break
+        }
+        names[v] = this.tableData[i]
       }
-      v = editData.offset == null ? '' : editData.offset
-      v = v.toString().replace(/ /gi, '')
-      if (v === '') {
-        isNotPassMesage = '必填项(点号)不能为空'
+      // const has = this.tableData.filter((item) => { if (item.name === v && row.id !== item.id) { return true } })
+      if (isNotPassMesage !== '') {
+        row.name = ''
+      } else {
+        v = editData.range == null ? '' : editData.range
+        v = v.toString().replace(/ /gi, '')
+        if (v === '') {
+          isNotPassMesage = '必填项(点号类型)不能为空'
+        }
+        v = editData.offset == null ? '' : editData.offset
+        v = v.toString().replace(/ /gi, '')
+        if (v === '') {
+          isNotPassMesage = '必填项(点号)不能为空'
+        } else {
+          const offsets = {}
+          for (let i = 0; i < this.tableData.length; i++) {
+            const v = this.tableData[i].range + ':' + this.tableData[i].offset
+            if (offsets[v] != null) {
+              isNotPassMesage = '点号' + v + '已经存在'
+              break
+            }
+            offsets[v] = this.tableData[i]
+          }
+          // const has2 = this.tableData.filter((item) => { if (item.offset === (v * 1) && row.id !== item.id) { return true } })
+          if (isNotPassMesage !== '') {
+            row.offset = ''
+          }
+        }
       }
       if (isNotPassMesage !== '') {
         this.$message({
@@ -563,10 +599,10 @@ export default {
           message: isNotPassMesage,
           offset: window.screen.height / 3
         })
-        return
+        return null
       }
       const res = await editRow(editPath, editData)
-      if (res) {
+      if (res && ishint !== 'nohint') {
         this.$set(this.tableData[index], 'id', res.id)
         this.$set(this.tableData[index], 'modbus', res.modbus)
         this.$set(this.tableData[index], 'iec104', res.iec104)
@@ -576,6 +612,7 @@ export default {
           offset: window.screen.height / 3
         })
       }
+      return res.id
     },
     delClick(row) {
       // return
@@ -594,8 +631,9 @@ export default {
               // 后端成功执行后,前端再删除选中行
               // this.tableData.splice(index, 1)
               // this.tableData = this.tableData.filter(item => item.id !== row.id)
-              const newData = this.tableData.filter(item => item.id !== row.id)
-              this.tableData = [...newData]
+              // const newData = this.tableData.filter(item => item.id !== row.id)
+              // this.tableData = [...newData]
+              this.getPlanCheckPoint()
             })
         } else {
         // 如果是新增的临时行,直接删除选中行
@@ -620,7 +658,11 @@ export default {
     },
     // 提交
     // 提交 下一步
-    submitPlan() {
+    async submitPlan() {
+      if (this.iscommitstate) {
+        // 数据正在提交中
+        return
+      }
       // console.log(`this.tmpTableData=`, this.tmpTableData)
       let currentStep = this.currentStep
       const noName = this.tableData.some(item => ((!item.name) || (!item.range) || (!item.offset.toString())))
@@ -640,22 +682,27 @@ export default {
           this.$emit('changeStep', currentStep)
           return
         }
+        this.iscommitstate = true
         // 不接受数组提交,只能单条提交,所以使用遍历提交
-        this.tableData.forEach((item, index) => {
+        let iserror = false
+        for (let index = 0; index < this.tableData.length; index++) {
+          const item = this.tableData[index]
           const tableRowData = this.getSubmitTableRowData(item)
-
-          // 保存步骤
-          const editPath = `/product/model/${this.currentPlanData.product}`
-          editRow(editPath, tableRowData).then(res => {
-            // console.log('PlanCheckPoint submitPlan currentStep=', currentStep)
-            // console.log('PlanCheckPoint submitPlan index=', index)
-            if (index === this.tableData.length - 1) {
+          await this.saveClick(tableRowData, index, 'nohint').then((res) => {
+            if (res == null) {
+              iserror = true
+            }
+            if (!iserror && index === this.tableData.length - 1) {
               // 如果是最后一条数据 提交成功,下一步
               currentStep = currentStep + 1
               this.$emit('changeStep', currentStep)
             }
           })
-        })
+          if (iserror) {
+            break
+          }
+        }
+        this.iscommitstate = false
       } else {
         // 已经是最后一步了
       }
@@ -708,19 +755,9 @@ export default {
     },
     // 批量删除
     async multDelete() {
-      /* const delUrl = `/product/model/${this.currentPlanData.product}/${item.id}`
-      delRecord(delUrl).then((response) => {
-        console.log('delRecord rs=', response)
-        // 后端成功执行后,前端再删除选中行
-        // this.tableData.splice(index, 1)
-        // this.tableData = this.tableData.filter(item => item.id !== row.id)
-        const newData = this.tableData.filter(par => par.id !== item.id)
-        this.tableData = [...newData]
-      }).catch((err) => {
-        console.log('delRecord err rs=', err)
-      }) */
       // 后端执行完成后,开始前端操作
       // 遍历 `tableData` 数组
+      let isDelCount = false
       for (let i = 0; i < this.tableData.length; i++) {
         const item = this.tableData[i]
         // 判断当前行数据是否被选中
@@ -732,8 +769,9 @@ export default {
             const delUrl = `/product/model/${this.currentPlanData.product}/${item.id}`
             await delRecord(delUrl).then((response) => {
               // 后端成功执行后,前端再删除选中行
-              this.tableData.splice(i, 1)
-              i-- // 因为 `splice` 方法会修改数组长度,所以需要将 `i` 减去 1,避免漏删下一个元素
+              // this.tableData.splice(i, 1)
+              // i-- // 因为 `splice` 方法会修改数组长度,所以需要将 `i` 减去 1,避免漏删下一个元素
+              isDelCount++
             })
           } else {
             // 如果是新增未保存过的数据,直接删除
@@ -742,6 +780,7 @@ export default {
           }
         }
       }
+      if (isDelCount) this.getPlanCheckPoint()
       // this.showDel = false
     },
     // 多选按钮状态改变 handleSelectionChange
@@ -780,16 +819,29 @@ export default {
         v = v.toString().replace(/ /gi, '')
         if (v === '') {
           isNotPassMesage = '必填项(测点名称)不能为空'
-        }
-        v = this.form.range || ''
-        v = v.toString().replace(/ /gi, '')
-        if (v === '') {
-          isNotPassMesage = '必填项(点号类型)不能为空'
-        }
-        v = this.form.offset == null ? '' : this.form.offset
-        v = v.toString().replace(/ /gi, '')
-        if (v === '') {
-          isNotPassMesage = '必填项(点号)不能为空'
+        } else {
+          const has = this.tableData.filter((item) => { if (item.name === v && this.form.id !== item.id) { return true } })
+          if (has !== null && has.length > 0) {
+            this.form.name = ''
+            isNotPassMesage = '测点名称' + v + '已经存在'
+          } else {
+            v = this.form.range || ''
+            v = v.toString().replace(/ /gi, '')
+            if (v === '') {
+              isNotPassMesage = '必填项(点号类型)不能为空'
+            }
+            v = this.form.offset == null ? '' : this.form.offset
+            v = v.toString().replace(/ /gi, '')
+            if (v === '') {
+              isNotPassMesage = '必填项(点号)不能为空'
+            } else {
+              const has2 = this.tableData.filter((item) => { if (item.range === this.form.range && item.offset === (v * 1) && this.form.id !== item.id) { return true } })
+              if (has2 !== null && has2.length > 0) {
+                this.form.offset = ''
+                isNotPassMesage = '点号' + this.form.range + ':' + v + '已经存在'
+              }
+            }
+          }
         }
         if (isNotPassMesage !== '') {
           this.$message({

+ 3 - 2
src/views/plan/components/PlanList.vue

@@ -426,13 +426,14 @@ export default {
           await delRecord(delUrl).then((response) => {
             // console.log('delRecord rs=', response)
             // 后端成功执行后,前端再删除选中行
-            this.tableData.splice(i, 1)
-            i-- // 因为 `splice` 方法会修改数组长度,所以需要将 `i` 减去 1,避免漏删下一个元素
+            // this.tableData.splice(i, 1)
+            // i-- // 因为 `splice` 方法会修改数组长度,所以需要将 `i` 减去 1,避免漏删下一个元素
           }).catch((err) => {
             console.log('delRecord err rs=', err)
           })
         }
       }
+      this.planSearch()
     },
     delClick(row, index) {
       // console.log('delClick row=', row)