修复: OSS收藏打开+连接指示器根目录+字段映射+侧边栏重构+文件监听+首屏优化
This commit is contained in:
57
app.go
57
app.go
@@ -5,6 +5,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -16,6 +17,7 @@ import (
|
|||||||
|
|
||||||
"u-desk/internal/api"
|
"u-desk/internal/api"
|
||||||
"u-desk/internal/common"
|
"u-desk/internal/common"
|
||||||
|
"u-desk/internal/filewatch"
|
||||||
"u-desk/internal/filesystem"
|
"u-desk/internal/filesystem"
|
||||||
"u-desk/internal/hotkey"
|
"u-desk/internal/hotkey"
|
||||||
osssvc "u-desk/internal/ossdrv"
|
osssvc "u-desk/internal/ossdrv"
|
||||||
@@ -44,6 +46,7 @@ type App struct {
|
|||||||
sftpService *sftp.Service
|
sftpService *sftp.Service
|
||||||
ossService *osssvc.Service
|
ossService *osssvc.Service
|
||||||
profileSvc *service.ProfileService
|
profileSvc *service.ProfileService
|
||||||
|
fileWatcher *filewatch.Watcher
|
||||||
isAlwaysOnTop bool
|
isAlwaysOnTop bool
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
unregisterHotkey func()
|
unregisterHotkey func()
|
||||||
@@ -61,6 +64,11 @@ func NewApp() *App {
|
|||||||
// SetMainWindow 设置主窗口引用(由 main.go 在创建窗口后调用)
|
// SetMainWindow 设置主窗口引用(由 main.go 在创建窗口后调用)
|
||||||
func (a *App) SetMainWindow(w *application.WebviewWindow) {
|
func (a *App) SetMainWindow(w *application.WebviewWindow) {
|
||||||
a.mainWindow = w
|
a.mainWindow = w
|
||||||
|
a.fileWatcher = filewatch.NewWatcher(func(name string, data ...any) {
|
||||||
|
if a.mainWindow != nil {
|
||||||
|
a.mainWindow.EmitEvent(name, data...)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterGlobalHotkey 注册 Ctrl+Shift+B 全局热键(需在窗口创建后调用)
|
// RegisterGlobalHotkey 注册 Ctrl+Shift+B 全局热键(需在窗口创建后调用)
|
||||||
@@ -69,11 +77,10 @@ func (a *App) RegisterGlobalHotkey() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.mu.Lock()
|
a.mu.Lock()
|
||||||
|
defer a.mu.Unlock()
|
||||||
if a.unregisterHotkey != nil {
|
if a.unregisterHotkey != nil {
|
||||||
a.mu.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.mu.Unlock()
|
|
||||||
hwnd := uintptr(a.mainWindow.NativeWindow())
|
hwnd := uintptr(a.mainWindow.NativeWindow())
|
||||||
if hwnd == 0 {
|
if hwnd == 0 {
|
||||||
fmt.Println("[全局热键] HWND 为 0,注册跳过")
|
fmt.Println("[全局热键] HWND 为 0,注册跳过")
|
||||||
@@ -85,9 +92,7 @@ func (a *App) RegisterGlobalHotkey() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Println("[全局热键] Ctrl+Shift+B 已注册")
|
fmt.Println("[全局热键] Ctrl+Shift+B 已注册")
|
||||||
a.mu.Lock()
|
|
||||||
a.unregisterHotkey = func() { hotkey.Unregister(hwnd, id) }
|
a.unregisterHotkey = func() { hotkey.Unregister(hwnd, id) }
|
||||||
a.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleHotkey 处理全局热键回调:切换 BgmBar 显示/隐藏
|
// HandleHotkey 处理全局热键回调:切换 BgmBar 显示/隐藏
|
||||||
@@ -102,6 +107,9 @@ func (a *App) HandleHotkey() {
|
|||||||
func (a *App) ServiceStartup(ctx context.Context, _ application.ServiceOptions) error {
|
func (a *App) ServiceStartup(ctx context.Context, _ application.ServiceOptions) error {
|
||||||
a.ctx = ctx
|
a.ctx = ctx
|
||||||
|
|
||||||
|
// dev 模式打开 DevTools
|
||||||
|
openDevTools(a.mainWindow)
|
||||||
|
|
||||||
// 1. 核心初始化:SQLite(必须同步,很快)
|
// 1. 核心初始化:SQLite(必须同步,很快)
|
||||||
if _, err := storage.InitFast(); err != nil {
|
if _, err := storage.InitFast(); err != nil {
|
||||||
return fmt.Errorf("SQLite 初始化失败,应用无法启动: %w", err)
|
return fmt.Errorf("SQLite 初始化失败,应用无法启动: %w", err)
|
||||||
@@ -310,6 +318,21 @@ func (a *App) ReadFile(path string) (string, error) {
|
|||||||
return a.filesystem.ReadFile(path)
|
return a.filesystem.ReadFile(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WatchFile 开始监听指定文件的变化,变化时发送 file-changed 事件
|
||||||
|
func (a *App) WatchFile(path string) error {
|
||||||
|
if a.fileWatcher == nil {
|
||||||
|
return fmt.Errorf("文件监听器未初始化")
|
||||||
|
}
|
||||||
|
return a.fileWatcher.WatchFile(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnwatchFile 停止监听文件变化
|
||||||
|
func (a *App) UnwatchFile() {
|
||||||
|
if a.fileWatcher != nil {
|
||||||
|
a.fileWatcher.UnwatchFile()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WriteFileRequest 写入文件请求结构体
|
// WriteFileRequest 写入文件请求结构体
|
||||||
type WriteFileRequest struct {
|
type WriteFileRequest struct {
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
@@ -435,6 +458,7 @@ func (a *App) ResolveShortcut(lnkPath string) (map[string]interface{}, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// getWindowsSpecialFolder 从注册表读取 Windows 特殊文件夹的真实路径
|
// getWindowsSpecialFolder 从注册表读取 Windows 特殊文件夹的真实路径
|
||||||
func getWindowsSpecialFolder(guid string, fallbackName string) string {
|
func getWindowsSpecialFolder(guid string, fallbackName string) string {
|
||||||
key, err := registry.OpenKey(registry.CURRENT_USER,
|
key, err := registry.OpenKey(registry.CURRENT_USER,
|
||||||
@@ -1194,28 +1218,9 @@ func (a *App) LoadConnectionProfiles() ([]map[string]interface{}, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result := make([]map[string]interface{}, len(list))
|
var result []map[string]interface{}
|
||||||
for i, p := range list {
|
data, _ := json.Marshal(list)
|
||||||
result[i] = map[string]interface{}{
|
json.Unmarshal(data, &result)
|
||||||
"id": float64(p.ID),
|
|
||||||
"name": p.Name,
|
|
||||||
"host": p.Host,
|
|
||||||
"port": p.Port,
|
|
||||||
"username": p.Username,
|
|
||||||
"password": p.Password,
|
|
||||||
"keyPath": p.KeyPath,
|
|
||||||
"type": p.Type,
|
|
||||||
"provider": p.Provider,
|
|
||||||
"token": p.Token,
|
|
||||||
"accessKey": p.AccessKey,
|
|
||||||
"secretKey": p.SecretKey,
|
|
||||||
"bucket": p.Bucket,
|
|
||||||
"region": p.Region,
|
|
||||||
"endpoint": p.Endpoint,
|
|
||||||
"lastConnected": p.LastConnected,
|
|
||||||
"sortOrder": float64(p.SortOrder),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ tasks:
|
|||||||
- cmd: rm -f *.syso
|
- cmd: rm -f *.syso
|
||||||
platforms: [linux, darwin]
|
platforms: [linux, darwin]
|
||||||
vars:
|
vars:
|
||||||
BUILD_FLAGS: '{{if eq .DEV "true"}}{{if .EXTRA_TAGS}}-tags {{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production,devtools -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{end}}'
|
BUILD_FLAGS: '{{if eq .DEV "true"}}{{if .EXTRA_TAGS}}-tags {{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{end}}'
|
||||||
env:
|
env:
|
||||||
GOOS: windows
|
GOOS: windows
|
||||||
CGO_ENABLED: '{{.CGO_ENABLED | default "0"}}'
|
CGO_ENABLED: '{{.CGO_ENABLED | default "0"}}'
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
{
|
{
|
||||||
"fixed": {
|
"fixed": {
|
||||||
"file_version": "0.1.0"
|
"file_version": "0.4.0"
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
"0000": {
|
"0000": {
|
||||||
"ProductVersion": "0.1.0",
|
"ProductVersion": "0.4.0",
|
||||||
"CompanyName": "My Company",
|
"CompanyName": "1216.top",
|
||||||
"FileDescription": "A u-desk application",
|
"FileDescription": "U-Desk 桌面文件管理器",
|
||||||
"LegalCopyright": "© 2026, My Company",
|
"LegalCopyright": "© 2026, 1216.top",
|
||||||
"ProductName": "U-Desk",
|
"ProductName": "U-Desk",
|
||||||
"Comments": "This is a comment"
|
"Comments": "桌面文件管理器"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
53
cmd/dbread/main.go
Normal file
53
cmd/dbread/main.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/glebarez/sqlite"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
home, _ := os.UserHomeDir()
|
||||||
|
dbPath := filepath.Join(home, ".u-desk", "app.db")
|
||||||
|
|
||||||
|
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "open db:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有列
|
||||||
|
type Profile struct {
|
||||||
|
ID uint `gorm:"primaryKey"`
|
||||||
|
Name string `gorm:"column:name"`
|
||||||
|
Type string `gorm:"column:type"`
|
||||||
|
Host string `gorm:"column:host"`
|
||||||
|
Port int `gorm:"column:port"`
|
||||||
|
Username string `gorm:"column:username"`
|
||||||
|
Provider string `gorm:"column:provider"`
|
||||||
|
Token string `gorm:"column:token"`
|
||||||
|
AccessKey string `gorm:"column:access_key"`
|
||||||
|
SecretKey string `gorm:"column:secret_key"`
|
||||||
|
Bucket string `gorm:"column:bucket"`
|
||||||
|
Region string `gorm:"column:region"`
|
||||||
|
Endpoint string `gorm:"column:endpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var profiles []Profile
|
||||||
|
db.Table("connection_profiles").Find(&profiles)
|
||||||
|
|
||||||
|
// 脱敏 secret_key
|
||||||
|
for i := range profiles {
|
||||||
|
if len(profiles[i].SecretKey) > 8 {
|
||||||
|
profiles[i].SecretKey = profiles[i].SecretKey[:4] + "****"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b, _ := json.MarshalIndent(profiles, "", " ")
|
||||||
|
fmt.Println("=== Connection Profiles ===")
|
||||||
|
fmt.Println(string(b))
|
||||||
|
}
|
||||||
16
devtools.go
Normal file
16
devtools.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
//go:build !production
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v3/pkg/application"
|
||||||
|
)
|
||||||
|
|
||||||
|
func openDevTools(window *application.WebviewWindow) {
|
||||||
|
go func() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
window.OpenDevTools()
|
||||||
|
}()
|
||||||
|
}
|
||||||
7
devtools_prod.go
Normal file
7
devtools_prod.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build production
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/wailsapp/wails/v3/pkg/application"
|
||||||
|
|
||||||
|
func openDevTools(window *application.WebviewWindow) {}
|
||||||
23
docs/代码改进清单.md
Normal file
23
docs/代码改进清单.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# 代码改进清单
|
||||||
|
|
||||||
|
> 基于 Wails 开发文档 vs 项目现状审查,2026-05-16
|
||||||
|
|
||||||
|
## 已完成
|
||||||
|
|
||||||
|
- [x] 🔴① `main.go` 添加 `SingleInstance` 单实例锁(`top.1216.udesk`)
|
||||||
|
- [x] 🔴② `app.go:74-97` RegisterGlobalHotkey 竞态修复(合并为单一 `defer mu.Unlock()`)
|
||||||
|
- [x] 🔴③ `build/windows/info.json` 版本号 0.1.0→0.4.0,公司名→1216.top
|
||||||
|
- [x] 🟡⑤ 删除 `frontend/src/wailsjs/wailsjs/` v2 遗留绑定目录
|
||||||
|
- [x] 🟡⑥ `LoadConnectionProfiles` 手动 map 转换改用 `json.Marshal/Unmarshal`
|
||||||
|
- [x] 🟡⑨ `App.vue` onMounted 添加 `contextmenu` 事件拦截(禁用浏览器默认右键菜单)
|
||||||
|
- [x] 🟡⑫ `main.go` Run() 错误输出改用 `fmt.Fprintf(os.Stderr, ...)`
|
||||||
|
- [x] Sidebar 设置按钮 `···` 点击无响应修复:移除 `.stop` + Teleport 重构 + 增大点击区域
|
||||||
|
|
||||||
|
## 待处理
|
||||||
|
|
||||||
|
- [ ] ④ App 结构体拆分 — 1344 行,应拆为 FilesystemService / ProfileService / BgmService / UpdateService 等 v3 Service
|
||||||
|
- [ ] ⑦ `internal/api/pdf_api.go:371` SelectDirectory 改用 Wails 原生对话框 `application.Get().Dialog.OpenFile()`
|
||||||
|
- [ ] ⑧ `app.go:176-189` HWND 轮询改事件驱动 — v3 alpha 暂无对应 API,后续跟进
|
||||||
|
- [ ] ⑩ `app.go:29` Windows 专用导入 `golang.org/x/sys/windows/registry` 加构建标签拆到 `*_windows.go`
|
||||||
|
- [ ] ⑪ 全局结构化日志 — `fmt.Println` 替换为 `log/slog`,按优先级分批替换
|
||||||
|
- [ ] ⑬ `app.go:158` 更新检查 URL `https://c.1216.top/last-version.json` 移入配置
|
||||||
@@ -674,6 +674,13 @@ export function SftpWriteFile(req: $models.SftpWriteFileRequest): $CancellablePr
|
|||||||
return $Call.ByID(2401472593, req);
|
return $Call.ByID(2401472593, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UnwatchFile 停止监听文件变化
|
||||||
|
*/
|
||||||
|
export function UnwatchFile(): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(3006906623);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VerifyUpdateFile 验证更新文件哈希值
|
* VerifyUpdateFile 验证更新文件哈希值
|
||||||
*/
|
*/
|
||||||
@@ -683,6 +690,13 @@ export function VerifyUpdateFile(filePath: string, expectedHash: string, hashTyp
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WatchFile 开始监听指定文件的变化,变化时发送 file-changed 事件
|
||||||
|
*/
|
||||||
|
export function WatchFile(path: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(325055910, path);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WindowClose 关闭窗口
|
* WindowClose 关闭窗口
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -176,6 +176,9 @@ onMounted(() => {
|
|||||||
// 禁止 Ctrl+滚轮缩放
|
// 禁止 Ctrl+滚轮缩放
|
||||||
document.addEventListener('wheel', preventZoom, { passive: false })
|
document.addEventListener('wheel', preventZoom, { passive: false })
|
||||||
|
|
||||||
|
// 禁用浏览器默认右键菜单(桌面应用体验)
|
||||||
|
document.addEventListener('contextmenu', e => e.preventDefault())
|
||||||
|
|
||||||
// 延迟检查更新(启动后 3 秒,静默模式)
|
// 延迟检查更新(启动后 3 秒,静默模式)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
updateStore.checkForUpdates(true)
|
updateStore.checkForUpdates(true)
|
||||||
|
|||||||
@@ -91,11 +91,14 @@ class ConnectionManagerImpl {
|
|||||||
try {
|
try {
|
||||||
const list = await LoadConnectionProfiles()
|
const list = await LoadConnectionProfiles()
|
||||||
if (list && list.length > 0) {
|
if (list && list.length > 0) {
|
||||||
this._profiles = list.map((p: any) => ({
|
this._profiles = list.map((p: any) => {
|
||||||
...p,
|
const camel = snakeToCamel(p)
|
||||||
id: String(p.id),
|
return {
|
||||||
lastConnected: p.lastConnected || p.last_connected ? new Date(p.lastConnected || p.last_connected).getTime() : undefined,
|
...camel,
|
||||||
}))
|
id: String(p.id),
|
||||||
|
lastConnected: camel.lastConnected ? new Date(camel.lastConnected).getTime() : undefined,
|
||||||
|
}
|
||||||
|
})
|
||||||
const hasLocal = this._profiles.some(p => p.type === 'local')
|
const hasLocal = this._profiles.some(p => p.type === 'local')
|
||||||
if (!hasLocal) {
|
if (!hasLocal) {
|
||||||
this._profiles.unshift({
|
this._profiles.unshift({
|
||||||
@@ -105,17 +108,20 @@ class ConnectionManagerImpl {
|
|||||||
}
|
}
|
||||||
} catch { /* 首次使用 */ }
|
} catch { /* 首次使用 */ }
|
||||||
this.notifyChange()
|
this.notifyChange()
|
||||||
this._profiles.forEach(p => {
|
// 延迟执行系统信息采集和自动连接,不阻塞首屏渲染
|
||||||
if (p.type === 'local') { this.fetchSystemInfo(p.id).catch(() => {}) }
|
setTimeout(() => {
|
||||||
})
|
this._profiles.forEach(p => {
|
||||||
const autoConnect = localStorage.getItem('desk:autoConnect')
|
if (p.type === 'local') { this.fetchSystemInfo(p.id).catch(() => {}) }
|
||||||
if (autoConnect !== 'false') {
|
})
|
||||||
for (const p of this._profiles) {
|
const autoConnect = localStorage.getItem('desk:autoConnect')
|
||||||
if (p.type !== 'local') {
|
if (autoConnect !== 'false') {
|
||||||
this.buildAndPool(String(p.id), p).catch(() => {})
|
for (const p of this._profiles) {
|
||||||
|
if (p.type !== 'local') {
|
||||||
|
this.buildAndPool(String(p.id), p).catch(() => {})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 保存/更新单个 profile 到 SQLite */
|
/** 保存/更新单个 profile 到 SQLite */
|
||||||
@@ -269,9 +275,16 @@ class ConnectionManagerImpl {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新建连接并入池(成功后再设 activeId)
|
// 先设 activeId(确保回调读到正确的 activeProfile),失败时回退
|
||||||
await this.buildAndPool(profileId, profile)
|
const prevActiveId = this._activeId
|
||||||
this._activeId = profileId
|
this._activeId = profileId
|
||||||
|
try {
|
||||||
|
await this.buildAndPool(profileId, profile)
|
||||||
|
} catch (err) {
|
||||||
|
this._activeId = prevActiveId
|
||||||
|
this.notifyChange()
|
||||||
|
throw err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 断开指定 profile 并从池移除 */
|
/** 断开指定 profile 并从池移除 */
|
||||||
|
|||||||
@@ -108,3 +108,20 @@ export async function detectFileTypeByContent(path: string) {
|
|||||||
export async function getCommonPaths() {
|
export async function getCommonPaths() {
|
||||||
return t().getCommonPaths()
|
return t().getCommonPaths()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 文件监听(仅本地模式,直接调用 Wails 绑定)
|
||||||
|
export async function watchFile(path: string): Promise<void> {
|
||||||
|
if (connectionManager.isRemote()) return
|
||||||
|
try {
|
||||||
|
const { WatchFile } = await import('../wailsjs/v3-bindings/u-desk/app')
|
||||||
|
await WatchFile(path)
|
||||||
|
} catch { /* 忽略绑定未生成的场景 */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function unwatchFile(): Promise<void> {
|
||||||
|
if (connectionManager.isRemote()) return
|
||||||
|
try {
|
||||||
|
const { UnwatchFile } = await import('../wailsjs/v3-bindings/u-desk/app')
|
||||||
|
await UnwatchFile()
|
||||||
|
} catch { /* 忽略 */ }
|
||||||
|
}
|
||||||
|
|||||||
BIN
frontend/src/assets/logo.png
Normal file
BIN
frontend/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -75,7 +75,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, shallowRef, onMounted, onUnmounted, provide, watch } from 'vue'
|
import { ref, computed, shallowRef, onMounted, onUnmounted, provide, inject, watch, type Ref } from 'vue'
|
||||||
import { IconCloud, IconFolder, IconExclamationCircle } from '@arco-design/web-vue/es/icon'
|
import { IconCloud, IconFolder, IconExclamationCircle } from '@arco-design/web-vue/es/icon'
|
||||||
import { Message } from '@arco-design/web-vue'
|
import { Message } from '@arco-design/web-vue'
|
||||||
import { connectionManager } from '@/api/connection-manager'
|
import { connectionManager } from '@/api/connection-manager'
|
||||||
@@ -98,6 +98,15 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const { setTimeout: delay, clearTimeout: clearDelay } = useTimeout()
|
const { setTimeout: delay, clearTimeout: clearDelay } = useTimeout()
|
||||||
|
|
||||||
|
// 下拉互斥:面包屑 vs 连接指示器
|
||||||
|
const dropdownOwner = inject<Ref<'connection' | 'breadcrumb' | null>>('dropdownOwner', ref(null))
|
||||||
|
watch(dropdownOwner, (owner) => {
|
||||||
|
if (owner === 'breadcrumb') {
|
||||||
|
showDirDropdown.value = false
|
||||||
|
closeAllMenusFn()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// === 连接菜单(原有逻辑) ===
|
// === 连接菜单(原有逻辑) ===
|
||||||
const showMenu = ref(false)
|
const showMenu = ref(false)
|
||||||
const moreOpenId = ref<string | null>(null)
|
const moreOpenId = ref<string | null>(null)
|
||||||
@@ -144,8 +153,9 @@ const dirHoverTimer = ref<NodeJS.Timeout | null>(null)
|
|||||||
const dirCloseTimer = ref<NodeJS.Timeout | null>(null)
|
const dirCloseTimer = ref<NodeJS.Timeout | null>(null)
|
||||||
|
|
||||||
const rootPath = computed(() => {
|
const rootPath = computed(() => {
|
||||||
const path = props.filePath?.replace(/\\/g, '/') || ''
|
const active = connectionManager.activeProfile
|
||||||
if (/^[A-Za-z]:/.test(path)) return path.substring(0, 2) + '/'
|
if (!active || active.type === 'local') return '/'
|
||||||
|
// 远程连接:根目录始终是 /
|
||||||
return '/'
|
return '/'
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -159,11 +169,14 @@ const loadRootChildren = async () => {
|
|||||||
try {
|
try {
|
||||||
const files = await listDir(path)
|
const files = await listDir(path)
|
||||||
dirLastLoadedPath.value = path
|
dirLastLoadedPath.value = path
|
||||||
dirChildren.value = sortFileList(files.map(f => ({
|
// 只保留目录,限制最多200条
|
||||||
name: f.name,
|
dirChildren.value = sortFileList(
|
||||||
path: f.path,
|
files.filter(f => f.isDir).map(f => ({
|
||||||
isDir: f.isDir
|
name: f.name,
|
||||||
})))
|
path: f.path,
|
||||||
|
isDir: f.isDir
|
||||||
|
}))
|
||||||
|
).slice(0, 200)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[ConnectionIndicator] 加载根目录失败:', err)
|
console.error('[ConnectionIndicator] 加载根目录失败:', err)
|
||||||
dirError.value = '加载失败'
|
dirError.value = '加载失败'
|
||||||
@@ -177,6 +190,7 @@ const onDirHover = () => {
|
|||||||
if (dirCloseTimer.value) clearDelay(dirCloseTimer.value)
|
if (dirCloseTimer.value) clearDelay(dirCloseTimer.value)
|
||||||
|
|
||||||
dirHoverTimer.value = delay(() => {
|
dirHoverTimer.value = delay(() => {
|
||||||
|
dropdownOwner.value = 'connection'
|
||||||
showDirDropdown.value = true
|
showDirDropdown.value = true
|
||||||
showMenu.value = false
|
showMenu.value = false
|
||||||
closeAllMenusFn()
|
closeAllMenusFn()
|
||||||
@@ -293,7 +307,7 @@ watch(() => props.filePath, () => {
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
padding: 2px 10px;
|
padding: 4px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@@ -373,9 +373,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 多文件预览浮动 Tab 栏 -->
|
<!-- 空状态:无文件预览 -->
|
||||||
|
<div v-if="!config.currentFileName" class="empty-preview">
|
||||||
|
<div class="empty-preview-content">
|
||||||
|
<img src="@/assets/logo.png" alt="U-Desk" class="empty-preview-icon" />
|
||||||
|
<div class="empty-preview-title">U-Desk</div>
|
||||||
|
<div class="empty-preview-subtitle">文件管理器</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文件预览浮动 Tab 栏 -->
|
||||||
<div
|
<div
|
||||||
v-if="previewTabs.length > 1"
|
v-if="previewTabs.length > 0"
|
||||||
class="preview-tabs"
|
class="preview-tabs"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -1811,4 +1820,40 @@ body[arco-theme*='dark'] .markdown-preview-content :deep(.hljs-link) {
|
|||||||
background: var(--color-fill-3);
|
background: var(--color-fill-3);
|
||||||
color: var(--color-text-1);
|
color: var(--color-text-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.empty-preview {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-preview-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-preview-icon {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
object-fit: contain;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-preview-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-2);
|
||||||
|
letter-spacing: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-preview-subtitle {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-3);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch, provide, type Ref } from 'vue'
|
import { ref, computed, watch, provide, inject, type Ref } from 'vue'
|
||||||
import { IconRight, IconFolder } from '@arco-design/web-vue/es/icon'
|
import { IconRight, IconFolder } from '@arco-design/web-vue/es/icon'
|
||||||
import { listDir } from '@/api/system'
|
import { listDir } from '@/api/system'
|
||||||
import { sortFileList } from '@/utils/fileUtils'
|
import { sortFileList } from '@/utils/fileUtils'
|
||||||
@@ -63,6 +63,14 @@ import DropdownItem from './DropdownItem.vue'
|
|||||||
|
|
||||||
const { setTimeout: delay, clearTimeout } = useTimeout()
|
const { setTimeout: delay, clearTimeout } = useTimeout()
|
||||||
|
|
||||||
|
// 下拉互斥:面包屑 vs 连接指示器
|
||||||
|
const dropdownOwner = inject<Ref<'connection' | 'breadcrumb' | null>>('dropdownOwner', ref(null))
|
||||||
|
watch(dropdownOwner, (owner) => {
|
||||||
|
if (owner === 'connection') {
|
||||||
|
resetAndClose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const openMenus = ref<Map<number, string>>(new Map())
|
const openMenus = ref<Map<number, string>>(new Map())
|
||||||
|
|
||||||
const closeMenu = (level: number) => {
|
const closeMenu = (level: number) => {
|
||||||
@@ -122,22 +130,31 @@ const closeTimer = ref<NodeJS.Timeout | null>(null)
|
|||||||
const children = ref<Array<{ name: string; path: string; isDir: boolean }>>([])
|
const children = ref<Array<{ name: string; path: string; isDir: boolean }>>([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
const lastLoadedPath = ref('')
|
|
||||||
|
// 缓存:路径 → 子目录列表(只缓存目录,跨导航保留)
|
||||||
|
const dirCache = new Map<string, Array<{ name: string; path: string; isDir: boolean }>>()
|
||||||
|
|
||||||
const loadChildren = async (path: string) => {
|
const loadChildren = async (path: string) => {
|
||||||
if (path === lastLoadedPath.value) return
|
if (dirCache.has(path)) {
|
||||||
|
children.value = dirCache.get(path)!
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
loading.value = true
|
loading.value = true
|
||||||
error.value = ''
|
error.value = ''
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const files = await listDir(path)
|
const files = await listDir(path)
|
||||||
lastLoadedPath.value = path
|
// 只保留目录(面包屑只用于导航),限制最多200条
|
||||||
children.value = sortFileList(files.map(f => ({
|
const dirs = sortFileList(
|
||||||
name: f.name,
|
files.filter(f => f.isDir).map(f => ({
|
||||||
path: f.path,
|
name: f.name,
|
||||||
isDir: f.isDir
|
path: f.path,
|
||||||
})))
|
isDir: f.isDir
|
||||||
|
}))
|
||||||
|
).slice(0, 200)
|
||||||
|
dirCache.set(path, dirs)
|
||||||
|
children.value = dirs
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[Breadcrumb] 加载子目录失败:', err)
|
console.error('[Breadcrumb] 加载子目录失败:', err)
|
||||||
error.value = '加载失败'
|
error.value = '加载失败'
|
||||||
@@ -159,6 +176,7 @@ const onHover = (segment: PathSegment, index: number) => {
|
|||||||
if (closeTimer.value) clearTimeout(closeTimer.value)
|
if (closeTimer.value) clearTimeout(closeTimer.value)
|
||||||
|
|
||||||
hoverTimer.value = delay(() => {
|
hoverTimer.value = delay(() => {
|
||||||
|
dropdownOwner.value = 'breadcrumb'
|
||||||
activeIndex.value = index
|
activeIndex.value = index
|
||||||
loadChildren(segment.path)
|
loadChildren(segment.path)
|
||||||
}, 200)
|
}, 200)
|
||||||
@@ -194,7 +212,6 @@ const onOpenFile = (path: string) => {
|
|||||||
watch(() => props.path, () => {
|
watch(() => props.path, () => {
|
||||||
activeIndex.value = null
|
activeIndex.value = null
|
||||||
children.value = []
|
children.value = []
|
||||||
lastLoadedPath.value = ''
|
|
||||||
openMenus.value = new Map()
|
openMenus.value = new Map()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div v-show="config.visible" class="sidebar">
|
<div v-show="config.visible" class="sidebar">
|
||||||
<template v-for="section in sectionOrder" :key="section">
|
<template v-for="section in sectionOrder" :key="section">
|
||||||
<!-- 服务器区块 -->
|
<!-- 服务器区块 -->
|
||||||
<div v-if="section === 'server' && showServer" class="sidebar-section" :class="{ 'section-on-top': settingsOpen || moreOpenId }">
|
<div v-if="section === 'server' && showServer" class="sidebar-section">
|
||||||
<div class="section-header" @click="serverCollapsed = !serverCollapsed">
|
<div class="section-header" @click="serverCollapsed = !serverCollapsed">
|
||||||
<span class="section-title">🖥️ 服务器</span>
|
<span class="section-title">🖥️ 服务器</span>
|
||||||
<icon-down v-if="!serverCollapsed" class="section-toggle" />
|
<icon-down v-if="!serverCollapsed" class="section-toggle" />
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<span class="col-metric">磁盘</span>
|
<span class="col-metric">磁盘</span>
|
||||||
<span class="col-metric">CPU</span>
|
<span class="col-metric">CPU</span>
|
||||||
<span class="col-metric">内存</span>
|
<span class="col-metric">内存</span>
|
||||||
<span class="col-action settings-btn" @click.stop="settingsOpen = !settingsOpen" title="管理">···</span>
|
<span class="col-action settings-btn" @click="toggleSettings($event)" title="管理">···</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 表格行 -->
|
<!-- 表格行 -->
|
||||||
<div
|
<div
|
||||||
@@ -35,46 +35,17 @@
|
|||||||
v-if="p.type !== 'local'"
|
v-if="p.type !== 'local'"
|
||||||
class="col-action more-btn"
|
class="col-action more-btn"
|
||||||
title="更多操作"
|
title="更多操作"
|
||||||
@click.stop="toggleMore(p.id)"
|
@click.stop="toggleMore(p, $event)"
|
||||||
>···</span>
|
>···</span>
|
||||||
<span v-else class="col-action"></span>
|
<span v-else class="col-action"></span>
|
||||||
<!-- 更多操作子菜单 -->
|
|
||||||
<div v-if="moreOpenId === p.id" class="more-menu" @click.stop>
|
|
||||||
<div class="more-item" @click="handleEdit(p)">编辑</div>
|
|
||||||
<div class="more-item danger" @click="handleDelete(p)">删除</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="settingsOpen" class="settings-panel" @click.stop>
|
|
||||||
<div class="settings-item" @click="$emit('openConnectionDialog'); settingsOpen = false">
|
|
||||||
<icon-plus /> 添加服务器
|
|
||||||
</div>
|
|
||||||
<div class="settings-item" @click="toggleAutoConnect">
|
|
||||||
<icon-check-circle :style="{ opacity: autoConnect ? 1 : 0.3 }" />
|
|
||||||
启动时自动连接所有服务器
|
|
||||||
</div>
|
|
||||||
<div class="settings-item" @click="toggleAutoRefresh">
|
|
||||||
<icon-check-circle :style="{ opacity: autoRefresh ? 1 : 0.3 }" />
|
|
||||||
自动刷新系统信息 (15s)
|
|
||||||
</div>
|
|
||||||
<div class="settings-divider" />
|
|
||||||
<div class="settings-label">显示服务器</div>
|
|
||||||
<div
|
|
||||||
v-for="p in profiles"
|
|
||||||
:key="'vis-' + p.id"
|
|
||||||
class="settings-item"
|
|
||||||
@click="toggleServerVisibility(p.id)"
|
|
||||||
>
|
|
||||||
<icon-check-circle :style="{ opacity: !hiddenServerIds.includes(String(p.id)) ? 1 : 0.3 }" />
|
|
||||||
{{ p.name }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 收藏夹区块 -->
|
<!-- 收藏夹区块 -->
|
||||||
<div v-if="section === 'favorites' && showFavorites" class="sidebar-section fav-section">
|
<div v-if="section === 'favorites' && showFavorites" class="sidebar-section fav-section" :class="{ 'fav-collapsed': favCollapsed }">
|
||||||
<div class="section-header" @click="favCollapsed = !favCollapsed">
|
<div class="section-header" @click="favCollapsed = !favCollapsed">
|
||||||
<span class="section-title">⭐ 收藏夹</span>
|
<span class="section-title">⭐ 收藏夹</span>
|
||||||
<span class="section-count">共{{ config.favoriteFiles.length }}项</span>
|
<span class="section-count">共{{ config.favoriteFiles.length }}项</span>
|
||||||
@@ -159,6 +130,38 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
|
<!-- 更多操作子菜单 — Teleport 到 body -->
|
||||||
|
<Teleport to="body">
|
||||||
|
<div v-if="moreOpenId" class="sidebar-popup more-menu" :style="moreMenuStyle" @click.stop>
|
||||||
|
<div class="more-item" @click="handleEdit(moreProfile!)">编辑</div>
|
||||||
|
<div class="more-item danger" @click="handleDelete(moreProfile!)">删除</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="settingsOpen" class="sidebar-popup settings-panel" :style="settingsPanelStyle" @click.stop>
|
||||||
|
<div class="settings-item" @click="$emit('openConnectionDialog'); settingsOpen = false">
|
||||||
|
<icon-plus /> 添加服务器
|
||||||
|
</div>
|
||||||
|
<div class="settings-item" @click="toggleAutoConnect">
|
||||||
|
<icon-check-circle :style="{ opacity: autoConnect ? 1 : 0.3 }" />
|
||||||
|
启动时自动连接所有服务器
|
||||||
|
</div>
|
||||||
|
<div class="settings-item" @click="toggleAutoRefresh">
|
||||||
|
<icon-check-circle :style="{ opacity: autoRefresh ? 1 : 0.3 }" />
|
||||||
|
自动刷新系统信息 (15s)
|
||||||
|
</div>
|
||||||
|
<div class="settings-divider" />
|
||||||
|
<div class="settings-label">显示服务器</div>
|
||||||
|
<div
|
||||||
|
v-for="p in profiles"
|
||||||
|
:key="'vis-' + p.id"
|
||||||
|
class="settings-item"
|
||||||
|
@click="toggleServerVisibility(p.id)"
|
||||||
|
>
|
||||||
|
<icon-check-circle :style="{ opacity: !hiddenServerIds.includes(String(p.id)) ? 1 : 0.3 }" />
|
||||||
|
{{ p.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -182,8 +185,8 @@ const props = defineProps<Props>()
|
|||||||
|
|
||||||
// 折叠状态(组件内部,不污染父组件)
|
// 折叠状态(组件内部,不污染父组件)
|
||||||
const serverCollapsed = ref(false)
|
const serverCollapsed = ref(false)
|
||||||
const favCollapsed = ref(false)
|
const favCollapsed = ref(true)
|
||||||
const helpCollapsed = ref(false)
|
const helpCollapsed = ref(true)
|
||||||
|
|
||||||
// 侧边栏区块可见性(从配置读取)
|
// 侧边栏区块可见性(从配置读取)
|
||||||
const showServer = computed(() => configStore.appConfig.sidebarSections?.includes('server') ?? true)
|
const showServer = computed(() => configStore.appConfig.sidebarSections?.includes('server') ?? true)
|
||||||
@@ -192,13 +195,55 @@ const showHelp = computed(() => configStore.appConfig.sidebarSections?.includes(
|
|||||||
// 区块排序
|
// 区块排序
|
||||||
const sectionOrder = computed(() => configStore.appConfig.sidebarSections || ['server', 'favorites', 'help'])
|
const sectionOrder = computed(() => configStore.appConfig.sidebarSections || ['server', 'favorites', 'help'])
|
||||||
|
|
||||||
// 管理设置
|
// === 弹出面板定位(Teleport 到 body,fixed 定位) ===
|
||||||
const settingsOpen = ref(false)
|
const settingsOpen = ref(false)
|
||||||
|
const settingsPanelStyle = ref<Record<string, string>>({})
|
||||||
|
|
||||||
|
const moreOpenId = ref<string | null>(null)
|
||||||
|
const moreProfile = ref<{ id: string; name: string } | null>(null)
|
||||||
|
const moreMenuStyle = ref<Record<string, string>>({})
|
||||||
|
|
||||||
const autoConnect = ref(localStorage.getItem('desk:autoConnect') !== 'false')
|
const autoConnect = ref(localStorage.getItem('desk:autoConnect') !== 'false')
|
||||||
const autoRefresh = ref(localStorage.getItem('desk:autoRefresh') === 'true')
|
const autoRefresh = ref(localStorage.getItem('desk:autoRefresh') === 'true')
|
||||||
const hiddenServerIds = ref<string[]>(JSON.parse(localStorage.getItem('desk:hiddenServers') || '[]'))
|
const hiddenServerIds = ref<string[]>(JSON.parse(localStorage.getItem('desk:hiddenServers') || '[]'))
|
||||||
let refreshTimer: ReturnType<typeof setInterval> | null = null
|
let refreshTimer: ReturnType<typeof setInterval> | null = null
|
||||||
|
|
||||||
|
function calcPopupStyle(el: HTMLElement): Record<string, string> {
|
||||||
|
const rect = el.getBoundingClientRect()
|
||||||
|
return {
|
||||||
|
position: 'fixed',
|
||||||
|
top: `${rect.bottom + 2}px`,
|
||||||
|
right: `${window.innerWidth - rect.right}px`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSettings(e: MouseEvent) {
|
||||||
|
if (settingsOpen.value) {
|
||||||
|
settingsOpen.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
moreOpenId.value = null
|
||||||
|
const btn = (e.target as HTMLElement).closest<HTMLElement>('.settings-btn')
|
||||||
|
if (!btn) return
|
||||||
|
settingsPanelStyle.value = calcPopupStyle(btn)
|
||||||
|
settingsOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleMore(p: { id: string; name: string }, e: MouseEvent) {
|
||||||
|
if (moreOpenId.value === p.id) {
|
||||||
|
moreOpenId.value = null
|
||||||
|
moreProfile.value = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
settingsOpen.value = false
|
||||||
|
moreOpenId.value = p.id
|
||||||
|
moreProfile.value = p
|
||||||
|
const target = (e.target as HTMLElement).closest('.more-btn') as HTMLElement
|
||||||
|
if (target) {
|
||||||
|
moreMenuStyle.value = calcPopupStyle(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function toggleAutoConnect() {
|
function toggleAutoConnect() {
|
||||||
autoConnect.value = !autoConnect.value
|
autoConnect.value = !autoConnect.value
|
||||||
localStorage.setItem('desk:autoConnect', String(autoConnect.value))
|
localStorage.setItem('desk:autoConnect', String(autoConnect.value))
|
||||||
@@ -230,13 +275,14 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
onUnmounted(() => stopAutoRefresh())
|
onUnmounted(() => stopAutoRefresh())
|
||||||
|
|
||||||
// 点击外部关闭更多菜单
|
// 点击外部关闭弹出面板
|
||||||
function handleClickOutside(e: MouseEvent) {
|
function handleClickOutside(e: MouseEvent) {
|
||||||
const el = e.target as HTMLElement
|
const el = e.target as HTMLElement
|
||||||
if (!el.closest('.server-table-row')) {
|
if (!el.closest('.sidebar-popup') && !el.closest('.more-btn')) {
|
||||||
moreOpenId.value = null
|
moreOpenId.value = null
|
||||||
|
moreProfile.value = null
|
||||||
}
|
}
|
||||||
if (!el.closest('.settings-panel') && !el.closest('.settings-btn')) {
|
if (!el.closest('.sidebar-popup') && !el.closest('.settings-btn')) {
|
||||||
settingsOpen.value = false
|
settingsOpen.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,7 +292,6 @@ onUnmounted(() => document.removeEventListener('click', handleClickOutside))
|
|||||||
// 服务器 Profile 列表状态
|
// 服务器 Profile 列表状态
|
||||||
const profiles = shallowRef(connectionManager.profiles)
|
const profiles = shallowRef(connectionManager.profiles)
|
||||||
const activeId = shallowRef(connectionManager.activeProfile?.id ?? '')
|
const activeId = shallowRef(connectionManager.activeProfile?.id ?? '')
|
||||||
const moreOpenId = ref<string | null>(null)
|
|
||||||
const sysInfoMap = ref<Record<string, SystemInfo>>({})
|
const sysInfoMap = ref<Record<string, SystemInfo>>({})
|
||||||
|
|
||||||
const visibleProfiles = computed(() =>
|
const visibleProfiles = computed(() =>
|
||||||
@@ -289,6 +334,7 @@ const helpItems = [
|
|||||||
{ key: 'Ctrl+B', desc: '切换侧边栏' },
|
{ key: 'Ctrl+B', desc: '切换侧边栏' },
|
||||||
{ key: 'Ctrl+H', desc: '历史记录' },
|
{ key: 'Ctrl+H', desc: '历史记录' },
|
||||||
{ key: 'Ctrl+F', desc: '聚焦搜索' },
|
{ key: 'Ctrl+F', desc: '聚焦搜索' },
|
||||||
|
{ key: 'Ctrl+⇧+C~H', desc: '快速定位本机盘符' },
|
||||||
{ key: 'Click ⭐', desc: '收藏文件' },
|
{ key: 'Click ⭐', desc: '收藏文件' },
|
||||||
{ key: 'Drag', desc: '排序收藏' },
|
{ key: 'Drag', desc: '排序收藏' },
|
||||||
]
|
]
|
||||||
@@ -428,6 +474,7 @@ function stateText(profileId: string): string {
|
|||||||
|
|
||||||
async function handleSelect(p: { id: string; type: string }) {
|
async function handleSelect(p: { id: string; type: string }) {
|
||||||
moreOpenId.value = null
|
moreOpenId.value = null
|
||||||
|
moreProfile.value = null
|
||||||
if (p.id === activeId.value) return
|
if (p.id === activeId.value) return
|
||||||
try {
|
try {
|
||||||
await connectionManager.connect(p.id)
|
await connectionManager.connect(p.id)
|
||||||
@@ -436,12 +483,9 @@ async function handleSelect(p: { id: string; type: string }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleMore(id: string) {
|
|
||||||
moreOpenId.value = moreOpenId.value === id ? null : id
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEdit(p: { id: string }) {
|
function handleEdit(p: { id: string }) {
|
||||||
moreOpenId.value = null
|
moreOpenId.value = null
|
||||||
|
moreProfile.value = null
|
||||||
emit('openConnectionDialog', p.id)
|
emit('openConnectionDialog', p.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,6 +493,7 @@ function handleDelete(p: { id: string; name: string }) {
|
|||||||
if (!window.confirm(`确定删除「${p.name}」?`)) return
|
if (!window.confirm(`确定删除「${p.name}」?`)) return
|
||||||
connectionManager.removeProfile(p.id)
|
connectionManager.removeProfile(p.id)
|
||||||
moreOpenId.value = null
|
moreOpenId.value = null
|
||||||
|
moreProfile.value = null
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -476,11 +521,20 @@ function handleDelete(p: { id: string; name: string }) {
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 服务器区块不需要 max-height 限制 */
|
||||||
|
.sidebar-section:first-child > .section-content-wrap {
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* 收藏夹区块弹性填充剩余空间 */
|
/* 收藏夹区块弹性填充剩余空间 */
|
||||||
.fav-section {
|
.fav-section {
|
||||||
flex: 1;
|
flex: 1 1 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow: hidden;
|
}
|
||||||
|
|
||||||
|
/* 收藏夹折叠时收缩为 header 高度 */
|
||||||
|
.fav-section.fav-collapsed {
|
||||||
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 收藏夹 section-content-wrap 由 flex 控制高度 */
|
/* 收藏夹 section-content-wrap 由 flex 控制高度 */
|
||||||
@@ -501,11 +555,7 @@ function handleDelete(p: { id: string; name: string }) {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-section.section-on-top {
|
/* 帮助区块固定在底部 */
|
||||||
z-index: 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 帮助区块固定在底部,不被推出窗口 */
|
|
||||||
.sidebar-section:last-child {
|
.sidebar-section:last-child {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@@ -544,15 +594,15 @@ function handleDelete(p: { id: string; name: string }) {
|
|||||||
transition: transform 0.2s;
|
transition: transform 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 区块折叠容器 - grid 动画精确匹配内容高度 */
|
/* 区块折叠容器 */
|
||||||
.section-content-wrap {
|
.section-content-wrap {
|
||||||
display: grid;
|
overflow: hidden;
|
||||||
grid-template-rows: 1fr;
|
max-height: 500px;
|
||||||
transition: grid-template-rows 0.2s ease;
|
transition: max-height 0.25s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-content-wrap.collapsed {
|
.section-content-wrap.collapsed {
|
||||||
grid-template-rows: 0fr;
|
max-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-content-wrap > .section-content {
|
.section-content-wrap > .section-content {
|
||||||
@@ -603,7 +653,6 @@ function handleDelete(p: { id: string; name: string }) {
|
|||||||
background: var(--color-fill-1);
|
background: var(--color-fill-1);
|
||||||
border-radius: 0 0 6px 6px;
|
border-radius: 0 0 6px 6px;
|
||||||
border-left: 3px solid var(--color-primary-6);
|
border-left: 3px solid var(--color-primary-6);
|
||||||
overflow: visible;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表头 */
|
/* 表头 */
|
||||||
@@ -624,7 +673,6 @@ function handleDelete(p: { id: string; name: string }) {
|
|||||||
|
|
||||||
/* 表格行 */
|
/* 表格行 */
|
||||||
.server-table-row {
|
.server-table-row {
|
||||||
position: relative;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 4px 4px;
|
padding: 4px 4px;
|
||||||
@@ -695,76 +743,19 @@ function handleDelete(p: { id: string; name: string }) {
|
|||||||
}
|
}
|
||||||
.server-table-row:hover .more-btn { opacity: 1; }
|
.server-table-row:hover .more-btn { opacity: 1; }
|
||||||
|
|
||||||
/* 更多操作子菜单 */
|
|
||||||
.more-menu {
|
|
||||||
position: absolute;
|
|
||||||
right: 4px;
|
|
||||||
top: 100%;
|
|
||||||
min-width: 80px;
|
|
||||||
background: var(--color-bg-popup);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
z-index: 10;
|
|
||||||
padding: 2px 0;
|
|
||||||
}
|
|
||||||
.more-item {
|
|
||||||
padding: 5px 12px;
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.15s;
|
|
||||||
}
|
|
||||||
.more-item:hover { background: var(--color-fill-1); }
|
|
||||||
.more-item.danger { color: var(--color-danger-6); }
|
|
||||||
|
|
||||||
/* 设置按钮 */
|
/* 设置按钮 */
|
||||||
.settings-btn {
|
.settings-btn {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--color-text-3);
|
color: var(--color-text-3);
|
||||||
padding: 0 2px;
|
padding: 3px 4px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
transition: color 0.15s;
|
transition: color 0.15s;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
.settings-btn:hover { color: var(--color-primary-6); }
|
.settings-btn:hover { color: var(--color-primary-6); }
|
||||||
|
|
||||||
/* 设置面板 — 绝对定位浮在按钮下方 */
|
|
||||||
.settings-panel {
|
|
||||||
position: absolute;
|
|
||||||
right: 4px;
|
|
||||||
top: 50px;
|
|
||||||
z-index: 20;
|
|
||||||
min-width: 200px;
|
|
||||||
background: var(--color-bg-popup);
|
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
|
||||||
padding: 2px 0;
|
|
||||||
}
|
|
||||||
.settings-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 7px 12px;
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.12s;
|
|
||||||
color: var(--color-text-2);
|
|
||||||
}
|
|
||||||
.settings-item:hover { background: var(--color-fill-1); }
|
|
||||||
.settings-divider {
|
|
||||||
height: 1px;
|
|
||||||
background: var(--color-border-2);
|
|
||||||
margin: 4px 12px;
|
|
||||||
}
|
|
||||||
.settings-label {
|
|
||||||
padding: 4px 12px 2px;
|
|
||||||
font-size: 11px;
|
|
||||||
color: var(--color-text-3);
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 区块操作图标 */
|
/* 区块操作图标 */
|
||||||
.section-action {
|
.section-action {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@@ -894,3 +885,67 @@ function handleDelete(p: { id: string; name: string }) {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- 非 scoped:Teleport 到 body 的面板样式 -->
|
||||||
|
<style>
|
||||||
|
/* 弹出面板公共 */
|
||||||
|
.sidebar-popup {
|
||||||
|
z-index: 9999;
|
||||||
|
min-width: 80px;
|
||||||
|
background: var(--color-bg-popup) !important;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
||||||
|
padding: 2px 0;
|
||||||
|
color: var(--color-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-popup.more-menu {
|
||||||
|
min-width: 80px;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-popup.settings-panel {
|
||||||
|
min-width: 200px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-item {
|
||||||
|
padding: 5px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--color-text-2) !important;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
.more-item:hover { background: var(--color-fill-1); }
|
||||||
|
.more-item.danger { color: var(--color-danger-6) !important; }
|
||||||
|
.more-item svg { color: inherit !important; fill: currentColor; }
|
||||||
|
|
||||||
|
.settings-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 7px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.12s;
|
||||||
|
color: var(--color-text-2) !important;
|
||||||
|
}
|
||||||
|
.settings-item svg {
|
||||||
|
color: var(--color-text-2) !important;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
.settings-item:hover { background: var(--color-fill-1); }
|
||||||
|
.settings-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: var(--color-border-2);
|
||||||
|
margin: 4px 12px;
|
||||||
|
}
|
||||||
|
.settings-label {
|
||||||
|
padding: 4px 12px 2px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--color-text-3);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -137,7 +137,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { nextTick } from 'vue'
|
import { nextTick, provide, ref } from 'vue'
|
||||||
import { IconForward, IconHistory, IconRefresh, IconMenu, IconClose, IconRight, IconCopy, IconCheck } from '@arco-design/web-vue/es/icon'
|
import { IconForward, IconHistory, IconRefresh, IconMenu, IconClose, IconRight, IconCopy, IconCheck } from '@arco-design/web-vue/es/icon'
|
||||||
import type { ToolbarConfig } from '@/types/file-system'
|
import type { ToolbarConfig } from '@/types/file-system'
|
||||||
import PathBreadcrumb from './PathBreadcrumb.vue'
|
import PathBreadcrumb from './PathBreadcrumb.vue'
|
||||||
@@ -145,6 +145,10 @@ import { useClipboardCopy } from '../composables/useClipboardCopy'
|
|||||||
import ConnectionIndicator from './ConnectionIndicator.vue'
|
import ConnectionIndicator from './ConnectionIndicator.vue'
|
||||||
import ConnectionDialog from './ConnectionDialog.vue'
|
import ConnectionDialog from './ConnectionDialog.vue'
|
||||||
|
|
||||||
|
// 面包屑/连接指示器下拉互斥:任一方打开时关闭另一方
|
||||||
|
const dropdownOwner = ref<'connection' | 'breadcrumb' | null>(null)
|
||||||
|
provide('dropdownOwner', dropdownOwner)
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
interface Props {
|
interface Props {
|
||||||
config: ToolbarConfig
|
config: ToolbarConfig
|
||||||
|
|||||||
@@ -60,7 +60,10 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 分隔条 -->
|
<!-- 分隔条 -->
|
||||||
<div class="resizer" @mousedown="handleHorizontalResize"></div>
|
<div class="resizer" @mousedown="handleResizeWithOverlay"></div>
|
||||||
|
|
||||||
|
<!-- 拖拽遮罩:防止 iframe 捕获鼠标事件 -->
|
||||||
|
<div v-if="isResizing" class="resize-overlay"></div>
|
||||||
|
|
||||||
<!-- 文件编辑器面板(始终显示,无选中文件时为空白预览区) -->
|
<!-- 文件编辑器面板(始终显示,无选中文件时为空白预览区) -->
|
||||||
<FileEditorPanel
|
<FileEditorPanel
|
||||||
@@ -116,7 +119,8 @@
|
|||||||
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
||||||
import { getPathSeparator } from '@/utils/fileUtils'
|
import { getPathSeparator } from '@/utils/fileUtils'
|
||||||
import { Message, Modal } from '@arco-design/web-vue'
|
import { Message, Modal } from '@arco-design/web-vue'
|
||||||
import { marked, renderMermaidDiagrams, rerenderMermaidDiagrams, setCurrentFileDir, setFileServerBase } from '@/utils/markedExtensions'
|
import { On, Off } from '@wailsio/events'
|
||||||
|
import { renderMarkdown, parseMarkdown, isMarkedReady, preloadMarked, renderMermaidDiagrams, rerenderMermaidDiagrams, setCurrentFileDir, setFileServerBase } from '@/utils/markedExtensions'
|
||||||
import { useThemeStore } from '@/stores/theme'
|
import { useThemeStore } from '@/stores/theme'
|
||||||
|
|
||||||
// 导入子组件
|
// 导入子组件
|
||||||
@@ -138,7 +142,7 @@ import { useMultiPreview, type PreviewTab, isDirty } from './composables/useMult
|
|||||||
// 导入工具函数
|
// 导入工具函数
|
||||||
import { getFileName, sortFileList } from '@/utils/fileUtils'
|
import { getFileName, sortFileList } from '@/utils/fileUtils'
|
||||||
import { isImageFile, isVideoFile, isAudioFile, isPdfFile, isHtmlFile, isMarkdownFile, isExcelFile, isWordFile, isCsvFile } from '@/utils/fileTypeHelpers'
|
import { isImageFile, isVideoFile, isAudioFile, isPdfFile, isHtmlFile, isMarkdownFile, isExcelFile, isWordFile, isCsvFile } from '@/utils/fileTypeHelpers'
|
||||||
import { listDir, saveBase64File } from '@/api/system'
|
import { listDir, saveBase64File, watchFile, unwatchFile } from '@/api/system'
|
||||||
import { connectionManager } from '@/api/connection-manager'
|
import { connectionManager } from '@/api/connection-manager'
|
||||||
import { STORAGE_KEYS, DEFAULTS, UI_TEXT, VALIDATION_RULES, FILE_EXTENSIONS, FILE_SIZE_THRESHOLDS } from '@/utils/constants'
|
import { STORAGE_KEYS, DEFAULTS, UI_TEXT, VALIDATION_RULES, FILE_EXTENSIONS, FILE_SIZE_THRESHOLDS } from '@/utils/constants'
|
||||||
import { createResizeHandler } from '@/utils/resize'
|
import { createResizeHandler } from '@/utils/resize'
|
||||||
@@ -356,36 +360,52 @@ const fileListPanelConfig = computed(() => ({
|
|||||||
editingFileName: editingFileName.value
|
editingFileName: editingFileName.value
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// 计算渲染内容
|
// Markdown 渲染状态(异步加载 marked 后触发重渲染)
|
||||||
|
const markdownRendered = ref('')
|
||||||
|
const setupMarkdownContext = () => {
|
||||||
|
const fullPath = selectedFileItem.value?.path || ''
|
||||||
|
const dir = fullPath ? fullPath.replace(/[/\\][^/\\]+$/, '') : (filePath.value || '')
|
||||||
|
setCurrentFileDir(dir)
|
||||||
|
const isRemote = connectionManager.isRemote()
|
||||||
|
const base = resolveFileServerBase()
|
||||||
|
setFileServerBase(isRemote ? base : base + '/localfs')
|
||||||
|
}
|
||||||
|
|
||||||
const computeRendered = computed(() => {
|
const computeRendered = computed(() => {
|
||||||
const currentFileName = selectedFileItem.value?.name || ''
|
const currentFileName = selectedFileItem.value?.name || ''
|
||||||
if (isHtmlFile(currentFileName)) {
|
if (isHtmlFile(currentFileName)) {
|
||||||
return fileContent.value || ''
|
return fileContent.value || ''
|
||||||
} else if (isMarkdownFile(currentFileName)) {
|
} else if (isMarkdownFile(currentFileName)) {
|
||||||
// 使用配置好的 marked 渲染 Markdown(支持 mermaid + 图片相对路径转换)
|
if (isMarkedReady()) {
|
||||||
try {
|
try {
|
||||||
const content = fileContent.value || ''
|
setupMarkdownContext()
|
||||||
|
return parseMarkdown(fileContent.value || '')
|
||||||
// 设置图片路径转换所需的上下文(renderer.image 钩子中读取)
|
} catch (error) {
|
||||||
// dir: 当前 md 文件所在目录(从文件完整路径中去掉文件名)
|
console.error('Markdown 解析失败:', error)
|
||||||
const fullPath = selectedFileItem.value?.path || ''
|
return fileContent.value || ''
|
||||||
const dir = fullPath ? fullPath.replace(/[/\\][^/\\]+$/, '') : (filePath.value || '')
|
}
|
||||||
setCurrentFileDir(dir)
|
|
||||||
|
|
||||||
// 设置文件服务器 Base URL
|
|
||||||
const isRemote = connectionManager.isRemote()
|
|
||||||
const base = resolveFileServerBase()
|
|
||||||
setFileServerBase(isRemote ? base : base + '/localfs')
|
|
||||||
|
|
||||||
return marked.parse(content) as string
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Markdown 解析失败:', error)
|
|
||||||
return fileContent.value || ''
|
|
||||||
}
|
}
|
||||||
|
// marked 未就绪时返回上次渲染结果或原文
|
||||||
|
preloadMarked()
|
||||||
|
return markdownRendered.value || fileContent.value || ''
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// marked 加载完成后异步渲染并缓存
|
||||||
|
watch([() => selectedFileItem.value?.name, fileContent], async () => {
|
||||||
|
const currentFileName = selectedFileItem.value?.name || ''
|
||||||
|
if (!isMarkdownFile(currentFileName)) return
|
||||||
|
if (isMarkedReady()) return // 同步 computed 已处理
|
||||||
|
try {
|
||||||
|
setupMarkdownContext()
|
||||||
|
const html = await renderMarkdown(fileContent.value || '')
|
||||||
|
markdownRendered.value = html
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Markdown 异步渲染失败:', e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 文件编辑器面板配置
|
// 文件编辑器面板配置
|
||||||
const fileEditorPanelConfig = computed(() => {
|
const fileEditorPanelConfig = computed(() => {
|
||||||
const currentFileName = selectedFileItem.value?.name || ''
|
const currentFileName = selectedFileItem.value?.name || ''
|
||||||
@@ -440,17 +460,38 @@ const handleRefresh = async () => {
|
|||||||
await loadDirectory(filePath.value)
|
await loadDirectory(filePath.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 文件变化事件处理:自动刷新预览(有未保存修改时跳过)
|
||||||
|
const handleFileChanged = async (event: any) => {
|
||||||
|
// Wails v3 On 回调参数是 WailsEvent 对象,路径在 event.data
|
||||||
|
const changedPath = event?.data ?? ''
|
||||||
|
if (!changedPath || !selectedFileItem.value) return
|
||||||
|
|
||||||
|
// 标准化路径比较
|
||||||
|
const normalize = (p: string) => p.replace(/\\/g, '/').toLowerCase().replace(/\/+$/, '')
|
||||||
|
if (normalize(changedPath) !== normalize(selectedFileItem.value.path)) return
|
||||||
|
|
||||||
|
// 有未保存修改时不覆盖用户编辑
|
||||||
|
if (originalContent.value !== undefined && fileContent.value !== originalContent.value) return
|
||||||
|
|
||||||
|
await loadFileContent(changedPath)
|
||||||
|
Message.success('文件已更新')
|
||||||
|
}
|
||||||
|
|
||||||
// 程序化切换 profile 时抑制自动导航(如打开收藏/tab切换)
|
// 程序化切换 profile 时抑制自动导航(如打开收藏/tab切换)
|
||||||
let _suppressAutoNav = false
|
let _suppressAutoNav = false
|
||||||
|
let _lastActiveId = connectionManager.activeProfile?.id
|
||||||
|
|
||||||
// 连接切换后重置路径并刷新文件列表
|
// 连接切换后重置路径并刷新文件列表(仅在活跃连接实际变化时触发)
|
||||||
connectionManager.onStateChange(async (state) => {
|
connectionManager.onStateChange(async (state) => {
|
||||||
if (state === 'connected' && !_suppressAutoNav) {
|
const currentId = connectionManager.activeProfile?.id
|
||||||
await loadCommonPaths()
|
if (state !== 'connected') return
|
||||||
const targetPath = connectionManager.isRemote() ? '/' : 'C:/'
|
if (currentId === _lastActiveId) return
|
||||||
filePath.value = targetPath
|
_lastActiveId = currentId
|
||||||
await loadDirectory(targetPath)
|
if (_suppressAutoNav) return
|
||||||
}
|
await loadCommonPaths()
|
||||||
|
const targetPath = connectionManager.isRemote() ? '/' : 'C:/'
|
||||||
|
filePath.value = targetPath
|
||||||
|
await loadDirectory(targetPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleSearchKeywordUpdate = (keyword: string) => {
|
const handleSearchKeywordUpdate = (keyword: string) => {
|
||||||
@@ -580,6 +621,8 @@ const handleOpenFavorite = async (file: FavoriteFile) => {
|
|||||||
await loadCommonPaths()
|
await loadCommonPaths()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('切换连接失败:', e)
|
console.error('切换连接失败:', e)
|
||||||
|
Message.error(`无法连接: ${e instanceof Error ? e.message : String(e)}`)
|
||||||
|
return
|
||||||
} finally {
|
} finally {
|
||||||
_suppressAutoNav = false
|
_suppressAutoNav = false
|
||||||
}
|
}
|
||||||
@@ -600,7 +643,6 @@ const handleOpenFavorite = async (file: FavoriteFile) => {
|
|||||||
await connectionManager.connect(remoteProfile.id)
|
await connectionManager.connect(remoteProfile.id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// disconnect() 也会触发 onStateChange,需要 suppress
|
|
||||||
connectionManager.disconnect()
|
connectionManager.disconnect()
|
||||||
}
|
}
|
||||||
await loadCommonPaths()
|
await loadCommonPaths()
|
||||||
@@ -613,7 +655,6 @@ const handleOpenFavorite = async (file: FavoriteFile) => {
|
|||||||
if (file.isDir) {
|
if (file.isDir) {
|
||||||
await navigate(file.path)
|
await navigate(file.path)
|
||||||
} else {
|
} else {
|
||||||
// 先导航到父目录,再选中文件
|
|
||||||
const parentPath = file.path.substring(0, Math.max(file.path.lastIndexOf('/'), file.path.lastIndexOf('\\')))
|
const parentPath = file.path.substring(0, Math.max(file.path.lastIndexOf('/'), file.path.lastIndexOf('\\')))
|
||||||
if (parentPath && parentPath !== filePath.value) {
|
if (parentPath && parentPath !== filePath.value) {
|
||||||
await navigate(parentPath)
|
await navigate(parentPath)
|
||||||
@@ -1222,8 +1263,11 @@ const selectFile = async (path: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadFileContent = async (path: string) => {
|
const loadFileContent = async (path: string) => {
|
||||||
|
// 切换文件时先取消前一个文件的监听
|
||||||
|
unwatchFile().catch(() => {})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
updatePreviewUrl(path)
|
await updatePreviewUrl(path)
|
||||||
|
|
||||||
const fileName = getFileName(path)
|
const fileName = getFileName(path)
|
||||||
const fileItem = selectedFileItem.value
|
const fileItem = selectedFileItem.value
|
||||||
@@ -1278,6 +1322,7 @@ const loadFileContent = async (path: string) => {
|
|||||||
|
|
||||||
// 其他情况:加载为文本文件
|
// 其他情况:加载为文本文件
|
||||||
await loadFile(path)
|
await loadFile(path)
|
||||||
|
watchFile(path).catch(() => {})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Message.error(`读取文件失败: ${error}`)
|
Message.error(`读取文件失败: ${error}`)
|
||||||
}
|
}
|
||||||
@@ -1396,6 +1441,8 @@ const extractZipTextAndRead = async (zipPath: string, filePath: string): Promise
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isResizing = ref(false)
|
||||||
|
|
||||||
const handleHorizontalResize = createResizeHandler(
|
const handleHorizontalResize = createResizeHandler(
|
||||||
() => workspaceRef.value,
|
() => workspaceRef.value,
|
||||||
() => panelWidth.value.left,
|
() => panelWidth.value.left,
|
||||||
@@ -1406,14 +1453,29 @@ const handleHorizontalResize = createResizeHandler(
|
|||||||
onResize: (percent) => {
|
onResize: (percent) => {
|
||||||
panelWidth.value = { left: percent, right: 100 - percent }
|
panelWidth.value = { left: percent, right: 100 - percent }
|
||||||
},
|
},
|
||||||
onResizeEnd: () => savePanelWidth(panelWidth.value),
|
onResizeEnd: () => {
|
||||||
|
isResizing.value = false
|
||||||
|
savePanelWidth(panelWidth.value)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// mousedown 时即激活遮罩,防止 iframe 捕获鼠标
|
||||||
|
const handleResizeWithOverlay = (e: MouseEvent) => {
|
||||||
|
isResizing.value = true
|
||||||
|
handleHorizontalResize(e)
|
||||||
|
}
|
||||||
|
|
||||||
// ========== 生命周期 ==========
|
// ========== 生命周期 ==========
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 加载系统路径(阻塞,确保快捷入口就绪)
|
// 1. 先注册全局事件,不阻塞渲染
|
||||||
|
window.addEventListener('keydown', handleKeyDown)
|
||||||
|
window.addEventListener('click', hideContextMenu)
|
||||||
|
window.addEventListener('paste', handlePaste)
|
||||||
|
On('file-changed', handleFileChanged)
|
||||||
|
|
||||||
|
// 2. 加载系统路径
|
||||||
await loadCommonPaths()
|
await loadCommonPaths()
|
||||||
|
|
||||||
// SFTP 连接是异步的,未就绪时跳过初始加载,由 onStateChange('connected') 触发
|
// SFTP 连接是异步的,未就绪时跳过初始加载,由 onStateChange('connected') 触发
|
||||||
@@ -1422,10 +1484,9 @@ onMounted(async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化加载:远程模式强制用根路径,避免 localStorage 残留 Windows 路径
|
// 3. 加载目录列表
|
||||||
const startPath = connectionManager.isRemote() ? '/'
|
const startPath = connectionManager.isRemote() ? '/'
|
||||||
: (commonPaths.value.length > 0 ? commonPaths.value[0].path : 'C:/')
|
: (commonPaths.value.length > 0 ? commonPaths.value[0].path : 'C:/')
|
||||||
// 本地模式下只恢复 Windows 路径,跳过 Linux/OSS 路径残留
|
|
||||||
const isLocalPath = filePath.value && /^[A-Za-z]:/.test(filePath.value)
|
const isLocalPath = filePath.value && /^[A-Za-z]:/.test(filePath.value)
|
||||||
if (isLocalPath && !connectionManager.isRemote()) {
|
if (isLocalPath && !connectionManager.isRemote()) {
|
||||||
await loadDirectory(filePath.value)
|
await loadDirectory(filePath.value)
|
||||||
@@ -1434,10 +1495,16 @@ onMounted(async () => {
|
|||||||
await loadDirectory(startPath)
|
await loadDirectory(startPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 恢复多文件预览会话
|
// 4. 会话恢复延迟到下一帧,先让界面渲染出来
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
restoreSession()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 会话恢复(不阻塞首屏)
|
||||||
|
async function restoreSession() {
|
||||||
const session = multiPreview.restoreSession()
|
const session = multiPreview.restoreSession()
|
||||||
if (session.paths.length > 0) {
|
if (session.paths.length > 0) {
|
||||||
// 找到激活 tab 的 profileId,先切换到该连接
|
|
||||||
const activeId = session.activePath
|
const activeId = session.activePath
|
||||||
? session.profileMap.get(session.activePath.replace(/\\/g, '/').toLowerCase())
|
? session.profileMap.get(session.activePath.replace(/\\/g, '/').toLowerCase())
|
||||||
: undefined
|
: undefined
|
||||||
@@ -1456,7 +1523,6 @@ onMounted(async () => {
|
|||||||
multiPreview.applyUnsavedContent(tab, session.unsavedMap)
|
multiPreview.applyUnsavedContent(tab, session.unsavedMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载激活 tab 的内容
|
|
||||||
const active = multiPreview.activeTab.value
|
const active = multiPreview.activeTab.value
|
||||||
if (active) {
|
if (active) {
|
||||||
selectedFileItem.value = active.fileItem
|
selectedFileItem.value = active.fileItem
|
||||||
@@ -1468,7 +1534,6 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 无会话记录,回退到旧逻辑:恢复上次打开的单个文件
|
|
||||||
const lastFile = localStorage.getItem(STORAGE_KEYS.FILESYSTEM.LAST_OPENED_FILE)
|
const lastFile = localStorage.getItem(STORAGE_KEYS.FILESYSTEM.LAST_OPENED_FILE)
|
||||||
if (lastFile) {
|
if (lastFile) {
|
||||||
const normalized = lastFile.replace(/\\/g, '/').replace(/\/+$/, '')
|
const normalized = lastFile.replace(/\\/g, '/').replace(/\/+$/, '')
|
||||||
@@ -1482,19 +1547,14 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 添加键盘快捷键
|
|
||||||
window.addEventListener('keydown', handleKeyDown)
|
|
||||||
window.addEventListener('click', hideContextMenu)
|
|
||||||
|
|
||||||
// 添加粘贴事件监听(剪贴板图片)
|
|
||||||
window.addEventListener('paste', handlePaste)
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('keydown', handleKeyDown)
|
window.removeEventListener('keydown', handleKeyDown)
|
||||||
window.removeEventListener('click', hideContextMenu)
|
window.removeEventListener('click', hideContextMenu)
|
||||||
window.removeEventListener('paste', handlePaste)
|
window.removeEventListener('paste', handlePaste)
|
||||||
|
Off('file-changed')
|
||||||
|
unwatchFile()
|
||||||
// 应用关闭时立即持久化当前会话
|
// 应用关闭时立即持久化当前会话
|
||||||
cacheCurrentTabState()
|
cacheCurrentTabState()
|
||||||
multiPreview.persistSession()
|
multiPreview.persistSession()
|
||||||
@@ -1528,7 +1588,7 @@ const handleKeyDown = async (event: KeyboardEvent) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ctrl+Shift+C/D/E/F/G/H 快速打开对应盘符
|
// Ctrl+Shift+C/D/E/F/G/H 快速定位到本机对应盘符
|
||||||
if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
|
if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
|
||||||
const driveLetter = event.key.toUpperCase()
|
const driveLetter = event.key.toUpperCase()
|
||||||
if (['C', 'D', 'E', 'F', 'G', 'H'].includes(driveLetter)) {
|
if (['C', 'D', 'E', 'F', 'G', 'H'].includes(driveLetter)) {
|
||||||
@@ -1536,6 +1596,16 @@ const handleKeyDown = async (event: KeyboardEvent) => {
|
|||||||
const drivePath = `${driveLetter}:\\`
|
const drivePath = `${driveLetter}:\\`
|
||||||
isNavigating.value = true
|
isNavigating.value = true
|
||||||
try {
|
try {
|
||||||
|
// 如果当前在远程连接,先切回本地
|
||||||
|
if (connectionManager.isRemote()) {
|
||||||
|
_suppressAutoNav = true
|
||||||
|
try {
|
||||||
|
await connectionManager.connect('local-default')
|
||||||
|
} finally {
|
||||||
|
_suppressAutoNav = false
|
||||||
|
}
|
||||||
|
await loadCommonPaths()
|
||||||
|
}
|
||||||
await navigate(drivePath)
|
await navigate(drivePath)
|
||||||
} finally {
|
} finally {
|
||||||
isNavigating.value = false
|
isNavigating.value = false
|
||||||
@@ -1772,6 +1842,7 @@ watch(() => themeStore.isDark, async () => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resizer {
|
.resizer {
|
||||||
@@ -1785,4 +1856,11 @@ watch(() => themeStore.isDark, async () => {
|
|||||||
.resizer:hover {
|
.resizer:hover {
|
||||||
background: var(--color-primary-light-1);
|
background: var(--color-primary-light-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.resize-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 100;
|
||||||
|
cursor: col-resize;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { marked } from '@/utils/markedExtensions'
|
import { parseMarkdown, renderMarkdown, isMarkedReady, preloadMarked } from '@/utils/markedExtensions'
|
||||||
|
|
||||||
function sanitizeHtml(html) {
|
function sanitizeHtml(html) {
|
||||||
return html
|
return html
|
||||||
@@ -27,9 +27,27 @@ export default {
|
|||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return { rendered: '' }
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
renderedMarkdown() {
|
renderedMarkdown() {
|
||||||
return sanitizeHtml(marked(this.content))
|
if (isMarkedReady()) {
|
||||||
|
return sanitizeHtml(parseMarkdown(this.content))
|
||||||
|
}
|
||||||
|
preloadMarked()
|
||||||
|
return sanitizeHtml(this.rendered || this.content)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
content: {
|
||||||
|
immediate: true,
|
||||||
|
async handler(val) {
|
||||||
|
if (!isMarkedReady()) {
|
||||||
|
const html = await renderMarkdown(val)
|
||||||
|
this.rendered = sanitizeHtml(html)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import { computed, watch, onMounted, onUnmounted, h, nextTick } from 'vue'
|
import { computed, watch, onMounted, onUnmounted, h, nextTick } from 'vue'
|
||||||
import { Modal, Message, Progress } from '@arco-design/web-vue'
|
import { Modal, Message, Progress } from '@arco-design/web-vue'
|
||||||
import { useUpdateStore } from '../stores/update'
|
import { useUpdateStore } from '../stores/update'
|
||||||
import { marked } from '../utils/markedExtensions'
|
import { parseMarkdown, isMarkedReady, preloadMarked } from '../utils/markedExtensions'
|
||||||
import { sanitizeHtml } from '@/utils/fileUtils'
|
import { sanitizeHtml } from '@/utils/fileUtils'
|
||||||
import { DownloadUpdate } from '../wailsjs/v3-bindings/u-desk/app'
|
import { DownloadUpdate } from '../wailsjs/v3-bindings/u-desk/app'
|
||||||
import { On, Off } from '@wailsio/events'
|
import { On, Off } from '@wailsio/events'
|
||||||
@@ -80,7 +80,7 @@ const showUpdateModal = () => {
|
|||||||
|
|
||||||
// 更新日志
|
// 更新日志
|
||||||
if (changelog.value) {
|
if (changelog.value) {
|
||||||
const changelogHtml = (() => { try { return sanitizeHtml(String(marked.parse(changelog.value))) } catch { return changelog.value } })()
|
const changelogHtml = (() => { try { if (isMarkedReady()) return sanitizeHtml(String(parseMarkdown(changelog.value))); preloadMarked(); return sanitizeHtml(changelog.value) } catch { return changelog.value } })()
|
||||||
elements.push(
|
elements.push(
|
||||||
h('div', { style: { marginBottom: '8px' } }, [
|
h('div', { style: { marginBottom: '8px' } }, [
|
||||||
h('div', { style: { fontSize: '12px', color: 'var(--color-text-2)', marginBottom: '4px' } }, '更新内容:'),
|
h('div', { style: { fontSize: '12px', color: 'var(--color-text-2)', marginBottom: '4px' } }, '更新内容:'),
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ import { Message, Modal } from '@arco-design/web-vue'
|
|||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { IconHistory } from '@arco-design/web-vue/es/icon'
|
import { IconHistory } from '@arco-design/web-vue/es/icon'
|
||||||
import { useUpdateStore } from '../stores/update'
|
import { useUpdateStore } from '../stores/update'
|
||||||
import { marked } from '../utils/markedExtensions'
|
import { parseMarkdown, isMarkedReady, preloadMarked } from '../utils/markedExtensions'
|
||||||
import { sanitizeHtml } from '@/utils/fileUtils'
|
import { sanitizeHtml } from '@/utils/fileUtils'
|
||||||
import { GetCurrentVersion, GetUpdateConfig, InstallUpdate } from '../wailsjs/v3-bindings/u-desk/app'
|
import { GetCurrentVersion, GetUpdateConfig, InstallUpdate } from '../wailsjs/v3-bindings/u-desk/app'
|
||||||
import { On, Off } from '@wailsio/events'
|
import { On, Off } from '@wailsio/events'
|
||||||
@@ -141,7 +141,7 @@ const downloadedFile = ref(null)
|
|||||||
/** 渲染 changelog(Markdown → HTML) */
|
/** 渲染 changelog(Markdown → HTML) */
|
||||||
function renderChangelog(text: string): string {
|
function renderChangelog(text: string): string {
|
||||||
if (!text) return ''
|
if (!text) return ''
|
||||||
try { return sanitizeHtml(marked.parse(text) as string) } catch { return text }
|
try { if (isMarkedReady()) return sanitizeHtml(parseMarkdown(text)); preloadMarked(); return sanitizeHtml(text) } catch { return text }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载当前版本
|
// 加载当前版本
|
||||||
|
|||||||
@@ -1,20 +1,176 @@
|
|||||||
import { marked } from 'marked'
|
|
||||||
import hljs from 'highlight.js'
|
|
||||||
import 'highlight.js/lib/common'
|
|
||||||
// 按需导入 common 包不包含的语言
|
|
||||||
import 'highlight.js/lib/languages/powershell'
|
|
||||||
import 'highlight.js/lib/languages/dos'
|
|
||||||
import 'highlight.js/lib/languages/autohotkey'
|
|
||||||
import 'highlight.js/lib/languages/latex'
|
|
||||||
import 'highlight.js/lib/languages/dockerfile'
|
|
||||||
import 'highlight.js/lib/languages/cmake'
|
|
||||||
import 'highlight.js/lib/languages/scala'
|
|
||||||
import 'highlight.js/lib/languages/dart'
|
|
||||||
import { getHljsLanguage } from './languageMap'
|
import { getHljsLanguage } from './languageMap'
|
||||||
|
|
||||||
let mermaidInstance: typeof import('mermaid').default | null = null
|
let mermaidInstance: typeof import('mermaid').default | null = null
|
||||||
let mermaidTheme: string | null = null
|
let mermaidTheme: string | null = null
|
||||||
|
|
||||||
|
// 懒加载 marked + hljs,首次调用时才初始化
|
||||||
|
let _marked: typeof import('marked').marked | null = null
|
||||||
|
let _initPromise: Promise<typeof import('marked').marked> | null = null
|
||||||
|
|
||||||
|
async function ensureMarked(): Promise<typeof import('marked').marked> {
|
||||||
|
if (_marked) return _marked
|
||||||
|
if (_initPromise) return _initPromise
|
||||||
|
|
||||||
|
_initPromise = (async () => {
|
||||||
|
const [markedModule, hljs, ...extras] = await Promise.all([
|
||||||
|
import('marked'),
|
||||||
|
import('highlight.js'),
|
||||||
|
import('highlight.js/lib/languages/powershell'),
|
||||||
|
import('highlight.js/lib/languages/dos'),
|
||||||
|
import('highlight.js/lib/languages/autohotkey'),
|
||||||
|
import('highlight.js/lib/languages/latex'),
|
||||||
|
import('highlight.js/lib/languages/dockerfile'),
|
||||||
|
import('highlight.js/lib/languages/cmake'),
|
||||||
|
import('highlight.js/lib/languages/scala'),
|
||||||
|
import('highlight.js/lib/languages/dart'),
|
||||||
|
])
|
||||||
|
// 注册额外语言到 hljs
|
||||||
|
const langNames = ['powershell', 'dos', 'autohotkey', 'latex', 'dockerfile', 'cmake', 'scala', 'dart']
|
||||||
|
extras.forEach((mod, i) => {
|
||||||
|
hljs.default.registerLanguage(langNames[i], (mod as any).default)
|
||||||
|
})
|
||||||
|
|
||||||
|
const marked = markedModule.marked
|
||||||
|
const renderer = new marked.Renderer()
|
||||||
|
|
||||||
|
renderer.code = function(token: any) {
|
||||||
|
if (token.lang === 'mermaid') {
|
||||||
|
return `<pre class="mermaid">${token.text}</pre>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const lang = getHljsLanguage(token.lang)
|
||||||
|
|
||||||
|
let highlighted: string
|
||||||
|
try {
|
||||||
|
highlighted = hljs.default.highlight(token.text, { language: lang }).value
|
||||||
|
} catch {
|
||||||
|
highlighted = token.text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||||
|
}
|
||||||
|
return `<pre><code class="hljs language-${lang}" data-theme="auto">${highlighted}</code></pre>`
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.heading = function(token: any) {
|
||||||
|
const raw = token.raw || ''
|
||||||
|
const depth = token.depth || 1
|
||||||
|
const text = token.text || ''
|
||||||
|
|
||||||
|
const id = raw
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^一-龥a-z0-9\s-]/g, '')
|
||||||
|
.trim()
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.replace(/-+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '') || `heading-${Math.random().toString(36).slice(2, 11)}`
|
||||||
|
|
||||||
|
return `<h${depth} id="${id}" class="heading">
|
||||||
|
${text}<a href="#${id}" class="heading-anchor" aria-hidden="true" title="跳转到此标题">#</a>
|
||||||
|
</h${depth}>`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片/链接渲染器
|
||||||
|
renderer.image = createImageRenderer()
|
||||||
|
renderer.link = createLinkRenderer()
|
||||||
|
|
||||||
|
marked.use({ renderer, breaks: true, gfm: true, async: false })
|
||||||
|
|
||||||
|
_marked = marked
|
||||||
|
return marked
|
||||||
|
})()
|
||||||
|
|
||||||
|
return _initPromise
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 图片相对路径转换支持 ==========
|
||||||
|
let _currentFileDir: string = ''
|
||||||
|
let _fileServerBase: string = 'http://localhost:2652/localfs'
|
||||||
|
|
||||||
|
export function setCurrentFileDir(dir: string): void {
|
||||||
|
_currentFileDir = dir
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCurrentFileDir(): string {
|
||||||
|
return _currentFileDir
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setFileServerBase(base: string): void {
|
||||||
|
_fileServerBase = base
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveImageUrl(src: string, fileServerBase: string): string {
|
||||||
|
if (!src) return src
|
||||||
|
if (/^(?:[a-zA-Z]:[/\\]|\/(?:[^/]|$)|https?:|ftp:|data:|#)/i.test(src)) return src
|
||||||
|
|
||||||
|
const dir = _currentFileDir || '/'
|
||||||
|
const sep = dir.includes('\\') ? '\\' : '/'
|
||||||
|
let resolved = normalizeRelativePath(dir, src, sep)
|
||||||
|
|
||||||
|
const encoded = encodeURIComponent(resolved).replace(/%2F/gi, '/').replace(/%5C/gi, '\\')
|
||||||
|
return `${fileServerBase}/${encoded}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeRelativePath(base: string, relative: string, sep: string): string {
|
||||||
|
let baseNormalized = base.replace(/[\\/]+$/, '')
|
||||||
|
if (!baseNormalized) baseNormalized = sep === '/' ? '/' : 'C:\\'
|
||||||
|
|
||||||
|
const baseParts = baseNormalized.split(sep).filter(Boolean)
|
||||||
|
const relParts = relative.split(/[\\/]/).filter(Boolean)
|
||||||
|
|
||||||
|
for (const part of relParts) {
|
||||||
|
if (part === '..') {
|
||||||
|
baseParts.pop()
|
||||||
|
} else if (part !== '.') {
|
||||||
|
baseParts.push(part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^[a-zA-Z]:$/i.test(baseNormalized.split(sep)[0] || '')) {
|
||||||
|
return baseParts.join(sep)
|
||||||
|
}
|
||||||
|
return sep + baseParts.join(sep)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isLocalFileLink = (href: string): boolean => {
|
||||||
|
if (!href) return false
|
||||||
|
if (/^(https?|ftp|mailto|tel|data):/i.test(href)) return false
|
||||||
|
if (href.startsWith('#')) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function createImageRenderer() {
|
||||||
|
return function(token: any) {
|
||||||
|
const src = token.href || ''
|
||||||
|
const title = token.title || ''
|
||||||
|
const alt = token.text || ''
|
||||||
|
const titleAttr = title ? ` title="${title}"` : ''
|
||||||
|
|
||||||
|
if (_currentFileDir && !/^(?:[a-zA-Z]:[/\\]|\/(?:[^/]|$)|https?:|ftp:|data:|#)/i.test(src)) {
|
||||||
|
const resolvedSrc = resolveImageUrl(src, _fileServerBase)
|
||||||
|
return `<img src="${resolvedSrc}" alt="${alt}"${titleAttr}>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<img src="${src}" alt="${alt}"${titleAttr}>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createLinkRenderer() {
|
||||||
|
return function(this: any, token: any) {
|
||||||
|
const href = token.href || ''
|
||||||
|
const text = this.parser.parseInline(token.tokens) || token.text || ''
|
||||||
|
const title = token.title || ''
|
||||||
|
const titleAttr = title ? ` title="${title}"` : ''
|
||||||
|
|
||||||
|
if (href.startsWith('#')) {
|
||||||
|
return `<a href="${href}${titleAttr}">${text}</a>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLocalFileLink(href)) {
|
||||||
|
return `<a href="javascript:void(0)" data-local-link="${href}" class="local-file-link"${titleAttr}>${text}</a>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<a href="${href}" target="_blank" rel="noopener noreferrer"${titleAttr}>${text}</a>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 检测当前是否为暗色主题
|
// 检测当前是否为暗色主题
|
||||||
function isDarkTheme(): boolean {
|
function isDarkTheme(): boolean {
|
||||||
if (typeof document === 'undefined') return false
|
if (typeof document === 'undefined') return false
|
||||||
@@ -64,167 +220,31 @@ async function loadMermaid() {
|
|||||||
return mermaidInstance
|
return mermaidInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderer = new marked.Renderer()
|
/** 同步渲染 Markdown(需先调用 ensureMarked 初始化) */
|
||||||
|
export async function renderMarkdown(content: string): Promise<string> {
|
||||||
renderer.code = function(token: any) {
|
const marked = await ensureMarked()
|
||||||
if (token.lang === 'mermaid') {
|
return marked.parse(content) as string
|
||||||
return `<pre class="mermaid">${token.text}</pre>`
|
|
||||||
}
|
|
||||||
|
|
||||||
const lang = getHljsLanguage(token.lang)
|
|
||||||
|
|
||||||
let highlighted: string
|
|
||||||
try {
|
|
||||||
highlighted = hljs.highlight(token.text, { language: lang }).value
|
|
||||||
} catch {
|
|
||||||
highlighted = token.text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
||||||
}
|
|
||||||
return `<pre><code class="hljs language-${lang}" data-theme="auto">${highlighted}</code></pre>`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.heading = function(token: any) {
|
/** 检查 marked 是否已初始化(同步渲染用) */
|
||||||
const raw = token.raw || ''
|
export function isMarkedReady(): boolean {
|
||||||
const depth = token.depth || 1
|
return _marked !== null
|
||||||
const text = token.text || ''
|
|
||||||
|
|
||||||
const id = raw
|
|
||||||
.toLowerCase()
|
|
||||||
.replace(/[^\u4e00-\u9fa5a-z0-9\s-]/g, '')
|
|
||||||
.trim()
|
|
||||||
.replace(/\s+/g, '-')
|
|
||||||
.replace(/-+/g, '-')
|
|
||||||
.replace(/^-+|-+$/g, '') || `heading-${Math.random().toString(36).slice(2, 11)}`
|
|
||||||
|
|
||||||
return `<h${depth} id="${id}" class="heading">
|
|
||||||
${text}<a href="#${id}" class="heading-anchor" aria-hidden="true" title="跳转到此标题">#</a>
|
|
||||||
</h${depth}>`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 图片相对路径转换支持 ==========
|
/** 同步渲染(仅当已初始化时可用) */
|
||||||
// 当前 Markdown 文件所在目录(由调用方在渲染前设置)
|
export function parseMarkdown(content: string): string {
|
||||||
let _currentFileDir: string = ''
|
if (!_marked) return ''
|
||||||
// 文件服务器 Base URL(由调用方在渲染前设置)
|
return _marked.parse(content) as string
|
||||||
let _fileServerBase: string = 'http://localhost:2652/localfs'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置当前 Markdown 文件所在目录(用于图片相对路径→文件服务器 URL 转换)
|
|
||||||
* @param dir 文件所在目录的绝对路径,如 "D:/docs" 或 "/"(根目录)
|
|
||||||
*/
|
|
||||||
export function setCurrentFileDir(dir: string): void {
|
|
||||||
_currentFileDir = dir
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取当前设置的文件目录 */
|
/** 触发懒加载(可在空闲时调用) */
|
||||||
export function getCurrentFileDir(): string {
|
export function preloadMarked(): void {
|
||||||
return _currentFileDir
|
ensureMarked().catch(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置文件服务器 Base URL(用于图片相对路径转换)
|
|
||||||
* @param base 完整的 base URL 前缀,如 "http://localhost:2652/localfs" 或 "https://host:port/api/v1/proxy/localfs"
|
|
||||||
*/
|
|
||||||
export function setFileServerBase(base: string): void {
|
|
||||||
_fileServerBase = base
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将相对路径图片 src 解析为文件服务器 URL
|
|
||||||
* - 绝对路径(Windows: D:/...、Unix: /usr/...)、网络URL、data URI → 不转换
|
|
||||||
* - 相对路径 → 基于当前文件目录解析为绝对路径,再编码为文件服务器 URL
|
|
||||||
*/
|
|
||||||
function resolveImageUrl(src: string, fileServerBase: string): string {
|
|
||||||
if (!src) return src
|
|
||||||
// 不转换:绝对路径(Windows 盘符)、网络协议、锚点、data URI
|
|
||||||
if (/^(?:[a-zA-Z]:[/\\]|\/(?:[^/]|$)|https?:|ftp:|data:|#)/i.test(src)) return src
|
|
||||||
|
|
||||||
// 解析相对路径(处理 ../ 和 ./)
|
|
||||||
const dir = _currentFileDir || '/'
|
|
||||||
const sep = dir.includes('\\') ? '\\' : '/'
|
|
||||||
let resolved = normalizeRelativePath(dir, src, sep)
|
|
||||||
|
|
||||||
// 编码路径(保留 / 分隔符)
|
|
||||||
const encoded = encodeURIComponent(resolved).replace(/%2F/gi, '/').replace(/%5C/gi, '\\')
|
|
||||||
return `${fileServerBase}/${encoded}`
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 规范化相对路径,处理 .. 和 . 段
|
|
||||||
*/
|
|
||||||
function normalizeRelativePath(base: string, relative: string, sep: string): string {
|
|
||||||
// 确保基础路径不以分隔符结尾
|
|
||||||
let baseNormalized = base.replace(/[\\/]+$/, '')
|
|
||||||
if (!baseNormalized) baseNormalized = sep === '/' ? '/' : 'C:\\'
|
|
||||||
|
|
||||||
const baseParts = baseNormalized.split(sep).filter(Boolean)
|
|
||||||
const relParts = relative.split(/[\\/]/).filter(Boolean)
|
|
||||||
|
|
||||||
for (const part of relParts) {
|
|
||||||
if (part === '..') {
|
|
||||||
baseParts.pop() // 向上一级
|
|
||||||
} else if (part !== '.') {
|
|
||||||
baseParts.push(part)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重建路径:Windows 绝对路径保留盘符前缀
|
|
||||||
if (/^[a-zA-Z]:$/i.test(baseNormalized.split(sep)[0] || '')) {
|
|
||||||
return baseParts.join(sep)
|
|
||||||
}
|
|
||||||
// Unix 风格:以 / 开头
|
|
||||||
return sep + baseParts.join(sep)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否为本地文件链接(相对路径或本地绝对路径)
|
|
||||||
const isLocalFileLink = (href: string): boolean => {
|
|
||||||
if (!href) return false
|
|
||||||
if (/^(https?|ftp|mailto|tel|data):/i.test(href)) return false
|
|
||||||
if (href.startsWith('#')) return false
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义图片渲染器 - 转换相对路径为文件服务器 URL
|
|
||||||
renderer.image = function(token: any) {
|
|
||||||
const src = token.href || ''
|
|
||||||
const title = token.title || ''
|
|
||||||
const alt = token.text || ''
|
|
||||||
const titleAttr = title ? ` title="${title}"` : ''
|
|
||||||
|
|
||||||
// 判断是否需要转换(仅处理相对路径,且当前目录已设置)
|
|
||||||
if (_currentFileDir && !/^(?:[a-zA-Z]:[/\\]|\/(?:[^/]|$)|https?:|ftp:|data:|#)/i.test(src)) {
|
|
||||||
const resolvedSrc = resolveImageUrl(src, _fileServerBase)
|
|
||||||
return `<img src="${resolvedSrc}" alt="${alt}"${titleAttr}>`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认渲染(绝对路径 / 网络 URL / data URI / 未设置目录时原样输出)
|
|
||||||
return `<img src="${src}" alt="${alt}"${titleAttr}>`
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义链接渲染器 - 支持本地文件链接
|
|
||||||
renderer.link = function(token: any) {
|
|
||||||
const href = token.href || ''
|
|
||||||
const text = this.parser.parseInline(token.tokens) || token.text || ''
|
|
||||||
const title = token.title || ''
|
|
||||||
const titleAttr = title ? ` title="${title}"` : ''
|
|
||||||
|
|
||||||
if (href.startsWith('#')) {
|
|
||||||
return `<a href="${href}${titleAttr}">${text}</a>`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLocalFileLink(href)) {
|
|
||||||
return `<a href="javascript:void(0)" data-local-link="${href}" class="local-file-link"${titleAttr}>${text}</a>`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `<a href="${href}" target="_blank" rel="noopener noreferrer"${titleAttr}>${text}</a>`
|
|
||||||
}
|
|
||||||
|
|
||||||
marked.use({ renderer, breaks: true, gfm: true, async: false })
|
|
||||||
|
|
||||||
export { marked }
|
|
||||||
|
|
||||||
export async function renderMermaidDiagrams() {
|
export async function renderMermaidDiagrams() {
|
||||||
const mermaid = await loadMermaid()
|
const mermaid = await loadMermaid()
|
||||||
if (mermaid) {
|
if (mermaid) {
|
||||||
// 渲染前保存原始源码(textContent 在 SVG 渲染后会变成 CSS 垃圾)
|
|
||||||
document.querySelectorAll('.mermaid:not([data-mermaid-src])').forEach(pre => {
|
document.querySelectorAll('.mermaid:not([data-mermaid-src])').forEach(pre => {
|
||||||
;(pre as HTMLElement).setAttribute('data-mermaid-src', pre.textContent || '')
|
;(pre as HTMLElement).setAttribute('data-mermaid-src', pre.textContent || '')
|
||||||
})
|
})
|
||||||
@@ -232,9 +252,7 @@ export async function renderMermaidDiagrams() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 清除已渲染内容并重新渲染(用于主题切换后刷新) */
|
|
||||||
export async function rerenderMermaidDiagrams(container?: HTMLElement | null) {
|
export async function rerenderMermaidDiagrams(container?: HTMLElement | null) {
|
||||||
// 强制重新加载(清除缓存,让下次 loadMermaid 重新初始化新主题)
|
|
||||||
mermaidInstance = null
|
mermaidInstance = null
|
||||||
mermaidTheme = null
|
mermaidTheme = null
|
||||||
|
|
||||||
@@ -242,7 +260,6 @@ export async function rerenderMermaidDiagrams(container?: HTMLElement | null) {
|
|||||||
target.querySelectorAll('.mermaid').forEach(pre => {
|
target.querySelectorAll('.mermaid').forEach(pre => {
|
||||||
const el = pre as HTMLElement
|
const el = pre as HTMLElement
|
||||||
if (el.getAttribute('data-processed')) {
|
if (el.getAttribute('data-processed')) {
|
||||||
// 从保存的原始源码恢复,而非 textContent(SVG 的 textContent 是 CSS 垃圾)
|
|
||||||
el.innerHTML = el.getAttribute('data-mermaid-src') || ''
|
el.innerHTML = el.getAttribute('data-mermaid-src') || ''
|
||||||
el.removeAttribute('data-processed')
|
el.removeAttribute('data-processed')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,52 +52,52 @@ export function createResizeHandler(
|
|||||||
const container = getContainer()
|
const container = getContainer()
|
||||||
if (!container) return
|
if (!container) return
|
||||||
|
|
||||||
// 初始值:pixels 模式下从 getter 获取像素值,percent 模式下获取百分比
|
// mousedown 时缓存容器尺寸,避免每帧 getBoundingClientRect 强制回流
|
||||||
|
const cachedRect = container.getBoundingClientRect()
|
||||||
|
const containerSize = isHorizontal ? cachedRect.width : cachedRect.height
|
||||||
|
|
||||||
|
// 初始值
|
||||||
let startValue = getInitialPercentage()
|
let startValue = getInitialPercentage()
|
||||||
if (usePixels) {
|
if (usePixels) {
|
||||||
// pixels 模式:将初始像素值转换为百分比用于拖拽计算
|
|
||||||
const rect = container.getBoundingClientRect()
|
|
||||||
const containerSize = isHorizontal ? rect.width : rect.height
|
|
||||||
if (containerSize > 0) {
|
if (containerSize > 0) {
|
||||||
startValue = (startValue / containerSize) * 100
|
startValue = (startValue / containerSize) * 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const minPercentFromPixels = containerSize > 0 ? (minPixels / containerSize) * 100 : 0
|
||||||
|
|
||||||
|
let rafId = 0
|
||||||
|
|
||||||
const handleMouseMove = (moveEvent: MouseEvent) => {
|
const handleMouseMove = (moveEvent: MouseEvent) => {
|
||||||
const currentRect = container.getBoundingClientRect()
|
cancelAnimationFrame(rafId)
|
||||||
let rawValue: number
|
rafId = requestAnimationFrame(() => {
|
||||||
|
let rawValue: number
|
||||||
|
|
||||||
if (isHorizontal) {
|
if (isHorizontal) {
|
||||||
rawValue = ((moveEvent.clientX - currentRect.left) / currentRect.width) * 100
|
rawValue = ((moveEvent.clientX - cachedRect.left) / containerSize) * 100
|
||||||
} else {
|
} else {
|
||||||
rawValue = ((moveEvent.clientY - currentRect.top) / currentRect.height) * 100
|
rawValue = ((moveEvent.clientY - cachedRect.top) / containerSize) * 100
|
||||||
}
|
}
|
||||||
|
|
||||||
const minPercentFromPixels = (minPixels / (isHorizontal ? currentRect.width : currentRect.height)) * 100
|
const clamped = Math.max(
|
||||||
const clamped = Math.max(
|
Math.max(minPercent, minPercentFromPixels),
|
||||||
Math.max(minPercent, minPercentFromPixels),
|
Math.min(maxPercent, rawValue)
|
||||||
Math.min(maxPercent, rawValue)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if (usePixels) {
|
if (usePixels) {
|
||||||
// 转回像素值传给回调
|
onResize?.(Math.round((clamped / 100) * containerSize))
|
||||||
const containerSize = isHorizontal ? currentRect.width : currentRect.height
|
} else {
|
||||||
onResize?.(Math.round((clamped / 100) * containerSize))
|
onResize?.(clamped)
|
||||||
} else {
|
}
|
||||||
onResize?.(clamped)
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMouseUp = () => {
|
const handleMouseUp = () => {
|
||||||
|
cancelAnimationFrame(rafId)
|
||||||
document.removeEventListener('mousemove', handleMouseMove)
|
document.removeEventListener('mousemove', handleMouseMove)
|
||||||
document.removeEventListener('mouseup', handleMouseUp)
|
document.removeEventListener('mouseup', handleMouseUp)
|
||||||
document.body.classList.remove('resizing')
|
document.body.classList.remove('resizing')
|
||||||
if (usePixels) {
|
onResizeEnd?.(getInitialPercentage())
|
||||||
// pixels 模式:传回当前像素值(onResize 已更新,读 getter 获取最新值)
|
|
||||||
onResizeEnd?.(getInitialPercentage())
|
|
||||||
} else {
|
|
||||||
onResizeEnd?.(getInitialPercentage())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('mousemove', handleMouseMove)
|
document.addEventListener('mousemove', handleMouseMove)
|
||||||
|
|||||||
@@ -21,12 +21,28 @@ import * as filesystem$0 from "./internal/filesystem/models.js";
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as $models from "./models.js";
|
import * as $models from "./models.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BgmGetPlaylist 获取播放列表
|
||||||
|
*/
|
||||||
|
export function BgmGetPlaylist(): $CancellablePromise<$models.BgmPlaylistItem[]> {
|
||||||
|
return $Call.ByID(3200870077).then(($result: any) => {
|
||||||
|
return $$createType1($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BgmSavePlaylist 全量保存播放列表(前端调用时传完整列表)
|
||||||
|
*/
|
||||||
|
export function BgmSavePlaylist(items: $models.BgmPlaylistItem[]): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(2929660002, items);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CheckUpdate 检查更新
|
* CheckUpdate 检查更新
|
||||||
*/
|
*/
|
||||||
export function CheckUpdate(): $CancellablePromise<{ [_ in string]?: any }> {
|
export function CheckUpdate(): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(586574094).then(($result: any) => {
|
return $Call.ByID(586574094).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +58,7 @@ export function ClearCache(): $CancellablePromise<void> {
|
|||||||
*/
|
*/
|
||||||
export function CreateDir(path: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
export function CreateDir(path: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
return $Call.ByID(632035444, path).then(($result: any) => {
|
return $Call.ByID(632035444, path).then(($result: any) => {
|
||||||
return $$createType2($result);
|
return $$createType4($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,16 +67,20 @@ export function CreateDir(path: string): $CancellablePromise<filesystem$0.FileOp
|
|||||||
*/
|
*/
|
||||||
export function CreateFile(path: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
export function CreateFile(path: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
return $Call.ByID(3418645411, path).then(($result: any) => {
|
return $Call.ByID(3418645411, path).then(($result: any) => {
|
||||||
return $$createType2($result);
|
return $$createType4($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function DeleteConnectionProfile(id: number): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(2675016907, id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeletePath 删除文件或目录
|
* DeletePath 删除文件或目录
|
||||||
*/
|
*/
|
||||||
export function DeletePath(path: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
export function DeletePath(path: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
return $Call.ByID(1564637217, path).then(($result: any) => {
|
return $Call.ByID(1564637217, path).then(($result: any) => {
|
||||||
return $$createType2($result);
|
return $$createType4($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +96,7 @@ export function DeletePermanently(recyclePath: string): $CancellablePromise<void
|
|||||||
*/
|
*/
|
||||||
export function DetectFileTypeByContent(path: string): $CancellablePromise<{ [_ in string]?: any }> {
|
export function DetectFileTypeByContent(path: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(3067282982, path).then(($result: any) => {
|
return $Call.ByID(3067282982, path).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +105,7 @@ export function DetectFileTypeByContent(path: string): $CancellablePromise<{ [_
|
|||||||
*/
|
*/
|
||||||
export function DownloadUpdate(downloadURL: string): $CancellablePromise<{ [_ in string]?: any }> {
|
export function DownloadUpdate(downloadURL: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(115027584, downloadURL).then(($result: any) => {
|
return $Call.ByID(115027584, downloadURL).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +121,7 @@ export function EmptyRecycleBin(): $CancellablePromise<void> {
|
|||||||
*/
|
*/
|
||||||
export function ExportPDF(content: string, title: string, fileName: string, fontSize: number, pageWidth: number, pageHeight: number): $CancellablePromise<{ [_ in string]?: any }> {
|
export function ExportPDF(content: string, title: string, fileName: string, fontSize: number, pageWidth: number, pageHeight: number): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(1770450987, content, title, fileName, fontSize, pageWidth, pageHeight).then(($result: any) => {
|
return $Call.ByID(1770450987, content, title, fileName, fontSize, pageWidth, pageHeight).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +144,7 @@ export function ExtractFileFromZipToTemp(zipPath: string, filePath: string): $Ca
|
|||||||
*/
|
*/
|
||||||
export function GetAppConfig(): $CancellablePromise<{ [_ in string]?: any }> {
|
export function GetAppConfig(): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(2006534548).then(($result: any) => {
|
return $Call.ByID(2006534548).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +153,7 @@ export function GetAppConfig(): $CancellablePromise<{ [_ in string]?: any }> {
|
|||||||
*/
|
*/
|
||||||
export function GetAuditLogs(limit: number): $CancellablePromise<{ [_ in string]?: any }[]> {
|
export function GetAuditLogs(limit: number): $CancellablePromise<{ [_ in string]?: any }[]> {
|
||||||
return $Call.ByID(3554903517, limit).then(($result: any) => {
|
return $Call.ByID(3554903517, limit).then(($result: any) => {
|
||||||
return $$createType3($result);
|
return $$createType5($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +162,7 @@ export function GetAuditLogs(limit: number): $CancellablePromise<{ [_ in string]
|
|||||||
*/
|
*/
|
||||||
export function GetCPUInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
export function GetCPUInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(2509681007).then(($result: any) => {
|
return $Call.ByID(2509681007).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +171,7 @@ export function GetCPUInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
|||||||
*/
|
*/
|
||||||
export function GetCommonPaths(): $CancellablePromise<{ [_ in string]?: string }> {
|
export function GetCommonPaths(): $CancellablePromise<{ [_ in string]?: string }> {
|
||||||
return $Call.ByID(3953343786).then(($result: any) => {
|
return $Call.ByID(3953343786).then(($result: any) => {
|
||||||
return $$createType4($result);
|
return $$createType6($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +180,7 @@ export function GetCommonPaths(): $CancellablePromise<{ [_ in string]?: string }
|
|||||||
*/
|
*/
|
||||||
export function GetCurrentVersion(): $CancellablePromise<{ [_ in string]?: any }> {
|
export function GetCurrentVersion(): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(1827245900).then(($result: any) => {
|
return $Call.ByID(1827245900).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +189,7 @@ export function GetCurrentVersion(): $CancellablePromise<{ [_ in string]?: any }
|
|||||||
*/
|
*/
|
||||||
export function GetDiskInfo(): $CancellablePromise<{ [_ in string]?: any }[]> {
|
export function GetDiskInfo(): $CancellablePromise<{ [_ in string]?: any }[]> {
|
||||||
return $Call.ByID(3756377758).then(($result: any) => {
|
return $Call.ByID(3756377758).then(($result: any) => {
|
||||||
return $$createType3($result);
|
return $$createType5($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +198,7 @@ export function GetDiskInfo(): $CancellablePromise<{ [_ in string]?: any }[]> {
|
|||||||
*/
|
*/
|
||||||
export function GetEnvVars(): $CancellablePromise<{ [_ in string]?: string }> {
|
export function GetEnvVars(): $CancellablePromise<{ [_ in string]?: string }> {
|
||||||
return $Call.ByID(363814436).then(($result: any) => {
|
return $Call.ByID(363814436).then(($result: any) => {
|
||||||
return $$createType4($result);
|
return $$createType6($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +207,7 @@ export function GetEnvVars(): $CancellablePromise<{ [_ in string]?: string }> {
|
|||||||
*/
|
*/
|
||||||
export function GetFileInfo(path: string): $CancellablePromise<{ [_ in string]?: any }> {
|
export function GetFileInfo(path: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(2071650585, path).then(($result: any) => {
|
return $Call.ByID(2071650585, path).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,12 +218,18 @@ export function GetFileServerURL(): $CancellablePromise<string> {
|
|||||||
return $Call.ByID(4117667287);
|
return $Call.ByID(4117667287);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GetLocalSystemInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
|
return $Call.ByID(2203542363).then(($result: any) => {
|
||||||
|
return $$createType2($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetMemoryInfo 获取内存信息
|
* GetMemoryInfo 获取内存信息
|
||||||
*/
|
*/
|
||||||
export function GetMemoryInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
export function GetMemoryInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(2096905876).then(($result: any) => {
|
return $Call.ByID(2096905876).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +238,7 @@ export function GetMemoryInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
|||||||
*/
|
*/
|
||||||
export function GetRecycleBinEntries(): $CancellablePromise<{ [_ in string]?: any }[]> {
|
export function GetRecycleBinEntries(): $CancellablePromise<{ [_ in string]?: any }[]> {
|
||||||
return $Call.ByID(2312855399).then(($result: any) => {
|
return $Call.ByID(2312855399).then(($result: any) => {
|
||||||
return $$createType3($result);
|
return $$createType5($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +247,7 @@ export function GetRecycleBinEntries(): $CancellablePromise<{ [_ in string]?: an
|
|||||||
*/
|
*/
|
||||||
export function GetSystemInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
export function GetSystemInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(1347250254).then(($result: any) => {
|
return $Call.ByID(1347250254).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +256,7 @@ export function GetSystemInfo(): $CancellablePromise<{ [_ in string]?: any }> {
|
|||||||
*/
|
*/
|
||||||
export function GetUpdateConfig(): $CancellablePromise<{ [_ in string]?: any }> {
|
export function GetUpdateConfig(): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(680804904).then(($result: any) => {
|
return $Call.ByID(680804904).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,16 +265,23 @@ export function GetUpdateConfig(): $CancellablePromise<{ [_ in string]?: any }>
|
|||||||
*/
|
*/
|
||||||
export function GetZipFileInfo(zipPath: string, filePath: string): $CancellablePromise<{ [_ in string]?: any }> {
|
export function GetZipFileInfo(zipPath: string, filePath: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(2031617692, zipPath, filePath).then(($result: any) => {
|
return $Call.ByID(2031617692, zipPath, filePath).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HandleHotkey 处理全局热键回调:切换 BgmBar 显示/隐藏
|
||||||
|
*/
|
||||||
|
export function HandleHotkey(): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(420101833);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* InstallUpdate 安装更新包
|
* InstallUpdate 安装更新包
|
||||||
*/
|
*/
|
||||||
export function InstallUpdate(installerPath: string, autoRestart: boolean): $CancellablePromise<{ [_ in string]?: any }> {
|
export function InstallUpdate(installerPath: string, autoRestart: boolean): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(2443992793, installerPath, autoRestart).then(($result: any) => {
|
return $Call.ByID(2443992793, installerPath, autoRestart).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +290,7 @@ export function InstallUpdate(installerPath: string, autoRestart: boolean): $Can
|
|||||||
*/
|
*/
|
||||||
export function InstallUpdateWithHash(installerPath: string, autoRestart: boolean, expectedHash: string, hashType: string): $CancellablePromise<{ [_ in string]?: any }> {
|
export function InstallUpdateWithHash(installerPath: string, autoRestart: boolean, expectedHash: string, hashType: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(3787276601, installerPath, autoRestart, expectedHash, hashType).then(($result: any) => {
|
return $Call.ByID(3787276601, installerPath, autoRestart, expectedHash, hashType).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +299,7 @@ export function InstallUpdateWithHash(installerPath: string, autoRestart: boolea
|
|||||||
*/
|
*/
|
||||||
export function ListDir(path: string): $CancellablePromise<{ [_ in string]?: any }[]> {
|
export function ListDir(path: string): $CancellablePromise<{ [_ in string]?: any }[]> {
|
||||||
return $Call.ByID(2120475736, path).then(($result: any) => {
|
return $Call.ByID(2120475736, path).then(($result: any) => {
|
||||||
return $$createType3($result);
|
return $$createType5($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +308,13 @@ export function ListDir(path: string): $CancellablePromise<{ [_ in string]?: any
|
|||||||
*/
|
*/
|
||||||
export function ListZipContents(zipPath: string): $CancellablePromise<{ [_ in string]?: any }[]> {
|
export function ListZipContents(zipPath: string): $CancellablePromise<{ [_ in string]?: any }[]> {
|
||||||
return $Call.ByID(3013109042, zipPath).then(($result: any) => {
|
return $Call.ByID(3013109042, zipPath).then(($result: any) => {
|
||||||
return $$createType3($result);
|
return $$createType5($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LoadConnectionProfiles(): $CancellablePromise<{ [_ in string]?: any }[]> {
|
||||||
|
return $Call.ByID(454364767).then(($result: any) => {
|
||||||
|
return $$createType5($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,6 +325,129 @@ export function OpenPath(path: string): $CancellablePromise<void> {
|
|||||||
return $Call.ByID(1591734570, path);
|
return $Call.ByID(1591734570, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function OssConnect(req: $models.OssConnectRequest): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(3667022538, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssCreateDir OSS 创建目录
|
||||||
|
*/
|
||||||
|
export function OssCreateDir(connID: string, dirPath: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
|
return $Call.ByID(605668951, connID, dirPath).then(($result: any) => {
|
||||||
|
return $$createType4($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssCreateFile OSS 创建文件
|
||||||
|
*/
|
||||||
|
export function OssCreateFile(connID: string, filePath: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
|
return $Call.ByID(4148593430, connID, filePath).then(($result: any) => {
|
||||||
|
return $$createType4($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssDeletePath OSS 删除
|
||||||
|
*/
|
||||||
|
export function OssDeletePath(connID: string, key: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
|
return $Call.ByID(4285234744, connID, key).then(($result: any) => {
|
||||||
|
return $$createType4($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssDisconnect 断开 OSS 连接
|
||||||
|
*/
|
||||||
|
export function OssDisconnect(connID: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(3427288622, connID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssDownloadSiteForPreview OSS 下载 HTML 及其引用的资源到临时目录
|
||||||
|
*/
|
||||||
|
export function OssDownloadSiteForPreview(connID: string, key: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(1387550222, connID, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssDownloadToTemp OSS 下载到临时文件
|
||||||
|
*/
|
||||||
|
export function OssDownloadToTemp(connID: string, key: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(370656471, connID, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssDownloadToTempCached 带缓存的 OSS 下载(命中缓存直接返回本地路径)
|
||||||
|
*/
|
||||||
|
export function OssDownloadToTempCached(connID: string, key: string, fileSize: number, modTime: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(1312098141, connID, key, fileSize, modTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssGetCommonPaths OSS 获取常用路径
|
||||||
|
*/
|
||||||
|
export function OssGetCommonPaths(connID: string): $CancellablePromise<{ [_ in string]?: string }> {
|
||||||
|
return $Call.ByID(3525024115, connID).then(($result: any) => {
|
||||||
|
return $$createType6($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssGetFileInfo OSS 获取文件信息
|
||||||
|
*/
|
||||||
|
export function OssGetFileInfo(connID: string, key: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
|
return $Call.ByID(852430614, connID, key).then(($result: any) => {
|
||||||
|
return $$createType2($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssGetSignedURL OSS 获取预签名 URL
|
||||||
|
*/
|
||||||
|
export function OssGetSignedURL(connID: string, key: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(1344953417, connID, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssListDir OSS 列出目录
|
||||||
|
*/
|
||||||
|
export function OssListDir(connID: string, prefix: string): $CancellablePromise<{ [_ in string]?: any }[]> {
|
||||||
|
return $Call.ByID(3013212019, connID, prefix).then(($result: any) => {
|
||||||
|
return $$createType5($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssReadFile OSS 读取文件
|
||||||
|
*/
|
||||||
|
export function OssReadFile(connID: string, key: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(1629576606, connID, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssRenamePath OSS 重命名
|
||||||
|
*/
|
||||||
|
export function OssRenamePath(req: $models.OssRenamePathRequest): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
|
return $Call.ByID(4218061693, req).then(($result: any) => {
|
||||||
|
return $$createType4($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssWriteBase64File OSS 写入 base64 编码文件
|
||||||
|
*/
|
||||||
|
export function OssWriteBase64File(connID: string, key: string, base64Content: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(1772140162, connID, key, base64Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssWriteFile OSS 写入文件
|
||||||
|
*/
|
||||||
|
export function OssWriteFile(connID: string, key: string, content: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(39773277, connID, key, content);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ReadFile 读取文件
|
* ReadFile 读取文件
|
||||||
*/
|
*/
|
||||||
@@ -293,6 +455,13 @@ export function ReadFile(path: string): $CancellablePromise<string> {
|
|||||||
return $Call.ByID(1160596971, path);
|
return $Call.ByID(1160596971, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegisterGlobalHotkey 注册 Ctrl+Shift+B 全局热键(需在窗口创建后调用)
|
||||||
|
*/
|
||||||
|
export function RegisterGlobalHotkey(): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(2089930789);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload 重新加载窗口(用于菜单项)
|
* Reload 重新加载窗口(用于菜单项)
|
||||||
*/
|
*/
|
||||||
@@ -305,7 +474,7 @@ export function Reload(): $CancellablePromise<void> {
|
|||||||
*/
|
*/
|
||||||
export function RenamePath(req: $models.RenamePathRequest): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
export function RenamePath(req: $models.RenamePathRequest): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
return $Call.ByID(1959759948, req).then(($result: any) => {
|
return $Call.ByID(1959759948, req).then(($result: any) => {
|
||||||
return $$createType2($result);
|
return $$createType4($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,7 +483,7 @@ export function RenamePath(req: $models.RenamePathRequest): $CancellablePromise<
|
|||||||
*/
|
*/
|
||||||
export function ResolveShortcut(lnkPath: string): $CancellablePromise<{ [_ in string]?: any }> {
|
export function ResolveShortcut(lnkPath: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(4051288361, lnkPath).then(($result: any) => {
|
return $Call.ByID(4051288361, lnkPath).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +499,7 @@ export function RestoreFromRecycleBin(recyclePath: string): $CancellablePromise<
|
|||||||
*/
|
*/
|
||||||
export function SaveAppConfig(req: $models.SaveAppConfigRequest): $CancellablePromise<{ [_ in string]?: any }> {
|
export function SaveAppConfig(req: $models.SaveAppConfigRequest): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(1942219977, req).then(($result: any) => {
|
return $Call.ByID(1942219977, req).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,6 +510,12 @@ export function SaveBase64File(req: $models.SaveBase64FileRequest): $Cancellable
|
|||||||
return $Call.ByID(1355120553, req);
|
return $Call.ByID(1355120553, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function SaveConnectionProfile(req: $models.SaveProfileRequest): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
|
return $Call.ByID(3622685069, req).then(($result: any) => {
|
||||||
|
return $$createType2($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SelectPDFSaveDirectory 选择PDF保存目录
|
* SelectPDFSaveDirectory 选择PDF保存目录
|
||||||
*/
|
*/
|
||||||
@@ -360,7 +535,7 @@ export function SetMainWindow(w: application$0.WebviewWindow | null): $Cancellab
|
|||||||
*/
|
*/
|
||||||
export function SetUpdateConfig(autoCheckEnabled: boolean, checkIntervalMinutes: number, checkURL: string): $CancellablePromise<{ [_ in string]?: any }> {
|
export function SetUpdateConfig(autoCheckEnabled: boolean, checkIntervalMinutes: number, checkURL: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(4271731092, autoCheckEnabled, checkIntervalMinutes, checkURL).then(($result: any) => {
|
return $Call.ByID(4271731092, autoCheckEnabled, checkIntervalMinutes, checkURL).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,15 +546,157 @@ export function SetWindowTitleBarColor(color: number, isDark: boolean): $Cancell
|
|||||||
return $Call.ByID(1570627619, color, isDark);
|
return $Call.ByID(1570627619, color, isDark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpConnect 建立 SFTP 连接,返回连接标识符 connID
|
||||||
|
*/
|
||||||
|
export function SftpConnect(req: $models.SftpConnectRequest): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(2742828454, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpCreateDir SFTP 创建目录
|
||||||
|
*/
|
||||||
|
export function SftpCreateDir(connID: string, dirPath: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
|
return $Call.ByID(586600875, connID, dirPath).then(($result: any) => {
|
||||||
|
return $$createType4($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpCreateFile SFTP 创建文件
|
||||||
|
*/
|
||||||
|
export function SftpCreateFile(connID: string, filePath: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
|
return $Call.ByID(623026146, connID, filePath).then(($result: any) => {
|
||||||
|
return $$createType4($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpDeletePath SFTP 删除文件或目录
|
||||||
|
*/
|
||||||
|
export function SftpDeletePath(connID: string, filePath: string): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
|
return $Call.ByID(1833619836, connID, filePath).then(($result: any) => {
|
||||||
|
return $$createType4($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpDisconnect 断开 SFTP 连接
|
||||||
|
*/
|
||||||
|
export function SftpDisconnect(connID: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(597628874, connID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpDownloadSiteForPreview 下载 HTML 及其网站资源到本地临时目录
|
||||||
|
*/
|
||||||
|
export function SftpDownloadSiteForPreview(connID: string, remotePath: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(1591575570, connID, remotePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpDownloadToTemp 下载远程文件到本地临时目录(用于预览)
|
||||||
|
*/
|
||||||
|
export function SftpDownloadToTemp(connID: string, remotePath: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(1159267603, connID, remotePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpDownloadToTempCached 带缓存的 SFTP 下载(命中缓存直接返回本地路径)
|
||||||
|
*/
|
||||||
|
export function SftpDownloadToTempCached(connID: string, remotePath: string, fileSize: number, modTime: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(3935472409, connID, remotePath, fileSize, modTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpGetCommonPaths 获取 SFTP 远程主机常用路径
|
||||||
|
*/
|
||||||
|
export function SftpGetCommonPaths(connID: string): $CancellablePromise<{ [_ in string]?: string }> {
|
||||||
|
return $Call.ByID(2874386183, connID).then(($result: any) => {
|
||||||
|
return $$createType6($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpGetFileInfo SFTP 获取文件信息
|
||||||
|
*/
|
||||||
|
export function SftpGetFileInfo(connID: string, filePath: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
|
return $Call.ByID(1959840482, connID, filePath).then(($result: any) => {
|
||||||
|
return $$createType2($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpGetSystemInfo 获取 SFTP 远程主机系统信息(CPU/内存/磁盘)
|
||||||
|
*/
|
||||||
|
export function SftpGetSystemInfo(connID: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
|
return $Call.ByID(1950143653, connID).then(($result: any) => {
|
||||||
|
return $$createType2($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpListDir SFTP 列出目录
|
||||||
|
*/
|
||||||
|
export function SftpListDir(connID: string, dirPath: string): $CancellablePromise<{ [_ in string]?: any }[]> {
|
||||||
|
return $Call.ByID(2061863855, connID, dirPath).then(($result: any) => {
|
||||||
|
return $$createType5($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpReadFile SFTP 读取文件内容
|
||||||
|
*/
|
||||||
|
export function SftpReadFile(connID: string, filePath: string): $CancellablePromise<string> {
|
||||||
|
return $Call.ByID(3068590994, connID, filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpRenamePath SFTP 重命名文件或目录
|
||||||
|
*/
|
||||||
|
export function SftpRenamePath(req: $models.SftpRenamePathRequest): $CancellablePromise<filesystem$0.FileOperationResult | null> {
|
||||||
|
return $Call.ByID(183173937, req).then(($result: any) => {
|
||||||
|
return $$createType4($result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpWriteBase64File SFTP 写入 base64 编码的二进制文件(粘贴图片等)
|
||||||
|
*/
|
||||||
|
export function SftpWriteBase64File(sessionID: string, filePath: string, base64Content: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(139141998, sessionID, filePath, base64Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpWriteFile SFTP 写入文件
|
||||||
|
*/
|
||||||
|
export function SftpWriteFile(req: $models.SftpWriteFileRequest): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(2401472593, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UnwatchFile 停止监听文件变化
|
||||||
|
*/
|
||||||
|
export function UnwatchFile(): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(3006906623);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VerifyUpdateFile 验证更新文件哈希值
|
* VerifyUpdateFile 验证更新文件哈希值
|
||||||
*/
|
*/
|
||||||
export function VerifyUpdateFile(filePath: string, expectedHash: string, hashType: string): $CancellablePromise<{ [_ in string]?: any }> {
|
export function VerifyUpdateFile(filePath: string, expectedHash: string, hashType: string): $CancellablePromise<{ [_ in string]?: any }> {
|
||||||
return $Call.ByID(2181909867, filePath, expectedHash, hashType).then(($result: any) => {
|
return $Call.ByID(2181909867, filePath, expectedHash, hashType).then(($result: any) => {
|
||||||
return $$createType0($result);
|
return $$createType2($result);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WatchFile 开始监听指定文件的变化,变化时发送 file-changed 事件
|
||||||
|
*/
|
||||||
|
export function WatchFile(path: string): $CancellablePromise<void> {
|
||||||
|
return $Call.ByID(325055910, path);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WindowClose 关闭窗口
|
* WindowClose 关闭窗口
|
||||||
*/
|
*/
|
||||||
@@ -423,8 +740,10 @@ export function WriteFile(req: $models.WriteFileRequest): $CancellablePromise<vo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Private type creation functions
|
// Private type creation functions
|
||||||
const $$createType0 = $Create.Map($Create.Any, $Create.Any);
|
const $$createType0 = $models.BgmPlaylistItem.createFrom;
|
||||||
const $$createType1 = filesystem$0.FileOperationResult.createFrom;
|
const $$createType1 = $Create.Array($$createType0);
|
||||||
const $$createType2 = $Create.Nullable($$createType1);
|
const $$createType2 = $Create.Map($Create.Any, $Create.Any);
|
||||||
const $$createType3 = $Create.Array($$createType0);
|
const $$createType3 = filesystem$0.FileOperationResult.createFrom;
|
||||||
const $$createType4 = $Create.Map($Create.Any, $Create.Any);
|
const $$createType4 = $Create.Nullable($$createType3);
|
||||||
|
const $$createType5 = $Create.Array($$createType2);
|
||||||
|
const $$createType6 = $Create.Map($Create.Any, $Create.Any);
|
||||||
|
|||||||
@@ -7,8 +7,15 @@ export {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
BgmPlaylistItem,
|
||||||
|
OssConnectRequest,
|
||||||
|
OssRenamePathRequest,
|
||||||
RenamePathRequest,
|
RenamePathRequest,
|
||||||
SaveAppConfigRequest,
|
SaveAppConfigRequest,
|
||||||
SaveBase64FileRequest,
|
SaveBase64FileRequest,
|
||||||
|
SaveProfileRequest,
|
||||||
|
SftpConnectRequest,
|
||||||
|
SftpRenamePathRequest,
|
||||||
|
SftpWriteFileRequest,
|
||||||
WriteFileRequest
|
WriteFileRequest
|
||||||
} from "./models.js";
|
} from "./models.js";
|
||||||
|
|||||||
@@ -9,6 +9,103 @@ import { Create as $Create } from "@wailsio/runtime";
|
|||||||
// @ts-ignore: Unused imports
|
// @ts-ignore: Unused imports
|
||||||
import * as api$0 from "./internal/api/models.js";
|
import * as api$0 from "./internal/api/models.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BgmPlaylistItem 播放列表条目
|
||||||
|
*/
|
||||||
|
export class BgmPlaylistItem {
|
||||||
|
"name": string;
|
||||||
|
"path": string;
|
||||||
|
"profile_id": string;
|
||||||
|
|
||||||
|
/** Creates a new BgmPlaylistItem instance. */
|
||||||
|
constructor($$source: Partial<BgmPlaylistItem> = {}) {
|
||||||
|
if (!("name" in $$source)) {
|
||||||
|
this["name"] = "";
|
||||||
|
}
|
||||||
|
if (!("path" in $$source)) {
|
||||||
|
this["path"] = "";
|
||||||
|
}
|
||||||
|
if (!("profile_id" in $$source)) {
|
||||||
|
this["profile_id"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new BgmPlaylistItem instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): BgmPlaylistItem {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new BgmPlaylistItem($$parsedSource as Partial<BgmPlaylistItem>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OssConnectRequest {
|
||||||
|
"provider": string;
|
||||||
|
"access_key": string;
|
||||||
|
"secret_key": string;
|
||||||
|
"endpoint": string;
|
||||||
|
|
||||||
|
/** Creates a new OssConnectRequest instance. */
|
||||||
|
constructor($$source: Partial<OssConnectRequest> = {}) {
|
||||||
|
if (!("provider" in $$source)) {
|
||||||
|
this["provider"] = "";
|
||||||
|
}
|
||||||
|
if (!("access_key" in $$source)) {
|
||||||
|
this["access_key"] = "";
|
||||||
|
}
|
||||||
|
if (!("secret_key" in $$source)) {
|
||||||
|
this["secret_key"] = "";
|
||||||
|
}
|
||||||
|
if (!("endpoint" in $$source)) {
|
||||||
|
this["endpoint"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new OssConnectRequest instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): OssConnectRequest {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new OssConnectRequest($$parsedSource as Partial<OssConnectRequest>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OssRenamePathRequest OSS 重命名请求
|
||||||
|
*/
|
||||||
|
export class OssRenamePathRequest {
|
||||||
|
"conn_id": string;
|
||||||
|
"old_path": string;
|
||||||
|
"new_path": string;
|
||||||
|
|
||||||
|
/** Creates a new OssRenamePathRequest instance. */
|
||||||
|
constructor($$source: Partial<OssRenamePathRequest> = {}) {
|
||||||
|
if (!("conn_id" in $$source)) {
|
||||||
|
this["conn_id"] = "";
|
||||||
|
}
|
||||||
|
if (!("old_path" in $$source)) {
|
||||||
|
this["old_path"] = "";
|
||||||
|
}
|
||||||
|
if (!("new_path" in $$source)) {
|
||||||
|
this["new_path"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new OssRenamePathRequest instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): OssRenamePathRequest {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new OssRenamePathRequest($$parsedSource as Partial<OssRenamePathRequest>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RenamePathRequest 重命名文件或目录请求结构体
|
* RenamePathRequest 重命名文件或目录请求结构体
|
||||||
*/
|
*/
|
||||||
@@ -109,6 +206,195 @@ export class SaveBase64FileRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SaveProfileRequest {
|
||||||
|
"id": number | null;
|
||||||
|
"name": string;
|
||||||
|
"host": string;
|
||||||
|
"port": number;
|
||||||
|
"username": string;
|
||||||
|
"password": string;
|
||||||
|
"key_path": string;
|
||||||
|
"type": string;
|
||||||
|
"provider": string;
|
||||||
|
"token": string;
|
||||||
|
"access_key": string;
|
||||||
|
"secret_key": string;
|
||||||
|
"bucket": string;
|
||||||
|
"region": string;
|
||||||
|
"endpoint": string;
|
||||||
|
"last_connected": number | null;
|
||||||
|
|
||||||
|
/** Creates a new SaveProfileRequest instance. */
|
||||||
|
constructor($$source: Partial<SaveProfileRequest> = {}) {
|
||||||
|
if (!("id" in $$source)) {
|
||||||
|
this["id"] = null;
|
||||||
|
}
|
||||||
|
if (!("name" in $$source)) {
|
||||||
|
this["name"] = "";
|
||||||
|
}
|
||||||
|
if (!("host" in $$source)) {
|
||||||
|
this["host"] = "";
|
||||||
|
}
|
||||||
|
if (!("port" in $$source)) {
|
||||||
|
this["port"] = 0;
|
||||||
|
}
|
||||||
|
if (!("username" in $$source)) {
|
||||||
|
this["username"] = "";
|
||||||
|
}
|
||||||
|
if (!("password" in $$source)) {
|
||||||
|
this["password"] = "";
|
||||||
|
}
|
||||||
|
if (!("key_path" in $$source)) {
|
||||||
|
this["key_path"] = "";
|
||||||
|
}
|
||||||
|
if (!("type" in $$source)) {
|
||||||
|
this["type"] = "";
|
||||||
|
}
|
||||||
|
if (!("provider" in $$source)) {
|
||||||
|
this["provider"] = "";
|
||||||
|
}
|
||||||
|
if (!("token" in $$source)) {
|
||||||
|
this["token"] = "";
|
||||||
|
}
|
||||||
|
if (!("access_key" in $$source)) {
|
||||||
|
this["access_key"] = "";
|
||||||
|
}
|
||||||
|
if (!("secret_key" in $$source)) {
|
||||||
|
this["secret_key"] = "";
|
||||||
|
}
|
||||||
|
if (!("bucket" in $$source)) {
|
||||||
|
this["bucket"] = "";
|
||||||
|
}
|
||||||
|
if (!("region" in $$source)) {
|
||||||
|
this["region"] = "";
|
||||||
|
}
|
||||||
|
if (!("endpoint" in $$source)) {
|
||||||
|
this["endpoint"] = "";
|
||||||
|
}
|
||||||
|
if (!("last_connected" in $$source)) {
|
||||||
|
this["last_connected"] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SaveProfileRequest instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): SaveProfileRequest {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new SaveProfileRequest($$parsedSource as Partial<SaveProfileRequest>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpConnectRequest SFTP 连接请求
|
||||||
|
*/
|
||||||
|
export class SftpConnectRequest {
|
||||||
|
"host": string;
|
||||||
|
"port": number;
|
||||||
|
"username": string;
|
||||||
|
"password": string;
|
||||||
|
"key_path": string;
|
||||||
|
"key_passphrase": string;
|
||||||
|
|
||||||
|
/** Creates a new SftpConnectRequest instance. */
|
||||||
|
constructor($$source: Partial<SftpConnectRequest> = {}) {
|
||||||
|
if (!("host" in $$source)) {
|
||||||
|
this["host"] = "";
|
||||||
|
}
|
||||||
|
if (!("port" in $$source)) {
|
||||||
|
this["port"] = 0;
|
||||||
|
}
|
||||||
|
if (!("username" in $$source)) {
|
||||||
|
this["username"] = "";
|
||||||
|
}
|
||||||
|
if (!("password" in $$source)) {
|
||||||
|
this["password"] = "";
|
||||||
|
}
|
||||||
|
if (!("key_path" in $$source)) {
|
||||||
|
this["key_path"] = "";
|
||||||
|
}
|
||||||
|
if (!("key_passphrase" in $$source)) {
|
||||||
|
this["key_passphrase"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SftpConnectRequest instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): SftpConnectRequest {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new SftpConnectRequest($$parsedSource as Partial<SftpConnectRequest>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpRenamePathRequest SFTP 重命名请求
|
||||||
|
*/
|
||||||
|
export class SftpRenamePathRequest {
|
||||||
|
"session_id": string;
|
||||||
|
"old_path": string;
|
||||||
|
"new_path": string;
|
||||||
|
|
||||||
|
/** Creates a new SftpRenamePathRequest instance. */
|
||||||
|
constructor($$source: Partial<SftpRenamePathRequest> = {}) {
|
||||||
|
if (!("session_id" in $$source)) {
|
||||||
|
this["session_id"] = "";
|
||||||
|
}
|
||||||
|
if (!("old_path" in $$source)) {
|
||||||
|
this["old_path"] = "";
|
||||||
|
}
|
||||||
|
if (!("new_path" in $$source)) {
|
||||||
|
this["new_path"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SftpRenamePathRequest instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): SftpRenamePathRequest {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new SftpRenamePathRequest($$parsedSource as Partial<SftpRenamePathRequest>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SftpWriteFileRequest SFTP 写入请求
|
||||||
|
*/
|
||||||
|
export class SftpWriteFileRequest {
|
||||||
|
"session_id": string;
|
||||||
|
"path": string;
|
||||||
|
"content": string;
|
||||||
|
|
||||||
|
/** Creates a new SftpWriteFileRequest instance. */
|
||||||
|
constructor($$source: Partial<SftpWriteFileRequest> = {}) {
|
||||||
|
if (!("session_id" in $$source)) {
|
||||||
|
this["session_id"] = "";
|
||||||
|
}
|
||||||
|
if (!("path" in $$source)) {
|
||||||
|
this["path"] = "";
|
||||||
|
}
|
||||||
|
if (!("content" in $$source)) {
|
||||||
|
this["content"] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(this, $$source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SftpWriteFileRequest instance from a string or object.
|
||||||
|
*/
|
||||||
|
static createFrom($$source: any = {}): SftpWriteFileRequest {
|
||||||
|
let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
|
||||||
|
return new SftpWriteFileRequest($$parsedSource as Partial<SftpWriteFileRequest>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WriteFileRequest 写入文件请求结构体
|
* WriteFileRequest 写入文件请求结构体
|
||||||
*/
|
*/
|
||||||
|
|||||||
98
frontend/src/wailsjs/wailsjs/go/main/App.d.ts
vendored
98
frontend/src/wailsjs/wailsjs/go/main/App.d.ts
vendored
@@ -1,98 +0,0 @@
|
|||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
|
||||||
// This file is automatically generated. DO NOT EDIT
|
|
||||||
import {filesystem} from '../models';
|
|
||||||
import {main} from '../models';
|
|
||||||
|
|
||||||
export function CheckUpdate():Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function ClearCache():Promise<void>;
|
|
||||||
|
|
||||||
export function CreateDir(arg1:string):Promise<filesystem.FileOperationResult>;
|
|
||||||
|
|
||||||
export function CreateFile(arg1:string):Promise<filesystem.FileOperationResult>;
|
|
||||||
|
|
||||||
export function DeletePath(arg1:string):Promise<filesystem.FileOperationResult>;
|
|
||||||
|
|
||||||
export function DeletePermanently(arg1:string):Promise<void>;
|
|
||||||
|
|
||||||
export function DetectFileTypeByContent(arg1:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function DownloadUpdate(arg1:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function EmptyRecycleBin():Promise<void>;
|
|
||||||
|
|
||||||
export function ExportPDF(arg1:string,arg2:string,arg3:string,arg4:number,arg5:number,arg6:number):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function ExtractFileFromZip(arg1:string,arg2:string):Promise<string>;
|
|
||||||
|
|
||||||
export function ExtractFileFromZipToTemp(arg1:string,arg2:string):Promise<string>;
|
|
||||||
|
|
||||||
export function GetAppConfig():Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function GetAuditLogs(arg1:number):Promise<Array<Record<string, any>>>;
|
|
||||||
|
|
||||||
export function GetCPUInfo():Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function GetCommonPaths():Promise<Record<string, string>>;
|
|
||||||
|
|
||||||
export function GetCurrentVersion():Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function GetDiskInfo():Promise<Array<Record<string, any>>>;
|
|
||||||
|
|
||||||
export function GetEnvVars():Promise<Record<string, string>>;
|
|
||||||
|
|
||||||
export function GetFileInfo(arg1:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function GetFileServerURL():Promise<string>;
|
|
||||||
|
|
||||||
export function GetMemoryInfo():Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function GetRecycleBinEntries():Promise<Array<Record<string, any>>>;
|
|
||||||
|
|
||||||
export function GetSystemInfo():Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function GetUpdateConfig():Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function GetZipFileInfo(arg1:string,arg2:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function InstallUpdate(arg1:string,arg2:boolean):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function InstallUpdateWithHash(arg1:string,arg2:boolean,arg3:string,arg4:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function ListDir(arg1:string):Promise<Array<Record<string, any>>>;
|
|
||||||
|
|
||||||
export function ListZipContents(arg1:string):Promise<Array<Record<string, any>>>;
|
|
||||||
|
|
||||||
export function OpenPath(arg1:string):Promise<void>;
|
|
||||||
|
|
||||||
export function ReadFile(arg1:string):Promise<string>;
|
|
||||||
|
|
||||||
export function Reload():Promise<void>;
|
|
||||||
|
|
||||||
export function RenamePath(arg1:main.RenamePathRequest):Promise<filesystem.FileOperationResult>;
|
|
||||||
|
|
||||||
export function ResolveShortcut(arg1:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function RestoreFromRecycleBin(arg1:string):Promise<void>;
|
|
||||||
|
|
||||||
export function SaveAppConfig(arg1:main.SaveAppConfigRequest):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function SaveBase64File(arg1:main.SaveBase64FileRequest):Promise<void>;
|
|
||||||
|
|
||||||
export function SelectPDFSaveDirectory():Promise<string>;
|
|
||||||
|
|
||||||
export function SetUpdateConfig(arg1:boolean,arg2:number,arg3:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function VerifyUpdateFile(arg1:string,arg2:string,arg3:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function WindowClose():Promise<void>;
|
|
||||||
|
|
||||||
export function WindowIsMaximized():Promise<boolean>;
|
|
||||||
|
|
||||||
export function WindowMaximize():Promise<void>;
|
|
||||||
|
|
||||||
export function WindowMinimize():Promise<void>;
|
|
||||||
|
|
||||||
export function WindowToggleAlwaysOnTop():Promise<boolean>;
|
|
||||||
|
|
||||||
export function WriteFile(arg1:main.WriteFileRequest):Promise<void>;
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
|
||||||
// This file is automatically generated. DO NOT EDIT
|
|
||||||
|
|
||||||
export function CheckUpdate() {
|
|
||||||
return window['go']['main']['App']['CheckUpdate']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ClearCache() {
|
|
||||||
return window['go']['main']['App']['ClearCache']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CreateDir(arg1) {
|
|
||||||
return window['go']['main']['App']['CreateDir'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CreateFile(arg1) {
|
|
||||||
return window['go']['main']['App']['CreateFile'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DeletePath(arg1) {
|
|
||||||
return window['go']['main']['App']['DeletePath'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DeletePermanently(arg1) {
|
|
||||||
return window['go']['main']['App']['DeletePermanently'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DetectFileTypeByContent(arg1) {
|
|
||||||
return window['go']['main']['App']['DetectFileTypeByContent'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DownloadUpdate(arg1) {
|
|
||||||
return window['go']['main']['App']['DownloadUpdate'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EmptyRecycleBin() {
|
|
||||||
return window['go']['main']['App']['EmptyRecycleBin']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ExportPDF(arg1, arg2, arg3, arg4, arg5, arg6) {
|
|
||||||
return window['go']['main']['App']['ExportPDF'](arg1, arg2, arg3, arg4, arg5, arg6);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ExtractFileFromZip(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['ExtractFileFromZip'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ExtractFileFromZipToTemp(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['ExtractFileFromZipToTemp'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetAppConfig() {
|
|
||||||
return window['go']['main']['App']['GetAppConfig']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetAuditLogs(arg1) {
|
|
||||||
return window['go']['main']['App']['GetAuditLogs'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetCPUInfo() {
|
|
||||||
return window['go']['main']['App']['GetCPUInfo']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetCommonPaths() {
|
|
||||||
return window['go']['main']['App']['GetCommonPaths']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetCurrentVersion() {
|
|
||||||
return window['go']['main']['App']['GetCurrentVersion']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetDiskInfo() {
|
|
||||||
return window['go']['main']['App']['GetDiskInfo']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetEnvVars() {
|
|
||||||
return window['go']['main']['App']['GetEnvVars']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetFileInfo(arg1) {
|
|
||||||
return window['go']['main']['App']['GetFileInfo'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetFileServerURL() {
|
|
||||||
return window['go']['main']['App']['GetFileServerURL']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetMemoryInfo() {
|
|
||||||
return window['go']['main']['App']['GetMemoryInfo']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetRecycleBinEntries() {
|
|
||||||
return window['go']['main']['App']['GetRecycleBinEntries']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetSystemInfo() {
|
|
||||||
return window['go']['main']['App']['GetSystemInfo']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetUpdateConfig() {
|
|
||||||
return window['go']['main']['App']['GetUpdateConfig']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GetZipFileInfo(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['GetZipFileInfo'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function InstallUpdate(arg1, arg2) {
|
|
||||||
return window['go']['main']['App']['InstallUpdate'](arg1, arg2);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function InstallUpdateWithHash(arg1, arg2, arg3, arg4) {
|
|
||||||
return window['go']['main']['App']['InstallUpdateWithHash'](arg1, arg2, arg3, arg4);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ListDir(arg1) {
|
|
||||||
return window['go']['main']['App']['ListDir'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ListZipContents(arg1) {
|
|
||||||
return window['go']['main']['App']['ListZipContents'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function OpenPath(arg1) {
|
|
||||||
return window['go']['main']['App']['OpenPath'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadFile(arg1) {
|
|
||||||
return window['go']['main']['App']['ReadFile'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Reload() {
|
|
||||||
return window['go']['main']['App']['Reload']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RenamePath(arg1) {
|
|
||||||
return window['go']['main']['App']['RenamePath'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ResolveShortcut(arg1) {
|
|
||||||
return window['go']['main']['App']['ResolveShortcut'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RestoreFromRecycleBin(arg1) {
|
|
||||||
return window['go']['main']['App']['RestoreFromRecycleBin'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SaveAppConfig(arg1) {
|
|
||||||
return window['go']['main']['App']['SaveAppConfig'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SaveBase64File(arg1) {
|
|
||||||
return window['go']['main']['App']['SaveBase64File'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SelectPDFSaveDirectory() {
|
|
||||||
return window['go']['main']['App']['SelectPDFSaveDirectory']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SetUpdateConfig(arg1, arg2, arg3) {
|
|
||||||
return window['go']['main']['App']['SetUpdateConfig'](arg1, arg2, arg3);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function VerifyUpdateFile(arg1, arg2, arg3) {
|
|
||||||
return window['go']['main']['App']['VerifyUpdateFile'](arg1, arg2, arg3);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowClose() {
|
|
||||||
return window['go']['main']['App']['WindowClose']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowIsMaximized() {
|
|
||||||
return window['go']['main']['App']['WindowIsMaximized']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowMaximize() {
|
|
||||||
return window['go']['main']['App']['WindowMaximize']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowMinimize() {
|
|
||||||
return window['go']['main']['App']['WindowMinimize']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowToggleAlwaysOnTop() {
|
|
||||||
return window['go']['main']['App']['WindowToggleAlwaysOnTop']();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WriteFile(arg1) {
|
|
||||||
return window['go']['main']['App']['WriteFile'](arg1);
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
export namespace api {
|
|
||||||
|
|
||||||
export class AppTabDefinition {
|
|
||||||
key: string;
|
|
||||||
title: string;
|
|
||||||
visible: boolean;
|
|
||||||
enabled: boolean;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new AppTabDefinition(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.key = source["key"];
|
|
||||||
this.title = source["title"];
|
|
||||||
this.visible = source["visible"];
|
|
||||||
this.enabled = source["enabled"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace filesystem {
|
|
||||||
|
|
||||||
export class FileOperationResult {
|
|
||||||
path: string;
|
|
||||||
name: string;
|
|
||||||
size: number;
|
|
||||||
size_str?: string;
|
|
||||||
is_dir: boolean;
|
|
||||||
mod_time?: string;
|
|
||||||
mode?: string;
|
|
||||||
old_path?: string;
|
|
||||||
deleted?: boolean;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new FileOperationResult(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.path = source["path"];
|
|
||||||
this.name = source["name"];
|
|
||||||
this.size = source["size"];
|
|
||||||
this.size_str = source["size_str"];
|
|
||||||
this.is_dir = source["is_dir"];
|
|
||||||
this.mod_time = source["mod_time"];
|
|
||||||
this.mode = source["mode"];
|
|
||||||
this.old_path = source["old_path"];
|
|
||||||
this.deleted = source["deleted"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export namespace main {
|
|
||||||
|
|
||||||
export class RenamePathRequest {
|
|
||||||
oldPath: string;
|
|
||||||
newPath: string;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new RenamePathRequest(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.oldPath = source["oldPath"];
|
|
||||||
this.newPath = source["newPath"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class SaveAppConfigRequest {
|
|
||||||
tabs: api.AppTabDefinition[];
|
|
||||||
visibleTabs: string[];
|
|
||||||
defaultTab: string;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new SaveAppConfigRequest(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.tabs = this.convertValues(source["tabs"], api.AppTabDefinition);
|
|
||||||
this.visibleTabs = source["visibleTabs"];
|
|
||||||
this.defaultTab = source["defaultTab"];
|
|
||||||
}
|
|
||||||
|
|
||||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
|
||||||
if (!a) {
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
if (a.slice && a.map) {
|
|
||||||
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
|
||||||
} else if ("object" === typeof a) {
|
|
||||||
if (asMap) {
|
|
||||||
for (const key of Object.keys(a)) {
|
|
||||||
a[key] = new classs(a[key]);
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
return new classs(a);
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class SaveBase64FileRequest {
|
|
||||||
path: string;
|
|
||||||
content: string;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new SaveBase64FileRequest(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.path = source["path"];
|
|
||||||
this.content = source["content"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class WriteFileRequest {
|
|
||||||
path: string;
|
|
||||||
content: string;
|
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
|
||||||
return new WriteFileRequest(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(source: any = {}) {
|
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
|
||||||
this.path = source["path"];
|
|
||||||
this.content = source["content"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@wailsapp/runtime",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"description": "Wails Javascript runtime library",
|
|
||||||
"main": "runtime.js",
|
|
||||||
"types": "runtime.d.ts",
|
|
||||||
"scripts": {
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/wailsapp/wails.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"Wails",
|
|
||||||
"Javascript",
|
|
||||||
"Go"
|
|
||||||
],
|
|
||||||
"author": "Lea Anthony <lea.anthony@gmail.com>",
|
|
||||||
"license": "MIT",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/wailsapp/wails/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/wailsapp/wails#readme"
|
|
||||||
}
|
|
||||||
330
frontend/src/wailsjs/wailsjs/runtime/runtime.d.ts
vendored
330
frontend/src/wailsjs/wailsjs/runtime/runtime.d.ts
vendored
@@ -1,330 +0,0 @@
|
|||||||
/*
|
|
||||||
_ __ _ __
|
|
||||||
| | / /___ _(_) /____
|
|
||||||
| | /| / / __ `/ / / ___/
|
|
||||||
| |/ |/ / /_/ / / (__ )
|
|
||||||
|__/|__/\__,_/_/_/____/
|
|
||||||
The electron alternative for Go
|
|
||||||
(c) Lea Anthony 2019-present
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface Position {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Size {
|
|
||||||
w: number;
|
|
||||||
h: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Screen {
|
|
||||||
isCurrent: boolean;
|
|
||||||
isPrimary: boolean;
|
|
||||||
width : number
|
|
||||||
height : number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Environment information such as platform, buildtype, ...
|
|
||||||
export interface EnvironmentInfo {
|
|
||||||
buildType: string;
|
|
||||||
platform: string;
|
|
||||||
arch: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
|
|
||||||
// emits the given event. Optional data may be passed with the event.
|
|
||||||
// This will trigger any event listeners.
|
|
||||||
export function EventsEmit(eventName: string, ...data: any): void;
|
|
||||||
|
|
||||||
// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
|
|
||||||
export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
|
|
||||||
|
|
||||||
// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
|
|
||||||
// sets up a listener for the given event name, but will only trigger a given number times.
|
|
||||||
export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
|
|
||||||
|
|
||||||
// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
|
|
||||||
// sets up a listener for the given event name, but will only trigger once.
|
|
||||||
export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
|
|
||||||
|
|
||||||
// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
|
|
||||||
// unregisters the listener for the given event name.
|
|
||||||
export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
|
|
||||||
|
|
||||||
// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
|
|
||||||
// unregisters all listeners.
|
|
||||||
export function EventsOffAll(): void;
|
|
||||||
|
|
||||||
// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
|
|
||||||
// logs the given message as a raw message
|
|
||||||
export function LogPrint(message: string): void;
|
|
||||||
|
|
||||||
// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
|
|
||||||
// logs the given message at the `trace` log level.
|
|
||||||
export function LogTrace(message: string): void;
|
|
||||||
|
|
||||||
// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
|
|
||||||
// logs the given message at the `debug` log level.
|
|
||||||
export function LogDebug(message: string): void;
|
|
||||||
|
|
||||||
// [LogError](https://wails.io/docs/reference/runtime/log#logerror)
|
|
||||||
// logs the given message at the `error` log level.
|
|
||||||
export function LogError(message: string): void;
|
|
||||||
|
|
||||||
// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
|
|
||||||
// logs the given message at the `fatal` log level.
|
|
||||||
// The application will quit after calling this method.
|
|
||||||
export function LogFatal(message: string): void;
|
|
||||||
|
|
||||||
// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
|
|
||||||
// logs the given message at the `info` log level.
|
|
||||||
export function LogInfo(message: string): void;
|
|
||||||
|
|
||||||
// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
|
|
||||||
// logs the given message at the `warning` log level.
|
|
||||||
export function LogWarning(message: string): void;
|
|
||||||
|
|
||||||
// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
|
|
||||||
// Forces a reload by the main application as well as connected browsers.
|
|
||||||
export function WindowReload(): void;
|
|
||||||
|
|
||||||
// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
|
|
||||||
// Reloads the application frontend.
|
|
||||||
export function WindowReloadApp(): void;
|
|
||||||
|
|
||||||
// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
|
|
||||||
// Sets the window AlwaysOnTop or not on top.
|
|
||||||
export function WindowSetAlwaysOnTop(b: boolean): void;
|
|
||||||
|
|
||||||
// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
|
|
||||||
// *Windows only*
|
|
||||||
// Sets window theme to system default (dark/light).
|
|
||||||
export function WindowSetSystemDefaultTheme(): void;
|
|
||||||
|
|
||||||
// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
|
|
||||||
// *Windows only*
|
|
||||||
// Sets window to light theme.
|
|
||||||
export function WindowSetLightTheme(): void;
|
|
||||||
|
|
||||||
// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
|
|
||||||
// *Windows only*
|
|
||||||
// Sets window to dark theme.
|
|
||||||
export function WindowSetDarkTheme(): void;
|
|
||||||
|
|
||||||
// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
|
|
||||||
// Centers the window on the monitor the window is currently on.
|
|
||||||
export function WindowCenter(): void;
|
|
||||||
|
|
||||||
// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
|
|
||||||
// Sets the text in the window title bar.
|
|
||||||
export function WindowSetTitle(title: string): void;
|
|
||||||
|
|
||||||
// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
|
|
||||||
// Makes the window full screen.
|
|
||||||
export function WindowFullscreen(): void;
|
|
||||||
|
|
||||||
// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
|
|
||||||
// Restores the previous window dimensions and position prior to full screen.
|
|
||||||
export function WindowUnfullscreen(): void;
|
|
||||||
|
|
||||||
// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
|
|
||||||
// Returns the state of the window, i.e. whether the window is in full screen mode or not.
|
|
||||||
export function WindowIsFullscreen(): Promise<boolean>;
|
|
||||||
|
|
||||||
// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
|
|
||||||
// Sets the width and height of the window.
|
|
||||||
export function WindowSetSize(width: number, height: number): void;
|
|
||||||
|
|
||||||
// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
|
|
||||||
// Gets the width and height of the window.
|
|
||||||
export function WindowGetSize(): Promise<Size>;
|
|
||||||
|
|
||||||
// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
|
|
||||||
// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
|
|
||||||
// Setting a size of 0,0 will disable this constraint.
|
|
||||||
export function WindowSetMaxSize(width: number, height: number): void;
|
|
||||||
|
|
||||||
// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
|
|
||||||
// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
|
|
||||||
// Setting a size of 0,0 will disable this constraint.
|
|
||||||
export function WindowSetMinSize(width: number, height: number): void;
|
|
||||||
|
|
||||||
// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
|
|
||||||
// Sets the window position relative to the monitor the window is currently on.
|
|
||||||
export function WindowSetPosition(x: number, y: number): void;
|
|
||||||
|
|
||||||
// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
|
|
||||||
// Gets the window position relative to the monitor the window is currently on.
|
|
||||||
export function WindowGetPosition(): Promise<Position>;
|
|
||||||
|
|
||||||
// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
|
|
||||||
// Hides the window.
|
|
||||||
export function WindowHide(): void;
|
|
||||||
|
|
||||||
// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
|
|
||||||
// Shows the window, if it is currently hidden.
|
|
||||||
export function WindowShow(): void;
|
|
||||||
|
|
||||||
// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
|
|
||||||
// Maximises the window to fill the screen.
|
|
||||||
export function WindowMaximise(): void;
|
|
||||||
|
|
||||||
// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
|
|
||||||
// Toggles between Maximised and UnMaximised.
|
|
||||||
export function WindowToggleMaximise(): void;
|
|
||||||
|
|
||||||
// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
|
|
||||||
// Restores the window to the dimensions and position prior to maximising.
|
|
||||||
export function WindowUnmaximise(): void;
|
|
||||||
|
|
||||||
// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
|
|
||||||
// Returns the state of the window, i.e. whether the window is maximised or not.
|
|
||||||
export function WindowIsMaximised(): Promise<boolean>;
|
|
||||||
|
|
||||||
// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
|
|
||||||
// Minimises the window.
|
|
||||||
export function WindowMinimise(): void;
|
|
||||||
|
|
||||||
// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
|
|
||||||
// Restores the window to the dimensions and position prior to minimising.
|
|
||||||
export function WindowUnminimise(): void;
|
|
||||||
|
|
||||||
// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
|
|
||||||
// Returns the state of the window, i.e. whether the window is minimised or not.
|
|
||||||
export function WindowIsMinimised(): Promise<boolean>;
|
|
||||||
|
|
||||||
// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
|
|
||||||
// Returns the state of the window, i.e. whether the window is normal or not.
|
|
||||||
export function WindowIsNormal(): Promise<boolean>;
|
|
||||||
|
|
||||||
// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
|
|
||||||
// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
|
|
||||||
export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
|
|
||||||
|
|
||||||
// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
|
|
||||||
// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
|
|
||||||
export function ScreenGetAll(): Promise<Screen[]>;
|
|
||||||
|
|
||||||
// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
|
|
||||||
// Opens the given URL in the system browser.
|
|
||||||
export function BrowserOpenURL(url: string): void;
|
|
||||||
|
|
||||||
// [Environment](https://wails.io/docs/reference/runtime/intro#environment)
|
|
||||||
// Returns information about the environment
|
|
||||||
export function Environment(): Promise<EnvironmentInfo>;
|
|
||||||
|
|
||||||
// [Quit](https://wails.io/docs/reference/runtime/intro#quit)
|
|
||||||
// Quits the application.
|
|
||||||
export function Quit(): void;
|
|
||||||
|
|
||||||
// [Hide](https://wails.io/docs/reference/runtime/intro#hide)
|
|
||||||
// Hides the application.
|
|
||||||
export function Hide(): void;
|
|
||||||
|
|
||||||
// [Show](https://wails.io/docs/reference/runtime/intro#show)
|
|
||||||
// Shows the application.
|
|
||||||
export function Show(): void;
|
|
||||||
|
|
||||||
// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
|
|
||||||
// Returns the current text stored on clipboard
|
|
||||||
export function ClipboardGetText(): Promise<string>;
|
|
||||||
|
|
||||||
// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
|
|
||||||
// Sets a text on the clipboard
|
|
||||||
export function ClipboardSetText(text: string): Promise<boolean>;
|
|
||||||
|
|
||||||
// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
|
|
||||||
// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
|
||||||
export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
|
|
||||||
|
|
||||||
// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
|
|
||||||
// OnFileDropOff removes the drag and drop listeners and handlers.
|
|
||||||
export function OnFileDropOff() :void
|
|
||||||
|
|
||||||
// Check if the file path resolver is available
|
|
||||||
export function CanResolveFilePaths(): boolean;
|
|
||||||
|
|
||||||
// Resolves file paths for an array of files
|
|
||||||
export function ResolveFilePaths(files: File[]): void
|
|
||||||
|
|
||||||
// Notification types
|
|
||||||
export interface NotificationOptions {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
subtitle?: string; // macOS and Linux only
|
|
||||||
body?: string;
|
|
||||||
categoryId?: string;
|
|
||||||
data?: { [key: string]: any };
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotificationAction {
|
|
||||||
id?: string;
|
|
||||||
title?: string;
|
|
||||||
destructive?: boolean; // macOS-specific
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NotificationCategory {
|
|
||||||
id?: string;
|
|
||||||
actions?: NotificationAction[];
|
|
||||||
hasReplyField?: boolean;
|
|
||||||
replyPlaceholder?: string;
|
|
||||||
replyButtonTitle?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [InitializeNotifications](https://wails.io/docs/reference/runtime/notification#initializenotifications)
|
|
||||||
// Initializes the notification service for the application.
|
|
||||||
// This must be called before sending any notifications.
|
|
||||||
export function InitializeNotifications(): Promise<void>;
|
|
||||||
|
|
||||||
// [CleanupNotifications](https://wails.io/docs/reference/runtime/notification#cleanupnotifications)
|
|
||||||
// Cleans up notification resources and releases any held connections.
|
|
||||||
export function CleanupNotifications(): Promise<void>;
|
|
||||||
|
|
||||||
// [IsNotificationAvailable](https://wails.io/docs/reference/runtime/notification#isnotificationavailable)
|
|
||||||
// Checks if notifications are available on the current platform.
|
|
||||||
export function IsNotificationAvailable(): Promise<boolean>;
|
|
||||||
|
|
||||||
// [RequestNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#requestnotificationauthorization)
|
|
||||||
// Requests notification authorization from the user (macOS only).
|
|
||||||
export function RequestNotificationAuthorization(): Promise<boolean>;
|
|
||||||
|
|
||||||
// [CheckNotificationAuthorization](https://wails.io/docs/reference/runtime/notification#checknotificationauthorization)
|
|
||||||
// Checks the current notification authorization status (macOS only).
|
|
||||||
export function CheckNotificationAuthorization(): Promise<boolean>;
|
|
||||||
|
|
||||||
// [SendNotification](https://wails.io/docs/reference/runtime/notification#sendnotification)
|
|
||||||
// Sends a basic notification with the given options.
|
|
||||||
export function SendNotification(options: NotificationOptions): Promise<void>;
|
|
||||||
|
|
||||||
// [SendNotificationWithActions](https://wails.io/docs/reference/runtime/notification#sendnotificationwithactions)
|
|
||||||
// Sends a notification with action buttons. Requires a registered category.
|
|
||||||
export function SendNotificationWithActions(options: NotificationOptions): Promise<void>;
|
|
||||||
|
|
||||||
// [RegisterNotificationCategory](https://wails.io/docs/reference/runtime/notification#registernotificationcategory)
|
|
||||||
// Registers a notification category that can be used with SendNotificationWithActions.
|
|
||||||
export function RegisterNotificationCategory(category: NotificationCategory): Promise<void>;
|
|
||||||
|
|
||||||
// [RemoveNotificationCategory](https://wails.io/docs/reference/runtime/notification#removenotificationcategory)
|
|
||||||
// Removes a previously registered notification category.
|
|
||||||
export function RemoveNotificationCategory(categoryId: string): Promise<void>;
|
|
||||||
|
|
||||||
// [RemoveAllPendingNotifications](https://wails.io/docs/reference/runtime/notification#removeallpendingnotifications)
|
|
||||||
// Removes all pending notifications from the notification center.
|
|
||||||
export function RemoveAllPendingNotifications(): Promise<void>;
|
|
||||||
|
|
||||||
// [RemovePendingNotification](https://wails.io/docs/reference/runtime/notification#removependingnotification)
|
|
||||||
// Removes a specific pending notification by its identifier.
|
|
||||||
export function RemovePendingNotification(identifier: string): Promise<void>;
|
|
||||||
|
|
||||||
// [RemoveAllDeliveredNotifications](https://wails.io/docs/reference/runtime/notification#removealldeliverednotifications)
|
|
||||||
// Removes all delivered notifications from the notification center.
|
|
||||||
export function RemoveAllDeliveredNotifications(): Promise<void>;
|
|
||||||
|
|
||||||
// [RemoveDeliveredNotification](https://wails.io/docs/reference/runtime/notification#removedeliverednotification)
|
|
||||||
// Removes a specific delivered notification by its identifier.
|
|
||||||
export function RemoveDeliveredNotification(identifier: string): Promise<void>;
|
|
||||||
|
|
||||||
// [RemoveNotification](https://wails.io/docs/reference/runtime/notification#removenotification)
|
|
||||||
// Removes a notification by its identifier (cross-platform convenience function).
|
|
||||||
export function RemoveNotification(identifier: string): Promise<void>;
|
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
/*
|
|
||||||
_ __ _ __
|
|
||||||
| | / /___ _(_) /____
|
|
||||||
| | /| / / __ `/ / / ___/
|
|
||||||
| |/ |/ / /_/ / / (__ )
|
|
||||||
|__/|__/\__,_/_/_/____/
|
|
||||||
The electron alternative for Go
|
|
||||||
(c) Lea Anthony 2019-present
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function LogPrint(message) {
|
|
||||||
window.runtime.LogPrint(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LogTrace(message) {
|
|
||||||
window.runtime.LogTrace(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LogDebug(message) {
|
|
||||||
window.runtime.LogDebug(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LogInfo(message) {
|
|
||||||
window.runtime.LogInfo(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LogWarning(message) {
|
|
||||||
window.runtime.LogWarning(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LogError(message) {
|
|
||||||
window.runtime.LogError(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LogFatal(message) {
|
|
||||||
window.runtime.LogFatal(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EventsOnMultiple(eventName, callback, maxCallbacks) {
|
|
||||||
return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EventsOn(eventName, callback) {
|
|
||||||
return EventsOnMultiple(eventName, callback, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EventsOff(eventName, ...additionalEventNames) {
|
|
||||||
return window.runtime.EventsOff(eventName, ...additionalEventNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EventsOffAll() {
|
|
||||||
return window.runtime.EventsOffAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EventsOnce(eventName, callback) {
|
|
||||||
return EventsOnMultiple(eventName, callback, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function EventsEmit(eventName) {
|
|
||||||
let args = [eventName].slice.call(arguments);
|
|
||||||
return window.runtime.EventsEmit.apply(null, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowReload() {
|
|
||||||
window.runtime.WindowReload();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowReloadApp() {
|
|
||||||
window.runtime.WindowReloadApp();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetAlwaysOnTop(b) {
|
|
||||||
window.runtime.WindowSetAlwaysOnTop(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetSystemDefaultTheme() {
|
|
||||||
window.runtime.WindowSetSystemDefaultTheme();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetLightTheme() {
|
|
||||||
window.runtime.WindowSetLightTheme();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetDarkTheme() {
|
|
||||||
window.runtime.WindowSetDarkTheme();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowCenter() {
|
|
||||||
window.runtime.WindowCenter();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetTitle(title) {
|
|
||||||
window.runtime.WindowSetTitle(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowFullscreen() {
|
|
||||||
window.runtime.WindowFullscreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowUnfullscreen() {
|
|
||||||
window.runtime.WindowUnfullscreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowIsFullscreen() {
|
|
||||||
return window.runtime.WindowIsFullscreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowGetSize() {
|
|
||||||
return window.runtime.WindowGetSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetSize(width, height) {
|
|
||||||
window.runtime.WindowSetSize(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetMaxSize(width, height) {
|
|
||||||
window.runtime.WindowSetMaxSize(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetMinSize(width, height) {
|
|
||||||
window.runtime.WindowSetMinSize(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetPosition(x, y) {
|
|
||||||
window.runtime.WindowSetPosition(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowGetPosition() {
|
|
||||||
return window.runtime.WindowGetPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowHide() {
|
|
||||||
window.runtime.WindowHide();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowShow() {
|
|
||||||
window.runtime.WindowShow();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowMaximise() {
|
|
||||||
window.runtime.WindowMaximise();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowToggleMaximise() {
|
|
||||||
window.runtime.WindowToggleMaximise();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowUnmaximise() {
|
|
||||||
window.runtime.WindowUnmaximise();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowIsMaximised() {
|
|
||||||
return window.runtime.WindowIsMaximised();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowMinimise() {
|
|
||||||
window.runtime.WindowMinimise();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowUnminimise() {
|
|
||||||
window.runtime.WindowUnminimise();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowSetBackgroundColour(R, G, B, A) {
|
|
||||||
window.runtime.WindowSetBackgroundColour(R, G, B, A);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ScreenGetAll() {
|
|
||||||
return window.runtime.ScreenGetAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowIsMinimised() {
|
|
||||||
return window.runtime.WindowIsMinimised();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function WindowIsNormal() {
|
|
||||||
return window.runtime.WindowIsNormal();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function BrowserOpenURL(url) {
|
|
||||||
window.runtime.BrowserOpenURL(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Environment() {
|
|
||||||
return window.runtime.Environment();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Quit() {
|
|
||||||
window.runtime.Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Hide() {
|
|
||||||
window.runtime.Hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Show() {
|
|
||||||
window.runtime.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ClipboardGetText() {
|
|
||||||
return window.runtime.ClipboardGetText();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ClipboardSetText(text) {
|
|
||||||
return window.runtime.ClipboardSetText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @callback OnFileDropCallback
|
|
||||||
* @param {number} x - x coordinate of the drop
|
|
||||||
* @param {number} y - y coordinate of the drop
|
|
||||||
* @param {string[]} paths - A list of file paths.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
|
||||||
*
|
|
||||||
* @export
|
|
||||||
* @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
|
||||||
* @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target)
|
|
||||||
*/
|
|
||||||
export function OnFileDrop(callback, useDropTarget) {
|
|
||||||
return window.runtime.OnFileDrop(callback, useDropTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OnFileDropOff removes the drag and drop listeners and handlers.
|
|
||||||
*/
|
|
||||||
export function OnFileDropOff() {
|
|
||||||
return window.runtime.OnFileDropOff();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CanResolveFilePaths() {
|
|
||||||
return window.runtime.CanResolveFilePaths();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ResolveFilePaths(files) {
|
|
||||||
return window.runtime.ResolveFilePaths(files);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function InitializeNotifications() {
|
|
||||||
return window.runtime.InitializeNotifications();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CleanupNotifications() {
|
|
||||||
return window.runtime.CleanupNotifications();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function IsNotificationAvailable() {
|
|
||||||
return window.runtime.IsNotificationAvailable();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RequestNotificationAuthorization() {
|
|
||||||
return window.runtime.RequestNotificationAuthorization();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CheckNotificationAuthorization() {
|
|
||||||
return window.runtime.CheckNotificationAuthorization();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SendNotification(options) {
|
|
||||||
return window.runtime.SendNotification(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SendNotificationWithActions(options) {
|
|
||||||
return window.runtime.SendNotificationWithActions(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RegisterNotificationCategory(category) {
|
|
||||||
return window.runtime.RegisterNotificationCategory(category);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RemoveNotificationCategory(categoryId) {
|
|
||||||
return window.runtime.RemoveNotificationCategory(categoryId);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RemoveAllPendingNotifications() {
|
|
||||||
return window.runtime.RemoveAllPendingNotifications();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RemovePendingNotification(identifier) {
|
|
||||||
return window.runtime.RemovePendingNotification(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RemoveAllDeliveredNotifications() {
|
|
||||||
return window.runtime.RemoveAllDeliveredNotifications();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RemoveDeliveredNotification(identifier) {
|
|
||||||
return window.runtime.RemoveDeliveredNotification(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function RemoveNotification(identifier) {
|
|
||||||
return window.runtime.RemoveNotification(identifier);
|
|
||||||
}
|
|
||||||
1
go.mod
1
go.mod
@@ -5,6 +5,7 @@ go 1.26
|
|||||||
require (
|
require (
|
||||||
github.com/chromedp/cdproto v0.0.0-20260427013145-5737772c319b
|
github.com/chromedp/cdproto v0.0.0-20260427013145-5737772c319b
|
||||||
github.com/chromedp/chromedp v0.15.1
|
github.com/chromedp/chromedp v0.15.1
|
||||||
|
github.com/fsnotify/fsnotify v1.10.1
|
||||||
github.com/glebarez/sqlite v1.11.0
|
github.com/glebarez/sqlite v1.11.0
|
||||||
github.com/labstack/echo/v4 v4.15.1
|
github.com/labstack/echo/v4 v4.15.1
|
||||||
github.com/pkg/sftp v1.13.10
|
github.com/pkg/sftp v1.13.10
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -36,6 +36,8 @@ github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o
|
|||||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
|
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||||
|
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||||
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
|
||||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||||
|
|||||||
@@ -268,6 +268,11 @@ func (s *FileSystemService) DeletePathWithContext(ctx context.Context, path stri
|
|||||||
|
|
||||||
// ListDir 列出目录内容
|
// ListDir 列出目录内容
|
||||||
func (s *FileSystemService) ListDir(path string) ([]map[string]interface{}, error) {
|
func (s *FileSystemService) ListDir(path string) ([]map[string]interface{}, error) {
|
||||||
|
// 根路径:返回 Windows 盘符列表
|
||||||
|
if path == "/" || path == "\\" {
|
||||||
|
return s.listDrives()
|
||||||
|
}
|
||||||
|
|
||||||
// 路径验证
|
// 路径验证
|
||||||
if err := s.validatePath(path); err != nil {
|
if err := s.validatePath(path); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -308,6 +313,25 @@ func (s *FileSystemService) ListDir(path string) ([]map[string]interface{}, erro
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// listDrives 列出 Windows 可用盘符
|
||||||
|
func (s *FileSystemService) listDrives() ([]map[string]interface{}, error) {
|
||||||
|
result := make([]map[string]interface{}, 0)
|
||||||
|
for _, drive := range "ABCDEFGHIJKLMNOPQRSTUVWXYZ" {
|
||||||
|
path := string(drive) + ":/"
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, map[string]interface{}{
|
||||||
|
"name": string(drive) + ":",
|
||||||
|
"path": path,
|
||||||
|
"is_dir": true,
|
||||||
|
"size": int64(0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateDir 创建目录,返回创建的目录信息
|
// CreateDir 创建目录,返回创建的目录信息
|
||||||
func (s *FileSystemService) CreateDir(path string) (*FileOperationResult, error) {
|
func (s *FileSystemService) CreateDir(path string) (*FileOperationResult, error) {
|
||||||
if err := s.validatePath(path); err != nil {
|
if err := s.validatePath(path); err != nil {
|
||||||
|
|||||||
138
internal/filewatch/watcher.go
Normal file
138
internal/filewatch/watcher.go
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
package filewatch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fsnotify/fsnotify"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Watcher struct {
|
||||||
|
watcher *fsnotify.Watcher
|
||||||
|
emitEvent func(name string, data ...any)
|
||||||
|
mu sync.Mutex
|
||||||
|
watched string // 当前监听的文件绝对路径
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWatcher(emitEvent func(name string, data ...any)) *Watcher {
|
||||||
|
return &Watcher{emitEvent: emitEvent}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchFile 开始监听指定文件的变化。切换文件时自动取消旧监听。
|
||||||
|
func (w *Watcher) WatchFile(path string) error {
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
|
||||||
|
absPath, err := filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("解析路径失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同一文件不重复监听
|
||||||
|
if absPath == w.watched {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止旧监听
|
||||||
|
w.stopLocked()
|
||||||
|
|
||||||
|
// 检查文件是否存在
|
||||||
|
if _, err := os.Stat(absPath); err != nil {
|
||||||
|
return fmt.Errorf("文件不存在: %s", absPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 fsnotify watcher
|
||||||
|
fw, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("创建文件监听器失败: %w", err)
|
||||||
|
}
|
||||||
|
w.watcher = fw
|
||||||
|
|
||||||
|
// fsnotify 在某些系统上不支持直接监听文件,监听其所在目录
|
||||||
|
dir := filepath.Dir(absPath)
|
||||||
|
if err := fw.Add(dir); err != nil {
|
||||||
|
fw.Close()
|
||||||
|
return fmt.Errorf("监听目录失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w.watched = absPath
|
||||||
|
|
||||||
|
// 后台消费事件
|
||||||
|
go w.consumeEvents()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnwatchFile 停止监听
|
||||||
|
func (w *Watcher) UnwatchFile() {
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
w.stopLocked()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) stopLocked() {
|
||||||
|
if w.watcher != nil {
|
||||||
|
w.watcher.Close()
|
||||||
|
w.watcher = nil
|
||||||
|
}
|
||||||
|
w.watched = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Watcher) consumeEvents() {
|
||||||
|
debounceDelay := 300 * time.Millisecond
|
||||||
|
var debounceTimer *time.Timer
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event, ok := <-w.watcher.Events:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 只处理目标文件的 Write/Create/Rename 事件
|
||||||
|
if event.Op&(fsnotify.Write|fsnotify.Create|fsnotify.Rename) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
w.mu.Lock()
|
||||||
|
target := w.watched
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
if target == "" {
|
||||||
|
return // 已停止监听
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路径比较(忽略大小写,Windows)
|
||||||
|
if !strings.EqualFold(event.Name, target) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防抖
|
||||||
|
if debounceTimer != nil {
|
||||||
|
debounceTimer.Stop()
|
||||||
|
}
|
||||||
|
debounceTimer = time.AfterFunc(debounceDelay, func() {
|
||||||
|
// 文件已不存在则跳过(如被删除)
|
||||||
|
if _, err := os.Stat(target); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if w.emitEvent != nil {
|
||||||
|
w.emitEvent("file-changed", target)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
case _, ok := <-w.watcher.Errors:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close 释放资源
|
||||||
|
func (w *Watcher) Close() {
|
||||||
|
w.UnwatchFile()
|
||||||
|
}
|
||||||
35
main.go
35
main.go
@@ -2,8 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"os"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v3/pkg/application"
|
"github.com/wailsapp/wails/v3/pkg/application"
|
||||||
"u-desk/internal/hotkey"
|
"u-desk/internal/hotkey"
|
||||||
@@ -14,8 +15,9 @@ var assets embed.FS
|
|||||||
|
|
||||||
// 标题栏颜色(0x00BBGGRR)
|
// 标题栏颜色(0x00BBGGRR)
|
||||||
var (
|
var (
|
||||||
titleBarLight = uint32(0xF0F0F0) // #F0F0F0 近白
|
titleBarLight = uint32(0xF0F0F0) // #F0F0F0 近白
|
||||||
titleBarDark = uint32(0x2D2D2D) // #2D2D2D 深灰
|
titleBarDark = uint32(0x2D2D2D) // #2D2D2D 深灰
|
||||||
|
noBorder = uint32(0xFFFFFFFE) // DWMWA_COLOR_NONE - Win11 抑制边框绘制
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -24,6 +26,9 @@ func main() {
|
|||||||
wailsApp := application.New(application.Options{
|
wailsApp := application.New(application.Options{
|
||||||
Name: "U-Desk",
|
Name: "U-Desk",
|
||||||
Description: "桌面文件管理器",
|
Description: "桌面文件管理器",
|
||||||
|
SingleInstance: &application.SingleInstanceOptions{
|
||||||
|
UniqueID: "top.1216.udesk",
|
||||||
|
},
|
||||||
Services: []application.Service{
|
Services: []application.Service{
|
||||||
application.NewService(app),
|
application.NewService(app),
|
||||||
},
|
},
|
||||||
@@ -32,7 +37,6 @@ func main() {
|
|||||||
Middleware: func(next http.Handler) http.Handler {
|
Middleware: func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
if req.URL.Path == "/wails/custom.js" {
|
if req.URL.Path == "/wails/custom.js" {
|
||||||
// custom.js 未使用,返回空响应避免 404 控制台报错
|
|
||||||
rw.Header().Set("Content-Type", "application/javascript")
|
rw.Header().Set("Content-Type", "application/javascript")
|
||||||
rw.WriteHeader(200)
|
rw.WriteHeader(200)
|
||||||
return
|
return
|
||||||
@@ -67,20 +71,27 @@ func main() {
|
|||||||
Height: 900,
|
Height: 900,
|
||||||
MinWidth: 1000,
|
MinWidth: 1000,
|
||||||
MinHeight: 600,
|
MinHeight: 600,
|
||||||
BackgroundColour: application.NewRGB(255, 255, 255),
|
BackgroundColour: application.NewRGB(45, 45, 45),
|
||||||
URL: "/",
|
URL: "/",
|
||||||
Frameless: true,
|
Frameless: true,
|
||||||
// 保留 Windows 11 原生装饰(圆角 + Aero 阴影)
|
|
||||||
Windows: application.WindowsWindow{
|
Windows: application.WindowsWindow{
|
||||||
Theme: application.SystemDefault,
|
Theme: application.SystemDefault,
|
||||||
CustomTheme: application.ThemeSettings{
|
CustomTheme: application.ThemeSettings{
|
||||||
LightModeActive: &application.WindowTheme{
|
LightModeActive: &application.WindowTheme{
|
||||||
TitleBarColour: &titleBarLight,
|
TitleBarColour: &titleBarLight,
|
||||||
BorderColour: &titleBarLight,
|
BorderColour: &noBorder,
|
||||||
|
},
|
||||||
|
LightModeInactive: &application.WindowTheme{
|
||||||
|
TitleBarColour: &titleBarLight,
|
||||||
|
BorderColour: &noBorder,
|
||||||
},
|
},
|
||||||
DarkModeActive: &application.WindowTheme{
|
DarkModeActive: &application.WindowTheme{
|
||||||
TitleBarColour: &titleBarDark,
|
TitleBarColour: &titleBarDark,
|
||||||
BorderColour: &titleBarDark,
|
BorderColour: &noBorder,
|
||||||
|
},
|
||||||
|
DarkModeInactive: &application.WindowTheme{
|
||||||
|
TitleBarColour: &titleBarDark,
|
||||||
|
BorderColour: &noBorder,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -88,15 +99,7 @@ func main() {
|
|||||||
|
|
||||||
app.SetMainWindow(window)
|
app.SetMainWindow(window)
|
||||||
|
|
||||||
// production+devtools 模式下 OpenInspectorOnStartup 不生效(需 debugMode=true)
|
|
||||||
// 手动延迟调用 OpenDevTools 弹出 Inspector
|
|
||||||
// TODO: 替换为 OnDomReady 回调,当前 alpha.80 可能未稳定支持
|
|
||||||
go func() {
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
window.OpenDevTools()
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := wailsApp.Run(); err != nil {
|
if err := wailsApp.Run(); err != nil {
|
||||||
println("Error:", err.Error())
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user