From d098a7ff81d181abb893e8e7cad818d256255706 Mon Sep 17 00:00:00 2001 From: zpc Date: Fri, 20 Feb 2026 15:10:15 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=AD=98=E5=82=A8=E6=A1=B6?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=8F=AF=E8=AE=BF=E9=97=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ConfigController.cs | 76 +++++++++++++++++++ .../admin-web/src/api/system/config.ts | 11 +++ .../src/views/system/config/upload.vue | 30 +++++++- 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/server/MiAssessment/src/MiAssessment.Admin/Controllers/ConfigController.cs b/server/MiAssessment/src/MiAssessment.Admin/Controllers/ConfigController.cs index cd8c53c..c9f8672 100644 --- a/server/MiAssessment/src/MiAssessment.Admin/Controllers/ConfigController.cs +++ b/server/MiAssessment/src/MiAssessment.Admin/Controllers/ConfigController.cs @@ -1,3 +1,6 @@ +using COSXML; +using COSXML.Auth; +using COSXML.Model.Bucket; using MiAssessment.Admin.Filters; using MiAssessment.Admin.Models.Common; using MiAssessment.Admin.Models.Config; @@ -93,4 +96,77 @@ public class ConfigController : ControllerBase return ApiResponse.Error(AdminErrorCodes.InternalError, "更新上传配置失败"); } } + + /// + /// 测试腾讯云COS连接 + /// + /// 上传配置 + /// 测试结果 + [HttpPost("upload/testConnection")] + public Task> TestCosConnection([FromBody] UploadSetting request) + { + // 验证必填参数 + if (request.Type != "3") + { + return Task.FromResult(ApiResponse.Error(AdminErrorCodes.InvalidParameter, "仅支持测试腾讯云COS连接")); + } + + if (string.IsNullOrWhiteSpace(request.AccessKeyId) || + string.IsNullOrWhiteSpace(request.AccessKeySecret) || + string.IsNullOrWhiteSpace(request.Bucket) || + string.IsNullOrWhiteSpace(request.Region)) + { + return Task.FromResult(ApiResponse.Error(AdminErrorCodes.InvalidParameter, "请填写完整的COS配置信息")); + } + + try + { + // 创建COS客户端 + var config = new CosXmlConfig.Builder() + .IsHttps(true) + .SetRegion(request.Region!) + .Build(); + + var credentialProvider = new DefaultQCloudCredentialProvider( + request.AccessKeyId!, + request.AccessKeySecret!, + 600); + + var cosXml = new CosXmlServer(config, credentialProvider); + + // 尝试 HeadBucket 验证连接 + var headBucketRequest = new HeadBucketRequest(request.Bucket!); + var result = cosXml.HeadBucket(headBucketRequest); + + if (result.IsSuccessful()) + { + return Task.FromResult(ApiResponse.Success(true, "连接成功")); + } + + return Task.FromResult(ApiResponse.Error(AdminErrorCodes.InternalError, $"连接失败: {result.httpMessage}")); + } + catch (COSXML.CosException.CosClientException clientEx) + { + _logger.LogWarning(clientEx, "COS连接测试客户端错误"); + return Task.FromResult(ApiResponse.Error(AdminErrorCodes.InternalError, $"连接失败: {clientEx.Message}")); + } + catch (COSXML.CosException.CosServerException serverEx) + { + _logger.LogWarning(serverEx, "COS连接测试服务端错误"); + var message = serverEx.errorCode switch + { + "NoSuchBucket" => "存储桶不存在,请检查Bucket名称", + "AccessDenied" => "访问被拒绝,请检查SecretId和SecretKey", + "SignatureDoesNotMatch" => "签名不匹配,请检查SecretKey", + "InvalidAccessKeyId" => "SecretId无效,请检查配置", + _ => $"连接失败: {serverEx.errorCode} - {serverEx.errorMessage}" + }; + return Task.FromResult(ApiResponse.Error(AdminErrorCodes.InternalError, message)); + } + catch (Exception ex) + { + _logger.LogError(ex, "COS连接测试异常"); + return Task.FromResult(ApiResponse.Error(AdminErrorCodes.InternalError, $"连接测试失败: {ex.Message}")); + } + } } diff --git a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/api/system/config.ts b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/api/system/config.ts index 2b496eb..4ad47a8 100644 --- a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/api/system/config.ts +++ b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/api/system/config.ts @@ -44,3 +44,14 @@ export function updateUploadConfig(data: UploadSetting): Promise> { + return request({ + url: '/admin/config/upload/testConnection', + method: 'post', + data + }) +} diff --git a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/system/config/upload.vue b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/system/config/upload.vue index 89dc9ca..27efa87 100644 --- a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/system/config/upload.vue +++ b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/system/config/upload.vue @@ -135,7 +135,7 @@ 重置 - + 测试连接 @@ -153,13 +153,14 @@ import { reactive, ref, computed, onMounted } from 'vue' import { FolderOpened, Cloudy, Check, Refresh, Connection } from '@element-plus/icons-vue' import { ElMessage, type FormInstance, type FormRules } from 'element-plus' -import { getUploadConfig, updateUploadConfig, type UploadSetting } from '@/api/system/config' +import { getUploadConfig, updateUploadConfig, testCosConnection, type UploadSetting } from '@/api/system/config' // ============ Types ============ interface UploadConfigState { loading: boolean saving: boolean + testing: boolean formData: UploadSetting } @@ -172,6 +173,7 @@ const formRef = ref() const state = reactive({ loading: false, saving: false, + testing: false, formData: { type: '1', appId: '', @@ -264,8 +266,28 @@ function handleReset() { } function handleTest() { - // TODO: 实现连接测试 - ElMessage.info('连接测试功能开发中') + // 先验证必填字段 + if (!state.formData.accessKeyId || !state.formData.accessKeySecret || + !state.formData.bucket || !state.formData.region) { + ElMessage.warning('请先填写完整的COS配置信息') + return + } + + state.testing = true + testCosConnection(state.formData) + .then(res => { + if (res.code === 0) { + ElMessage.success(res.message || '连接成功') + } else { + ElMessage.error(res.message || '连接失败') + } + }) + .catch(() => { + ElMessage.error('连接测试请求失败') + }) + .finally(() => { + state.testing = false + }) } // ============ Lifecycle ============