修改部分样式

This commit is contained in:
2025-08-17 13:25:15 +08:00
parent aa2a552820
commit f45aa01cf0
17 changed files with 14003 additions and 13556 deletions

6
API.md
View File

@@ -337,8 +337,8 @@ async fn send_status_update(status: PlayerState) -> Result<(), Box<dyn Error>>
### PlayerState
```typescript
interface PlayerState {
connectionStatus: 'connected' | 'connecting' | 'disconnected' | { error: string }
playbackStatus: 'playing' | 'paused' | 'stopped' | 'loading'
connectionStatus: "connected" | "connecting" | "disconnected" | { error: string }
playbackStatus: "playing" | "paused" | "stopped" | "loading"
currentVideo?: VideoInfo
position: number
duration: number
@@ -379,7 +379,7 @@ interface AppSettings {
defaultVolume: number
defaultLoop: boolean
autoFullscreen: boolean
playbackEndBehavior: 'stop' | 'next' | 'repeat'
playbackEndBehavior: "stop" | "next" | "repeat"
theme: string
language: string
showNotifications: boolean

View File

@@ -9,6 +9,10 @@ export default defineAppConfig({
colors: {
primary: "blue",
neutral: "zinc"
},
icons: {
light: "ph-sun",
dark: "ph-moon"
}
}
});

View File

@@ -1,5 +1,5 @@
@import "tailwindcss";
@import "@nuxt/ui";
@import "@nuxt/ui-pro";
@theme {
--font-heading: "Montserrat", sans-serif;

View File

@@ -1,11 +1,20 @@
<template>
<div class="min-h-screen bg-gray-50 dark:bg-gray-900 flex">
<!-- 左侧边栏 -->
<aside class="w-40 bg-white dark:bg-gray-800 shadow-sm border-r border-gray-200 dark:border-gray-700 flex flex-col h-screen">
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
<aside
class="w-40 bg-white dark:bg-gray-800 shadow-sm border-r border-gray-200 dark:border-gray-700 flex flex-col h-screen fixed top-0 left-0 z-30"
>
<div class="flex items-center justify-between p-3 border-b border-gray-200 dark:border-gray-700">
<h1 class="text-xl font-semibold text-gray-900 dark:text-white">
视频控制器
</h1>
<div class="mx-auto mt-1">
<UColorModeButton size="xs">
<template #fallback>
<UButton loading variant="ghost" color="neutral" />
</template>
</UColorModeButton>
</div>
</div>
<nav class="flex-1 p-4">
@@ -13,8 +22,7 @@
<li>
<NuxtLink
to="/"
class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors"
:class="$route.path === '/'
class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors" :class="$route.path === '/'
? 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-200'
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700'"
>
@@ -25,8 +33,7 @@
<li>
<NuxtLink
to="/settings"
class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors"
:class="$route.path === '/settings'
class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors" :class="$route.path === '/settings'
? 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-200'
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700'"
>
@@ -36,13 +43,11 @@
</li>
</ul>
</nav>
<!-- 关于 -->
<div class="p-4 border-t border-gray-200 dark:border-gray-700">
<div class="p-4 ">
<NuxtLink
to="/about"
class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors"
:class="$route.path === '/about'
class="flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors" :class="$route.path === '/about'
? 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-200'
: 'text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700'"
>
@@ -53,7 +58,7 @@
</aside>
<!-- 主体区域 -->
<main class="flex-1 overflow-auto">
<main class="flex-1 overflow-auto ml-40">
<div class="p-6">
<slot />
</div>

View File

@@ -3,7 +3,9 @@
<!-- 应用信息 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">应用信息</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
应用信息
</h2>
</template>
<div class="space-y-4">
<div class="flex items-center space-x-4">
@@ -11,13 +13,19 @@
<UIcon name="i-heroicons-tv" class="w-8 h-8 text-blue-600 dark:text-blue-400" />
</div>
<div>
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">{{ appInfo.name }}</h3>
<p class="text-gray-600 dark:text-gray-400">版本 {{ appInfo.version }}</p>
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">
{{ appInfo.name }}
</h3>
<p class="text-gray-600 dark:text-gray-400">
版本 {{ appInfo.version }}
</p>
</div>
</div>
<div class="space-y-2">
<p class="text-gray-700 dark:text-gray-300">{{ appInfo.description }}</p>
<p class="text-gray-700 dark:text-gray-300">
{{ appInfo.description }}
</p>
<p class="text-sm text-gray-600 dark:text-gray-400">
构建时间: {{ appInfo.buildDate }}
</p>
@@ -31,33 +39,37 @@
<!-- 技术栈 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">技术栈</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
技术栈
</h2>
</template>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-3">
<h4 class="font-medium text-gray-900 dark:text-white">前端技术</h4>
<h4 class="font-medium text-gray-900 dark:text-white">
前端技术
</h4>
<div class="space-y-2">
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-green-100 dark:bg-green-900 rounded flex items-center justify-center">
<div class="w-3 h-3 bg-green-500 rounded"></div>
<div class="w-3 h-3 bg-green-500 rounded" />
</div>
<span class="text-sm">Nuxt 4 - 全栈 Vue.js 框架</span>
</div>
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-blue-100 dark:bg-blue-900 rounded flex items-center justify-center">
<div class="w-3 h-3 bg-blue-500 rounded"></div>
<div class="w-3 h-3 bg-blue-500 rounded" />
</div>
<span class="text-sm">Vue 3 - 渐进式 JavaScript 框架</span>
</div>
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-cyan-100 dark:bg-cyan-900 rounded flex items-center justify-center">
<div class="w-3 h-3 bg-cyan-500 rounded"></div>
<div class="w-3 h-3 bg-cyan-500 rounded" />
</div>
<span class="text-sm">Tailwind CSS - 原子化 CSS 框架</span>
</div>
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-emerald-100 dark:bg-emerald-900 rounded flex items-center justify-center">
<div class="w-3 h-3 bg-emerald-500 rounded"></div>
<div class="w-3 h-3 bg-emerald-500 rounded" />
</div>
<span class="text-sm">Nuxt UI - 现代化 UI 组件库</span>
</div>
@@ -65,23 +77,25 @@
</div>
<div class="space-y-3">
<h4 class="font-medium text-gray-900 dark:text-white">后端技术</h4>
<h4 class="font-medium text-gray-900 dark:text-white">
后端技术
</h4>
<div class="space-y-2">
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-orange-100 dark:bg-orange-900 rounded flex items-center justify-center">
<div class="w-3 h-3 bg-orange-500 rounded"></div>
<div class="w-3 h-3 bg-orange-500 rounded" />
</div>
<span class="text-sm">Tauri 2 - 跨平台桌面应用框架</span>
</div>
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-red-100 dark:bg-red-900 rounded flex items-center justify-center">
<div class="w-3 h-3 bg-red-500 rounded"></div>
<div class="w-3 h-3 bg-red-500 rounded" />
</div>
<span class="text-sm">Rust - 系统级编程语言</span>
</div>
<div class="flex items-center space-x-3">
<div class="w-6 h-6 bg-purple-100 dark:bg-purple-900 rounded flex items-center justify-center">
<div class="w-3 h-3 bg-purple-500 rounded"></div>
<div class="w-3 h-3 bg-purple-500 rounded" />
</div>
<span class="text-sm">WebSocket - 实时通信协议</span>
</div>
@@ -93,7 +107,9 @@
<!-- 功能特性 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">功能特性</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
功能特性
</h2>
</template>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="space-y-2">
@@ -138,11 +154,15 @@
<!-- 系统要求 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">系统要求</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
系统要求
</h2>
</template>
<div class="space-y-4">
<div>
<h4 class="font-medium text-gray-900 dark:text-white mb-2">支持的操作系统</h4>
<h4 class="font-medium text-gray-900 dark:text-white mb-2">
支持的操作系统
</h4>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="flex items-center space-x-2 text-sm">
<UIcon name="i-heroicons-computer-desktop" class="w-5 h-5 text-gray-500" />
@@ -160,7 +180,9 @@
</div>
<div>
<h4 class="font-medium text-gray-900 dark:text-white mb-2">网络要求</h4>
<h4 class="font-medium text-gray-900 dark:text-white mb-2">
网络要求
</h4>
<ul class="text-sm text-gray-600 dark:text-gray-400 space-y-1">
<li> 与视频播放器处于同一局域网</li>
<li> TCP/IP 网络连接</li>
@@ -173,7 +195,9 @@
<!-- 开源许可 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">开源许可</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
开源许可
</h2>
</template>
<div class="space-y-3">
<p class="text-sm text-gray-600 dark:text-gray-400">
@@ -195,7 +219,9 @@
<!-- 反馈和支持 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">反馈和支持</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
反馈和支持
</h2>
</template>
<div class="space-y-4">
<p class="text-sm text-gray-600 dark:text-gray-400">
@@ -221,32 +247,32 @@
</template>
<script lang="ts" setup>
interface AppInfo {
interface AppInfo {
name: string
version: string
description: string
author: string
buildDate: string
}
}
const { app } = useAppConfig()
const { app } = useAppConfig();
// 应用信息
const appInfo = ref<AppInfo>({
// 应用信息
const appInfo = ref<AppInfo>({
name: app.name,
version: app.version,
description: app.description,
author: app.author,
buildDate: new Date().toLocaleDateString('zh-CN')
})
buildDate: new Date().toLocaleDateString("zh-CN")
});
// 页面加载时获取构建信息
onMounted(async () => {
// 页面加载时获取构建信息
onMounted(async () => {
try {
// TODO: 调用 Tauri API 获取应用构建信息
console.log('获取应用信息')
console.log("获取应用信息");
} catch (error) {
console.error('获取应用信息失败:', error)
console.error("获取应用信息失败:", error);
}
})
});
</script>

View File

@@ -3,20 +3,22 @@
<!-- 连接状态 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">连接状态</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
连接状态
</h2>
</template>
<div class="flex items-center justify-between">
<div class="flex items-center space-x-3">
<div :class="connectionStatus === 'connected' ? 'bg-green-500' : connectionStatus === 'connecting' ? 'bg-yellow-500' : 'bg-red-500'" class="w-3 h-3 rounded-full"></div>
<div :class="connectionStatus === 'connected' ? 'bg-green-500' : connectionStatus === 'connecting' ? 'bg-yellow-500' : 'bg-red-500'" class="w-3 h-3 rounded-full" />
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
{{ connectionStatusText }}
</span>
</div>
<UButton
@click="toggleConnection"
:variant="connectionStatus === 'connected' ? 'soft' : 'solid'"
:color="connectionStatus === 'connected' ? 'red' : 'blue'"
size="sm"
@click="toggleConnection"
>
{{ connectionStatus === 'connected' ? '断开连接' : '连接' }}
</UButton>
@@ -29,16 +31,22 @@
<!-- 视频预览区域 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">视频预览</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
视频预览
</h2>
</template>
<div class="bg-black rounded-lg aspect-video flex items-center justify-center">
<div v-if="currentVideo" class="text-center">
<UIcon name="i-heroicons-film" class="w-16 h-16 text-gray-400 mx-auto mb-2" />
<p class="text-white text-sm">{{ currentVideo }}</p>
<p class="text-white text-sm">
{{ currentVideo }}
</p>
</div>
<div v-else class="text-center">
<UIcon name="i-heroicons-video-camera-slash" class="w-16 h-16 text-gray-600 mx-auto mb-2" />
<p class="text-gray-400 text-sm">暂无视频</p>
<p class="text-gray-400 text-sm">
暂无视频
</p>
</div>
</div>
</UCard>
@@ -46,20 +54,22 @@
<!-- 播放控制 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">播放控制</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
播放控制
</h2>
</template>
<div class="space-y-4">
<!-- 主要控制按钮 -->
<div class="flex justify-center space-x-4">
<UButton @click="playVideo" :disabled="!isConnected" color="green" size="lg">
<UButton :disabled="!isConnected" color="green" size="lg" @click="playVideo">
<UIcon name="i-heroicons-play" class="w-5 h-5 mr-2" />
播放
</UButton>
<UButton @click="pauseVideo" :disabled="!isConnected" color="orange" size="lg">
<UButton :disabled="!isConnected" color="orange" size="lg" @click="pauseVideo">
<UIcon name="i-heroicons-pause" class="w-5 h-5 mr-2" />
暂停
</UButton>
<UButton @click="stopVideo" :disabled="!isConnected" color="red" size="lg">
<UButton :disabled="!isConnected" color="red" size="lg" @click="stopVideo">
<UIcon name="i-heroicons-stop" class="w-5 h-5 mr-2" />
停止
</UButton>
@@ -87,15 +97,15 @@
<!-- 额外功能 -->
<div class="flex flex-wrap gap-2 pt-4 border-t border-gray-200 dark:border-gray-700">
<UButton @click="toggleLoop" :disabled="!isConnected" :variant="isLooping ? 'solid' : 'outline'" size="sm">
<UButton :disabled="!isConnected" :variant="isLooping ? 'solid' : 'outline'" size="sm" @click="toggleLoop">
<UIcon name="i-heroicons-arrow-path" class="w-4 h-4 mr-1" />
循环播放
</UButton>
<UButton @click="toggleFullscreen" :disabled="!isConnected" variant="outline" size="sm">
<UButton :disabled="!isConnected" variant="outline" size="sm" @click="toggleFullscreen">
<UIcon name="i-heroicons-arrows-pointing-out" class="w-4 h-4 mr-1" />
全屏
</UButton>
<UButton @click="openVideoFile" variant="outline" size="sm">
<UButton variant="outline" size="sm" @click="openVideoFile">
<UIcon name="i-heroicons-folder-open" class="w-4 h-4 mr-1" />
打开文件
</UButton>
@@ -107,8 +117,10 @@
<UCard>
<template #header>
<div class="flex items-center justify-between">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">播放列表</h2>
<UButton @click="clearPlaylist" variant="ghost" size="sm" color="red">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
播放列表
</h2>
<UButton variant="ghost" size="sm" color="red" @click="clearPlaylist">
<UIcon name="i-heroicons-trash" class="w-4 h-4 mr-1" />
清空
</UButton>
@@ -130,10 +142,10 @@
<span class="text-sm font-medium">{{ item }}</span>
</div>
<div class="flex space-x-1">
<UButton @click="playVideoFromPlaylist(index)" size="xs" variant="ghost">
<UButton size="xs" variant="ghost" @click="playVideoFromPlaylist(index)">
<UIcon name="i-heroicons-play" class="w-4 h-4" />
</UButton>
<UButton @click="removeFromPlaylist(index)" size="xs" variant="ghost" color="red">
<UButton size="xs" variant="ghost" color="red" @click="removeFromPlaylist(index)">
<UIcon name="i-heroicons-x-mark" class="w-4 h-4" />
</UButton>
</div>
@@ -145,108 +157,108 @@
</template>
<script lang="ts" setup>
interface VideoControllerState {
connectionStatus: 'connected' | 'connecting' | 'disconnected'
interface VideoControllerState {
connectionStatus: "connected" | "connecting" | "disconnected"
currentVideo: string | null
progress: number
volume: number
isLooping: boolean
playlist: string[]
playerAddress: string
}
// 响应式状态
const connectionStatus = ref<VideoControllerState['connectionStatus']>('disconnected')
const currentVideo = ref<string | null>(null)
const progress = ref(0)
const volume = ref(50)
const isLooping = ref(false)
const playlist = ref<string[]>([])
const playerAddress = ref('192.168.1.100:8080')
// 计算属性
const isConnected = computed(() => connectionStatus.value === 'connected')
const connectionStatusText = computed(() => {
switch (connectionStatus.value) {
case 'connected': return '已连接'
case 'connecting': return '连接中...'
default: return '未连接'
}
})
// 方法
const toggleConnection = async () => {
if (connectionStatus.value === 'connected') {
// 响应式状态
const connectionStatus = ref<VideoControllerState["connectionStatus"]>("disconnected");
const currentVideo = ref<string | null>(null);
const progress = ref(0);
const volume = ref(50);
const isLooping = ref(false);
const playlist = ref<string[]>([]);
const playerAddress = ref("192.168.1.100:8080");
// 计算属性
const isConnected = computed(() => connectionStatus.value === "connected");
const connectionStatusText = computed(() => {
switch (connectionStatus.value) {
case "connected": return "已连接";
case "connecting": return "连接中...";
default: return "未连接";
}
});
// 方法
const toggleConnection = async () => {
if (connectionStatus.value === "connected") {
// 断开连接
connectionStatus.value = 'disconnected'
connectionStatus.value = "disconnected";
} else {
// 尝试连接
connectionStatus.value = 'connecting'
connectionStatus.value = "connecting";
// TODO: 在这里调用 Tauri API 进行实际连接
setTimeout(() => {
connectionStatus.value = 'connected' // 模拟连接成功
}, 1000)
connectionStatus.value = "connected"; // 模拟连接成功
}, 1000);
}
}
};
const playVideo = async () => {
const playVideo = async () => {
// TODO: 调用 Tauri API
console.log('播放视频')
}
console.log("播放视频");
};
const pauseVideo = async () => {
const pauseVideo = async () => {
// TODO: 调用 Tauri API
console.log('暂停视频')
}
console.log("暂停视频");
};
const stopVideo = async () => {
const stopVideo = async () => {
// TODO: 调用 Tauri API
console.log('停止视频')
}
console.log("停止视频");
};
const toggleLoop = async () => {
isLooping.value = !isLooping.value
const toggleLoop = async () => {
isLooping.value = !isLooping.value;
// TODO: 调用 Tauri API
console.log('循环播放:', isLooping.value)
}
console.log("循环播放:", isLooping.value);
};
const toggleFullscreen = async () => {
const toggleFullscreen = async () => {
// TODO: 调用 Tauri API
console.log('切换全屏')
}
console.log("切换全屏");
};
const openVideoFile = async () => {
const openVideoFile = async () => {
// TODO: 调用 Tauri API 打开文件选择器
console.log('打开文件')
console.log("打开文件");
// 模拟添加到播放列表
playlist.value.push(`示例视频${playlist.value.length + 1}.mp4`)
}
playlist.value.push(`示例视频${playlist.value.length + 1}.mp4`);
};
const playVideoFromPlaylist = async (index: number) => {
currentVideo.value = playlist.value[index]
const playVideoFromPlaylist = async (index: number) => {
currentVideo.value = playlist.value[index];
// TODO: 调用 Tauri API 播放指定视频
console.log('播放:', currentVideo.value)
}
console.log("播放:", currentVideo.value);
};
const removeFromPlaylist = (index: number) => {
playlist.value.splice(index, 1)
}
const removeFromPlaylist = (index: number) => {
playlist.value.splice(index, 1);
};
const clearPlaylist = () => {
playlist.value = []
currentVideo.value = null
}
const clearPlaylist = () => {
playlist.value = [];
currentVideo.value = null;
};
// 监听进度变化
watch(progress, (newProgress) => {
// 监听进度变化
watch(progress, (newProgress) => {
// TODO: 调用 Tauri API 设置播放进度
console.log('设置进度:', newProgress)
})
console.log("设置进度:", newProgress);
});
// 监听音量变化
watch(volume, (newVolume) => {
// 监听音量变化
watch(volume, (newVolume) => {
// TODO: 调用 Tauri API 设置音量
console.log('设置音量:', newVolume)
})
console.log("设置音量:", newVolume);
});
</script>

View File

@@ -3,7 +3,9 @@
<!-- 连接设置 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">连接设置</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
连接设置
</h2>
</template>
<div class="space-y-4">
<UFormGroup label="视频播放器地址" description="设置要连接的视频播放器的IP地址和端口">
@@ -37,7 +39,9 @@
<!-- 播放设置 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">播放设置</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
播放设置
</h2>
</template>
<div class="space-y-4">
<UFormGroup label="默认音量" description="新视频播放时的默认音量">
@@ -69,7 +73,9 @@
<!-- 界面设置 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">界面设置</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
界面设置
</h2>
</template>
<div class="space-y-4">
<UFormGroup label="主题模式">
@@ -99,7 +105,9 @@
<!-- 高级设置 -->
<UCard>
<template #header>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">高级设置</h2>
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
高级设置
</h2>
</template>
<div class="space-y-4">
<UFormGroup label="调试模式" description="启用详细的日志记录">
@@ -118,20 +126,20 @@
<!-- 操作按钮 -->
<div class="flex justify-between">
<UButton @click="resetSettings" variant="outline" color="gray">
<UButton variant="outline" color="gray" @click="resetSettings">
<UIcon name="i-heroicons-arrow-path" class="w-4 h-4 mr-2" />
重置设置
</UButton>
<div class="space-x-2">
<UButton @click="exportSettings" variant="outline">
<UButton variant="outline" @click="exportSettings">
<UIcon name="i-heroicons-arrow-up-tray" class="w-4 h-4 mr-2" />
导出配置
</UButton>
<UButton @click="importSettings" variant="outline">
<UButton variant="outline" @click="importSettings">
<UIcon name="i-heroicons-arrow-down-tray" class="w-4 h-4 mr-2" />
导入配置
</UButton>
<UButton @click="saveSettings" color="blue">
<UButton color="blue" @click="saveSettings">
<UIcon name="i-heroicons-check" class="w-4 h-4 mr-2" />
保存设置
</UButton>
@@ -141,7 +149,7 @@
</template>
<script lang="ts" setup>
interface AppSettings {
interface AppSettings {
playerHost: string
playerPort: number
connectionTimeout: number
@@ -157,11 +165,11 @@ interface AppSettings {
debugMode: boolean
cacheSize: number
proxy: string
}
}
// 响应式设置数据
const settings = ref<AppSettings>({
playerHost: '192.168.1.100',
// 响应式设置数据
const settings = ref<AppSettings>({
playerHost: "192.168.1.100",
playerPort: 8080,
connectionTimeout: 10,
autoReconnect: true,
@@ -169,52 +177,52 @@ const settings = ref<AppSettings>({
defaultVolume: 50,
defaultLoop: false,
autoFullscreen: false,
playbackEndBehavior: 'stop',
theme: 'system',
language: 'zh-CN',
playbackEndBehavior: "stop",
theme: "system",
language: "zh-CN",
showNotifications: true,
debugMode: false,
cacheSize: 100,
proxy: ''
})
proxy: ""
});
// 选项数据
const playbackEndOptions = [
{ label: '停止播放', value: 'stop' },
{ label: '播放下一个', value: 'next' },
{ label: '重复播放', value: 'repeat' }
]
// 选项数据
const playbackEndOptions = [
{ label: "停止播放", value: "stop" },
{ label: "播放下一个", value: "next" },
{ label: "重复播放", value: "repeat" }
];
const themeOptions = [
{ label: '跟随系统', value: 'system' },
{ label: '浅色模式', value: 'light' },
{ label: '深色模式', value: 'dark' }
]
const themeOptions = [
{ label: "跟随系统", value: "system" },
{ label: "浅色模式", value: "light" },
{ label: "深色模式", value: "dark" }
];
const languageOptions = [
{ label: '简体中文', value: 'zh-CN' },
{ label: 'English', value: 'en' },
{ label: '日本語', value: 'ja' }
]
const languageOptions = [
{ label: "简体中文", value: "zh-CN" },
{ label: "English", value: "en" },
{ label: "日本語", value: "ja" }
];
// 方法
const saveSettings = async () => {
// 方法
const saveSettings = async () => {
try {
// TODO: 调用 Tauri API 保存设置
console.log('保存设置:', settings.value)
console.log("保存设置:", settings.value);
// 显示成功通知
// useToast().add({ title: '设置已保存', color: 'green' })
} catch (error) {
console.error('保存设置失败:', error)
console.error("保存设置失败:", error);
// 显示错误通知
// useToast().add({ title: '保存失败', color: 'red' })
}
}
};
const resetSettings = async () => {
const resetSettings = async () => {
// 重置为默认设置
settings.value = {
playerHost: '192.168.1.100',
playerHost: "192.168.1.100",
playerPort: 8080,
connectionTimeout: 10,
autoReconnect: true,
@@ -222,47 +230,47 @@ const resetSettings = async () => {
defaultVolume: 50,
defaultLoop: false,
autoFullscreen: false,
playbackEndBehavior: 'stop',
theme: 'system',
language: 'zh-CN',
playbackEndBehavior: "stop",
theme: "system",
language: "zh-CN",
showNotifications: true,
debugMode: false,
cacheSize: 100,
proxy: ''
}
}
proxy: ""
};
};
const exportSettings = async () => {
const exportSettings = async () => {
try {
// TODO: 调用 Tauri API 导出设置到文件
console.log('导出设置')
console.log("导出设置");
} catch (error) {
console.error('导出设置失败:', error)
console.error("导出设置失败:", error);
}
}
};
const importSettings = async () => {
const importSettings = async () => {
try {
// TODO: 调用 Tauri API 从文件导入设置
console.log('导入设置')
console.log("导入设置");
} catch (error) {
console.error('导入设置失败:', error)
console.error("导入设置失败:", error);
}
}
};
// 页面加载时读取设置
onMounted(async () => {
// 页面加载时读取设置
onMounted(async () => {
try {
// TODO: 调用 Tauri API 读取保存的设置
console.log('加载设置')
console.log("加载设置");
} catch (error) {
console.error('加载设置失败:', error)
console.error("加载设置失败:", error);
}
})
});
// 监听设置变化并自动保存关键设置
watch(() => [settings.value.playerHost, settings.value.playerPort], async () => {
// 监听设置变化并自动保存关键设置
watch(() => [settings.value.playerHost, settings.value.playerPort], async () => {
// 自动保存连接相关设置
await saveSettings()
}, { debounce: 1000 })
await saveSettings();
}, { debounce: 1000 });
</script>

View File

@@ -1,10 +1,10 @@
export default defineNuxtConfig({
modules: [
"@vueuse/nuxt",
"@nuxt/ui",
"nuxt-svgo",
"reka-ui/nuxt",
"@nuxt/eslint"
"@nuxt/eslint",
"@nuxt/ui-pro"
],
app: {
head: {

View File

@@ -24,7 +24,7 @@
},
"dependencies": {
"@iconify/vue": "^5.0.0",
"@nuxt/ui": "^3.2.0",
"@nuxt/ui-pro": "^3.3.2",
"@tauri-apps/api": "^2.6.0",
"@tauri-apps/plugin-fs": "^2.4.0",
"@tauri-apps/plugin-notification": "^2.3.0",

652
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ tauri-plugin-os = "2.3.0"
tauri-plugin-fs = "2.4.0"
tauri-plugin-store = "2.3.0"
serde_json = "1"
tokio = { version = "1.0", features = ["full"] }
tokio = { version = "1.0", features = [ "full" ] }
tokio-tungstenite = "0.23"
futures-util = "0.3"
log = "0.4"

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"main":{"identifier":"main","description":"Capabilities for the app window","local":true,"windows":["main","secondary"],"permissions":["core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","shell:allow-open",{"identifier":"shell:allow-execute","allow":[{"args":["-c",{"validator":"\\S+"}],"cmd":"sh","name":"exec-sh","sidecar":false}]},"notification:default","os:allow-platform","os:allow-arch","os:allow-family","os:allow-version","os:allow-locale","fs:allow-document-read","fs:allow-document-write","store:default","core:webview:allow-create-webview","core:webview:allow-create-webview-window"]}}
{ "main": { "identifier": "main", "description": "Capabilities for the app window", "local": true, "windows": ["main", "secondary"], "permissions": ["core:path:default", "core:event:default", "core:window:default", "core:app:default", "core:resources:default", "core:menu:default", "core:tray:default", "shell:allow-open", { "identifier": "shell:allow-execute", "allow": [{ "args": ["-c", { "validator": "\\S+" }], "cmd": "sh", "name": "exec-sh", "sidecar": false }] }, "notification:default", "os:allow-platform", "os:allow-arch", "os:allow-family", "os:allow-version", "os:allow-locale", "fs:allow-document-read", "fs:allow-document-write", "store:default", "core:webview:allow-create-webview", "core:webview:allow-create-webview-window"] } }