<script>
|
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",
|
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 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>
|