mirror of
				https://github.com/yangjian102621/geekai.git
				synced 2025-11-04 16:23:42 +08:00 
			
		
		
		
	feat: image-wall page for mobile is ready
This commit is contained in:
		@@ -40,8 +40,10 @@ import {
 | 
			
		||||
    Sticky,
 | 
			
		||||
    SwipeCell,
 | 
			
		||||
    Switch,
 | 
			
		||||
    Tab,
 | 
			
		||||
    Tabbar,
 | 
			
		||||
    TabbarItem,
 | 
			
		||||
    Tabs,
 | 
			
		||||
    Tag,
 | 
			
		||||
    TextEllipsis,
 | 
			
		||||
    Uploader
 | 
			
		||||
@@ -93,6 +95,8 @@ app.use(Circle);
 | 
			
		||||
app.use(Loading);
 | 
			
		||||
app.use(Lazyload);
 | 
			
		||||
app.use(ImagePreview);
 | 
			
		||||
app.use(Tab);
 | 
			
		||||
app.use(Tabs);
 | 
			
		||||
app.use(router).use(ElementPlus).mount('#app')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -183,9 +183,9 @@ const routes = [
 | 
			
		||||
                component: () => import('@/views/mobile/Profile.vue'),
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                path: '/mobile/apps',
 | 
			
		||||
                name: 'mobile-app',
 | 
			
		||||
                component: () => import('@/views/mobile/ChatApps.vue'),
 | 
			
		||||
                path: '/mobile/img-wall',
 | 
			
		||||
                name: 'mobile-img-wall',
 | 
			
		||||
                component: () => import('@/views/mobile/ImgWall.vue'),
 | 
			
		||||
            },
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -1,72 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="mobile-setting container">
 | 
			
		||||
    <van-nav-bar :title="title"/>
 | 
			
		||||
 | 
			
		||||
    <div class="content">
 | 
			
		||||
      <van-empty description="功能正在开发中"/>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {onMounted, ref} from "vue";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import {showFailToast, showSuccessToast} from "vant";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
 | 
			
		||||
const title = ref('图片创作广场')
 | 
			
		||||
const form = ref({
 | 
			
		||||
  chat_config: {
 | 
			
		||||
    api_keys: {OpenAI: "", Azure: "", ChatGLM: ""}
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
const showPicker = ref(false)
 | 
			
		||||
const models = ref([])
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  // 获取最新用户信息
 | 
			
		||||
  httpGet('/api/user/profile').then(res => {
 | 
			
		||||
    form.value = res.data
 | 
			
		||||
    form.value.chat_config.api_keys = res.data.chat_config.api_keys ?? {OpenAI: "", Azure: "", ChatGLM: ""}
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    showFailToast('获取用户信息失败')
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 加载系统配置
 | 
			
		||||
  httpGet('/api/admin/config/get?key=system').then(res => {
 | 
			
		||||
    const mds = res.data.models;
 | 
			
		||||
    mds.forEach(item => {
 | 
			
		||||
      models.value.push({text: item, value: item})
 | 
			
		||||
    })
 | 
			
		||||
  }).catch(e => {
 | 
			
		||||
    ElMessage.error("加载系统配置失败: " + e.message)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const selectModel = (item) => {
 | 
			
		||||
  showPicker.value = false
 | 
			
		||||
  form.value.chat_config.model = item.selectedValues[0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const save = () => {
 | 
			
		||||
  httpPost('/api/user/profile/update', form.value).then(() => {
 | 
			
		||||
    showSuccessToast('保存成功')
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    showFailToast('保存失败')
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.mobile-setting {
 | 
			
		||||
  .content {
 | 
			
		||||
    padding-top 60px
 | 
			
		||||
 | 
			
		||||
    .van-field__label {
 | 
			
		||||
      width 100px
 | 
			
		||||
      text-align right
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
      <van-tabbar route v-model="active" @change="onChange">
 | 
			
		||||
        <van-tabbar-item to="/mobile/chat" name="home" icon="chat-o">对话</van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/mj" name="imageMj" icon="photo-o">绘图</van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/apps" name="apps" icon="apps-o">广场</van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/img-wall" name="apps" icon="apps-o">广场</van-tabbar-item>
 | 
			
		||||
        <van-tabbar-item to="/mobile/profile" name="profile" icon="user-o">我的</van-tabbar-item>
 | 
			
		||||
      </van-tabbar>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -269,15 +269,6 @@ onMounted(() => {
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    router.push('/login')
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const clipboard = new Clipboard('.copy-prompt');
 | 
			
		||||
  clipboard.on('success', () => {
 | 
			
		||||
    ElMessage.success("复制成功!");
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  clipboard.on('error', () => {
 | 
			
		||||
    ElMessage.error('复制失败!');
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const heartbeatHandle = ref(null)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										132
									
								
								web/src/views/mobile/ImgWall.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								web/src/views/mobile/ImgWall.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="img-wall container">
 | 
			
		||||
    <van-nav-bar :title="title"/>
 | 
			
		||||
 | 
			
		||||
    <div class="content">
 | 
			
		||||
      <van-tabs v-model:active="activeName">
 | 
			
		||||
        <van-tab title="MidJourney" name="mj">
 | 
			
		||||
          <van-list
 | 
			
		||||
              v-model:error="data['mj'].error"
 | 
			
		||||
              v-model:loading="data['mj'].loading"
 | 
			
		||||
              :finished="data['mj'].finished"
 | 
			
		||||
              error-text="请求失败,点击重新加载"
 | 
			
		||||
              finished-text="没有更多了"
 | 
			
		||||
              @load="onLoad"
 | 
			
		||||
          >
 | 
			
		||||
            <van-cell v-for="item in data['mj'].data" :key="item.id">
 | 
			
		||||
              <van-image :src="item['img_thumb']" @click="showPrompt(item)" fit="cover"/>
 | 
			
		||||
            </van-cell>
 | 
			
		||||
          </van-list>
 | 
			
		||||
        </van-tab>
 | 
			
		||||
        <van-tab title="StableDiffusion" name="sd">
 | 
			
		||||
          <van-list
 | 
			
		||||
              v-model:error="data['sd'].error"
 | 
			
		||||
              v-model:loading="data['sd'].loading"
 | 
			
		||||
              :finished="data['sd'].finished"
 | 
			
		||||
              error-text="请求失败,点击重新加载"
 | 
			
		||||
              finished-text="没有更多了"
 | 
			
		||||
              @load="onLoad"
 | 
			
		||||
          >
 | 
			
		||||
            <van-cell v-for="item in data['sd'].data" :key="item.id">
 | 
			
		||||
              <van-image :src="item['img_thumb']" @click="showPrompt(item)" fit="cover"/>
 | 
			
		||||
            </van-cell>
 | 
			
		||||
          </van-list>
 | 
			
		||||
        </van-tab>
 | 
			
		||||
        <van-tab title="DALLE3" name="dalle3">
 | 
			
		||||
          <van-empty description="功能正在开发中"/>
 | 
			
		||||
        </van-tab>
 | 
			
		||||
      </van-tabs>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import {onMounted, ref} from "vue";
 | 
			
		||||
import {httpGet, httpPost} from "@/utils/http";
 | 
			
		||||
import {showDialog, showFailToast, showSuccessToast} from "vant";
 | 
			
		||||
import {ElMessage} from "element-plus";
 | 
			
		||||
 | 
			
		||||
const title = ref('图片创作广场')
 | 
			
		||||
const activeName = ref("mj")
 | 
			
		||||
const data = ref({
 | 
			
		||||
  "mj": {
 | 
			
		||||
    loading: false,
 | 
			
		||||
    finished: false,
 | 
			
		||||
    error: false,
 | 
			
		||||
    page: 1,
 | 
			
		||||
    pageSize: 12,
 | 
			
		||||
    url: "/api/mj/jobs",
 | 
			
		||||
    data: []
 | 
			
		||||
  },
 | 
			
		||||
  "sd": {
 | 
			
		||||
    loading: false,
 | 
			
		||||
    finished: false,
 | 
			
		||||
    error: false,
 | 
			
		||||
    page: 1,
 | 
			
		||||
    pageSize: 12,
 | 
			
		||||
    url: "/api/sd/jobs",
 | 
			
		||||
    data: []
 | 
			
		||||
  },
 | 
			
		||||
  "dalle3": {
 | 
			
		||||
    loading: false,
 | 
			
		||||
    finished: false,
 | 
			
		||||
    error: false,
 | 
			
		||||
    page: 1,
 | 
			
		||||
    pageSize: 12,
 | 
			
		||||
    url: "/api/dalle3/jobs",
 | 
			
		||||
    data: []
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const onLoad = () => {
 | 
			
		||||
  const d = data.value[activeName.value]
 | 
			
		||||
  httpGet(`${d.url}?status=1&page=${d.page}&page_size=${d.pageSize}&publish=true`).then(res => {
 | 
			
		||||
    d.loading = false
 | 
			
		||||
    if (res.data.length === 0) {
 | 
			
		||||
      d.finished = true
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 生成缩略图
 | 
			
		||||
    const imageList = res.data
 | 
			
		||||
    for (let i = 0; i < imageList.length; i++) {
 | 
			
		||||
      imageList[i]["img_thumb"] = imageList[i]["img_url"] + "?imageView2/4/w/300/h/0/q/75"
 | 
			
		||||
    }
 | 
			
		||||
    if (imageList.length < d.pageSize) {
 | 
			
		||||
      d.finished = true
 | 
			
		||||
    }
 | 
			
		||||
    if (d.data.length === 0) {
 | 
			
		||||
      d.data = imageList
 | 
			
		||||
    } else {
 | 
			
		||||
      d.data = d.data.concat(imageList)
 | 
			
		||||
    }
 | 
			
		||||
    d.page += 1
 | 
			
		||||
  }).catch(() => {
 | 
			
		||||
    d.error = true
 | 
			
		||||
    showFailToast("加载图片数据失败")
 | 
			
		||||
  })
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showPrompt = (item) => {
 | 
			
		||||
  showDialog({
 | 
			
		||||
    title: "绘画提示词",
 | 
			
		||||
    message: item.prompt,
 | 
			
		||||
  }).then(() => {
 | 
			
		||||
    // on close
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus">
 | 
			
		||||
.img-wall {
 | 
			
		||||
  .content {
 | 
			
		||||
    padding-top 60px
 | 
			
		||||
 | 
			
		||||
    .van-cell__value {
 | 
			
		||||
      .van-image {
 | 
			
		||||
        width 100%
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
		Reference in New Issue
	
	Block a user