optimize the vue component communication, replace event listening with share data

This commit is contained in:
RockYang
2024-09-30 14:20:59 +08:00
parent 1a1734abf0
commit 8923e938d2
23 changed files with 473 additions and 480 deletions

View File

@@ -81,11 +81,9 @@
description="暂无记录"
/>
<van-grid :gutter="10" :column-num="3" v-else>
<van-grid-item v-for="item in runningJobs">
<van-grid-item v-for="item in runningJobs" :key="item.id">
<div v-if="item.progress > 0">
<van-image :src="item['img_url']">
<template v-slot:error>加载失败</template>
</van-image>
<van-image src="/images/img-holder.png"></van-image>
<div class="progress">
<van-circle
v-model:current-rate="item.progress"
@@ -124,8 +122,15 @@
@load="onLoad"
>
<van-grid :gutter="10" :column-num="2">
<van-grid-item v-for="item in finishedJobs">
<div class="job-item">
<van-grid-item v-for="item in finishedJobs" :key="item.id">
<div class="failed" v-if="item.progress === 101">
<div class="title">任务失败</div>
<div class="opt">
<van-button size="small" @click="showErrMsg(item)">详情</van-button>
<van-button type="danger" @click="removeImage($event,item)" size="small">删除</van-button>
</div>
</div>
<div class="job-item" v-else>
<van-image
:src="item['img_url']"
:class="item['can_opt'] ? '' : 'upscale'"
@@ -165,7 +170,7 @@ import {onMounted, onUnmounted, ref} from "vue"
import {Delete} from "@element-plus/icons-vue";
import {httpGet, httpPost} from "@/utils/http";
import Clipboard from "clipboard";
import {checkSession, getSystemInfo} from "@/store/cache";
import {checkSession, getClientId, getSystemInfo} from "@/store/cache";
import {useRouter} from "vue-router";
import {getSessionId} from "@/store/session";
import {
@@ -178,10 +183,10 @@ import {
showToast
} from "vant";
import {showLoginDialog} from "@/utils/libs";
import {useSharedStore} from "@/store/sharedata";
const listBoxHeight = ref(window.innerHeight - 40)
const mjBoxHeight = ref(window.innerHeight - 150)
const item = ref({})
const isLogin = ref(false)
window.onresize = () => {
@@ -203,6 +208,7 @@ const styles = [
{text: "自然", value: "natural"}
]
const params = ref({
client_id: getClientId(),
quality: qualities[0].value,
size: sizes[0].value,
style: styles[0].value,
@@ -223,56 +229,8 @@ const router = useRouter()
const power = ref(0)
const dallPower = ref(0) // 画一张 DALL 图片消耗算力
const socket = ref(null)
const userId = ref(0)
const heartbeatHandle = ref(null)
const connect = () => {
let host = process.env.VUE_APP_WS_HOST
if (host === '') {
if (location.protocol === 'https:') {
host = 'wss://' + location.host;
} else {
host = 'ws://' + location.host;
}
}
// 心跳函数
const sendHeartbeat = () => {
clearTimeout(heartbeatHandle.value)
new Promise((resolve, reject) => {
if (socket.value !== null) {
socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
}
resolve("success")
}).then(() => {
heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000)
});
}
const _socket = new WebSocket(host + `/api/dall/client?user_id=${userId.value}`);
_socket.addEventListener('open', () => {
socket.value = _socket;
// 发送心跳消息
sendHeartbeat()
});
_socket.addEventListener('message', event => {
if (event.data instanceof Blob) {
fetchRunningJobs()
finished.value = false
page.value = 1
fetchFinishJobs(page.value)
}
});
_socket.addEventListener('close', () => {
if (socket.value !== null) {
connect()
}
});
}
const store = useSharedStore()
const clipboard = ref(null)
const prompt = ref('')
onMounted(() => {
@@ -290,25 +248,32 @@ onMounted(() => {
}).catch(e => {
showNotify({type: "danger", message: "获取系统配置失败:" + e.message})
})
store.addMessageHandler("dall", (data) => {
if (data.channel !== "dall" || data.clientId !== getClientId()) {
return
}
if (data.body === "FINISH" || data.body === "FAIL") {
page.value = 1
fetchFinishJobs(1)
}
fetchRunningJobs()
})
})
onUnmounted(() => {
clipboard.value.destroy()
if (socket.value !== null) {
socket.value.close()
socket.value = null
}
store.removeMessageHandler("dall")
})
const initData = () => {
checkSession().then(user => {
power.value = user['power']
userId.value = user.id
isLogin.value = true
fetchRunningJobs()
fetchFinishJobs(1)
connect()
}).catch(() => {
loading.value = false
});
@@ -317,20 +282,7 @@ const initData = () => {
const fetchRunningJobs = () => {
// 获取运行中的任务
httpGet(`/api/dall/jobs?finish=0`).then(res => {
const jobs = res.data.items
const _jobs = []
for (let i = 0; i < jobs.length; i++) {
if (jobs[i].progress === -1) {
showNotify({
message: `任务ID${jobs[i]['task_id']} 原因:${jobs[i]['err_msg']}`,
type: 'danger',
})
power.value += dallPower.value
continue
}
_jobs.push(jobs[i])
}
runningJobs.value = _jobs
runningJobs.value = res.data.items
}).catch(e => {
showNotify({type: "danger", message: "获取任务失败:" + e.message})
})
@@ -349,10 +301,17 @@ const fetchFinishJobs = (page) => {
if (jobs.length < pageSize.value) {
finished.value = true
}
const _jobs = []
for (let i = 0; i < jobs.length; i++) {
if (jobs[i].progress === -1) {
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/600/q/75'
}
_jobs.push(jobs[i])
}
if (page === 1) {
finishedJobs.value = jobs
finishedJobs.value = _jobs
} else {
finishedJobs.value = finishedJobs.value.concat(jobs)
finishedJobs.value = finishedJobs.value.concat(_jobs)
}
loading.value = false
}).catch(e => {
@@ -385,6 +344,7 @@ const generate = () => {
httpPost("/api/dall/image", params.value).then(() => {
showSuccessToast("绘画任务推送成功,请耐心等待任务执行...")
power.value -= dallPower.value
fetchRunningJobs()
}).catch(e => {
showFailToast("任务推送失败:" + e.message)
})
@@ -403,6 +363,15 @@ const showPrompt = (item) => {
});
}
const showErrMsg = (item) => {
showDialog({
title: '错误详情',
message: item['err_msg'],
}).then(() => {
// on close
});
}
const removeImage = (event, item) => {
event.stopPropagation()
showConfirmDialog({
@@ -412,6 +381,7 @@ const removeImage = (event, item) => {
}).then(() => {
httpGet("/api/dall/remove", {id: item.id, user_id: item.user_id}).then(() => {
showSuccessToast("任务删除成功")
fetchFinishJobs(1)
}).catch(e => {
showFailToast("任务删除失败:" + e.message)
})
@@ -458,14 +428,6 @@ const sizeConfirm =(item) => {
showSizePicker.value =false
}
const showInfo = (message) => {
showDialog({
title: "参数说明",
message: message,
}).then(() => {
// on close
});
}
</script>
<style lang="stylus">

View File

@@ -180,11 +180,9 @@
description="暂无记录"
/>
<van-grid :gutter="10" :column-num="3" v-else>
<van-grid-item v-for="item in runningJobs">
<van-grid-item v-for="item in runningJobs" :key="item.id">
<div v-if="item.progress > 0">
<van-image :src="item['img_url']">
<template v-slot:error>加载失败</template>
</van-image>
<van-image src="/images/img-holder.png"></van-image>
<div class="progress">
<van-circle
v-model:current-rate="item.progress"
@@ -223,8 +221,15 @@
@load="onLoad"
>
<van-grid :gutter="10" :column-num="2">
<van-grid-item v-for="item in finishedJobs">
<div class="job-item">
<van-grid-item v-for="item in finishedJobs" :key="item.id">
<div class="failed" v-if="item.progress === 101">
<div class="title">任务失败</div>
<div class="opt">
<van-button size="small" @click="showErrMsg(item)">详情</van-button>
<van-button type="danger" @click="removeImage(item)" size="small">删除</van-button>
</div>
</div>
<div class="job-item" v-else>
<van-image
:src="item['thumb_url']"
:class="item['can_opt'] ? '' : 'upscale'"
@@ -234,6 +239,10 @@
<template v-slot:loading>
<van-loading type="spinner" size="20"/>
</template>
<template v-slot:error>
<span style="margin-bottom: 20px">正在下载图片</span>
<van-loading type="circular" color="#1989fa" size="40"/>
</template>
</van-image>
<div class="opt" v-if="item['can_opt']">
@@ -276,15 +285,16 @@
<script setup>
import {nextTick, onMounted, onUnmounted, ref} from "vue";
import {showConfirmDialog, showFailToast, showImagePreview, showNotify, showSuccessToast, showToast} from "vant";
import {showConfirmDialog, showFailToast, showImagePreview, showNotify, showSuccessToast, showToast,showDialog } from "vant";
import {httpGet, httpPost} from "@/utils/http";
import Compressor from "compressorjs";
import {getSessionId} from "@/store/session";
import {checkSession, getSystemInfo} from "@/store/cache";
import {checkSession, getClientId, getSystemInfo} from "@/store/cache";
import {useRouter} from "vue-router";
import {Delete} from "@element-plus/icons-vue";
import {showLoginDialog} from "@/utils/libs";
import Clipboard from "clipboard";
import {useSharedStore} from "@/store/sharedata";
const activeColspan = ref([""])
@@ -306,6 +316,7 @@ const models = [
]
const imgList = ref([])
const params = ref({
client_id: getClientId(),
task_type: "image",
rate: rates[0].value,
model: models[0].value,
@@ -327,11 +338,11 @@ const userId = ref(0)
const router = useRouter()
const runningJobs = ref([])
const finishedJobs = ref([])
const socket = ref(null)
const power = ref(0)
const activeName = ref("txt2img")
const isLogin = ref(false)
const prompt = ref('')
const store = useSharedStore()
const clipboard = ref(null)
onMounted(() => {
@@ -349,19 +360,26 @@ onMounted(() => {
isLogin.value = true
fetchRunningJobs()
fetchFinishJobs(1)
connect()
}).catch(() => {
// router.push('/login')
});
store.addMessageHandler("mj", (data) => {
if (data.channel !== "mj" || data.clientId !== getClientId()) {
return
}
if (data.body === "FINISH" || data.body === "FAIL") {
page.value = 1
fetchFinishJobs(1)
}
fetchRunningJobs()
})
})
onUnmounted(() => {
clipboard.value.destroy()
if (socket.value !== null) {
socket.value.close()
socket.value = null
}
store.removeMessageHandler("mj")
})
const mjPower = ref(1)
@@ -373,60 +391,6 @@ getSystemInfo().then(res => {
showNotify({type: "danger", message: "获取系统配置失败:" + e.message})
})
const heartbeatHandle = ref(null)
const connect = () => {
let host = process.env.VUE_APP_WS_HOST
if (host === '') {
if (location.protocol === 'https:') {
host = 'wss://' + location.host;
} else {
host = 'ws://' + location.host;
}
}
// 心跳函数
const sendHeartbeat = () => {
clearTimeout(heartbeatHandle.value)
new Promise((resolve, reject) => {
if (socket.value !== null) {
socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
}
resolve("success")
}).then(() => {
heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000)
});
}
const _socket = new WebSocket(host + `/api/mj/client?user_id=${userId.value}`);
_socket.addEventListener('open', () => {
socket.value = _socket;
// 发送心跳消息
sendHeartbeat()
});
_socket.addEventListener('message', event => {
if (event.data instanceof Blob) {
const reader = new FileReader();
reader.readAsText(event.data, "UTF-8")
reader.onload = () => {
const message = String(reader.result)
if (message === "FINISH" || message === "FAIL") {
page.value = 1
fetchFinishJobs(1)
}
fetchRunningJobs()
}
}
});
_socket.addEventListener('close', () => {
if (socket.value !== null) {
connect()
}
});
}
// 获取运行中的任务
const fetchRunningJobs = (userId) => {
httpGet(`/api/mj/jobs?finish=0&user_id=${userId}`).then(res => {
@@ -464,27 +428,10 @@ const fetchFinishJobs = (page) => {
httpGet(`/api/mj/jobs?finish=1&page=${page}&page_size=${pageSize.value}`).then(res => {
const jobs = res.data.items
for (let i = 0; i < jobs.length; i++) {
if (jobs[i].progress === 101) {
showNotify({
message: `任务ID${jobs[i]['task_id']} 原因:${jobs[i]['err_msg']}`,
type: 'danger',
})
if (jobs[i].type === 'image') {
power.value += mjPower.value
} else {
power.value += mjActionPower.value
}
continue
}
if (jobs[i]['use_proxy']) {
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?x-oss-process=image/quality,q_60&format=webp'
if (jobs[i].type === 'upscale' || jobs[i].type === 'swapFace') {
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/600/q/75'
} else {
if (jobs[i].type === 'upscale' || jobs[i].type === 'swapFace') {
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/600/q/75'
} else {
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/480/q/75'
}
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/480/q/75'
}
if ((jobs[i].type === 'image' || jobs[i].type === 'variation') && jobs[i].progress === 100){
@@ -557,6 +504,7 @@ const uploadImg = (file) => {
const send = (url, index, item) => {
httpPost(url, {
client_id: getClientId(),
index: index,
channel_id: item.channel_id,
message_id: item.message_id,
@@ -566,6 +514,7 @@ const send = (url, index, item) => {
}).then(() => {
showSuccessToast("任务推送成功,请耐心等待任务执行...")
power.value -= mjActionPower.value
fetchRunningJobs()
}).catch(e => {
showFailToast("任务推送失败:" + e.message)
})
@@ -597,6 +546,7 @@ const generate = () => {
httpPost("/api/mj/image", params.value).then(() => {
showToast("绘画任务推送成功,请耐心等待任务执行")
power.value -= mjPower.value
fetchRunningJobs()
}).catch(e => {
showFailToast("任务推送失败:" + e.message)
})
@@ -604,12 +554,13 @@ const generate = () => {
const removeImage = (item) => {
showConfirmDialog({
title: '标题',
title: '删除提示',
message:
'此操作将会删除任务和图片,继续操作码?',
}).then(() => {
httpGet("/api/mj/remove", {id: item.id, user_id: item.user_id}).then(() => {
showSuccessToast("任务删除成功")
fetchFinishJobs(1)
}).catch(e => {
showFailToast("任务删除失败:" + e.message)
})
@@ -644,6 +595,15 @@ const showPrompt = (item) => {
});
}
const showErrMsg = (item) => {
showDialog({
title: '错误详情',
message: item['err_msg'],
}).then(() => {
// on close
});
}
const imageView = (item) => {
showImagePreview([item['img_url']]);
}

View File

@@ -133,11 +133,9 @@
description="暂无记录"
/>
<van-grid :gutter="10" :column-num="3" v-else>
<van-grid-item v-for="item in runningJobs">
<van-grid-item v-for="item in runningJobs" :key="item.id">
<div v-if="item.progress > 0">
<van-image :src="item['img_url']">
<template v-slot:error>加载失败</template>
</van-image>
<van-image src="/images/img-holder.png"></van-image>
<div class="progress">
<van-circle
v-model:current-rate="item.progress"
@@ -176,8 +174,15 @@
@load="onLoad"
>
<van-grid :gutter="10" :column-num="2">
<van-grid-item v-for="item in finishedJobs">
<div class="job-item">
<van-grid-item v-for="item in finishedJobs" :key="item.id">
<div class="failed" v-if="item.progress === 101">
<div class="title">任务失败</div>
<div class="opt">
<van-button size="small" @click="showErrMsg(item)">详情</van-button>
<van-button type="danger" @click="removeImage($event,item)" size="small">删除</van-button>
</div>
</div>
<div class="job-item" v-else>
<van-image
:src="item['img_url']"
:class="item['can_opt'] ? '' : 'upscale'"
@@ -217,7 +222,7 @@ import {onMounted, onUnmounted, ref} from "vue"
import {Delete} from "@element-plus/icons-vue";
import {httpGet, httpPost} from "@/utils/http";
import Clipboard from "clipboard";
import {checkSession, getSystemInfo} from "@/store/cache";
import {checkSession, getClientId, getSystemInfo} from "@/store/cache";
import {useRouter} from "vue-router";
import {getSessionId} from "@/store/session";
import {
@@ -230,10 +235,10 @@ import {
showToast
} from "vant";
import {showLoginDialog} from "@/utils/libs";
import {useSharedStore} from "@/store/sharedata";
const listBoxHeight = ref(window.innerHeight - 40)
const mjBoxHeight = ref(window.innerHeight - 150)
const item = ref({})
const isLogin = ref(false)
const activeColspan = ref([""])
@@ -261,6 +266,7 @@ const upscaleAlgArr = ref([
const showUpscalePicker = ref(false)
const params = ref({
client_id: getClientId(),
width: 1024,
height: 1024,
sampler: samplers.value[0].value,
@@ -287,56 +293,8 @@ if (_params) {
const power = ref(0)
const sdPower = ref(0) // 画一张 SD 图片消耗算力
const socket = ref(null)
const userId = ref(0)
const heartbeatHandle = ref(null)
const connect = () => {
let host = process.env.VUE_APP_WS_HOST
if (host === '') {
if (location.protocol === 'https:') {
host = 'wss://' + location.host;
} else {
host = 'ws://' + location.host;
}
}
// 心跳函数
const sendHeartbeat = () => {
clearTimeout(heartbeatHandle.value)
new Promise((resolve, reject) => {
if (socket.value !== null) {
socket.value.send(JSON.stringify({type: "heartbeat", content: "ping"}))
}
resolve("success")
}).then(() => {
heartbeatHandle.value = setTimeout(() => sendHeartbeat(), 5000)
});
}
const _socket = new WebSocket(host + `/api/sd/client?user_id=${userId.value}`);
_socket.addEventListener('open', () => {
socket.value = _socket;
// 发送心跳消息
sendHeartbeat()
});
_socket.addEventListener('message', event => {
if (event.data instanceof Blob) {
fetchRunningJobs()
finished.value = false
page.value = 1
fetchFinishJobs(page.value)
}
});
_socket.addEventListener('close', () => {
if (socket.value !== null) {
connect()
}
});
}
const store = useSharedStore()
const clipboard = ref(null)
const prompt = ref('')
onMounted(() => {
@@ -355,14 +313,23 @@ onMounted(() => {
}).catch(e => {
showNotify({type: "danger", message: "获取系统配置失败:" + e.message})
})
store.addMessageHandler("sd", (data) => {
if (data.channel !== "sd" || data.clientId !== getClientId()) {
return
}
if (data.body === "FINISH" || data.body === "FAIL") {
page.value = 1
fetchFinishJobs(1)
}
fetchRunningJobs()
})
})
onUnmounted(() => {
clipboard.value.destroy()
if (socket.value !== null) {
socket.value.close()
socket.value = null
}
store.removeMessageHandler("sd")
})
@@ -373,7 +340,6 @@ const initData = () => {
isLogin.value = true
fetchRunningJobs()
fetchFinishJobs(1)
connect()
}).catch(() => {
loading.value = false
});
@@ -414,10 +380,17 @@ const fetchFinishJobs = (page) => {
if (jobs.length < pageSize.value) {
finished.value = true
}
const _jobs = []
for (let i = 0; i < jobs.length; i++) {
if (jobs[i].progress === -1) {
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?imageView2/1/w/480/h/600/q/75'
}
_jobs.push(jobs[i])
}
if (page === 1) {
finishedJobs.value = jobs
finishedJobs.value = _jobs
} else {
finishedJobs.value = finishedJobs.value.concat(jobs)
finishedJobs.value = finishedJobs.value.concat(_jobs)
}
loading.value = false
}).catch(e => {
@@ -450,6 +423,7 @@ const generate = () => {
httpPost("/api/sd/image", params.value).then(() => {
showSuccessToast("绘画任务推送成功,请耐心等待任务执行...")
power.value -= sdPower.value
fetchRunningJobs()
}).catch(e => {
showFailToast("任务推送失败:" + e.message)
})
@@ -468,6 +442,15 @@ const showPrompt = (item) => {
});
}
const showErrMsg = (item) => {
showDialog({
title: '错误详情',
message: item['err_msg'],
}).then(() => {
// on close
});
}
const removeImage = (event, item) => {
event.stopPropagation()
showConfirmDialog({
@@ -477,6 +460,7 @@ const removeImage = (event, item) => {
}).then(() => {
httpGet("/api/sd/remove", {id: item.id, user_id: item.user}).then(() => {
showSuccessToast("任务删除成功")
fetchFinishJobs(1)
}).catch(e => {
showFailToast("任务删除失败:" + e.message)
})