reformat(update) and add badge to sidebar/update
This commit is contained in:
parent
981b0fbfed
commit
bc92656e20
|
@ -13,6 +13,7 @@ import {globalNotify} from "@/composables/notification";
|
||||||
import {isDevMode} from "@/composables/buildMode";
|
import {isDevMode} from "@/composables/buildMode";
|
||||||
import {useSystemModule} from "@/composables/useSystemModule";
|
import {useSystemModule} from "@/composables/useSystemModule";
|
||||||
import {useDataFlowModule} from "@/composables/useDataFlowModule";
|
import {useDataFlowModule} from "@/composables/useDataFlowModule";
|
||||||
|
import {useUpdateModule} from "@/composables/useUpdateModule";
|
||||||
|
|
||||||
const wsState = useWsStore();
|
const wsState = useWsStore();
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ onMounted(() => {
|
||||||
|
|
||||||
useSystemModule();
|
useSystemModule();
|
||||||
useDataFlowModule();
|
useDataFlowModule();
|
||||||
|
useUpdateModule();
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
import {registerModule} from "@/router/msgRouter";
|
||||||
|
import {type ApiJsonMsg, ControlEvent, type ControlMsg, ControlMsgType, WtModuleID} from "@/api";
|
||||||
|
import {useUpdateStore} from "@/stores/useUpdateStore";
|
||||||
|
import {
|
||||||
|
type IOTAFmInfo,
|
||||||
|
type IOTAProgress,
|
||||||
|
WtOTACmd,
|
||||||
|
WtOTAProgressStatus,
|
||||||
|
wt_ota_get_progress,
|
||||||
|
wt_ota_get_update_info,
|
||||||
|
} from "@/api/apiOTA";
|
||||||
|
import {isDevMode} from "@/composables/buildMode";
|
||||||
|
import {useSystemStore} from "@/stores/useSystemStore";
|
||||||
|
|
||||||
|
export function useUpdateModule() {
|
||||||
|
const updateStore = useUpdateStore()
|
||||||
|
const sysStore = useSystemStore()
|
||||||
|
|
||||||
|
function onClientCtrl(msg: ControlMsg) {
|
||||||
|
if (msg.type !== ControlMsgType.WS_EVENT) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.data === ControlEvent.CONNECTED) {
|
||||||
|
wt_ota_get_update_info();
|
||||||
|
wt_ota_get_progress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClientMsg(msg: ApiJsonMsg) {
|
||||||
|
switch (msg.cmd as WtOTACmd) {
|
||||||
|
case WtOTACmd.WT_OTA_GET_UPDATE_INFO: {
|
||||||
|
const info = msg as IOTAFmInfo;
|
||||||
|
Object.assign(updateStore.newFmInfo, info);
|
||||||
|
if (updateStore.newFmInfo.fm_ver !== sysStore.curFmInfo.ver && updateStore.newFmInfo.fm_ver[0] !== '-'
|
||||||
|
&& (updateStore.updateStatus === 'IDLE' || updateStore.updateStatus === 'FAILED')) {
|
||||||
|
updateStore.canUpdate = true;
|
||||||
|
} else {
|
||||||
|
updateStore.canUpdate = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WtOTACmd.WT_OTA_DO_UPDATE:
|
||||||
|
break;
|
||||||
|
case WtOTACmd.WT_OTA_GET_PROGRESS: {
|
||||||
|
const progress = msg as IOTAProgress;
|
||||||
|
updateStore.updateStatus = progress.status;
|
||||||
|
if (progress.total_size !== 0) {
|
||||||
|
updateStore.updateProgress = (progress.progress / progress.total_size) * 100;
|
||||||
|
} else {
|
||||||
|
updateStore.updateProgress = 0;
|
||||||
|
}
|
||||||
|
if (progress.status === WtOTAProgressStatus.IDLE) {
|
||||||
|
if (updateStore.newFmInfo.fm_ver !== sysStore.curFmInfo.ver && updateStore.newFmInfo.fm_ver[0] !== '-') {
|
||||||
|
updateStore.canUpdate = true;
|
||||||
|
} else {
|
||||||
|
updateStore.canUpdate = false;
|
||||||
|
}
|
||||||
|
updateStore.clearProgressInterval();
|
||||||
|
updateStore.progressBarStatus = '';
|
||||||
|
} else if (progress.status === WtOTAProgressStatus.FAILED) {
|
||||||
|
if (updateStore.newFmInfo.fm_ver !== sysStore.curFmInfo.ver && updateStore.newFmInfo.fm_ver[0] !== '-') {
|
||||||
|
updateStore.canUpdate = true;
|
||||||
|
} else {
|
||||||
|
updateStore.canUpdate = false;
|
||||||
|
}
|
||||||
|
updateStore.clearProgressInterval();
|
||||||
|
updateStore.progressBarStatus = 'exception';
|
||||||
|
} else if (progress.status === WtOTAProgressStatus.IN_PROGRESS) {
|
||||||
|
updateStore.setProgressInterval();
|
||||||
|
updateStore.progressBarStatus = '';
|
||||||
|
updateStore.canUpdate = false;
|
||||||
|
} else if (progress.status === WtOTAProgressStatus.OK) {
|
||||||
|
updateStore.clearProgressInterval();
|
||||||
|
updateStore.canUpdate = false;
|
||||||
|
updateStore.progressBarStatus = 'success';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDevMode()) {
|
||||||
|
console.log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerModule(WtModuleID.OTA, {
|
||||||
|
ctrlCallback: onClientCtrl,
|
||||||
|
serverJsonMsgCallback: onClientMsg,
|
||||||
|
serverBinMsgCallback: () => {
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import {wt_ota_get_progress} from "@/api/apiOTA";
|
||||||
|
|
||||||
|
export const useUpdateStore = defineStore('update', () => {
|
||||||
|
const canUpdate = ref(false);
|
||||||
|
const updateProgress = ref(0);
|
||||||
|
const updateStatus = ref('');
|
||||||
|
|
||||||
|
const progressBarStatus = ref('');
|
||||||
|
|
||||||
|
let progressIntervalID = -1;
|
||||||
|
|
||||||
|
const newFmInfo = ref({
|
||||||
|
fm_size: 0,
|
||||||
|
fm_ver: "-",
|
||||||
|
upd_date: "-",
|
||||||
|
upd_note: "-",
|
||||||
|
})
|
||||||
|
|
||||||
|
function setProgressInterval() {
|
||||||
|
if (progressIntervalID < 0) {
|
||||||
|
progressIntervalID = setInterval(() => {
|
||||||
|
wt_ota_get_progress();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearProgressInterval() {
|
||||||
|
if (progressIntervalID >= 0) {
|
||||||
|
clearInterval(progressIntervalID);
|
||||||
|
progressIntervalID = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
canUpdate,
|
||||||
|
updateProgress,
|
||||||
|
updateStatus,
|
||||||
|
progressBarStatus,
|
||||||
|
newFmInfo,
|
||||||
|
setProgressInterval,
|
||||||
|
clearProgressInterval,
|
||||||
|
}
|
||||||
|
})
|
|
@ -26,21 +26,21 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-button @click="doUpdate" type="primary" :disabled="!canUpdate">
|
<el-button @click="doUpdate" type="primary" :disabled="!updateStore.canUpdate">
|
||||||
更新
|
更新
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<el-descriptions-item label="固件版本">{{ newFmInfo.fm_ver }}</el-descriptions-item>
|
<el-descriptions-item label="固件版本">{{ updateStore.newFmInfo.fm_ver }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="更新日期">{{ newFmInfo.upd_date }}</el-descriptions-item>
|
<el-descriptions-item label="更新日期">{{ updateStore.newFmInfo.upd_date }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="固件大小">{{ newFmInfo.fm_size }}</el-descriptions-item>
|
<el-descriptions-item label="固件大小">{{ updateStore.newFmInfo.fm_size }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="更新进度">
|
<el-descriptions-item label="更新进度">
|
||||||
<el-alert v-if="updateStatus === 'OK'" title="更新已完成,重启后,刷新网页生效" type="success" show-icon :closable="false" />
|
<el-alert v-if="updateStore.updateStatus === 'OK'" title="更新已完成,重启后,刷新网页生效" type="success" show-icon :closable="false" />
|
||||||
<el-progress v-else :percentage="updateProgress" :format="format" :status="progressBarStatus"/>
|
<el-progress v-else :percentage="updateStore.updateProgress" :format="format" :status="updateStore.progressBarStatus"/>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="更新内容">
|
<el-descriptions-item label="更新内容">
|
||||||
<pre>{{ newFmInfo.upd_note }}</pre>
|
<pre>{{ updateStore.newFmInfo.upd_note }}</pre>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
|
@ -57,121 +57,25 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {onMounted, onUnmounted, ref} from "vue";
|
import {onMounted, onUnmounted, ref} from "vue";
|
||||||
import type {ApiJsonMsg, ControlMsg} from "@/api";
|
|
||||||
import {
|
import {
|
||||||
type IOTAFmInfo,
|
|
||||||
type IOTAProgress,
|
|
||||||
wt_ota_do_update, wt_ota_do_url_update,
|
wt_ota_do_update, wt_ota_do_url_update,
|
||||||
wt_ota_get_progress,
|
wt_ota_get_progress, wt_ota_get_update_info,
|
||||||
wt_ota_get_update_info,
|
|
||||||
WtOTACmd, WtOTAProgressStatus
|
|
||||||
} from "@/api/apiOTA";
|
} from "@/api/apiOTA";
|
||||||
import {ControlEvent, ControlMsgType, WtModuleID} from "@/api";
|
|
||||||
import {registerModule, unregisterModule} from "@/router/msgRouter";
|
|
||||||
import {useSystemStore} from "@/stores/useSystemStore";
|
import {useSystemStore} from "@/stores/useSystemStore";
|
||||||
import {wt_sys_reboot} from "@/api/apiSystem";
|
import {wt_sys_reboot} from "@/api/apiSystem";
|
||||||
import {isDevMode} from "@/composables/buildMode";
|
import {useUpdateStore} from "@/stores/useUpdateStore";
|
||||||
|
|
||||||
const sysStore = useSystemStore();
|
const sysStore = useSystemStore();
|
||||||
|
const updateStore = useUpdateStore();
|
||||||
const showHidden = ref(false)
|
const showHidden = ref(false)
|
||||||
|
|
||||||
const format = (percentage: number) => (percentage.toFixed(2) + '%')
|
|
||||||
|
|
||||||
const canUpdate = ref(false);
|
|
||||||
const updateProgress = ref(0);
|
|
||||||
const updateStatus = ref('');
|
|
||||||
|
|
||||||
const progressBarStatus = ref('');
|
|
||||||
|
|
||||||
const directLinkUpdate = ref("");
|
const directLinkUpdate = ref("");
|
||||||
|
|
||||||
let progressIntervalID = -1;
|
const format = (percentage: number) => (percentage.toFixed(2) + '%')
|
||||||
|
|
||||||
const newFmInfo = ref({
|
|
||||||
fm_size: 0,
|
|
||||||
fm_ver: "-",
|
|
||||||
upd_date: "-",
|
|
||||||
upd_note: "-",
|
|
||||||
})
|
|
||||||
const onClientMsg = (msg: ApiJsonMsg) => {
|
|
||||||
switch (msg.cmd as WtOTACmd) {
|
|
||||||
case WtOTACmd.WT_OTA_GET_UPDATE_INFO: {
|
|
||||||
const info = msg as IOTAFmInfo;
|
|
||||||
Object.assign(newFmInfo.value, info);
|
|
||||||
if (newFmInfo.value.fm_ver !== sysStore.curFmInfo.ver && newFmInfo.value.fm_ver[0] !== '-'
|
|
||||||
&& updateStatus.value === 'IDLE') {
|
|
||||||
canUpdate.value = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WtOTACmd.WT_OTA_DO_UPDATE:
|
|
||||||
break;
|
|
||||||
case WtOTACmd.WT_OTA_GET_PROGRESS: {
|
|
||||||
const progress = msg as IOTAProgress;
|
|
||||||
updateStatus.value = progress.status;
|
|
||||||
if (progress.total_size !== 0) {
|
|
||||||
updateProgress.value = (progress.progress / progress.total_size) * 100;
|
|
||||||
} else {
|
|
||||||
updateProgress.value = 0;
|
|
||||||
}
|
|
||||||
if (progress.status === WtOTAProgressStatus.IDLE) {
|
|
||||||
if (newFmInfo.value.fm_ver !== sysStore.curFmInfo.ver && newFmInfo.value.fm_ver[0] !== '-') {
|
|
||||||
canUpdate.value = true;
|
|
||||||
}
|
|
||||||
if (progressIntervalID >= 0) {
|
|
||||||
clearInterval(progressIntervalID);
|
|
||||||
progressIntervalID = -1;
|
|
||||||
}
|
|
||||||
progressBarStatus.value = '';
|
|
||||||
} else if (progress.status === WtOTAProgressStatus.FAILED) {
|
|
||||||
if (progressIntervalID >= 0) {
|
|
||||||
clearInterval(progressIntervalID);
|
|
||||||
progressIntervalID = -1;
|
|
||||||
}
|
|
||||||
progressBarStatus.value = 'exception';
|
|
||||||
} else if (progress.status === WtOTAProgressStatus.IN_PROGRESS) {
|
|
||||||
if (progressIntervalID < 0) {
|
|
||||||
progressIntervalID = setInterval(() => {
|
|
||||||
wt_ota_get_progress();
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
progressBarStatus.value = '';
|
|
||||||
canUpdate.value = false;
|
|
||||||
} else if (progress.status === WtOTAProgressStatus.OK) {
|
|
||||||
if (progressIntervalID >= 0) {
|
|
||||||
clearInterval(progressIntervalID);
|
|
||||||
progressIntervalID = -1;
|
|
||||||
}
|
|
||||||
canUpdate.value = false;
|
|
||||||
progressBarStatus.value = 'success';
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDevMode()) {
|
|
||||||
console.log(msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClientCtrl = (msg: ControlMsg) => {
|
|
||||||
if (msg.type !== ControlMsgType.WS_EVENT) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.data === ControlEvent.CONNECTED) {
|
|
||||||
wt_ota_get_update_info();
|
|
||||||
wt_ota_get_progress();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function doUpdate() {
|
function doUpdate() {
|
||||||
wt_ota_do_update();
|
wt_ota_do_update();
|
||||||
progressIntervalID = setInterval(() => {
|
updateStore.setProgressInterval();
|
||||||
wt_ota_get_progress();
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function doReboot() {
|
function doReboot() {
|
||||||
|
@ -182,34 +86,21 @@ function doDirectLinkUpdate() {
|
||||||
if (directLinkUpdate.value.length === 0) {
|
if (directLinkUpdate.value.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
progressIntervalID = setInterval(() => {
|
updateStore.setProgressInterval();
|
||||||
wt_ota_get_progress();
|
|
||||||
}, 1000);
|
|
||||||
wt_ota_do_url_update(directLinkUpdate.value);
|
wt_ota_do_url_update(directLinkUpdate.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
registerModule(WtModuleID.OTA, {
|
|
||||||
ctrlCallback: onClientCtrl,
|
|
||||||
serverJsonMsgCallback: onClientMsg,
|
|
||||||
serverBinMsgCallback: () => {
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
wt_ota_get_update_info();
|
wt_ota_get_update_info();
|
||||||
wt_ota_get_progress();
|
wt_ota_get_progress();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
unregisterModule(WtModuleID.OTA);
|
updateStore.clearProgressInterval();
|
||||||
clearInterval(progressIntervalID);
|
|
||||||
progressIntervalID = -1;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.description-style :deep(.el-descriptions__label) {
|
.description-style :deep(.el-descriptions__label) {
|
||||||
@apply w-32
|
@apply w-32
|
||||||
|
|
|
@ -68,7 +68,10 @@
|
||||||
<div class="flex flex-col justify-between m-4 mt-0">
|
<div class="flex flex-col justify-between m-4 mt-0">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(item, index) in sideBarItems" class="mb-1" :key="index">
|
<li v-for="(item, index) in sideBarItems" class="mb-1" :key="index">
|
||||||
<router-link @click="sideMenuOpen=false" :title="item.name" :to="item.href" :class="[sideMenuItemClass, item?.class]">{{ item.name }}</router-link>
|
<router-link @click="sideMenuOpen=false" :title="item.name" :to="item.href" :class="[sideMenuItemClass, item?.class]">
|
||||||
|
{{ item.name }}
|
||||||
|
<el-badge v-if="item?.badge?.value" is-dot></el-badge>
|
||||||
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -105,18 +108,20 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import InlineSvg from "@/components/InlineSvg.vue";
|
import InlineSvg from "@/components/InlineSvg.vue";
|
||||||
import {computed, ref} from "vue";
|
import {computed, type Ref, ref} from "vue";
|
||||||
import {useWsStore} from "@/stores/websocket";
|
import {useWsStore} from "@/stores/websocket";
|
||||||
import {translate} from "@/locales";
|
import {translate} from "@/locales";
|
||||||
import {ControlEvent} from "@/api";
|
import {ControlEvent} from "@/api";
|
||||||
import {useRoute} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import { useFullscreen } from '@vueuse/core'
|
import { useFullscreen } from '@vueuse/core'
|
||||||
|
import {useUpdateStore} from "@/stores/useUpdateStore";
|
||||||
|
|
||||||
const wsStore = useWsStore();
|
const wsStore = useWsStore();
|
||||||
|
const updateStore = useUpdateStore();
|
||||||
const {isFullscreen, toggle} = useFullscreen();
|
const {isFullscreen, toggle} = useFullscreen();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const sideMenuItemClass = "block p-4 text-sm font-semibold hover:bg-blue-50 hover:text-blue-600 rounded"
|
const sideMenuItemClass = "block p-4 text-sm font-semibold hover:bg-blue-50 hover:text-blue-600 rounded flex"
|
||||||
const sideMenuOpen = ref(false);
|
const sideMenuOpen = ref(false);
|
||||||
const stateMenuOpen = ref(false)
|
const stateMenuOpen = ref(false)
|
||||||
|
|
||||||
|
@ -144,6 +149,7 @@ type Item = {
|
||||||
name: string;
|
name: string;
|
||||||
href: string;
|
href: string;
|
||||||
class?: string;
|
class?: string;
|
||||||
|
badge?: Ref<boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const menuItems: Item[] = ([
|
const menuItems: Item[] = ([
|
||||||
|
@ -160,10 +166,6 @@ const menuItems: Item[] = ([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const sideBarItems: Item[] = ([
|
const sideBarItems: Item[] = ([
|
||||||
/* {
|
|
||||||
name: translate("page.home"),
|
|
||||||
href: "/",
|
|
||||||
}, */
|
|
||||||
{
|
{
|
||||||
name: translate("page.uart"),
|
name: translate("page.uart"),
|
||||||
href: "/uart",
|
href: "/uart",
|
||||||
|
@ -179,6 +181,7 @@ const sideBarItems: Item[] = ([
|
||||||
}, {
|
}, {
|
||||||
name: translate("page.update"),
|
name: translate("page.update"),
|
||||||
href: "/update",
|
href: "/update",
|
||||||
|
badge: computed(() => updateStore.canUpdate),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="shrink-0 min-h-6 flex gap-2 justify-between">
|
<div class="shrink-0 min-h-6 flex gap-2 justify-between overflow-auto">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<el-link @click="clearSendInput">
|
<el-link @click="clearSendInput">
|
||||||
<el-tag class="font-mono" size="small">
|
<el-tag class="font-mono" size="small">
|
||||||
|
|
Loading…
Reference in New Issue