add back-to-top component for all list page

This commit is contained in:
RockYang 2024-07-29 11:00:53 +08:00
parent 088a614160
commit 95457b7dcd
9 changed files with 137 additions and 53 deletions

View File

@ -456,15 +456,44 @@ func (h *MidJourneyHandler) Remove(c *gin.Context) {
resp.ERROR(c, "记录不存在")
return
}
// remove job recode
res := h.DB.Delete(&job)
if res.Error != nil {
resp.ERROR(c, res.Error.Error())
tx := h.DB.Begin()
if err := tx.Delete(&job).Error; err != nil {
tx.Rollback()
resp.ERROR(c, err.Error())
return
}
// refund power
err := tx.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power)).Error
if err != nil {
tx.Rollback()
resp.ERROR(c, err.Error())
return
}
var user model.User
h.DB.Where("id = ?", job.UserId).First(&user)
err = tx.Create(&model.PowerLog{
UserId: user.Id,
Username: user.Username,
Type: types.PowerConsume,
Amount: job.Power,
Balance: user.Power + job.Power,
Mark: types.PowerAdd,
Model: "mid-journey",
Remark: fmt.Sprintf("绘画任务失败退回算力。任务ID%s", job.TaskId),
CreatedAt: time.Now(),
}).Error
if err != nil {
tx.Rollback()
resp.ERROR(c, err.Error())
return
}
tx.Commit()
// remove image
err := h.uploader.GetUploadHandler().Delete(job.ImgURL)
err = h.uploader.GetUploadHandler().Delete(job.ImgURL)
if err != nil {
logger.Error("remove image failed: ", err)
}

View File

@ -8,7 +8,6 @@ package mj
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
import (
"fmt"
"geekai/core/types"
logger2 "geekai/logger"
"geekai/service"
@ -188,28 +187,6 @@ func (p *ServicePool) SyncTaskProgress() {
}
for _, job := range jobs {
// 失败或者 30 分钟还没完成的任务删除并退回算力
if time.Now().Sub(job.CreatedAt) > time.Minute*30 {
p.db.Delete(&job)
// 退回算力
tx := p.db.Model(&model.User{}).Where("id = ?", job.UserId).UpdateColumn("power", gorm.Expr("power + ?", job.Power))
if tx.Error == nil && tx.RowsAffected > 0 {
var user model.User
p.db.Where("id = ?", job.UserId).First(&user)
p.db.Create(&model.PowerLog{
UserId: user.Id,
Username: user.Username,
Type: types.PowerConsume,
Amount: job.Power,
Balance: user.Power + job.Power,
Mark: types.PowerAdd,
Model: "mid-journey",
Remark: fmt.Sprintf("绘画任务失败退回算力。任务ID%s", job.TaskId),
CreatedAt: time.Now(),
})
}
continue
}
if servicePlus := p.getService(job.ChannelId); servicePlus != nil {
_ = servicePlus.Notify(job)
}

View File

@ -79,7 +79,7 @@
background-color #383838
border 1px solid #454545
border-radius 5px
padding 10px
padding 5px
margin-bottom 10px
display flex
flex-flow column
@ -91,12 +91,13 @@
}
.el-image {
height 60px
height 30px
width 100%
}
.text {
margin-top 6px
margin-top 4px
font-size 12px
}
}

View File

@ -0,0 +1,77 @@
<template>
<button v-if="showButton" @click="scrollToTop" class="scroll-to-top" :style="{bottom: bottom + 'px', right: right + 'px', backgroundColor: bgColor}">
<el-icon><ArrowUpBold /></el-icon>
</button>
</template>
<script>
import {ArrowUpBold} from "@element-plus/icons-vue";
export default {
name: 'BackTop',
components: {ArrowUpBold},
props: {
bottom: {
type: Number,
default: 30
},
right: {
type: Number,
default: 30
},
bgColor: {
type: String,
default: '#007bff'
}
},
data() {
return {
showButton: false
};
},
mounted() {
this.checkScroll();
window.addEventListener('resize', this.checkScroll);
this.$el.parentElement.addEventListener('scroll', this.checkScroll);
},
beforeUnmount() {
window.removeEventListener('resize', this.checkScroll);
this.$el.parentElement.removeEventListener('scroll', this.checkScroll);
},
methods: {
scrollToTop() {
const container = this.$el.parentElement;
container.scrollTo({
top: 0,
behavior: 'smooth'
});
},
checkScroll() {
const container = this.$el.parentElement;
this.showButton = container.scrollTop > 50;
}
}
}
</script>
<style scoped lang="stylus">
.scroll-to-top {
position: fixed;
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
outline: none;
transition: opacity 0.3s;
width 40px
height 40px
display flex
justify-content center
align-items center
font-size 20px
&:hover {
opacity: 0.6;
}
}
</style>

View File

@ -118,6 +118,8 @@
v-if="item.type==='prompt'" :data="item" :list-style="listStyle"/>
<chat-reply v-else-if="item.type==='reply'" :data="item" @regen="reGenerate" :read-only="false" :list-style="listStyle"/>
</div>
<back-top :right="30" :bottom="100" bg-color="#19C27D"/>
</div><!-- end chat box -->
<div class="input-box">
@ -220,6 +222,8 @@ import FileSelect from "@/components/FileSelect.vue";
import FileList from "@/components/FileList.vue";
import ChatSetting from "@/components/ChatSetting.vue";
import axios from "axios";
import BackTop from "@/components/BackTop.vue";
import {showMessageError} from "@/utils/dialog";
const title = ref('ChatGPT-智能助手');
const models = ref([])
@ -603,18 +607,6 @@ const connect = function (chat_id, role_id) {
}
}
//
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/chat/new?session_id=${sessionId.value}&role_id=${role_id}&chat_id=${chat_id}&model_id=${modelID.value}&token=${getUserToken()}`);
_socket.addEventListener('open', () => {
chatData.value = []; //
@ -636,8 +628,6 @@ const connect = function (chat_id, role_id) {
} else { //
loadChatHistory(chat_id);
}
//
sendHeartbeat()
});
_socket.addEventListener('message', event => {
@ -648,7 +638,7 @@ const connect = function (chat_id, role_id) {
reader.onload = () => {
const data = JSON.parse(String(reader.result));
if (data.type === 'start') {
const prePrompt = chatData.value[chatData.value.length-1].content
const prePrompt = chatData.value[chatData.value.length-1]?.content
chatData.value.push({
type: "reply",
id: randString(32),
@ -689,8 +679,10 @@ const connect = function (chat_id, role_id) {
} else {
lineBuffer.value += data.content;
const reply = chatData.value[chatData.value.length - 1]
reply['orgContent'] = lineBuffer.value;
reply['content'] = md.render(processContent(lineBuffer.value));
if (reply) {
reply['orgContent'] = lineBuffer.value;
reply['content'] = md.render(processContent(lineBuffer.value));
}
}
//
nextTick(() => {
@ -716,7 +708,7 @@ const connect = function (chat_id, role_id) {
connect(chat_id, role_id)
}).catch(() => {
loading.value = true
setTimeout(() => connect(chat_id, role_id), 3000)
showMessageError("会话已断开,刷新页面...")
});
});

View File

@ -174,7 +174,7 @@
</div> <!-- end finish job list-->
</div>
</div>
<back-top :right="30" :bottom="30" bg-color="#0f7a71"/>
</div><!-- end task list box -->
</div>
@ -193,6 +193,7 @@ import Clipboard from "clipboard";
import {checkSession} from "@/action/session";
import {useSharedStore} from "@/store/sharedata";
import TaskList from "@/components/TaskList.vue";
import BackTop from "@/components/BackTop.vue";
const listBoxHeight = ref(0)
// const paramBoxHeight = ref(0)

View File

@ -593,6 +593,7 @@
</div> <!-- end finish job list-->
</div>
</div>
<back-top :right="30" :bottom="30" bg-color="#0f7a71"/>
</div><!-- end task list box -->
</div>
@ -613,6 +614,7 @@ import {getSessionId} from "@/store/session";
import {copyObj, removeArrayItem} from "@/utils/libs";
import {useSharedStore} from "@/store/sharedata";
import TaskList from "@/components/TaskList.vue";
import BackTop from "@/components/BackTop.vue";
const listBoxHeight = ref(0)
const paramBoxHeight = ref(0)
@ -1014,7 +1016,7 @@ const publishImage = (item, action) => {
item.publish = action
page.value = 0
isOver.value = false
fetchFinishJobs()
item.publish = action
}).catch(e => {
ElMessage.error(text + "失败:" + e.message)
})

View File

@ -345,7 +345,7 @@
</div> <!-- end finish job list-->
</div>
</div>
<back-top :right="30" :bottom="30" bg-color="#0f7a71"/>
</div><!-- end task list box -->
</div>
@ -476,6 +476,7 @@ import {useRouter} from "vue-router";
import {getSessionId} from "@/store/session";
import {useSharedStore} from "@/store/sharedata";
import TaskList from "@/components/TaskList.vue";
import BackTop from "@/components/BackTop.vue";
const listBoxHeight = ref(0)
// const paramBoxHeight = ref(0)
@ -755,7 +756,7 @@ const publishImage = (event, item, action) => {
item.publish = action
page.value = 0
isOver.value = false
fetchFinishJobs()
item.publish = action
}).catch(e => {
ElMessage.error(text + "失败:" + e.message)
})

View File

@ -163,7 +163,10 @@
<i class="iconfont icon-face"></i>
</div>
</div>
<back-top :right="30" :bottom="30" bg-color="#0f7a71"/>
</div><!-- end of waterfall -->
</div>
<!-- 任务详情弹框 -->
<el-dialog v-model="showTaskDialog" title="绘画任务详情" :fullscreen="true">
@ -301,6 +304,7 @@ import {httpGet} from "@/utils/http";
import {ElMessage} from "element-plus";
import Clipboard from "clipboard";
import {useRouter} from "vue-router";
import BackTop from "@/components/BackTop.vue";
const data = ref({
"mj": [],