generated from duanshuwen/webapp-vue-frontend
feat: 接口交互的调整
This commit is contained in:
@@ -14,7 +14,9 @@ const KeepAliveList = ref([])
|
|||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
const keepAlive = to?.meta?.keepAlive
|
const keepAlive = to?.meta?.keepAlive
|
||||||
Session.set('token', to.query.token)
|
if (to.query.token) {
|
||||||
|
Session.set('token', to.query.token)
|
||||||
|
}
|
||||||
|
|
||||||
if (!router.hasRoute(to.name)) {
|
if (!router.hasRoute(to.name)) {
|
||||||
router.push('/home')
|
router.push('/home')
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import request from '@common/ajax';
|
import request from '@common/ajax'
|
||||||
import type { Response } from './types';
|
import type { Response } from './types'
|
||||||
|
|
||||||
export interface GeneratorPhotoTask {
|
export interface GeneratorPhotoTask {
|
||||||
pageNum: number;
|
pageNum: number
|
||||||
pageSize: number;
|
pageSize: number
|
||||||
taskStatus: string;
|
taskStatus?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GeneratorPhotoTaskListItem {
|
export interface GeneratorPhotoTaskListItem {
|
||||||
records: PhotoTaskRecordsItem[];
|
records: PhotoTaskRecordsItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PhotoTaskRecordsItem {
|
export interface PhotoTaskRecordsItem {
|
||||||
sceneName: string;
|
sceneName: string
|
||||||
createTime: string;
|
createTime: string
|
||||||
taskStatus: string;
|
taskStatus: string
|
||||||
generatorPhoto: string;
|
generatorPhoto: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generatorPhotoTaskList = (params: GeneratorPhotoTask) => {
|
export const generatorPhotoTaskList = (params: GeneratorPhotoTask) => {
|
||||||
return request<Response<GeneratorPhotoTaskListItem[]>>({
|
return request<Response<GeneratorPhotoTaskListItem>>({
|
||||||
url: '/aigc/generatorPhotoTaskList',
|
url: '/aigc/generatorPhotoTaskList',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params,
|
params
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { tansParams } from '@utils/tansParams'
|
|||||||
import { getAccessToken } from '@/constant/token'
|
import { getAccessToken } from '@/constant/token'
|
||||||
|
|
||||||
// 获取.env中的服务地址
|
// 获取.env中的服务地址
|
||||||
const { VITE_BASE_API, VITE_ENV } = import.meta.env
|
const VITE_BASE_API = (import.meta.env.VITE_BASE_API || '').trim()
|
||||||
|
const VITE_ENV = (import.meta.env.VITE_ENV || '').trim()
|
||||||
console.log('🚀 ~ VITE_ENV:', VITE_ENV)
|
console.log('🚀 ~ VITE_ENV:', VITE_ENV)
|
||||||
console.log('🚀 ~ VITE_BASE_API:', VITE_BASE_API)
|
console.log('🚀 ~ VITE_BASE_API:', VITE_BASE_API)
|
||||||
|
|
||||||
@@ -18,21 +19,31 @@ const instance = axios.create({
|
|||||||
|
|
||||||
// 添加拦截器
|
// 添加拦截器
|
||||||
instance.interceptors.request.use((config) => {
|
instance.interceptors.request.use((config) => {
|
||||||
const token = getAccessToken();
|
const token = getAccessToken()
|
||||||
config.headers['Authorization'] = `Bearer ${token}`
|
console.log('🚀 ~ Request Token:', token)
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
// 兼容不同版本的 axios 设置 header
|
||||||
|
config.headers = config.headers || {}
|
||||||
|
config.headers.Authorization = `Bearer ${token}`
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🚀 ~ Final Headers:', config.headers)
|
||||||
|
|
||||||
// get请求映射params参数
|
// get请求映射params参数
|
||||||
if (config.method === 'get' && config.params) {
|
const method = (config.method || '').toLowerCase()
|
||||||
|
if (method === 'get' && config.params) {
|
||||||
let url = config.url + '?' + tansParams(config.params)
|
let url = config.url + '?' + tansParams(config.params)
|
||||||
console.log('🚀 ~ url:', url)
|
|
||||||
|
|
||||||
url = url.slice(0, -1)
|
url = url.slice(0, -1)
|
||||||
config.params = {}
|
config.params = {}
|
||||||
config.url = url
|
config.url = url
|
||||||
}
|
}
|
||||||
|
|
||||||
// post/put/patch 请求将 params 映射到 body(data)
|
// post/put/patch 请求将 params 映射到 body(data)
|
||||||
if ((config.method === 'post' || config.method === 'put' || config.method === 'patch') && config.params) {
|
if (
|
||||||
|
(method === 'post' || method === 'put' || method === 'patch') &&
|
||||||
|
config.params
|
||||||
|
) {
|
||||||
config.data = config.params
|
config.data = config.params
|
||||||
config.params = {}
|
config.params = {}
|
||||||
}
|
}
|
||||||
@@ -43,9 +54,16 @@ instance.interceptors.request.use((config) => {
|
|||||||
// 添加响应拦截器
|
// 添加响应拦截器
|
||||||
instance.interceptors.response.use(
|
instance.interceptors.response.use(
|
||||||
(res) => {
|
(res) => {
|
||||||
return Promise.resolve(res.data.data)
|
console.log('🚀 ~ res:', res)
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
return Promise.resolve(res.data.data)
|
||||||
|
} else {
|
||||||
|
console.error('业务报错:', res.data.msg)
|
||||||
|
return Promise.reject(res.data)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
console.error('网络或服务器报错:', error)
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Session } from '@/utils/storage'
|
import { Session } from '@/utils/storage'
|
||||||
|
|
||||||
export const getAccessToken = () => {
|
export const getAccessToken = () => {
|
||||||
const token = Session.getToken()
|
const token = Session.getToken()
|
||||||
// const token = 'H7rzcCtsvPqwc0ecDnBT9mlhOqHsWDyS6nXkRjnd1oAgOQqlEhsCy4OZPQ8YyVBj57pmNpwSXJYcd6Ox4YB-W1pHr4aTM9_d6nYJ3OrbRB9f0J7kP9FbbviN609nGO0m'
|
// const token = 'AqmeApe592cOm__Xx8B8NAwJuS_3l8T9GLq9jYqxGSPojQUjmMLbgkG-h5OijP6OdTxwtFm-4ZlShqKYS_pr1OJ1ItZkbRKZjGZh0BIokJ0QIxcOkMQOAf9_XudBedvT'
|
||||||
return token;
|
return token
|
||||||
}
|
}
|
||||||
@@ -44,13 +44,24 @@ export const Local = {
|
|||||||
export const Session = {
|
export const Session = {
|
||||||
// 设置临时缓存
|
// 设置临时缓存
|
||||||
set(key: string, val: any) {
|
set(key: string, val: any) {
|
||||||
window.sessionStorage.setItem(key, JSON.stringify(val))
|
if (val === undefined || val === null) {
|
||||||
|
window.sessionStorage.removeItem(key)
|
||||||
|
} else {
|
||||||
|
window.sessionStorage.setItem(key, JSON.stringify(val))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取临时缓存
|
// 获取临时缓存
|
||||||
get(key: string) {
|
get(key: string) {
|
||||||
let json = <string>window.sessionStorage.getItem(key)
|
let json = <string>window.sessionStorage.getItem(key)
|
||||||
return JSON.parse(json)
|
if (!json || json === 'undefined' || json === 'null') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return JSON.parse(json)
|
||||||
|
} catch (e) {
|
||||||
|
return json
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 移除临时缓存
|
// 移除临时缓存
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<!-- 顶部栏 -->
|
<!-- 顶部栏 -->
|
||||||
<TopNavBar title="生成中" color="white" :showHistory="true" @back="onBack" @history="onHistory" />
|
<TopNavBar
|
||||||
|
title="生成中"
|
||||||
|
color="white"
|
||||||
|
:showHistory="true"
|
||||||
|
@back="onBack"
|
||||||
|
@history="onHistory"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 中间内容 -->
|
<!-- 中间内容 -->
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -9,17 +15,13 @@
|
|||||||
|
|
||||||
<div class="desc">
|
<div class="desc">
|
||||||
<div class="main">预计等待5~7分钟</div>
|
<div class="main">预计等待5~7分钟</div>
|
||||||
<div class="sub">
|
<div class="sub">WHEE云处理中,特效生成需要一定时间,请耐心等待。</div>
|
||||||
WHEE云处理中,特效生成需要一定时间,请耐心等待。
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部按钮 -->
|
<!-- 底部按钮 -->
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<button class="btn primary" @click="handleGenerate">
|
<button class="btn primary" @click="handleGenerate">生成新的特效</button>
|
||||||
生成新的特效
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn outline" @click="handleHistory">
|
<button class="btn outline" @click="handleHistory">
|
||||||
<span>查看生成记录</span>
|
<span>查看生成记录</span>
|
||||||
@@ -28,30 +30,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts" name="generate">
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import TopNavBar from '../components/TopNavBar.vue';
|
import TopNavBar from '../components/TopNavBar.vue'
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
|
|
||||||
const handleGenerate = () => {
|
const handleGenerate = () => {
|
||||||
console.log('重新生成')
|
console.log('重新生成')
|
||||||
|
router.back()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleHistory = () => {
|
const handleHistory = () => {
|
||||||
console.log('查看记录')
|
console.log('查看记录')
|
||||||
router.push('/history');
|
router.push('/history')
|
||||||
}
|
}
|
||||||
|
|
||||||
const onBack = () => {
|
const onBack = () => {
|
||||||
router.back();
|
router.back()
|
||||||
};
|
}
|
||||||
|
|
||||||
const onHistory = () => {
|
const onHistory = () => {
|
||||||
handleHistory();
|
handleHistory()
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -86,7 +88,7 @@ const onHistory = () => {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
text-stroke: 1px rgba(255, 255, 255, 0.2);
|
text-stroke: 1px rgba(255, 255, 255, 0.2);
|
||||||
background: linear-gradient(45deg, #A6E0C6 0%, #7DBBF6 100%);
|
background: linear-gradient(45deg, #a6e0c6 0%, #7dbbf6 100%);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
-webkit-text-stroke: 1px rgba(255, 255, 255, 0.2);
|
-webkit-text-stroke: 1px rgba(255, 255, 255, 0.2);
|
||||||
@@ -120,7 +122,7 @@ const onHistory = () => {
|
|||||||
.main {
|
.main {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
color: #FFFFFF;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sub {
|
.sub {
|
||||||
@@ -149,7 +151,7 @@ const onHistory = () => {
|
|||||||
|
|
||||||
/* 渐变按钮 */
|
/* 渐变按钮 */
|
||||||
.primary {
|
.primary {
|
||||||
background: linear-gradient(90deg, #D9FBC8 0%, #8BE2FF 100%);
|
background: linear-gradient(90deg, #d9fbc8 0%, #8be2ff 100%);
|
||||||
color: #000;
|
color: #000;
|
||||||
border: none;
|
border: none;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -170,18 +172,16 @@ const onHistory = () => {
|
|||||||
|
|
||||||
/* 内层内容 */
|
/* 内层内容 */
|
||||||
.outline::before {
|
.outline::before {
|
||||||
content: "";
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
background: linear-gradient(90deg, #D9FBC8 0%, #8BE2FF 100%);
|
background: linear-gradient(90deg, #d9fbc8 0%, #8be2ff 100%);
|
||||||
padding: 1.5px;
|
padding: 1.5px;
|
||||||
/* 控制边框粗细 */
|
/* 控制边框粗细 */
|
||||||
|
|
||||||
/* 核心:挖空中间 */
|
/* 核心:挖空中间 */
|
||||||
-webkit-mask:
|
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||||
linear-gradient(#fff 0 0) content-box,
|
|
||||||
linear-gradient(#fff 0 0);
|
|
||||||
-webkit-mask-composite: xor;
|
-webkit-mask-composite: xor;
|
||||||
mask-composite: exclude;
|
mask-composite: exclude;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<TopNavBar title="最近任务" color="white" :showHistory="false" @back="onBack" />
|
<TopNavBar
|
||||||
|
title="最近任务"
|
||||||
|
color="white"
|
||||||
|
:showHistory="false"
|
||||||
|
@back="onBack"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div v-for="(item, index) in list" :key="`${item.name}-${index}`" class="card">
|
<div
|
||||||
|
v-for="(item, index) in list"
|
||||||
|
:key="`${item.name}-${index}`"
|
||||||
|
class="card"
|
||||||
|
>
|
||||||
<!-- 排队中 -->
|
<!-- 排队中 -->
|
||||||
<template v-if="item.status == 0">
|
<template v-if="item.status == 0">
|
||||||
<div class="left queued-box">排队中</div>
|
<div class="left queued-box">排队中</div>
|
||||||
@@ -25,10 +34,15 @@
|
|||||||
<div class="name">{{ item.name }}</div>
|
<div class="name">{{ item.name }}</div>
|
||||||
|
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div class="bar" :style="{ width: (item.progress || 0) + '%' }"></div>
|
<div
|
||||||
|
class="bar"
|
||||||
|
:style="{ width: (item.progress || 0) + '%' }"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-text">生成中 {{ item.progress ? item.progress + '%' : '' }}</div>
|
<div class="status-text">
|
||||||
|
生成中 {{ item.progress ? item.progress + '%' : '' }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -56,20 +70,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="tip"> {{ list.length == 0 ? '暂无记录' : `仅保留最近20天生成记录` }}</div>
|
<div class="tip">
|
||||||
|
{{ list.length == 0 ? '暂无记录' : `仅保留最近20天生成记录` }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted } from 'vue';
|
import { onMounted, reactive } from 'vue'
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import TopNavBar from '../components/TopNavBar.vue';
|
import TopNavBar from '../components/TopNavBar.vue'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { generatorPhotoTaskList } from '@api';
|
import { generatorPhotoTaskList } from '@api'
|
||||||
import { closeToast, showLoadingToast } from 'vant';
|
import { closeToast, showLoadingToast } from 'vant'
|
||||||
import 'vant/lib/toast/style';
|
import 'vant/lib/toast/style'
|
||||||
|
|
||||||
interface TaskItem {
|
interface TaskItem {
|
||||||
name: string
|
name: string
|
||||||
@@ -79,44 +95,58 @@ interface TaskItem {
|
|||||||
time?: string
|
time?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const list: TaskItem[] = []
|
const list = reactive<TaskItem[]>([])
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
|
|
||||||
const onBack = () => {
|
const onBack = () => {
|
||||||
router.back();
|
router.back()
|
||||||
};
|
|
||||||
|
|
||||||
const lookPicture = (item: TaskItem) => {
|
|
||||||
console.log('查看图片');
|
|
||||||
const encoded = encodeURIComponent(JSON.stringify(item));
|
|
||||||
router.push({ path: '/prepicture', query: { data: encoded } });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTaskList = () => {
|
const lookPicture = (item: TaskItem) => {
|
||||||
showLoadingToast('加载中...');
|
console.log('查看图片')
|
||||||
generatorPhotoTaskList({ pageNum: 1, pageSize: 20 }).then(res => {
|
const encoded = encodeURIComponent(JSON.stringify(item))
|
||||||
closeToast();
|
router.push({ path: '/prepicture', query: { data: encoded } })
|
||||||
if (res.code === 0) {
|
}
|
||||||
const data = res.data || [];
|
|
||||||
list.splice(0, list.length, ...data.map(item => {
|
const getTaskList = async () => {
|
||||||
let statusNum: number = item.taskStatus as unknown as number; // 先尝试直接转换为数字
|
showLoadingToast('加载中...')
|
||||||
|
try {
|
||||||
|
const res = await generatorPhotoTaskList({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
taskStatus: '1'
|
||||||
|
})
|
||||||
|
console.log('🚀 ~ generatorPhotoTaskList res:', res)
|
||||||
|
closeToast()
|
||||||
|
|
||||||
|
// 因为拦截器返回了 res.data.data,所以这里的 res 直接就是数据内容
|
||||||
|
// 根据后端返回结构,这里 res 应该是 { records: [] }
|
||||||
|
const data = res?.records || []
|
||||||
|
|
||||||
|
list.splice(
|
||||||
|
0,
|
||||||
|
list.length,
|
||||||
|
...data.map((item: any) => {
|
||||||
|
let statusNum: number = Number(item.taskStatus)
|
||||||
return {
|
return {
|
||||||
name: item.sceneName,
|
name: item.sceneName,
|
||||||
status: statusNum as 0 | 1 | 2 | 3,
|
status: statusNum as 0 | 1 | 2 | 3,
|
||||||
progress: statusNum === 1 ? 50 : undefined, // 若后端有真实进度请替换
|
progress: statusNum === 1 ? 50 : undefined,
|
||||||
cover: item.generatorPhoto,
|
cover: item.generatorPhoto,
|
||||||
time: item.createTime,
|
time: item.createTime
|
||||||
} as TaskItem;
|
} as TaskItem
|
||||||
}));
|
})
|
||||||
}
|
)
|
||||||
});
|
} catch (error) {
|
||||||
|
console.error('🚀 ~ getTaskList error details:', error)
|
||||||
|
closeToast()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTaskList();
|
getTaskList()
|
||||||
});
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,24 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<transition name="fade" mode="out-in">
|
<transition name="fade" mode="out-in">
|
||||||
<img :key="activeScene.sceneName" :src="activeScene.sceneCoverUrl" class="bg-image" />
|
<img
|
||||||
|
:key="activeScene.sceneName"
|
||||||
|
:src="activeScene.sceneCoverUrl"
|
||||||
|
class="bg-image"
|
||||||
|
/>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<div class="gradient-overlay"></div>
|
<div class="gradient-overlay"></div>
|
||||||
|
|
||||||
<TopNavBar title="" color="white" :showHistory="true" @back="onBack" @history="onHistory" />
|
<TopNavBar
|
||||||
|
title=""
|
||||||
|
color="white"
|
||||||
|
:showHistory="true"
|
||||||
|
@back="onBack"
|
||||||
|
@history="onHistory"
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="content-layer">
|
<div class="content-layer">
|
||||||
<div class="style-tabs">
|
<div class="style-tabs">
|
||||||
<div v-for="tab in styles" :key="tab.id" :class="['tab-item', { active: activeStyleId === tab.id }]"
|
<div
|
||||||
@click="handleStyleChange(tab.id)">
|
v-for="tab in styles"
|
||||||
|
:key="tab.id"
|
||||||
|
:class="['tab-item', { active: activeStyleId === tab.id }]"
|
||||||
|
@click="handleStyleChange(tab.id)"
|
||||||
|
>
|
||||||
{{ tab.name }}
|
{{ tab.name }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="scene-list-container">
|
<div class="scene-list-container">
|
||||||
<div v-for="(item, index) in currentScenes" :key="`${activeStyleId}-${index}`"
|
<div
|
||||||
:class="['scene-card', { active: activeSceneIndex === index }]" @click="activeSceneIndex = index">
|
v-for="(item, index) in currentScenes"
|
||||||
|
:key="`${activeStyleId}-${index}`"
|
||||||
|
:class="['scene-card', { active: activeSceneIndex === index }]"
|
||||||
|
@click="activeSceneIndex = index"
|
||||||
|
>
|
||||||
<img :src="item.sceneCoverUrl" class="thumb-img" />
|
<img :src="item.sceneCoverUrl" class="thumb-img" />
|
||||||
<div class="scene-name">{{ item.sceneName }}</div>
|
<div class="scene-name">{{ item.sceneName }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -35,92 +53,108 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 协议提示 -->
|
<!-- 协议提示 -->
|
||||||
<van-popup v-model:show="showAgree" round :close-on-click-overlay="false"
|
<van-popup
|
||||||
:style="{ padding: '30px 24px', width: '80%' }">
|
v-model:show="showAgree"
|
||||||
<AgreementTip @cancel="cancelAgree" @confirm="onAgree" @view-rule="onViewRule" />
|
round
|
||||||
|
:close-on-click-overlay="false"
|
||||||
|
:style="{ padding: '30px 24px', width: '80%' }"
|
||||||
|
>
|
||||||
|
<AgreementTip
|
||||||
|
@cancel="cancelAgree"
|
||||||
|
@confirm="onAgree"
|
||||||
|
@view-rule="onViewRule"
|
||||||
|
/>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
|
|
||||||
<!-- 选图说明 -->
|
<!-- 选图说明 -->
|
||||||
<van-popup v-model:show="showGuide" round position="bottom" closeable close-icon-position="top-left">
|
<van-popup
|
||||||
|
v-model:show="showGuide"
|
||||||
|
round
|
||||||
|
position="bottom"
|
||||||
|
closeable
|
||||||
|
close-icon-position="top-left"
|
||||||
|
>
|
||||||
<PhotoGuide @start="onStartSelect" />
|
<PhotoGuide @start="onStartSelect" />
|
||||||
</van-popup>
|
</van-popup>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts" name="home">
|
||||||
import { ref, computed, onMounted, reactive } from 'vue';
|
import { ref, computed, onMounted, reactive, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { Session } from '@/utils/storage'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import TopNavBar from '../components/TopNavBar.vue';
|
import TopNavBar from '../components/TopNavBar.vue'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import PhotoGuide from '../components/PhotoGuide.vue';
|
import PhotoGuide from '../components/PhotoGuide.vue'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import AgreementTip from '../components/AgreementTip.vue';
|
import AgreementTip from '../components/AgreementTip.vue'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { getAigcSceneList, AigcSceneListItem, AigcSceneStyleItem } from '@api';
|
import { getAigcSceneList, AigcSceneListItem, AigcSceneStyleItem } from '@api'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { createGeneratorPhotoTask } from '@api';
|
import { createGeneratorPhotoTask } from '@api'
|
||||||
import { showFailToast, showSuccessToast } from 'vant';
|
import { showFailToast, showSuccessToast } from 'vant'
|
||||||
import 'vant/lib/toast/style';
|
import 'vant/lib/toast/style'
|
||||||
|
|
||||||
// --- 测试数据 ---
|
// --- 测试数据 ---
|
||||||
const styles = [
|
const styles = [
|
||||||
{ id: 'real', name: '真实风格', sceneStyle: '0' },
|
{ id: 'real', name: '真实风格', sceneStyle: '0' },
|
||||||
{ id: 'comic', name: '漫画风格', sceneStyle: '1' }
|
{ id: 'comic', name: '漫画风格', sceneStyle: '1' }
|
||||||
];
|
]
|
||||||
|
|
||||||
const mockData = reactive({
|
const mockData = reactive({
|
||||||
real: [] as AigcSceneStyleItem[],
|
real: [] as AigcSceneStyleItem[],
|
||||||
comic: [] as AigcSceneStyleItem[]
|
comic: [] as AigcSceneStyleItem[]
|
||||||
});
|
})
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
// --- 状态 ---
|
// --- 状态 ---
|
||||||
const activeStyleId = ref<'real' | 'comic'>('real');
|
const activeStyleId = ref<'real' | 'comic'>('real')
|
||||||
const activeSceneIndex = ref(0);
|
const activeSceneIndex = ref(0)
|
||||||
const showGuide = ref(false);
|
const showGuide = ref(false)
|
||||||
|
|
||||||
const showAgree = ref(true);
|
const showAgree = ref(!Session.get('hasAgreedPrivacy'))
|
||||||
|
|
||||||
const cancelAgree = () => {
|
const cancelAgree = () => {
|
||||||
console.log("用户拒绝了协议");
|
console.log('用户拒绝了协议')
|
||||||
showAgree.value = false;
|
showAgree.value = false
|
||||||
if (window.wx && wx.miniProgram) {
|
const wx = (window as any).wx
|
||||||
wx.miniProgram.navigateBack();
|
if (wx && wx.miniProgram) {
|
||||||
|
wx.miniProgram.navigateBack()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const onAgree = () => {
|
const onAgree = () => {
|
||||||
console.log("用户同意了协议");
|
console.log('用户同意了协议')
|
||||||
showAgree.value = false;
|
showAgree.value = false
|
||||||
|
Session.set('hasAgreedPrivacy', true)
|
||||||
// 执行下一步选图逻辑
|
// 执行下一步选图逻辑
|
||||||
};
|
}
|
||||||
|
|
||||||
const onViewRule = () => {
|
const onViewRule = () => {
|
||||||
console.log("跳转到规则详情页");
|
console.log('跳转到规则详情页')
|
||||||
// 可以是打开另一个 popup 或者 router.push
|
// 可以是打开另一个 popup 或者 router.push
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
const onBack = () => {
|
const onBack = () => {
|
||||||
router.back();
|
router.back()
|
||||||
};
|
}
|
||||||
|
|
||||||
const onHistory = () => {
|
const onHistory = () => {
|
||||||
router.push('/history');
|
router.push('/history')
|
||||||
};
|
}
|
||||||
|
|
||||||
const generateAction = () => {
|
const generateAction = () => {
|
||||||
showGuide.value = true;
|
showGuide.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const onStartSelect = () => {
|
const onStartSelect = () => {
|
||||||
console.log("用户已阅读说明,开始打开相册逻辑...");
|
console.log('用户已阅读说明,开始打开相册逻辑...')
|
||||||
showGuide.value = false;
|
showGuide.value = false
|
||||||
// 这里写调用系统相册的代码
|
// 这里写调用系统相册的代码
|
||||||
uploadImage();
|
uploadImage()
|
||||||
};
|
}
|
||||||
|
|
||||||
// 调用上传
|
// 调用上传
|
||||||
const uploadImage = () => {
|
const uploadImage = () => {
|
||||||
@@ -133,73 +167,71 @@ const uploadImage = () => {
|
|||||||
// return
|
// return
|
||||||
|
|
||||||
/// 调用小程序上传接口
|
/// 调用小程序上传接口
|
||||||
if (window.wx && wx.miniProgram) {
|
const wx = (window as any).wx
|
||||||
|
if (wx && wx.miniProgram) {
|
||||||
wx.miniProgram.navigateTo({
|
wx.miniProgram.navigateTo({
|
||||||
url: '/pages-bridge/UploadImage'
|
url: '/pages-bridge/UploadImage'
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('hashchange', () => {
|
// 监听 URL 中的 imageUrl 参数(通常从小程序跳转回来时携带)
|
||||||
const imageUrl = getHashParam('imageUrl')
|
watch(
|
||||||
console.log('从 hash 中获取的 imageUrl:', imageUrl)
|
() => route.query.imageUrl,
|
||||||
if (imageUrl) {
|
(newUrl) => {
|
||||||
sendGeneratorPhotoTask(imageUrl)
|
if (newUrl && typeof newUrl === 'string' && newUrl !== 'error') {
|
||||||
}
|
console.log('检测到 hash 中的 imageUrl:', newUrl)
|
||||||
})
|
sendGeneratorPhotoTask(newUrl)
|
||||||
|
|
||||||
const getHashParam = (key) => {
|
// 处理完后清除 URL 参数,防止返回或刷新时重复触发
|
||||||
const hash = window.location.hash
|
const newQuery = { ...route.query }
|
||||||
console.log('hash URL:', hash)
|
delete newQuery.imageUrl
|
||||||
|
router.replace({ query: newQuery })
|
||||||
const queryStr = hash.split('?')[1] || ''
|
|
||||||
const params = queryStr.split('&')
|
|
||||||
|
|
||||||
for (let i = 0; i < params.length; i++) {
|
|
||||||
const [k, v] = params[i].split('=')
|
|
||||||
if (k === key) {
|
|
||||||
return decodeURIComponent(v || '')
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
return null
|
{ immediate: true }
|
||||||
}
|
)
|
||||||
|
|
||||||
/// 发送生成任务
|
/// 发送生成任务
|
||||||
const sendGeneratorPhotoTask = async (photoUrl: string) => {
|
const sendGeneratorPhotoTask = async (photoUrl: string) => {
|
||||||
const photoUrlList = [photoUrl];
|
const photoUrlList = [photoUrl]
|
||||||
try {
|
try {
|
||||||
const response = await createGeneratorPhotoTask({ photoUrlList: photoUrlList, sceneId: activeScene.value.sceneStyleId });
|
const response = await createGeneratorPhotoTask({
|
||||||
|
photoUrlList: photoUrlList,
|
||||||
|
sceneId: activeScene.value.sceneStyleId
|
||||||
|
})
|
||||||
if (response) {
|
if (response) {
|
||||||
showSuccessToast('生成任务创建成功!');
|
showSuccessToast('生成任务创建成功!')
|
||||||
router.push('/generate');
|
router.push('/generate')
|
||||||
} else {
|
} else {
|
||||||
showFailToast('生成任务创建失败,请重试。');
|
showFailToast('生成任务创建失败,请稍后再试。')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('创建生成任务时发生错误:', error);
|
console.error('创建生成任务时发生错误:', error)
|
||||||
showFailToast('创建生成任务时发生错误,请稍后再试。');
|
showFailToast('创建生成任务时发生错误,请稍后再试。')
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- 计算属性 ---
|
// --- 计算属性 ---
|
||||||
const currentScenes = computed(() => mockData[activeStyleId.value] || []);
|
const currentScenes = computed(() => mockData[activeStyleId.value] || [])
|
||||||
const activeScene = computed(() => currentScenes.value[activeSceneIndex.value] || {});
|
const activeScene = computed(
|
||||||
|
() => currentScenes.value[activeSceneIndex.value] || {}
|
||||||
|
)
|
||||||
|
|
||||||
// --- 方法 ---
|
// --- 方法 ---
|
||||||
const handleStyleChange = (id: 'real' | 'comic') => {
|
const handleStyleChange = (id: any) => {
|
||||||
activeStyleId.value = id;
|
activeStyleId.value = id
|
||||||
activeSceneIndex.value = 0;
|
activeSceneIndex.value = 0
|
||||||
};
|
}
|
||||||
|
|
||||||
// 数据请求
|
// 数据请求
|
||||||
const fetchSceneList = async () => {
|
const fetchSceneList = async () => {
|
||||||
const list: AigcSceneListItem[] = await getAigcSceneList();
|
const list: AigcSceneListItem[] = await getAigcSceneList()
|
||||||
const realArr: any[] = [];
|
const realArr: any[] = []
|
||||||
const comicArr: any[] = [];
|
const comicArr: any[] = []
|
||||||
|
|
||||||
list.forEach((scene) => {
|
list.forEach((scene) => {
|
||||||
const styles = scene.aigcSceneStyleList || [];
|
const styles = scene.aigcSceneStyleList || []
|
||||||
styles.forEach((s: AigcSceneStyleItem) => {
|
styles.forEach((s: AigcSceneStyleItem) => {
|
||||||
const styleItem: AigcSceneStyleItem = {
|
const styleItem: AigcSceneStyleItem = {
|
||||||
sceneName: scene.sceneName,
|
sceneName: scene.sceneName,
|
||||||
@@ -207,27 +239,25 @@ const fetchSceneList = async () => {
|
|||||||
sortIndex: scene.sortIndex,
|
sortIndex: scene.sortIndex,
|
||||||
sceneStyle: s.sceneStyle,
|
sceneStyle: s.sceneStyle,
|
||||||
sceneStyleId: s.sceneStyleId,
|
sceneStyleId: s.sceneStyleId,
|
||||||
sceneCoverUrl: s.sceneCoverUrl,
|
sceneCoverUrl: s.sceneCoverUrl
|
||||||
};
|
}
|
||||||
if (s.sceneStyle === '0') {
|
if (s.sceneStyle === '0') {
|
||||||
realArr.push(styleItem);
|
realArr.push(styleItem)
|
||||||
}
|
}
|
||||||
if (s.sceneStyle === '1') {
|
if (s.sceneStyle === '1') {
|
||||||
comicArr.push(styleItem);
|
comicArr.push(styleItem)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
mockData.real = realArr;
|
|
||||||
mockData.comic = comicArr;
|
|
||||||
console.log('处理后的场景列表:', JSON.stringify(mockData));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
mockData.real = realArr
|
||||||
|
mockData.comic = comicArr
|
||||||
|
console.log('处理后的场景列表:', JSON.stringify(mockData))
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchSceneList();
|
fetchSceneList()
|
||||||
});
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -257,11 +287,15 @@ onMounted(() => {
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
height: 60%;
|
height: 60%;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.1) 70%, rgba(0, 0, 0, 0.7) 85%, #000 100%);
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
rgba(0, 0, 0, 0) 0%,
|
||||||
|
rgba(0, 0, 0, 0.1) 70%,
|
||||||
|
rgba(0, 0, 0, 0.7) 85%,
|
||||||
|
#000 100%
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* 内容布局层 */
|
/* 内容布局层 */
|
||||||
.content-layer {
|
.content-layer {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -379,7 +413,7 @@ onMounted(() => {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 56px;
|
font-size: 56px;
|
||||||
margin: 12px 0 32px;
|
margin: 12px 0 32px;
|
||||||
background: linear-gradient(to bottom, #FFFFFF 0%, #CBF2FC 100%);
|
background: linear-gradient(to bottom, #ffffff 0%, #cbf2fc 100%);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
@@ -419,7 +453,7 @@ onMounted(() => {
|
|||||||
height: 60px;
|
height: 60px;
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
border: none;
|
border: none;
|
||||||
background: linear-gradient(90deg, #D9FBC8 0%, #8BE2FF 100%);
|
background: linear-gradient(90deg, #d9fbc8 0%, #8be2ff 100%);
|
||||||
box-shadow: 0px 0px 20px 0px rgba(217, 251, 200, 0.3);
|
box-shadow: 0px 0px 20px 0px rgba(217, 251, 200, 0.3);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts" name="prepicture">
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
Reference in New Issue
Block a user