mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 08:13:43 +08:00 
			
		
		
		
	feat: mobile mj list page is ready
This commit is contained in:
		@@ -340,20 +340,22 @@ func (h *MidJourneyHandler) JobList(c *gin.Context) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 失败的任务直接删除
 | 
			
		||||
		if job.Progress == -1 {
 | 
			
		||||
			h.db.Delete(&model.MidJourneyJob{Id: job.Id})
 | 
			
		||||
			jobs = append(jobs, job)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if item.Progress < 100 && item.ImgURL == "" && item.OrgURL != "" {
 | 
			
		||||
			// 正在运行中任务使用代理访问图片
 | 
			
		||||
			if job.UseProxy {
 | 
			
		||||
				job.ImgURL = job.OrgURL
 | 
			
		||||
			} else {
 | 
			
		||||
			// discord 服务器图片需要使用代理转发图片数据流
 | 
			
		||||
			if strings.HasPrefix(item.OrgURL, "https://cdn.discordapp.com") {
 | 
			
		||||
				image, err := utils.DownloadImage(item.OrgURL, h.App.Config.ProxyURL)
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					job.ImgURL = "data:image/png;base64," + base64.StdEncoding.EncodeToString(image)
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				job.ImgURL = job.OrgURL
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ func (s *Service) Run() {
 | 
			
		||||
		s.taskStartTimes[int(task.Id)] = time.Now()
 | 
			
		||||
		atomic.AddInt32(&s.HandledTaskNum, 1)
 | 
			
		||||
		// 更新任务 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,
 | 
			
		||||
			"channel_id": s.Name,
 | 
			
		||||
		})
 | 
			
		||||
 
 | 
			
		||||
@@ -201,7 +201,7 @@ func (p *ServicePool) SyncTaskProgress() {
 | 
			
		||||
			for _, v := range items {
 | 
			
		||||
				// 30 分钟还没完成的任务直接删除
 | 
			
		||||
				if time.Now().Sub(v.CreatedAt) > time.Minute*30 {
 | 
			
		||||
					//p.db.Delete(&v)
 | 
			
		||||
					p.db.Delete(&v)
 | 
			
		||||
					// 非放大任务,退回绘图次数
 | 
			
		||||
					if v.Type != types.TaskUpscale.String() {
 | 
			
		||||
						p.db.Model(&model.User{}).Where("id = ?", v.UserId).UpdateColumn("img_calls", gorm.Expr("img_calls + ?", 1))
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,8 @@
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  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;
 | 
			
		||||
}
 | 
			
		||||
.mobile-mj .content .running-job-list .van-grid .van-grid-item .van-grid-item__content .progress {
 | 
			
		||||
@@ -95,40 +96,38 @@
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  border-radius: 6px;
 | 
			
		||||
  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 {
 | 
			
		||||
  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;
 | 
			
		||||
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .opt .opt-btn {
 | 
			
		||||
  padding: 3px 10px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  margin: 3px 0;
 | 
			
		||||
  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 .el-image {
 | 
			
		||||
  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 {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
.mobile-mj .content .finish-job-list .van-grid .van-grid-item .van-grid-item__content .job-item .el-image .image-slot {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  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 {
 | 
			
		||||
  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;
 | 
			
		||||
  right: 5px;
 | 
			
		||||
  top: 5px;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@
 | 
			
		||||
            padding 0
 | 
			
		||||
            position relative
 | 
			
		||||
 | 
			
		||||
            .van-image {
 | 
			
		||||
            .van-image, .task-in-queue {
 | 
			
		||||
              min-height 100px
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -134,53 +134,47 @@
 | 
			
		||||
              overflow hidden
 | 
			
		||||
              border-radius 6px
 | 
			
		||||
              position relative
 | 
			
		||||
              height 100%
 | 
			
		||||
              width 100%
 | 
			
		||||
 | 
			
		||||
              .opt {
 | 
			
		||||
                .opt-line {
 | 
			
		||||
                  margin 6px 0
 | 
			
		||||
                .opt-btn {
 | 
			
		||||
                  padding 3px 10px
 | 
			
		||||
                  text-align center
 | 
			
		||||
                  border-radius 5px
 | 
			
		||||
                  margin 3px 0
 | 
			
		||||
                  display block
 | 
			
		||||
                  cursor pointer
 | 
			
		||||
                  background-color #4E5058
 | 
			
		||||
                  color #ffffff
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
                  ul {
 | 
			
		||||
                    display flex
 | 
			
		||||
                    flex-flow row
 | 
			
		||||
              .el-image {
 | 
			
		||||
                width 100%
 | 
			
		||||
                height 200px
 | 
			
		||||
 | 
			
		||||
                    li {
 | 
			
		||||
                      margin-right 6px
 | 
			
		||||
                .image-slot {
 | 
			
		||||
                  height 100%
 | 
			
		||||
                  display flex
 | 
			
		||||
                  justify-content center
 | 
			
		||||
                  align-items center
 | 
			
		||||
 | 
			
		||||
                      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
 | 
			
		||||
                    }
 | 
			
		||||
                  .iconfont {
 | 
			
		||||
                    margin-right 5px
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              .remove {
 | 
			
		||||
                display none
 | 
			
		||||
                position absolute
 | 
			
		||||
                right 10px
 | 
			
		||||
                top 10px
 | 
			
		||||
              .upscale {
 | 
			
		||||
                height 260px
 | 
			
		||||
                width 100%
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              &:hover {
 | 
			
		||||
                .remove {
 | 
			
		||||
                  display block
 | 
			
		||||
                }
 | 
			
		||||
              .remove {
 | 
			
		||||
                position absolute
 | 
			
		||||
                right 5px
 | 
			
		||||
                top 5px
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -824,7 +824,7 @@ const reGenerate = function () {
 | 
			
		||||
    icon: loginUser.value.avatar,
 | 
			
		||||
    content: md.render(text)
 | 
			
		||||
  });
 | 
			
		||||
  socket.value.send(previousText);
 | 
			
		||||
  socket.value.send(previousText.value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const chatName = ref('')
 | 
			
		||||
 
 | 
			
		||||
@@ -504,7 +504,7 @@ import Clipboard from "clipboard";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import {useRouter} from "vue-router";
 | 
			
		||||
import {getSessionId} from "@/store/session";
 | 
			
		||||
import {removeArrayItem} from "@/utils/libs";
 | 
			
		||||
import {isMobile, removeArrayItem} from "@/utils/libs";
 | 
			
		||||
 | 
			
		||||
const listBoxHeight = ref(window.innerHeight - 40)
 | 
			
		||||
const mjBoxHeight = ref(window.innerHeight - 150)
 | 
			
		||||
@@ -560,7 +560,7 @@ const params = ref({
 | 
			
		||||
  rate: rates[0].value,
 | 
			
		||||
  model: models[0].value,
 | 
			
		||||
  chaos: 0,
 | 
			
		||||
  stylize: 100,
 | 
			
		||||
  stylize: 0,
 | 
			
		||||
  seed: 0,
 | 
			
		||||
  img_arr: [],
 | 
			
		||||
  raw: false,
 | 
			
		||||
@@ -584,6 +584,10 @@ const imgCalls = ref(0)
 | 
			
		||||
const loading = ref(false)
 | 
			
		||||
const userId = ref(0)
 | 
			
		||||
 | 
			
		||||
if (isMobile()) {
 | 
			
		||||
  router.replace("/mobile/mj")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rewritePrompt = () => {
 | 
			
		||||
  loading.value = true
 | 
			
		||||
  httpPost("/api/prompt/rewrite", {"prompt": params.value.prompt}).then(res => {
 | 
			
		||||
 
 | 
			
		||||
@@ -377,6 +377,7 @@ const sendMessage = () => {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (prompt.value.trim().length === 0) {
 | 
			
		||||
    showToast("请输入需要 AI 回答的问题")
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -417,7 +418,7 @@ const reGenerate = () => {
 | 
			
		||||
    icon: loginUser.value.avatar,
 | 
			
		||||
    content: renderInputText(text)
 | 
			
		||||
  });
 | 
			
		||||
  socket.value.send(text);
 | 
			
		||||
  socket.value.send(previousText.value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const showShare = ref(false)
 | 
			
		||||
 
 | 
			
		||||
@@ -140,7 +140,7 @@
 | 
			
		||||
                   image-size="80"
 | 
			
		||||
                   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">
 | 
			
		||||
            <div class="job-item">
 | 
			
		||||
              <el-image
 | 
			
		||||
@@ -168,43 +168,17 @@
 | 
			
		||||
              </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>
 | 
			
		||||
                <van-grid :gutter="0" :column-num="4">
 | 
			
		||||
                  <van-grid-item><a @click="upscale(1, item)" class="opt-btn">U1</a></van-grid-item>
 | 
			
		||||
                  <van-grid-item><a @click="upscale(2, item)" class="opt-btn">U2</a></van-grid-item>
 | 
			
		||||
                  <van-grid-item><a @click="upscale(3, item)" class="opt-btn">U3</a></van-grid-item>
 | 
			
		||||
                  <van-grid-item><a @click="upscale(4, item)" class="opt-btn">U4</a></van-grid-item>
 | 
			
		||||
                  <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>
 | 
			
		||||
                  <van-grid-item><a @click="variation(3, item)" class="opt-btn">V3</a></van-grid-item>
 | 
			
		||||
                  <van-grid-item><a @click="variation(4, item)" class="opt-btn">V4</a></van-grid-item>
 | 
			
		||||
                </van-grid>
 | 
			
		||||
              </div>
 | 
			
		||||
 | 
			
		||||
              <div class="remove">
 | 
			
		||||
@@ -236,7 +210,7 @@ import {getSessionId} from "@/store/session";
 | 
			
		||||
import {checkSession} from "@/action/session";
 | 
			
		||||
import Clipboard from "clipboard";
 | 
			
		||||
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 activeColspan = ref([""])
 | 
			
		||||
@@ -263,7 +237,7 @@ const params = ref({
 | 
			
		||||
  rate: rates[0].value,
 | 
			
		||||
  model: models[0].value,
 | 
			
		||||
  chaos: 0,
 | 
			
		||||
  stylize: 100,
 | 
			
		||||
  stylize: 0,
 | 
			
		||||
  seed: 0,
 | 
			
		||||
  img_arr: [],
 | 
			
		||||
  raw: false,
 | 
			
		||||
@@ -356,7 +330,7 @@ const fetchRunningJobs = (userId) => {
 | 
			
		||||
      if (jobs[i].progress === -1) {
 | 
			
		||||
        showNotify({
 | 
			
		||||
          message: `任务执行失败:${jobs[i]['err_msg']}`,
 | 
			
		||||
          type: 'error',
 | 
			
		||||
          type: 'danger',
 | 
			
		||||
        })
 | 
			
		||||
        imgCalls.value += 1
 | 
			
		||||
        continue
 | 
			
		||||
@@ -439,10 +413,10 @@ const generate = () => {
 | 
			
		||||
  params.value.session_id = getSessionId()
 | 
			
		||||
  params.value.img_arr = imgList.value.map(img => img.url)
 | 
			
		||||
  httpPost("/api/mj/image", params.value).then(() => {
 | 
			
		||||
    ElMessage.success("绘画任务推送成功,请耐心等待任务执行...")
 | 
			
		||||
    showToast("绘画任务推送成功,请耐心等待任务执行")
 | 
			
		||||
    imgCalls.value -= 1
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("任务推送失败:" + e.message)
 | 
			
		||||
    showFailToast("任务推送失败:" + e.message)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user