增加ws逻辑,支持实时获取状态

main
RogerWork 10 months ago
parent 63676e4d2a
commit e8007b9fde
  1. 3
      package.json
  2. 161
      src/components/update/CinemaUpdate.vue
  3. 34
      src/components/update/ProcessIcon.vue
  4. 4
      src/main.js
  5. 6
      src/request/config.js
  6. 5
      yarn.lock

@ -19,7 +19,8 @@
"vite-plugin-commonjs": "^0.10.1", "vite-plugin-commonjs": "^0.10.1",
"vue": "^3.3.8", "vue": "^3.3.8",
"vue-router": "^4.0.13", "vue-router": "^4.0.13",
"vuex": "^4.0.2" "vuex": "^4.0.2",
"ws": "^8.16.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.5.0", "@vitejs/plugin-vue": "^4.5.0",

@ -1,9 +1,11 @@
<script setup> <script setup>
import {computed, ref, watch} from "vue"; import {onBeforeMount, ref, computed} from "vue";
import {onBeforeMount, onUnmounted, onMounted, onBeforeUnmount} from "vue"; import {useStore} from "vuex";
import {mapState, useStore} from "vuex";
import {get_git_ver, get_update_option, handle_update} from "@/apis/update.js" import {get_git_ver, get_update_option, handle_update} from "@/apis/update.js"
import Tips from "@/components/update/Tips.vue" import Tips from "@/components/update/Tips.vue"
import config from "@/request/config.js"
import ProcessIcon from "@/components/update/ProcessIcon.vue";
// store // store
const store = useStore() const store = useStore()
@ -16,6 +18,128 @@ const props = defineProps({
}, },
}) })
//
const updateStatus = ref({})
let showStatusTips = ref(false)
//
const handleShowStatusTips = () => {
if (store.state.update_status[props.ip]) {
showStatusTips.value = true
}
}
// websocket
let ws = null
let wsGetStatusInterval = null
const createWs = () => {
console.log(ws)
if (!ws) {
console.log("建立ws连接")
ws = new WebSocket(config.baseWS + "/ws/update/")
ws.onopen = wsOpen
ws.onmessage = wsMessage
ws.onerror = wsError
ws.onclose = wsClose
}
}
const wsOpen = () => {
wsSend(JSON.stringify({"msg": "ping"}))
}
const wsError = () => {
ws.close()
console.log("重新连接")
if (ws.readyState !== 3) {
ws = null
createWs()
}
}
const wsMessage = (event) => {
handleWsMessage(event.data)
}
const wsClose = () => {
console.log("关闭ws")
ws = null
}
const wsSend = (msg) => {
console.log(ws)
if (ws === null) {
createWs()
}
console.log(ws)
if (ws.readyState === 1) {
ws.send(msg)
}
}
const handleWsMessage = function (msg) {
if (msg === "你已经连接成功") {
return
}
if (JSON.parse(msg).hasOwnProperty('msg')) {
if (JSON.parse(msg)['msg'] === "ping") {
wsSend(JSON.stringify({"msg": "pong"}))
}
}
if (JSON.parse(msg).hasOwnProperty('status')) {
console.log(JSON.parse(msg))
updateStatus.value = JSON.parse(msg)['status']['result']
}
}
const wsGetStatus = function () {
if (ws === null || ws.readyState === 3) {
createWs()
wsGetStatusInterval = setInterval(() => {
wsSend(JSON.stringify({'ip': props.ip}))
}, 1000)
} else {
wsGetStatusInterval = setInterval(() => {
wsSend(JSON.stringify({'ip': props.ip}))
}, 1000)
}
}
const stopWsGetStatus = function () {
setTimeout(() => {
clearInterval(wsGetStatusInterval)
}, 1000)
}
const handleWsOpen = () => {
if (store.state.update_status[props.ip] === true) {
createWs()
wsGetStatus()
} else {
createWs()
}
}
// const handleWsClose = () => {
// if (store.state.update_status[props.ip] === false) {
// ws.send(JSON.stringify({"msg": "finish"}))
// wsClose()
// }
// }
const handleWsClear = (ip) => {
if (store.state.update_status[ip] === false) {
wsSend(JSON.stringify({"finish": ip}))
updateStatus.value = {}
}
}
// const clearUpdateStatus = () => {
// if ()
// updateStatus.value = {}
// }
// region git // region git
const git_ver = ref([]) const git_ver = ref([])
const selectedVersion = ref('') const selectedVersion = ref('')
@ -116,11 +240,17 @@ const handleOpened = () => {
addUpdateStatus() addUpdateStatus()
handleBtnName(props.ip) handleBtnName(props.ip)
handleDisable(props.ip) handleDisable(props.ip)
handleWsOpen()
handleShowStatusTips()
} }
// endregion // endregion
// region close // region close
const handleClose = () => { const handleClose = () => {
stopWsGetStatus()
handleWsClear(props.ip)
// handleWsClose()
showStatusTips.value = false
store.state.update_dialog_show = false store.state.update_dialog_show = false
} }
// endregion // endregion
@ -135,6 +265,7 @@ const handleRep = (ip) => {
changUpdateStatus(ip) // changUpdateStatus(ip) //
handleBtnName(props.ip) // handleBtnName(props.ip) //
handleDisable(props.ip) // handleDisable(props.ip) //
handleShowStatusTips()
console.log(store.state.update_status[ip]) console.log(store.state.update_status[ip])
} }
@ -143,8 +274,14 @@ const handleUpdate = async () => {
alert("请先选择影院和目标版本!") alert("请先选择影院和目标版本!")
return return
} }
updateStatus.value = {}
handleRep(props.ip) handleRep(props.ip)
// ws
wsGetStatus()
// store // store
let data = {} let data = {}
data = { data = {
@ -177,14 +314,16 @@ const handleUpdate = async () => {
handleRep(res_ip) handleRep(res_ip)
store.commit("clear_update_status", res_ip) // store.commit("clear_update_status", res_ip) //
} }
stopWsGetStatus() // ws
}).catch(err => { }).catch(err => {
const ip = err.config.params.ip const ip = err.config.params.ip
handleRep(ip) handleRep(ip)
store.commit("clear_update_status", ip) // store.commit("clear_update_status", ip) //
stopWsGetStatus() // ws
alert(ip + " 升级失败,请重试!") alert(ip + " 升级失败,请重试!")
}) })
} }
// endregion // endregion
</script> </script>
@ -204,6 +343,8 @@ const handleUpdate = async () => {
<el-checkbox-group v-model="checkedCmd" :disabled="disableAll"> <el-checkbox-group v-model="checkedCmd" :disabled="disableAll">
<el-divider content-position="left"> <el-divider content-position="left">
<span class="cmd_label">执行脚本</span> <span class="cmd_label">执行脚本</span>
<ProcessIcon v-if="showStatusTips" class="process_icon"
:exec-status="updateStatus.setup"/>
</el-divider> </el-divider>
<el-checkbox v-for="cmd in updateCmd.setup" :label="cmd.id" :key="cmd.id" <el-checkbox v-for="cmd in updateCmd.setup" :label="cmd.id" :key="cmd.id"
:checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }} :checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }}
@ -212,6 +353,8 @@ const handleUpdate = async () => {
<el-divider content-position="left"> <el-divider content-position="left">
<span class="cmd_label">数据库</span> <span class="cmd_label">数据库</span>
<ProcessIcon v-if="showStatusTips" class="process_icon"
:exec-status="updateStatus.sql"/>
</el-divider> </el-divider>
<el-checkbox v-for="cmd in updateCmd.sql" :label="cmd.id" :key="cmd.id" <el-checkbox v-for="cmd in updateCmd.sql" :label="cmd.id" :key="cmd.id"
:checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }} :checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }}
@ -219,6 +362,8 @@ const handleUpdate = async () => {
</el-checkbox> </el-checkbox>
<el-divider content-position="left"> <el-divider content-position="left">
<span class="cmd_label">执行升级</span> <span class="cmd_label">执行升级</span>
<ProcessIcon v-if="showStatusTips" class="process_icon"
:exec-status="updateStatus.teardown"/>
</el-divider> </el-divider>
<el-checkbox v-for="cmd in updateCmd.teardown" :label="cmd.id" :key="cmd.id" <el-checkbox v-for="cmd in updateCmd.teardown" :label="cmd.id" :key="cmd.id"
:checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }} :checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }}
@ -226,6 +371,8 @@ const handleUpdate = async () => {
</el-checkbox> </el-checkbox>
<el-divider content-position="left"> <el-divider content-position="left">
<span class="cmd_label">修改设置</span> <span class="cmd_label">修改设置</span>
<ProcessIcon v-if="showStatusTips" class="process_icon"
:exec-status="updateStatus.config"/>
</el-divider> </el-divider>
<el-checkbox v-for="cmd in updateCmd.config" :label="cmd.id" :key="cmd.id" <el-checkbox v-for="cmd in updateCmd.config" :label="cmd.id" :key="cmd.id"
:checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }} :checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }}
@ -233,6 +380,8 @@ const handleUpdate = async () => {
</el-checkbox> </el-checkbox>
<el-divider content-position="left"> <el-divider content-position="left">
<span class="cmd_label">客户端</span> <span class="cmd_label">客户端</span>
<ProcessIcon v-if="showStatusTips" class="process_icon"
:exec-status="updateStatus.client"/>
</el-divider> </el-divider>
<el-checkbox v-for="cmd in updateCmd.client" :label="cmd.id" :key="cmd.id" <el-checkbox v-for="cmd in updateCmd.client" :label="cmd.id" :key="cmd.id"
:checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }} :checked="cmd.is_checked" :disabled="cmd.is_force">{{ cmd.desc }}
@ -272,4 +421,8 @@ const handleUpdate = async () => {
margin-right: 100px; margin-right: 100px;
} }
:deep(.el-divider--horizontal .el-icon) {
margin-left: 10px;
}
</style> </style>

@ -0,0 +1,34 @@
<script setup>
import {Loading, SuccessFilled, CircleCloseFilled, InfoFilled} from "@element-plus/icons-vue";
const props = defineProps({
execStatus: {
type: Object,
default: {result: "", msg: ""}
}
})
</script>
<!-- :content="props.execStatus.msg"-->
<template>
<el-popover
placement="top-start"
title='执行结果'
width="400"
trigger="hover"
>
<div class="content" v-html="props.execStatus.msg">
</div>
<template #reference>
<el-icon :size="18" :class="execStatus['result']=== 'running'? 'is-loading' : ''">
<Loading v-if="execStatus['result']=== 'running'" v-loading="true"/>
<SuccessFilled v-if="execStatus['result'] === 'success'" color="green"/>
<CircleCloseFilled v-if="execStatus['result'] === 'fail'" color="red"/>
</el-icon>
</template>
</el-popover>
</template>
<style scoped>
</style>

@ -1,4 +1,4 @@
import { createApp } from 'vue' import {createApp} from 'vue'
import './style.css' import './style.css'
import App from './App.vue' import App from './App.vue'
import ElementPlus from 'element-plus' import ElementPlus from 'element-plus'
@ -9,7 +9,7 @@ import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
const app = createApp(App) const app = createApp(App)
for (const name in ELIcons){ for (const name in ELIcons) {
app.component(name, ELIcons[name]); app.component(name, ELIcons[name]);
} }

@ -1,7 +1,9 @@
export default { export default {
// method: 'get', // method: 'get',
// baseURL: 'http://172.16.1.63:8000', baseURL: 'http://172.16.1.63:8000',
baseURL: 'http://127.0.0.1:8000', // baseURL: 'http://127.0.0.1:8000',
baseWS: 'ws://172.16.1.63:8000',
// baseWS: 'ws://127.0.0.1:8000',
headers: { headers: {
'Content-Type': 'application/json;charset=UTF-8', 'Content-Type': 'application/json;charset=UTF-8',
'Authorization': 'token 4e63b8854974c1fdac9deb891fd74dc145b53f85' 'Authorization': 'token 4e63b8854974c1fdac9deb891fd74dc145b53f85'

@ -1298,3 +1298,8 @@ webpack-virtual-modules@^0.6.0:
version "0.6.1" version "0.6.1"
resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz" resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz"
integrity sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg== integrity sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==
ws@^8.16.0:
version "8.16.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4"
integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==

Loading…
Cancel
Save