445 lines
9.7 KiB
Vue
445 lines
9.7 KiB
Vue
<template>
|
||
<h1 class="text-center text-3xl title">ESP32程序批量烧录</h1>
|
||
<div class="home">
|
||
<div class="operatebox">
|
||
<div class="flexbox">
|
||
<div class="p-4 nop">
|
||
<div class="textport">待烧录串口</div>
|
||
<textarea disabled class="commsg resize-none border-2" :value="ports">
|
||
</textarea>
|
||
</div>
|
||
<div class="p-4 nop">
|
||
<div class="textport">文 件 路 径</div>
|
||
<button
|
||
class="seleanni px-4 border-2 rounded text-white"
|
||
:class="loading ? 'bg-gray-500' : 'bg-blue-500'"
|
||
:disabled="loading"
|
||
@click="selectFile"
|
||
>
|
||
选 择
|
||
</button>
|
||
</div>
|
||
<div class="p-4 truncate nop">
|
||
<input
|
||
disabled
|
||
type="text"
|
||
class="filebox border-2"
|
||
:value="selectedFilePath"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div class="col-span-2 nopd">
|
||
<button
|
||
class="anni px-4 border-2 rounded text-white"
|
||
:class="loading ? 'bg-gray-500' : 'bg-blue-500'"
|
||
:disabled="loading"
|
||
@click="burn_start"
|
||
>
|
||
<svg
|
||
v-if="loadings"
|
||
class="svgbox animate-spin h-5 w-5"
|
||
xmlns="http://www.w3.org/2000/svg"
|
||
fill="none"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<circle
|
||
class="opacity-25"
|
||
cx="12"
|
||
cy="12"
|
||
r="10"
|
||
stroke="currentColor"
|
||
stroke-width="4"
|
||
></circle>
|
||
<path
|
||
class="opacity-75"
|
||
fill="currentColor"
|
||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||
></path>
|
||
</svg>
|
||
<div class="fontset" v-else>烧 录</div>
|
||
</button>
|
||
</div>
|
||
<div class="tips">
|
||
<h6 class="tipstitle">操 作 方 法</h6>
|
||
<textarea disabled class="tipsmsg resize-none border-2">
|
||
1. 待烧录或烧录失败的串口会自动显示。
|
||
2. 点击按钮选择需要烧录的程序。
|
||
3. 点击烧录按钮,等待烧录完成。
|
||
|
||
**右侧为烧录输出**
|
||
#若烧录失败可以通过烧录输出判断错误原因#
|
||
</textarea
|
||
>
|
||
</div>
|
||
</div>
|
||
<div class="msgbox">
|
||
<textarea
|
||
ref="container"
|
||
disabled
|
||
class="textbox resize-none border-2 w-full"
|
||
:value="msg"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { ref, inject, watch, onMounted } from "vue";
|
||
|
||
function alert(data) {
|
||
loading.value = true;
|
||
var a = document.createElement("div"),
|
||
p = document.createElement("p"),
|
||
btn = document.createElement("div"),
|
||
textNode = document.createTextNode(data ? data : ""),
|
||
btnText = document.createTextNode("确定");
|
||
// 控制样式
|
||
css(a, {
|
||
"padding-top": "60px",
|
||
position: "fixed",
|
||
left: "0",
|
||
right: "0",
|
||
top: "40%",
|
||
width: "300px",
|
||
height: "180px",
|
||
margin: "0 auto",
|
||
"background-color": "#fff",
|
||
border: "2px solid #ccc",
|
||
"font-size": "100%",
|
||
"text-align": "center",
|
||
"z-index": "3",
|
||
});
|
||
css(btn, {
|
||
margin: "10%",
|
||
"margin-bottom": "5%",
|
||
width: "80%",
|
||
position: "absolute",
|
||
bottom: "0",
|
||
background: "#2222ff",
|
||
opacity: "0.8",
|
||
"border-radius": "24px",
|
||
color: "#fff",
|
||
});
|
||
// 内部结构套入
|
||
p.appendChild(textNode);
|
||
btn.appendChild(btnText);
|
||
a.appendChild(p);
|
||
a.appendChild(btn);
|
||
// 整体显示到页面内
|
||
document.getElementsByTagName("body")[0].appendChild(a);
|
||
|
||
// 确定绑定点击事件删除标签
|
||
btn.onclick = function () {
|
||
a.parentNode?.removeChild(a);
|
||
loading.value = false;
|
||
};
|
||
}
|
||
function css(targetObj, cssObj) {
|
||
var str = targetObj.getAttribute("style") ? targetObj.getAttribute("style") : "";
|
||
for (var i in cssObj) {
|
||
str += i + ":" + cssObj[i] + ";";
|
||
}
|
||
targetObj.style.cssText = str;
|
||
}
|
||
window.alert = alert;
|
||
|
||
const IPCRENDERER_API_SUPPORTED = inject("IPCRENDERER_API_SUPPORTED", false);
|
||
|
||
const loading = ref(false);
|
||
const loadings = ref(false);
|
||
const msg = ref("烧录结果输出:\n");
|
||
const container = ref(null);
|
||
const selectedPort = ref("");
|
||
const ports = ref([]);
|
||
const errsum = ref(0);
|
||
const sucsum = ref(0);
|
||
const succom = ref([]);
|
||
const failedcom = ref([]);
|
||
const comlength = ref(0);
|
||
|
||
const setPorts = (value: Object[]) => {
|
||
let compath = [];
|
||
value.forEach((element) => {
|
||
compath.push(element.path);
|
||
});
|
||
|
||
if (loading.value == false) {
|
||
ports.value = compath;
|
||
}
|
||
comlength.value = ports.value.length;
|
||
};
|
||
|
||
const selectedFilePath = ref("");
|
||
|
||
const setSelectedFilePath = (value: string) => (selectedFilePath.value = value);
|
||
|
||
const selectFile = () => {
|
||
if (!IPCRENDERER_API_SUPPORTED) {
|
||
alert("The ipcRenderer API is not supported.");
|
||
return;
|
||
}
|
||
|
||
ipcRenderer.send("SELECT_FILE");
|
||
};
|
||
|
||
const alert_msg = (value: string) => {
|
||
if (!value) {
|
||
return;
|
||
}
|
||
|
||
alert(value);
|
||
};
|
||
|
||
const errlog = (value: number) => {
|
||
if (!value) {
|
||
return;
|
||
}
|
||
|
||
errsum.value = value;
|
||
};
|
||
|
||
const suclog = (value: number) => {
|
||
if (!value) {
|
||
return;
|
||
}
|
||
|
||
sucsum.value = value;
|
||
};
|
||
|
||
const append_msg = (value: string) => {
|
||
if (!value) {
|
||
return;
|
||
}
|
||
|
||
msg.value += value + "\n";
|
||
};
|
||
|
||
const suc_result = (value: Array<string>) => {
|
||
if (!value) {
|
||
return;
|
||
}
|
||
|
||
succom.value.push(value);
|
||
};
|
||
|
||
const failed_result = (value: Array<string>) => {
|
||
if (!value) {
|
||
return;
|
||
}
|
||
|
||
failedcom.value.push(value);
|
||
};
|
||
|
||
const scroll = () => {
|
||
setTimeout(() => (container.value.scrollTop = container.value.scrollHeight), 5);
|
||
};
|
||
|
||
const burn = () => {
|
||
selectedPort.value = ports.value.shift();
|
||
const param = {
|
||
selectedPort: selectedPort.value,
|
||
selectedFilePath: selectedFilePath.value,
|
||
errsum: errsum.value,
|
||
sucsum: sucsum.value,
|
||
};
|
||
ipcRenderer.send("BURN", param);
|
||
loading.value = true;
|
||
loadings.value = true;
|
||
};
|
||
|
||
const burn_start = () => {
|
||
if (ports.value.length == 0) {
|
||
alert("未发现串口");
|
||
return;
|
||
}
|
||
if (!selectedFilePath.value) {
|
||
alert("请选择程序文件");
|
||
return;
|
||
}
|
||
succom.value = [];
|
||
failedcom.value = [];
|
||
errsum.value = 0;
|
||
sucsum.value = 0;
|
||
msg.value = "烧录结果输出:\n";
|
||
burn();
|
||
};
|
||
|
||
watch(msg, () => {
|
||
scroll();
|
||
});
|
||
|
||
onMounted(() => {
|
||
if (!IPCRENDERER_API_SUPPORTED) {
|
||
alert("The ipcRenderer API is not supported.");
|
||
return;
|
||
}
|
||
|
||
ipcRenderer.receive("SELECT_FILE", setSelectedFilePath);
|
||
ipcRenderer.receive("LIST_PORTS", setPorts);
|
||
ipcRenderer.receive("BURN_END", () => {
|
||
if (ports.value.length == 0) {
|
||
loadings.value = false;
|
||
loading.value = false;
|
||
if (errsum.value == 0) {
|
||
alert("串口已全部烧录成功!");
|
||
return;
|
||
} else if (sucsum.value == 0) {
|
||
alert("串口已全部烧录失败!");
|
||
ports.value = failedcom.value;
|
||
return;
|
||
} else {
|
||
alert(`烧录结束,成功:${sucsum.value}个,失败:${errsum.value}个`);
|
||
ports.value = failedcom.value;
|
||
return;
|
||
}
|
||
}
|
||
burn();
|
||
});
|
||
ipcRenderer.receive("ALERT_MSG", alert_msg);
|
||
ipcRenderer.receive("ERR_SUM", errlog);
|
||
ipcRenderer.receive("SUC_SUM", suclog);
|
||
ipcRenderer.receive("APPEND_MSG", append_msg);
|
||
ipcRenderer.receive("FAILED_RESULT", failed_result);
|
||
ipcRenderer.receive("SUC_RESULT", suc_result);
|
||
// ipcRenderer.receive('CLEAN_MSG' , () => msg.value = '')
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.title {
|
||
min-width: 220px;
|
||
height: 14vh;
|
||
line-height: 14vh;
|
||
}
|
||
.textport {
|
||
width: 45%;
|
||
font-size: clamp(0.8rem, 0.5rem + 1vw, 2rem);
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.anni {
|
||
width: 40%;
|
||
min-width: 60px;
|
||
height: 80%;
|
||
margin-top: 1%;
|
||
border-radius: 48px;
|
||
position: relative;
|
||
z-index: 2;
|
||
}
|
||
.fontset {
|
||
margin: auto;
|
||
width: 100%;
|
||
text-align: center;
|
||
display: flex;
|
||
font-size: clamp(0.8rem, 0.5rem + 1vw, 2rem);
|
||
justify-content: space-around;
|
||
align-items: center;
|
||
}
|
||
.seleanni {
|
||
width: 45%;
|
||
border-radius: 24px;
|
||
height: 100%;
|
||
font-size: clamp(0.8rem, 0.5rem + 1vw, 2rem);
|
||
}
|
||
.selebox {
|
||
width: 45%;
|
||
border-radius: 24px;
|
||
height: 100%;
|
||
box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.3),
|
||
inset -4px -4px 4px rgba(255, 255, 255, 0.7);
|
||
}
|
||
.filebox {
|
||
min-width: 90px;
|
||
width: 90%;
|
||
background-color: #fff;
|
||
height: 100%;
|
||
border-radius: 24px;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
box-shadow: inset 4px 4px 4px rgba(0, 0, 0, 0.3),
|
||
inset -4px -4px 4px rgba(255, 255, 255, 0.7);
|
||
}
|
||
.flexbox {
|
||
margin: 0;
|
||
width: 100%;
|
||
height: 40%;
|
||
background-color: #eeffff;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-content: space-evenly;
|
||
flex-wrap: wrap;
|
||
overflow: hidden;
|
||
}
|
||
.svgbox {
|
||
margin: auto;
|
||
}
|
||
.nop {
|
||
padding: 0;
|
||
padding-left: 10%;
|
||
flex: 1;
|
||
min-width: 100%;
|
||
max-width: 200%;
|
||
height: 16%;
|
||
min-height: 28px;
|
||
overflow: hidden;
|
||
display: flex;
|
||
justify-content: start;
|
||
}
|
||
.nopd {
|
||
padding: 0;
|
||
flex: 1;
|
||
display: flex;
|
||
width: 100%;
|
||
height: 10%;
|
||
justify-content: center;
|
||
align-content: center;
|
||
}
|
||
.msgbox {
|
||
padding: 0;
|
||
width: 48%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
.textbox {
|
||
height: 100%;
|
||
background-color: #ffe;
|
||
}
|
||
.home {
|
||
height: 80vh;
|
||
display: flex;
|
||
justify-content: center;
|
||
margin: auto;
|
||
}
|
||
.operatebox {
|
||
margin: 0;
|
||
width: 48%;
|
||
margin-right: 1%;
|
||
height: 100%;
|
||
background-color: #ccffff;
|
||
}
|
||
.tips {
|
||
width: 100%;
|
||
height: 50%;
|
||
background-color: #99ffff;
|
||
padding-left: 9%;
|
||
}
|
||
.tipstitle {
|
||
width: 90%;
|
||
min-width: 120px;
|
||
min-height: 10%;
|
||
text-align: center;
|
||
padding-top: 1.5%;
|
||
font-size: clamp(0.6rem, 0.5rem + 1vw, 1.2rem);
|
||
}
|
||
.tipsmsg {
|
||
width: 90%;
|
||
height: 80%;
|
||
background-color: #efe;
|
||
}
|
||
.commsg {
|
||
width: 45%;
|
||
height: 100%;
|
||
background-color: #efe;
|
||
}
|
||
</style>
|