| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- <template>
- <el-config-provider :locale="zhCn">
- <!-- 全局加载界面(Splash Screen) -->
- <transition name="splash-fade">
- <div v-if="showSplash" class="splash-screen">
- <div class="splash-content">
- <div class="splash-logo">智媒通</div>
- <div class="splash-dots">
- <span></span>
- <span></span>
- <span></span>
- </div>
- <p class="splash-text">
- <template v-if="!servicesReady">
- 正在启动服务...
- <span class="service-status">
- Node: {{ serviceStatus.node ? '✓' : '⟳' }}
- Python: {{ serviceStatus.python ? '✓' : '⟳' }}
- </span>
- </template>
- <template v-else>加载完成!</template>
- </p>
- </div>
- </div>
- </transition>
- <router-view />
- </el-config-provider>
- </template>
- <script setup lang="ts">
- import { ref, onMounted, onUnmounted } from 'vue';
- import { useRouter } from 'vue-router';
- import zhCn from 'element-plus/es/locale/lang/zh-cn';
- import { useServerStore } from '@/stores/server';
- const showSplash = ref(true);
- const servicesReady = ref(false);
- const serviceStatus = ref({ node: false, python: false });
- const router = useRouter();
- const serverStore = useServerStore();
- // 自动配置本地服务 URL(不写入数据库,只写入本地 store)
- async function autoConfigLocalServices() {
- try {
- const urls = await window.electronAPI?.getLocalUrls?.();
- if (urls) {
- // 直接覆盖 store 中的配置,指向本地服务
- serverStore.setSingleServer({
- name: '本地服务',
- url: urls.nodeUrl,
- pythonServiceUrl: urls.pythonUrl,
- });
- console.log('[App] 本地服务已自动配置:', urls.nodeUrl, urls.pythonUrl);
- }
- } catch (e) {
- console.warn('[App] 获取本地 URL 失败:', e);
- }
- }
- // 监听服务状态变化
- async function onServicesStatusChanged(status: { nodeOk: boolean; pythonOk: boolean }) {
- serviceStatus.value = { node: status.nodeOk, python: status.pythonOk };
- if (status.nodeOk && status.pythonOk) {
- servicesReady.value = true;
- serverStore.servicesReady = true; // 通知全局服务已就绪
- // 自动配置本地服务
- autoConfigLocalServices();
- // 路由首次导航完成后隐藏加载界面
- router.isReady().then(() => {
- setTimeout(() => {
- showSplash.value = false;
- }, 300);
- });
- }
- }
- onMounted(() => {
- // 监听服务状态
- window.electronAPI?.onServicesStatusChanged(onServicesStatusChanged);
- });
- onUnmounted(() => {
- // 清理监听
- window.electronAPI?.removeServicesStatusListener?.();
- });
- </script>
- <style>
- html, body, #app {
- height: 100%;
- margin: 0;
- padding: 0;
- }
- </style>
- <style scoped>
- .splash-screen {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 99999;
- }
- .splash-content {
- text-align: center;
- color: #fff;
- }
- .splash-logo {
- font-size: 42px;
- font-weight: 700;
- letter-spacing: 4px;
- margin-bottom: 40px;
- text-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- }
- .splash-dots {
- display: flex;
- justify-content: center;
- gap: 8px;
- margin-bottom: 24px;
- }
- .splash-dots span {
- width: 10px;
- height: 10px;
- border-radius: 50%;
- background: rgba(255, 255, 255, 0.6);
- animation: dot-bounce 1.4s ease-in-out infinite;
- }
- .splash-dots span:nth-child(1) {
- animation-delay: 0s;
- }
- .splash-dots span:nth-child(2) {
- animation-delay: 0.2s;
- }
- .splash-dots span:nth-child(3) {
- animation-delay: 0.4s;
- }
- @keyframes dot-bounce {
- 0%, 80%, 100% {
- transform: scale(0.6);
- opacity: 0.4;
- background: rgba(255, 255, 255, 0.4);
- }
- 40% {
- transform: scale(1);
- opacity: 1;
- background: #fff;
- }
- }
- .splash-text {
- font-size: 16px;
- opacity: 0.8;
- margin: 0;
- animation: text-pulse 2s ease-in-out infinite;
- }
- .service-status {
- display: block;
- margin-top: 8px;
- font-size: 14px;
- opacity: 0.7;
- }
- @keyframes text-pulse {
- 0%, 100% { opacity: 0.5; }
- 50% { opacity: 1; }
- }
- .splash-fade-leave-active {
- transition: opacity 0.4s ease;
- }
- .splash-fade-leave-to {
- opacity: 0;
- }
- </style>
|