feat: mobile mj list page is ready

This commit is contained in:
RockYang 2024-02-15 18:11:22 +08:00
parent 68cda968a1
commit 49e9f41ef2
9 changed files with 88 additions and 114 deletions

View File

@ -340,20 +340,22 @@ func (h *MidJourneyHandler) JobList(c *gin.Context) {
continue continue
} }
// 失败的任务直接删除
if job.Progress == -1 { if job.Progress == -1 {
h.db.Delete(&model.MidJourneyJob{Id: job.Id}) h.db.Delete(&model.MidJourneyJob{Id: job.Id})
jobs = append(jobs, job)
continue continue
} }
if item.Progress < 100 && item.ImgURL == "" && item.OrgURL != "" { if item.Progress < 100 && item.ImgURL == "" && item.OrgURL != "" {
// 正在运行中任务使用代理访问图片 // discord 服务器图片需要使用代理转发图片数据流
if job.UseProxy { if strings.HasPrefix(item.OrgURL, "https://cdn.discordapp.com") {
job.ImgURL = job.OrgURL
} else {
image, err := utils.DownloadImage(item.OrgURL, h.App.Config.ProxyURL) image, err := utils.DownloadImage(item.OrgURL, h.App.Config.ProxyURL)
if err == nil { if err == nil {
job.ImgURL = "data:image/png;base64," + base64.StdEncoding.EncodeToString(image) job.ImgURL = "data:image/png;base64," + base64.StdEncoding.EncodeToString(image)
} }
} else {
job.ImgURL = job.OrgURL
} }
} }

View File

@ -108,7 +108,7 @@ func (s *Service) Run() {
s.taskStartTimes[int(task.Id)] = time.Now() s.taskStartTimes[int(task.Id)] = time.Now()
atomic.AddInt32(&s.HandledTaskNum, 1) atomic.AddInt32(&s.HandledTaskNum, 1)
// 更新任务 ID/频道 // 更新任务 ID/频道
s.db.Debug().Model(&model.MidJourneyJob{Id: task.Id}).UpdateColumns(map[string]interface{}{ s.db.Model(&model.MidJourneyJob{Id: task.Id}).UpdateColumns(map[string]interface{}{
"task_id": res.Result, "task_id": res.Result,
"channel_id": s.Name, "channel_id": s.Name,
}) })

View File

@ -201,7 +201,7 @@ func (p *ServicePool) SyncTaskProgress() {
for _, v := range items { for _, v := range items {
// 30 分钟还没完成的任务直接删除 // 30 分钟还没完成的任务直接删除
if time.Now().Sub(v.CreatedAt) > time.Minute*30 { if time.Now().Sub(v.CreatedAt) > time.Minute*30 {
//p.db.Delete(&v) p.db.Delete(&v)
// 非放大任务,退回绘图次数 // 非放大任务,退回绘图次数
if v.Type != types.TaskUpscale.String() { if v.Type != types.TaskUpscale.String() {
p.db.Model(&model.User{}).Where("id = ?", v.UserId).UpdateColumn("img_calls", gorm.Expr("img_calls + ?", 1)) p.db.Model(&model.User{}).Where("id = ?", v.UserId).UpdateColumn("img_calls", gorm.Expr("img_calls + ?", 1))

View File

@ -55,7 +55,8 @@
padding: 0; padding: 0;
position: relative; position: relative;
} }
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .van-image { .mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .van-image,
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue {
min-height: 100px; min-height: 100px;
} }
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress { .mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress {
@ -95,40 +96,38 @@
overflow: hidden; overflow: hidden;
border-radius: 6px; border-radius: 6px;
position: relative; position: relative;
height: 100%;
width: 100%;
} }
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-line { .mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-btn {
margin: 6px 0; padding: 3px 10px;
}
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-line ul {
display: flex;
flex-flow: row;
}
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-line ul li {
margin-right: 6px;
}
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-line ul li a {
padding: 3px 0;
width: 40px;
text-align: center; text-align: center;
border-radius: 5px; border-radius: 5px;
margin: 3px 0;
display: block; display: block;
cursor: pointer; cursor: pointer;
background-color: #4e5058; background-color: #4e5058;
color: #fff; color: #fff;
} }
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-line ul li a:hover { .mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .el-image {
background-color: #6d6f78; width: 100%;
height: 200px;
} }
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-line ul .show-prompt { .mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .el-image .image-slot {
font-size: 20px; height: 100%;
cursor: pointer; display: flex;
justify-content: center;
align-items: center;
}
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .el-image .image-slot .iconfont {
margin-right: 5px;
}
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .upscale {
height: 260px;
width: 100%;
} }
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove { .mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove {
display: none;
position: absolute; position: absolute;
right: 10px; right: 5px;
top: 10px; top: 5px;
}
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item:hover .remove {
display: block;
} }

View File

@ -76,7 +76,7 @@
padding 0 padding 0
position relative position relative
.van-image { .van-image, .task-in-queue {
min-height 100px min-height 100px
} }
@ -134,53 +134,47 @@
overflow hidden overflow hidden
border-radius 6px border-radius 6px
position relative position relative
height 100%
width 100%
.opt { .opt {
.opt-line { .opt-btn {
margin 6px 0 padding 3px 10px
text-align center
border-radius 5px
margin 3px 0
display block
cursor pointer
background-color #4E5058
color #ffffff
}
}
ul { .el-image {
display flex width 100%
flex-flow row height 200px
li { .image-slot {
margin-right 6px height 100%
display flex
justify-content center
align-items center
a { .iconfont {
padding 3px 0 margin-right 5px
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 { .upscale {
display none height 260px
position absolute width 100%
right 10px
top 10px
} }
&:hover { .remove {
.remove { position absolute
display block right 5px
} top 5px
} }
} }

View File

@ -824,7 +824,7 @@ const reGenerate = function () {
icon: loginUser.value.avatar, icon: loginUser.value.avatar,
content: md.render(text) content: md.render(text)
}); });
socket.value.send(previousText); socket.value.send(previousText.value);
} }
const chatName = ref('') const chatName = ref('')

View File

@ -504,7 +504,7 @@ import Clipboard from "clipboard";
import {checkSession} from "@/action/session"; import {checkSession} from "@/action/session";
import {useRouter} from "vue-router"; import {useRouter} from "vue-router";
import {getSessionId} from "@/store/session"; import {getSessionId} from "@/store/session";
import {removeArrayItem} from "@/utils/libs"; import {isMobile, removeArrayItem} from "@/utils/libs";
const listBoxHeight = ref(window.innerHeight - 40) const listBoxHeight = ref(window.innerHeight - 40)
const mjBoxHeight = ref(window.innerHeight - 150) const mjBoxHeight = ref(window.innerHeight - 150)
@ -560,7 +560,7 @@ const params = ref({
rate: rates[0].value, rate: rates[0].value,
model: models[0].value, model: models[0].value,
chaos: 0, chaos: 0,
stylize: 100, stylize: 0,
seed: 0, seed: 0,
img_arr: [], img_arr: [],
raw: false, raw: false,
@ -584,6 +584,10 @@ const imgCalls = ref(0)
const loading = ref(false) const loading = ref(false)
const userId = ref(0) const userId = ref(0)
if (isMobile()) {
router.replace("/mobile/mj")
}
const rewritePrompt = () => { const rewritePrompt = () => {
loading.value = true loading.value = true
httpPost("/api/prompt/rewrite", {"prompt": params.value.prompt}).then(res => { httpPost("/api/prompt/rewrite", {"prompt": params.value.prompt}).then(res => {

View File

@ -377,6 +377,7 @@ const sendMessage = () => {
} }
if (prompt.value.trim().length === 0) { if (prompt.value.trim().length === 0) {
showToast("请输入需要 AI 回答的问题")
return false; return false;
} }
@ -417,7 +418,7 @@ const reGenerate = () => {
icon: loginUser.value.avatar, icon: loginUser.value.avatar,
content: renderInputText(text) content: renderInputText(text)
}); });
socket.value.send(text); socket.value.send(previousText.value);
} }
const showShare = ref(false) const showShare = ref(false)

View File

@ -140,7 +140,7 @@
image-size="80" image-size="80"
description="暂无记录" description="暂无记录"
/> />
<van-grid :gutter="10" :column-num="3" v-else> <van-grid :gutter="10" :column-num="2" v-else>
<van-grid-item v-for="item in finishedJobs"> <van-grid-item v-for="item in finishedJobs">
<div class="job-item"> <div class="job-item">
<el-image <el-image
@ -168,43 +168,17 @@
</el-image> </el-image>
<div class="opt" v-if="item['can_opt']"> <div class="opt" v-if="item['can_opt']">
<div class="opt-line">
<ul>
<li><a @click="upscale(1, item)">U1</a></li>
<li><a @click="upscale(2, item)">U2</a></li>
<li><a @click="upscale(3, item)">U3</a></li>
<li><a @click="upscale(4, item)">U4</a></li>
<li class="show-prompt">
<el-popover placement="left" title="提示词" :width="240" trigger="hover"> <van-grid :gutter="0" :column-num="4">
<template #reference> <van-grid-item><a @click="upscale(1, item)" class="opt-btn">U1</a></van-grid-item>
<el-icon> <van-grid-item><a @click="upscale(2, item)" class="opt-btn">U2</a></van-grid-item>
<ChromeFilled/> <van-grid-item><a @click="upscale(3, item)" class="opt-btn">U3</a></van-grid-item>
</el-icon> <van-grid-item><a @click="upscale(4, item)" class="opt-btn">U4</a></van-grid-item>
</template> <van-grid-item><a @click="variation(1, item)" class="opt-btn">V1</a></van-grid-item>
<van-grid-item><a @click="variation(2, item)" class="opt-btn">V2</a></van-grid-item>
<template #default> <van-grid-item><a @click="variation(3, item)" class="opt-btn">V3</a></van-grid-item>
<div class="mj-list-item-prompt"> <van-grid-item><a @click="variation(4, item)" class="opt-btn">V4</a></van-grid-item>
<span>{{ item.prompt }}</span> </van-grid>
<el-icon class="copy-prompt"
:data-clipboard-text="item.prompt">
<DocumentCopy/>
</el-icon>
</div>
</template>
</el-popover>
</li>
</ul>
</div>
<div class="opt-line">
<ul>
<li><a @click="variation(1, item)">V1</a></li>
<li><a @click="variation(2, item)">V2</a></li>
<li><a @click="variation(3, item)">V3</a></li>
<li><a @click="variation(4, item)">V4</a></li>
</ul>
</div>
</div> </div>
<div class="remove"> <div class="remove">
@ -236,7 +210,7 @@ import {getSessionId} from "@/store/session";
import {checkSession} from "@/action/session"; import {checkSession} from "@/action/session";
import Clipboard from "clipboard"; import Clipboard from "clipboard";
import {useRouter} from "vue-router"; import {useRouter} from "vue-router";
import {ChromeFilled, Delete, DocumentCopy, Picture} from "@element-plus/icons-vue"; import {Delete, Picture} from "@element-plus/icons-vue";
const title = ref('MidJourney 绘画') const title = ref('MidJourney 绘画')
const activeColspan = ref([""]) const activeColspan = ref([""])
@ -263,7 +237,7 @@ const params = ref({
rate: rates[0].value, rate: rates[0].value,
model: models[0].value, model: models[0].value,
chaos: 0, chaos: 0,
stylize: 100, stylize: 0,
seed: 0, seed: 0,
img_arr: [], img_arr: [],
raw: false, raw: false,
@ -356,7 +330,7 @@ const fetchRunningJobs = (userId) => {
if (jobs[i].progress === -1) { if (jobs[i].progress === -1) {
showNotify({ showNotify({
message: `任务执行失败:${jobs[i]['err_msg']}`, message: `任务执行失败:${jobs[i]['err_msg']}`,
type: 'error', type: 'danger',
}) })
imgCalls.value += 1 imgCalls.value += 1
continue continue
@ -439,10 +413,10 @@ const generate = () => {
params.value.session_id = getSessionId() params.value.session_id = getSessionId()
params.value.img_arr = imgList.value.map(img => img.url) params.value.img_arr = imgList.value.map(img => img.url)
httpPost("/api/mj/image", params.value).then(() => { httpPost("/api/mj/image", params.value).then(() => {
ElMessage.success("绘画任务推送成功,请耐心等待任务执行...") showToast("绘画任务推送成功,请耐心等待任务执行")
imgCalls.value -= 1 imgCalls.value -= 1
}).catch(e => { }).catch(e => {
ElMessage.error("任务推送失败:" + e.message) showFailToast("任务推送失败:" + e.message)
}) })
} }