Compare commits
1 Commits
master
...
feat/tauri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c090299b1 |
79
.github/workflows/build-app.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
name: Build Desktop App
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest, ubuntu-latest, windows-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install dependencies (Ubuntu)
|
||||
if: matrix.platform == 'ubuntu-latest'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
pip install uv
|
||||
uv sync
|
||||
|
||||
- name: Build Python backend with Nuitka
|
||||
run: |
|
||||
pip install nuitka
|
||||
python build_nuitka.py
|
||||
|
||||
- name: Install Node dependencies
|
||||
working-directory: ./dashboard
|
||||
run: npm install
|
||||
|
||||
- name: Build Tauri app
|
||||
working-directory: ./dashboard
|
||||
run: npm run tauri:build
|
||||
|
||||
- name: Upload artifacts (macOS)
|
||||
if: matrix.platform == 'macos-latest'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: astrbot-macos
|
||||
path: dashboard/src-tauri/target/release/bundle/dmg/*.dmg
|
||||
|
||||
- name: Upload artifacts (Windows)
|
||||
if: matrix.platform == 'windows-latest'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: astrbot-windows
|
||||
path: dashboard/src-tauri/target/release/bundle/msi/*.msi
|
||||
|
||||
- name: Upload artifacts (Linux)
|
||||
if: matrix.platform == 'ubuntu-latest'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: astrbot-linux
|
||||
path: |
|
||||
dashboard/src-tauri/target/release/bundle/deb/*.deb
|
||||
dashboard/src-tauri/target/release/bundle/appimage/*.AppImage
|
||||
2
.gitignore
vendored
@@ -32,6 +32,7 @@ tests/astrbot_plugin_openai
|
||||
# Dashboard
|
||||
dashboard/node_modules/
|
||||
dashboard/dist/
|
||||
dashboard/src-tauri/target
|
||||
package-lock.json
|
||||
package.json
|
||||
|
||||
@@ -47,3 +48,4 @@ astrbot.lock
|
||||
chroma
|
||||
venv/*
|
||||
pytest.ini
|
||||
build/
|
||||
287
BUILD_INSTRUCTIONS.md
Normal file
@@ -0,0 +1,287 @@
|
||||
# AstrBot 桌面应用构建指南
|
||||
|
||||
本指南介绍如何使用 Nuitka 将 Python 后端打包并集成到 Tauri 桌面应用中。
|
||||
|
||||
## 前置要求
|
||||
|
||||
### 系统要求
|
||||
- Python 3.10+
|
||||
- Node.js 20+
|
||||
- Rust (通过 rustup 安装)
|
||||
- UV 包管理器
|
||||
|
||||
### macOS 额外要求
|
||||
- Xcode Command Line Tools: `xcode-select --install`
|
||||
|
||||
### Linux 额外要求
|
||||
```bash
|
||||
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev \
|
||||
libappindicator3-dev librsvg2-dev patchelf
|
||||
```
|
||||
|
||||
### Windows 额外要求
|
||||
- Visual Studio 2019+ with C++ build tools
|
||||
- Windows 10 SDK
|
||||
|
||||
## 构建步骤
|
||||
|
||||
### 1. 安装 Python 依赖
|
||||
```bash
|
||||
pip install uv
|
||||
uv sync
|
||||
```
|
||||
|
||||
### 2. 安装 Nuitka
|
||||
```bash
|
||||
pip install nuitka
|
||||
```
|
||||
|
||||
### 3. 构建 Python 后端
|
||||
```bash
|
||||
python build_nuitka.py
|
||||
```
|
||||
|
||||
这会使用 Nuitka 将 `main.py` 编译为独立可执行文件,输出到 `build/nuitka/` 目录。
|
||||
|
||||
**注意**: Nuitka 编译过程可能需要 10-30 分钟,取决于您的系统性能。
|
||||
|
||||
### 4. 安装前端依赖
|
||||
```bash
|
||||
cd dashboard
|
||||
npm install
|
||||
```
|
||||
|
||||
### 5. 构建 Tauri 应用
|
||||
```bash
|
||||
npm run tauri:build
|
||||
```
|
||||
|
||||
构建脚本会自动:
|
||||
1. 运行 `build_nuitka.py` 编译 Python 后端
|
||||
2. 将编译好的可执行文件复制到 `src-tauri/resources/` 目录
|
||||
3. 构建 Tauri 应用并打包所有资源
|
||||
|
||||
### 6. 查找构建产物
|
||||
|
||||
构建完成后,您可以在以下位置找到安装包:
|
||||
|
||||
- **macOS**: `dashboard/src-tauri/target/release/bundle/dmg/AstrBot_*.dmg`
|
||||
- **Windows**: `dashboard/src-tauri/target/release/bundle/msi/AstrBot_*.msi`
|
||||
- **Linux**:
|
||||
- `dashboard/src-tauri/target/release/bundle/deb/astrbot_*.deb`
|
||||
- `dashboard/src-tauri/target/release/bundle/appimage/astrbot_*.AppImage`
|
||||
|
||||
## 开发模式
|
||||
|
||||
在开发时,您可能不想每次都完整编译 Python 后端。
|
||||
|
||||
### 仅开发 Tauri + Vue
|
||||
```bash
|
||||
cd dashboard
|
||||
npm run tauri:dev
|
||||
```
|
||||
|
||||
这会启动开发服务器,但不会自动启动 Python 后端。您需要手动运行:
|
||||
```bash
|
||||
uv run main.py
|
||||
```
|
||||
|
||||
### 测试完整集成
|
||||
如果您想测试 Tauri 自动启动 Python 后端的功能:
|
||||
|
||||
1. 先编译一次 Python 后端:
|
||||
```bash
|
||||
python build_nuitka.py
|
||||
```
|
||||
|
||||
2. 手动复制到资源目录:
|
||||
```bash
|
||||
# macOS
|
||||
cp -r build/nuitka/main.app dashboard/src-tauri/resources/astrbot-backend.app
|
||||
|
||||
# Windows
|
||||
copy build\nuitka\main.exe dashboard\src-tauri\resources\astrbot-backend.exe
|
||||
|
||||
# Linux
|
||||
cp build/nuitka/main.bin dashboard/src-tauri/resources/astrbot-backend
|
||||
```
|
||||
|
||||
3. 运行开发模式:
|
||||
```bash
|
||||
cd dashboard
|
||||
npm run tauri:dev
|
||||
```
|
||||
|
||||
## Nuitka 构建选项说明
|
||||
|
||||
`build_nuitka.py` 脚本使用以下关键选项:
|
||||
|
||||
- `--standalone`: 创建包含所有依赖的独立目录
|
||||
- `--onefile`: 将所有内容打包到单个可执行文件
|
||||
- `--follow-imports`: 自动跟踪所有 Python 导入
|
||||
- `--include-package`: 明确包含特定包
|
||||
- `--include-data-dir`: 包含数据目录(插件、配置等)
|
||||
|
||||
### 自定义构建
|
||||
|
||||
如果您需要修改构建选项,编辑 `build_nuitka.py`:
|
||||
|
||||
```python
|
||||
# 添加更多要包含的包
|
||||
include_packages = [
|
||||
"astrbot",
|
||||
"your_custom_package",
|
||||
# ...
|
||||
]
|
||||
|
||||
# 添加更多数据目录
|
||||
data_includes = [
|
||||
"data/config",
|
||||
"your_custom_data",
|
||||
# ...
|
||||
]
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. Nuitka 编译失败
|
||||
**问题**: 编译时出现 "module not found" 错误
|
||||
|
||||
**解决方案**: 在 `build_nuitka.py` 中添加缺失的包到 `include_packages` 列表
|
||||
|
||||
### 2. 运行时找不到资源文件
|
||||
**问题**: 应用启动后提示找不到配置文件或插件
|
||||
|
||||
**解决方案**: 确保在 `build_nuitka.py` 中使用 `--include-data-dir` 包含了所有必要的数据目录
|
||||
|
||||
### 3. macOS 安全警告
|
||||
**问题**: macOS 提示"应用来自未知开发者"
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 临时解除限制
|
||||
sudo spctl --master-disable
|
||||
|
||||
# 或者为特定应用授权
|
||||
xattr -cr /Applications/AstrBot.app
|
||||
```
|
||||
|
||||
对于生产发布,您需要:
|
||||
1. 注册 Apple Developer 账号
|
||||
2. 对应用进行代码签名
|
||||
3. 提交公证 (Notarization)
|
||||
|
||||
### 4. Windows Defender 报毒
|
||||
**问题**: Windows Defender 或其他杀毒软件报毒
|
||||
|
||||
**解决方案**:
|
||||
- 这是 Nuitka 打包程序的常见问题
|
||||
- 可以使用 `--windows-company-name` 和 `--windows-product-name` 添加元数据
|
||||
- 对于生产发布,需要购买代码签名证书
|
||||
|
||||
### 5. Linux 依赖问题
|
||||
**问题**: 在某些 Linux 发行版上缺少共享库
|
||||
|
||||
**解决方案**: 使用 AppImage 格式,它包含所有依赖:
|
||||
```bash
|
||||
# 构建时会自动生成 AppImage
|
||||
npm run tauri:build
|
||||
```
|
||||
|
||||
## 优化构建大小
|
||||
|
||||
默认的 `--onefile` 模式会生成较大的可执行文件。如果需要减小体积:
|
||||
|
||||
1. 移除不需要的包
|
||||
2. 使用 `--standalone` 而不是 `--onefile`
|
||||
3. 排除不必要的数据文件
|
||||
|
||||
修改 `build_nuitka.py`:
|
||||
```python
|
||||
# 移除 --onefile,使用 --standalone
|
||||
nuitka_cmd = [
|
||||
sys.executable,
|
||||
"-m", "nuitka",
|
||||
"--standalone", # 只使用 standalone
|
||||
# "--onefile", # 注释掉 onefile
|
||||
# ...
|
||||
]
|
||||
```
|
||||
|
||||
## CI/CD 集成
|
||||
|
||||
项目已配置 GitHub Actions 工作流 (`.github/workflows/build-app.yml`),可以自动为所有平台构建应用。
|
||||
|
||||
推送标签时自动触发:
|
||||
```bash
|
||||
git tag v4.5.7
|
||||
git push origin v4.5.7
|
||||
```
|
||||
|
||||
或手动触发:
|
||||
在 GitHub Actions 页面选择 "Build Desktop App" 工作流并点击 "Run workflow"
|
||||
|
||||
## 发布清单
|
||||
|
||||
在发布新版本前:
|
||||
|
||||
- [ ] 更新版本号
|
||||
- `pyproject.toml` - Python 项目版本
|
||||
- `dashboard/package.json` - Node 项目版本
|
||||
- `dashboard/src-tauri/Cargo.toml` - Rust 项目版本
|
||||
- `dashboard/src-tauri/tauri.conf.json` - Tauri 配置版本
|
||||
|
||||
- [ ] 运行代码检查
|
||||
```bash
|
||||
uv run ruff check .
|
||||
uv run ruff format .
|
||||
```
|
||||
|
||||
- [ ] 本地测试构建
|
||||
```bash
|
||||
python build_nuitka.py
|
||||
cd dashboard && npm run tauri:build
|
||||
```
|
||||
|
||||
- [ ] 测试安装包
|
||||
- 安装生成的安装包
|
||||
- 验证应用启动
|
||||
- 验证 Python 后端自动启动
|
||||
- 测试核心功能
|
||||
|
||||
- [ ] 创建发布标签
|
||||
```bash
|
||||
git tag -a v4.5.7 -m "Release v4.5.7"
|
||||
git push origin v4.5.7
|
||||
```
|
||||
|
||||
## 技术架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Tauri Desktop App │
|
||||
│ (Rust + WebView) │
|
||||
│ │
|
||||
│ ┌─────────────────────────────┐ │
|
||||
│ │ Vue.js Dashboard │ │
|
||||
│ │ (Frontend UI) │ │
|
||||
│ └─────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────┐ │
|
||||
│ │ Python Backend │ │
|
||||
│ │ (Nuitka Compiled) │ │
|
||||
│ │ - AstrBot Core │ │
|
||||
│ │ - Plugins │ │
|
||||
│ │ - API Server │ │
|
||||
│ └─────────────────────────────┘ │
|
||||
│ │
|
||||
│ HTTP/WebSocket │
|
||||
│ localhost:6185 │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [Nuitka 文档](https://nuitka.net/doc/user-manual.html)
|
||||
- [Tauri 文档](https://tauri.app/v1/guides/)
|
||||
- [AstrBot 文档](https://astrbot.fun)
|
||||
134
build_nuitka.py
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Use Nuitka to build the AstrBot project into standalone executables
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_platform_info():
|
||||
"""fetch the current platform information"""
|
||||
system = platform.system()
|
||||
machine = platform.machine()
|
||||
return system, machine
|
||||
|
||||
|
||||
def build_with_nuitka():
|
||||
"""use Nuitka to build the project"""
|
||||
system, machine = get_platform_info()
|
||||
|
||||
print(f"🚀 Starting build for {system} ({machine}) platform...")
|
||||
|
||||
# Output directory
|
||||
output_dir = Path("build/nuitka")
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Base Nuitka command
|
||||
nuitka_cmd = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"nuitka",
|
||||
"--standalone", # Create standalone directory
|
||||
"--onefile", # Single file mode
|
||||
"--follow-imports", # Follow all imports
|
||||
"--enable-plugin=multiprocessing", # Enable multiprocessing support
|
||||
"--output-dir=build/nuitka", # Output directory
|
||||
"--quiet", # Reduce output verbosity
|
||||
"--assume-yes-for-downloads", # Automatically download dependencies
|
||||
"--jobs=4", # Use multiple CPU cores
|
||||
]
|
||||
|
||||
# include specific packages
|
||||
include_packages = [
|
||||
"astrbot",
|
||||
]
|
||||
|
||||
for pkg in include_packages:
|
||||
nuitka_cmd.extend([f"--include-package={pkg}"])
|
||||
|
||||
# include data directories
|
||||
# data_includes = [
|
||||
# "data/config",
|
||||
# "data/plugins",
|
||||
# "data/temp",
|
||||
# ]
|
||||
|
||||
# for data_dir in data_includes:
|
||||
# if os.path.exists(data_dir):
|
||||
# nuitka_cmd.extend([f"--include-data-dir={data_dir}={data_dir}"])
|
||||
|
||||
# include packages directory (built-in plugins)
|
||||
# if os.path.exists("packages"):
|
||||
# nuitka_cmd.extend(["--include-data-dir=packages=packages"])
|
||||
|
||||
# Platform specific settings
|
||||
if system == "Darwin": # macOS
|
||||
nuitka_cmd.extend(
|
||||
[
|
||||
"--macos-create-app-bundle", # Create .app bundle
|
||||
"--macos-app-name=AstrBot",
|
||||
]
|
||||
)
|
||||
# macOS icon (if exists)
|
||||
icon_path = "dashboard/src-tauri/icons/icon.icns"
|
||||
if os.path.exists(icon_path):
|
||||
nuitka_cmd.extend([f"--macos-app-icon={icon_path}"])
|
||||
elif system == "Windows":
|
||||
nuitka_cmd.extend(
|
||||
[
|
||||
"--windows-console-mode=disable", # 无控制台窗口
|
||||
]
|
||||
)
|
||||
# Windows icon (if exists)
|
||||
icon_path = "dashboard/src-tauri/icons/icon.ico"
|
||||
if os.path.exists(icon_path):
|
||||
nuitka_cmd.extend([f"--windows-icon-from-ico={icon_path}"])
|
||||
|
||||
# Main file to compile
|
||||
nuitka_cmd.append("main.py")
|
||||
|
||||
print(f"📦 Executing command: {' '.join(nuitka_cmd)}")
|
||||
|
||||
try:
|
||||
subprocess.run(nuitka_cmd, check=True)
|
||||
print("✅ Nuitka build successful!")
|
||||
|
||||
# Find the generated executable
|
||||
if system == "Darwin":
|
||||
built_file = list(output_dir.glob("*.app"))
|
||||
if built_file:
|
||||
print(f"Generated macOS app: {built_file[0]}")
|
||||
elif system == "Windows":
|
||||
built_file = list(output_dir.glob("*.exe"))
|
||||
if built_file:
|
||||
print(f"Generated Windows executable: {built_file[0]}")
|
||||
else: # Linux
|
||||
built_file = list(output_dir.glob("main.bin"))
|
||||
if built_file:
|
||||
print(f"Generated Linux executable: {built_file[0]}")
|
||||
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ Nuitka build failed: {e}")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("AstrBot Nuitka Builder")
|
||||
print("=" * 60)
|
||||
|
||||
# 构建
|
||||
if build_with_nuitka():
|
||||
print("\n" + "=" * 60)
|
||||
print("🎉 Build Complete!")
|
||||
print("=" * 60)
|
||||
else:
|
||||
print("\n" + "=" * 60)
|
||||
print("❌ Build Failed")
|
||||
print("=" * 60)
|
||||
sys.exit(1)
|
||||
134
build_pyinstaller.py
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Use PyInstaller to build the AstrBot project into standalone executables
|
||||
"""
|
||||
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_platform_info():
|
||||
"""fetch the current platform information"""
|
||||
system = platform.system()
|
||||
machine = platform.machine()
|
||||
return system, machine
|
||||
|
||||
|
||||
def build_with_pyinstaller():
|
||||
"""use PyInstaller to build the project"""
|
||||
system, machine = get_platform_info()
|
||||
|
||||
print(f"🚀 Starting build for {system} ({machine}) platform...")
|
||||
|
||||
# Output directory
|
||||
output_dir = Path("build/pyinstaller")
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Base PyInstaller command
|
||||
pyinstaller_cmd = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"PyInstaller",
|
||||
"--clean", # Clean cache before build
|
||||
"--noconfirm", # Replace output directory without asking
|
||||
"--onefile", # Single file mode
|
||||
"--distpath=build/pyinstaller/dist", # Distribution directory
|
||||
"--workpath=build/pyinstaller/build", # Work directory
|
||||
"--specpath=build/pyinstaller", # Spec file directory
|
||||
"--name=AstrBot", # Output executable name
|
||||
]
|
||||
# Platform specific settings
|
||||
# if system == "Darwin": # macOS
|
||||
# # macOS icon (if exists)
|
||||
# icon_path = "dashboard/src-tauri/icons/icon.icns"
|
||||
# if os.path.exists(icon_path):
|
||||
# pyinstaller_cmd.extend([f"--icon={icon_path}"])
|
||||
# # Create .app bundle
|
||||
# pyinstaller_cmd.extend(["--windowed"])
|
||||
# elif system == "Windows":
|
||||
# # Windows icon (if exists)
|
||||
# icon_path = "dashboard/src-tauri/icons/icon.ico"
|
||||
# if os.path.exists(icon_path):
|
||||
# pyinstaller_cmd.extend([f"--icon={icon_path}"])
|
||||
# # No console window
|
||||
# pyinstaller_cmd.extend(["--windowed"])
|
||||
# else: # Linux
|
||||
# pyinstaller_cmd.extend(["--console"])
|
||||
|
||||
# Main file to compile
|
||||
pyinstaller_cmd.append("main.py")
|
||||
|
||||
print(f"📦 Executing command: {' '.join(pyinstaller_cmd)}")
|
||||
|
||||
try:
|
||||
subprocess.run(pyinstaller_cmd, check=True)
|
||||
print("✅ PyInstaller build successful!")
|
||||
|
||||
# Find the generated executable
|
||||
dist_dir = output_dir / "dist"
|
||||
if system == "Darwin":
|
||||
built_file = list(dist_dir.glob("AstrBot.app"))
|
||||
if not built_file:
|
||||
built_file = list(dist_dir.glob("AstrBot"))
|
||||
if built_file:
|
||||
print(f"📱 Generated macOS app: {built_file[0]}")
|
||||
elif system == "Windows":
|
||||
built_file = list(dist_dir.glob("AstrBot.exe"))
|
||||
if built_file:
|
||||
print(f"💻 Generated Windows executable: {built_file[0]}")
|
||||
else: # Linux
|
||||
built_file = list(dist_dir.glob("AstrBot"))
|
||||
if built_file:
|
||||
print(f"🐧 Generated Linux executable: {built_file[0]}")
|
||||
|
||||
print(f"\n📁 Output directory: {dist_dir.absolute()}")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ PyInstaller build failed: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ Unexpected error: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def install_pyinstaller():
|
||||
"""Install PyInstaller if not already installed"""
|
||||
try:
|
||||
import PyInstaller
|
||||
|
||||
print(f"✅ PyInstaller already installed (version {PyInstaller.__version__})")
|
||||
return True
|
||||
except ImportError:
|
||||
print("📥 PyInstaller not found, installing...")
|
||||
try:
|
||||
subprocess.run(
|
||||
[sys.executable, "-m", "pip", "install", "pyinstaller"], check=True
|
||||
)
|
||||
print("✅ PyInstaller installed successfully!")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ Failed to install PyInstaller: {e}")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 60)
|
||||
print("AstrBot PyInstaller Builder")
|
||||
print("=" * 60)
|
||||
|
||||
# Check and install PyInstaller
|
||||
if not install_pyinstaller():
|
||||
sys.exit(1)
|
||||
|
||||
# Build
|
||||
if build_with_pyinstaller():
|
||||
print("\n" + "=" * 60)
|
||||
print("🎉 Build Complete!")
|
||||
print("=" * 60)
|
||||
else:
|
||||
print("\n" + "=" * 60)
|
||||
print("❌ Build Failed")
|
||||
print("=" * 60)
|
||||
sys.exit(1)
|
||||
225
dashboard/TAURI_README.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# AstrBot Dashboard - Tauri 桌面应用
|
||||
|
||||
本项目现已支持通过 Tauri 构建为桌面应用,同时保持与 Web 版本的兼容性。
|
||||
|
||||
## 环境要求
|
||||
|
||||
### 系统依赖
|
||||
|
||||
**macOS:**
|
||||
```bash
|
||||
# 安装 Xcode Command Line Tools
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
- 安装 [Microsoft Visual Studio C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
|
||||
- 安装 [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)
|
||||
|
||||
**Linux (Ubuntu/Debian):**
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install libwebkit2gtk-4.0-dev \
|
||||
build-essential \
|
||||
curl \
|
||||
wget \
|
||||
file \
|
||||
libssl-dev \
|
||||
libgtk-3-dev \
|
||||
libayatana-appindicator3-dev \
|
||||
librsvg2-dev
|
||||
```
|
||||
|
||||
### Rust 环境
|
||||
|
||||
```bash
|
||||
# 安装 Rust
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
|
||||
# 验证安装
|
||||
rustc --version
|
||||
cargo --version
|
||||
```
|
||||
|
||||
## 安装依赖
|
||||
|
||||
```bash
|
||||
cd dashboard
|
||||
npm install
|
||||
```
|
||||
|
||||
## 开发模式
|
||||
|
||||
### Web 端开发(不变)
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
访问 http://localhost:3000
|
||||
|
||||
### 桌面端开发
|
||||
|
||||
```bash
|
||||
npm run tauri:dev
|
||||
```
|
||||
|
||||
这会同时启动:
|
||||
1. Vite 开发服务器(端口 3000)
|
||||
2. Tauri 桌面应用窗口
|
||||
|
||||
热重载功能正常工作,修改代码后会自动刷新。
|
||||
|
||||
## 构建
|
||||
|
||||
### Web 端构建(不变)
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
输出目录:`dist/`
|
||||
|
||||
### 桌面端构建
|
||||
|
||||
```bash
|
||||
npm run tauri:build
|
||||
```
|
||||
|
||||
构建产物位置:
|
||||
- **macOS**: `src-tauri/target/release/bundle/dmg/`
|
||||
- **Windows**: `src-tauri/target/release/bundle/msi/`
|
||||
- **Linux**: `src-tauri/target/release/bundle/deb/` 或 `appimage/`
|
||||
|
||||
## 图标设置
|
||||
|
||||
### 自动生成图标
|
||||
|
||||
准备一个至少 512x512 像素的 PNG 图标,然后运行:
|
||||
|
||||
```bash
|
||||
npm run tauri icon path/to/your/icon.png
|
||||
```
|
||||
|
||||
### 手动设置图标
|
||||
|
||||
将以下图标放入 `src-tauri/icons/` 目录:
|
||||
- `32x32.png`
|
||||
- `128x128.png`
|
||||
- `128x128@2x.png`
|
||||
- `icon.icns` (macOS)
|
||||
- `icon.ico` (Windows)
|
||||
|
||||
## 代码兼容性
|
||||
|
||||
项目已配置为同时支持 Web 和桌面端,使用相同的代码库。
|
||||
|
||||
### 环境检测工具
|
||||
|
||||
在 `src/utils/tauri.ts` 中提供了环境检测工具:
|
||||
|
||||
```typescript
|
||||
import { isTauri, isWeb, PlatformAPI } from '@/utils/tauri';
|
||||
|
||||
// 检测运行环境
|
||||
if (isTauri()) {
|
||||
console.log('运行在桌面应用中');
|
||||
} else {
|
||||
console.log('运行在浏览器中');
|
||||
}
|
||||
|
||||
// 获取正确的 API 端点
|
||||
const baseURL = PlatformAPI.getBaseURL();
|
||||
```
|
||||
|
||||
### API 调用注意事项
|
||||
|
||||
- **Web 端**: 使用 Vite 代理,API 路径为 `/api/*`
|
||||
- **桌面端**: 直接连接到 `http://127.0.0.1:6185`
|
||||
|
||||
已在 `PlatformAPI.getBaseURL()` 中处理,使用 axios 时:
|
||||
|
||||
```typescript
|
||||
import axios from 'axios';
|
||||
import { PlatformAPI } from '@/utils/tauri';
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: PlatformAPI.getBaseURL()
|
||||
});
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### tauri.conf.json
|
||||
|
||||
主要配置项:
|
||||
- `build.devPath`: 开发服务器地址(http://localhost:3000)
|
||||
- `build.distDir`: 构建输出目录(../dist)
|
||||
- `tauri.allowlist`: API 权限配置
|
||||
- `tauri.windows`: 窗口配置(大小、标题等)
|
||||
|
||||
### 安全性
|
||||
|
||||
默认配置已启用必要的权限:
|
||||
- 文件系统访问(限定在 APPDATA 目录)
|
||||
- HTTP 请求(限定到本地后端)
|
||||
- 窗口控制
|
||||
- 对话框(打开/保存文件)
|
||||
|
||||
可在 `tauri.conf.json` 的 `allowlist` 部分调整权限。
|
||||
|
||||
## 后端连接
|
||||
|
||||
桌面应用需要后端服务运行在 `http://127.0.0.1:6185`。
|
||||
|
||||
### 启动流程
|
||||
|
||||
1. 启动 AstrBot 后端:
|
||||
```bash
|
||||
cd /path/to/AstrBot
|
||||
uv run main.py
|
||||
```
|
||||
|
||||
2. 启动桌面应用:
|
||||
```bash
|
||||
cd dashboard
|
||||
npm run tauri:dev
|
||||
```
|
||||
|
||||
或直接运行打包后的应用(后端需要已启动)。
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: 桌面应用无法连接到后端?
|
||||
|
||||
确保:
|
||||
1. AstrBot 后端正在运行(`uv run main.py`)
|
||||
2. 后端监听在 `127.0.0.1:6185`
|
||||
3. 防火墙未阻止连接
|
||||
|
||||
### Q: 图标未显示?
|
||||
|
||||
检查 `src-tauri/icons/` 目录中是否有所需的图标文件,或使用 `npm run tauri icon` 命令生成。
|
||||
|
||||
### Q: 构建失败?
|
||||
|
||||
- 确保已安装 Rust 和系统依赖
|
||||
- 运行 `cargo clean` 清理缓存后重试
|
||||
- 检查 Rust 版本(需要 1.60+)
|
||||
|
||||
### Q: Web 端功能是否受影响?
|
||||
|
||||
不受影响。`npm run dev` 和 `npm run build` 的行为完全不变。
|
||||
|
||||
## 开发建议
|
||||
|
||||
1. **优先使用 Web 端开发**: 更快的热重载,更好的调试体验
|
||||
2. **定期测试桌面端**: 确保跨平台兼容性
|
||||
3. **使用环境检测**: 针对不同平台提供最佳体验
|
||||
4. **注意 API 差异**: Web 和桌面端的某些 API 可能有差异
|
||||
|
||||
## 更多资源
|
||||
|
||||
- [Tauri 官方文档](https://tauri.app/)
|
||||
- [Tauri API 参考](https://tauri.app/v1/api/js/)
|
||||
- [Tauri Discord 社区](https://discord.com/invite/tauri)
|
||||
@@ -10,10 +10,14 @@
|
||||
"build-prod": "vue-tsc --noEmit && vite build --base=/vue/free/",
|
||||
"preview": "vite preview --port 5050",
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||
"tauri": "tauri",
|
||||
"tauri:dev": "tauri dev",
|
||||
"tauri:build": "tauri build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@guolao/vue-monaco-editor": "^1.5.4",
|
||||
"@tauri-apps/api": "^2.9.0",
|
||||
"@tiptap/starter-kit": "2.1.7",
|
||||
"@tiptap/vue-3": "2.1.7",
|
||||
"apexcharts": "3.42.0",
|
||||
@@ -43,6 +47,7 @@
|
||||
"devDependencies": {
|
||||
"@mdi/font": "7.2.96",
|
||||
"@rushstack/eslint-patch": "1.3.3",
|
||||
"@tauri-apps/cli": "^2.9.4",
|
||||
"@types/chance": "1.1.3",
|
||||
"@types/markdown-it": "^14.1.2",
|
||||
"@types/node": "^20.5.7",
|
||||
|
||||
4509
dashboard/pnpm-lock.yaml
generated
Normal file
3
dashboard/src-tauri/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Tauri specific
|
||||
src-tauri/target/
|
||||
src-tauri/WixTools/
|
||||
4692
dashboard/src-tauri/Cargo.lock
generated
Normal file
27
dashboard/src-tauri/Cargo.toml
Normal file
@@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "astrbot-dashboard"
|
||||
version = "4.5.6"
|
||||
description = "AstrBot"
|
||||
authors = ["AstrBot Team"]
|
||||
license = "AGPL-3.0"
|
||||
repository = "https://github.com/AstrBotDevs/AstrBot"
|
||||
default-run = "astrbot-dashboard"
|
||||
edition = "2021"
|
||||
rust-version = "1.91.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "2.9.2", features = ["macos-private-api", "protocol-asset"] }
|
||||
tauri-plugin-opener = "2"
|
||||
|
||||
[features]
|
||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
||||
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
|
||||
# DO NOT REMOVE!!
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
||||
3
dashboard/src-tauri/build.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
1
dashboard/src-tauri/gen/schemas/acl-manifests.json
Normal file
1
dashboard/src-tauri/gen/schemas/capabilities.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
2244
dashboard/src-tauri/gen/schemas/desktop-schema.json
Normal file
2244
dashboard/src-tauri/gen/schemas/macOS-schema.json
Normal file
BIN
dashboard/src-tauri/icons/128x128.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
dashboard/src-tauri/icons/128x128@2x.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
dashboard/src-tauri/icons/32x32.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
dashboard/src-tauri/icons/64x64.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
dashboard/src-tauri/icons/Square107x107Logo.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
dashboard/src-tauri/icons/Square142x142Logo.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
dashboard/src-tauri/icons/Square150x150Logo.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
dashboard/src-tauri/icons/Square284x284Logo.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
dashboard/src-tauri/icons/Square30x30Logo.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
dashboard/src-tauri/icons/Square310x310Logo.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
dashboard/src-tauri/icons/Square44x44Logo.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
dashboard/src-tauri/icons/Square71x71Logo.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
dashboard/src-tauri/icons/Square89x89Logo.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
dashboard/src-tauri/icons/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
</adaptive-icon>
|
||||
BIN
dashboard/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
BIN
dashboard/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
BIN
dashboard/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
BIN
dashboard/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
BIN
dashboard/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#fff</color>
|
||||
</resources>
|
||||
BIN
dashboard/src-tauri/icons/icon.icns
Normal file
BIN
dashboard/src-tauri/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
dashboard/src-tauri/icons/icon.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-20x20@1x.png
Normal file
|
After Width: | Height: | Size: 602 B |
BIN
dashboard/src-tauri/icons/ios/AppIcon-20x20@2x-1.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-20x20@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-20x20@3x.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-29x29@1x.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-29x29@2x-1.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-29x29@2x.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-29x29@3x.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-40x40@1x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-40x40@2x-1.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-40x40@2x.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-40x40@3x.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-512@2x.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-60x60@2x.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-60x60@3x.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-76x76@1x.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-76x76@2x.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
dashboard/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
104
dashboard/src-tauri/src/main.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use std::process::{Child, Command};
|
||||
use std::sync::Mutex;
|
||||
use tauri::{AppHandle, Emitter, Listener, Manager, State};
|
||||
|
||||
struct BackendProcess(Mutex<Option<Child>>);
|
||||
|
||||
fn start_backend_process(app_handle: &AppHandle) -> Option<Child> {
|
||||
#[cfg(target_os = "macos")]
|
||||
let backend_path = "astrbot-backend.app/Contents/MacOS/main";
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let backend_path = "astrbot-backend.exe";
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
let backend_path = "astrbot-backend";
|
||||
|
||||
// 获取资源目录
|
||||
let resource_dir = match app_handle
|
||||
.path()
|
||||
.resource_dir()
|
||||
{
|
||||
Ok(dir) => dir,
|
||||
Err(e) => {
|
||||
eprintln!("Failed to get resource directory: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let full_backend_path = resource_dir.join(backend_path);
|
||||
|
||||
println!("Starting backend process at: {:?}", full_backend_path);
|
||||
|
||||
match Command::new(&full_backend_path).spawn() {
|
||||
Ok(child) => {
|
||||
println!(
|
||||
"Backend process started successfully with PID: {}",
|
||||
child.id()
|
||||
);
|
||||
Some(child)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Failed to start backend process: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn restart_backend(
|
||||
app_handle: AppHandle,
|
||||
backend_state: State<BackendProcess>,
|
||||
) -> Result<String, String> {
|
||||
let mut backend = backend_state.0.lock().unwrap();
|
||||
|
||||
// 停止现有进程
|
||||
if let Some(mut child) = backend.take() {
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
}
|
||||
|
||||
// 启动新进程
|
||||
*backend = start_backend_process(&app_handle);
|
||||
|
||||
if backend.is_some() {
|
||||
Ok("Backend restarted successfully".to_string())
|
||||
} else {
|
||||
Err("Failed to restart backend".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.setup(|app| {
|
||||
// 启动后端进程
|
||||
let backend_process = start_backend_process(app.handle());
|
||||
app.manage(BackendProcess(Mutex::new(backend_process)));
|
||||
Ok(())
|
||||
})
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.invoke_handler(tauri::generate_handler![restart_backend])
|
||||
.on_window_event(|window, event| {
|
||||
if let tauri::WindowEvent::CloseRequested { .. } = event {
|
||||
// 关闭窗口时清理后端进程
|
||||
if let Some(backend_state) = window.app_handle().try_state::<BackendProcess>() {
|
||||
let mut backend = backend_state.0.lock().unwrap();
|
||||
if let Some(mut child) = backend.take() {
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
run();
|
||||
}
|
||||
|
||||
53
dashboard/src-tauri/tauri.conf.json
Normal file
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "AstrBot",
|
||||
"version": "4.5.6",
|
||||
"identifier": "com.astrbot.app",
|
||||
"build": {
|
||||
"beforeDevCommand": "pnpm dev",
|
||||
"devUrl": "http://localhost:3000",
|
||||
"beforeBuildCommand": "pnpm build",
|
||||
"frontendDist": "../dist"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
"macOSPrivateApi": true,
|
||||
"windows": [
|
||||
{
|
||||
"title": "AstrBot",
|
||||
"label": "main",
|
||||
"url": "/",
|
||||
"width": 1400,
|
||||
"height": 900
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null,
|
||||
"assetProtocol": {
|
||||
"enable": true,
|
||||
"scope": [
|
||||
"$APPDATA/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": [
|
||||
"resources/*"
|
||||
]
|
||||
},
|
||||
"plugins": {
|
||||
"fs": {
|
||||
"requireLiteralLeadingDot": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import MarkdownIt from 'markdown-it';
|
||||
import { useI18n } from '@/i18n/composables';
|
||||
import { router } from '@/router';
|
||||
import { useTheme } from 'vuetify';
|
||||
import { isTauri } from '@/utils/tauri';
|
||||
|
||||
// 配置markdown-it,默认安全设置
|
||||
const md = new MarkdownIt({
|
||||
|
||||
71
dashboard/src/utils/tauri.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Tauri 环境检测工具
|
||||
* 用于区分 Web 端和桌面端环境
|
||||
*/
|
||||
|
||||
/**
|
||||
* 检测是否在 Tauri 环境中运行
|
||||
* @returns {boolean} 如果在 Tauri 环境中返回 true,否则返回 false
|
||||
*/
|
||||
export function isTauri(): boolean {
|
||||
return typeof window !== 'undefined' &&
|
||||
(window as any).__TAURI_INTERNALS__ !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测是否在 Web 环境中运行
|
||||
* @returns {boolean} 如果在 Web 环境中返回 true,否则返回 false
|
||||
*/
|
||||
export function isWeb(): boolean {
|
||||
return !isTauri();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Tauri API(仅在 Tauri 环境中可用)
|
||||
* @returns {any} Tauri API 对象或 null
|
||||
*/
|
||||
export function getTauriAPI(): any {
|
||||
if (isTauri()) {
|
||||
// Tauri 2.0 建议使用 @tauri-apps/api 包而不是全局对象
|
||||
return (window as any).__TAURI_INTERNALS__;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台特定的 API 调用包装器
|
||||
* 在 Web 环境中使用 HTTP API,在 Tauri 环境中可以使用本地 API
|
||||
*/
|
||||
export class PlatformAPI {
|
||||
/**
|
||||
* 根据平台选择合适的 API 端点
|
||||
* @param webEndpoint Web 端 API 地址
|
||||
* @param tauriEndpoint Tauri 端 API 地址(可选,默认使用 webEndpoint)
|
||||
*/
|
||||
static getEndpoint(webEndpoint: string, tauriEndpoint?: string): string {
|
||||
if (isTauri() && tauriEndpoint) {
|
||||
return tauriEndpoint;
|
||||
}
|
||||
return webEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取基础 URL
|
||||
* Web 端使用相对路径,Tauri 端使用完整的后端地址
|
||||
*/
|
||||
static getBaseURL(): string {
|
||||
if (isTauri()) {
|
||||
// Tauri 环境中,需要连接到本地运行的后端服务
|
||||
return 'http://127.0.0.1:6185';
|
||||
}
|
||||
// Web 环境中使用相对路径,由 Vite 代理处理
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
isTauri,
|
||||
isWeb,
|
||||
getTauriAPI,
|
||||
PlatformAPI
|
||||
};
|
||||
@@ -43,5 +43,8 @@ export default defineConfig({
|
||||
changeOrigin: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// Tauri 特定配置
|
||||
clearScreen: false,
|
||||
envPrefix: ['VITE_', 'TAURI_'],
|
||||
});
|
||||
|
||||