diff --git a/backend/internal/modules/paymentconfig/handler.go b/backend/internal/modules/paymentconfig/handler.go index 6addc05..7d71a99 100644 --- a/backend/internal/modules/paymentconfig/handler.go +++ b/backend/internal/modules/paymentconfig/handler.go @@ -96,7 +96,7 @@ func (h *Handler) Create(c *gin.Context) { if err == ErrNameRequired || err == ErrMerchantIDRequired || err == ErrGatewayURLRequired || err == ErrSignKeyRequired || err == ErrNotifyKeyRequired || err == ErrInvalidProvider || err == ErrNotifyURLRequired || err == ErrInvalidSignType || err == ErrAppIDRequired || - err == ErrSerialNoRequired || err == ErrTermNoRequired { + err == ErrInvalidStatus || err == ErrSerialNoRequired || err == ErrTermNoRequired { response.BadRequest(c, err.Error()) return } @@ -139,7 +139,7 @@ func (h *Handler) Update(c *gin.Context) { response.NotFound(c, "配置不存在") return } - if err == ErrInvalidSignType || err == ErrNotifyURLRequired { + if err == ErrInvalidSignType || err == ErrInvalidStatus || err == ErrNotifyURLRequired { response.BadRequest(c, err.Error()) return } diff --git a/backend/internal/modules/paymentconfig/repository.go b/backend/internal/modules/paymentconfig/repository.go index 52d2e96..2a3eb08 100644 --- a/backend/internal/modules/paymentconfig/repository.go +++ b/backend/internal/modules/paymentconfig/repository.go @@ -171,15 +171,6 @@ func (r *Repository) Create(req CreateRequest, actorID uint64, meta AuditMeta) ( var dto ConfigDTO err := r.db.Transaction(func(tx *gorm.DB) error { - // 如果设置为默认,先取消同 provider 的其他默认配置 - if req.IsDefault { - if err := tx.Model(&model.PaymentMerchantConfig{}). - Where("provider = ? AND is_default = ?", req.Provider, true). - Update("is_default", false).Error; err != nil { - return err - } - } - // 加密密钥 encryptedSignKey, err := r.encryptor.Encrypt(req.SignKey) if err != nil { @@ -198,6 +189,15 @@ func (r *Repository) Create(req CreateRequest, actorID uint64, meta AuditMeta) ( if environment == "" { environment = "production" } + isDefault := req.IsDefault + if status == "active" { + if err := deactivateOtherConfigs(tx, 0, actorID); err != nil { + return err + } + isDefault = true + } else { + isDefault = false + } item := model.PaymentMerchantConfig{ Name: req.Name, @@ -212,7 +212,7 @@ func (r *Repository) Create(req CreateRequest, actorID uint64, meta AuditMeta) ( JSPayFlag: firstNonEmpty(req.JSPayFlag, "2"), SignType: firstNonEmpty(req.SignType, defaultSignType(req.Provider)), ExtraConfig: req.ExtraConfig, - IsDefault: req.IsDefault, + IsDefault: isDefault, Status: status, Environment: environment, BusinessTags: req.BusinessTags, @@ -247,6 +247,9 @@ func (r *Repository) Update(id uint64, req UpdateRequest, actorID uint64, meta A if req.SignType != nil && *req.SignType != "" && !isValidSignType(*req.SignType) { return nil, ErrInvalidSignType } + if req.Status != nil && !isValidStatus(*req.Status) { + return nil, ErrInvalidStatus + } if req.NotifyURL != nil && *req.NotifyURL == "" { return nil, ErrNotifyURLRequired } @@ -261,15 +264,6 @@ func (r *Repository) Update(id uint64, req UpdateRequest, actorID uint64, meta A return err } - // 如果设置为默认,先取消同 provider 的其他默认配置 - if req.IsDefault != nil && *req.IsDefault && !item.IsDefault { - if err := tx.Model(&model.PaymentMerchantConfig{}). - Where("provider = ? AND is_default = ? AND id != ?", item.Provider, true, id). - Update("is_default", false).Error; err != nil { - return err - } - } - updates := make(map[string]any) if req.Name != nil { updates["name"] = *req.Name @@ -326,6 +320,20 @@ func (r *Repository) Update(id uint64, req UpdateRequest, actorID uint64, meta A } updates["updated_by"] = actorID + finalStatus := item.Status + if req.Status != nil { + finalStatus = *req.Status + } + if finalStatus == "active" { + if err := deactivateOtherConfigs(tx, id, actorID); err != nil { + return err + } + updates["status"] = "active" + updates["is_default"] = true + } else { + updates["is_default"] = false + } + if err := tx.Model(&item).Updates(updates).Error; err != nil { return err } @@ -430,6 +438,20 @@ func (r *Repository) RecordUsage(configID uint64, paymentOrderID uint64, provide }) } +// deactivateOtherConfigs 保证全局同一时间只有一个启用配置。 +func deactivateOtherConfigs(tx *gorm.DB, activeID uint64, actorID uint64) error { + db := tx.Model(&model.PaymentMerchantConfig{}). + Where("status = ? OR is_default = ?", "active", true) + if activeID > 0 { + db = db.Where("id != ?", activeID) + } + return db.Updates(map[string]any{ + "status": "disabled", + "is_default": false, + "updated_by": actorID, + }).Error +} + // toDTO 转换为 DTO func (r *Repository) toDTO(item model.PaymentMerchantConfig, includeSecret bool) (ConfigDTO, error) { dto := ConfigDTO{ @@ -492,6 +514,9 @@ func (r *Repository) validateCreateRequest(req CreateRequest) error { if req.SignType != "" && !isValidSignType(req.SignType) { return ErrInvalidSignType } + if req.Status != "" && !isValidStatus(req.Status) { + return ErrInvalidStatus + } // leshua 特定验证 if req.Provider == "leshua" { @@ -555,6 +580,10 @@ func isValidSignType(value string) bool { return value == "MD5" || value == "SHA256withRSA" } +func isValidStatus(value string) bool { + return value == "active" || value == "disabled" || value == "testing" +} + func extraString(config map[string]any, key string) string { if config == nil { return "" diff --git a/frontend/src/features/admin/components/PaymentConfigDialog.vue b/frontend/src/features/admin/components/PaymentConfigDialog.vue index 1a618cb..eeadf18 100644 --- a/frontend/src/features/admin/components/PaymentConfigDialog.vue +++ b/frontend/src/features/admin/components/PaymentConfigDialog.vue @@ -287,7 +287,7 @@ function handleClose() { - 每个服务商只能有一个默认配置 + 全局只能启用一个配置,启用后会自动设为默认 diff --git a/frontend/src/features/admin/views/AdminPaymentConfigsView.vue b/frontend/src/features/admin/views/AdminPaymentConfigsView.vue index 9f045e3..b11a97d 100644 --- a/frontend/src/features/admin/views/AdminPaymentConfigsView.vue +++ b/frontend/src/features/admin/views/AdminPaymentConfigsView.vue @@ -173,7 +173,7 @@ function deleteDisabledReason(row: PaymentConfig) {
diff --git a/frontend/src/features/wallet/views/WalletView.vue b/frontend/src/features/wallet/views/WalletView.vue index 2bf10df..df3e5da 100644 --- a/frontend/src/features/wallet/views/WalletView.vue +++ b/frontend/src/features/wallet/views/WalletView.vue @@ -1,5 +1,5 @@