restore use power when removed not finish jobs

This commit is contained in:
RockYang
2024-07-31 16:08:46 +08:00
parent 96f1126d02
commit 1d9d487f0e
25 changed files with 425 additions and 487 deletions

View File

@@ -221,134 +221,7 @@
//
.job-list-box {
@import "running-job-list.styl"
.finish-job-list {
#waterfall {
display flex
justify-content center
padding-top 20px
flex-flow column
.job-item {
width 100%
height 100%
border 1px solid #666666
padding 6px
overflow hidden
border-radius 6px
transition: all 0.3s ease; /* */
position relative
.opt {
.opt-line {
margin 6px 0
ul {
display flex
flex-flow row
li {
margin-right 6px
a {
padding 3px 0
width 40px
text-align center
border-radius 5px
display block
cursor pointer
background-color #4E5058
color #ffffff
&:hover {
background-color #6D6F78
}
}
}
.show-prompt {
font-size 20px
cursor pointer
}
}
}
}
.remove {
display none
position absolute
right 10px
top 10px
}
&:hover {
.remove {
display block
}
}
}
.animate {
&:hover {
box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* */
transform: translateY(-10px); /* 10 */
}
}
}
}
.el-image {
width 100%
height 100%
overflow visible
.el-image-viewer__wrapper {
img {
width auto
height auto
}
}
.image-slot {
display flex
flex-flow column
justify-content center
align-items center
min-height 200px
color #ffffff
.iconfont {
font-size 50px
margin-bottom 10px
}
}
}
.el-image.upscale {
img {
height 310px
}
.image-slot {
height 310px
}
.el-image-viewer__wrapper {
img {
width auto
height auto
}
}
}
}
@import "waterfall-list.styl"
}
.no-more-data {

View File

@@ -220,136 +220,8 @@
}
}
//
.job-list-box {
@import "running-job-list.styl"
.finish-job-list {
#waterfall {
display flex
justify-content center
padding-top 20px
flex-flow column
.job-item {
width 100%
height 100%
border 1px solid #666666
padding 6px
overflow hidden
border-radius 6px
transition: all 0.3s ease; /* */
position relative
.opt {
.opt-line {
margin 6px 0
ul {
display flex
flex-flow row
li {
margin-right 6px
a {
padding 3px 0
width 40px
text-align center
border-radius 5px
display block
cursor pointer
background-color #4E5058
color #ffffff
&:hover {
background-color #6D6F78
}
}
}
.show-prompt {
font-size 20px
cursor pointer
}
}
}
}
.remove {
display none
position absolute
right 10px
top 10px
}
&:hover {
.remove {
display block
}
}
}
.animate {
&:hover {
box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* */
transform: translateY(-10px); /* 10 */
}
}
}
}
.el-image {
width 100%
height 100%
overflow visible
.el-image-viewer__wrapper {
img {
width auto
height auto
}
}
.image-slot {
display flex
flex-flow column
justify-content center
align-items center
min-height 200px
color #ffffff
.iconfont {
font-size 50px
margin-bottom 10px
}
}
}
.el-image.upscale {
img {
height 310px
}
.image-slot {
height 310px
}
.el-image-viewer__wrapper {
img {
width auto
height auto
}
}
}
}
@import "waterfall-list.styl"
}
.no-more-data {

View File

@@ -0,0 +1,146 @@
.job-list-box {
@import "running-job-list.styl"
.finish-job-list {
#waterfall {
display flex
justify-content center
padding-top 20px
flex-flow column
.job-item {
width 100%
height 100%
border 1px solid #666666
padding 6px
overflow hidden
border-radius 6px
transition: all 0.3s ease; /* */
position relative
.opt {
.opt-line {
margin 6px 0
ul {
display flex
flex-flow row
li {
margin-right 6px
a {
padding 3px 0
width 40px
text-align center
border-radius 5px
display block
cursor pointer
background-color #4E5058
color #ffffff
&:hover {
background-color #6D6F78
}
}
}
.show-prompt {
font-size 20px
cursor pointer
}
}
}
}
.remove {
display none
position absolute
right 10px
top 10px
}
&:hover {
.remove {
display block
}
}
}
.animate {
&:hover {
box-shadow: 0 0 10px rgba(71, 255, 241, 0.6); /* */
transform: translateY(-10px); /* 10 */
}
}
}
}
.el-image {
width 100%
height 100%
overflow visible
.el-image-viewer__wrapper {
img {
width auto
height auto
}
}
.image-slot {
display flex
flex-flow column
justify-content center
align-items center
min-height 220px
color #ffffff
.err-msg-container {
overflow hidden
word-break break-all
padding 15px
.title {
font-size 20px
text-align center
font-weight bold
color #f56c6c
margin-bottom 30px
}
.opt {
display flex
justify-content center
}
}
.iconfont {
font-size 50px
margin-bottom 10px
}
}
}
.el-image.upscale {
img {
height 310px
}
.image-slot {
height 310px
}
.el-image-viewer__wrapper {
img {
width auto
height auto
}
}
}
}

View File

@@ -367,7 +367,6 @@ const initData = () => {
inputRef.value.addEventListener('paste', (event) => {
const items = (event.clipboardData || window.clipboardData).items;
let fileFound = false;
loading.value = true
for (let item of items) {
if (item.kind === 'file') {
@@ -376,6 +375,7 @@ const initData = () => {
const formData = new FormData();
formData.append('file', file);
loading.value = true
// 执行上传操作
httpPost('/api/upload', formData).then((res) => {
files.value.push(res.data)
@@ -389,7 +389,7 @@ const initData = () => {
break;
}
}
if (!fileFound) {
document.getElementById('status').innerText = 'No file found in paste data.';
}

View File

@@ -125,6 +125,24 @@
</template>
</el-image>
<el-image v-else-if="slotProp.item.progress === 101">
<template #error>
<div class="image-slot">
<div class="err-msg-container">
<div class="title">任务失败</div>
<div class="opt">
<el-popover title="错误详情" trigger="click" :width="250" :content="slotProp.item['err_msg']" placement="top">
<template #reference>
<el-button type="info">详情</el-button>
</template>
</el-popover>
<el-button type="danger" @click="removeImage(slotProp.item)">删除</el-button>
</div>
</div>
</div>
</template>
</el-image>
<el-image v-else>
<template #error>
<div class="image-slot">
@@ -136,17 +154,17 @@
<div class="remove">
<el-tooltip content="删除" placement="top" effect="light">
<el-button type="danger" :icon="Delete" @click="removeImage($event,slotProp.item)" circle/>
<el-button type="danger" :icon="Delete" @click="removeImage(slotProp.item)" circle/>
</el-tooltip>
<el-tooltip content="分享" placement="top" effect="light" v-if="slotProp.item.publish">
<el-button type="warning"
@click="publishImage($event,slotProp.item, false)"
@click="publishImage(slotProp.item, false)"
circle>
<i class="iconfont icon-cancel-share"></i>
</el-button>
</el-tooltip>
<el-tooltip content="取消分享" placement="top" effect="light" v-else>
<el-button type="success" @click="publishImage($event,slotProp.item, true)" circle>
<el-button type="success" @click="publishImage(slotProp.item, true)" circle>
<i class="iconfont icon-share-bold"></i>
</el-button>
</el-tooltip>
@@ -185,7 +203,7 @@
</template>
<script setup>
import {onMounted, onUnmounted, ref} from "vue"
import {nextTick, onMounted, onUnmounted, ref} from "vue"
import {Delete, InfoFilled, Picture} from "@element-plus/icons-vue";
import {httpGet, httpPost} from "@/utils/http";
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
@@ -286,25 +304,9 @@ const connect = () => {
}
}
// 心跳函数
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 => {
@@ -313,12 +315,12 @@ const connect = () => {
reader.readAsText(event.data, "UTF-8")
reader.onload = () => {
const message = String(reader.result)
if (message === "FINISH") {
if (message === "FINISH" || message === "FAIL") {
page.value = 0
isOver.value = false
fetchFinishJobs(page.value)
}
fetchRunningJobs()
nextTick(() => fetchRunningJobs())
}
}
});
@@ -336,22 +338,7 @@ const fetchRunningJobs = () => {
}
// 获取运行中的任务
httpGet(`/api/dall/jobs?finish=false`).then(res => {
const jobs = res.data
const _jobs = []
for (let i = 0; i < jobs.length; i++) {
if (jobs[i].progress === -1) {
ElNotification({
title: '任务执行失败',
dangerouslyUseHTMLString: true,
message: `任务ID${jobs[i]['task_id']}<br />原因:${jobs[i]['err_msg']}`,
type: 'error',
})
power.value += dallPower.value
continue
}
_jobs.push(jobs[i])
}
runningJobs.value = _jobs
runningJobs.value = res.data
}).catch(e => {
ElMessage.error("获取任务失败:" + e.message)
})
@@ -409,8 +396,7 @@ const generate = () => {
})
}
const removeImage = (event, item) => {
event.stopPropagation()
const removeImage = (item) => {
ElMessageBox.confirm(
'此操作将会删除任务和图片,继续操作码?',
'删除提示',
@@ -420,7 +406,7 @@ const removeImage = (event, item) => {
type: 'warning',
}
).then(() => {
httpGet("/api/dall/remove", {id: item.id, user_id: item.user}).then(() => {
httpGet("/api/dall/remove", {id: item.id}).then(() => {
ElMessage.success("任务删除成功")
page.value = 0
isOver.value = false
@@ -437,18 +423,16 @@ const previewImg = (item) => {
}
// 发布图片到作品墙
const publishImage = (event, item, action) => {
event.stopPropagation()
const publishImage = (item, action) => {
let text = "图片发布"
if (action === false) {
text = "取消发布"
}
httpGet("/api/dall/publish", {id: item.id, action: action,user_id:item.user_id}).then(() => {
httpGet("/api/dall/publish", {id: item.id, action: action}).then(() => {
ElMessage.success(text + "成功")
item.publish = action
page.value = 0
isOver.value = false
fetchFinishJobs()
}).catch(e => {
ElMessage.error(text + "失败:" + e.message)
})

View File

@@ -17,7 +17,7 @@
effect="light"
content="部署文档"
placement="bottom">
<a href="https://docs.geekai.me/install/" class="link-button" target="_blank">
<a :href="docsURL" class="link-button" target="_blank">
<i class="iconfont icon-book"></i>
</a>
</el-tooltip>

View File

@@ -487,7 +487,7 @@
</div>
</template>
</el-image>
<el-image v-else-if="slotProp.item['err_msg'] !== ''">
<el-image v-else-if="slotProp.item.progress === 101">
<template #error>
<div class="image-slot">
<div class="err-msg-container">

View File

@@ -313,21 +313,41 @@
:isOver="isOver"
@scrollReachBottom="fetchFinishJobs()">
<template #default="slotProp">
<div class="job-item animate" @click="showTask(slotProp.item)">
<el-image
:src="slotProp.item['img_thumb']"
fit="cover"
loading="lazy"/>
<div class="remove">
<el-button type="danger" :icon="Delete" @click="removeImage($event,slotProp.item)" circle/>
<el-button type="warning" v-if="slotProp.item.publish"
@click="publishImage($event,slotProp.item, false)"
circle>
<i class="iconfont icon-cancel-share"></i>
</el-button>
<el-button type="success" v-else @click="publishImage($event,slotProp.item, true)" circle>
<i class="iconfont icon-share-bold"></i>
</el-button>
<div class="job-item animate">
<el-image v-if="slotProp.item.progress === 101">
<template #error>
<div class="image-slot">
<div class="err-msg-container">
<div class="title">任务失败</div>
<div class="opt">
<el-popover title="错误详情" trigger="click" :width="250" :content="slotProp.item['err_msg']" placement="top">
<template #reference>
<el-button type="info">详情</el-button>
</template>
</el-popover>
<el-button type="danger" @click="removeImage(slotProp.item)">删除</el-button>
</div>
</div>
</div>
</template>
</el-image>
<div v-else>
<el-image
:src="slotProp.item['img_thumb']"
@click="showTask(slotProp.item)"
fit="cover"
loading="lazy"/>
<div class="remove">
<el-button type="danger" :icon="Delete" @click="removeImage(slotProp.item)" circle/>
<el-button type="warning" v-if="slotProp.item.publish"
@click="publishImage(slotProp.item, false)"
circle>
<i class="iconfont icon-cancel-share"></i>
</el-button>
<el-button type="success" v-else @click="publishImage(slotProp.item, true)" circle>
<i class="iconfont icon-share-bold"></i>
</el-button>
</div>
</div>
</div>
</template>
@@ -466,7 +486,7 @@
</template>
<script setup>
import {onMounted, onUnmounted, ref} from "vue"
import {nextTick, onMounted, onUnmounted, ref} from "vue"
import {Delete, DocumentCopy, InfoFilled, Orange, Picture} from "@element-plus/icons-vue";
import {httpGet, httpPost} from "@/utils/http";
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
@@ -540,25 +560,9 @@ const connect = () => {
}
}
// 心跳函数
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 => {
@@ -567,12 +571,12 @@ const connect = () => {
reader.readAsText(event.data, "UTF-8")
reader.onload = () => {
const message = String(reader.result)
if (message === "FINISH") {
if (message === "FINISH" || message === "FAIL") {
page.value = 0
isOver.value = false
fetchFinishJobs()
}
fetchRunningJobs()
nextTick(() => fetchRunningJobs())
}
}
});
@@ -633,22 +637,7 @@ const fetchRunningJobs = () => {
// 获取运行中的任务
httpGet(`/api/sd/jobs?finish=0`).then(res => {
const jobs = res.data
const _jobs = []
for (let i = 0; i < jobs.length; i++) {
if (jobs[i].progress === -1) {
ElNotification({
title: '任务执行失败',
dangerouslyUseHTMLString: true,
message: `任务ID${jobs[i]['task_id']}<br />原因:${jobs[i]['err_msg']}`,
type: 'error',
})
power.value += sdPower.value
continue
}
_jobs.push(jobs[i])
}
runningJobs.value = _jobs
runningJobs.value = res.data
}).catch(e => {
ElMessage.error("获取任务失败:" + e.message)
})
@@ -699,7 +688,7 @@ const generate = () => {
return
}
if (params.value.seed === '') {
if (!params.value.seed) {
params.value.seed = -1
}
params.value.session_id = getSessionId()
@@ -721,8 +710,7 @@ const copyParams = (row) => {
showTaskDialog.value = false
}
const removeImage = (event, item) => {
event.stopPropagation()
const removeImage = (item) => {
ElMessageBox.confirm(
'此操作将会删除任务和图片,继续操作码?',
'删除提示',
@@ -732,7 +720,7 @@ const removeImage = (event, item) => {
type: 'warning',
}
).then(() => {
httpGet("/api/sd/remove", {id: item.id, user_id: item.user}).then(() => {
httpGet("/api/sd/remove", {id: item.id}).then(() => {
ElMessage.success("任务删除成功")
page.value = 0
isOver.value = false
@@ -745,13 +733,12 @@ const removeImage = (event, item) => {
}
// 发布图片到作品墙
const publishImage = (event, item, action) => {
event.stopPropagation()
const publishImage = (item, action) => {
let text = "图片发布"
if (action === false) {
text = "取消发布"
}
httpGet("/api/sd/publish", {id: item.id, action: action, user_id: item.user}).then(() => {
httpGet("/api/sd/publish", {id: item.id, action: action}).then(() => {
ElMessage.success(text + "成功")
item.publish = action
page.value = 0

View File

@@ -156,7 +156,7 @@ httpGet("/api/config/get?key=system").then(res => {
const initData = () => {
httpGet("/api/model/list").then(res => {
for (let v of res.data) {
if (v.platform === "OpenAI" && v.value.indexOf("gpt-4-gizmo") === -1) {
if (v.value.indexOf("gpt-4-gizmo") === -1) {
models.value.push(v)
}
}

View File

@@ -381,9 +381,9 @@ onMounted(() => {
checkSession().then(user => {
userId.value = user.id
fetchData(1)
connect()
})
fetchData(1)
})
onUnmounted(() => {
@@ -410,6 +410,8 @@ const fetchData = (_page) => {
list.value = items
noData.value = list.value.length === 0
}).catch(e => {
loading.value = false
noData.value = true
showMessageError("获取作品列表失败:"+e.message)
})
}