From 53fd9ff7dcaebf4b716aa7c45e881fdd63bec90f Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 28 May 2026 16:06:48 +0800 Subject: [PATCH] feat: add custom download URL for manual update method - Add custom_download_url field to Version model - Show custom download URL input when update method is 'manual' - Use platform default URL if custom URL is not set - Add i18n translations for new field Co-Authored-By: Claude Opus 4.7 --- backend/internal/model/models.go | 3 +- backend/internal/router/admin/versions.go | 97 ++++++++++---------- frontend/src/pages/admin/versions/[id].vue | 19 ++++ frontend/src/pages/admin/versions/create.vue | 18 ++++ frontend/src/plugins/i18n/en.json | 5 + frontend/src/plugins/i18n/zh.json | 5 + 6 files changed, 100 insertions(+), 47 deletions(-) diff --git a/backend/internal/model/models.go b/backend/internal/model/models.go index a640590..20d1105 100644 --- a/backend/internal/model/models.go +++ b/backend/internal/model/models.go @@ -229,7 +229,8 @@ type Version struct { EntryFile string `gorm:"size:255" json:"entry_file"` UpdateStrategy string `gorm:"size:20;default:optional" json:"update_strategy"` UpdateType string `gorm:"size:20;default:full" json:"update_type"` - UpdateMethod string `gorm:"size:20;default:auto" json:"update_method"` + UpdateMethod string `gorm:"size:20;default:auto" json:"update_method"` + CustomDownloadURL string `gorm:"size:500" json:"custom_download_url"` Description string `gorm:"type:text" json:"description"` Changelog string `gorm:"type:text" json:"changelog"` Status string `gorm:"size:20;default:active" json:"status"` diff --git a/backend/internal/router/admin/versions.go b/backend/internal/router/admin/versions.go index e950f6c..61132f2 100644 --- a/backend/internal/router/admin/versions.go +++ b/backend/internal/router/admin/versions.go @@ -226,38 +226,40 @@ func handleGetVersionByID(c *gin.Context) { } response.Success(c, gin.H{ - "id": version.ID, - "application_id": version.ApplicationID, - "application_name": appNameMap[version.ApplicationID], - "version": version.Version, - "description": version.Description, - "file_path": version.FilePath, - "file_size": version.FileSize, - "file_hash": version.FileHash, - "update_strategy": version.UpdateStrategy, - "update_type": version.UpdateType, - "update_method": version.UpdateMethod, - "changelog": version.Changelog, - "status": computedStatus, - "base_version_id": version.BaseVersionID, - "files": version.Files, - "created_at": version.CreatedAt, - "updated_at": version.UpdatedAt, + "id": version.ID, + "application_id": version.ApplicationID, + "application_name": appNameMap[version.ApplicationID], + "version": version.Version, + "description": version.Description, + "file_path": version.FilePath, + "file_size": version.FileSize, + "file_hash": version.FileHash, + "update_strategy": version.UpdateStrategy, + "update_type": version.UpdateType, + "update_method": version.UpdateMethod, + "custom_download_url": version.CustomDownloadURL, + "changelog": version.Changelog, + "status": computedStatus, + "base_version_id": version.BaseVersionID, + "files": version.Files, + "created_at": version.CreatedAt, + "updated_at": version.UpdatedAt, }) } type CreateVersionRequest struct { - ApplicationID uint `json:"application_id"` - Version string `json:"version"` - FilePath string `json:"file_path"` - FileSize int64 `json:"file_size"` - FileHash string `json:"file_hash"` - EntryFile string `json:"entry_file"` - UpdateStrategy string `json:"update_strategy"` - UpdateType string `json:"update_type"` - UpdateMethod string `json:"update_method"` - Description string `json:"description"` - Changelog string `json:"changelog"` + ApplicationID uint `json:"application_id"` + Version string `json:"version"` + FilePath string `json:"file_path"` + FileSize int64 `json:"file_size"` + FileHash string `json:"file_hash"` + EntryFile string `json:"entry_file"` + UpdateStrategy string `json:"update_strategy"` + UpdateType string `json:"update_type"` + UpdateMethod string `json:"update_method"` + CustomDownloadURL string `json:"custom_download_url"` + Description string `json:"description"` + Changelog string `json:"changelog"` } func handleCreateVersionGlobal(c *gin.Context) { @@ -287,18 +289,19 @@ func handleCreateVersionGlobal(c *gin.Context) { } version := model.Version{ - ApplicationID: req.ApplicationID, - Version: req.Version, - FilePath: req.FilePath, - FileSize: req.FileSize, - FileHash: req.FileHash, - EntryFile: req.EntryFile, - UpdateStrategy: req.UpdateStrategy, - UpdateType: req.UpdateType, - UpdateMethod: req.UpdateMethod, - Description: req.Description, - Changelog: req.Changelog, - Status: "active", + ApplicationID: req.ApplicationID, + Version: req.Version, + FilePath: req.FilePath, + FileSize: req.FileSize, + FileHash: req.FileHash, + EntryFile: req.EntryFile, + UpdateStrategy: req.UpdateStrategy, + UpdateType: req.UpdateType, + UpdateMethod: req.UpdateMethod, + CustomDownloadURL: req.CustomDownloadURL, + Description: req.Description, + Changelog: req.Changelog, + Status: "active", } if version.UpdateStrategy == "" { @@ -341,12 +344,13 @@ func handleCreateVersionGlobal(c *gin.Context) { } type UpdateVersionRequest struct { - Version string `json:"version"` - UpdateStrategy string `json:"update_strategy"` - UpdateType string `json:"update_type"` - UpdateMethod string `json:"update_method"` - Description string `json:"description"` - Changelog string `json:"changelog"` + Version string `json:"version"` + UpdateStrategy string `json:"update_strategy"` + UpdateType string `json:"update_type"` + UpdateMethod string `json:"update_method"` + CustomDownloadURL string `json:"custom_download_url"` + Description string `json:"description"` + Changelog string `json:"changelog"` } func handleUpdateVersionGlobal(c *gin.Context) { @@ -403,6 +407,7 @@ func handleUpdateVersionGlobal(c *gin.Context) { if req.UpdateMethod != "" { updates["update_method"] = req.UpdateMethod } + updates["custom_download_url"] = req.CustomDownloadURL if req.Description != "" { updates["description"] = req.Description } diff --git a/frontend/src/pages/admin/versions/[id].vue b/frontend/src/pages/admin/versions/[id].vue index 39c516b..80b7d9d 100644 --- a/frontend/src/pages/admin/versions/[id].vue +++ b/frontend/src/pages/admin/versions/[id].vue @@ -46,6 +46,7 @@ const formData = ref({ update_strategy: 'optional' as 'optional' | 'forced', update_type: 'full' as 'full' | 'patch', update_method: 'auto' as 'auto' | 'manual', + custom_download_url: '', changelog: '', entry_file: '', file: null as File | null, @@ -97,6 +98,7 @@ async function fetchVersion() { formData.value.update_strategy = ver.update_strategy || 'optional' formData.value.update_type = ver.update_type || 'full' formData.value.update_method = ver.update_method || 'auto' + formData.value.custom_download_url = ver.custom_download_url || '' formData.value.changelog = ver.changelog || '' formData.value.entry_file = ver.entry_file || '' } @@ -184,6 +186,7 @@ async function handleSubmit() { update_strategy: formData.value.update_strategy, update_type: formData.value.update_type, update_method: formData.value.update_method, + custom_download_url: formData.value.custom_download_url, changelog: formData.value.changelog, entry_file: formData.value.entry_file, } @@ -460,6 +463,18 @@ onMounted(() => { +
+ {{ t('admin.versions.createForm.customDownloadUrl') }} +

+ {{ t('admin.versions.createForm.customDownloadUrlDesc') }} +

+ +
+
{{ t('admin.versions.createForm.changelog') }} @@ -516,6 +531,10 @@ onMounted(() => { : t('admin.versions.methods.manual') }}
+
+ {{ t('admin.versions.createForm.previewCustomDownloadUrl') }} + {{ formData.custom_download_url || t('admin.versions.createForm.useDefault') }} +
diff --git a/frontend/src/pages/admin/versions/create.vue b/frontend/src/pages/admin/versions/create.vue index 11e7c43..309f59c 100644 --- a/frontend/src/pages/admin/versions/create.vue +++ b/frontend/src/pages/admin/versions/create.vue @@ -45,6 +45,7 @@ const formData = ref({ update_strategy: 'optional' as 'optional' | 'forced', update_type: 'full' as 'full' | 'patch', update_method: 'auto' as 'auto' | 'manual', + custom_download_url: '', changelog: '', entry_file: '', file: null as File | null, @@ -188,6 +189,7 @@ async function handleSubmit() { update_strategy: formData.value.update_strategy, update_type: formData.value.update_type, update_method: formData.value.update_method, + custom_download_url: formData.value.custom_download_url, changelog: formData.value.changelog, entry_file: formData.value.entry_file, file_path: uploadedData.value.file_path, @@ -454,6 +456,18 @@ onMounted(() => {
+
+ {{ t('admin.versions.createForm.customDownloadUrl') }} +

+ {{ t('admin.versions.createForm.customDownloadUrlDesc') }} +

+ +
+
{{ t('admin.versions.createForm.changelog') }} @@ -516,6 +530,10 @@ onMounted(() => { {{ t('admin.versions.createForm.previewUpdateMethod') }} {{ methodLabel }}
+
+ {{ t('admin.versions.createForm.previewCustomDownloadUrl') }} + {{ formData.custom_download_url || t('admin.versions.createForm.useDefault') }} +
diff --git a/frontend/src/plugins/i18n/en.json b/frontend/src/plugins/i18n/en.json index 6601c1b..504e0e3 100644 --- a/frontend/src/plugins/i18n/en.json +++ b/frontend/src/plugins/i18n/en.json @@ -1499,6 +1499,11 @@ "previewUpdateType": "Update Type", "previewUpdateMethod": "Update Method", "previewAutoUpdate": "Auto Update", + "customDownloadUrl": "Custom Download URL", + "customDownloadUrlDesc": "Set a custom download URL, or use the platform default if not set", + "customDownloadUrlPlaceholder": "e.g., https://your-cdn.com/download/app.zip", + "previewCustomDownloadUrl": "Download URL", + "useDefault": "Use Default", "changelogPreview": "Changelog Preview", "noChangelog": "No changelog", "notUploaded": "Not uploaded", diff --git a/frontend/src/plugins/i18n/zh.json b/frontend/src/plugins/i18n/zh.json index 5fdd44d..e474ac5 100644 --- a/frontend/src/plugins/i18n/zh.json +++ b/frontend/src/plugins/i18n/zh.json @@ -1477,6 +1477,11 @@ "previewUpdateType": "更新类型", "previewUpdateMethod": "更新方式", "previewAutoUpdate": "自动更新", + "customDownloadUrl": "自定义下载地址", + "customDownloadUrlDesc": "设置自定义下载地址,不设置则使用平台默认地址", + "customDownloadUrlPlaceholder": "例如: https://your-cdn.com/download/app.zip", + "previewCustomDownloadUrl": "下载地址", + "useDefault": "使用默认地址", "changelogPreview": "更新日志预览", "noChangelog": "暂无更新日志", "notUploaded": "未上传",