mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
add back-to-top component for all list page
This commit is contained in:
parent
088a614160
commit
95457b7dcd
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
77
web/src/components/BackTop.vue
Normal file
77
web/src/components/BackTop.vue
Normal 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>
|
@ -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("会话已断开,刷新页面...")
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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": [],
|
||||
|
Loading…
Reference in New Issue
Block a user