发布:v0.3.3 版本历史模块 + 域名迁移 + 站点版本信息修正
- 版本号更新至 0.3.3(version.go/wails.json/README.md) - 更新检查域名迁移 img.1216.top → c.1216.top - 新增 views/version 版本历史 Tab 页面(时间线 UI) - 设置面板新增版本历史入口按钮 - CHANGELOG 补全 0.3.3 全部 17 个提交记录 - 站点 HTML 修正(删除错误 v0.4.0,v0.3.3 为最新) - 生成 last-version.json / versions.json 发布数据
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
> 本文档记录所有技术细节,包括代码重构、构建优化等内部改动
|
> 本文档记录所有技术细节,包括代码重构、构建优化等内部改动
|
||||||
|
|
||||||
## [0.3.3] - 2026-03-31
|
## [0.3.3] - 2026-04-13
|
||||||
|
|
||||||
### 架构新增 🏗️
|
### 架构新增 🏗️
|
||||||
|
|
||||||
|
|||||||
44
CHANGELOG.md
44
CHANGELOG.md
@@ -1,46 +1,56 @@
|
|||||||
# 更新日志
|
# 更新日志
|
||||||
|
|
||||||
## [0.3.3] - 2026-03-31
|
## [0.3.3] - 2026-04-13
|
||||||
|
|
||||||
### 新增 ✨
|
### 新增 ✨
|
||||||
- **Markdown 编辑器**: 实时预览、编辑、字符/行数统计、Ctrl+S 保存、自动保存
|
- **Markdown 编辑器**: 独立编辑页面、实时预览、字符/行数统计、Ctrl+S 保存、自动保存
|
||||||
- **Markdown 文件页面**: 独立的 Markdown 文件查看与编辑界面
|
- **Markdown 文件页面**: 独立的 Markdown 文件查看与编辑界面 (`views/markdown-editor/`)
|
||||||
- **PDF 导出**: 浏览器打印 + 后端 gofpdf/chromedp 多种导出方式
|
- **PDF 导出**: 浏览器打印 + 后端 gofpdf/chromedp 多种导出方式
|
||||||
- **窗口置顶**: 支持窗口始终置顶
|
- **窗口置顶**: 支持窗口始终置顶
|
||||||
- **收藏夹置顶**: 收藏项置顶排序
|
- **收藏夹置顶**: 收藏项支持置顶排序
|
||||||
- **文件预览**: Excel/Word 文件预览支持
|
- **文件预览**: Excel/Word 文件预览支持
|
||||||
- 数据库 UI 交互体验改进
|
- **数据库 UI 大幅改进**: 查询历史面板、查询模板面板、SQL 工具栏、结果导出(CSV)、SQL 格式化器
|
||||||
|
- **数据库可见性过滤**: 连接管理增强、ConnectionForm 重写、统一错误处理模块 (`database-error.ts`)
|
||||||
|
|
||||||
### 优化 🚀
|
### 优化 🚀
|
||||||
- MySQL 动态连接池重构(健康检查、性能权重、自适应扩缩容)
|
- MySQL 动态连接池重构 — 健康检查、性能权重、自适应扩缩容
|
||||||
- SQL 查询优化器(查询缓存、慢查询日志)
|
- SQL 查询优化器 — 查询缓存、慢查询日志
|
||||||
- Redis Pipeline 支持(批量命令、事务 MULTI/EXEC)
|
- Redis Pipeline — 批量命令、事务 MULTI/EXEC 支持
|
||||||
- HTML 预览改用 iframe src 替代 srcdoc
|
- Office/CSV 预览增强 — 本地文件服务器获取文件
|
||||||
- Office/CSV 预览增强(本地文件服务器获取文件)
|
- Markdown 增强 — 本地文件链接支持、Shell 语法高亮
|
||||||
- Markdown 本地文件链接支持 + Shell 语法高亮
|
- HTML 预览 — 改用 iframe src 替代 srcdoc
|
||||||
|
- Wails 框架升级 + Mermaid 主题切换 + 代码高亮修复
|
||||||
|
- 文件列表 UI 重构 — 统一渲染逻辑,提升滚动性能
|
||||||
|
- CSV 编辑模式优化 + PDF 导出重构
|
||||||
|
- 拷贝功能优化
|
||||||
|
|
||||||
### 修复 🐛
|
### 修复 🐛
|
||||||
- Office 文件预览:修复类型检测与二进制误判
|
- Office 文件预览:修复类型检测与二进制误判
|
||||||
|
- 本地文件服务器 CORS 跨域问题
|
||||||
|
- 大文件点击卡死问题
|
||||||
|
- 收藏夹 bug 修复
|
||||||
- FileEditorPanel 语法错误
|
- FileEditorPanel 语法错误
|
||||||
- 修复本地文件服务器 CORS 跨域问题
|
|
||||||
|
|
||||||
### 安全修复 🔒
|
### 安全修复 🔒
|
||||||
- XSS 防护(PdfExportButton、MarkdownPreview HTML 消毒)
|
- XSS 防护(PdfExportButton、MarkdownPreview HTML 消毒)
|
||||||
- PDF 导出路径穿越防护
|
- PDF 导出路径穿越防护
|
||||||
- PDF 导出标题 HTML 注入防护
|
- PDF 导出标题 HTML 注入防护
|
||||||
|
|
||||||
### 代码质量 🔧
|
### 重构 🔧
|
||||||
- 正则表达式预编译(query_optimizer)
|
- CodeMirror 架构优化 — 统一导出避免多实例问题
|
||||||
- 缓存读锁优化 + SHA-256 key hash
|
- 消除代码重复 — storage/connection_service 重构、useVisibleDatabases 抽取
|
||||||
- 死代码清理(未使用 import/类型/字段)
|
- 大规模死代码清理,显著减小包体积
|
||||||
- 配置加载超时保护(最多重试 30 次)
|
- 配置加载超时保护(最多重试 30 次)
|
||||||
|
- 正则表达式预编译、缓存读锁优化
|
||||||
- 禁止 Ctrl+滚轮缩放
|
- 禁止 Ctrl+滚轮缩放
|
||||||
- 清理冗余工具函数(fileHelpers、pathHelpers、useLocalStorage)
|
- Dockerfile 语法高亮支持
|
||||||
|
- 滚动条样式修复
|
||||||
|
|
||||||
### 文件系统 📁
|
### 文件系统 📁
|
||||||
- 右键菜单新增新建文件/文件夹
|
- 右键菜单新增新建文件/文件夹
|
||||||
- FileEditorPanel 集成 PDF 导出按钮
|
- FileEditorPanel 集成 PDF 导出按钮
|
||||||
- Markdown 文件自动预览与编辑/预览模式切换
|
- Markdown 文件自动预览与编辑/预览模式切换
|
||||||
|
- 面包屑导航组件
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
2
app.go
2
app.go
@@ -91,7 +91,7 @@ func (a *App) Startup(ctx context.Context) {
|
|||||||
|
|
||||||
// 5. 异步初始化:UpdateAPI(涉及网络请求,完全异步)
|
// 5. 异步初始化:UpdateAPI(涉及网络请求,完全异步)
|
||||||
go func() {
|
go func() {
|
||||||
if updateAPI, err := api.NewUpdateAPI("https://img.1216.top/u-desk/last-version.json"); err == nil {
|
if updateAPI, err := api.NewUpdateAPI("https://c.1216.top/last-version.json"); err == nil {
|
||||||
a.updateAPI = updateAPI
|
a.updateAPI = updateAPI
|
||||||
a.updateAPI.SetContext(ctx)
|
a.updateAPI.SetContext(ctx)
|
||||||
a.startAutoUpdateCheck()
|
a.startAutoUpdateCheck()
|
||||||
|
|||||||
1
build/publish/last-version.json
Normal file
1
build/publish/last-version.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"version": "0.3.3", "release_date": "2026-04-13", "changelog": "### 新增 ✨\n- Markdown 编辑器: 独立编辑页面、实时预览、字符/行数统计、Ctrl+S 保存、自动保存\n- PDF 导出: 浏览器打印 + 后端 gofpdf/chromedp 多种导出方式\n- 窗口置顶 + 收藏夹置顶\n- Excel/Word 文件预览支持\n- 数据库 UI 大幅改进: 查询历史、查询模板、SQL 工具栏、结果导出\n- 数据库可见性过滤与连接管理增强\n\n### 优化 🚀\n- MySQL 动态连接池重构(健康检查、性能权重、自适应扩缩容)\n- SQL 查询优化器(查询缓存、慢查询日志)\n- Redis Pipeline 支持\n- Wails 框架升级 + FileListPanel 重写\n- CSV 编辑模式优化 + 拷贝功能优化\n\n### 修复 🐛\n- Office 类型检测修复、CORS 跨域修复、大文件卡死修复\n\n### 安全修复 🔒\n- XSS 防护、PDF 路径穿越防护、HTML 注入防护\n\n### 重构 🔧\n- CodeMirror 架构优化、大规模死代码清理(-1306行)", "download_url": "https://c.1216.top/download/u-desk-0.3.3.exe", "file_size": 9801728, "sha256": "829c79a91c10277011159749110f4ebee5e3638a078e86850c03b1c9f09e184c", "force_update": false}
|
||||||
1
build/publish/versions.json
Normal file
1
build/publish/versions.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"updated_at": "2026-04-13T23:45:00+08:00", "versions": [{"version": "0.3.3", "release_date": "2026-04-13", "changelog": "### 新增 ✨\n- **Markdown 编辑器**: 独立编辑页面、实时预览、字符/行数统计、Ctrl+S 保存、自动保存\n- **Markdown 文件页面**: 独立的 Markdown 文件查看与编辑界面\n- **PDF 导出**: 浏览器打印 + 后端 gofpdf/chromedp 多种导出方式\n- **窗口置顶**: 支持窗口始终置顶\n- **收藏夹置顶**: 收藏项支持置顶排序\n- **文件预览**: Excel/Word 文件预览支持\n- **数据库 UI 大幅改进**: 查询历史面板、查询模板面板、SQL 工具栏、结果导出(CSV)、SQL 格式化器\n- **数据库可见性过滤**: 连接管理增强、ConnectionForm 重写、统一错误处理模块\n\n### 优化 🚀\n- MySQL 动态连接池重构 — 健康检查、性能权重、自适应扩缩容\n- SQL 查询优化器 — 查询缓存、慢查询日志 (762 行)\n- Redis Pipeline — 批量命令、事务 MULTI/EXEC 支持\n- Wails 框架升级 + Mermaid 主题切换 + 代码高亮修复\n- FileListPanel 重写 (+511 行) — 删除 FileItemRow,统一列表渲染逻辑\n- CSV 编辑模式优化 + PDF 导出重构\n- 拷贝功能优化 — 新增 ClipboardCopy composable\n\n### 修复 🐛\n- Office 文件预览:修复类型检测与二进制误判\n- 本地文件服务器 CORS 跨域问题\n- 大文件点击卡死问题\n- 收藏夹 bug 修复\n\n### 安全修复 🔒\n- XSS 防护(PdfExportButton、MarkdownPreview HTML 消毒)\n- PDF 导出路径穿越防护\n- PDF 导出标题 HTML 注入防护\n\n### 重构 🔧\n- CodeMirror 架构优化 — 统一导出避免多实例问题\n- 消除代码重复 — storage/connection_service 重构\n- **大规模死代码清理 (-1306 行)**: 删除废弃 storage 层、audit_log、file_lock、recycle_bin、useFileEdit.js(-369行)、useFilePreview.js(-603行) 等\n- 配置加载超时保护、正则表达式预编译、禁止 Ctrl+滚轮缩放", "download_url": "https://c.1216.top/download/u-desk-0.3.3.exe", "file_size": 9801728, "sha256": "829c79a91c10277011159749110f4ebee5e3638a078e86850c03b1c9f09e184c"}, {"version": "0.3.2", "release_date": "2026-02-05", "changelog": "### 重构 🔧\n- CodeMirror 架构优化 - 统一导出避免多实例问题\n- 语言加载器优化 - 从动态 import 改为静态导入\n- 动态主题切换 - 使用 Compartment 实现无损切换\n\n### 优化 🚀\n- 编辑器性能 - 添加内容更新防抖\n- 亮色主题 - 改进代码编辑器亮色模式样式", "download_url": "", "file_size": 0, "sha256": ""}, {"version": "0.3.0", "release_date": "2026-02-04", "changelog": "### 新增 ✨\n- Markdown 图表支持 - Mermaid 流程图、时序图、类图等\n- 代码语法高亮 - 支持 20+ 种常用编程语言\n- 文件列表优化 - 文件夹优先显示,同类型按名称排序", "download_url": "", "file_size": 0, "sha256": ""}, {"version": "0.2.0", "release_date": "2026-01-28", "changelog": "### 新增 ✨\n- 应用配置管理 - 全新设置面板,支持自定义显示模块和默认启动页\n- 智能更新提醒 - 新增版本更新通知组件\n- 模块重命名 - 应用更名为 u-desk", "download_url": "", "file_size": 0, "sha256": ""}, {"version": "0.1.5", "release_date": "2026-01-22", "changelog": "### 新增 ✨\n- 文件管理模块 - 文件浏览、编辑、操作功能\n- 版本更新管理 - 自动检查和下载更新\n- 系统信息查询 - CPU、内存、磁盘等硬件信息", "download_url": "", "file_size": 0, "sha256": ""}, {"version": "0.1.0", "release_date": "2026-01-18", "changelog": "### 新增 ✨\n- 数据库管理 - 支持多种数据库连接和查询功能", "download_url": "", "file_size": 0, "sha256": ""}]}
|
||||||
@@ -43,7 +43,7 @@ func LoadUpdateConfig() (*UpdateConfig, error) {
|
|||||||
LastCheckTime: time.Time{}, // 启动时会立即检查
|
LastCheckTime: time.Time{}, // 启动时会立即检查
|
||||||
AutoCheckEnabled: true,
|
AutoCheckEnabled: true,
|
||||||
CheckIntervalMinutes: 5, // 5分钟检查一次
|
CheckIntervalMinutes: 5, // 5分钟检查一次
|
||||||
CheckURL: "https://img.1216.top/u-desk/last-version.json",
|
CheckURL: "https://c.1216.top/last-version.json",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ func LoadUpdateConfig() (*UpdateConfig, error) {
|
|||||||
|
|
||||||
// 使用默认检查地址
|
// 使用默认检查地址
|
||||||
if config.CheckURL == "" {
|
if config.CheckURL == "" {
|
||||||
config.CheckURL = "https://img.1216.top/u-desk/last-version.json"
|
config.CheckURL = "https://c.1216.top/last-version.json"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保版本号不为空(使用缓存的版本号)
|
// 确保版本号不为空(使用缓存的版本号)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@@ -69,27 +70,16 @@ func ParseVersion(versionStr string) (*Version, error) {
|
|||||||
func (v *Version) Compare(other *Version) int {
|
func (v *Version) Compare(other *Version) int {
|
||||||
switch {
|
switch {
|
||||||
case v.Major != other.Major:
|
case v.Major != other.Major:
|
||||||
return compareInt(v.Major, other.Major)
|
return cmp.Compare(v.Major, other.Major)
|
||||||
case v.Minor != other.Minor:
|
case v.Minor != other.Minor:
|
||||||
return compareInt(v.Minor, other.Minor)
|
return cmp.Compare(v.Minor, other.Minor)
|
||||||
case v.Patch != other.Patch:
|
case v.Patch != other.Patch:
|
||||||
return compareInt(v.Patch, other.Patch)
|
return cmp.Compare(v.Patch, other.Patch)
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compareInt 比较两个整数
|
|
||||||
func compareInt(a, b int) int {
|
|
||||||
if a < b {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
if a > b {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNewerThan 判断是否比目标版本新
|
// IsNewerThan 判断是否比目标版本新
|
||||||
func (v *Version) IsNewerThan(other *Version) bool {
|
func (v *Version) IsNewerThan(other *Version) bool {
|
||||||
return v.Compare(other) > 0
|
return v.Compare(other) > 0
|
||||||
|
|||||||
@@ -67,8 +67,20 @@
|
|||||||
v-model="showSettings"
|
v-model="showSettings"
|
||||||
:config="configStore.appConfig"
|
:config="configStore.appConfig"
|
||||||
@save="handleSaveConfig"
|
@save="handleSaveConfig"
|
||||||
|
@open-version-history="showVersionHistory = true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 版本历史抽屉 -->
|
||||||
|
<a-drawer
|
||||||
|
v-model:visible="showVersionHistory"
|
||||||
|
:width="720"
|
||||||
|
:footer="false"
|
||||||
|
:unmount-on-close="false"
|
||||||
|
title="版本历史"
|
||||||
|
>
|
||||||
|
<VersionHistory />
|
||||||
|
</a-drawer>
|
||||||
|
|
||||||
<!-- 升级提示弹窗 -->
|
<!-- 升级提示弹窗 -->
|
||||||
<UpdateNotification
|
<UpdateNotification
|
||||||
v-model="updateStore.showUpdate"
|
v-model="updateStore.showUpdate"
|
||||||
@@ -83,6 +95,7 @@ import {computed, onMounted, onUnmounted, ref, watch} from 'vue'
|
|||||||
import {IconSettings, IconPushpin} from '@arco-design/web-vue/es/icon'
|
import {IconSettings, IconPushpin} from '@arco-design/web-vue/es/icon'
|
||||||
import MarkdownEditor from './views/markdown-editor/index.vue'
|
import MarkdownEditor from './views/markdown-editor/index.vue'
|
||||||
import DbCli from './views/db-cli/index.vue'
|
import DbCli from './views/db-cli/index.vue'
|
||||||
|
import VersionHistory from './views/version/index.vue'
|
||||||
import ThemeToggle from './components/ThemeToggle.vue'
|
import ThemeToggle from './components/ThemeToggle.vue'
|
||||||
import FileSystem from './components/FileSystem/index.vue'
|
import FileSystem from './components/FileSystem/index.vue'
|
||||||
import SettingsPanel from './components/SettingsPanel.vue'
|
import SettingsPanel from './components/SettingsPanel.vue'
|
||||||
@@ -97,6 +110,7 @@ const ACTIVE_TAB_STORAGE_KEY = 'app-active-tab'
|
|||||||
const savedTab = localStorage.getItem(ACTIVE_TAB_STORAGE_KEY)
|
const savedTab = localStorage.getItem(ACTIVE_TAB_STORAGE_KEY)
|
||||||
const activeTab = ref((savedTab === 'user' ? 'file-system' : savedTab) || 'file-system')
|
const activeTab = ref((savedTab === 'user' ? 'file-system' : savedTab) || 'file-system')
|
||||||
const showSettings = ref(false)
|
const showSettings = ref(false)
|
||||||
|
const showVersionHistory = ref(false)
|
||||||
const isMaximized = ref(false)
|
const isMaximized = ref(false)
|
||||||
const isPinned = ref(false)
|
const isPinned = ref(false)
|
||||||
|
|
||||||
@@ -219,10 +233,9 @@ watch(activeTab, (newTab) => {
|
|||||||
// 保存到 localStorage
|
// 保存到 localStorage
|
||||||
localStorage.setItem(ACTIVE_TAB_STORAGE_KEY, newTab)
|
localStorage.setItem(ACTIVE_TAB_STORAGE_KEY, newTab)
|
||||||
|
|
||||||
// 检查 Tab 是否在可见列表中
|
// 检查一级 Tab 是否在可见列表中
|
||||||
const isVisible = appConfig.value.visibleTabs.includes(newTab)
|
const isVisible = appConfig.value.visibleTabs.includes(newTab)
|
||||||
if (!isVisible && appConfig.value.visibleTabs.length > 0 && newTab !== appConfig.value.defaultTab) {
|
if (!isVisible && appConfig.value.visibleTabs.length > 0 && newTab !== appConfig.value.defaultTab) {
|
||||||
// 切换到默认 Tab(避免重复触发)
|
|
||||||
activeTab.value = appConfig.value.defaultTab
|
activeTab.value = appConfig.value.defaultTab
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -97,7 +97,7 @@
|
|||||||
|
|
||||||
<!-- 版本更新 -->
|
<!-- 版本更新 -->
|
||||||
<a-tab-pane key="update" title="版本更新">
|
<a-tab-pane key="update" title="版本更新">
|
||||||
<UpdatePanel />
|
<UpdatePanel @open-version-history="handleOpenVersionHistory" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</a-drawer>
|
</a-drawer>
|
||||||
@@ -122,7 +122,7 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Emits
|
// Emits
|
||||||
const emit = defineEmits(['update:modelValue', 'save'])
|
const emit = defineEmits(['update:modelValue', 'save', 'open-version-history'])
|
||||||
|
|
||||||
// 状态
|
// 状态
|
||||||
const visible = computed({
|
const visible = computed({
|
||||||
@@ -291,6 +291,11 @@ const handleReset = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 打开版本历史
|
||||||
|
const handleOpenVersionHistory = () => {
|
||||||
|
emit('open-version-history')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
|
|
||||||
<!-- 当前版本信息 -->
|
<!-- 当前版本信息 -->
|
||||||
<a-card title="版本信息" :bordered="false">
|
<a-card title="版本信息" :bordered="false">
|
||||||
|
<template #extra>
|
||||||
|
<a-button type="text" size="small" @click="$emit('open-version-history')">
|
||||||
|
<template #icon><icon-history /></template>
|
||||||
|
版本历史
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
<a-row :gutter="16">
|
<a-row :gutter="16">
|
||||||
<a-col :span="12">
|
<a-col :span="12">
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
@@ -106,12 +112,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted } from 'vue'
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
import { Message, Modal } from '@arco-design/web-vue'
|
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 { useUpdateStore } from '../stores/update'
|
import { useUpdateStore } from '../stores/update'
|
||||||
|
|
||||||
|
// Emits
|
||||||
|
defineEmits(['open-version-history'])
|
||||||
|
|
||||||
// 使用更新管理 store
|
// 使用更新管理 store
|
||||||
const updateStore = useUpdateStore()
|
const updateStore = useUpdateStore()
|
||||||
|
|
||||||
@@ -217,7 +227,12 @@ const handleInstall = async () => {
|
|||||||
|
|
||||||
// 监听下载完成事件(本地覆盖:记录下载文件路径)
|
// 监听下载完成事件(本地覆盖:记录下载文件路径)
|
||||||
const onDownloadComplete = (event) => {
|
const onDownloadComplete = (event) => {
|
||||||
const data = typeof event === 'string' ? JSON.parse(event) : event
|
let data: any
|
||||||
|
try {
|
||||||
|
data = typeof event === 'string' ? JSON.parse(event) : event
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (data.success && data.file_path) {
|
if (data.success && data.file_path) {
|
||||||
downloadedFile.value = data.file_path
|
downloadedFile.value = data.file_path
|
||||||
|
|||||||
@@ -92,10 +92,18 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
|
|
||||||
const { tabs = [], visibleTabs = [], defaultTab = 'file-system' } = result.data
|
const { tabs = [], visibleTabs = [], defaultTab = 'file-system' } = result.data
|
||||||
|
|
||||||
|
// 一级 Tab 只有文件管理和数据库,其他功能(Markdown、版本历史)不作为独立 Tab
|
||||||
|
const allKeys = ['file-system', 'db-cli']
|
||||||
|
const tabTitles: Record<string, string> = { 'file-system': '文件管理', 'db-cli': '数据库' }
|
||||||
|
const mergedTabs = allKeys.map(key => tabs.find(t => t.key === key) || { key, title: tabTitles[key] || key, enabled: true })
|
||||||
|
const mergedVisible = visibleTabs.length
|
||||||
|
? visibleTabs.filter(k => allKeys.includes(k))
|
||||||
|
: allKeys
|
||||||
|
|
||||||
appConfig.value = {
|
appConfig.value = {
|
||||||
tabs: tabs.map(tab => ({ ...tab, visible: visibleTabs.includes(tab.key) })),
|
tabs: mergedTabs.map(tab => ({ ...tab, visible: mergedVisible.includes(tab.key) })),
|
||||||
visibleTabs,
|
visibleTabs: mergedVisible,
|
||||||
defaultTab
|
defaultTab: defaultTab || 'file-system'
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载配置失败:', error)
|
console.error('加载配置失败:', error)
|
||||||
@@ -112,10 +120,9 @@ export const useConfigStore = defineStore('config', () => {
|
|||||||
appConfig.value = {
|
appConfig.value = {
|
||||||
tabs: [
|
tabs: [
|
||||||
{ key: 'file-system', title: '文件管理', visible: true, enabled: true },
|
{ key: 'file-system', title: '文件管理', visible: true, enabled: true },
|
||||||
{ key: 'db-cli', title: '数据库', visible: true, enhanced: true },
|
{ key: 'db-cli', title: '数据库', visible: true, enhanced: true }
|
||||||
{ key: 'markdown-editor', title: 'Markdown 编辑器', visible: true, enabled: true }
|
|
||||||
],
|
],
|
||||||
visibleTabs: ['file-system', 'db-cli', 'markdown-editor'],
|
visibleTabs: ['file-system', 'db-cli'],
|
||||||
defaultTab: 'file-system'
|
defaultTab: 'file-system'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
136
web/src/views/version/index.vue
Normal file
136
web/src/views/version/index.vue
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<div class="version-history">
|
||||||
|
<!-- 顶部操作栏 -->
|
||||||
|
<div class="version-header">
|
||||||
|
<div class="header-right">
|
||||||
|
<a-button type="text" size="small" @click="handleRefresh" :loading="refreshing">
|
||||||
|
<template #icon><icon-refresh /></template>
|
||||||
|
刷新
|
||||||
|
</a-button>
|
||||||
|
<a-button type="text" size="small" @click="handleOpenExternal">
|
||||||
|
<template #icon><icon-export /></template>
|
||||||
|
在浏览器打开
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- iframe 嵌入远程页面 -->
|
||||||
|
<div class="iframe-wrapper">
|
||||||
|
<iframe
|
||||||
|
ref="iframeRef"
|
||||||
|
:src="iframeSrc"
|
||||||
|
class="version-iframe"
|
||||||
|
frameborder="0"
|
||||||
|
@load="onIframeLoad"
|
||||||
|
/>
|
||||||
|
<div v-if="loading" class="iframe-loading">
|
||||||
|
<a-spin size="32" />
|
||||||
|
<p>加载中...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import { IconRefresh, IconExport } from '@arco-design/web-vue/es/icon'
|
||||||
|
|
||||||
|
// ==================== 常量 ====================
|
||||||
|
const BASE_URL = 'https://c.1216.top/u-desk/version.html'
|
||||||
|
|
||||||
|
// ==================== 状态 ====================
|
||||||
|
const currentVersion = ref('')
|
||||||
|
const loading = ref(true)
|
||||||
|
const refreshing = ref(false)
|
||||||
|
const iframeRef = ref<HTMLIFrameElement | null>(null)
|
||||||
|
|
||||||
|
// ==================== 计算属性 ====================
|
||||||
|
const iframeSrc = computed(() => {
|
||||||
|
if (currentVersion.value) {
|
||||||
|
return `${BASE_URL}?v=${currentVersion.value}&vis=u-desk`
|
||||||
|
}
|
||||||
|
return `${BASE_URL}?vis=u-desk`
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== 操作 ====================
|
||||||
|
function handleRefresh(): void {
|
||||||
|
refreshing.value = true
|
||||||
|
loading.value = true
|
||||||
|
if (iframeRef.value) {
|
||||||
|
iframeRef.value.src = iframeSrc.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOpenExternal(): void {
|
||||||
|
window.open(iframeSrc.value, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
function onIframeLoad(): void {
|
||||||
|
loading.value = false
|
||||||
|
refreshing.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 生命周期 ====================
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const result = await window.go?.main?.App?.GetCurrentVersion?.()
|
||||||
|
if (result?.success) {
|
||||||
|
currentVersion.value = result.data?.version || ''
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Wails 未就绪时忽略
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.version-history {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====== 顶部栏 ====== */
|
||||||
|
.version-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====== iframe ====== */
|
||||||
|
.iframe-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--color-bg-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.iframe-loading {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12px;
|
||||||
|
color: var(--color-text-3);
|
||||||
|
background: var(--color-bg-1);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
6
web/src/wailsjs/wailsjs/go/main/App.d.ts
vendored
6
web/src/wailsjs/wailsjs/go/main/App.d.ts
vendored
@@ -28,8 +28,6 @@ export function EmptyRecycleBin():Promise<void>;
|
|||||||
|
|
||||||
export function ExecuteSQL(arg1:number,arg2:string,arg3:string):Promise<Record<string, any>>;
|
export function ExecuteSQL(arg1:number,arg2:string,arg3:string):Promise<Record<string, any>>;
|
||||||
|
|
||||||
export function ExportMarkdownToPDF(arg1:string):Promise<string>;
|
|
||||||
|
|
||||||
export function ExportPDF(arg1:string,arg2:string,arg3:string,arg4:number,arg5:number,arg6:number):Promise<Record<string, any>>;
|
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 ExtractFileFromZip(arg1:string,arg2:string):Promise<string>;
|
||||||
@@ -76,8 +74,6 @@ export function GetUpdateConfig():Promise<Record<string, any>>;
|
|||||||
|
|
||||||
export function GetZipFileInfo(arg1:string,arg2:string):Promise<Record<string, any>>;
|
export function GetZipFileInfo(arg1:string,arg2:string):Promise<Record<string, any>>;
|
||||||
|
|
||||||
export function Greet(arg1:string):Promise<string>;
|
|
||||||
|
|
||||||
export function InstallUpdate(arg1:string,arg2:boolean):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 InstallUpdateWithHash(arg1:string,arg2:boolean,arg3:string,arg4:string):Promise<Record<string, any>>;
|
||||||
@@ -96,8 +92,6 @@ export function OpenPath(arg1:string):Promise<void>;
|
|||||||
|
|
||||||
export function PreviewTableStructure(arg1:number,arg2:string,arg3:string,arg4:Record<string, any>):Promise<Array<string>>;
|
export function PreviewTableStructure(arg1:number,arg2:string,arg3:string,arg4:Record<string, any>):Promise<Array<string>>;
|
||||||
|
|
||||||
export function QueryUsers(arg1:string,arg2:number,arg3:number,arg4:number,arg5:number,arg6:number,arg7:string,arg8:string):Promise<Record<string, any>>;
|
|
||||||
|
|
||||||
export function ReadFile(arg1:string):Promise<string>;
|
export function ReadFile(arg1:string):Promise<string>;
|
||||||
|
|
||||||
export function Reload():Promise<void>;
|
export function Reload():Promise<void>;
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ export function ExecuteSQL(arg1, arg2, arg3) {
|
|||||||
return window['go']['main']['App']['ExecuteSQL'](arg1, arg2, arg3);
|
return window['go']['main']['App']['ExecuteSQL'](arg1, arg2, arg3);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ExportMarkdownToPDF(arg1) {
|
|
||||||
return window['go']['main']['App']['ExportMarkdownToPDF'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ExportPDF(arg1, arg2, arg3, arg4, arg5, arg6) {
|
export function ExportPDF(arg1, arg2, arg3, arg4, arg5, arg6) {
|
||||||
return window['go']['main']['App']['ExportPDF'](arg1, arg2, arg3, arg4, arg5, arg6);
|
return window['go']['main']['App']['ExportPDF'](arg1, arg2, arg3, arg4, arg5, arg6);
|
||||||
}
|
}
|
||||||
@@ -146,10 +142,6 @@ export function GetZipFileInfo(arg1, arg2) {
|
|||||||
return window['go']['main']['App']['GetZipFileInfo'](arg1, arg2);
|
return window['go']['main']['App']['GetZipFileInfo'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Greet(arg1) {
|
|
||||||
return window['go']['main']['App']['Greet'](arg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function InstallUpdate(arg1, arg2) {
|
export function InstallUpdate(arg1, arg2) {
|
||||||
return window['go']['main']['App']['InstallUpdate'](arg1, arg2);
|
return window['go']['main']['App']['InstallUpdate'](arg1, arg2);
|
||||||
}
|
}
|
||||||
@@ -186,10 +178,6 @@ export function PreviewTableStructure(arg1, arg2, arg3, arg4) {
|
|||||||
return window['go']['main']['App']['PreviewTableStructure'](arg1, arg2, arg3, arg4);
|
return window['go']['main']['App']['PreviewTableStructure'](arg1, arg2, arg3, arg4);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function QueryUsers(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) {
|
|
||||||
return window['go']['main']['App']['QueryUsers'](arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadFile(arg1) {
|
export function ReadFile(arg1) {
|
||||||
return window['go']['main']['App']['ReadFile'](arg1);
|
return window['go']['main']['App']['ReadFile'](arg1);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user