This commit is contained in:
13121765685 2025-12-08 14:59:11 +08:00
parent 79630d2802
commit 9f7047fbb9
25 changed files with 345 additions and 443 deletions

View File

@ -70,6 +70,10 @@ import { MeshyServer } from '@deotaland/utils'
const meshServer = new MeshyServer() const meshServer = new MeshyServer()
const isLoading = ref(false); const isLoading = ref(false);
const props = defineProps({ const props = defineProps({
resultTask: {
type: String,
required: true
},
taskId: { taskId: {
type: String, type: String,
required: true required: true
@ -150,24 +154,27 @@ watch(() => initializationProgress.value, (newVal) => {
}) })
const loadmodelUrl = ()=>{ const loadmodelUrl = ()=>{
if(props.taskId){ if(props.taskId){
startModelTask(props.taskId) startModelTask(props.taskId,props.resultTask)
} }
else if(props.imgUrl){ else if(props.imgUrl){
meshServer.createModelTask({ meshServer.createModelTask({
image_url:props.imgUrl, image_url:props.imgUrl,
project_id:props.projectId project_id:props.projectId
},(result)=>{ },(result,resultTask)=>{
emit('save',result) emit('save',result,resultTask)
startModelTask(result) startModelTask(result,resultTask)
},()=>{ },()=>{
emit('delete') emit('delete')
},{ },{
}) })
} }
} }
const startModelTask = (result) => { const startModelTask = (result,resultTask) => {
showInitializationOverlay.value = true; showInitializationOverlay.value = true;
meshServer.getModelTaskStatus(result,(modelurl)=>{ meshServer.getModelTaskStatus({
result:result,
resultTask:resultTask,
},(modelurl)=>{
setInitializationProgress(100) setInitializationProgress(100)
modelUrl.value = modelurl; modelUrl.value = modelurl;
},(error)=>{ },(error)=>{

View File

@ -160,10 +160,11 @@
@preview="previewModel" @preview="previewModel"
:img-url="item.image" :img-url="item.image"
:task-id="item.taskId" :task-id="item.taskId"
:result-task="item.resultTask"
width="100%" width="100%"
height="150px" height="150px"
:project-id="orderDetail.projectId" :project-id="orderDetail.projectId"
@save="(result)=>saveModel(index,result)" @save="(result,resultTask)=>saveModel(index,result,resultTask)"
:show-delete="true" :show-delete="true"
@delete="deleteModel(index)" @delete="deleteModel(index)"
/> />
@ -312,9 +313,9 @@ const orderDetail = ref({
status: 'pending', status: 'pending',
processingCompleteTime: null processingCompleteTime: null
}) })
const saveModel = (index,result)=>{ const saveModel = (index,result,resultTask)=>{
console.log(index,result,'currentStepcurrentStep');
generatedModels.value[index].taskId = result; generatedModels.value[index].taskId = result;
generatedModels.value[index].resultTask = resultTask;
} }
// //
@ -485,20 +486,7 @@ const handleDisassembly = () => {
const deleteModel = (index) => { const deleteModel = (index) => {
ElMessageBox.confirm(
'确定要删除这个模型吗?',
'删除确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
).then(() => {
generatedModels.value.splice(index, 1) generatedModels.value.splice(index, 1)
ElMessage.success('模型已删除')
}).catch(() => {
//
})
} }
// //
const handleProcessingComplete = () => { const handleProcessingComplete = () => {

View File

@ -26,6 +26,7 @@
"element-plus": "^2.11.7", "element-plus": "^2.11.7",
"jose": "^6.1.1", "jose": "^6.1.1",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1", "pinia-plugin-persistedstate": "^4.7.1",
"three": "^0.180.0", "three": "^0.180.0",

View File

@ -18,7 +18,6 @@ function initializeTheme() {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
const savedTheme = localStorage.getItem('theme') const savedTheme = localStorage.getItem('theme')
const hasDarkClass = document.documentElement.classList.contains('dark') const hasDarkClass = document.documentElement.classList.contains('dark')
if (savedTheme === 'dark') { if (savedTheme === 'dark') {
document.documentElement.classList.add('dark') document.documentElement.classList.add('dark')
themeState.value = true 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 // Initialize on component mount
onMounted(() => { onMounted(() => {
initializeTheme() initializeTheme()
@ -44,41 +58,119 @@ onMounted(() => {
'fullscreen-mode': isFullScreenPage, 'fullscreen-mode': isFullScreenPage,
'homepage-mode': isHomePage '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 /> <router-view />
</main> </main>
<!-- 全屏页面如创建项目 --> <!-- 全屏页面如创建项目 -->
<main v-else-if="isFullScreenPage" class="fullscreen-content"> <main v-else-if="isFullScreenPage" class="fullscreen-content">
<div class="sidebar-overlay" :class="{ 'sidebar-overlay-active': loading }"></div>
<router-view /> <router-view />
</main> </main>
<!-- 应用内页面使用布局组件 --> <!-- 应用内页面使用布局组件 -->
<MainLayout v-else> <div v-else style="position: relative;">
<MainLayout :loading="loading" >
<template #header> <template #header>
<AppHeader /> <AppHeader />
</template> </template>
<template #sidebar> <template #sidebar>
<AppSidebar /> <AppSidebar />
</template> </template>
<template #default> <template #default>
<router-view /> <router-view />
</template> </template>
</MainLayout> </MainLayout>
</div> </div>
</div>
<div v-else> <div v-else>
<router-view /> <router-view />
</div> </div>
</template> </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> <style scoped>
header strong { font-size: 1.25rem; } header strong { font-size: 1.25rem; }
/* 应用容器基础样式 */ /* 应用容器基础样式 */
#app-container { #app-container {
width: 100vw; width: 100vw;
@ -119,7 +211,7 @@ header strong { font-size: 1.25rem; }
height: 100vh !important; height: 100vh !important;
margin: 0 !important; margin: 0 !important;
padding: 0 !important; padding: 0 !important;
overflow: auto !important; /* 确保全屏内容可以滚动 */ position: relative;
} }
/* 首页全屏滚动模式 - 使用浏览器原生滚动 */ /* 首页全屏滚动模式 - 使用浏览器原生滚动 */

View File

@ -288,7 +288,7 @@ const handleGenerateImage = async () => {
formData.value.status = 'success'; formData.value.status = 'success';
saveProject(); saveProject();
} catch (error) { } catch (error) {
ElMessage.error('生成图片失败,请稍后重试'); // ElMessage.error('');
emit('delete'); emit('delete');
} }
}; };

View File

@ -282,7 +282,7 @@ const formData = ref({
const textareaRef = ref(null); const textareaRef = ref(null);
const fileInput = ref(null); // const fileInput = ref(null); //
const generateCount = ref(1); // 1 const generateCount = ref(4); // 1
const isOptimizing = ref(false); // const isOptimizing = ref(false); //
const isDragOver = ref(false); // const isDragOver = ref(false); //
// IP/ // IP/

View File

@ -62,7 +62,7 @@
<el-dropdown-item command="settings"> <el-dropdown-item command="settings">
{{ t('header.settings') }} {{ t('header.settings') }}
</el-dropdown-item> --> </el-dropdown-item> -->
<el-dropdown-item divided command="logout"> <el-dropdown-item command="logout">
<LogoutIcon class="dropdown-item-icon" /> <LogoutIcon class="dropdown-item-icon" />
{{ t('header.logout') }} {{ t('header.logout') }}
</el-dropdown-item> </el-dropdown-item>
@ -545,7 +545,7 @@ export default {
font-weight: 500; font-weight: 500;
color: var(--text-primary, #1f2937); color: var(--text-primary, #1f2937);
max-width: 100px; max-width: 100px;
overflow: hidden; /* overflow: hidden; */
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }

View File

@ -476,7 +476,7 @@ export default {
font-weight: 600; font-weight: 600;
color: var(--text-primary, #1f2937); color: var(--text-primary, #1f2937);
white-space: nowrap; white-space: nowrap;
overflow: hidden; /* overflow: hidden; */
text-overflow: ellipsis; text-overflow: ellipsis;
letter-spacing: 0.02em; letter-spacing: 0.02em;
line-height: 1.3; line-height: 1.3;

View File

@ -1,11 +1,5 @@
<template> <template>
<div class="main-layout" :class="layoutClasses"> <div class="main-layout" :class="layoutClasses">
<!-- 移动端遮罩层 -->
<div
v-if="isMobile && sidebarVisible"
class="sidebar-overlay"
@click="toggleSidebar"
></div>
<!-- 第一行头部导航栏 --> <!-- 第一行头部导航栏 -->
<header class="header-container"> <header class="header-container">
@ -28,11 +22,13 @@
</aside> </aside>
<!-- 主内容区域 --> <!-- 主内容区域 -->
<div class="main-content" :class="{ 'sidebar-collapsed': !sidebarVisible && !isMobile }"> <div class="main-content" :class="{ 'sidebar-collapsed': !sidebarVisible && !isMobile }">
<div class="sidebar-overlay" :class="{ 'sidebar-overlay-active': loading }"></div>
<!-- 面包屑导航 --> <!-- 面包屑导航 -->
<!-- <BreadcrumbNavigation class="breadcrumb-container" /> --> <!-- <BreadcrumbNavigation class="breadcrumb-container" /> -->
<!-- 页面内容 --> <!-- 页面内容 -->
<main class="page-content"> <main class="page-content">
<router-view v-slot="{ Component, route }"> <router-view v-slot="{ Component, route }">
<keep-alive v-if="route.meta.keepAlive"> <keep-alive v-if="route.meta.keepAlive">
<component :is="Component" :key="route.name" /> <component :is="Component" :key="route.name" />
@ -45,20 +41,22 @@
</div> </div>
</template> </template>
<script> <script setup>
import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue' import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue'
import AppHeader from './AppHeader.vue' import AppHeader from './AppHeader.vue'
import AppSidebar from './AppSidebar.vue' import AppSidebar from './AppSidebar.vue'
import BreadcrumbNavigation from './BreadcrumbNavigation.vue' import BreadcrumbNavigation from './BreadcrumbNavigation.vue'
export default { //
name: 'MainLayout', defineOptions({
components: { name: 'MainLayout'
AppHeader, })
AppSidebar, const props = defineProps({
BreadcrumbNavigation loading: {
}, type: Boolean,
setup() { default: false
}
})
// //
const state = reactive({ const state = reactive({
screenWidth: window.innerWidth, screenWidth: window.innerWidth,
@ -80,6 +78,12 @@ export default {
'desktop-layout': state.isDesktop 'desktop-layout': state.isDesktop
})) }))
// 使
const sidebarVisible = computed(() => state.sidebarVisible)
const isMobile = computed(() => state.isMobile)
const isTablet = computed(() => state.isTablet)
const isDesktop = computed(() => state.isDesktop)
// //
const updateBreakpoints = () => { const updateBreakpoints = () => {
state.screenWidth = window.innerWidth state.screenWidth = window.innerWidth
@ -104,8 +108,6 @@ export default {
} }
} }
// //
const handleNavigate = (route) => { const handleNavigate = (route) => {
// //
@ -142,18 +144,6 @@ export default {
state.sidebarVisible = false state.sidebarVisible = false
} }
}) })
return {
sidebarVisible: computed(() => state.sidebarVisible),
isMobile: computed(() => state.isMobile),
isTablet: computed(() => state.isTablet),
isDesktop: computed(() => state.isDesktop),
layoutClasses,
toggleSidebar,
handleNavigate
}
}
}
</script> </script>
<style scoped> <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 { .main-content {
@ -222,6 +202,7 @@ export default {
width: 100%; width: 100%;
/* 移除 overflow: hidden 以允许页面滚动 */ /* 移除 overflow: hidden 以允许页面滚动 */
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
} }
.breadcrumb-container { .breadcrumb-container {

View File

@ -108,7 +108,7 @@ import { computed, ref, onMounted } from 'vue';
import ThreeModelViewer from '../ThreeModelViewer/index.vue'; import ThreeModelViewer from '../ThreeModelViewer/index.vue';
import { MeshyServer } from '@deotaland/utils'; 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 Meshy = new MeshyServer();
// //
const showRightControls = ref(false); const showRightControls = ref(false);
@ -137,28 +137,30 @@ const handleGenerateModel = async () => {
let result; let result;
if(props.cardData.taskId){ if(props.cardData.taskId){
result = props.cardData.taskId; result = props.cardData.taskId;
TaskStatus(result); TaskStatus(result,props.cardData.resultTask);
return return
} }
Meshy.createModelTask({ Meshy.createModelTask({
project_id: props.cardData.project_id, project_id: props.cardData.project_id,
image_url: props.cardData.imageUrl, image_url: props.cardData.imageUrl,
},(result)=>{ },(result,resultTask)=>{
if(result){ if(result){
emit('save-project',{ emit('save-project',{
...props.cardData, ...props.cardData,
resultTask:resultTask,
taskId:result taskId:result
}); });
TaskStatus(result); TaskStatus(result,resultTask);
} }
},(error)=>{ },(error)=>{
console.error('模型生成失败:', error); emit('delete');
isGenerating.value = false;
progressPercentage.value = 0;
},{}) },{})
}; };
const TaskStatus = (result)=>{ const TaskStatus = (result,resultTask)=>{
Meshy.getModelTaskStatus(result,(modelUrl)=>{ Meshy.getModelTaskStatus({
result:result,
resultTask:resultTask,
},(modelUrl)=>{
if(modelUrl){ if(modelUrl){
// //
generatedModelUrl.value = modelUrl; generatedModelUrl.value = modelUrl;
@ -173,8 +175,7 @@ const TaskStatus = (result)=>{
} }
},(error)=>{ },(error)=>{
console.error('模型生成失败:', error); console.error('模型生成失败:', error);
isGenerating.value = false; emit('delete');
progressPercentage.value = 0;
},(progress)=>{ },(progress)=>{
if (progress !== undefined) { if (progress !== undefined) {
progressPercentage.value = progress; progressPercentage.value = progress;

View File

@ -18,20 +18,21 @@ import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import VueLazyload from 'vue3-lazyload' import VueLazyload from 'vue3-lazyload'
import 'element-plus/dist/index.css' import 'element-plus/dist/index.css'
import 'nprogress/nprogress.css'
import {ElMessage,ElLoading } from 'element-plus' import {ElMessage,ElLoading } from 'element-plus'
const app = createApp(App) const app = createApp(App)
window.setElMessage = (options={})=>{ window.setElMessage = (options={})=>{
ElMessage[options.type || 'info'](options.message || '请求失败') ElMessage[options.type || 'info'](options.message || '请求失败')
} }
window.setElLoading = ()=>{ // window.setElLoading = ()=>{
const loading = ElLoading.service({ // const loading = ElLoading.service({
lock: true, // lock: true,
text: 'Loading', // text: 'Loading',
background: 'rgba(0, 0, 0, 0.4)', // background: 'rgba(0, 0, 0, 0.4)',
}) // })
return loading // return loading
// loading.close() // // loading.close()
} // }
// Pinia // Pinia
const pinia = createPinia() const pinia = createPinia()
pinia.use(piniaPluginPersistedstate) pinia.use(piniaPluginPersistedstate)

View File

@ -1,6 +1,6 @@
import { createRouter, createWebHistory,createWebHashHistory} from 'vue-router' import { createRouter, createWebHistory,createWebHashHistory} from 'vue-router'
import { useAuthStore } from '@/stores/auth' import { useAuthStore } from '@/stores/auth'
import NProgress from 'nprogress'
const ModernHome = () => import('../views/ModernHome.vue') const ModernHome = () => import('../views/ModernHome.vue')
const List = () => import('../views/List.vue') const List = () => import('../views/List.vue')
const Login = () => import('../views/Login/Login.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 AddAgent = () => import('../views/AddAgent.vue')
const UiTest = () => import('../views/UiTest.vue') const UiTest = () => import('../views/UiTest.vue')
const home = () => import('../views/home/index.vue') const home = () => import('../views/home/index.vue')
NProgress.configure({
showSpinner: false,
})// 开启轻量模式(顶部细线)
// 路由配置 // 路由配置
const routes = [ const routes = [
{ {
@ -128,9 +130,9 @@ const router = createRouter({
// 路由守卫 // 路由守卫
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start()
// window.localStorage.setItem('token','123') // window.localStorage.setItem('token','123')
// return next() // return next()
// 检查是否需要登录
if (to.meta.requiresAuth) { if (to.meta.requiresAuth) {
const token = localStorage.getItem('token') const token = localStorage.getItem('token')
// 如果没有 token跳转到登录页 // 如果没有 token跳转到登录页
@ -139,16 +141,10 @@ router.beforeEach(async (to, from, next) => {
return return
} }
} }
// 检查是否需要游客身份
if (to.meta.requiresGuest) {
const authStore = useAuthStore()
// 如果有 token跳转到首页
if (authStore.token) {
next('/')
return
}
}
next() next()
}) })
router.afterEach(() => {
NProgress.done()
})
export default router export default router

View File

@ -45,7 +45,6 @@ export const useAuthStore = defineStore('auth', () => {
callback&&callback(); callback&&callback();
const router = useRouter(); const router = useRouter();
localStorage.removeItem('token') localStorage.removeItem('token')
router.replace({ name: 'login' });
} }
} }

View File

@ -81,19 +81,6 @@
</div> </div>
</div> </div>
</el-scrollbar> </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 <div
v-if="showTrash" v-if="showTrash"
@ -111,65 +98,6 @@
<p>{{ $t('creationWorkspace.dropToDeleteHint') }}</p> <p>{{ $t('creationWorkspace.dropToDeleteHint') }}</p>
</div> </div>
</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 <div
v-if="showDeleteConfirm" v-if="showDeleteConfirm"
@ -226,7 +154,6 @@ export default {
setup() { setup() {
const { t } = useI18n() const { t } = useI18n()
const router = useRouter() const router = useRouter()
// //
const showModal = ref(false) const showModal = ref(false)
const modalType = ref('') // 'view' or 'edit' const modalType = ref('') // 'view' or 'edit'

View File

@ -23,6 +23,7 @@
<div class="google-login-section"> <div class="google-login-section">
<GoogleOAuthButton <GoogleOAuthButton
@success="handleLoginSuccess" @success="handleLoginSuccess"
:loading="plugin.loading"
/> />
</div> </div>
@ -37,6 +38,7 @@
<div class="email-login-section"> <div class="email-login-section">
<LoginForm <LoginForm
@login="handleLogin" @login="handleLogin"
:loading="plugin.loading"
/> />
</div> </div>
<!-- 角色信息展示 --> <!-- 角色信息展示 -->
@ -68,7 +70,6 @@
<el-icon class="error-icon"><WarningFilled /></el-icon> <el-icon class="error-icon"><WarningFilled /></el-icon>
<span>{{ authStore.error }}</span> <span>{{ authStore.error }}</span>
</div> </div>
<!-- 忘记密码和注册链接 --> <!-- 忘记密码和注册链接 -->
<div class="auth-links"> <div class="auth-links">
<div class="auth-links-row"> <div class="auth-links-row">

View File

@ -3,12 +3,15 @@ import { useRouter } from 'vue-router'
import {ElMessage} from 'element-plus'; import {ElMessage} from 'element-plus';
import { useAuthStore } from '@/stores/auth.js'; import { useAuthStore } from '@/stores/auth.js';
export default class Login { export default class Login {
loading = false;//登录loading
constructor() { constructor() {
this.router = useRouter(); this.router = useRouter();
this.authStore = useAuthStore(); this.authStore = useAuthStore();
} }
async login(data) { async login(data) {
this.loading = true;
this.authStore.login(data,()=>{ this.authStore.login(data,()=>{
this.loading = false;
this.router.push({ name: 'czhome' }) this.router.push({ name: 'czhome' })
// this.refreshGoogleRefreshToken() // this.refreshGoogleRefreshToken()
}); });

View File

@ -1,6 +1,5 @@
<template> <template>
<div class="creative-zone" :style="{ '--grid-size': `${gridSize}px` }"> <div class="creative-zone" :style="{ '--grid-size': `${gridSize}px` }">
<div class="sidebar-overlay" :class="{ 'sidebar-overlay-active': showSidebarOverlay }"></div>
<!-- 顶部固定头部组件 --> <!-- 顶部固定头部组件 -->
<div class="header-wrapper"> <div class="header-wrapper">
<HeaderComponent :projectName="projectInfo.title" @updateProjectInfo="projectInfo = {...projectInfo, ...$event}" @openGuideModal="showGuideModal = true" /> <HeaderComponent :projectName="projectInfo.title" @updateProjectInfo="projectInfo = {...projectInfo, ...$event}" @openGuideModal="showGuideModal = true" />
@ -72,6 +71,7 @@
v-else-if="card.type === 'model'" v-else-if="card.type === 'model'"
:cardData="card" :cardData="card"
:clickDisabled="isElementDragging" :clickDisabled="isElementDragging"
@delete="handleDeleteCard(index)"
:projectId="projectId" :projectId="projectId"
@save-project="(item)=>{handleSaveProject(index,item,'model')}" @save-project="(item)=>{handleSaveProject(index,item,'model')}"
@clickModel="handleModelClick" @clickModel="handleModelClick"
@ -134,20 +134,6 @@ const selectedModel = ref(null);
const showImportModal = ref(false); const showImportModal = ref(false);
const importUrl = ref('https://xiaozhi.me/console/agents'); const importUrl = ref('https://xiaozhi.me/console/agents');
const showGuideModal = ref(false); const showGuideModal = ref(false);
//
const showSidebarOverlay = ref(false);
// /
const showSidebarTransition = () => {
showSidebarOverlay.value = true;
};
const hideSidebarTransition = () => {
showSidebarOverlay.value = false;
};
// //
const cleanupFunctions = ref({}); const cleanupFunctions = ref({});
const projectId = ref(null); const projectId = ref(null);
@ -173,6 +159,7 @@ const handleSaveProject = (index,item,type='image')=>{
case 'model': case 'model':
cardItem.modelUrl = item.modelUrl; cardItem.modelUrl = item.modelUrl;
cardItem.taskId = item.taskId; cardItem.taskId = item.taskId;
cardItem.resultTask = item.resultTask;
break; break;
} }
cardItem.status = item.status; cardItem.status = item.status;
@ -190,7 +177,6 @@ const createProject = async ()=>{
} }
// //
const getProjectInfo = async (id)=>{ const getProjectInfo = async (id)=>{
showSidebarTransition();
const data = await PluginProject.getProject(id); const data = await PluginProject.getProject(id);
console.log(data,'data'); console.log(data,'data');
projectInfo.value = {...data}; projectInfo.value = {...data};
@ -199,7 +185,6 @@ const getProjectInfo = async (id)=>{
...card, ...card,
id: card.id || Date.now() + Math.random().toString(36).substr(2, 9) id: card.id || Date.now() + Math.random().toString(36).substr(2, 9)
})); }));
hideSidebarTransition();
} }
// //
const updateProjectInfo = async (newProjectInfo)=>{ const updateProjectInfo = async (newProjectInfo)=>{
@ -455,6 +440,8 @@ const handleGenerateRequested = async (params) => {
}); });
// //
cards.value.push(newCard); 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); 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 { .test-animation-btn {

7
package-lock.json generated
View File

@ -43,6 +43,7 @@
"element-plus": "^2.11.7", "element-plus": "^2.11.7",
"jose": "^6.1.1", "jose": "^6.1.1",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1", "pinia-plugin-persistedstate": "^4.7.1",
"three": "^0.180.0", "three": "^0.180.0",
@ -4943,6 +4944,12 @@
"integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==", "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==",
"license": "MIT" "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": { "node_modules/nth-check": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz", "resolved": "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz",

View File

@ -1,6 +1,6 @@
const login = { const login = {
LOGIN:{url:'/api-base/user/login',method:'POST'},// 登录 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'},// 注册 REGISTER:{url:'/api-base/user/register',method:'POST'},// 注册
SEND_EMAIL_CODE:{url:'/api-base/user/send-email-code',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弹窗授权 OAUTH_GOOGLE:{url:'/api-base/user/oauth/google',method:'POST'},// google弹窗授权

View File

@ -1,5 +1,5 @@
const order = { 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'},// 获取订单详情 getOrderDetail:{url:'/api-core/front/order/get',method:'GET'},// 获取订单详情
orderCancel:{url:'/api-core/front/order/cancel',method:'POST'},// 取消订单支付 orderCancel:{url:'/api-core/front/order/cancel',method:'POST'},// 取消订单支付
receiveAddress:{url:'/api-core/front/order/receive',method:'POST'},// 确认收货 receiveAddress:{url:'/api-core/front/order/receive',method:'POST'},// 确认收货

View File

@ -19,11 +19,11 @@ const login = {
* 项目详情接口 * 项目详情接口
* 引用示例: PROJECT_GET * 引用示例: 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
*/ */
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; export default login;

View File

@ -19,10 +19,13 @@ const getPorjectType = () => {
}; };
export class GiminiServer extends FileServer { export class GiminiServer extends FileServer {
RULE = getPorjectType(); RULE = getPorjectType();
// 任务并发队列
static taskQueue = new Map();
//最高并发限制
static MAX_CONCURRENT_TASKS = 4;
constructor() { constructor() {
super(); super();
} }
/** /**
* 从URL获取MIME类型 * 从URL获取MIME类型
* @param {*} url 图片URL * @param {*} url 图片URL
@ -141,8 +144,17 @@ export class GiminiServer extends FileServer {
} }
}) })
}; };
//线上生模型 //线上生图片模型
async generateImageFromMultipleImagesOnline(baseImages, prompt,config={}){ 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) => { return new Promise(async (resolve, reject) => {
// 标准化输入:确保 baseImages 是数组 // 标准化输入:确保 baseImages 是数组
baseImages = Array.isArray(baseImages) ? baseImages : [baseImages]; baseImages = Array.isArray(baseImages) ? baseImages : [baseImages];
@ -163,21 +175,9 @@ export class GiminiServer extends FileServer {
const imageParts = await Promise.all(images.map(async image =>{ const imageParts = await Promise.all(images.map(async image =>{
return await this.dataUrlToGenerativePart(image,'url'); 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 = { const params = {
"aspect_ratio": "9:16", "aspect_ratio": "9:16",
"model": "gemini-2.5-flash-image",//models/gemini-3-pro-image-preview "model": "gemini-2.5-flash-image",//models/gemini-3-pro-image-preview/"gemini-2.5-flash-image",
"location": "global", "location": "global",
"vertexai": true, "vertexai": true,
...config, ...config,
@ -188,19 +188,6 @@ const params = {
} }
const requestUrl = this.RULE=='admin'?adminApi.default.GENERATE_IMAGE_ADMIN:clientApi.default.GENERATE_IMAGE; const requestUrl = this.RULE=='admin'?adminApi.default.GENERATE_IMAGE_ADMIN:clientApi.default.GENERATE_IMAGE;
const response = await requestUtils.common(requestUrl, params); 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){ if(response.data.error){
reject(response.data.error.message); reject(response.data.error.message);
return; return;
@ -217,6 +204,9 @@ const params = {
} catch (error) { } catch (error) {
reject(error); reject(error);
console.log(error, 'errorerrorerrorerrorerrorerror'); console.log(error, 'errorerrorerrorerrorerrorerror');
} finally {
// 任务完成后从队列中移除
GiminiServer.taskQueue.delete(taskId);
} }
}) })
} }

View File

@ -16,12 +16,27 @@ const getPorjectType = () => {
}; };
export class MeshyServer extends FileServer { export class MeshyServer extends FileServer {
RULE = getPorjectType(); RULE = getPorjectType();
// 任务并发队列
static taskQueue = new Map();
//最高并发限制
static MAX_CONCURRENT_TASKS = 1;
static pollingEnabled = true; static pollingEnabled = true;
constructor() { constructor() {
super(); super();
} }
//提交模型任务返回id //提交模型任务返回id
async createModelTask(item={},callback,errorCallback,config={}) { 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 { try {
let params = { let params = {
project_id: item.project_id, project_id: item.project_id,
@ -51,7 +66,7 @@ export class MeshyServer extends FileServer {
// } // }
// }; // };
if(response.code==0){ if(response.code==0){
callback&&callback(response?.data?.result); callback&&callback(response?.data?.result,taskId);
} }
} catch (error) { } catch (error) {
console.error('创建模型任务失败:', error); console.error('创建模型任务失败:', error);
@ -59,29 +74,36 @@ export class MeshyServer extends FileServer {
throw error; 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 = { const requestUrl = {
url:this.RULE=='admin'?adminApi.default.FIND_TASK_IDADMIN.url.replace('TASKID', result):clientApi.default.FIND_TASK_ID.url.replace('TASKID', result), 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, method:this.RULE=='admin'?adminApi.default.FIND_TASK_IDADMIN.method:clientApi.default.FIND_TASK_ID.method,
}; };
let response = await requestUtils.common(requestUrl, {}); let response = await requestUtils.common(requestUrl, {});
if(response.code==0){ if(response.code==0){
let data = response?.data let data = response?.data
console.log(data,'查询任务状态');
switch (data.status) { switch (data.status) {
case 1: case 1:
// let modelurl = data.model_url.replace("https://assets.meshy.ai", "https://api.deotaland.ai/model"); // let modelurl = data.model_url.replace("https://assets.meshy.ai", "https://api.deotaland.ai/model");
let modelurl = data.result.s3_glb_url; let modelurl = data.result.s3_glb_url;
resultTask&&MeshyServer.taskQueue.delete(resultTask);
callback&&callback(modelurl); callback&&callback(modelurl);
break; break;
case 2: case 2:
errorCallback&&errorCallback(); errorCallback&&errorCallback();
resultTask&&MeshyServer.taskQueue.delete(resultTask);
break; break;
case 3: case 3:
errorCallback&&errorCallback(); errorCallback&&errorCallback();
resultTask&&MeshyServer.taskQueue.delete(resultTask);
break; break;
default: default:
if(!MeshyServer.pollingEnabled){//如果禁用轮询,直接返回 if(!MeshyServer.pollingEnabled){//如果禁用轮询,直接返回
@ -90,9 +112,18 @@ export class MeshyServer extends FileServer {
// 等待三秒 // 等待三秒
await new Promise(resolve => setTimeout(resolve, 3000)); await new Promise(resolve => setTimeout(resolve, 3000));
progressCallback&&progressCallback(data.progress); progressCallback&&progressCallback(data.progress);
this.getModelTaskStatus(result,callback,errorCallback,progressCallback); this.getModelTaskStatus({
result:result,
resultTask:resultTask,
},callback,errorCallback,progressCallback);
break; break;
} }
} }
} }
catch (error) {
resultTask&&MeshyServer.taskQueue.delete(resultTask);
errorCallback&&errorCallback(error);
throw error;
}
}
} }

View File

@ -1,5 +1,5 @@
import axios from 'axios'; import axios from 'axios';
var ElLoading = null var closeMethods = null
// 获取环境变量中的基础URL // 获取环境变量中的基础URL
const getEnvBaseURL = () => { const getEnvBaseURL = () => {
// 浏览器环境 // 浏览器环境
@ -50,8 +50,8 @@ service.interceptors.request.use(
// 响应拦截器 // 响应拦截器
service.interceptors.response.use( service.interceptors.response.use(
response => { response => {
if(ElLoading){ if(closeMethods){
ElLoading.close() closeMethods.close()
} }
// 直接返回响应数据 // 直接返回响应数据
const res = response.data; const res = response.data;
@ -183,7 +183,7 @@ export const request = {
requestConfig.data = data; requestConfig.data = data;
} }
if(config.isLoading){ if(config.isLoading){
ElLoading = window.setElLoading() closeMethods = window.setElLoading(config.isqp)
} }
return service(requestConfig); return service(requestConfig);
}, },

View File

@ -77,7 +77,7 @@ importers:
version: 5.44.1 version: 5.44.1
unplugin-auto-import: unplugin-auto-import:
specifier: ^20.2.0 specifier: ^20.2.0
version: 20.2.0(@vueuse/core@14.1.0) version: 20.2.0
unplugin-vue-components: unplugin-vue-components:
specifier: ^30.0.0 specifier: ^30.0.0
version: 30.0.0(vue@3.5.24) version: 30.0.0(vue@3.5.24)
@ -132,6 +132,9 @@ importers:
normalize.css: normalize.css:
specifier: ^8.0.1 specifier: ^8.0.1
version: 8.0.1 version: 8.0.1
nprogress:
specifier: ^0.2.0
version: 0.2.0
pinia: pinia:
specifier: ^3.0.4 specifier: ^3.0.4
version: 3.0.4(vue@3.5.24) version: 3.0.4(vue@3.5.24)
@ -1285,10 +1288,6 @@ packages:
resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
dev: false dev: false
/@types/web-bluetooth@0.0.21:
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
dev: true
/@types/webxr@0.5.24: /@types/webxr@0.5.24:
resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==} resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==}
dev: false dev: false
@ -1424,17 +1423,6 @@ packages:
vue-demi: 0.13.11(vue@3.5.24) vue-demi: 0.13.11(vue@3.5.24)
dev: false 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): /@vueuse/core@9.13.0(vue@3.5.24):
resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
dependencies: dependencies:
@ -1447,22 +1435,10 @@ packages:
- vue - vue
dev: false dev: false
/@vueuse/metadata@14.1.0:
resolution: {integrity: sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==}
dev: true
/@vueuse/metadata@9.13.0: /@vueuse/metadata@9.13.0:
resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
dev: false 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): /@vueuse/shared@9.13.0(vue@3.5.24):
resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
dependencies: dependencies:
@ -2924,6 +2900,10 @@ packages:
resolution: {integrity: sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==} resolution: {integrity: sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==}
dev: false dev: false
/nprogress@0.2.0:
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
dev: false
/nth-check@2.1.1: /nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
dependencies: dependencies:
@ -3525,27 +3505,6 @@ packages:
unplugin-utils: 0.3.1 unplugin-utils: 0.3.1
dev: true 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: /unplugin-icons@22.5.0:
resolution: {integrity: sha512-MBlMtT5RuMYZy4TZgqUL2OTtOdTUVsS1Mhj6G1pEzMlFJlEnq6mhUfoIt45gBWxHcsOdXJDWLg3pRZ+YmvAVWQ==} resolution: {integrity: sha512-MBlMtT5RuMYZy4TZgqUL2OTtOdTUVsS1Mhj6G1pEzMlFJlEnq6mhUfoIt45gBWxHcsOdXJDWLg3pRZ+YmvAVWQ==}
peerDependencies: peerDependencies: