feat: 支付渠道、邮箱配置、存储管理页面添加批量操作功能

- 添加表格多选功能
- 添加批量启用/禁用/删除功能
- 添加统计卡片(总数、已启用、已禁用、启用率)
- 后端添加批量操作API接口
- 存储配置批量删除保护本地存储
This commit is contained in:
2026-05-02 18:07:19 +08:00
parent 9b82fbef4e
commit 00067b1bff
9 changed files with 525 additions and 15 deletions
@@ -20,6 +20,8 @@ func SetupEmailConfigRoutes(r *gin.RouterGroup) {
emailConfigs.DELETE("/:id", handleDeleteSystemEmailConfig)
emailConfigs.PUT("/:id/status", handleUpdateSystemEmailConfigStatus)
emailConfigs.POST("/:id/test", handleTestSystemEmailConfig)
emailConfigs.PUT("/batch/status", handleBatchUpdateEmailConfigStatus)
emailConfigs.DELETE("/batch", handleBatchDeleteEmailConfigs)
}
}
@@ -301,3 +303,84 @@ func handleTestSystemEmailConfig(c *gin.Context) {
"message": "测试邮件已发送",
})
}
type BatchUpdateEmailConfigStatusRequest struct {
IDs []uint `json:"ids"`
Status string `json:"status"`
}
func handleBatchUpdateEmailConfigStatus(c *gin.Context) {
var req BatchUpdateEmailConfigStatusRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "参数错误",
})
return
}
if req.Status != "active" && req.Status != "inactive" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "无效的状态",
})
return
}
if len(req.IDs) == 0 {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "请选择要更新的邮箱配置",
})
return
}
if err := database.DB.Model(&model.EmailConfig{}).Where("id IN ?", req.IDs).Update("status", req.Status).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "批量更新失败",
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "批量更新成功",
})
}
type BatchDeleteEmailConfigsRequest struct {
IDs []uint `json:"ids"`
}
func handleBatchDeleteEmailConfigs(c *gin.Context) {
var req BatchDeleteEmailConfigsRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "参数错误",
})
return
}
if len(req.IDs) == 0 {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "请选择要删除的邮箱配置",
})
return
}
if err := database.DB.Where("id IN ?", req.IDs).Delete(&model.EmailConfig{}).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "批量删除失败",
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "批量删除成功",
})
}
@@ -20,6 +20,8 @@ func SetupStorageConfigRoutes(r *gin.RouterGroup) {
storageConfigs.PUT("/:id/status", handleUpdateStorageConfigStatus)
storageConfigs.PUT("/:id/default", handleSetDefaultStorageConfig)
storageConfigs.POST("/:id/test", handleTestStorageConfig)
storageConfigs.PUT("/batch/status", handleBatchUpdateStorageConfigStatus)
storageConfigs.DELETE("/batch", handleBatchDeleteStorageConfigs)
}
}
@@ -317,3 +319,94 @@ func handleTestStorageConfig(c *gin.Context) {
"message": "连接成功",
})
}
type BatchUpdateStorageConfigStatusRequest struct {
IDs []uint `json:"ids"`
Status string `json:"status"`
}
func handleBatchUpdateStorageConfigStatus(c *gin.Context) {
var req BatchUpdateStorageConfigStatusRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "参数错误",
})
return
}
if req.Status != "active" && req.Status != "inactive" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "无效的状态",
})
return
}
if len(req.IDs) == 0 {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "请选择要更新的存储配置",
})
return
}
if err := database.DB.Model(&model.StorageConfig{}).Where("id IN ?", req.IDs).Update("status", req.Status).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "批量更新失败",
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "批量更新成功",
})
}
type BatchDeleteStorageConfigsRequest struct {
IDs []uint `json:"ids"`
}
func handleBatchDeleteStorageConfigs(c *gin.Context) {
var req BatchDeleteStorageConfigsRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "参数错误",
})
return
}
if len(req.IDs) == 0 {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "请选择要删除的存储配置",
})
return
}
var localConfigs []model.StorageConfig
database.DB.Where("id IN ? AND type = ?", req.IDs, "local").Find(&localConfigs)
if len(localConfigs) > 0 {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "本地存储不能删除",
})
return
}
if err := database.DB.Where("id IN ?", req.IDs).Delete(&model.StorageConfig{}).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "批量删除失败",
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "批量删除成功",
})
}
@@ -35,6 +35,8 @@ func SetupSystemSettingsRoutes(r *gin.RouterGroup) {
paymentChannels.PUT("/:id", handleUpdatePaymentChannel)
paymentChannels.DELETE("/:id", handleDeletePaymentChannel)
paymentChannels.PUT("/:id/status", handleUpdatePaymentChannelStatus)
paymentChannels.PUT("/batch/status", handleBatchUpdatePaymentChannelStatus)
paymentChannels.DELETE("/batch", handleBatchDeletePaymentChannels)
}
}
@@ -682,3 +684,84 @@ func handleUpdatePaymentChannelStatus(c *gin.Context) {
"message": "更新成功",
})
}
type BatchUpdatePaymentChannelStatusRequest struct {
IDs []uint `json:"ids"`
Status string `json:"status"`
}
func handleBatchUpdatePaymentChannelStatus(c *gin.Context) {
var req BatchUpdatePaymentChannelStatusRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "参数错误",
})
return
}
if req.Status != "active" && req.Status != "inactive" {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "无效的状态",
})
return
}
if len(req.IDs) == 0 {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "请选择要更新的支付渠道",
})
return
}
if err := database.DB.Model(&model.PaymentChannel{}).Where("id IN ?", req.IDs).Update("status", req.Status).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "批量更新失败",
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "批量更新成功",
})
}
type BatchDeletePaymentChannelsRequest struct {
IDs []uint `json:"ids"`
}
func handleBatchDeletePaymentChannels(c *gin.Context) {
var req BatchDeletePaymentChannelsRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "参数错误",
})
return
}
if len(req.IDs) == 0 {
c.JSON(http.StatusBadRequest, gin.H{
"code": 400,
"message": "请选择要删除的支付渠道",
})
return
}
if err := database.DB.Where("id IN ?", req.IDs).Delete(&model.PaymentChannel{}).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"code": 500,
"message": "批量删除失败",
})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 200,
"message": "批量删除成功",
})
}