he wei
2023-11-16 65599edd022b729d4855802f553ed449bdfbf3f8
src/views/home/index.vue
@@ -1,34 +1,548 @@
<script>
import {mapState} from "vuex";
import { mapState } from "vuex";
import { updateDfu, readFileList, getDevFileName, stopDfu } from "./api";
import FileProcess from "./fileProcess";
import getWebUrl from "@/assets/js/getWebUrl";
import createWs from "@/assets/js/websocket/plus";
const WSMixin = createWs("dev", "dfu");
const WORKSTATE = ["通信故障", "通信正常", "远程升级中", "文件下载中"];
export default {
   name: "home",
   data() {
      return {
         num: 0
      }
   },
   methods: {
      add() {
         this.num++;
      }
   },
   computed: {
      ...mapState({
         cachedViews: state => state.tagsView.cachedViews
      }),
   }
}
  name: "home",
  mixins: [WSMixin],
  components: {
    FileProcess,
  },
  data() {
    const baseURL = getWebUrl();
    return {
      updatePercent: 0,
      baseURL,
      fileListVisible: false,
      updateVisible: false,
      battListVisible: false,
      tableData: [],
      headers: [
        {
          prop: "devIp",
          label: "设备Ip",
          width: "180",
        },
        {
          prop: "devVersion",
          label: "设备版本号",
          width: "240",
        },
        {
          prop: "devId",
          label: "设备ID",
          width: "180",
        },
        {
          prop: "recordDatetime",
          label: "更新时间",
          width: "180",
        },
        {
          prop: "devEachgroupBattsum",
          label: "电池组数",
          width: "120",
        },
        {
          prop: "devState",
          label: "设备工作状态",
          width: "120",
        },
        {
          prop: "devCommcount",
          label: "设备通信计数",
          width: "120",
        },
        {
          prop: "devErrcommcount",
          label: "设备通信错误计数",
          width: "150",
        },
      ],
      tableBattsData: [],
      battsHeaders: [
        {
          prop: "battName",
          label: "电池组名称",
          width: "240",
        },
      ],
      fileList: [],
      currDevId: 0,
      transferFiles: {},
      pcFileListVisible: false,
      pcFileList: [],
      multipleSelection: [],
    };
  },
  methods: {
    onWSMessage1(res) {
      res = JSON.parse(res.data);
      let sys_time = new Date(res.data3).getTime();
      let data = res.data2.map((v) => {
        v.isTimeout =
          Math.abs(new Date(v.recordDatetime).getTime() - sys_time) > 1000 * 60;
        v.devState = v.isTimeout ? "连接超时" : WORKSTATE[v.devWorkstate];
        v.batts = v.battnamelist.split(",");
        return v;
      });
      // console.log(data, "=====data", sys_time);
      this.tableData = data;
    },
    onWSMessage2(res) {
      res = JSON.parse(res.data);
      let { dfuDataBlocklen, dfuDataBlocknum } = res.data2;
      if (!dfuDataBlocklen) {
        this.updatePercent = 0;
        return false;
      }
      this.updatePercent =
        Math.round((dfuDataBlocknum / dfuDataBlocklen) * 10000) / 100;
    },
    sendMessage2() {
      if (!this.isWSOpen2) {
        setTimeout(this.sendMessage2, 500);
        return false;
      }
      this.SOCKET2.send(JSON.stringify(this.currDevId));
    },
    canUpdate(record) {
      let { isTimeout, devWorkstate } = record;
      return !isTimeout && (devWorkstate == 1 || devWorkstate == 2);
    },
    canRead(record) {
      let { isTimeout, devWorkstate } = record;
      return !isTimeout && (devWorkstate == 1 || devWorkstate == 3);
    },
    showBatts(record) {
      this.currDevId = record.devId;
      this.tableBattsData = record.batts.map((v, i) => ({
        battName: v,
        idx: i,
      }));
      this.battListVisible = true;
    },
    update(record) {
      this.currDevId = record.devId;
      this.fileList = [];
      this.updateVisible = true;
      this.sendMessage2();
    },
    fileChange(file, fileList) {
      console.log(file, fileList, "change");
      this.fileList = [file];
    },
    fileRemove(file, fileList) {
      this.fileList = fileList;
    },
    stopUpdate() {
      let loading = this.$layer.loading();
      stopDfu(this.currDevId)
        .then((res) => {
          let { code, data } = res.data;
          if (code && data) {
            this.$message.success("操作成功");
          } else {
            this.$message.error("操作失败");
          }
          this.$layer.close(loading);
        })
        .catch((err) => {
          this.$layer.close(loading);
          console.log(err);
        });
    },
    upload() {
      let formData = new FormData();
      formData.append("file", this.fileList[0].raw);
      formData.append("devId", this.currDevId);
      let loading = this.$layer.loading();
      updateDfu(formData)
        .then((res) => {
          let { code, data, msg } = res.data;
          if (code && data) {
            this.$message.success(msg);
          } else {
            this.$message.error(msg);
          }
          this.$layer.close(loading);
        })
        .catch((err) => {
          this.$layer.close(loading);
          console.log(err);
        });
    },
    showFiles(record) {
      // 如果是下载中 则不请求数据 进组件 查websocket
      if (this.isTransfering) {
        this.fileListVisible = true;
        this.transferFiles = {};
        return;
      }
      let battIndex = record.idx;
      let devId = this.currDevId;
      let fileIndex = 0;
      let loading = this.$layer.loading();
      readFileList(battIndex, devId, fileIndex)
        .then((res) => {
          let { code, data, data2, msg } = res.data;
          if (code && data) {
            this.$message.success(msg);
            this.fileListVisible = true;
            this.transferFiles = data2;
          } else {
            this.$message.error(msg);
            this.transferFiles = {};
          }
          this.$layer.close(loading);
        })
        .catch((err) => {
          this.$layer.close(loading);
          console.log(err);
        });
    },
    showPCFiles(record) {
      let battName = record.battName;
      let devId = this.currDevId;
      let loading = this.$layer.loading();
      getDevFileName(battName, devId)
        .then((res) => {
          let { code, data, data2 } = res.data;
          let list = [];
          if (code && data) {
            console.log(data);
            list = data2.map((v) => {
              let url = v;
              let fileName = url.split("\\").pop();
              return {
                url,
                fileName,
              };
            });
          }
          this.$layer.close(loading);
          this.pcFileList = list;
          this.pcFileListVisible = true;
        })
        .catch((err) => {
          this.$layer.close(loading);
          console.log(err);
        });
    },
    handleSelectionChange(val) {
      console.log(val, "selection");
      this.multipleSelection = val;
    },
    downloadFile(url) {
      // const fileName = url.split("\\").pop();
      // let link = document.createElement("a");
      // link.style.display = "none";
      // link.href = this.baseURL + url;
      // link.download = fileName;
      // document.body.appendChild(link);
      // link.click();
      // document.body.removeChild(link);
      const iframe = document.createElement("iframe");
      iframe.style.display = "none";
      iframe.src = this.baseURL + url;
      document.body.appendChild(iframe);
      setTimeout(() => {
        iframe.remove();
      }, 10 * 1000);
    },
    downloadFiles() {
      // console.log(this.multipleSelection, "??z");
      this.multipleSelection.forEach((v, i) => {
        this.downloadFile(v.url);
      });
    },
  },
  computed: {
    ...mapState({
      cachedViews: (state) => state.tagsView.cachedViews,
    }),
    isTransfering() {
      if (!this.currDevId) {
        return false;
      }
      let obj = this.tableData.filter((v) => v.devId == this.currDevId)[0];
      let { isTimeout, devWorkstate } = obj;
      console.log("是否下载中", !isTimeout && devWorkstate == 3);
      return !isTimeout && devWorkstate == 3;
    },
    isUpdateing() {
      if (!this.currDevId) {
        return false;
      }
      let obj = this.tableData.filter((v) => v.devId == this.currDevId)[0];
      let { isTimeout, devWorkstate } = obj;
      return !isTimeout && devWorkstate == 2;
    },
    readingBattName() {
      if (!this.currDevId) {
        return false;
      }
      let obj = this.tableData.filter((v) => v.devId == this.currDevId)[0];
      return obj.nowDownloadBatt;
    },
    progressColor() {
      if (this.updatePercent < 30) {
        return "#ff0000";
      }
      if (this.updatePercent < 60) {
        return "#AA40F0";
      }
      if (this.updatePercent == 100) {
        return "#009900";
      } else {
        return "#4840F0";
      }
    },
    progressTextColor() {
      if (this.updatePercent < 8) {
        return "#00f7f9";
      }
      return "#ffffff";
    },
  },
  mounted() {},
};
</script>
<template>
   <div>
      首页
      <div>{{num}} <el-button @click="add"></el-button></div>
      {{cachedViews}}
   </div>
  <div class="p-container" ref="root">
    <div class="p-title">设备列表</div>
    <el-table
      ref="table"
      :data="tableData"
      border
      height="100%"
      style="width: 100%"
      tooltip-effect="light"
    >
      <el-table-column type="index" label="序号" width="80"></el-table-column>
      <el-table-column
        v-for="header in headers"
        :key="header.prop"
        :prop="header.prop"
        :label="header.label"
        :min-width="header.width"
        align="center"
        show-overflow-tooltip
      ></el-table-column>
      <el-table-column label="操作" fixed="right" width="180" align="center">
        <template slot-scope="scope">
          <el-button
            type="primary"
            size="mini"
            :disabled="!canRead(scope.row)"
            @click="showBatts(scope.row)"
            >电池组列表</el-button
          >
          <el-button
            type="danger"
            :disabled="!canUpdate(scope.row)"
            size="mini"
            @click="update(scope.row)"
            >升级</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    <!-- 升级弹窗 -->
    <el-dialog
      title="电池组列表"
      :visible.sync="updateVisible"
      top="0"
      :close-on-click-modal="false"
      class="dialog-center"
      width="700px"
      center
    >
      <el-upload
        v-if="!isUpdateing"
        class="upload-demo"
        ref="upload"
        action=""
        :multiple="false"
        :on-remove="fileRemove"
        :on-change="fileChange"
        :file-list="fileList"
        accept=".sm5"
        :auto-upload="false"
      >
        <el-button slot="trigger" size="small" type="primary"
          >选取文件</el-button
        >
      </el-upload>
      <template v-else>
        <div class="s-title">升级中</div>
        <el-progress
          :text-inside="true"
          :stroke-width="24"
          :percentage="updatePercent"
          :color="progressColor"
          :text-color="progressTextColor"
        ></el-progress>
      </template>
      <span slot="footer" class="dialog-footer">
        <el-button @click="updateVisible = false">关闭</el-button>
        <el-button
          v-if="!isUpdateing"
          type="primary"
          :disabled="!fileList.length"
          @click="upload"
          >上传并升级</el-button
        >
        <el-button v-else type="primary" @click="stopUpdate"
          >终止升级</el-button
        >
      </span>
    </el-dialog>
    <!-- 弹窗 -->
    <el-dialog
      title="电池组列表"
      :visible.sync="battListVisible"
      top="0"
      :close-on-click-modal="false"
      class="dialog-center"
      width="700px"
      center
    >
      <el-table
        ref="table"
        :data="tableBattsData"
        border
        max-height="300"
        style="width: 100%"
        tooltip-effect="light"
      >
        <el-table-column type="index" label="序号" width="80"></el-table-column>
        <el-table-column
          v-for="header in battsHeaders"
          :key="header.prop"
          :prop="header.prop"
          :label="header.label"
          :min-width="header.width"
          align="center"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column label="操作" fixed="right" width="260" align="center">
          <template slot-scope="scope">
            <el-button
              type="primary"
              size="mini"
              :disabled="
                isTransfering &&
                !!readingBattName &&
                readingBattName != scope.row.battName
              "
              @click="showFiles(scope.row)"
              >读取文件列表</el-button
            >
            <el-button
              type="primary"
              size="mini"
              @click="showPCFiles(scope.row)"
              >已导入文件列表</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <!-- 服务器文件列表 -->
    <el-dialog
      title="已导入文件列表"
      :visible.sync="pcFileListVisible"
      top="0"
      :close-on-click-modal="false"
      class="dialog-center"
      width="700px"
      center
    >
      <div class="btn-grp">
        <el-button
          type="primary"
          size="mini"
          @click="downloadFiles"
          :disabled="!multipleSelection.length"
          >下载选中项</el-button
        >
      </div>
      <el-table
        ref="table"
        :data="pcFileList"
        border
        max-height="300"
        style="width: 100%"
        @selection-change="handleSelectionChange"
        tooltip-effect="light"
      >
        <el-table-column type="selection" width="55"> </el-table-column>
        <el-table-column type="index" label="序号" width="80"></el-table-column>
        <el-table-column
          prop="fileName"
          label="文件名称"
          align="center"
          show-overflow-tooltip
        ></el-table-column>
        <el-table-column label="操作" fixed="right" width="160" align="center">
          <template slot-scope="scope">
            <el-button
              type="primary"
              size="mini"
              @click="downloadFile(scope.row.url)"
              >下载</el-button
            >
          </template>
        </el-table-column>
      </el-table>
    </el-dialog>
    <!-- 传输进度弹窗 -->
    <el-dialog
      title="电池组文件列表"
      :visible.sync="fileListVisible"
      top="0"
      :close-on-click-modal="false"
      class="dialog-center"
      width="700px"
      center
    >
      <file-process
        v-if="fileListVisible"
        :dev-id="currDevId"
        :transfer="isTransfering"
        :infos="transferFiles"
      ></file-process>
    </el-dialog>
  </div>
</template>
<style scoped lang="less">
.p-container {
  height: 100%;
  display: flex;
  flex-direction: column;
}
.p-title {
  font-size: 20px;
  font-weight: bold;
  color: #333;
  padding: 0.4em;
}
.btn-grp {
  padding-bottom: 10px;
}
.s-title {
  font-weight: bolder;
  padding-bottom: 10px;
}
</style>