mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
feat: add mj image list component for mobile page. fixed bug for html tag escape
This commit is contained in:
parent
54d70623ab
commit
827f2b9739
@ -97,7 +97,7 @@ func (h *ChatHandler) ChatHandle(c *gin.Context) {
|
|||||||
|
|
||||||
// use old chat data override the chat model and role ID
|
// use old chat data override the chat model and role ID
|
||||||
var chat model.ChatItem
|
var chat model.ChatItem
|
||||||
res = h.db.Where("chat_id=?", chatId).First(&chat)
|
res = h.db.Where("chat_id = ?", chatId).First(&chat)
|
||||||
if res.Error == nil {
|
if res.Error == nil {
|
||||||
chatModel.Id = chat.ModelId
|
chatModel.Id = chat.ModelId
|
||||||
roleId = int(chat.RoleId)
|
roleId = int(chat.RoleId)
|
||||||
|
@ -342,6 +342,7 @@ func (h *MidJourneyHandler) JobList(c *gin.Context) {
|
|||||||
|
|
||||||
if job.Progress == -1 {
|
if job.Progress == -1 {
|
||||||
h.db.Delete(&model.MidJourneyJob{Id: job.Id})
|
h.db.Delete(&model.MidJourneyJob{Id: job.Id})
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if item.Progress < 100 && item.ImgURL == "" && item.OrgURL != "" {
|
if item.Progress < 100 && item.ImgURL == "" && item.OrgURL != "" {
|
||||||
|
@ -76,6 +76,12 @@ func (h *PaymentHandler) DoPay(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fix: 这里先检查一下订单状态,如果已经支付了,就直接返回
|
||||||
|
if order.Status == types.OrderPaidSuccess {
|
||||||
|
resp.ERROR(c, "This order had been paid, please do not pay twice")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 更新扫码状态
|
// 更新扫码状态
|
||||||
h.db.Model(&order).UpdateColumn("status", types.OrderScanned)
|
h.db.Model(&order).UpdateColumn("status", types.OrderScanned)
|
||||||
if payWay == "alipay" { // 支付宝
|
if payWay == "alipay" { // 支付宝
|
||||||
|
@ -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))
|
||||||
|
@ -1 +0,0 @@
|
|||||||
package wanx
|
|
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
func NewGormConfig() *gorm.Config {
|
func NewGormConfig() *gorm.Config {
|
||||||
return &gorm.Config{
|
return &gorm.Config{
|
||||||
Logger: logger.Default.LogMode(logger.Warn),
|
Logger: logger.Default.LogMode(logger.Silent),
|
||||||
NamingStrategy: schema.NamingStrategy{
|
NamingStrategy: schema.NamingStrategy{
|
||||||
TablePrefix: "chatgpt_", // 设置表前缀
|
TablePrefix: "chatgpt_", // 设置表前缀
|
||||||
SingularTable: false, // 使用单数表名形式
|
SingularTable: false, // 使用单数表名形式
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
.mobile-mj .content .van-field__label {
|
|
||||||
width: 100px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
.mobile-mj .content .text-line {
|
.mobile-mj .content .text-line {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@ -48,3 +44,91 @@
|
|||||||
.mobile-mj .content .text-line .van-row .van-col .active {
|
.mobile-mj .content .text-line .van-row .van-col .active {
|
||||||
background-color: #e5e5e5;
|
background-color: #e5e5e5;
|
||||||
}
|
}
|
||||||
|
.mobile-mj .content .text-line .van-button {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .text-line .van-button .van-tag {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content {
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .van-image {
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(50,50,50,0.5);
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress .van-circle__text {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
justify-content: center;
|
||||||
|
color: #c1c1c1;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .icon {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .icon .iconfont {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .task-in-queue .text {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item {
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 6px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-line {
|
||||||
|
margin: 6px 0;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #4e5058;
|
||||||
|
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 {
|
||||||
|
background-color: #6d6f78;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-line ul .show-prompt {
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .remove {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item:hover .remove {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
.mobile-mj {
|
.mobile-mj {
|
||||||
.content {
|
.content {
|
||||||
padding-bottom 60px
|
|
||||||
|
|
||||||
.text-line {
|
.text-line {
|
||||||
padding 6px
|
padding 6px
|
||||||
font-size 14px
|
font-size 14px
|
||||||
@ -70,5 +68,126 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.running-job-list {
|
||||||
|
.van-grid {
|
||||||
|
.van-grid-item {
|
||||||
|
.van-grid-item__content {
|
||||||
|
padding 0
|
||||||
|
position relative
|
||||||
|
|
||||||
|
.van-image {
|
||||||
|
min-height 100px
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
background rgba(50, 50, 50, 0.5)
|
||||||
|
position absolute
|
||||||
|
left 0
|
||||||
|
top 0
|
||||||
|
|
||||||
|
.van-circle__text {
|
||||||
|
color #ffffff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// end progress
|
||||||
|
|
||||||
|
.task-in-queue {
|
||||||
|
display flex
|
||||||
|
flex-flow column
|
||||||
|
justify-content center
|
||||||
|
color #c1c1c1
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
text-align center
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-size 24px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size 14px
|
||||||
|
margin-top 5px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//end running jobs
|
||||||
|
|
||||||
|
.finish-job-list {
|
||||||
|
.van-grid {
|
||||||
|
.van-grid-item {
|
||||||
|
.van-grid-item__content {
|
||||||
|
padding 0
|
||||||
|
|
||||||
|
.job-item {
|
||||||
|
overflow hidden
|
||||||
|
border-radius 6px
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,6 +9,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Cell,
|
Cell,
|
||||||
CellGroup,
|
CellGroup,
|
||||||
|
Circle,
|
||||||
Col,
|
Col,
|
||||||
Collapse,
|
Collapse,
|
||||||
CollapseItem,
|
CollapseItem,
|
||||||
@ -16,11 +17,17 @@ import {
|
|||||||
Dialog,
|
Dialog,
|
||||||
DropdownItem,
|
DropdownItem,
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
Empty,
|
||||||
Field,
|
Field,
|
||||||
Form,
|
Form,
|
||||||
|
Grid,
|
||||||
|
GridItem,
|
||||||
Icon,
|
Icon,
|
||||||
Image,
|
Image,
|
||||||
|
ImagePreview,
|
||||||
|
Lazyload,
|
||||||
List,
|
List,
|
||||||
|
Loading,
|
||||||
NavBar,
|
NavBar,
|
||||||
Notify,
|
Notify,
|
||||||
Overlay,
|
Overlay,
|
||||||
@ -79,6 +86,13 @@ app.use(Slider)
|
|||||||
app.use(Badge)
|
app.use(Badge)
|
||||||
app.use(Collapse);
|
app.use(Collapse);
|
||||||
app.use(CollapseItem);
|
app.use(CollapseItem);
|
||||||
|
app.use(Grid);
|
||||||
|
app.use(GridItem);
|
||||||
|
app.use(Empty);
|
||||||
|
app.use(Circle);
|
||||||
|
app.use(Loading);
|
||||||
|
app.use(Lazyload);
|
||||||
|
app.use(ImagePreview);
|
||||||
app.use(router).use(ElementPlus).mount('#app')
|
app.use(router).use(ElementPlus).mount('#app')
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,3 +197,9 @@ export function processContent(content) {
|
|||||||
return lines.join("\n")
|
return lines.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function escapeHTML(html) {
|
||||||
|
return html.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -259,7 +259,16 @@ import {
|
|||||||
VideoPause
|
VideoPause
|
||||||
} from '@element-plus/icons-vue'
|
} from '@element-plus/icons-vue'
|
||||||
import 'highlight.js/styles/a11y-dark.css'
|
import 'highlight.js/styles/a11y-dark.css'
|
||||||
import {dateFormat, isImage, isMobile, processContent, randString, removeArrayItem, UUID} from "@/utils/libs";
|
import {
|
||||||
|
dateFormat,
|
||||||
|
escapeHTML,
|
||||||
|
isImage,
|
||||||
|
isMobile,
|
||||||
|
processContent,
|
||||||
|
randString,
|
||||||
|
removeArrayItem,
|
||||||
|
UUID
|
||||||
|
} from "@/utils/libs";
|
||||||
import {ElMessage, ElMessageBox} from "element-plus";
|
import {ElMessage, ElMessageBox} from "element-plus";
|
||||||
import hl from "highlight.js";
|
import hl from "highlight.js";
|
||||||
import {getSessionId, getUserToken, removeUserToken} from "@/store/session";
|
import {getSessionId, getUserToken, removeUserToken} from "@/store/session";
|
||||||
@ -717,7 +726,7 @@ const sendMessage = function () {
|
|||||||
type: "prompt",
|
type: "prompt",
|
||||||
id: randString(32),
|
id: randString(32),
|
||||||
icon: loginUser.value.avatar,
|
icon: loginUser.value.avatar,
|
||||||
content: md.render(processContent(prompt.value)),
|
content: md.render(escapeHTML(processContent(prompt.value))),
|
||||||
created_at: new Date().getTime(),
|
created_at: new Date().getTime(),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -815,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(text);
|
socket.value.send(previousText);
|
||||||
}
|
}
|
||||||
|
|
||||||
const chatName = ref('')
|
const chatName = ref('')
|
||||||
|
@ -39,6 +39,7 @@ const onChange = (index) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus">
|
<style lang="stylus">
|
||||||
|
@import '@/assets/iconfont/iconfont.css';
|
||||||
.mobile-home {
|
.mobile-home {
|
||||||
.container {
|
.container {
|
||||||
.van-nav-bar {
|
.van-nav-bar {
|
||||||
@ -47,7 +48,7 @@ const onChange = (index) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding 46px 10px 0 10px;
|
padding 46px 10px 60px 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,128 @@
|
|||||||
</div>
|
</div>
|
||||||
</van-form>
|
</van-form>
|
||||||
|
|
||||||
<h2>任务列表</h2>
|
<h3>任务列表</h3>
|
||||||
|
<div class="running-job-list">
|
||||||
|
<van-empty v-if="runningJobs.length ===0"
|
||||||
|
image="https://fastly.jsdelivr.net/npm/@vant/assets/custom-empty-image.png"
|
||||||
|
image-size="80"
|
||||||
|
description="暂无记录"
|
||||||
|
/>
|
||||||
|
<van-grid :gutter="10" :column-num="3" v-else>
|
||||||
|
<van-grid-item v-for="item in runningJobs">
|
||||||
|
<div v-if="item.progress > 0">
|
||||||
|
<van-image :src="item['img_url']">
|
||||||
|
<template v-slot:error>加载失败</template>
|
||||||
|
</van-image>
|
||||||
|
<div class="progress">
|
||||||
|
<van-circle
|
||||||
|
v-model:current-rate="item.progress"
|
||||||
|
:rate="item.progress"
|
||||||
|
:speed="100"
|
||||||
|
:text="item.progress+'%'"
|
||||||
|
:stroke-width="60"
|
||||||
|
size="90px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else class="task-in-queue">
|
||||||
|
<span class="icon"><i class="iconfont icon-quick-start"></i></span>
|
||||||
|
<span class="text">排队中</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</van-grid-item>
|
||||||
|
</van-grid>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>创作记录</h3>
|
||||||
|
<div class="finish-job-list">
|
||||||
|
<van-empty v-if="finishedJobs.length ===0"
|
||||||
|
image="https://fastly.jsdelivr.net/npm/@vant/assets/custom-empty-image.png"
|
||||||
|
image-size="80"
|
||||||
|
description="暂无记录"
|
||||||
|
/>
|
||||||
|
<van-grid :gutter="10" :column-num="3" v-else>
|
||||||
|
<van-grid-item v-for="item in finishedJobs">
|
||||||
|
<div class="job-item">
|
||||||
|
<el-image
|
||||||
|
:src="item['thumb_url']"
|
||||||
|
:class="item['can_opt'] ? '' : 'upscale'" :zoom-rate="1.2"
|
||||||
|
:preview-src-list="[item['img_url']]" fit="cover" :initial-index="0"
|
||||||
|
loading="lazy" v-if="item.progress > 0">
|
||||||
|
<template #placeholder>
|
||||||
|
<div class="image-slot">
|
||||||
|
正在加载图片
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #error>
|
||||||
|
<div class="image-slot" v-if="item['img_url'] === ''">
|
||||||
|
<i class="iconfont icon-loading"></i>
|
||||||
|
<span>正在下载图片</span>
|
||||||
|
</div>
|
||||||
|
<div class="image-slot" v-else>
|
||||||
|
<el-icon>
|
||||||
|
<Picture/>
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
<template #reference>
|
||||||
|
<el-icon>
|
||||||
|
<ChromeFilled/>
|
||||||
|
</el-icon>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #default>
|
||||||
|
<div class="mj-list-item-prompt">
|
||||||
|
<span>{{ item.prompt }}</span>
|
||||||
|
<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 class="remove">
|
||||||
|
<el-button type="danger" :icon="Delete" @click="removeImage(item)" circle/>
|
||||||
|
<el-button type="warning" v-if="item.publish" @click="publishImage(item, false)"
|
||||||
|
circle>
|
||||||
|
<i class="iconfont icon-cancel-share"></i>
|
||||||
|
</el-button>
|
||||||
|
<el-button type="success" v-else @click="publishImage(item, true)" circle>
|
||||||
|
<i class="iconfont icon-share-bold"></i>
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-grid-item>
|
||||||
|
</van-grid>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -107,14 +228,15 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted, ref} from "vue";
|
import {onMounted, ref} from "vue";
|
||||||
import {showFailToast, showToast} from "vant";
|
import {showFailToast, showNotify, showToast} from "vant";
|
||||||
import {httpPost} from "@/utils/http";
|
import {httpGet, httpPost} from "@/utils/http";
|
||||||
import Compressor from "compressorjs";
|
import Compressor from "compressorjs";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
import {getSessionId} from "@/store/session";
|
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";
|
||||||
|
|
||||||
const title = ref('MidJourney 绘画')
|
const title = ref('MidJourney 绘画')
|
||||||
const activeColspan = ref([""])
|
const activeColspan = ref([""])
|
||||||
@ -154,14 +276,18 @@ const params = ref({
|
|||||||
const imgCalls = ref(0)
|
const imgCalls = ref(0)
|
||||||
const userId = ref(0)
|
const userId = ref(0)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const runningJobs = ref([])
|
||||||
|
const finishedJobs = ref([])
|
||||||
|
const socket = ref(null)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
checkSession().then(user => {
|
checkSession().then(user => {
|
||||||
imgCalls.value = user['img_calls']
|
imgCalls.value = user['img_calls']
|
||||||
userId.value = user.id
|
userId.value = user.id
|
||||||
|
|
||||||
// fetchRunningJobs(userId.value)
|
fetchRunningJobs(userId.value)
|
||||||
// fetchFinishJobs(userId.value)
|
fetchFinishJobs(userId.value)
|
||||||
// connect()
|
connect()
|
||||||
|
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
@ -176,6 +302,98 @@ onMounted(() => {
|
|||||||
ElMessage.error('复制失败!');
|
ElMessage.error('复制失败!');
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
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) {
|
||||||
|
fetchRunningJobs(userId.value)
|
||||||
|
fetchFinishJobs(userId.value)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_socket.addEventListener('close', () => {
|
||||||
|
connect()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取运行中的任务
|
||||||
|
const fetchRunningJobs = (userId) => {
|
||||||
|
httpGet(`/api/mj/jobs?status=0&user_id=${userId}`).then(res => {
|
||||||
|
const jobs = res.data
|
||||||
|
const _jobs = []
|
||||||
|
for (let i = 0; i < jobs.length; i++) {
|
||||||
|
if (jobs[i].progress === -1) {
|
||||||
|
showNotify({
|
||||||
|
message: `任务执行失败:${jobs[i]['err_msg']}`,
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
imgCalls.value += 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_jobs.push(jobs[i])
|
||||||
|
}
|
||||||
|
runningJobs.value = _jobs
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error("获取任务失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchFinishJobs = (userId) => {
|
||||||
|
// 获取已完成的任务
|
||||||
|
httpGet(`/api/mj/jobs?status=1&user_id=${userId}`).then(res => {
|
||||||
|
const jobs = res.data
|
||||||
|
for (let i = 0; i < jobs.length; i++) {
|
||||||
|
if (jobs[i]['use_proxy']) {
|
||||||
|
jobs[i]['thumb_url'] = jobs[i]['img_url'] + '?x-oss-process=image/quality,q_60&format=webp'
|
||||||
|
} 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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobs[i].type === 'image' || jobs[i].type === 'variation') {
|
||||||
|
jobs[i]['can_opt'] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finishedJobs.value = jobs
|
||||||
|
}).catch(e => {
|
||||||
|
ElMessage.error("获取任务失败:" + e.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 切换图片比例
|
// 切换图片比例
|
||||||
const changeRate = (item) => {
|
const changeRate = (item) => {
|
||||||
params.value.rate = item.value
|
params.value.rate = item.value
|
||||||
@ -227,8 +445,9 @@ const generate = () => {
|
|||||||
ElMessage.error("任务推送失败:" + e.message)
|
ElMessage.error("任务推送失败:" + e.message)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus">
|
||||||
@import "@/assets/css/mobile/image-mj.styl"
|
@import "@/assets/css/mobile/image-mj.styl"
|
||||||
</style>
|
</style>
|
Loading…
Reference in New Issue
Block a user