修改部分样式
This commit is contained in:
216
API.md
216
API.md
@@ -33,31 +33,31 @@ connect_to_player(config: ConnectionConfig) -> Result<ApiResponse<PlayerState>,
|
||||
**参数:**
|
||||
```json
|
||||
{
|
||||
"host": "192.168.1.100",
|
||||
"port": 8080,
|
||||
"timeout": 10,
|
||||
"autoReconnect": true,
|
||||
"reconnectInterval": 5
|
||||
"host": "192.168.1.100",
|
||||
"port": 8080,
|
||||
"timeout": 10,
|
||||
"autoReconnect": true,
|
||||
"reconnectInterval": 5
|
||||
}
|
||||
```
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"connectionStatus": "connected",
|
||||
"playbackStatus": "stopped",
|
||||
"currentVideo": null,
|
||||
"position": 0.0,
|
||||
"duration": 0.0,
|
||||
"volume": 50.0,
|
||||
"isLooping": false,
|
||||
"isFullscreen": false,
|
||||
"playlist": [],
|
||||
"currentPlaylistIndex": null
|
||||
},
|
||||
"message": "成功连接到视频播放器"
|
||||
"success": true,
|
||||
"data": {
|
||||
"connectionStatus": "connected",
|
||||
"playbackStatus": "stopped",
|
||||
"currentVideo": null,
|
||||
"position": 0.0,
|
||||
"duration": 0.0,
|
||||
"volume": 50.0,
|
||||
"isLooping": false,
|
||||
"isFullscreen": false,
|
||||
"playlist": [],
|
||||
"currentPlaylistIndex": null
|
||||
},
|
||||
"message": "成功连接到视频播放器"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -88,76 +88,76 @@ send_playback_command(command: PlaybackCommand) -> Result<ApiResponse<()>, Strin
|
||||
1. **播放**
|
||||
```json
|
||||
{
|
||||
"type": "play"
|
||||
"type": "play"
|
||||
}
|
||||
```
|
||||
|
||||
2. **暂停**
|
||||
```json
|
||||
{
|
||||
"type": "pause"
|
||||
"type": "pause"
|
||||
}
|
||||
```
|
||||
|
||||
3. **停止**
|
||||
```json
|
||||
{
|
||||
"type": "stop"
|
||||
"type": "stop"
|
||||
}
|
||||
```
|
||||
|
||||
4. **跳转**
|
||||
```json
|
||||
{
|
||||
"type": "seek",
|
||||
"position": 60.5
|
||||
"type": "seek",
|
||||
"position": 60.5
|
||||
}
|
||||
```
|
||||
|
||||
5. **设置音量**
|
||||
```json
|
||||
{
|
||||
"type": "setVolume",
|
||||
"volume": 75.0
|
||||
"type": "setVolume",
|
||||
"volume": 75.0
|
||||
}
|
||||
```
|
||||
|
||||
6. **设置循环**
|
||||
```json
|
||||
{
|
||||
"type": "setLoop",
|
||||
"enabled": true
|
||||
"type": "setLoop",
|
||||
"enabled": true
|
||||
}
|
||||
```
|
||||
|
||||
7. **切换全屏**
|
||||
```json
|
||||
{
|
||||
"type": "toggleFullscreen"
|
||||
"type": "toggleFullscreen"
|
||||
}
|
||||
```
|
||||
|
||||
8. **加载视频**
|
||||
```json
|
||||
{
|
||||
"type": "loadVideo",
|
||||
"path": "/path/to/video.mp4"
|
||||
"type": "loadVideo",
|
||||
"path": "/path/to/video.mp4"
|
||||
}
|
||||
```
|
||||
|
||||
9. **设置播放列表**
|
||||
```json
|
||||
{
|
||||
"type": "setPlaylist",
|
||||
"videos": ["/path/to/video1.mp4", "/path/to/video2.mp4"]
|
||||
"type": "setPlaylist",
|
||||
"videos": ["/path/to/video1.mp4", "/path/to/video2.mp4"]
|
||||
}
|
||||
```
|
||||
|
||||
10. **播放列表中的指定视频**
|
||||
```json
|
||||
{
|
||||
"type": "playFromPlaylist",
|
||||
"index": 0
|
||||
"type": "playFromPlaylist",
|
||||
"index": 0
|
||||
}
|
||||
```
|
||||
|
||||
@@ -266,30 +266,30 @@ async fn send_status_update(status: PlayerState) -> Result<(), Box<dyn Error>>
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "status",
|
||||
"data": {
|
||||
"playbackStatus": "playing|paused|stopped|loading",
|
||||
"currentVideo": {
|
||||
"path": "/path/to/current/video.mp4",
|
||||
"title": "Video Title",
|
||||
"duration": 3600.0,
|
||||
"size": 1024000000,
|
||||
"format": "mp4"
|
||||
},
|
||||
"position": 120.5,
|
||||
"duration": 3600.0,
|
||||
"volume": 75.0,
|
||||
"isLooping": false,
|
||||
"isFullscreen": true,
|
||||
"playlist": [
|
||||
{
|
||||
"path": "/path/to/video1.mp4",
|
||||
"title": "Video 1",
|
||||
"duration": 1800.0
|
||||
}
|
||||
],
|
||||
"currentPlaylistIndex": 0
|
||||
}
|
||||
"type": "status",
|
||||
"data": {
|
||||
"playbackStatus": "playing|paused|stopped|loading",
|
||||
"currentVideo": {
|
||||
"path": "/path/to/current/video.mp4",
|
||||
"title": "Video Title",
|
||||
"duration": 3600.0,
|
||||
"size": 1024000000,
|
||||
"format": "mp4"
|
||||
},
|
||||
"position": 120.5,
|
||||
"duration": 3600.0,
|
||||
"volume": 75.0,
|
||||
"isLooping": false,
|
||||
"isFullscreen": true,
|
||||
"playlist": [
|
||||
{
|
||||
"path": "/path/to/video1.mp4",
|
||||
"title": "Video 1",
|
||||
"duration": 1800.0
|
||||
}
|
||||
],
|
||||
"currentPlaylistIndex": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -300,23 +300,23 @@ async fn send_status_update(status: PlayerState) -> Result<(), Box<dyn Error>>
|
||||
#### 视频播放完成
|
||||
```json
|
||||
{
|
||||
"type": "event",
|
||||
"event": "playbackFinished",
|
||||
"data": {
|
||||
"videoPath": "/path/to/finished/video.mp4"
|
||||
}
|
||||
"type": "event",
|
||||
"event": "playbackFinished",
|
||||
"data": {
|
||||
"videoPath": "/path/to/finished/video.mp4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 播放错误
|
||||
```json
|
||||
{
|
||||
"type": "event",
|
||||
"event": "playbackError",
|
||||
"data": {
|
||||
"error": "Failed to load video file",
|
||||
"videoPath": "/path/to/problematic/video.mp4"
|
||||
}
|
||||
"type": "event",
|
||||
"event": "playbackError",
|
||||
"data": {
|
||||
"error": "Failed to load video file",
|
||||
"videoPath": "/path/to/problematic/video.mp4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -337,55 +337,55 @@ 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'
|
||||
currentVideo?: VideoInfo
|
||||
position: number
|
||||
duration: number
|
||||
volume: number
|
||||
isLooping: boolean
|
||||
isFullscreen: boolean
|
||||
playlist: VideoInfo[]
|
||||
currentPlaylistIndex?: number
|
||||
connectionStatus: "connected" | "connecting" | "disconnected" | { error: string }
|
||||
playbackStatus: "playing" | "paused" | "stopped" | "loading"
|
||||
currentVideo?: VideoInfo
|
||||
position: number
|
||||
duration: number
|
||||
volume: number
|
||||
isLooping: boolean
|
||||
isFullscreen: boolean
|
||||
playlist: VideoInfo[]
|
||||
currentPlaylistIndex?: number
|
||||
}
|
||||
```
|
||||
|
||||
### VideoInfo
|
||||
```typescript
|
||||
interface VideoInfo {
|
||||
path: string
|
||||
title: string
|
||||
duration?: number
|
||||
size?: number
|
||||
format?: string
|
||||
path: string
|
||||
title: string
|
||||
duration?: number
|
||||
size?: number
|
||||
format?: string
|
||||
}
|
||||
```
|
||||
|
||||
### ConnectionConfig
|
||||
```typescript
|
||||
interface ConnectionConfig {
|
||||
host: string
|
||||
port: number
|
||||
timeout: number
|
||||
autoReconnect: boolean
|
||||
reconnectInterval: number
|
||||
host: string
|
||||
port: number
|
||||
timeout: number
|
||||
autoReconnect: boolean
|
||||
reconnectInterval: number
|
||||
}
|
||||
```
|
||||
|
||||
### AppSettings
|
||||
```typescript
|
||||
interface AppSettings {
|
||||
connection: ConnectionConfig
|
||||
defaultVolume: number
|
||||
defaultLoop: boolean
|
||||
autoFullscreen: boolean
|
||||
playbackEndBehavior: 'stop' | 'next' | 'repeat'
|
||||
theme: string
|
||||
language: string
|
||||
showNotifications: boolean
|
||||
debugMode: boolean
|
||||
cacheSize: number
|
||||
proxy?: string
|
||||
connection: ConnectionConfig
|
||||
defaultVolume: number
|
||||
defaultLoop: boolean
|
||||
autoFullscreen: boolean
|
||||
playbackEndBehavior: "stop" | "next" | "repeat"
|
||||
theme: string
|
||||
language: string
|
||||
showNotifications: boolean
|
||||
debugMode: boolean
|
||||
cacheSize: number
|
||||
proxy?: string
|
||||
}
|
||||
```
|
||||
|
||||
@@ -403,9 +403,9 @@ interface AppSettings {
|
||||
### 错误响应格式
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "CONNECTION_FAILED",
|
||||
"message": "无法连接到视频播放器 192.168.1.100:8080"
|
||||
"success": false,
|
||||
"error": "CONNECTION_FAILED",
|
||||
"message": "无法连接到视频播放器 192.168.1.100:8080"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -443,18 +443,18 @@ use futures_util::{StreamExt, SinkExt};
|
||||
async fn start_player_server() -> Result<(), Box<dyn Error>> {
|
||||
let listener = TcpListener::bind("0.0.0.0:8080").await?;
|
||||
println!("视频播放器服务器启动在 0.0.0.0:8080");
|
||||
|
||||
|
||||
while let Ok((stream, _)) = listener.accept().await {
|
||||
tokio::spawn(handle_connection(stream));
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_connection(stream: TcpStream) -> Result<(), Box<dyn Error>> {
|
||||
let ws_stream = accept_async(stream).await?;
|
||||
let (mut ws_sender, mut ws_receiver) = ws_stream.split();
|
||||
|
||||
|
||||
while let Some(msg) = ws_receiver.next().await {
|
||||
match msg? {
|
||||
Message::Text(text) => {
|
||||
@@ -469,7 +469,7 @@ async fn handle_connection(stream: TcpStream) -> Result<(), Box<dyn Error>> {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
@@ -20,7 +20,7 @@ error[E0599]: no method named `emit` found for struct `tauri::Window` in the cur
|
||||
// 修复前
|
||||
use tauri::{State, Window};
|
||||
|
||||
// 修复后
|
||||
// 修复后
|
||||
use tauri::{Emitter, State, Window};
|
||||
```
|
||||
|
||||
@@ -131,7 +131,7 @@ cargo build # 完整构建
|
||||
以下功能完全正常工作:
|
||||
|
||||
1. **WebSocket 连接管理**
|
||||
2. **设置持久化存储**
|
||||
2. **设置持久化存储**
|
||||
3. **播放命令发送**
|
||||
4. **状态管理和同步**
|
||||
5. **视频信息获取**
|
||||
|
@@ -22,14 +22,14 @@
|
||||
- 进度条和音量控制
|
||||
- 循环播放、全屏等高级功能
|
||||
- 播放列表管理
|
||||
|
||||
|
||||
- ✅ **设置页面 (`/settings`)**:全面的应用配置
|
||||
- 连接设置(IP地址、端口、超时等)
|
||||
- 播放设置(默认音量、循环播放等)
|
||||
- 界面设置(主题、语言等)
|
||||
- 高级设置(调试模式、缓存等)
|
||||
- 设置的导入导出功能
|
||||
|
||||
|
||||
- ✅ **关于页面 (`/about`)**:应用信息展示
|
||||
- 应用基本信息
|
||||
- 技术栈展示
|
||||
@@ -218,7 +218,7 @@ cargo build # 构建 Rust 后端
|
||||
该视频控制器项目成功搭建了一个现代化的桌面应用基础架构,具备:
|
||||
|
||||
- 完整的用户界面和用户体验
|
||||
- 健壮的后端API和服务架构
|
||||
- 健壮的后端API和服务架构
|
||||
- 详细的开发文档和规范
|
||||
- 良好的可扩展性和维护性
|
||||
|
||||
|
@@ -9,6 +9,10 @@ export default defineAppConfig({
|
||||
colors: {
|
||||
primary: "blue",
|
||||
neutral: "zinc"
|
||||
},
|
||||
icons: {
|
||||
light: "ph-sun",
|
||||
dark: "ph-moon"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@@ -1,5 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
@import "@nuxt/ui";
|
||||
@import "@nuxt/ui-pro";
|
||||
|
||||
@theme {
|
||||
--font-heading: "Montserrat", sans-serif;
|
||||
|
@@ -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>
|
||||
|
@@ -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,57 +39,63 @@
|
||||
<!-- 技术栈 -->
|
||||
<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>
|
||||
</div>
|
||||
</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" />
|
||||
@@ -158,9 +178,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</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 {
|
||||
name: string
|
||||
version: string
|
||||
description: string
|
||||
author: string
|
||||
buildDate: string
|
||||
}
|
||||
|
||||
const { app } = useAppConfig()
|
||||
|
||||
// 应用信息
|
||||
const appInfo = ref<AppInfo>({
|
||||
name: app.name,
|
||||
version: app.version,
|
||||
description: app.description,
|
||||
author: app.author,
|
||||
buildDate: new Date().toLocaleDateString('zh-CN')
|
||||
})
|
||||
|
||||
// 页面加载时获取构建信息
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 获取应用构建信息
|
||||
console.log('获取应用信息')
|
||||
} catch (error) {
|
||||
console.error('获取应用信息失败:', error)
|
||||
interface AppInfo {
|
||||
name: string
|
||||
version: string
|
||||
description: string
|
||||
author: string
|
||||
buildDate: string
|
||||
}
|
||||
})
|
||||
|
||||
const { app } = useAppConfig();
|
||||
|
||||
// 应用信息
|
||||
const appInfo = ref<AppInfo>({
|
||||
name: app.name,
|
||||
version: app.version,
|
||||
description: app.description,
|
||||
author: app.author,
|
||||
buildDate: new Date().toLocaleDateString("zh-CN")
|
||||
});
|
||||
|
||||
// 页面加载时获取构建信息
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 获取应用构建信息
|
||||
console.log("获取应用信息");
|
||||
} catch (error) {
|
||||
console.error("获取应用信息失败:", error);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@@ -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"
|
||||
<UButton
|
||||
: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>
|
||||
@@ -120,8 +132,8 @@
|
||||
<p>播放列表为空</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div
|
||||
v-for="(item, index) in playlist"
|
||||
<div
|
||||
v-for="(item, index) in playlist"
|
||||
:key="index"
|
||||
class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-lg"
|
||||
>
|
||||
@@ -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'
|
||||
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 '未连接'
|
||||
interface VideoControllerState {
|
||||
connectionStatus: "connected" | "connecting" | "disconnected"
|
||||
currentVideo: string | null
|
||||
progress: number
|
||||
volume: number
|
||||
isLooping: boolean
|
||||
playlist: string[]
|
||||
playerAddress: string
|
||||
}
|
||||
})
|
||||
|
||||
// 方法
|
||||
const toggleConnection = async () => {
|
||||
if (connectionStatus.value === 'connected') {
|
||||
// 断开连接
|
||||
connectionStatus.value = 'disconnected'
|
||||
} else {
|
||||
// 尝试连接
|
||||
connectionStatus.value = 'connecting'
|
||||
// TODO: 在这里调用 Tauri API 进行实际连接
|
||||
setTimeout(() => {
|
||||
connectionStatus.value = 'connected' // 模拟连接成功
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
// 响应式状态
|
||||
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 playVideo = async () => {
|
||||
// TODO: 调用 Tauri API
|
||||
console.log('播放视频')
|
||||
}
|
||||
// 计算属性
|
||||
const isConnected = computed(() => connectionStatus.value === "connected");
|
||||
|
||||
const pauseVideo = async () => {
|
||||
// TODO: 调用 Tauri API
|
||||
console.log('暂停视频')
|
||||
}
|
||||
const connectionStatusText = computed(() => {
|
||||
switch (connectionStatus.value) {
|
||||
case "connected": return "已连接";
|
||||
case "connecting": return "连接中...";
|
||||
default: return "未连接";
|
||||
}
|
||||
});
|
||||
|
||||
const stopVideo = async () => {
|
||||
// TODO: 调用 Tauri API
|
||||
console.log('停止视频')
|
||||
}
|
||||
// 方法
|
||||
const toggleConnection = async () => {
|
||||
if (connectionStatus.value === "connected") {
|
||||
// 断开连接
|
||||
connectionStatus.value = "disconnected";
|
||||
} else {
|
||||
// 尝试连接
|
||||
connectionStatus.value = "connecting";
|
||||
// TODO: 在这里调用 Tauri API 进行实际连接
|
||||
setTimeout(() => {
|
||||
connectionStatus.value = "connected"; // 模拟连接成功
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleLoop = async () => {
|
||||
isLooping.value = !isLooping.value
|
||||
// TODO: 调用 Tauri API
|
||||
console.log('循环播放:', isLooping.value)
|
||||
}
|
||||
const playVideo = async () => {
|
||||
// TODO: 调用 Tauri API
|
||||
console.log("播放视频");
|
||||
};
|
||||
|
||||
const toggleFullscreen = async () => {
|
||||
// TODO: 调用 Tauri API
|
||||
console.log('切换全屏')
|
||||
}
|
||||
const pauseVideo = async () => {
|
||||
// TODO: 调用 Tauri API
|
||||
console.log("暂停视频");
|
||||
};
|
||||
|
||||
const openVideoFile = async () => {
|
||||
// TODO: 调用 Tauri API 打开文件选择器
|
||||
console.log('打开文件')
|
||||
// 模拟添加到播放列表
|
||||
playlist.value.push(`示例视频${playlist.value.length + 1}.mp4`)
|
||||
}
|
||||
const stopVideo = async () => {
|
||||
// TODO: 调用 Tauri API
|
||||
console.log("停止视频");
|
||||
};
|
||||
|
||||
const playVideoFromPlaylist = async (index: number) => {
|
||||
currentVideo.value = playlist.value[index]
|
||||
// TODO: 调用 Tauri API 播放指定视频
|
||||
console.log('播放:', currentVideo.value)
|
||||
}
|
||||
const toggleLoop = async () => {
|
||||
isLooping.value = !isLooping.value;
|
||||
// TODO: 调用 Tauri API
|
||||
console.log("循环播放:", isLooping.value);
|
||||
};
|
||||
|
||||
const removeFromPlaylist = (index: number) => {
|
||||
playlist.value.splice(index, 1)
|
||||
}
|
||||
const toggleFullscreen = async () => {
|
||||
// TODO: 调用 Tauri API
|
||||
console.log("切换全屏");
|
||||
};
|
||||
|
||||
const clearPlaylist = () => {
|
||||
playlist.value = []
|
||||
currentVideo.value = null
|
||||
}
|
||||
const openVideoFile = async () => {
|
||||
// TODO: 调用 Tauri API 打开文件选择器
|
||||
console.log("打开文件");
|
||||
// 模拟添加到播放列表
|
||||
playlist.value.push(`示例视频${playlist.value.length + 1}.mp4`);
|
||||
};
|
||||
|
||||
// 监听进度变化
|
||||
watch(progress, (newProgress) => {
|
||||
// TODO: 调用 Tauri API 设置播放进度
|
||||
console.log('设置进度:', newProgress)
|
||||
})
|
||||
const playVideoFromPlaylist = async (index: number) => {
|
||||
currentVideo.value = playlist.value[index];
|
||||
// TODO: 调用 Tauri API 播放指定视频
|
||||
console.log("播放:", currentVideo.value);
|
||||
};
|
||||
|
||||
// 监听音量变化
|
||||
watch(volume, (newVolume) => {
|
||||
// TODO: 调用 Tauri API 设置音量
|
||||
console.log('设置音量:', newVolume)
|
||||
})
|
||||
const removeFromPlaylist = (index: number) => {
|
||||
playlist.value.splice(index, 1);
|
||||
};
|
||||
|
||||
const clearPlaylist = () => {
|
||||
playlist.value = [];
|
||||
currentVideo.value = null;
|
||||
};
|
||||
|
||||
// 监听进度变化
|
||||
watch(progress, (newProgress) => {
|
||||
// TODO: 调用 Tauri API 设置播放进度
|
||||
console.log("设置进度:", newProgress);
|
||||
});
|
||||
|
||||
// 监听音量变化
|
||||
watch(volume, (newVolume) => {
|
||||
// TODO: 调用 Tauri API 设置音量
|
||||
console.log("设置音量:", newVolume);
|
||||
});
|
||||
</script>
|
||||
|
@@ -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地址和端口">
|
||||
@@ -23,12 +25,12 @@
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="重连间隔 (秒)" description="自动重连的间隔时间">
|
||||
<UInput
|
||||
v-model.number="settings.reconnectInterval"
|
||||
type="number"
|
||||
min="1"
|
||||
<UInput
|
||||
v-model.number="settings.reconnectInterval"
|
||||
type="number"
|
||||
min="1"
|
||||
max="300"
|
||||
:disabled="!settings.autoReconnect"
|
||||
:disabled="!settings.autoReconnect"
|
||||
/>
|
||||
</UFormGroup>
|
||||
</div>
|
||||
@@ -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="新视频播放时的默认音量">
|
||||
@@ -56,7 +60,7 @@
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="播放完成后行为">
|
||||
<USelectMenu
|
||||
<USelectMenu
|
||||
v-model="settings.playbackEndBehavior"
|
||||
:options="playbackEndOptions"
|
||||
option-attribute="label"
|
||||
@@ -69,11 +73,13 @@
|
||||
<!-- 界面设置 -->
|
||||
<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="主题模式">
|
||||
<USelectMenu
|
||||
<USelectMenu
|
||||
v-model="settings.theme"
|
||||
:options="themeOptions"
|
||||
option-attribute="label"
|
||||
@@ -82,7 +88,7 @@
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="语言">
|
||||
<USelectMenu
|
||||
<USelectMenu
|
||||
v-model="settings.language"
|
||||
:options="languageOptions"
|
||||
option-attribute="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,80 +149,27 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
interface AppSettings {
|
||||
playerHost: string
|
||||
playerPort: number
|
||||
connectionTimeout: number
|
||||
autoReconnect: boolean
|
||||
reconnectInterval: number
|
||||
defaultVolume: number
|
||||
defaultLoop: boolean
|
||||
autoFullscreen: boolean
|
||||
playbackEndBehavior: string
|
||||
theme: string
|
||||
language: string
|
||||
showNotifications: boolean
|
||||
debugMode: boolean
|
||||
cacheSize: number
|
||||
proxy: string
|
||||
}
|
||||
|
||||
// 响应式设置数据
|
||||
const settings = ref<AppSettings>({
|
||||
playerHost: '192.168.1.100',
|
||||
playerPort: 8080,
|
||||
connectionTimeout: 10,
|
||||
autoReconnect: true,
|
||||
reconnectInterval: 5,
|
||||
defaultVolume: 50,
|
||||
defaultLoop: false,
|
||||
autoFullscreen: false,
|
||||
playbackEndBehavior: 'stop',
|
||||
theme: 'system',
|
||||
language: 'zh-CN',
|
||||
showNotifications: true,
|
||||
debugMode: false,
|
||||
cacheSize: 100,
|
||||
proxy: ''
|
||||
})
|
||||
|
||||
// 选项数据
|
||||
const playbackEndOptions = [
|
||||
{ label: '停止播放', value: 'stop' },
|
||||
{ label: '播放下一个', value: 'next' },
|
||||
{ label: '重复播放', value: 'repeat' }
|
||||
]
|
||||
|
||||
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 saveSettings = async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 保存设置
|
||||
console.log('保存设置:', settings.value)
|
||||
// 显示成功通知
|
||||
// useToast().add({ title: '设置已保存', color: 'green' })
|
||||
} catch (error) {
|
||||
console.error('保存设置失败:', error)
|
||||
// 显示错误通知
|
||||
// useToast().add({ title: '保存失败', color: 'red' })
|
||||
interface AppSettings {
|
||||
playerHost: string
|
||||
playerPort: number
|
||||
connectionTimeout: number
|
||||
autoReconnect: boolean
|
||||
reconnectInterval: number
|
||||
defaultVolume: number
|
||||
defaultLoop: boolean
|
||||
autoFullscreen: boolean
|
||||
playbackEndBehavior: string
|
||||
theme: string
|
||||
language: string
|
||||
showNotifications: boolean
|
||||
debugMode: boolean
|
||||
cacheSize: number
|
||||
proxy: string
|
||||
}
|
||||
}
|
||||
|
||||
const resetSettings = async () => {
|
||||
// 重置为默认设置
|
||||
settings.value = {
|
||||
playerHost: '192.168.1.100',
|
||||
// 响应式设置数据
|
||||
const settings = ref<AppSettings>({
|
||||
playerHost: "192.168.1.100",
|
||||
playerPort: 8080,
|
||||
connectionTimeout: 10,
|
||||
autoReconnect: true,
|
||||
@@ -222,47 +177,100 @@ 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 () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 导出设置到文件
|
||||
console.log('导出设置')
|
||||
} catch (error) {
|
||||
console.error('导出设置失败:', error)
|
||||
}
|
||||
}
|
||||
// 选项数据
|
||||
const playbackEndOptions = [
|
||||
{ label: "停止播放", value: "stop" },
|
||||
{ label: "播放下一个", value: "next" },
|
||||
{ label: "重复播放", value: "repeat" }
|
||||
];
|
||||
|
||||
const importSettings = async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 从文件导入设置
|
||||
console.log('导入设置')
|
||||
} catch (error) {
|
||||
console.error('导入设置失败:', error)
|
||||
}
|
||||
}
|
||||
const themeOptions = [
|
||||
{ label: "跟随系统", value: "system" },
|
||||
{ label: "浅色模式", value: "light" },
|
||||
{ label: "深色模式", value: "dark" }
|
||||
];
|
||||
|
||||
// 页面加载时读取设置
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 读取保存的设置
|
||||
console.log('加载设置')
|
||||
} catch (error) {
|
||||
console.error('加载设置失败:', error)
|
||||
}
|
||||
})
|
||||
const languageOptions = [
|
||||
{ label: "简体中文", value: "zh-CN" },
|
||||
{ label: "English", value: "en" },
|
||||
{ label: "日本語", value: "ja" }
|
||||
];
|
||||
|
||||
// 监听设置变化并自动保存关键设置
|
||||
watch(() => [settings.value.playerHost, settings.value.playerPort], async () => {
|
||||
// 自动保存连接相关设置
|
||||
await saveSettings()
|
||||
}, { debounce: 1000 })
|
||||
// 方法
|
||||
const saveSettings = async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 保存设置
|
||||
console.log("保存设置:", settings.value);
|
||||
// 显示成功通知
|
||||
// useToast().add({ title: '设置已保存', color: 'green' })
|
||||
} catch (error) {
|
||||
console.error("保存设置失败:", error);
|
||||
// 显示错误通知
|
||||
// useToast().add({ title: '保存失败', color: 'red' })
|
||||
}
|
||||
};
|
||||
|
||||
const resetSettings = async () => {
|
||||
// 重置为默认设置
|
||||
settings.value = {
|
||||
playerHost: "192.168.1.100",
|
||||
playerPort: 8080,
|
||||
connectionTimeout: 10,
|
||||
autoReconnect: true,
|
||||
reconnectInterval: 5,
|
||||
defaultVolume: 50,
|
||||
defaultLoop: false,
|
||||
autoFullscreen: false,
|
||||
playbackEndBehavior: "stop",
|
||||
theme: "system",
|
||||
language: "zh-CN",
|
||||
showNotifications: true,
|
||||
debugMode: false,
|
||||
cacheSize: 100,
|
||||
proxy: ""
|
||||
};
|
||||
};
|
||||
|
||||
const exportSettings = async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 导出设置到文件
|
||||
console.log("导出设置");
|
||||
} catch (error) {
|
||||
console.error("导出设置失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const importSettings = async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 从文件导入设置
|
||||
console.log("导入设置");
|
||||
} catch (error) {
|
||||
console.error("导入设置失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载时读取设置
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// TODO: 调用 Tauri API 读取保存的设置
|
||||
console.log("加载设置");
|
||||
} catch (error) {
|
||||
console.error("加载设置失败:", error);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听设置变化并自动保存关键设置
|
||||
watch(() => [settings.value.playerHost, settings.value.playerPort], async () => {
|
||||
// 自动保存连接相关设置
|
||||
await saveSettings();
|
||||
}, { debounce: 1000 });
|
||||
</script>
|
||||
|
@@ -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: {
|
||||
|
@@ -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
652
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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"] } }
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user