feat: 补全多云资产与账单同步

- 接入 AWS、华为云和 Azure 资产及账单 API

- 按原始币种隔离统计并修正账号服务器数

- 修复侧栏菜单展开后的滚动行为
This commit is contained in:
Logan.Li committed 2026-07-29 06:15:00 +08:00
1 parent 65e2f09b97
commit 132fe9ba97
25 files changed
+1094 -141

No files matched your search

+41 -1
View File
@@ -1,6 +1,7 @@
package controller
import (
"fmt"
"net/http"
"strconv"
"strings"
@@ -32,6 +33,24 @@ func NewCloudAccountHandler(db *gorm.DB) *CloudAccountHandler {
func (h *CloudAccountHandler) ListCloudAccounts(c *gin.Context) {
var accounts []model.CloudAccount
h.db.Find(&accounts)
// 服务器数来自真实云账号关联,避免重复导入后被“本次新增数”覆盖。 // Logan.Li
type accountServerCount struct {
CloudAccountID uint
Total int
}
var serverCounts []accountServerCount
h.db.Model(&model.Server{}).
Select("cloud_account_id, COUNT(*) AS total").
Where("cloud_account_id IS NOT NULL").Group("cloud_account_id").Scan(&serverCounts)
countByAccount := make(map[uint]int, len(serverCounts))
for _, item := range serverCounts {
countByAccount[item.CloudAccountID] = item.Total
}
for index := range accounts {
if total, ok := countByAccount[accounts[index].ID]; ok {
accounts[index].ServerCount = total
}
}
c.JSON(http.StatusOK, model.Response{
Code: 200,
@@ -80,6 +99,10 @@ func (h *CloudAccountHandler) CreateCloudAccount(c *gin.Context) {
})
return
}
if err := validateCloudAccountCredentials(req.Provider, req.AccessKey, req.SecretKey); err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: err.Error()})
return
}
status := strings.TrimSpace(req.Status)
if status == "" {
@@ -158,6 +181,10 @@ func (h *CloudAccountHandler) UpdateCloudAccount(c *gin.Context) {
account.Status = strings.TrimSpace(req.Status)
}
account.MonthlyCost = req.MonthlyCost
if err := validateCloudAccountCredentials(account.Provider, account.AccessKey, account.SecretKey); err != nil {
c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: err.Error()})
return
}
if err := h.db.Save(&account).Error; err != nil {
c.JSON(http.StatusInternalServerError, model.Response{
@@ -174,6 +201,20 @@ func (h *CloudAccountHandler) UpdateCloudAccount(c *gin.Context) {
})
}
// validateCloudAccountCredentials 校验各云厂商调用 API 所需的凭据格式。 // Logan.Li
func validateCloudAccountCredentials(provider, accessKey, secretKey string) error {
if strings.TrimSpace(accessKey) == "" || strings.TrimSpace(secretKey) == "" {
return fmt.Errorf("AccessKey 和 SecretKey 不能为空")
}
if provider == "azure" {
parts := strings.Split(accessKey, ":")
if len(parts) != 3 || strings.TrimSpace(parts[0]) == "" || strings.TrimSpace(parts[1]) == "" || strings.TrimSpace(parts[2]) == "" {
return fmt.Errorf("Azure AccessKey 格式应为 租户ID:订阅ID:客户端ID")
}
}
return nil
}
// DeleteCloudAccount 删除云账号
// @Summary 删除云账号
// @Description 删除指定云账号
@@ -199,4 +240,3 @@ func (h *CloudAccountHandler) DeleteCloudAccount(c *gin.Context) {
Message: "删除成功",
})
}