| | |
| | | <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> |