From e2ebb6e46e1607499d768d46cc4a87302e1ab26e Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 8 May 2026 16:21:35 +0800 Subject: [PATCH] =?UTF-8?q?=E7=89=88=E6=9C=AC=E7=AE=A1=E7=90=86=E5=85=A8?= =?UTF-8?q?=E9=9D=A2=E5=A2=9E=E5=BC=BA=EF=BC=9A=E7=8A=B6=E6=80=81=E3=80=81?= =?UTF-8?q?=E8=A1=A5=E4=B8=81=E6=9B=B4=E6=96=B0=E3=80=81=E7=83=AD=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 自动状态管理 - 新增版本自动标记状态:最新版本为'有效',旧版本自动标记为'已失效' - 前端列表页新增状态列和状态筛选 2. 更新方式升级 - 更新方式从手动/自动改为:手动更新/热更新/完整更新 - 热更新:运行时增量替换文件,无需重启 - 完整更新:下载完整包替换,需重启 3. 补丁更新支持 - 新增 base_version_id 字段支持增量补丁 - 创建版本时可选择基础版本,自动识别为补丁模式 - 补丁模式仅上传变更文件 4. ZIP解析上传(已有功能完善) - 上传ZIP自动解析文件列表 - 支持选择入口文件 5. 国际化完善 - 中英文新增状态、更新方式等翻译 --- backend/internal/model/models.go | 2 + backend/internal/router/admin/versions.go | 14 +++ frontend/src/pages/admin/versions/[id].vue | 66 ++++++++--- .../admin/versions/components/columns.ts | 21 +++- frontend/src/pages/admin/versions/create.vue | 104 +++++++++++++++--- .../src/pages/admin/versions/data/schema.ts | 5 +- frontend/src/pages/admin/versions/index.vue | 19 +++- frontend/src/plugins/i18n/en.json | 15 ++- frontend/src/plugins/i18n/zh.json | 15 ++- 9 files changed, 218 insertions(+), 43 deletions(-) diff --git a/backend/internal/model/models.go b/backend/internal/model/models.go index f846d8e..69fb165 100644 --- a/backend/internal/model/models.go +++ b/backend/internal/model/models.go @@ -232,12 +232,14 @@ type Version struct { Description string `gorm:"type:text" json:"description"` Changelog string `gorm:"type:text" json:"changelog"` Status string `gorm:"size:20;default:active" json:"status"` + BaseVersionID *uint `json:"base_version_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` Application Application `gorm:"foreignKey:ApplicationID" json:"application,omitempty"` Files []VersionFile `gorm:"foreignKey:VersionID" json:"files,omitempty"` + BaseVersion *Version `gorm:"foreignKey:BaseVersionID" json:"base_version,omitempty"` } // VersionFile 版本文件模型 diff --git a/backend/internal/router/admin/versions.go b/backend/internal/router/admin/versions.go index c1bcf0c..21d0334 100644 --- a/backend/internal/router/admin/versions.go +++ b/backend/internal/router/admin/versions.go @@ -43,6 +43,7 @@ func handleGetAllVersions(c *gin.Context) { applicationIDFilter := c.Query("application_id") updateStrategyFilter := c.Query("update_strategy") updateMethodFilter := c.Query("update_method") + statusFilter := c.Query("status") searchFilter := c.Query("search") var total int64 @@ -85,6 +86,9 @@ func handleGetAllVersions(c *gin.Context) { if updateMethodFilter != "" { countQuery = countQuery.Where("update_method = ?", updateMethodFilter) } + if statusFilter != "" { + countQuery = countQuery.Where("status = ?", statusFilter) + } if searchFilter != "" { searchLower := strings.ToLower(searchFilter) countQuery = countQuery.Where("LOWER(version) LIKE ? OR LOWER(description) LIKE ?", "%"+searchLower+"%", "%"+searchLower+"%") @@ -101,6 +105,9 @@ func handleGetAllVersions(c *gin.Context) { if updateMethodFilter != "" { query = query.Where("update_method = ?", updateMethodFilter) } + if statusFilter != "" { + query = query.Where("status = ?", statusFilter) + } if searchFilter != "" { searchLower := strings.ToLower(searchFilter) query = query.Where("LOWER(version) LIKE ? OR LOWER(description) LIKE ?", "%"+searchLower+"%", "%"+searchLower+"%") @@ -186,6 +193,7 @@ func handleGetVersionByID(c *gin.Context) { "min_version": version.MinVersion, "changelog": version.Changelog, "status": version.Status, + "base_version_id": version.BaseVersionID, "files": version.Files, "created_at": version.CreatedAt, "updated_at": version.UpdatedAt, @@ -205,6 +213,7 @@ type CreateVersionRequest struct { MinVersion string `json:"min_version"` Description string `json:"description"` Changelog string `json:"changelog"` + BaseVersionID *uint `json:"base_version_id"` } func handleCreateVersionGlobal(c *gin.Context) { @@ -247,6 +256,7 @@ func handleCreateVersionGlobal(c *gin.Context) { Description: req.Description, Changelog: req.Changelog, Status: "active", + BaseVersionID: req.BaseVersionID, } if version.UpdateStrategy == "" { @@ -261,6 +271,10 @@ func handleCreateVersionGlobal(c *gin.Context) { return } + database.DB.Model(&model.Version{}). + Where("application_id = ? AND id != ? AND status = ?", req.ApplicationID, version.ID, "active"). + Update("status", "superseded") + userIDPtr := &userID versionIDPtr := &version.ID service.CreateLog(service.LogParams{ diff --git a/frontend/src/pages/admin/versions/[id].vue b/frontend/src/pages/admin/versions/[id].vue index 8ba87e9..0d33585 100644 --- a/frontend/src/pages/admin/versions/[id].vue +++ b/frontend/src/pages/admin/versions/[id].vue @@ -1,6 +1,6 @@ diff --git a/frontend/src/plugins/i18n/en.json b/frontend/src/plugins/i18n/en.json index 179b740..ffa6680 100644 --- a/frontend/src/plugins/i18n/en.json +++ b/frontend/src/plugins/i18n/en.json @@ -1418,6 +1418,7 @@ "fileSize": "File Size", "strategy": "Strategy", "method": "Method", + "status": "Status", "createdAt": "Created At", "actions": "Actions" }, @@ -1427,7 +1428,12 @@ }, "methods": { "manual": "Manual", - "auto": "Auto" + "hot": "Hot", + "full": "Full" + }, + "status": { + "active": "Active", + "superseded": "Superseded" }, "createForm": { "title": "Create Version", @@ -1461,6 +1467,12 @@ "entryFilePlaceholder": "Select entry file (optional)", "forcedUpdate": "Force Update", "forcedUpdateDesc": "When enabled, users must update to this version to continue using", + "updateMethod": "Update Method", + "baseVersion": "Base Version", + "baseVersionPlaceholder": "Select base version (patch mode)", + "baseVersionDesc": "Select a base version to only upload changed files for incremental patch update", + "noBaseVersion": "None (Full version)", + "status": "Status", "autoUpdate": "Auto Update", "autoUpdateDesc": "When enabled, the application will automatically download and install updates", "changelog": "Changelog", @@ -1474,6 +1486,7 @@ "previewFileCount": "File Count", "previewEntryFile": "Entry File", "previewForcedUpdate": "Force Update", + "previewUpdateMethod": "Update Method", "previewAutoUpdate": "Auto Update", "changelogPreview": "Changelog Preview", "noChangelog": "No changelog", diff --git a/frontend/src/plugins/i18n/zh.json b/frontend/src/plugins/i18n/zh.json index c7de8cb..626f497 100644 --- a/frontend/src/plugins/i18n/zh.json +++ b/frontend/src/plugins/i18n/zh.json @@ -1385,6 +1385,7 @@ "fileSize": "文件大小", "strategy": "更新策略", "method": "更新方式", + "status": "状态", "createdAt": "创建时间", "actions": "操作" }, @@ -1394,7 +1395,12 @@ }, "methods": { "manual": "手动更新", - "auto": "自动更新" + "hot": "热更新", + "full": "完整更新" + }, + "status": { + "active": "有效", + "superseded": "已失效" }, "createForm": { "title": "创建版本", @@ -1428,6 +1434,12 @@ "entryFilePlaceholder": "选择入口文件(可选)", "forcedUpdate": "强制更新", "forcedUpdateDesc": "启用后用户必须更新到此版本才能继续使用", + "updateMethod": "更新方式", + "baseVersion": "基础版本", + "baseVersionPlaceholder": "选择基础版本(补丁模式)", + "baseVersionDesc": "选择基础版本后,只会上传变更的文件,用于增量补丁更新", + "noBaseVersion": "无(完整版本)", + "status": "状态", "autoUpdate": "自动更新", "autoUpdateDesc": "启用后应用将自动下载并安装更新", "changelog": "更新日志", @@ -1441,6 +1453,7 @@ "previewFileCount": "文件数量", "previewEntryFile": "入口文件", "previewForcedUpdate": "强制更新", + "previewUpdateMethod": "更新方式", "previewAutoUpdate": "自动更新", "changelogPreview": "更新日志预览", "noChangelog": "暂无更新日志",