222
This commit is contained in:
parent
79630d2802
commit
9f7047fbb9
|
|
@ -70,6 +70,10 @@ import { MeshyServer } from '@deotaland/utils'
|
|||
const meshServer = new MeshyServer()
|
||||
const isLoading = ref(false);
|
||||
const props = defineProps({
|
||||
resultTask: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
taskId: {
|
||||
type: String,
|
||||
required: true
|
||||
|
|
@ -150,24 +154,27 @@ watch(() => initializationProgress.value, (newVal) => {
|
|||
})
|
||||
const loadmodelUrl = ()=>{
|
||||
if(props.taskId){
|
||||
startModelTask(props.taskId)
|
||||
startModelTask(props.taskId,props.resultTask)
|
||||
}
|
||||
else if(props.imgUrl){
|
||||
meshServer.createModelTask({
|
||||
image_url:props.imgUrl,
|
||||
project_id:props.projectId
|
||||
},(result)=>{
|
||||
emit('save',result)
|
||||
startModelTask(result)
|
||||
},(result,resultTask)=>{
|
||||
emit('save',result,resultTask)
|
||||
startModelTask(result,resultTask)
|
||||
},()=>{
|
||||
emit('delete')
|
||||
},{
|
||||
})
|
||||
}
|
||||
}
|
||||
const startModelTask = (result) => {
|
||||
const startModelTask = (result,resultTask) => {
|
||||
showInitializationOverlay.value = true;
|
||||
meshServer.getModelTaskStatus(result,(modelurl)=>{
|
||||
meshServer.getModelTaskStatus({
|
||||
result:result,
|
||||
resultTask:resultTask,
|
||||
},(modelurl)=>{
|
||||
setInitializationProgress(100)
|
||||
modelUrl.value = modelurl;
|
||||
},(error)=>{
|
||||
|
|
|
|||
|
|
@ -160,10 +160,11 @@
|
|||
@preview="previewModel"
|
||||
:img-url="item.image"
|
||||
:task-id="item.taskId"
|
||||
:result-task="item.resultTask"
|
||||
width="100%"
|
||||
height="150px"
|
||||
:project-id="orderDetail.projectId"
|
||||
@save="(result)=>saveModel(index,result)"
|
||||
@save="(result,resultTask)=>saveModel(index,result,resultTask)"
|
||||
:show-delete="true"
|
||||
@delete="deleteModel(index)"
|
||||
/>
|
||||
|
|
@ -312,9 +313,9 @@ const orderDetail = ref({
|
|||
status: 'pending',
|
||||
processingCompleteTime: null
|
||||
})
|
||||
const saveModel = (index,result)=>{
|
||||
console.log(index,result,'currentStepcurrentStep');
|
||||
const saveModel = (index,result,resultTask)=>{
|
||||
generatedModels.value[index].taskId = result;
|
||||
generatedModels.value[index].resultTask = resultTask;
|
||||
}
|
||||
|
||||
// 当前步骤
|
||||
|
|
@ -485,20 +486,7 @@ const handleDisassembly = () => {
|
|||
|
||||
|
||||
const deleteModel = (index) => {
|
||||
ElMessageBox.confirm(
|
||||
'确定要删除这个模型吗?',
|
||||
'删除确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
}
|
||||
).then(() => {
|
||||
generatedModels.value.splice(index, 1)
|
||||
ElMessage.success('模型已删除')
|
||||
}).catch(() => {
|
||||
// 用户取消删除
|
||||
})
|
||||
}
|
||||
// 加工完成方法
|
||||
const handleProcessingComplete = () => {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
"element-plus": "^2.11.7",
|
||||
"jose": "^6.1.1",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
"three": "^0.180.0",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ function initializeTheme() {
|
|||
if (typeof window !== 'undefined') {
|
||||
const savedTheme = localStorage.getItem('theme')
|
||||
const hasDarkClass = document.documentElement.classList.contains('dark')
|
||||
|
||||
if (savedTheme === 'dark') {
|
||||
document.documentElement.classList.add('dark')
|
||||
themeState.value = true
|
||||
|
|
@ -31,7 +30,22 @@ function initializeTheme() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const loading = ref(false);
|
||||
const qmLoading = ref(false);
|
||||
const closeMethods = {
|
||||
close: ()=>{
|
||||
loading.value = false
|
||||
qmLoading.value = false;
|
||||
}
|
||||
}
|
||||
window.setElLoading = (qp=false)=>{
|
||||
if(qp){
|
||||
qmLoading.value = true
|
||||
}else{
|
||||
loading.value = true
|
||||
}
|
||||
return closeMethods
|
||||
}
|
||||
// Initialize on component mount
|
||||
onMounted(() => {
|
||||
initializeTheme()
|
||||
|
|
@ -44,41 +58,119 @@ onMounted(() => {
|
|||
'fullscreen-mode': isFullScreenPage,
|
||||
'homepage-mode': isHomePage
|
||||
}">
|
||||
<div class="sidebar-overlay" :class="{ 'sidebar-overlay-active': qmLoading }"></div>
|
||||
<!-- 登录页面全屏显示 -->
|
||||
<main v-if="isLoginPage">
|
||||
<main style="position: relative;" v-if="isLoginPage">
|
||||
<div class="sidebar-overlay" :class="{ 'sidebar-overlay-active': loading }"></div>
|
||||
<router-view />
|
||||
</main>
|
||||
|
||||
|
||||
|
||||
<!-- 全屏页面(如创建项目) -->
|
||||
<main v-else-if="isFullScreenPage" class="fullscreen-content">
|
||||
<div class="sidebar-overlay" :class="{ 'sidebar-overlay-active': loading }"></div>
|
||||
<router-view />
|
||||
</main>
|
||||
|
||||
<!-- 应用内页面使用布局组件 -->
|
||||
<MainLayout v-else>
|
||||
<div v-else style="position: relative;">
|
||||
<MainLayout :loading="loading" >
|
||||
<template #header>
|
||||
<AppHeader />
|
||||
</template>
|
||||
|
||||
<template #sidebar>
|
||||
<AppSidebar />
|
||||
</template>
|
||||
|
||||
<template #default>
|
||||
<router-view />
|
||||
</template>
|
||||
</MainLayout>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
#nprogress .bar {
|
||||
/* 自定义加载条颜色 */
|
||||
background: #9c7eef !important; /* Element Plus 主色 */
|
||||
height: 2px !important; /* 高度 */
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
/* 侧边栏过渡动画蒙层 */
|
||||
.sidebar-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
/* background: rgba(111, 75, 197, 0.1); */
|
||||
/* background: red; */
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
z-index: 9999;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 蒙层激活状态 */
|
||||
.sidebar-overlay-active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* 转圈加载动画 */
|
||||
.sidebar-overlay::before {
|
||||
content: '';
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid rgba(113, 77, 199, 0.3);
|
||||
border-top: 4px solid #714DC7;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
box-shadow: 0 0 20px rgba(113, 77, 199, 0.5);
|
||||
}
|
||||
|
||||
.sidebar-overlay::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border: 2px solid rgba(113, 77, 199, 0.1);
|
||||
border-bottom: 2px solid rgba(113, 77, 199, 0.3);
|
||||
border-radius: 50%;
|
||||
animation: spin 1.5s linear infinite reverse;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 暗色主题下的蒙层效果 */
|
||||
html.dark .sidebar-overlay {
|
||||
background: rgba(31, 41, 55, 0.85);
|
||||
}
|
||||
|
||||
html.dark .sidebar-overlay::before {
|
||||
border: 4px solid rgba(255, 255, 255, 0.2);
|
||||
border-top: 4px solid #A78BFA;
|
||||
box-shadow: 0 0 20px rgba(167, 139, 250, 0.5);
|
||||
}
|
||||
|
||||
html.dark .sidebar-overlay::after {
|
||||
border: 2px solid rgba(167, 139, 250, 0.1);
|
||||
border-bottom: 2px solid rgba(167, 139, 250, 0.4);
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
header strong { font-size: 1.25rem; }
|
||||
|
||||
|
||||
/* 应用容器基础样式 */
|
||||
#app-container {
|
||||
width: 100vw;
|
||||
|
|
@ -119,7 +211,7 @@ header strong { font-size: 1.25rem; }
|
|||
height: 100vh !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
overflow: auto !important; /* 确保全屏内容可以滚动 */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 首页全屏滚动模式 - 使用浏览器原生滚动 */
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ const handleGenerateImage = async () => {
|
|||
formData.value.status = 'success';
|
||||
saveProject();
|
||||
} catch (error) {
|
||||
ElMessage.error('生成图片失败,请稍后重试');
|
||||
// ElMessage.error('生成图片失败,请稍后重试');
|
||||
emit('delete');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ const formData = ref({
|
|||
|
||||
const textareaRef = ref(null);
|
||||
const fileInput = ref(null); // 文件输入引用
|
||||
const generateCount = ref(1); // 生成数量,默认为1
|
||||
const generateCount = ref(4); // 生成数量,默认为1
|
||||
const isOptimizing = ref(false); // 优化状态
|
||||
const isDragOver = ref(false); // 拖拽状态
|
||||
// IP类型选择(人物/动物),默认人物,并保存到本地
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
<el-dropdown-item command="settings">
|
||||
{{ t('header.settings') }}
|
||||
</el-dropdown-item> -->
|
||||
<el-dropdown-item divided command="logout">
|
||||
<el-dropdown-item command="logout">
|
||||
<LogoutIcon class="dropdown-item-icon" />
|
||||
{{ t('header.logout') }}
|
||||
</el-dropdown-item>
|
||||
|
|
@ -545,7 +545,7 @@ export default {
|
|||
font-weight: 500;
|
||||
color: var(--text-primary, #1f2937);
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
/* overflow: hidden; */
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,7 +476,7 @@ export default {
|
|||
font-weight: 600;
|
||||
color: var(--text-primary, #1f2937);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
/* overflow: hidden; */
|
||||
text-overflow: ellipsis;
|
||||
letter-spacing: 0.02em;
|
||||
line-height: 1.3;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
<template>
|
||||
<div class="main-layout" :class="layoutClasses">
|
||||
<!-- 移动端遮罩层 -->
|
||||
<div
|
||||
v-if="isMobile && sidebarVisible"
|
||||
class="sidebar-overlay"
|
||||
@click="toggleSidebar"
|
||||
></div>
|
||||
|
||||
<!-- 第一行:头部导航栏 -->
|
||||
<header class="header-container">
|
||||
|
|
@ -28,11 +22,13 @@
|
|||
</aside>
|
||||
<!-- 主内容区域 -->
|
||||
<div class="main-content" :class="{ 'sidebar-collapsed': !sidebarVisible && !isMobile }">
|
||||
<div class="sidebar-overlay" :class="{ 'sidebar-overlay-active': loading }"></div>
|
||||
<!-- 面包屑导航 -->
|
||||
<!-- <BreadcrumbNavigation class="breadcrumb-container" /> -->
|
||||
|
||||
<!-- 页面内容 -->
|
||||
<main class="page-content">
|
||||
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<keep-alive v-if="route.meta.keepAlive">
|
||||
<component :is="Component" :key="route.name" />
|
||||
|
|
@ -45,115 +41,109 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
import AppHeader from './AppHeader.vue'
|
||||
import AppSidebar from './AppSidebar.vue'
|
||||
import BreadcrumbNavigation from './BreadcrumbNavigation.vue'
|
||||
|
||||
export default {
|
||||
name: 'MainLayout',
|
||||
components: {
|
||||
AppHeader,
|
||||
AppSidebar,
|
||||
BreadcrumbNavigation
|
||||
},
|
||||
setup() {
|
||||
// 响应式状态管理
|
||||
const state = reactive({
|
||||
screenWidth: window.innerWidth,
|
||||
sidebarVisible: true,
|
||||
isMobile: false,
|
||||
isTablet: false,
|
||||
isDesktop: false
|
||||
})
|
||||
// 注册组件
|
||||
defineOptions({
|
||||
name: 'MainLayout'
|
||||
})
|
||||
const props = defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
// 响应式状态管理
|
||||
const state = reactive({
|
||||
screenWidth: window.innerWidth,
|
||||
sidebarVisible: true,
|
||||
isMobile: false,
|
||||
isTablet: false,
|
||||
isDesktop: false
|
||||
})
|
||||
|
||||
// 计算属性:断点判断
|
||||
const breakpoints = {
|
||||
mobile: 768,
|
||||
tablet: 1024
|
||||
}
|
||||
// 计算属性:断点判断
|
||||
const breakpoints = {
|
||||
mobile: 768,
|
||||
tablet: 1024
|
||||
}
|
||||
|
||||
const layoutClasses = computed(() => ({
|
||||
'mobile-layout': state.isMobile,
|
||||
'tablet-layout': state.isTablet,
|
||||
'desktop-layout': state.isDesktop
|
||||
}))
|
||||
const layoutClasses = computed(() => ({
|
||||
'mobile-layout': state.isMobile,
|
||||
'tablet-layout': state.isTablet,
|
||||
'desktop-layout': state.isDesktop
|
||||
}))
|
||||
|
||||
// 响应式断点更新
|
||||
const updateBreakpoints = () => {
|
||||
state.screenWidth = window.innerWidth
|
||||
state.isMobile = state.screenWidth < breakpoints.mobile
|
||||
state.isTablet = state.screenWidth >= breakpoints.mobile && state.screenWidth < breakpoints.tablet
|
||||
state.isDesktop = state.screenWidth >= breakpoints.tablet
|
||||
// 导出需要在模板中使用的响应式数据
|
||||
const sidebarVisible = computed(() => state.sidebarVisible)
|
||||
const isMobile = computed(() => state.isMobile)
|
||||
const isTablet = computed(() => state.isTablet)
|
||||
const isDesktop = computed(() => state.isDesktop)
|
||||
|
||||
// 移动端默认隐藏侧边栏
|
||||
if (state.isMobile) {
|
||||
state.sidebarVisible = false
|
||||
} else if (state.isDesktop) {
|
||||
state.sidebarVisible = true
|
||||
}
|
||||
}
|
||||
// 响应式断点更新
|
||||
const updateBreakpoints = () => {
|
||||
state.screenWidth = window.innerWidth
|
||||
state.isMobile = state.screenWidth < breakpoints.mobile
|
||||
state.isTablet = state.screenWidth >= breakpoints.mobile && state.screenWidth < breakpoints.tablet
|
||||
state.isDesktop = state.screenWidth >= breakpoints.tablet
|
||||
|
||||
// 切换侧边栏显示
|
||||
const toggleSidebar = () => {
|
||||
if (state.isMobile) {
|
||||
state.sidebarVisible = !state.sidebarVisible
|
||||
} else {
|
||||
state.sidebarVisible = !state.sidebarVisible
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 处理导航
|
||||
const handleNavigate = (route) => {
|
||||
// 移动端点击导航后隐藏侧边栏
|
||||
if (state.isMobile) {
|
||||
state.sidebarVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
// 窗口大小变化监听
|
||||
let resizeTimer = null
|
||||
const handleResize = () => {
|
||||
clearTimeout(resizeTimer)
|
||||
resizeTimer = setTimeout(() => {
|
||||
updateBreakpoints()
|
||||
}, 150)
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
updateBreakpoints()
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
if (resizeTimer) {
|
||||
clearTimeout(resizeTimer)
|
||||
}
|
||||
})
|
||||
|
||||
// 监听路由变化,在移动端自动隐藏侧边栏
|
||||
watch(() => window.location.pathname, () => {
|
||||
if (state.isMobile) {
|
||||
state.sidebarVisible = false
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
sidebarVisible: computed(() => state.sidebarVisible),
|
||||
isMobile: computed(() => state.isMobile),
|
||||
isTablet: computed(() => state.isTablet),
|
||||
isDesktop: computed(() => state.isDesktop),
|
||||
layoutClasses,
|
||||
toggleSidebar,
|
||||
handleNavigate
|
||||
}
|
||||
// 移动端默认隐藏侧边栏
|
||||
if (state.isMobile) {
|
||||
state.sidebarVisible = false
|
||||
} else if (state.isDesktop) {
|
||||
state.sidebarVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
// 切换侧边栏显示
|
||||
const toggleSidebar = () => {
|
||||
if (state.isMobile) {
|
||||
state.sidebarVisible = !state.sidebarVisible
|
||||
} else {
|
||||
state.sidebarVisible = !state.sidebarVisible
|
||||
}
|
||||
}
|
||||
|
||||
// 处理导航
|
||||
const handleNavigate = (route) => {
|
||||
// 移动端点击导航后隐藏侧边栏
|
||||
if (state.isMobile) {
|
||||
state.sidebarVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
// 窗口大小变化监听
|
||||
let resizeTimer = null
|
||||
const handleResize = () => {
|
||||
clearTimeout(resizeTimer)
|
||||
resizeTimer = setTimeout(() => {
|
||||
updateBreakpoints()
|
||||
}, 150)
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
updateBreakpoints()
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', handleResize)
|
||||
if (resizeTimer) {
|
||||
clearTimeout(resizeTimer)
|
||||
}
|
||||
})
|
||||
|
||||
// 监听路由变化,在移动端自动隐藏侧边栏
|
||||
watch(() => window.location.pathname, () => {
|
||||
if (state.isMobile) {
|
||||
state.sidebarVisible = false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -202,17 +192,7 @@ export default {
|
|||
|
||||
|
||||
|
||||
/* 移动端遮罩层 */
|
||||
.sidebar-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
|
||||
/* 主内容区域 */
|
||||
.main-content {
|
||||
|
|
@ -222,6 +202,7 @@ export default {
|
|||
width: 100%;
|
||||
/* 移除 overflow: hidden 以允许页面滚动 */
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ import { computed, ref, onMounted } from 'vue';
|
|||
import ThreeModelViewer from '../ThreeModelViewer/index.vue';
|
||||
import { MeshyServer } from '@deotaland/utils';
|
||||
// 定义组件事件
|
||||
const emit = defineEmits(['clickModel','refineModel','save-project']);
|
||||
const emit = defineEmits(['clickModel','refineModel','save-project','delete']);
|
||||
const Meshy = new MeshyServer();
|
||||
// 控制右侧按钮显示状态
|
||||
const showRightControls = ref(false);
|
||||
|
|
@ -137,28 +137,30 @@ const handleGenerateModel = async () => {
|
|||
let result;
|
||||
if(props.cardData.taskId){
|
||||
result = props.cardData.taskId;
|
||||
TaskStatus(result);
|
||||
TaskStatus(result,props.cardData.resultTask);
|
||||
return
|
||||
}
|
||||
Meshy.createModelTask({
|
||||
project_id: props.cardData.project_id,
|
||||
image_url: props.cardData.imageUrl,
|
||||
},(result)=>{
|
||||
},(result,resultTask)=>{
|
||||
if(result){
|
||||
emit('save-project',{
|
||||
...props.cardData,
|
||||
resultTask:resultTask,
|
||||
taskId:result
|
||||
});
|
||||
TaskStatus(result);
|
||||
TaskStatus(result,resultTask);
|
||||
}
|
||||
},(error)=>{
|
||||
console.error('模型生成失败:', error);
|
||||
isGenerating.value = false;
|
||||
progressPercentage.value = 0;
|
||||
emit('delete');
|
||||
},{})
|
||||
};
|
||||
const TaskStatus = (result)=>{
|
||||
Meshy.getModelTaskStatus(result,(modelUrl)=>{
|
||||
const TaskStatus = (result,resultTask)=>{
|
||||
Meshy.getModelTaskStatus({
|
||||
result:result,
|
||||
resultTask:resultTask,
|
||||
},(modelUrl)=>{
|
||||
if(modelUrl){
|
||||
// 模型生成完成
|
||||
generatedModelUrl.value = modelUrl;
|
||||
|
|
@ -173,8 +175,7 @@ const TaskStatus = (result)=>{
|
|||
}
|
||||
},(error)=>{
|
||||
console.error('模型生成失败:', error);
|
||||
isGenerating.value = false;
|
||||
progressPercentage.value = 0;
|
||||
emit('delete');
|
||||
},(progress)=>{
|
||||
if (progress !== undefined) {
|
||||
progressPercentage.value = progress;
|
||||
|
|
|
|||
|
|
@ -18,20 +18,21 @@ import { createPinia } from 'pinia'
|
|||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
import VueLazyload from 'vue3-lazyload'
|
||||
import 'element-plus/dist/index.css'
|
||||
import 'nprogress/nprogress.css'
|
||||
import {ElMessage,ElLoading } from 'element-plus'
|
||||
const app = createApp(App)
|
||||
window.setElMessage = (options={})=>{
|
||||
ElMessage[options.type || 'info'](options.message || '请求失败')
|
||||
}
|
||||
window.setElLoading = ()=>{
|
||||
const loading = ElLoading.service({
|
||||
lock: true,
|
||||
text: 'Loading',
|
||||
background: 'rgba(0, 0, 0, 0.4)',
|
||||
})
|
||||
return loading
|
||||
// loading.close()
|
||||
}
|
||||
// window.setElLoading = ()=>{
|
||||
// const loading = ElLoading.service({
|
||||
// lock: true,
|
||||
// text: 'Loading',
|
||||
// background: 'rgba(0, 0, 0, 0.4)',
|
||||
// })
|
||||
// return loading
|
||||
// // loading.close()
|
||||
// }
|
||||
// Pinia
|
||||
const pinia = createPinia()
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { createRouter, createWebHistory,createWebHashHistory} from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
|
||||
import NProgress from 'nprogress'
|
||||
const ModernHome = () => import('../views/ModernHome.vue')
|
||||
const List = () => import('../views/List.vue')
|
||||
const Login = () => import('../views/Login/Login.vue')
|
||||
|
|
@ -15,7 +15,9 @@ const AgentManagement = () => import('../views/AgentManagement.vue')
|
|||
const AddAgent = () => import('../views/AddAgent.vue')
|
||||
const UiTest = () => import('../views/UiTest.vue')
|
||||
const home = () => import('../views/home/index.vue')
|
||||
|
||||
NProgress.configure({
|
||||
showSpinner: false,
|
||||
})// 开启轻量模式(顶部细线)
|
||||
// 路由配置
|
||||
const routes = [
|
||||
{
|
||||
|
|
@ -128,9 +130,9 @@ const router = createRouter({
|
|||
|
||||
// 路由守卫
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start()
|
||||
// window.localStorage.setItem('token','123')
|
||||
// return next()
|
||||
// 检查是否需要登录
|
||||
if (to.meta.requiresAuth) {
|
||||
const token = localStorage.getItem('token')
|
||||
// 如果没有 token,跳转到登录页
|
||||
|
|
@ -139,16 +141,10 @@ router.beforeEach(async (to, from, next) => {
|
|||
return
|
||||
}
|
||||
}
|
||||
// 检查是否需要游客身份
|
||||
if (to.meta.requiresGuest) {
|
||||
const authStore = useAuthStore()
|
||||
// 如果有 token,跳转到首页
|
||||
if (authStore.token) {
|
||||
next('/')
|
||||
return
|
||||
}
|
||||
}
|
||||
next()
|
||||
})
|
||||
router.afterEach(() => {
|
||||
NProgress.done()
|
||||
})
|
||||
|
||||
export default router
|
||||
|
|
@ -45,7 +45,6 @@ export const useAuthStore = defineStore('auth', () => {
|
|||
callback&&callback();
|
||||
const router = useRouter();
|
||||
localStorage.removeItem('token')
|
||||
router.replace({ name: 'login' });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,19 +81,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<!-- 初始加载蒙层 -->
|
||||
<div v-if="loading && page === 1" class="overlay-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
</div>
|
||||
|
||||
<!-- 加载更多状态 -->
|
||||
<div v-if="loading" class="loading-more loading">
|
||||
{{ $t('loading') }}
|
||||
</div>
|
||||
<div v-else-if="finished && projects.length > 0" class="loading-more">
|
||||
{{ $t('allLoaded') }}
|
||||
</div>
|
||||
|
||||
<!-- 垃圾箱抽屉 -->
|
||||
<div
|
||||
v-if="showTrash"
|
||||
|
|
@ -111,65 +98,6 @@
|
|||
<p>{{ $t('creationWorkspace.dropToDeleteHint') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 全屏模态蒙层 -->
|
||||
<div
|
||||
v-if="showModal"
|
||||
class="modal-overlay"
|
||||
@click="closeModal"
|
||||
>
|
||||
<div class="modal-content" @click.stop>
|
||||
<!-- 关闭按钮 -->
|
||||
<button class="modal-close" @click="closeModal">
|
||||
<CloseIcon class="close-icon" />
|
||||
</button>
|
||||
|
||||
<!-- 模态内容 -->
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title">{{ modalTitle }}</h2>
|
||||
<p class="modal-subtitle">{{ modalSubtitle }}</p>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<!-- 查看项目内容 -->
|
||||
<div v-if="modalType === 'view'" class="modal-view-content">
|
||||
<div class="project-preview">
|
||||
<div class="preview-icon">
|
||||
<FolderIcon />
|
||||
</div>
|
||||
<div class="preview-info">
|
||||
<h3>{{ currentProject?.title }}</h3>
|
||||
<p>{{ currentProject?.description }}</p>
|
||||
<div class="preview-meta">
|
||||
<span class="preview-type">{{ currentProject?.type }}</span>
|
||||
<span class="preview-date">{{ formatDate(currentProject?.updatedAt) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="modal-action-btn primary" @click="openProject(currentProject)">
|
||||
<ViewIcon class="btn-icon" />
|
||||
进入项目
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 更换缩略图内容 -->
|
||||
<div v-if="modalType === 'edit'" class="modal-edit-content">
|
||||
<div class="upload-area">
|
||||
<div class="upload-icon">
|
||||
<UploadIcon />
|
||||
</div>
|
||||
<h3>更换项目缩略图</h3>
|
||||
<p>选择一张图片作为项目缩略图</p>
|
||||
<button class="modal-action-btn" @click="triggerFileSelect">
|
||||
<EditIcon class="btn-icon" />
|
||||
选择图片
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 删除确认对话框 -->
|
||||
<div
|
||||
v-if="showDeleteConfirm"
|
||||
|
|
@ -226,7 +154,6 @@ export default {
|
|||
setup() {
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
// 模态状态
|
||||
const showModal = ref(false)
|
||||
const modalType = ref('') // 'view' or 'edit'
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
<div class="google-login-section">
|
||||
<GoogleOAuthButton
|
||||
@success="handleLoginSuccess"
|
||||
:loading="plugin.loading"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -37,6 +38,7 @@
|
|||
<div class="email-login-section">
|
||||
<LoginForm
|
||||
@login="handleLogin"
|
||||
:loading="plugin.loading"
|
||||
/>
|
||||
</div>
|
||||
<!-- 角色信息展示 -->
|
||||
|
|
@ -68,7 +70,6 @@
|
|||
<el-icon class="error-icon"><WarningFilled /></el-icon>
|
||||
<span>{{ authStore.error }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 忘记密码和注册链接 -->
|
||||
<div class="auth-links">
|
||||
<div class="auth-links-row">
|
||||
|
|
|
|||
|
|
@ -3,12 +3,15 @@ import { useRouter } from 'vue-router'
|
|||
import {ElMessage} from 'element-plus';
|
||||
import { useAuthStore } from '@/stores/auth.js';
|
||||
export default class Login {
|
||||
loading = false;//登录loading
|
||||
constructor() {
|
||||
this.router = useRouter();
|
||||
this.authStore = useAuthStore();
|
||||
}
|
||||
async login(data) {
|
||||
this.loading = true;
|
||||
this.authStore.login(data,()=>{
|
||||
this.loading = false;
|
||||
this.router.push({ name: 'czhome' })
|
||||
// this.refreshGoogleRefreshToken()
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<template>
|
||||
<div class="creative-zone" :style="{ '--grid-size': `${gridSize}px` }">
|
||||
<div class="sidebar-overlay" :class="{ 'sidebar-overlay-active': showSidebarOverlay }"></div>
|
||||
<!-- 顶部固定头部组件 -->
|
||||
<div class="header-wrapper">
|
||||
<HeaderComponent :projectName="projectInfo.title" @updateProjectInfo="projectInfo = {...projectInfo, ...$event}" @openGuideModal="showGuideModal = true" />
|
||||
|
|
@ -72,6 +71,7 @@
|
|||
v-else-if="card.type === 'model'"
|
||||
:cardData="card"
|
||||
:clickDisabled="isElementDragging"
|
||||
@delete="handleDeleteCard(index)"
|
||||
:projectId="projectId"
|
||||
@save-project="(item)=>{handleSaveProject(index,item,'model')}"
|
||||
@clickModel="handleModelClick"
|
||||
|
|
@ -134,20 +134,6 @@ const selectedModel = ref(null);
|
|||
const showImportModal = ref(false);
|
||||
const importUrl = ref('https://xiaozhi.me/console/agents');
|
||||
const showGuideModal = ref(false);
|
||||
|
||||
// 侧边栏过渡动画蒙层状态
|
||||
const showSidebarOverlay = ref(false);
|
||||
|
||||
// 控制侧边栏蒙层显示/隐藏的方法
|
||||
const showSidebarTransition = () => {
|
||||
showSidebarOverlay.value = true;
|
||||
};
|
||||
|
||||
const hideSidebarTransition = () => {
|
||||
showSidebarOverlay.value = false;
|
||||
};
|
||||
|
||||
|
||||
// 事件监听器清理函数存储
|
||||
const cleanupFunctions = ref({});
|
||||
const projectId = ref(null);
|
||||
|
|
@ -173,6 +159,7 @@ const handleSaveProject = (index,item,type='image')=>{
|
|||
case 'model':
|
||||
cardItem.modelUrl = item.modelUrl;
|
||||
cardItem.taskId = item.taskId;
|
||||
cardItem.resultTask = item.resultTask;
|
||||
break;
|
||||
}
|
||||
cardItem.status = item.status;
|
||||
|
|
@ -190,7 +177,6 @@ const createProject = async ()=>{
|
|||
}
|
||||
//获取项目信息
|
||||
const getProjectInfo = async (id)=>{
|
||||
showSidebarTransition();
|
||||
const data = await PluginProject.getProject(id);
|
||||
console.log(data,'data');
|
||||
projectInfo.value = {...data};
|
||||
|
|
@ -199,7 +185,6 @@ const getProjectInfo = async (id)=>{
|
|||
...card,
|
||||
id: card.id || Date.now() + Math.random().toString(36).substr(2, 9)
|
||||
}));
|
||||
hideSidebarTransition();
|
||||
}
|
||||
//更新项目信息
|
||||
const updateProjectInfo = async (newProjectInfo)=>{
|
||||
|
|
@ -442,7 +427,7 @@ const handleCreatePromptCard = (index,params) => {
|
|||
const handleGenerateRequested = async (params) => {
|
||||
// 根据请求的数量动态生成对应数量的IPCard组件实例
|
||||
const {count,profile,inspirationImage,ipType,ipTypeImg} = params
|
||||
for (let i = 0; i < count; i++) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
// 使用统一的智能定位和层级管理系统创建卡片
|
||||
const newCard = createSmartCard({
|
||||
imageUrl: null, // 初始为空,将由IPCard组件自己生成
|
||||
|
|
@ -455,6 +440,8 @@ const handleGenerateRequested = async (params) => {
|
|||
});
|
||||
// 添加到卡片数组
|
||||
cards.value.push(newCard);
|
||||
// 等待 200 毫秒
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -886,75 +873,6 @@ html.dark .sidebar-container {
|
|||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* 侧边栏过渡动画蒙层 */
|
||||
.sidebar-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(107, 70, 193, 0.1);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
z-index: 9999;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 蒙层激活状态 */
|
||||
.sidebar-overlay-active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* 转圈加载动画 */
|
||||
.sidebar-overlay::before {
|
||||
content: '';
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 4px solid rgba(255, 255, 255, 0.3);
|
||||
border-top: 4px solid #ffffff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
box-shadow: 0 0 20px rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.sidebar-overlay::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.1);
|
||||
border-bottom: 2px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
animation: spin 1.5s linear infinite reverse;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 暗色主题下的蒙层效果 */
|
||||
html.dark .sidebar-overlay {
|
||||
background: rgba(31, 41, 55, 0.85);
|
||||
}
|
||||
|
||||
html.dark .sidebar-overlay::before {
|
||||
border: 4px solid rgba(255, 255, 255, 0.2);
|
||||
border-top: 4px solid #A78BFA;
|
||||
box-shadow: 0 0 20px rgba(167, 139, 250, 0.5);
|
||||
}
|
||||
|
||||
html.dark .sidebar-overlay::after {
|
||||
border: 2px solid rgba(167, 139, 250, 0.1);
|
||||
border-bottom: 2px solid rgba(167, 139, 250, 0.4);
|
||||
}
|
||||
|
||||
/* 测试动画按钮样式 */
|
||||
.test-animation-btn {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
"element-plus": "^2.11.7",
|
||||
"jose": "^6.1.1",
|
||||
"normalize.css": "^8.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
"three": "^0.180.0",
|
||||
|
|
@ -4943,6 +4944,12 @@
|
|||
"integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nprogress": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/nprogress/-/nprogress-0.2.0.tgz",
|
||||
"integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nth-check": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const login = {
|
||||
LOGIN:{url:'/api-base/user/login',method:'POST'},// 登录
|
||||
LOGOUT:{url:'/api-base/user/logout',method:'POST',isLoading:true},// 登出
|
||||
LOGOUT:{url:'/api-base/user/logout',method:'POST',isLoading:true,isqp:true},// 登出
|
||||
REGISTER:{url:'/api-base/user/register',method:'POST'},// 注册
|
||||
SEND_EMAIL_CODE:{url:'/api-base/user/send-email-code',method:'POST'},// 发送邮箱验证码
|
||||
OAUTH_GOOGLE:{url:'/api-base/user/oauth/google',method:'POST'},// google弹窗授权
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const order = {
|
||||
getOrderList:{url:'/api-core/front/order/list',method:'POST'},// 获取订单列表
|
||||
getOrderList:{url:'/api-core/front/order/list',method:'POST',isLoading:true},// 获取订单列表
|
||||
getOrderDetail:{url:'/api-core/front/order/get',method:'GET'},// 获取订单详情
|
||||
orderCancel:{url:'/api-core/front/order/cancel',method:'POST'},// 取消订单支付
|
||||
receiveAddress:{url:'/api-core/front/order/receive',method:'POST'},// 确认收货
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ const login = {
|
|||
* 项目详情接口
|
||||
* 引用示例: PROJECT_GET
|
||||
*/
|
||||
PROJECT_GET:{url:'/api-core/front/project/get',method:'GET'},
|
||||
PROJECT_GET:{url:'/api-core/front/project/get',method:'GET',isLoading:true},
|
||||
/**
|
||||
* 项目列表接口
|
||||
* 引用示例: PROJECT_LIST
|
||||
*/
|
||||
PROJECT_LIST:{url:'/api-core/front/project/list',method:'POST'},
|
||||
PROJECT_LIST:{url:'/api-core/front/project/list',method:'POST',isLoading:true},
|
||||
}
|
||||
export default login;
|
||||
|
|
|
|||
|
|
@ -19,10 +19,13 @@ const getPorjectType = () => {
|
|||
};
|
||||
export class GiminiServer extends FileServer {
|
||||
RULE = getPorjectType();
|
||||
// 任务并发队列
|
||||
static taskQueue = new Map();
|
||||
//最高并发限制
|
||||
static MAX_CONCURRENT_TASKS = 4;
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从URL获取MIME类型
|
||||
* @param {*} url 图片URL
|
||||
|
|
@ -141,8 +144,17 @@ export class GiminiServer extends FileServer {
|
|||
}
|
||||
})
|
||||
};
|
||||
//线上生成模型
|
||||
//线上生图片模型
|
||||
async generateImageFromMultipleImagesOnline(baseImages, prompt,config={}){
|
||||
if(GiminiServer.taskQueue.size >= GiminiServer.MAX_CONCURRENT_TASKS){
|
||||
window.setElMessage({
|
||||
type:'warning',
|
||||
message:'Concurrent limit reached'
|
||||
})
|
||||
return Promise.reject('Concurrent limit reached');
|
||||
}
|
||||
const taskId = new Date().getTime();
|
||||
GiminiServer.taskQueue.set(taskId, taskId);
|
||||
return new Promise(async (resolve, reject) => {
|
||||
// 标准化输入:确保 baseImages 是数组
|
||||
baseImages = Array.isArray(baseImages) ? baseImages : [baseImages];
|
||||
|
|
@ -163,24 +175,12 @@ export class GiminiServer extends FileServer {
|
|||
const imageParts = await Promise.all(images.map(async image =>{
|
||||
return await this.dataUrlToGenerativePart(image,'url');
|
||||
} ));
|
||||
// 构建请求的 parts 数组
|
||||
// const params = {
|
||||
// "aspect_ratio": "9:16",
|
||||
// "model": "gemini-2.5-flash-image",
|
||||
// "location": "global",
|
||||
// "vertexai": true,
|
||||
// ...config,
|
||||
// inputs: [
|
||||
// ...imageParts,
|
||||
// { text: prompt }
|
||||
// ]
|
||||
// }
|
||||
const params = {
|
||||
"aspect_ratio": "9:16",
|
||||
"model": "gemini-2.5-flash-image",//models/gemini-3-pro-image-preview
|
||||
"location": "global",
|
||||
"vertexai": true,
|
||||
...config,
|
||||
const params = {
|
||||
"aspect_ratio": "9:16",
|
||||
"model": "gemini-2.5-flash-image",//models/gemini-3-pro-image-preview/"gemini-2.5-flash-image",
|
||||
"location": "global",
|
||||
"vertexai": true,
|
||||
...config,
|
||||
inputs: [
|
||||
...imageParts,
|
||||
{ text: prompt }
|
||||
|
|
@ -188,19 +188,6 @@ const params = {
|
|||
}
|
||||
const requestUrl = this.RULE=='admin'?adminApi.default.GENERATE_IMAGE_ADMIN:clientApi.default.GENERATE_IMAGE;
|
||||
const response = await requestUtils.common(requestUrl, params);
|
||||
// const response = {
|
||||
// "code": 0,
|
||||
// "message": "",
|
||||
// "success": true,
|
||||
// "data": {
|
||||
// "urls": [
|
||||
// {
|
||||
// "url": "/upload/51831c919193447e86843388ae31fc48.png",
|
||||
// "mime_type": "image/png"
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// }
|
||||
if(response.data.error){
|
||||
reject(response.data.error.message);
|
||||
return;
|
||||
|
|
@ -217,6 +204,9 @@ const params = {
|
|||
} catch (error) {
|
||||
reject(error);
|
||||
console.log(error, 'errorerrorerrorerrorerrorerror');
|
||||
} finally {
|
||||
// 任务完成后从队列中移除
|
||||
GiminiServer.taskQueue.delete(taskId);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,27 @@ const getPorjectType = () => {
|
|||
};
|
||||
export class MeshyServer extends FileServer {
|
||||
RULE = getPorjectType();
|
||||
// 任务并发队列
|
||||
static taskQueue = new Map();
|
||||
//最高并发限制
|
||||
static MAX_CONCURRENT_TASKS = 1;
|
||||
static pollingEnabled = true;
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
//提交模型任务返回id
|
||||
async createModelTask(item={},callback,errorCallback,config={}) {
|
||||
// 检查当前并发任务数
|
||||
if(MeshyServer.taskQueue.size >= MeshyServer.MAX_CONCURRENT_TASKS){
|
||||
window.setElMessage({
|
||||
type:'warning',
|
||||
message:'Concurrent limit reached'
|
||||
})
|
||||
errorCallback&&errorCallback('Concurrent limit reached');
|
||||
return Promise.reject('Concurrent limit reached');
|
||||
}
|
||||
const taskId = new Date().getTime();
|
||||
MeshyServer.taskQueue.set(taskId, taskId);
|
||||
try {
|
||||
let params = {
|
||||
project_id: item.project_id,
|
||||
|
|
@ -51,7 +66,7 @@ export class MeshyServer extends FileServer {
|
|||
// }
|
||||
// };
|
||||
if(response.code==0){
|
||||
callback&&callback(response?.data?.result);
|
||||
callback&&callback(response?.data?.result,taskId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('创建模型任务失败:', error);
|
||||
|
|
@ -59,29 +74,36 @@ export class MeshyServer extends FileServer {
|
|||
throw error;
|
||||
}
|
||||
}
|
||||
static demoNum = 0;
|
||||
//查询任务状态
|
||||
async getModelTaskStatus(result,callback,errorCallback,progressCallback){
|
||||
async getModelTaskStatus(resultItem,callback,errorCallback,progressCallback){
|
||||
const result = resultItem.result;
|
||||
const resultTask = resultItem.resultTask;
|
||||
if(!MeshyServer.taskQueue.has(resultTask)){//用户刷新了页面清除了任务队列重新添加进任务队列
|
||||
MeshyServer.taskQueue.set(resultTask, resultTask);
|
||||
}
|
||||
try {
|
||||
const requestUrl = {
|
||||
url:this.RULE=='admin'?adminApi.default.FIND_TASK_IDADMIN.url.replace('TASKID', result):clientApi.default.FIND_TASK_ID.url.replace('TASKID', result),
|
||||
method:this.RULE=='admin'?adminApi.default.FIND_TASK_IDADMIN.method:clientApi.default.FIND_TASK_ID.method,
|
||||
};
|
||||
|
||||
let response = await requestUtils.common(requestUrl, {});
|
||||
if(response.code==0){
|
||||
let data = response?.data
|
||||
console.log(data,'查询任务状态');
|
||||
|
||||
switch (data.status) {
|
||||
case 1:
|
||||
// let modelurl = data.model_url.replace("https://assets.meshy.ai", "https://api.deotaland.ai/model");
|
||||
let modelurl = data.result.s3_glb_url;
|
||||
resultTask&&MeshyServer.taskQueue.delete(resultTask);
|
||||
callback&&callback(modelurl);
|
||||
break;
|
||||
case 2:
|
||||
errorCallback&&errorCallback();
|
||||
resultTask&&MeshyServer.taskQueue.delete(resultTask);
|
||||
break;
|
||||
case 3:
|
||||
errorCallback&&errorCallback();
|
||||
resultTask&&MeshyServer.taskQueue.delete(resultTask);
|
||||
break;
|
||||
default:
|
||||
if(!MeshyServer.pollingEnabled){//如果禁用轮询,直接返回
|
||||
|
|
@ -90,9 +112,18 @@ export class MeshyServer extends FileServer {
|
|||
// 等待三秒
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
progressCallback&&progressCallback(data.progress);
|
||||
this.getModelTaskStatus(result,callback,errorCallback,progressCallback);
|
||||
this.getModelTaskStatus({
|
||||
result:result,
|
||||
resultTask:resultTask,
|
||||
},callback,errorCallback,progressCallback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
resultTask&&MeshyServer.taskQueue.delete(resultTask);
|
||||
errorCallback&&errorCallback(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import axios from 'axios';
|
||||
var ElLoading = null
|
||||
var closeMethods = null
|
||||
// 获取环境变量中的基础URL
|
||||
const getEnvBaseURL = () => {
|
||||
// 浏览器环境
|
||||
|
|
@ -50,8 +50,8 @@ service.interceptors.request.use(
|
|||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
if(ElLoading){
|
||||
ElLoading.close()
|
||||
if(closeMethods){
|
||||
closeMethods.close()
|
||||
}
|
||||
// 直接返回响应数据
|
||||
const res = response.data;
|
||||
|
|
@ -183,7 +183,7 @@ export const request = {
|
|||
requestConfig.data = data;
|
||||
}
|
||||
if(config.isLoading){
|
||||
ElLoading = window.setElLoading()
|
||||
closeMethods = window.setElLoading(config.isqp)
|
||||
}
|
||||
return service(requestConfig);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ importers:
|
|||
version: 5.44.1
|
||||
unplugin-auto-import:
|
||||
specifier: ^20.2.0
|
||||
version: 20.2.0(@vueuse/core@14.1.0)
|
||||
version: 20.2.0
|
||||
unplugin-vue-components:
|
||||
specifier: ^30.0.0
|
||||
version: 30.0.0(vue@3.5.24)
|
||||
|
|
@ -132,6 +132,9 @@ importers:
|
|||
normalize.css:
|
||||
specifier: ^8.0.1
|
||||
version: 8.0.1
|
||||
nprogress:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
pinia:
|
||||
specifier: ^3.0.4
|
||||
version: 3.0.4(vue@3.5.24)
|
||||
|
|
@ -1285,10 +1288,6 @@ packages:
|
|||
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
|
||||
dev: false
|
||||
|
||||
/@types/web-bluetooth@0.0.21:
|
||||
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
|
||||
dev: true
|
||||
|
||||
/@types/webxr@0.5.24:
|
||||
resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==}
|
||||
dev: false
|
||||
|
|
@ -1424,17 +1423,6 @@ packages:
|
|||
vue-demi: 0.13.11(vue@3.5.24)
|
||||
dev: false
|
||||
|
||||
/@vueuse/core@14.1.0(vue@3.5.24):
|
||||
resolution: {integrity: sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
dependencies:
|
||||
'@types/web-bluetooth': 0.0.21
|
||||
'@vueuse/metadata': 14.1.0
|
||||
'@vueuse/shared': 14.1.0(vue@3.5.24)
|
||||
vue: 3.5.24
|
||||
dev: true
|
||||
|
||||
/@vueuse/core@9.13.0(vue@3.5.24):
|
||||
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
|
||||
dependencies:
|
||||
|
|
@ -1447,22 +1435,10 @@ packages:
|
|||
- vue
|
||||
dev: false
|
||||
|
||||
/@vueuse/metadata@14.1.0:
|
||||
resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==}
|
||||
dev: true
|
||||
|
||||
/@vueuse/metadata@9.13.0:
|
||||
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
|
||||
dev: false
|
||||
|
||||
/@vueuse/shared@14.1.0(vue@3.5.24):
|
||||
resolution: {integrity: sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.0
|
||||
dependencies:
|
||||
vue: 3.5.24
|
||||
dev: true
|
||||
|
||||
/@vueuse/shared@9.13.0(vue@3.5.24):
|
||||
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
|
||||
dependencies:
|
||||
|
|
@ -2924,6 +2900,10 @@ packages:
|
|||
resolution: {integrity: sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==}
|
||||
dev: false
|
||||
|
||||
/nprogress@0.2.0:
|
||||
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
|
||||
dev: false
|
||||
|
||||
/nth-check@2.1.1:
|
||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||
dependencies:
|
||||
|
|
@ -3525,27 +3505,6 @@ packages:
|
|||
unplugin-utils: 0.3.1
|
||||
dev: true
|
||||
|
||||
/unplugin-auto-import@20.2.0(@vueuse/core@14.1.0):
|
||||
resolution: {integrity: sha512-vfBI/SvD9hJqYNinipVOAj5n8dS8DJXFlCKFR5iLDp2SaQwsfdnfLXgZ+34Kd3YY3YEY9omk8XQg0bwos3Q8ug==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
'@nuxt/kit': ^4.0.0
|
||||
'@vueuse/core': '*'
|
||||
peerDependenciesMeta:
|
||||
'@nuxt/kit':
|
||||
optional: true
|
||||
'@vueuse/core':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@vueuse/core': 14.1.0(vue@3.5.24)
|
||||
local-pkg: 1.1.2
|
||||
magic-string: 0.30.21
|
||||
picomatch: 4.0.3
|
||||
unimport: 5.5.0
|
||||
unplugin: 2.3.10
|
||||
unplugin-utils: 0.3.1
|
||||
dev: true
|
||||
|
||||
/unplugin-icons@22.5.0:
|
||||
resolution: {integrity: sha512-MBlMtT5RuMYZy4TZgqUL2OTtOdTUVsS1Mhj6G1pEzMlFJlEnq6mhUfoIt45gBWxHcsOdXJDWLg3pRZ+YmvAVWQ==}
|
||||
peerDependencies:
|
||||
|
|
|
|||
Loading…
Reference in New Issue