mirror of
https://github.com/yangjian102621/geekai.git
synced 2026-04-24 12:04:31 +08:00
优化移动端即梦页面
This commit is contained in:
410
web/src/store/mobile/jimeng.js
Normal file
410
web/src/store/mobile/jimeng.js
Normal file
@@ -0,0 +1,410 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { httpGet, httpPost } from '@/utils/http'
|
||||
import { showMessageError, showMessageOK, showLoading, closeLoading } from '@/utils/dialog'
|
||||
import { showConfirmDialog } from 'vant'
|
||||
|
||||
export const useJimengStore = defineStore('mobile-jimeng', () => {
|
||||
// 响应式数据
|
||||
const activeCategory = ref('image_generation')
|
||||
const useImageInput = ref(false)
|
||||
const submitting = ref(false)
|
||||
const listLoading = ref(false)
|
||||
const listFinished = ref(false)
|
||||
const currentList = ref([])
|
||||
const showMediaDialog = ref(false)
|
||||
const currentMediaUrl = ref('')
|
||||
const currentPrompt = ref('')
|
||||
const page = ref(1)
|
||||
const pageSize = ref(10)
|
||||
const total = ref(0)
|
||||
const currentPowerCost = ref(0)
|
||||
const taskPulling = ref(true)
|
||||
const tastPullHandler = ref(null)
|
||||
|
||||
// 功能分类
|
||||
const categories = ref([
|
||||
{ key: 'image_generation', name: '图像生成' },
|
||||
{ key: 'image_editing', name: '图像编辑' },
|
||||
{ key: 'image_effects', name: '图像特效' },
|
||||
{ key: 'video_generation', name: '视频生成' },
|
||||
])
|
||||
|
||||
// 选项数据
|
||||
const imageSizeOptions = [
|
||||
{ label: '512x512', value: '512x512' },
|
||||
{ label: '768x768', value: '768x768' },
|
||||
{ label: '1024x1024', value: '1024x1024' },
|
||||
{ label: '1024x1536', value: '1024x1536' },
|
||||
{ label: '1536x1024', value: '1536x1024' },
|
||||
]
|
||||
|
||||
const videoAspectRatioOptions = [
|
||||
{ label: '16:9', value: '16:9' },
|
||||
{ label: '9:16', value: '9:16' },
|
||||
{ label: '1:1', value: '1:1' },
|
||||
{ label: '4:3', value: '4:3' },
|
||||
]
|
||||
|
||||
const imageEffectsTemplateOptions = [
|
||||
{ label: '亚克力装饰', value: 'acrylic_ornaments' },
|
||||
{ label: '天使小雕像', value: 'angel_figurine' },
|
||||
{ label: '毛毫3D拍立得', value: 'felt_3d_polaroid' },
|
||||
{ label: '水彩插图', value: 'watercolor_illustration' },
|
||||
]
|
||||
|
||||
// 功能参数
|
||||
const textToImageParams = ref({
|
||||
size: '1024x1024',
|
||||
scale: 7.5,
|
||||
use_pre_llm: false,
|
||||
})
|
||||
|
||||
const imageToImageParams = ref({
|
||||
image_input: [],
|
||||
size: '1024x1024',
|
||||
})
|
||||
|
||||
const imageEditParams = ref({
|
||||
image_urls: [],
|
||||
scale: 0.5,
|
||||
})
|
||||
|
||||
const imageEffectsParams = ref({
|
||||
image_input1: [],
|
||||
template_id: '',
|
||||
size: '1024x1024',
|
||||
})
|
||||
|
||||
const textToVideoParams = ref({
|
||||
aspect_ratio: '16:9',
|
||||
})
|
||||
|
||||
const imageToVideoParams = ref({
|
||||
image_urls: [],
|
||||
aspect_ratio: '16:9',
|
||||
})
|
||||
|
||||
// 计算属性
|
||||
const activeFunction = computed(() => {
|
||||
if (activeCategory.value === 'image_generation') {
|
||||
return useImageInput.value ? 'image_to_image' : 'text_to_image'
|
||||
} else if (activeCategory.value === 'image_editing') {
|
||||
return 'image_edit'
|
||||
} else if (activeCategory.value === 'video_generation') {
|
||||
return useImageInput.value ? 'image_to_video' : 'text_to_video'
|
||||
}
|
||||
return 'text_to_image'
|
||||
})
|
||||
|
||||
// Actions
|
||||
const getCategoryIcon = (category) => {
|
||||
const iconMap = {
|
||||
image_generation: 'iconfont icon-image',
|
||||
image_editing: 'iconfont icon-edit',
|
||||
image_effects: 'iconfont icon-chuangzuo',
|
||||
video_generation: 'iconfont icon-video',
|
||||
}
|
||||
return iconMap[category] || 'iconfont icon-image'
|
||||
}
|
||||
|
||||
const switchCategory = (key) => {
|
||||
activeCategory.value = key
|
||||
useImageInput.value = false
|
||||
}
|
||||
|
||||
const switchInputMode = () => {
|
||||
currentPrompt.value = ''
|
||||
}
|
||||
|
||||
const handleMultipleImageUpload = (event) => {
|
||||
const files = Array.from(event.target.files)
|
||||
files.forEach((file) => {
|
||||
if (imageToVideoParams.value.image_urls.length < 2) {
|
||||
onImageUpload({ file, name: file.name })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const removeImage = (index) => {
|
||||
imageToVideoParams.value.image_urls.splice(index, 1)
|
||||
}
|
||||
|
||||
const onImageUpload = (file) => {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file.file, file.name)
|
||||
showLoading('正在上传图片...')
|
||||
|
||||
return httpPost('/api/upload', formData)
|
||||
.then((res) => {
|
||||
showMessageOK('图片上传成功')
|
||||
const imageData = { url: res.data.url, content: res.data.url }
|
||||
|
||||
// 根据当前活动功能添加到相应的参数中
|
||||
if (activeFunction.value === 'image_to_image') {
|
||||
imageToImageParams.value.image_input = [imageData]
|
||||
} else if (activeFunction.value === 'image_edit') {
|
||||
imageEditParams.value.image_urls = [imageData]
|
||||
} else if (activeFunction.value === 'image_effects') {
|
||||
imageEffectsParams.value.image_input1 = [imageData]
|
||||
} else if (activeFunction.value === 'image_to_video') {
|
||||
imageToVideoParams.value.image_urls.push(imageData)
|
||||
}
|
||||
|
||||
return res.data.url
|
||||
})
|
||||
.catch((e) => {
|
||||
showMessageError('图片上传失败:' + e.message)
|
||||
})
|
||||
.finally(() => {
|
||||
closeLoading()
|
||||
})
|
||||
}
|
||||
|
||||
const submitTask = () => {
|
||||
if (!currentPrompt.value.trim()) {
|
||||
showMessageError('请输入提示词')
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
const params = {
|
||||
type: activeFunction.value,
|
||||
prompt: currentPrompt.value,
|
||||
}
|
||||
|
||||
// 根据功能类型添加相应参数
|
||||
if (activeFunction.value === 'text_to_image') {
|
||||
Object.assign(params, textToImageParams.value)
|
||||
} else if (activeFunction.value === 'image_to_image') {
|
||||
Object.assign(params, imageToImageParams.value)
|
||||
} else if (activeFunction.value === 'image_edit') {
|
||||
Object.assign(params, imageEditParams.value)
|
||||
} else if (activeFunction.value === 'image_effects') {
|
||||
Object.assign(params, imageEffectsParams.value)
|
||||
} else if (activeFunction.value === 'text_to_video') {
|
||||
Object.assign(params, textToVideoParams.value)
|
||||
} else if (activeFunction.value === 'image_to_video') {
|
||||
Object.assign(params, imageToVideoParams.value)
|
||||
}
|
||||
|
||||
return httpPost('/api/jimeng/create', params)
|
||||
.then(() => {
|
||||
fetchData(1)
|
||||
taskPulling.value = true
|
||||
showMessageOK('创建任务成功')
|
||||
currentPrompt.value = ''
|
||||
})
|
||||
.catch((e) => {
|
||||
showMessageError('创建任务失败:' + e.message)
|
||||
})
|
||||
.finally(() => {
|
||||
submitting.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const fetchData = (_page) => {
|
||||
if (_page) {
|
||||
page.value = _page
|
||||
}
|
||||
listLoading.value = true
|
||||
|
||||
return httpGet('/api/jimeng/list', { page: page.value, page_size: pageSize.value })
|
||||
.then((res) => {
|
||||
total.value = res.data.total
|
||||
let needPull = false
|
||||
const items = []
|
||||
for (let v of res.data.items) {
|
||||
if (v.status === 'in_queue' || v.status === 'generating') {
|
||||
needPull = true
|
||||
}
|
||||
items.push(v)
|
||||
}
|
||||
listLoading.value = false
|
||||
taskPulling.value = needPull
|
||||
|
||||
if (page.value === 1) {
|
||||
currentList.value = items
|
||||
} else {
|
||||
currentList.value.push(...items)
|
||||
}
|
||||
|
||||
if (items.length < pageSize.value) {
|
||||
listFinished.value = true
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
listLoading.value = false
|
||||
showMessageError('获取作品列表失败:' + e.message)
|
||||
})
|
||||
}
|
||||
|
||||
const loadMore = () => {
|
||||
page.value++
|
||||
fetchData()
|
||||
}
|
||||
|
||||
const playMedia = (item) => {
|
||||
currentMediaUrl.value = item.img_url || item.video_url
|
||||
showMediaDialog.value = true
|
||||
}
|
||||
|
||||
const downloadFile = (item) => {
|
||||
item.downloading = true
|
||||
const link = document.createElement('a')
|
||||
link.href = item.img_url || item.video_url
|
||||
link.download = item.title || 'file'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
item.downloading = false
|
||||
showMessageSuccess('开始下载')
|
||||
}
|
||||
|
||||
const retryTask = (id) => {
|
||||
return httpPost('/api/jimeng/retry', { id })
|
||||
.then(() => {
|
||||
showMessageOK('重试任务成功')
|
||||
fetchData(1)
|
||||
})
|
||||
.catch((e) => {
|
||||
showMessageError('重试任务失败:' + e.message)
|
||||
})
|
||||
}
|
||||
|
||||
const removeJob = (item) => {
|
||||
return showConfirmDialog({
|
||||
title: '确认删除',
|
||||
message: '此操作将会删除任务相关文件,继续操作吗?',
|
||||
confirmButtonText: '确认删除',
|
||||
cancelButtonText: '取消',
|
||||
})
|
||||
.then(() => {
|
||||
return httpGet('/api/jimeng/remove', { id: item.id })
|
||||
.then(() => {
|
||||
showMessageOK('任务删除成功')
|
||||
fetchData(1)
|
||||
})
|
||||
.catch((e) => {
|
||||
showMessageError('任务删除失败:' + e.message)
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const getFunctionName = (type) => {
|
||||
const nameMap = {
|
||||
text_to_image: '文生图',
|
||||
image_to_image: '图生图',
|
||||
image_edit: '图像编辑',
|
||||
image_effects: '图像特效',
|
||||
text_to_video: '文生视频',
|
||||
image_to_video: '图生视频',
|
||||
}
|
||||
return nameMap[type] || type
|
||||
}
|
||||
|
||||
const getTaskType = (type) => {
|
||||
return type.includes('video') ? 'warning' : 'primary'
|
||||
}
|
||||
|
||||
const startTaskPolling = () => {
|
||||
tastPullHandler.value = setInterval(() => {
|
||||
if (taskPulling.value) {
|
||||
fetchData(1)
|
||||
}
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
const stopTaskPolling = () => {
|
||||
if (tastPullHandler.value) {
|
||||
clearInterval(tastPullHandler.value)
|
||||
}
|
||||
}
|
||||
|
||||
const resetParams = () => {
|
||||
textToImageParams.value = {
|
||||
size: '1024x1024',
|
||||
scale: 7.5,
|
||||
use_pre_llm: false,
|
||||
}
|
||||
imageToImageParams.value = {
|
||||
image_input: [],
|
||||
size: '1024x1024',
|
||||
}
|
||||
imageEditParams.value = {
|
||||
image_urls: [],
|
||||
scale: 0.5,
|
||||
}
|
||||
imageEffectsParams.value = {
|
||||
image_input1: [],
|
||||
template_id: '',
|
||||
size: '1024x1024',
|
||||
}
|
||||
textToVideoParams.value = {
|
||||
aspect_ratio: '16:9',
|
||||
}
|
||||
imageToVideoParams.value = {
|
||||
image_urls: [],
|
||||
aspect_ratio: '16:9',
|
||||
}
|
||||
}
|
||||
|
||||
const closeMediaDialog = () => {
|
||||
showMediaDialog.value = false
|
||||
currentMediaUrl.value = ''
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
activeCategory,
|
||||
useImageInput,
|
||||
submitting,
|
||||
listLoading,
|
||||
listFinished,
|
||||
currentList,
|
||||
showMediaDialog,
|
||||
currentMediaUrl,
|
||||
currentPrompt,
|
||||
page,
|
||||
pageSize,
|
||||
total,
|
||||
currentPowerCost,
|
||||
taskPulling,
|
||||
tastPullHandler,
|
||||
categories,
|
||||
imageSizeOptions,
|
||||
videoAspectRatioOptions,
|
||||
imageEffectsTemplateOptions,
|
||||
textToImageParams,
|
||||
imageToImageParams,
|
||||
imageEditParams,
|
||||
imageEffectsParams,
|
||||
textToVideoParams,
|
||||
imageToVideoParams,
|
||||
|
||||
// Computed
|
||||
activeFunction,
|
||||
|
||||
// Actions
|
||||
getCategoryIcon,
|
||||
switchCategory,
|
||||
switchInputMode,
|
||||
handleMultipleImageUpload,
|
||||
removeImage,
|
||||
onImageUpload,
|
||||
submitTask,
|
||||
fetchData,
|
||||
loadMore,
|
||||
playMedia,
|
||||
downloadFile,
|
||||
retryTask,
|
||||
removeJob,
|
||||
getFunctionName,
|
||||
getTaskType,
|
||||
startTaskPolling,
|
||||
stopTaskPolling,
|
||||
resetParams,
|
||||
closeMediaDialog,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user