feat():learning后台管理项目初始化
This commit is contained in:
73
internal/api/handlers/audit_log_handler.go
Normal file
73
internal/api/handlers/audit_log_handler.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AuditLogHandler 审计日志处理器
|
||||
type AuditLogHandler struct {
|
||||
service services.AuditLogService
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
// NewAuditLogHandler 创建审计日志处理器
|
||||
func NewAuditLogHandler(service services.AuditLogService) *AuditLogHandler {
|
||||
return &AuditLogHandler{
|
||||
service: service,
|
||||
response: utils.NewResponse(),
|
||||
}
|
||||
}
|
||||
|
||||
// List 获取审计日志列表
|
||||
func (h *AuditLogHandler) List(c *gin.Context) {
|
||||
var req models.AuditLogListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if req.Page < 1 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Size < 1 {
|
||||
req.Size = 20
|
||||
}
|
||||
if req.SortBy == "" {
|
||||
req.SortBy = "operation_time"
|
||||
}
|
||||
if req.SortOrder == "" {
|
||||
req.SortOrder = "desc"
|
||||
}
|
||||
|
||||
result, err := h.service.List(&req)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result)
|
||||
}
|
||||
|
||||
// GetByID 获取审计日志详情
|
||||
func (h *AuditLogHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
log, err := h.service.GetByID(uint(id))
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, log)
|
||||
}
|
||||
633
internal/api/handlers/finance_handler.go
Normal file
633
internal/api/handlers/finance_handler.go
Normal file
@@ -0,0 +1,633 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
)
|
||||
|
||||
type FinanceHandler struct {
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
func NewFinanceHandler() *FinanceHandler {
|
||||
return &FinanceHandler{response: utils.NewResponse()}
|
||||
}
|
||||
|
||||
func getPageParams(c *gin.Context) (int, int) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if size < 1 {
|
||||
size = 20
|
||||
}
|
||||
offset := (page - 1) * size
|
||||
return offset, size
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) ListSandboxRecords(c *gin.Context) {
|
||||
offset, size := getPageParams(c)
|
||||
// 兼容多种参数命名:user/user_id,project/project_id
|
||||
userID := c.DefaultQuery("user_id", c.Query("user"))
|
||||
project := c.DefaultQuery("project", c.Query("project_id"))
|
||||
start := c.Query("start")
|
||||
end := c.Query("end")
|
||||
res, err := services.ListSandboxRecords(offset, size, userID, project, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Page(c, res.List, res.Total, offset/size+1, size)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) ListTokenUsages(c *gin.Context) {
|
||||
offset, size := getPageParams(c)
|
||||
userID := c.DefaultQuery("user_id", c.Query("user"))
|
||||
project := c.DefaultQuery("project", c.Query("project_id"))
|
||||
start := c.Query("start") // 对于token使用,按day进行过滤
|
||||
end := c.Query("end")
|
||||
res, err := services.ListTokenUsages(offset, size, userID, project, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Page(c, res.List, res.Total, offset/size+1, size)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) ListMCPUsages(c *gin.Context) {
|
||||
offset, size := getPageParams(c)
|
||||
userID := c.DefaultQuery("user_id", c.Query("user"))
|
||||
project := c.DefaultQuery("project", c.Query("project_id"))
|
||||
start := c.Query("start")
|
||||
end := c.Query("end")
|
||||
res, err := services.ListMCPUsages(offset, size, userID, project, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Page(c, res.List, res.Total, offset/size+1, size)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) ListTransactionLogs(c *gin.Context) {
|
||||
offset, size := getPageParams(c)
|
||||
userID := c.Query("user_id")
|
||||
orderID := c.Query("order_id")
|
||||
txType := c.Query("type")
|
||||
status := c.Query("status")
|
||||
start := c.Query("start")
|
||||
end := c.Query("end")
|
||||
res, err := services.ListTransactionLogs(offset, size, userID, orderID, txType, status, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Page(c, res.List, res.Total, offset/size+1, size)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) ListPaymentRecords(c *gin.Context) {
|
||||
offset, size := getPageParams(c)
|
||||
userID := c.Query("user_id")
|
||||
orderID := c.Query("order_id")
|
||||
paypalOrderID := c.Query("paypal_order_id")
|
||||
status := c.Query("status")
|
||||
refundStatus := c.Query("refund_status")
|
||||
payerEmail := c.Query("payer_email")
|
||||
start := c.Query("start")
|
||||
end := c.Query("end")
|
||||
res, err := services.ListPaymentRecords(offset, size, userID, orderID, paypalOrderID, status, refundStatus, payerEmail, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Page(c, res.List, res.Total, offset/size+1, size)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) RefundPaymentRecord(c *gin.Context) {
|
||||
var req struct {
|
||||
OrderID string `json:"order_id"`
|
||||
PayPalCaptureID string `json:"paypal_capture_id"`
|
||||
Amount *int64 `json:"amount"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := services.RefundPaymentRecord(req.OrderID, req.PayPalCaptureID, req.Amount)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "退款请求已提交"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) ListMcpAccountRechargeRecords(c *gin.Context) {
|
||||
offset, size := getPageParams(c)
|
||||
provider := c.Query("provider")
|
||||
account := c.Query("account")
|
||||
start := c.Query("start")
|
||||
end := c.Query("end")
|
||||
res, err := services.ListMcpAccountRechargeRecords(offset, size, provider, account, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Page(c, res.List, res.Total, offset/size+1, size)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) CreateMcpAccountRechargeRecord(c *gin.Context) {
|
||||
var req struct {
|
||||
ProviderID string `json:"provider_id" binding:"required"`
|
||||
Amount float64 `json:"amount" binding:"required,gt=0"`
|
||||
RechargeDate string `json:"recharge_date" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取当前操作人信息
|
||||
var operatorID interface{}
|
||||
operatorName := "系统管理员"
|
||||
if user, exists := c.Get("user"); exists {
|
||||
if userInfo, ok := user.(map[string]interface{}); ok {
|
||||
// 尝试从userInfo中获取sub字段(可能是UUID格式)
|
||||
if sub, ok := userInfo["sub"].(string); ok {
|
||||
operatorID = sub
|
||||
}
|
||||
if name, ok := userInfo["name"].(string); ok {
|
||||
operatorName = name
|
||||
} else if email, ok := userInfo["email"].(string); ok {
|
||||
operatorName = email
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果user中没有sub,尝试从user_id获取
|
||||
if operatorID == nil {
|
||||
operatorID, _ = c.Get("user_id")
|
||||
}
|
||||
|
||||
err := services.CreateMcpAccountRechargeRecord(
|
||||
req.ProviderID,
|
||||
req.Amount,
|
||||
req.RechargeDate,
|
||||
operatorID,
|
||||
operatorName,
|
||||
req.Remark,
|
||||
)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "创建成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) UpdateMcpAccountRechargeRecord(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var req struct {
|
||||
Amount *float64 `json:"amount"`
|
||||
RechargeDate *string `json:"recharge_date"`
|
||||
Remark *string `json:"remark"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := services.UpdateMcpAccountRechargeRecord(id, req.Amount, req.RechargeDate, req.Remark)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "更新成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) DeleteMcpAccountRechargeRecord(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
err := services.DeleteMcpAccountRechargeRecord(id)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "删除成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) GetMcpProviderAccounts(c *gin.Context) {
|
||||
status := c.Query("status")
|
||||
var isUsed *bool
|
||||
if v := c.Query("is_used"); v != "" {
|
||||
if v == "true" {
|
||||
val := true
|
||||
isUsed = &val
|
||||
} else if v == "false" {
|
||||
val := false
|
||||
isUsed = &val
|
||||
}
|
||||
}
|
||||
|
||||
list, err := services.GetMcpProviderAccounts(status, isUsed)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, list)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) GetMcpAccountBalances(c *gin.Context) {
|
||||
list, err := services.GetMcpAccountBalances()
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, list)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) GetMcpAccountBalanceHistory(c *gin.Context) {
|
||||
providerID := c.Param("provider_id")
|
||||
start := c.Query("start")
|
||||
end := c.Query("end")
|
||||
|
||||
list, err := services.GetMcpAccountBalanceHistory(providerID, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, list)
|
||||
}
|
||||
|
||||
// ========== 模型账号充值记录和余额管理 ==========
|
||||
|
||||
func (h *FinanceHandler) ListModelAccountRechargeRecords(c *gin.Context) {
|
||||
offset, size := getPageParams(c)
|
||||
provider := c.Query("provider")
|
||||
modelName := c.Query("model_name")
|
||||
start := c.Query("start")
|
||||
end := c.Query("end")
|
||||
res, err := services.ListModelAccountRechargeRecords(offset, size, provider, modelName, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Page(c, res.List, res.Total, offset/size+1, size)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) CreateModelAccountRechargeRecord(c *gin.Context) {
|
||||
var req struct {
|
||||
Account string `json:"account" binding:"required"`
|
||||
Amount float64 `json:"amount" binding:"required,gt=0"`
|
||||
RechargeDate string `json:"recharge_date" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取当前操作人信息
|
||||
var operatorID interface{}
|
||||
operatorName := "系统管理员"
|
||||
|
||||
// 先尝试从 user_id 获取
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
operatorID = userID
|
||||
}
|
||||
|
||||
// 从 user 信息中获取名称
|
||||
if user, exists := c.Get("user"); exists {
|
||||
// user 可能是 *models.UserInfo 类型
|
||||
if userInfo, ok := user.(map[string]interface{}); ok {
|
||||
if name, ok := userInfo["name"].(string); ok && name != "" {
|
||||
operatorName = name
|
||||
} else if email, ok := userInfo["email"].(string); ok && email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
} else {
|
||||
// 尝试使用反射获取结构体字段
|
||||
userVal := reflect.ValueOf(user)
|
||||
if userVal.Kind() == reflect.Ptr {
|
||||
userVal = userVal.Elem()
|
||||
}
|
||||
if userVal.Kind() == reflect.Struct {
|
||||
if nameField := userVal.FieldByName("Name"); nameField.IsValid() && nameField.Kind() == reflect.String {
|
||||
if name := nameField.String(); name != "" {
|
||||
operatorName = name
|
||||
}
|
||||
}
|
||||
if operatorName == "系统管理员" {
|
||||
if emailField := userVal.FieldByName("Email"); emailField.IsValid() && emailField.Kind() == reflect.String {
|
||||
if email := emailField.String(); email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := services.CreateModelAccountRechargeRecord(
|
||||
req.Account,
|
||||
req.Amount,
|
||||
req.RechargeDate,
|
||||
operatorID,
|
||||
operatorName,
|
||||
req.Remark,
|
||||
)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "创建成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) UpdateModelAccountRechargeRecord(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var req struct {
|
||||
Amount *float64 `json:"amount"`
|
||||
RechargeDate *string `json:"recharge_date"`
|
||||
Remark *string `json:"remark"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := services.UpdateModelAccountRechargeRecord(id, req.Amount, req.RechargeDate, req.Remark)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "更新成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) DeleteModelAccountRechargeRecord(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
err := services.DeleteModelAccountRechargeRecord(id)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "删除成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) GetModelConfigAccounts(c *gin.Context) {
|
||||
var enabled *bool
|
||||
if v := c.Query("enabled"); v != "" {
|
||||
if v == "true" {
|
||||
val := true
|
||||
enabled = &val
|
||||
} else if v == "false" {
|
||||
val := false
|
||||
enabled = &val
|
||||
}
|
||||
}
|
||||
|
||||
list, err := services.GetModelConfigAccounts(enabled)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, list)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) GetModelAccountBalances(c *gin.Context) {
|
||||
list, err := services.GetModelAccountBalances()
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, list)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) GetModelAccountBalanceHistory(c *gin.Context) {
|
||||
account := c.Param("account")
|
||||
start := c.Query("start")
|
||||
end := c.Query("end")
|
||||
|
||||
list, err := services.GetModelAccountBalanceHistory(account, start, end)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, list)
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) AdjustMcpAccountBalance(c *gin.Context) {
|
||||
providerID := c.Param("provider_id")
|
||||
var req struct {
|
||||
Balance float64 `json:"balance" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
operatorName := "系统管理员"
|
||||
if user, exists := c.Get("user"); exists {
|
||||
if userInfo, ok := user.(map[string]interface{}); ok {
|
||||
if name, ok := userInfo["name"].(string); ok && name != "" {
|
||||
operatorName = name
|
||||
} else if email, ok := userInfo["email"].(string); ok && email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
} else {
|
||||
userVal := reflect.ValueOf(user)
|
||||
if userVal.Kind() == reflect.Ptr {
|
||||
userVal = userVal.Elem()
|
||||
}
|
||||
if userVal.Kind() == reflect.Struct {
|
||||
if nameField := userVal.FieldByName("Name"); nameField.IsValid() && nameField.Kind() == reflect.String {
|
||||
if name := nameField.String(); name != "" {
|
||||
operatorName = name
|
||||
}
|
||||
}
|
||||
if operatorName == "系统管理员" {
|
||||
if emailField := userVal.FieldByName("Email"); emailField.IsValid() && emailField.Kind() == reflect.String {
|
||||
if email := emailField.String(); email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := services.AdjustMcpAccountBalance(providerID, req.Balance, operatorName, req.Remark); err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"message": "更新成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) AdjustModelAccountBalance(c *gin.Context) {
|
||||
account := c.Param("account")
|
||||
var req struct {
|
||||
Balance float64 `json:"balance" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
operatorName := "系统管理员"
|
||||
if user, exists := c.Get("user"); exists {
|
||||
if userInfo, ok := user.(map[string]interface{}); ok {
|
||||
if name, ok := userInfo["name"].(string); ok && name != "" {
|
||||
operatorName = name
|
||||
} else if email, ok := userInfo["email"].(string); ok && email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
} else {
|
||||
userVal := reflect.ValueOf(user)
|
||||
if userVal.Kind() == reflect.Ptr {
|
||||
userVal = userVal.Elem()
|
||||
}
|
||||
if userVal.Kind() == reflect.Struct {
|
||||
if nameField := userVal.FieldByName("Name"); nameField.IsValid() && nameField.Kind() == reflect.String {
|
||||
if name := nameField.String(); name != "" {
|
||||
operatorName = name
|
||||
}
|
||||
}
|
||||
if operatorName == "系统管理员" {
|
||||
if emailField := userVal.FieldByName("Email"); emailField.IsValid() && emailField.Kind() == reflect.String {
|
||||
if email := emailField.String(); email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := services.AdjustModelAccountBalance(account, req.Balance, operatorName, req.Remark); err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"message": "更新成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) CreateModelAccountBalance(c *gin.Context) {
|
||||
var req struct {
|
||||
Account string `json:"account" binding:"required"`
|
||||
Balance float64 `json:"balance" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
operatorName := "系统管理员"
|
||||
if user, exists := c.Get("user"); exists {
|
||||
if userInfo, ok := user.(map[string]interface{}); ok {
|
||||
if name, ok := userInfo["name"].(string); ok && name != "" {
|
||||
operatorName = name
|
||||
} else if email, ok := userInfo["email"].(string); ok && email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
} else {
|
||||
userVal := reflect.ValueOf(user)
|
||||
if userVal.Kind() == reflect.Ptr {
|
||||
userVal = userVal.Elem()
|
||||
}
|
||||
if userVal.Kind() == reflect.Struct {
|
||||
if nameField := userVal.FieldByName("Name"); nameField.IsValid() && nameField.Kind() == reflect.String {
|
||||
if name := nameField.String(); name != "" {
|
||||
operatorName = name
|
||||
}
|
||||
}
|
||||
if operatorName == "系统管理员" {
|
||||
if emailField := userVal.FieldByName("Email"); emailField.IsValid() && emailField.Kind() == reflect.String {
|
||||
if email := emailField.String(); email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := services.CreateModelAccountBalanceRecord(req.Account, req.Balance, operatorName, req.Remark); err != nil {
|
||||
if strings.Contains(err.Error(), "已存在") {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
} else {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"message": "创建成功"})
|
||||
}
|
||||
|
||||
func (h *FinanceHandler) CreateMcpAccountBalance(c *gin.Context) {
|
||||
var req struct {
|
||||
ProviderID string `json:"provider_id" binding:"required"`
|
||||
Balance float64 `json:"balance" binding:"required"`
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
operatorName := "系统管理员"
|
||||
if user, exists := c.Get("user"); exists {
|
||||
if userInfo, ok := user.(map[string]interface{}); ok {
|
||||
if name, ok := userInfo["name"].(string); ok && name != "" {
|
||||
operatorName = name
|
||||
} else if email, ok := userInfo["email"].(string); ok && email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
} else {
|
||||
userVal := reflect.ValueOf(user)
|
||||
if userVal.Kind() == reflect.Ptr {
|
||||
userVal = userVal.Elem()
|
||||
}
|
||||
if userVal.Kind() == reflect.Struct {
|
||||
if nameField := userVal.FieldByName("Name"); nameField.IsValid() && nameField.Kind() == reflect.String {
|
||||
if name := nameField.String(); name != "" {
|
||||
operatorName = name
|
||||
}
|
||||
}
|
||||
if operatorName == "系统管理员" {
|
||||
if emailField := userVal.FieldByName("Email"); emailField.IsValid() && emailField.Kind() == reflect.String {
|
||||
if email := emailField.String(); email != "" {
|
||||
operatorName = email
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := services.CreateMcpAccountBalanceRecord(req.ProviderID, req.Balance, operatorName, req.Remark); err != nil {
|
||||
if strings.Contains(err.Error(), "已存在") {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
} else {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "创建成功"})
|
||||
}
|
||||
245
internal/api/handlers/goalfymax_user_handler.go
Normal file
245
internal/api/handlers/goalfymax_user_handler.go
Normal file
@@ -0,0 +1,245 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type GoalfyMaxUserHandler struct {
|
||||
service services.GoalfyMaxUserService
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
func NewGoalfyMaxUserHandler(s services.GoalfyMaxUserService) *GoalfyMaxUserHandler {
|
||||
return &GoalfyMaxUserHandler{service: s, response: utils.NewResponse()}
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) List(c *gin.Context) {
|
||||
var req models.GoalfyMaxUserListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
users, total, err := h.service.List(&req)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"users": users, "total": total, "page": req.Page, "size": req.Size})
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id64, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
user, err := h.service.GetByID(uint(id64))
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, user)
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) Create(c *gin.Context) {
|
||||
var req models.GoalfyMaxUserCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
user, err := h.service.Create(&req)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, user)
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) Update(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id64, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
var req models.GoalfyMaxUserUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
user, err := h.service.Update(uint(id64), &req)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, user)
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) Delete(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id64, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
if err := h.service.Delete(uint(id64)); err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"message": "删除成功"})
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) Ban(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id64, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
var req models.GoalfyMaxUserBanRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 从上下文获取当前管理员ID
|
||||
adminID := 0
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
switch v := userID.(type) {
|
||||
case int:
|
||||
adminID = v
|
||||
case uint:
|
||||
adminID = int(v)
|
||||
case string:
|
||||
if parsedID, err := strconv.Atoi(v); err == nil {
|
||||
adminID = parsedID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.service.Ban(uint(id64), &req, adminID); err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"message": "封禁成功"})
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) Unban(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id64, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
if err := h.service.Unban(uint(id64)); err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"message": "解封成功"})
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) AddBalance(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id64, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
var req models.GoalfyMaxUserAddBalanceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 从上下文获取当前管理员信息
|
||||
operatorID := 0
|
||||
operatorEmail := "system@goalfy.com"
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
switch v := userID.(type) {
|
||||
case int:
|
||||
operatorID = v
|
||||
case uint:
|
||||
operatorID = int(v)
|
||||
case string:
|
||||
if parsedID, err := strconv.Atoi(v); err == nil {
|
||||
operatorID = parsedID
|
||||
}
|
||||
}
|
||||
}
|
||||
// 尝试获取用户邮箱(从userInfo中获取)
|
||||
if userInfo, exists := c.Get("user"); exists {
|
||||
if user, ok := userInfo.(*models.UserInfo); ok && user != nil {
|
||||
if user.Email != "" {
|
||||
operatorEmail = user.Email
|
||||
} else if user.PreferredUsername != "" {
|
||||
operatorEmail = user.PreferredUsername + "@goalfy.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取IP地址和UserAgent
|
||||
ipAddress := c.ClientIP()
|
||||
userAgent := c.Request.UserAgent()
|
||||
|
||||
if err := h.service.AddBalance(uint(id64), &req, operatorID, operatorEmail, ipAddress, userAgent); err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"message": "增加余额成功"})
|
||||
}
|
||||
|
||||
func (h *GoalfyMaxUserHandler) DeductBalance(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id64, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
var req models.GoalfyMaxUserAddBalanceRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 从上下文获取当前管理员信息
|
||||
operatorID := 0
|
||||
operatorEmail := "system@goalfy.com"
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
switch v := userID.(type) {
|
||||
case int:
|
||||
operatorID = v
|
||||
case uint:
|
||||
operatorID = int(v)
|
||||
case string:
|
||||
if parsedID, err := strconv.Atoi(v); err == nil {
|
||||
operatorID = parsedID
|
||||
}
|
||||
}
|
||||
}
|
||||
// 尝试获取用户邮箱(从userInfo中获取)
|
||||
if userInfo, exists := c.Get("user"); exists {
|
||||
if user, ok := userInfo.(*models.UserInfo); ok && user != nil {
|
||||
if user.Email != "" {
|
||||
operatorEmail = user.Email
|
||||
} else if user.PreferredUsername != "" {
|
||||
operatorEmail = user.PreferredUsername + "@goalfy.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取IP地址和UserAgent
|
||||
ipAddress := c.ClientIP()
|
||||
userAgent := c.Request.UserAgent()
|
||||
|
||||
if err := h.service.DeductBalance(uint(id64), &req, operatorID, operatorEmail, ipAddress, userAgent); err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, gin.H{"message": "减少余额成功"})
|
||||
}
|
||||
254
internal/api/handlers/invite_code_application_handler.go
Normal file
254
internal/api/handlers/invite_code_application_handler.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
)
|
||||
|
||||
type InviteCodeApplicationHandler struct {
|
||||
service *services.InviteCodeApplicationService
|
||||
}
|
||||
|
||||
// NewInviteCodeApplicationHandler 创建邀请码申请处理器
|
||||
func NewInviteCodeApplicationHandler(db *gorm.DB) *InviteCodeApplicationHandler {
|
||||
return &InviteCodeApplicationHandler{
|
||||
service: services.NewInviteCodeApplicationService(db),
|
||||
}
|
||||
}
|
||||
|
||||
// SubmitApplication 提交邀请码申请(公开接口,官网使用)
|
||||
func (h *InviteCodeApplicationHandler) SubmitApplication(c *gin.Context) {
|
||||
var req models.InviteCodeApplicationCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "请求参数无效",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
application, err := h.service.SubmitApplication(&req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "申请已提交,我们将在1-2个工作日内处理您的申请",
|
||||
"data": application,
|
||||
})
|
||||
}
|
||||
|
||||
// GetApplicationList 获取申请列表(后台管理接口,需要权限)
|
||||
func (h *InviteCodeApplicationHandler) GetApplicationList(c *gin.Context) {
|
||||
var req models.InviteCodeApplicationListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "请求参数无效",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Size <= 0 {
|
||||
req.Size = 20
|
||||
}
|
||||
|
||||
response, err := h.service.GetApplicationList(&req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "获取申请列表失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": response,
|
||||
})
|
||||
}
|
||||
|
||||
// GetStatistics 获取申请统计(后台管理接口,需要权限)
|
||||
func (h *InviteCodeApplicationHandler) GetStatistics(c *gin.Context) {
|
||||
stats, err := h.service.GetStatistics()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "获取统计信息失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": stats,
|
||||
})
|
||||
}
|
||||
|
||||
// ApproveApplication 审批通过申请(后台管理接口,需要权限)
|
||||
func (h *InviteCodeApplicationHandler) ApproveApplication(c *gin.Context) {
|
||||
var req models.InviteCodeApplicationApproveRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "请求参数无效",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 从上下文获取操作人信息(需要在中间件中设置)
|
||||
approvedBy := c.GetString("username")
|
||||
if approvedBy == "" {
|
||||
approvedBy = "admin"
|
||||
}
|
||||
|
||||
if err := h.service.ApproveApplication(&req, approvedBy); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "审批通过成功",
|
||||
})
|
||||
}
|
||||
|
||||
// RejectApplication 审批拒绝申请(后台管理接口,需要权限)
|
||||
func (h *InviteCodeApplicationHandler) RejectApplication(c *gin.Context) {
|
||||
var req models.InviteCodeApplicationRejectRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "请求参数无效",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 从上下文获取操作人信息(需要在中间件中设置)
|
||||
approvedBy := c.GetString("username")
|
||||
if approvedBy == "" {
|
||||
approvedBy = "admin"
|
||||
}
|
||||
|
||||
if err := h.service.RejectApplication(&req, approvedBy); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "审批拒绝成功",
|
||||
})
|
||||
}
|
||||
|
||||
// BatchApproveApplications 批量审批通过(后台管理接口,需要权限)
|
||||
func (h *InviteCodeApplicationHandler) BatchApproveApplications(c *gin.Context) {
|
||||
var req models.InviteCodeApplicationBatchApproveRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "请求参数无效",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 从上下文获取操作人信息(需要在中间件中设置)
|
||||
approvedBy := c.GetString("username")
|
||||
if approvedBy == "" {
|
||||
approvedBy = "admin"
|
||||
}
|
||||
|
||||
if err := h.service.BatchApproveApplications(&req, approvedBy); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "批量审批通过成功",
|
||||
})
|
||||
}
|
||||
|
||||
// BatchRejectApplications 批量审批拒绝(后台管理接口,需要权限)
|
||||
func (h *InviteCodeApplicationHandler) BatchRejectApplications(c *gin.Context) {
|
||||
var req models.InviteCodeApplicationBatchRejectRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "请求参数无效",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 从上下文获取操作人信息(需要在中间件中设置)
|
||||
approvedBy := c.GetString("username")
|
||||
if approvedBy == "" {
|
||||
approvedBy = "admin"
|
||||
}
|
||||
|
||||
if err := h.service.BatchRejectApplications(&req, approvedBy); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "批量审批拒绝成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetPendingCount 获取待处理申请数量(后台管理接口,需要权限)
|
||||
func (h *InviteCodeApplicationHandler) GetPendingCount(c *gin.Context) {
|
||||
count, err := h.service.GetPendingApplicationsCount()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "获取待处理数量失败",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": gin.H{
|
||||
"count": count,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterRoutes 注册路由
|
||||
func (h *InviteCodeApplicationHandler) RegisterRoutes(router *gin.RouterGroup, authMiddleware gin.HandlerFunc) {
|
||||
// 公开接口(官网提交申请)
|
||||
public := router.Group("/public")
|
||||
{
|
||||
public.POST("/invite-code/apply", h.SubmitApplication)
|
||||
}
|
||||
|
||||
// 需要认证的接口(后台管理)
|
||||
protected := router.Group("/invite-code/applications")
|
||||
protected.Use(authMiddleware)
|
||||
{
|
||||
protected.GET("", h.GetApplicationList)
|
||||
protected.GET("/statistics", h.GetStatistics)
|
||||
protected.GET("/pending-count", h.GetPendingCount)
|
||||
protected.POST("/approve", h.ApproveApplication)
|
||||
protected.POST("/reject", h.RejectApplication)
|
||||
protected.POST("/batch-approve", h.BatchApproveApplications)
|
||||
protected.POST("/batch-reject", h.BatchRejectApplications)
|
||||
}
|
||||
}
|
||||
458
internal/api/handlers/invite_code_handler.go
Normal file
458
internal/api/handlers/invite_code_handler.go
Normal file
@@ -0,0 +1,458 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"goalfymax-admin/internal/config"
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type InviteCodeHandler struct {
|
||||
service services.InviteCodeService
|
||||
userLevelService services.UserLevelConfigService
|
||||
}
|
||||
|
||||
func NewInviteCodeHandler(service services.InviteCodeService, userLevelService services.UserLevelConfigService) *InviteCodeHandler {
|
||||
return &InviteCodeHandler{
|
||||
service: service,
|
||||
userLevelService: userLevelService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetInviteCodeList 获取邀请码列表
|
||||
func (h *InviteCodeHandler) GetInviteCodeList(c *gin.Context) {
|
||||
var req models.InviteCodeListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认分页参数
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Size <= 0 {
|
||||
req.Size = 20
|
||||
}
|
||||
|
||||
response, err := h.service.List(&req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// enrich invite_url
|
||||
base := config.GetConfig().SSO.SSOServerURL
|
||||
base = strings.TrimRight(base, "/")
|
||||
enriched := make([]gin.H, 0, len(response.List))
|
||||
for _, item := range response.List {
|
||||
// 获取用户等级信息
|
||||
var userLevelName string
|
||||
if item.UserLevelID != nil {
|
||||
if level, err := h.userLevelService.GetByID(*item.UserLevelID); err == nil {
|
||||
userLevelName = level.LevelName
|
||||
}
|
||||
}
|
||||
|
||||
enriched = append(enriched, gin.H{
|
||||
"id": item.ID,
|
||||
"code": item.Code,
|
||||
"is_used": item.IsUsed,
|
||||
"client_id": item.ClientID,
|
||||
"client_label": config.GetClientValue(item.ClientID),
|
||||
"email": item.Email,
|
||||
"user_level_id": item.UserLevelID,
|
||||
"user_level_name": userLevelName,
|
||||
"expires_at": item.ExpiresAt,
|
||||
"created_at": item.CreatedAt,
|
||||
"invite_url": base + "/invite/" + item.Code,
|
||||
})
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "获取成功",
|
||||
"data": gin.H{
|
||||
"list": enriched,
|
||||
"total": response.Total,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetInviteCodeDetail 获取邀请码详情
|
||||
func (h *InviteCodeHandler) GetInviteCodeDetail(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "ID格式错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
inviteCode, err := h.service.GetByID(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": 404,
|
||||
"message": "邀请码不存在",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
base := config.GetConfig().SSO.SSOServerURL
|
||||
base = strings.TrimRight(base, "/")
|
||||
|
||||
// 获取用户等级信息
|
||||
var userLevelName string
|
||||
if inviteCode.UserLevelID != nil {
|
||||
if level, err := h.userLevelService.GetByID(*inviteCode.UserLevelID); err == nil {
|
||||
userLevelName = level.LevelName
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "获取成功",
|
||||
"data": gin.H{
|
||||
"id": inviteCode.ID,
|
||||
"code": inviteCode.Code,
|
||||
"is_used": inviteCode.IsUsed,
|
||||
"client_id": inviteCode.ClientID,
|
||||
"client_label": config.GetClientValue(inviteCode.ClientID),
|
||||
"email": inviteCode.Email,
|
||||
"user_level_id": inviteCode.UserLevelID,
|
||||
"user_level_name": userLevelName,
|
||||
"expires_at": inviteCode.ExpiresAt,
|
||||
"created_at": inviteCode.CreatedAt,
|
||||
"invite_url": base + "/invite/" + inviteCode.Code,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// validateEmail 验证邮箱格式
|
||||
func validateEmail(email string) bool {
|
||||
emailRegex := regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
|
||||
return emailRegex.MatchString(email)
|
||||
}
|
||||
|
||||
// CreateInviteCode 创建邀请码(支持设置过期时间和邮箱列表)
|
||||
func (h *InviteCodeHandler) CreateInviteCode(c *gin.Context) {
|
||||
var req models.InviteCodeCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "参数错误:" + err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证邮箱格式
|
||||
if len(req.Emails) > 0 {
|
||||
for _, email := range req.Emails {
|
||||
if email != "" && !validateEmail(email) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "邮箱格式不正确: " + email,
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证用户等级ID是否存在且启用
|
||||
if req.UserLevelID != nil {
|
||||
userLevel, err := h.userLevelService.GetByID(*req.UserLevelID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "用户等级不存在",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
if userLevel.Status != 1 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "用户等级已禁用",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
inviteCodes, err := h.service.Create(&req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
base := config.GetConfig().SSO.SSOServerURL
|
||||
base = strings.TrimRight(base, "/")
|
||||
|
||||
// 如果只创建了一个邀请码,返回单个对象(向后兼容)
|
||||
if len(inviteCodes) == 1 {
|
||||
inviteCode := inviteCodes[0]
|
||||
var userLevelName string
|
||||
if inviteCode.UserLevelID != nil {
|
||||
if level, err := h.userLevelService.GetByID(*inviteCode.UserLevelID); err == nil {
|
||||
userLevelName = level.LevelName
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": gin.H{
|
||||
"id": inviteCode.ID,
|
||||
"code": inviteCode.Code,
|
||||
"is_used": inviteCode.IsUsed,
|
||||
"client_id": inviteCode.ClientID,
|
||||
"client_label": config.GetClientValue(inviteCode.ClientID),
|
||||
"email": inviteCode.Email,
|
||||
"user_level_id": inviteCode.UserLevelID,
|
||||
"user_level_name": userLevelName,
|
||||
"expires_at": inviteCode.ExpiresAt,
|
||||
"created_at": inviteCode.CreatedAt,
|
||||
"invite_url": base + "/invite/" + inviteCode.Code,
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 如果创建了多个邀请码,返回数组
|
||||
enriched := make([]gin.H, 0, len(inviteCodes))
|
||||
for _, inviteCode := range inviteCodes {
|
||||
var userLevelName string
|
||||
if inviteCode.UserLevelID != nil {
|
||||
if level, err := h.userLevelService.GetByID(*inviteCode.UserLevelID); err == nil {
|
||||
userLevelName = level.LevelName
|
||||
}
|
||||
}
|
||||
|
||||
enriched = append(enriched, gin.H{
|
||||
"id": inviteCode.ID,
|
||||
"code": inviteCode.Code,
|
||||
"is_used": inviteCode.IsUsed,
|
||||
"client_id": inviteCode.ClientID,
|
||||
"client_label": config.GetClientValue(inviteCode.ClientID),
|
||||
"email": inviteCode.Email,
|
||||
"user_level_id": inviteCode.UserLevelID,
|
||||
"user_level_name": userLevelName,
|
||||
"expires_at": inviteCode.ExpiresAt,
|
||||
"created_at": inviteCode.CreatedAt,
|
||||
"invite_url": base + "/invite/" + inviteCode.Code,
|
||||
})
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "创建成功",
|
||||
"data": enriched,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateInviteCode 更新邀请码(支持更新过期时间)
|
||||
func (h *InviteCodeHandler) UpdateInviteCode(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "ID格式错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req models.InviteCodeUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
inviteCode, err := h.service.Update(uint(id), &req)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
base := config.GetConfig().SSO.SSOServerURL
|
||||
base = strings.TrimRight(base, "/")
|
||||
|
||||
// 获取用户等级信息
|
||||
var userLevelName string
|
||||
if inviteCode.UserLevelID != nil {
|
||||
if level, err := h.userLevelService.GetByID(*inviteCode.UserLevelID); err == nil {
|
||||
userLevelName = level.LevelName
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "更新成功",
|
||||
"data": gin.H{
|
||||
"id": inviteCode.ID,
|
||||
"code": inviteCode.Code,
|
||||
"is_used": inviteCode.IsUsed,
|
||||
"client_id": inviteCode.ClientID,
|
||||
"client_label": config.GetClientValue(inviteCode.ClientID),
|
||||
"email": inviteCode.Email,
|
||||
"user_level_id": inviteCode.UserLevelID,
|
||||
"user_level_name": userLevelName,
|
||||
"expires_at": inviteCode.ExpiresAt,
|
||||
"created_at": inviteCode.CreatedAt,
|
||||
"invite_url": base + "/invite/" + inviteCode.Code,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteInviteCode 删除邀请码
|
||||
func (h *InviteCodeHandler) DeleteInviteCode(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "ID格式错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.Delete(uint(id))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "删除成功",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
// GetInviteCodeStatistics 获取统计信息
|
||||
func (h *InviteCodeHandler) GetInviteCodeStatistics(c *gin.Context) {
|
||||
stats, err := h.service.GetStatistics()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "获取成功",
|
||||
"data": stats,
|
||||
})
|
||||
}
|
||||
|
||||
// MarkInviteCodeAsUsed 标记邀请码为已使用
|
||||
func (h *InviteCodeHandler) MarkInviteCodeAsUsed(c *gin.Context) {
|
||||
var req struct {
|
||||
Code string `json:"code" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := h.service.MarkAsUsed(req.Code)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "标记成功",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
// ValidateInviteCode 验证邀请码是否有效
|
||||
func (h *InviteCodeHandler) ValidateInviteCode(c *gin.Context) {
|
||||
var req struct {
|
||||
Code string `json:"code" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": "参数错误",
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := h.service.ValidateInviteCode(req.Code)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": 400,
|
||||
"message": err.Error(),
|
||||
"data": nil,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "邀请码有效",
|
||||
"data": nil,
|
||||
})
|
||||
}
|
||||
|
||||
// GetClientOptions 获取客户端选项列表
|
||||
func (h *InviteCodeHandler) GetClientOptions(c *gin.Context) {
|
||||
options := config.GetClientOptions()
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "获取成功",
|
||||
"data": options,
|
||||
})
|
||||
}
|
||||
186
internal/api/handlers/mcp_provider_handler.go
Normal file
186
internal/api/handlers/mcp_provider_handler.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"goalfymax-admin/internal/storage"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type MCPProvider struct {
|
||||
ID uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
|
||||
Provider string `json:"provider"`
|
||||
BaseURL string `json:"base_url"`
|
||||
Auth *string `json:"auth"`
|
||||
Account *string `json:"account"`
|
||||
PriceType string `json:"price_type"`
|
||||
Price float64 `json:"price"`
|
||||
FloatingRatio float64 `json:"floating_ratio"`
|
||||
IsUsed bool `json:"is_used"`
|
||||
Status string `json:"status"`
|
||||
Description *string `json:"description"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
type MCPProviderHandler struct {
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
func NewMCPProviderHandler() *MCPProviderHandler {
|
||||
return &MCPProviderHandler{response: utils.NewResponse()}
|
||||
}
|
||||
|
||||
func (h *MCPProviderHandler) List(c *gin.Context) {
|
||||
db := storage.GetPG()
|
||||
if db == nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"message": "PostgreSQL未初始化"})
|
||||
return
|
||||
}
|
||||
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "10"))
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if size <= 0 {
|
||||
size = 10
|
||||
}
|
||||
offset := (page - 1) * size
|
||||
|
||||
q := db.Table("mcp_providers")
|
||||
if v := c.Query("provider"); v != "" {
|
||||
q = q.Where("provider ILIKE ?", "%"+v+"%")
|
||||
}
|
||||
if v := c.Query("status"); v != "" {
|
||||
q = q.Where("status = ?", v)
|
||||
}
|
||||
if v := c.Query("is_used"); v != "" {
|
||||
if v == "true" {
|
||||
q = q.Where("is_used = ?", true)
|
||||
} else if v == "false" {
|
||||
q = q.Where("is_used = ?", false)
|
||||
}
|
||||
}
|
||||
|
||||
var total int64
|
||||
if err := q.Count(&total).Error; err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
var list []MCPProvider
|
||||
if err := q.Order("created_at DESC").Offset(offset).Limit(size).Find(&list).Error; err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Page(c, list, total, page, size)
|
||||
}
|
||||
|
||||
func (h *MCPProviderHandler) GetByID(c *gin.Context) {
|
||||
db := storage.GetPG()
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效ID")
|
||||
return
|
||||
}
|
||||
var m MCPProvider
|
||||
if err := db.Table("mcp_providers").Where("id = ?", id).First(&m).Error; err != nil {
|
||||
h.response.NotFound(c, "记录不存在")
|
||||
return
|
||||
}
|
||||
h.response.Success(c, m)
|
||||
}
|
||||
|
||||
func (h *MCPProviderHandler) Create(c *gin.Context) {
|
||||
db := storage.GetPG()
|
||||
var req map[string]any
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
if err := db.Table("mcp_providers").Create(req).Error; err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, "创建成功")
|
||||
}
|
||||
|
||||
func (h *MCPProviderHandler) Update(c *gin.Context) {
|
||||
db := storage.GetPG()
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效ID")
|
||||
return
|
||||
}
|
||||
var req map[string]any
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
delete(req, "id")
|
||||
if err := db.Table("mcp_providers").Where("id = ?", id).Updates(req).Error; err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, "更新成功")
|
||||
}
|
||||
|
||||
func (h *MCPProviderHandler) Delete(c *gin.Context) {
|
||||
db := storage.GetPG()
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效ID")
|
||||
return
|
||||
}
|
||||
if err := db.Table("mcp_providers").Where("id = ?", id).Delete(nil).Error; err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, "删除成功")
|
||||
}
|
||||
|
||||
func (h *MCPProviderHandler) UpdateStatus(c *gin.Context) {
|
||||
db := storage.GetPG()
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效ID")
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
Status string `json:"status" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
if err := db.Table("mcp_providers").Where("id = ?", id).Update("status", body.Status).Error; err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, "状态更新成功")
|
||||
}
|
||||
|
||||
func (h *MCPProviderHandler) UpdateIsUsed(c *gin.Context) {
|
||||
db := storage.GetPG()
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效ID")
|
||||
return
|
||||
}
|
||||
var body struct {
|
||||
IsUsed bool `json:"is_used" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
if err := db.Table("mcp_providers").Where("id = ?", id).Update("is_used", body.IsUsed).Error; err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.Success(c, "使用状态更新成功")
|
||||
}
|
||||
134
internal/api/handlers/message_push_handler.go
Normal file
134
internal/api/handlers/message_push_handler.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// MessagePushHandler 消息推送处理器
|
||||
type MessagePushHandler struct {
|
||||
service services.MessagePushService
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
// NewMessagePushHandler 创建消息推送处理器
|
||||
func NewMessagePushHandler(service services.MessagePushService) *MessagePushHandler {
|
||||
return &MessagePushHandler{
|
||||
service: service,
|
||||
response: utils.NewResponse(),
|
||||
}
|
||||
}
|
||||
|
||||
// SendMessage 发送消息
|
||||
func (h *MessagePushHandler) SendMessage(c *gin.Context) {
|
||||
var req models.MessagePushRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取当前用户信息
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
h.response.Unauthorized(c, "无法获取用户信息")
|
||||
return
|
||||
}
|
||||
|
||||
// 处理用户ID类型
|
||||
var senderID int
|
||||
switch v := userID.(type) {
|
||||
case int:
|
||||
senderID = v
|
||||
case uint:
|
||||
senderID = int(v)
|
||||
case string:
|
||||
var err error
|
||||
senderID, err = strconv.Atoi(v)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, "用户ID格式错误")
|
||||
return
|
||||
}
|
||||
default:
|
||||
h.response.InternalServerError(c, "用户ID格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取发送人姓名(从用户信息中获取)
|
||||
senderName := "系统管理员"
|
||||
if user, exists := c.Get("user"); exists {
|
||||
if userInfo, ok := user.(map[string]interface{}); ok {
|
||||
if name, ok := userInfo["name"].(string); ok {
|
||||
senderName = name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result, err := h.service.SendMessage(c.Request.Context(), &req, senderID, senderName)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result)
|
||||
}
|
||||
|
||||
// GetPushLogs 获取推送记录列表
|
||||
func (h *MessagePushHandler) GetPushLogs(c *gin.Context) {
|
||||
var req models.MessagePushListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.service.GetPushLogs(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result)
|
||||
}
|
||||
|
||||
// GetPushLogByID 根据ID获取推送记录
|
||||
func (h *MessagePushHandler) GetPushLogByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的推送记录ID")
|
||||
return
|
||||
}
|
||||
|
||||
log, err := h.service.GetPushLogByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err.Error() == "推送记录不存在" {
|
||||
h.response.NotFound(c, "推送记录不存在")
|
||||
return
|
||||
}
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, log)
|
||||
}
|
||||
|
||||
// SearchUsers 搜索用户
|
||||
func (h *MessagePushHandler) SearchUsers(c *gin.Context) {
|
||||
var req models.UserSearchRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.service.SearchUsers(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result)
|
||||
}
|
||||
144
internal/api/handlers/page_handler.go
Normal file
144
internal/api/handlers/page_handler.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// PageHandler 页面处理器
|
||||
type PageHandler struct {
|
||||
pageService services.PageService
|
||||
response *utils.Response
|
||||
logger *utils.Logger
|
||||
}
|
||||
|
||||
// NewPageHandler 创建页面处理器
|
||||
func NewPageHandler(pageService services.PageService, logger *utils.Logger) *PageHandler {
|
||||
return &PageHandler{
|
||||
pageService: pageService,
|
||||
response: utils.NewResponse(),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建页面
|
||||
func (h *PageHandler) Create(c *gin.Context) {
|
||||
var req models.PageCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("参数绑定失败", zap.Error(err))
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
page, err := h.pageService.Create(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("创建页面失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, page)
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取页面
|
||||
func (h *PageHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("页面ID格式错误", zap.Error(err))
|
||||
h.response.BadRequest(c, "无效的页面ID")
|
||||
return
|
||||
}
|
||||
|
||||
page, err := h.pageService.GetByID(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("获取页面失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, page)
|
||||
}
|
||||
|
||||
// Update 更新页面
|
||||
func (h *PageHandler) Update(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("页面ID格式错误", zap.Error(err))
|
||||
h.response.BadRequest(c, "无效的页面ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.PageUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("参数绑定失败", zap.Error(err))
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
page, err := h.pageService.Update(uint(id), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("更新页面失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, page)
|
||||
}
|
||||
|
||||
// Delete 删除页面
|
||||
func (h *PageHandler) Delete(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("页面ID格式错误", zap.Error(err))
|
||||
h.response.BadRequest(c, "无效的页面ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.pageService.Delete(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("删除页面失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "页面删除成功"})
|
||||
}
|
||||
|
||||
// List 获取页面列表
|
||||
func (h *PageHandler) List(c *gin.Context) {
|
||||
var req models.PageListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.logger.Error("参数绑定失败", zap.Error(err))
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
pages, total, err := h.pageService.List(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("获取页面列表失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 如果没有分页参数,直接返回页面列表
|
||||
if req.Page <= 0 || req.Size <= 0 {
|
||||
h.response.Success(c, pages)
|
||||
return
|
||||
}
|
||||
|
||||
// 有分页参数时返回完整的分页信息
|
||||
h.response.Success(c, gin.H{
|
||||
"pages": pages,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"size": req.Size,
|
||||
})
|
||||
}
|
||||
117
internal/api/handlers/quota_handler.go
Normal file
117
internal/api/handlers/quota_handler.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
)
|
||||
|
||||
// QuotaHandler 配额处理器
|
||||
type QuotaHandler struct {
|
||||
quotaService services.QuotaService
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
// NewQuotaHandler 创建配额处理器
|
||||
func NewQuotaHandler(quotaService services.QuotaService) *QuotaHandler {
|
||||
return &QuotaHandler{
|
||||
quotaService: quotaService,
|
||||
response: utils.NewResponse(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetQuotaHistory 获取配额历史数据
|
||||
func (h *QuotaHandler) GetQuotaHistory(c *gin.Context) {
|
||||
var req models.QuotaHistoryRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 调用服务层
|
||||
response, err := h.quotaService.GetQuotaHistory(&req)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 返回响应
|
||||
if response.Success {
|
||||
h.response.Success(c, response.Data)
|
||||
} else {
|
||||
h.response.BadRequest(c, response.Message)
|
||||
}
|
||||
}
|
||||
|
||||
// HealthCheck 健康检查
|
||||
func (h *QuotaHandler) HealthCheck(c *gin.Context) {
|
||||
err := h.quotaService.HealthCheck()
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, "配额服务健康检查失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"status": "ok", "service": "quota"})
|
||||
}
|
||||
|
||||
// GetQuotaRules 获取配额规则列表(透传网关)
|
||||
func (h *QuotaHandler) GetQuotaRules(c *gin.Context) {
|
||||
resp, err := h.quotaService.GetQuotaRules()
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
if resp.Success {
|
||||
// 透传 data
|
||||
c.JSON(200, gin.H{
|
||||
"code": 200,
|
||||
"message": "操作成功",
|
||||
"data": resp.Data,
|
||||
})
|
||||
return
|
||||
}
|
||||
h.response.BadRequest(c, resp.Message)
|
||||
}
|
||||
|
||||
// CreateQuotaRule 创建配额规则(代理网关)
|
||||
func (h *QuotaHandler) CreateQuotaRule(c *gin.Context) {
|
||||
var body map[string]any
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
resp, err := h.quotaService.CreateQuotaRule(body)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"code": 200, "message": "操作成功", "data": resp.Data})
|
||||
}
|
||||
|
||||
// UpdateQuotaRule 更新配额规则(代理网关)
|
||||
func (h *QuotaHandler) UpdateQuotaRule(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var body map[string]any
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
resp, err := h.quotaService.UpdateQuotaRule(id, body)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"code": 200, "message": "操作成功", "data": resp.Data})
|
||||
}
|
||||
|
||||
// DeleteQuotaRule 删除配额规则(代理网关)
|
||||
func (h *QuotaHandler) DeleteQuotaRule(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
resp, err := h.quotaService.DeleteQuotaRule(id)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"code": 200, "message": "操作成功", "data": resp.Data})
|
||||
}
|
||||
182
internal/api/handlers/rbac_handler.go
Normal file
182
internal/api/handlers/rbac_handler.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// RBACHandler 简化的RBAC处理器
|
||||
type RBACHandler struct {
|
||||
rbacService services.RBACService
|
||||
response *utils.Response
|
||||
logger *utils.Logger
|
||||
}
|
||||
|
||||
// NewRBACHandler 创建RBAC处理器
|
||||
func NewRBACHandler(rbacService services.RBACService, logger *utils.Logger) *RBACHandler {
|
||||
return &RBACHandler{
|
||||
rbacService: rbacService,
|
||||
response: utils.NewResponse(),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// AssignRolePagePermissions 分配角色页面权限
|
||||
func (h *RBACHandler) AssignRolePagePermissions(c *gin.Context) {
|
||||
var req models.RolePagePermissionAssignRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("参数绑定失败", zap.Error(err))
|
||||
h.response.Error(c, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
err := h.rbacService.AssignRolePagePermissions(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("分配角色页面权限失败", zap.Error(err))
|
||||
h.response.Error(c, 500, "分配角色页面权限失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "分配角色页面权限成功")
|
||||
}
|
||||
|
||||
// RemoveRolePagePermissions 移除角色页面权限
|
||||
func (h *RBACHandler) RemoveRolePagePermissions(c *gin.Context) {
|
||||
roleIDStr := c.Param("id")
|
||||
roleID, err := strconv.ParseUint(roleIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("角色ID格式错误", zap.Error(err))
|
||||
h.response.Error(c, 400, "角色ID格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
PageIDs []uint `json:"pageIds" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("参数绑定失败", zap.Error(err))
|
||||
h.response.Error(c, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.rbacService.RemoveRolePagePermissions(uint(roleID), req.PageIDs)
|
||||
if err != nil {
|
||||
h.logger.Error("移除角色页面权限失败", zap.Error(err))
|
||||
h.response.Error(c, 500, "移除角色页面权限失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "移除角色页面权限成功")
|
||||
}
|
||||
|
||||
// GetRolePagePermissions 获取角色页面权限
|
||||
func (h *RBACHandler) GetRolePagePermissions(c *gin.Context) {
|
||||
roleIDStr := c.Param("id")
|
||||
roleID, err := strconv.ParseUint(roleIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("角色ID格式错误", zap.Error(err))
|
||||
h.response.Error(c, 400, "角色ID格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
pages, err := h.rbacService.GetRolePagePermissions(uint(roleID))
|
||||
if err != nil {
|
||||
h.logger.Error("获取角色页面权限失败", zap.Error(err))
|
||||
h.response.Error(c, 500, "获取角色页面权限失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, pages)
|
||||
}
|
||||
|
||||
// GetUserPermissions 获取用户权限
|
||||
func (h *RBACHandler) GetUserPermissions(c *gin.Context) {
|
||||
userIDStr := c.Param("id")
|
||||
userID, err := strconv.ParseUint(userIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("用户ID格式错误", zap.Error(err))
|
||||
h.response.Error(c, 400, "用户ID格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
permissions, err := h.rbacService.GetUserPermissionsResponse(uint(userID))
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户权限失败", zap.Error(err))
|
||||
h.response.Error(c, 500, "获取用户权限失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, permissions)
|
||||
}
|
||||
|
||||
// GetRolePermissions 获取角色权限
|
||||
func (h *RBACHandler) GetRolePermissions(c *gin.Context) {
|
||||
roleIDStr := c.Param("id")
|
||||
roleID, err := strconv.ParseUint(roleIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("角色ID格式错误", zap.Error(err))
|
||||
h.response.Error(c, 400, "角色ID格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
permissions, err := h.rbacService.GetRolePagePermissionsResponse(uint(roleID))
|
||||
if err != nil {
|
||||
h.logger.Error("获取角色权限失败", zap.Error(err))
|
||||
h.response.Error(c, 500, "获取角色权限失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, permissions)
|
||||
}
|
||||
|
||||
// CheckPagePermission 检查页面权限
|
||||
func (h *RBACHandler) CheckPagePermission(c *gin.Context) {
|
||||
userIDStr := c.Query("user_id")
|
||||
pagePath := c.Query("page_path")
|
||||
|
||||
userID, err := strconv.ParseUint(userIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("用户ID格式错误", zap.Error(err))
|
||||
h.response.Error(c, 400, "用户ID格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
hasPermission, err := h.rbacService.CheckUserPagePermission(uint(userID), pagePath)
|
||||
if err != nil {
|
||||
h.logger.Error("检查页面权限失败", zap.Error(err))
|
||||
h.response.Error(c, 500, "检查页面权限失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{
|
||||
"hasPermission": hasPermission,
|
||||
"pagePath": pagePath,
|
||||
})
|
||||
}
|
||||
|
||||
// GetUserAccessiblePages 获取用户可访问页面
|
||||
func (h *RBACHandler) GetUserAccessiblePages(c *gin.Context) {
|
||||
userIDStr := c.Param("id")
|
||||
userID, err := strconv.ParseUint(userIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Error("用户ID格式错误", zap.Error(err))
|
||||
h.response.Error(c, 400, "用户ID格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
pages, err := h.rbacService.GetUserAccessiblePages(uint(userID))
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户可访问页面失败", zap.Error(err))
|
||||
h.response.Error(c, 500, "获取用户可访问页面失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{
|
||||
"pages": pages,
|
||||
})
|
||||
}
|
||||
228
internal/api/handlers/role_handler.go
Normal file
228
internal/api/handlers/role_handler.go
Normal file
@@ -0,0 +1,228 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// RoleHandler 角色处理器
|
||||
type RoleHandler struct {
|
||||
roleService services.RoleService
|
||||
rbacService services.RBACService
|
||||
response *utils.Response
|
||||
logger *utils.Logger
|
||||
}
|
||||
|
||||
// NewRoleHandler 创建角色处理器
|
||||
func NewRoleHandler(roleService services.RoleService, rbacService services.RBACService, logger *utils.Logger) *RoleHandler {
|
||||
return &RoleHandler{
|
||||
roleService: roleService,
|
||||
rbacService: rbacService,
|
||||
response: utils.NewResponse(),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建角色
|
||||
func (h *RoleHandler) Create(c *gin.Context) {
|
||||
var req models.RoleCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
role, err := h.roleService.Create(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("创建角色失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, role)
|
||||
}
|
||||
|
||||
// GetByID 获取角色详情
|
||||
func (h *RoleHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的角色ID")
|
||||
return
|
||||
}
|
||||
|
||||
role, err := h.roleService.GetByID(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("获取角色失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, role)
|
||||
}
|
||||
|
||||
// Update 更新角色
|
||||
func (h *RoleHandler) Update(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的角色ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.RoleUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
role, err := h.roleService.Update(uint(id), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("更新角色失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, role)
|
||||
}
|
||||
|
||||
// Delete 删除角色
|
||||
func (h *RoleHandler) Delete(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的角色ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.roleService.Delete(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("删除角色失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "角色删除成功"})
|
||||
}
|
||||
|
||||
// List 获取角色列表
|
||||
func (h *RoleHandler) List(c *gin.Context) {
|
||||
var req models.RoleListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
roles, total, err := h.roleService.List(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("获取角色列表失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 为每个角色获取页面权限
|
||||
rolesWithPermissions := make([]gin.H, len(roles))
|
||||
for i, role := range roles {
|
||||
// 获取角色的页面权限
|
||||
pages, err := h.rbacService.GetRolePagePermissions(role.ID)
|
||||
if err != nil {
|
||||
h.logger.Warn("获取角色页面权限失败", zap.Uint("roleId", role.ID), zap.Error(err))
|
||||
pages = []models.Page{} // 如果获取失败,返回空数组
|
||||
}
|
||||
|
||||
rolesWithPermissions[i] = gin.H{
|
||||
"id": role.ID,
|
||||
"name": role.Name,
|
||||
"level": role.Level,
|
||||
"description": role.Description,
|
||||
"isDefault": role.IsDefault,
|
||||
"createdAt": role.CreatedAt,
|
||||
"updatedAt": role.UpdatedAt,
|
||||
"deletedAt": role.DeletedAt,
|
||||
"pages": pages, // 添加页面权限信息
|
||||
}
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{
|
||||
"roles": rolesWithPermissions,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"size": req.Size,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateStatus 更新角色状态
|
||||
func (h *RoleHandler) UpdateStatus(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的角色ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Status int `json:"status" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.roleService.UpdateStatus(uint(id), req.Status)
|
||||
if err != nil {
|
||||
h.logger.Error("更新角色状态失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "角色状态更新成功"})
|
||||
}
|
||||
|
||||
// UpdatePermissions 更新角色权限
|
||||
func (h *RoleHandler) UpdatePermissions(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的角色ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.RolePagePermissionAssignRequest
|
||||
req.RoleID = uint(id)
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.rbacService.AssignRolePagePermissions(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("更新角色权限失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "角色权限更新成功"})
|
||||
}
|
||||
|
||||
// GetRolePermissions 获取角色权限
|
||||
func (h *RoleHandler) GetRolePermissions(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的角色ID")
|
||||
return
|
||||
}
|
||||
|
||||
permissions, err := h.rbacService.GetRolePagePermissions(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("获取角色权限失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"permissions": permissions})
|
||||
}
|
||||
267
internal/api/handlers/sso_handler.go
Normal file
267
internal/api/handlers/sso_handler.go
Normal file
@@ -0,0 +1,267 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// SSOHandler SSO处理器
|
||||
type SSOHandler struct {
|
||||
ssoService services.SSOService
|
||||
response *utils.Response
|
||||
logger *utils.Logger
|
||||
}
|
||||
|
||||
// NewSSOHandler 创建SSO处理器
|
||||
func NewSSOHandler(ssoService services.SSOService, logger *utils.Logger) *SSOHandler {
|
||||
return &SSOHandler{
|
||||
ssoService: ssoService,
|
||||
response: utils.NewResponse(),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// HandleSSOLogin 处理SSO登录请求(合并登录和回调逻辑)
|
||||
func (h *SSOHandler) HandleSSOLogin(c *gin.Context) {
|
||||
if c.Request.Method != http.MethodPost {
|
||||
h.response.BadRequest(c, "Method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.SSOCallbackRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
// 解析失败时,走登录逻辑
|
||||
h.handleLoginLogic(c, models.SSOLoginRequest{})
|
||||
return
|
||||
}
|
||||
|
||||
// 如果code为空,走登录逻辑
|
||||
if req.Code == "" {
|
||||
h.handleLoginLogic(c, models.SSOLoginRequest{})
|
||||
return
|
||||
}
|
||||
|
||||
// 如果code不为空,走回调逻辑
|
||||
h.handleCallbackLogic(c, req)
|
||||
}
|
||||
|
||||
// HandleSSOCallback 处理SSO回调
|
||||
func (h *SSOHandler) HandleSSOCallback(c *gin.Context) {
|
||||
if c.Request.Method != http.MethodPost {
|
||||
h.response.BadRequest(c, "Method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.SSOCallbackRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证参数
|
||||
if req.Code == "" || req.State == "" {
|
||||
h.response.BadRequest(c, "Code and state are required")
|
||||
return
|
||||
}
|
||||
|
||||
// 调用服务层处理回调
|
||||
response, err := h.ssoService.HandleCallback(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to handle SSO callback", zap.Error(err))
|
||||
// 返回更具体的错误信息,避免前端重复尝试
|
||||
if strings.Contains(err.Error(), "password") {
|
||||
h.response.BadRequest(c, "数据库表结构错误,请联系管理员")
|
||||
} else {
|
||||
h.response.InternalServerError(c, "SSO登录处理失败,请稍后重试")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, response)
|
||||
}
|
||||
|
||||
// HandleRefreshToken 处理令牌刷新
|
||||
func (h *SSOHandler) HandleRefreshToken(c *gin.Context) {
|
||||
if c.Request.Method != http.MethodPost {
|
||||
h.response.BadRequest(c, "Method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.RefreshTokenRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if req.RefreshToken == "" {
|
||||
h.response.BadRequest(c, "Refresh token is required")
|
||||
return
|
||||
}
|
||||
|
||||
// 调用服务层刷新令牌
|
||||
response, err := h.ssoService.RefreshToken(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to refresh token", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, response)
|
||||
}
|
||||
|
||||
// HandleLogout 处理登出请求
|
||||
func (h *SSOHandler) HandleLogout(c *gin.Context) {
|
||||
if c.Request.Method != http.MethodPost {
|
||||
h.response.BadRequest(c, "Method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
// 从Authorization头获取访问令牌
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" {
|
||||
h.response.Unauthorized(c, "Authorization header is required")
|
||||
return
|
||||
}
|
||||
|
||||
// 提取Bearer令牌
|
||||
token := ""
|
||||
if len(authHeader) > 7 && authHeader[:7] == "Bearer " {
|
||||
token = authHeader[7:]
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
h.response.Unauthorized(c, "Invalid authorization header")
|
||||
return
|
||||
}
|
||||
|
||||
// 调用服务层登出
|
||||
response, err := h.ssoService.Logout(c.Request.Context(), token)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to logout", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, response)
|
||||
}
|
||||
|
||||
// HandleUserInfo 处理用户信息请求
|
||||
func (h *SSOHandler) HandleUserInfo(c *gin.Context) {
|
||||
if c.Request.Method != http.MethodGet {
|
||||
h.response.BadRequest(c, "Method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
// 从Authorization头获取访问令牌
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader == "" {
|
||||
h.response.Unauthorized(c, "Authorization header is required")
|
||||
return
|
||||
}
|
||||
|
||||
// 提取Bearer令牌
|
||||
token := ""
|
||||
if len(authHeader) > 7 && authHeader[:7] == "Bearer " {
|
||||
token = authHeader[7:]
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
h.response.Unauthorized(c, "Invalid authorization header")
|
||||
return
|
||||
}
|
||||
|
||||
// 调用服务层获取用户信息
|
||||
response, err := h.ssoService.GetUserInfo(c.Request.Context(), token)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to get user info", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, response)
|
||||
}
|
||||
|
||||
// handleLoginLogic 处理登录逻辑
|
||||
func (h *SSOHandler) handleLoginLogic(c *gin.Context, req models.SSOLoginRequest) {
|
||||
// 调用服务层初始化登录
|
||||
response, err := h.ssoService.InitiateLogin(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("failed to initiate SSO login", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, response)
|
||||
}
|
||||
|
||||
// handleCallbackLogic 处理回调逻辑
|
||||
func (h *SSOHandler) handleCallbackLogic(c *gin.Context, req models.SSOCallbackRequest) {
|
||||
// 验证参数
|
||||
if req.State == "" {
|
||||
// 参数缺失时,走登录逻辑
|
||||
h.handleLoginLogic(c, models.SSOLoginRequest{})
|
||||
return
|
||||
}
|
||||
|
||||
// 调用服务层处理回调
|
||||
response, err := h.ssoService.HandleCallback(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to handle SSO callback", zap.Error(err))
|
||||
// 回调失败时,走登录逻辑
|
||||
h.handleLoginLogic(c, models.SSOLoginRequest{})
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, response)
|
||||
}
|
||||
|
||||
// GetOnlineUsers 获取在线用户列表
|
||||
func (h *SSOHandler) GetOnlineUsers(c *gin.Context) {
|
||||
users, err := h.ssoService.GetOnlineUsers(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("failed to get online users", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, users)
|
||||
}
|
||||
|
||||
// GetOnlineUserCount 获取在线用户数量
|
||||
func (h *SSOHandler) GetOnlineUserCount(c *gin.Context) {
|
||||
count, err := h.ssoService.GetOnlineUserCount(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("failed to get online user count", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"count": count})
|
||||
}
|
||||
|
||||
// BatchLogout 批量登出用户
|
||||
func (h *SSOHandler) BatchLogout(c *gin.Context) {
|
||||
var req struct {
|
||||
UserIDs []int `json:"user_ids" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.ssoService.BatchUserLogout(c.Request.Context(), req.UserIDs)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to batch logout users", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "批量登出成功")
|
||||
}
|
||||
189
internal/api/handlers/system_config_handler.go
Normal file
189
internal/api/handlers/system_config_handler.go
Normal file
@@ -0,0 +1,189 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// SystemConfigHandler 系统配置处理器
|
||||
type SystemConfigHandler struct {
|
||||
service services.SystemConfigService
|
||||
response *utils.Response
|
||||
logger *utils.Logger
|
||||
}
|
||||
|
||||
// NewSystemConfigHandler 创建系统配置处理器
|
||||
func NewSystemConfigHandler(service services.SystemConfigService, logger *utils.Logger) *SystemConfigHandler {
|
||||
return &SystemConfigHandler{
|
||||
service: service,
|
||||
response: utils.NewResponse(),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建系统配置
|
||||
func (h *SystemConfigHandler) Create(c *gin.Context) {
|
||||
var req models.SystemConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.service.Create(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("创建系统配置失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, config)
|
||||
}
|
||||
|
||||
// GetByID 获取系统配置详情
|
||||
func (h *SystemConfigHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.service.GetByID(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("获取系统配置失败", zap.Error(err))
|
||||
h.response.NotFound(c, "配置不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, config)
|
||||
}
|
||||
|
||||
// GetByKey 根据配置标识获取系统配置
|
||||
func (h *SystemConfigHandler) GetByKey(c *gin.Context) {
|
||||
key := c.Param("key")
|
||||
if key == "" {
|
||||
h.response.BadRequest(c, "配置标识不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.service.GetByKey(key)
|
||||
if err != nil {
|
||||
h.logger.Error("获取系统配置失败", zap.Error(err))
|
||||
h.response.NotFound(c, "配置不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, config)
|
||||
}
|
||||
|
||||
// List 获取系统配置列表
|
||||
func (h *SystemConfigHandler) List(c *gin.Context) {
|
||||
var req models.SystemConfigListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Size <= 0 {
|
||||
req.Size = 20
|
||||
}
|
||||
|
||||
configs, total, err := h.service.List(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("获取系统配置列表失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, "获取列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Page(c, configs, total, req.Page, req.Size)
|
||||
}
|
||||
|
||||
// Update 更新系统配置
|
||||
func (h *SystemConfigHandler) Update(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.SystemConfigUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.service.Update(uint(id), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("更新系统配置失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, config)
|
||||
}
|
||||
|
||||
// Delete 删除系统配置
|
||||
func (h *SystemConfigHandler) Delete(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.Delete(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("删除系统配置失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, nil)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新状态
|
||||
func (h *SystemConfigHandler) UpdateStatus(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.SystemConfigUpdateStatusRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.UpdateStatus(uint(id), req.Status)
|
||||
if err != nil {
|
||||
h.logger.Error("更新系统配置状态失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, nil)
|
||||
}
|
||||
|
||||
// GetAll 获取所有系统配置
|
||||
func (h *SystemConfigHandler) GetAll(c *gin.Context) {
|
||||
configs, err := h.service.GetAll()
|
||||
if err != nil {
|
||||
h.logger.Error("获取所有系统配置失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, "获取配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, configs)
|
||||
}
|
||||
195
internal/api/handlers/user_feedback_handler.go
Normal file
195
internal/api/handlers/user_feedback_handler.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// UserFeedbackHandler 用户反馈处理器
|
||||
type UserFeedbackHandler struct {
|
||||
service *services.UserFeedbackService
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
// NewUserFeedbackHandler 创建用户反馈处理器
|
||||
func NewUserFeedbackHandler(service *services.UserFeedbackService) *UserFeedbackHandler {
|
||||
return &UserFeedbackHandler{
|
||||
service: service,
|
||||
response: utils.NewResponse(),
|
||||
}
|
||||
}
|
||||
|
||||
// List 获取用户反馈列表
|
||||
func (h *UserFeedbackHandler) List(c *gin.Context) {
|
||||
var req models.UserFeedbackListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.service.List(c.Request.Context(), &req)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result)
|
||||
}
|
||||
|
||||
// GetByID 根据ID获取用户反馈
|
||||
func (h *UserFeedbackHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的反馈ID")
|
||||
return
|
||||
}
|
||||
|
||||
feedbackItem, err := h.service.GetByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err.Error() == "反馈不存在" {
|
||||
h.response.NotFound(c, "反馈不存在")
|
||||
return
|
||||
}
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, feedbackItem)
|
||||
}
|
||||
|
||||
// MarkHandled 标记为已处理
|
||||
func (h *UserFeedbackHandler) MarkHandled(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的反馈ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.UserFeedbackMarkRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取当前用户ID(从JWT token中解析)
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
h.response.Unauthorized(c, "无法获取用户信息")
|
||||
return
|
||||
}
|
||||
|
||||
// 处理用户ID,支持多种类型
|
||||
var handledBy int
|
||||
switch v := userID.(type) {
|
||||
case int:
|
||||
handledBy = v
|
||||
case uint:
|
||||
handledBy = int(v)
|
||||
case string:
|
||||
var err error
|
||||
handledBy, err = strconv.Atoi(v)
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, "用户ID格式错误")
|
||||
return
|
||||
}
|
||||
default:
|
||||
h.response.InternalServerError(c, "用户ID格式错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取当前状态以确定切换后的状态
|
||||
feedback, err := h.service.GetByID(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err.Error() == "反馈不存在" {
|
||||
h.response.NotFound(c, "反馈不存在")
|
||||
return
|
||||
}
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
newStatus := 0
|
||||
message := "标记为未处理成功"
|
||||
if feedback.Status == 0 {
|
||||
// 当前是未处理,切换为已处理
|
||||
newStatus = 1
|
||||
message = "标记为已处理成功"
|
||||
}
|
||||
|
||||
err = h.service.MarkHandled(c.Request.Context(), id, handledBy, req.Note)
|
||||
if err != nil {
|
||||
if err.Error() == "反馈不存在" {
|
||||
h.response.NotFound(c, "反馈不存在")
|
||||
return
|
||||
}
|
||||
if err.Error() == "处理人ID无效" {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 返回处理结果
|
||||
result := map[string]interface{}{
|
||||
"id": id,
|
||||
"status": newStatus,
|
||||
"message": message,
|
||||
}
|
||||
if newStatus == 1 {
|
||||
result["handled_by"] = handledBy
|
||||
}
|
||||
|
||||
h.response.Success(c, result)
|
||||
}
|
||||
|
||||
// Delete 删除用户反馈
|
||||
func (h *UserFeedbackHandler) Delete(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的反馈ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.Delete(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err.Error() == "反馈不存在" {
|
||||
h.response.NotFound(c, "反馈不存在")
|
||||
return
|
||||
}
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "删除成功"})
|
||||
}
|
||||
|
||||
// GetStatistics 获取反馈统计信息
|
||||
func (h *UserFeedbackHandler) GetStatistics(c *gin.Context) {
|
||||
stats, err := h.service.GetStatistics(c.Request.Context())
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, stats)
|
||||
}
|
||||
|
||||
// hasHTTPPrefix 判断字符串是否为 http/https URL
|
||||
func hasHTTPPrefix(s string) bool {
|
||||
if len(s) < 7 {
|
||||
return false
|
||||
}
|
||||
if len(s) >= 8 && (s[:8] == "https://") {
|
||||
return true
|
||||
}
|
||||
return len(s) >= 7 && (s[:7] == "http://")
|
||||
}
|
||||
285
internal/api/handlers/user_handler.go
Normal file
285
internal/api/handlers/user_handler.go
Normal file
@@ -0,0 +1,285 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// UserHandler 用户处理器
|
||||
type UserHandler struct {
|
||||
userService services.UserService
|
||||
rbacService services.RBACService
|
||||
response *utils.Response
|
||||
logger *utils.Logger
|
||||
}
|
||||
|
||||
// NewUserHandler 创建用户处理器
|
||||
func NewUserHandler(userService services.UserService, rbacService services.RBACService, logger *utils.Logger) *UserHandler {
|
||||
return &UserHandler{
|
||||
userService: userService,
|
||||
rbacService: rbacService,
|
||||
response: utils.NewResponse(),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建用户
|
||||
func (h *UserHandler) Create(c *gin.Context) {
|
||||
var req models.UserCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.userService.Create(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("创建用户失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, user)
|
||||
}
|
||||
|
||||
// GetByID 获取用户详情
|
||||
func (h *UserHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.userService.GetByID(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, user)
|
||||
}
|
||||
|
||||
// Update 更新用户
|
||||
func (h *UserHandler) Update(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.UserUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.userService.Update(uint(id), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("更新用户失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, user)
|
||||
}
|
||||
|
||||
// Delete 删除用户
|
||||
func (h *UserHandler) Delete(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.userService.Delete(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("删除用户失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "用户删除成功"})
|
||||
}
|
||||
|
||||
// List 获取用户列表
|
||||
func (h *UserHandler) List(c *gin.Context) {
|
||||
var req models.UserListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
users, total, err := h.userService.ListWithRoles(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户列表失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{
|
||||
"users": users,
|
||||
"total": total,
|
||||
"page": req.Page,
|
||||
"size": req.Size,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateStatus 更新用户状态
|
||||
func (h *UserHandler) UpdateStatus(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Status int `json:"status" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.userService.UpdateStatus(uint(id), req.Status)
|
||||
if err != nil {
|
||||
h.logger.Error("更新用户状态失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "用户状态更新成功"})
|
||||
}
|
||||
|
||||
// UpdateRoles 更新用户角色
|
||||
func (h *UserHandler) UpdateRoles(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.UserRoleAssignRequest
|
||||
req.UserID = uint(id)
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 现在用户只有一个角色,直接更新用户的role_id
|
||||
err = h.userService.UpdateRole(uint(id), req.RoleIDs[0])
|
||||
if err != nil {
|
||||
h.logger.Error("更新用户角色失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "用户角色更新成功"})
|
||||
}
|
||||
|
||||
// GetUserRoles 获取用户角色
|
||||
func (h *UserHandler) GetUserRoles(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
// 现在用户只有一个角色,直接获取用户信息
|
||||
user, err := h.userService.GetByID(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户信息失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 获取角色信息
|
||||
role, err := h.rbacService.GetRoleByID(user.RoleID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取角色信息失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"roles": []models.Role{*role}})
|
||||
}
|
||||
|
||||
// GetUserPermissions 获取用户权限
|
||||
func (h *UserHandler) GetUserPermissions(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
permissions, err := h.rbacService.GetUserPermissionsResponse(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户权限失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"permissions": permissions})
|
||||
}
|
||||
|
||||
// CheckUserRole 检查用户当前系统角色
|
||||
// GET /admin/users/check-role/:user_id
|
||||
func (h *UserHandler) CheckUserRole(c *gin.Context) {
|
||||
userIDStr := c.Param("user_id")
|
||||
userID, err := strconv.Atoi(userIDStr)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
isSystemAdmin, err := h.userService.CheckUserSystemRole(userID)
|
||||
if err != nil {
|
||||
h.logger.Error("检查用户系统角色失败", zap.Int("user_id", userID), zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
currentRole := "custom"
|
||||
if isSystemAdmin {
|
||||
currentRole = "sys_admin"
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{
|
||||
"is_system_admin": isSystemAdmin,
|
||||
"current_role": currentRole,
|
||||
})
|
||||
}
|
||||
|
||||
// ChangeUserSystemRole 变更用户系统角色
|
||||
// POST /admin/users/change-system-role
|
||||
func (h *UserHandler) ChangeUserSystemRole(c *gin.Context) {
|
||||
var req struct {
|
||||
UserID int `json:"user_id" binding:"required"`
|
||||
SystemRole string `json:"system_role" binding:"required,oneof=sys_admin custom"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.userService.ChangeUserSystemRole(req.UserID, req.SystemRole)
|
||||
if err != nil {
|
||||
h.logger.Error("变更用户系统角色失败", zap.Int("user_id", req.UserID), zap.String("system_role", req.SystemRole), zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, gin.H{"message": "角色变更成功"})
|
||||
}
|
||||
171
internal/api/handlers/user_level_config_handler.go
Normal file
171
internal/api/handlers/user_level_config_handler.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// UserLevelConfigHandler 用户等级配置处理器
|
||||
type UserLevelConfigHandler struct {
|
||||
service services.UserLevelConfigService
|
||||
response *utils.Response
|
||||
logger *utils.Logger
|
||||
}
|
||||
|
||||
// NewUserLevelConfigHandler 创建用户等级配置处理器
|
||||
func NewUserLevelConfigHandler(service services.UserLevelConfigService, logger *utils.Logger) *UserLevelConfigHandler {
|
||||
return &UserLevelConfigHandler{
|
||||
service: service,
|
||||
response: utils.NewResponse(),
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建用户等级配置
|
||||
func (h *UserLevelConfigHandler) Create(c *gin.Context) {
|
||||
var req models.UserLevelConfigCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.service.Create(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("创建用户等级配置失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, config)
|
||||
}
|
||||
|
||||
// GetByID 获取用户等级配置详情
|
||||
func (h *UserLevelConfigHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.service.GetByID(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户等级配置失败", zap.Error(err))
|
||||
h.response.NotFound(c, "配置不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, config)
|
||||
}
|
||||
|
||||
// List 获取用户等级配置列表
|
||||
func (h *UserLevelConfigHandler) List(c *gin.Context) {
|
||||
var req models.UserLevelConfigListRequest
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.Size <= 0 {
|
||||
req.Size = 20
|
||||
}
|
||||
|
||||
configs, total, err := h.service.List(&req)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户等级配置列表失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, "获取列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Page(c, configs, total, req.Page, req.Size)
|
||||
}
|
||||
|
||||
// Update 更新用户等级配置
|
||||
func (h *UserLevelConfigHandler) Update(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.UserLevelConfigUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.service.Update(uint(id), &req)
|
||||
if err != nil {
|
||||
h.logger.Error("更新用户等级配置失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, config)
|
||||
}
|
||||
|
||||
// Delete 删除用户等级配置
|
||||
func (h *UserLevelConfigHandler) Delete(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.Delete(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Error("删除用户等级配置失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, nil)
|
||||
}
|
||||
|
||||
// UpdateStatus 更新状态
|
||||
func (h *UserLevelConfigHandler) UpdateStatus(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.response.BadRequest(c, "无效的ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.UserLevelConfigUpdateStatusRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.service.UpdateStatus(uint(id), req.Status)
|
||||
if err != nil {
|
||||
h.logger.Error("更新用户等级配置状态失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, nil)
|
||||
}
|
||||
|
||||
// GetAll 获取所有用户等级配置
|
||||
func (h *UserLevelConfigHandler) GetAll(c *gin.Context) {
|
||||
configs, err := h.service.GetAll()
|
||||
if err != nil {
|
||||
h.logger.Error("获取所有用户等级配置失败", zap.Error(err))
|
||||
h.response.InternalServerError(c, "获取配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, configs)
|
||||
}
|
||||
97
internal/api/handlers/user_project_quota_handler.go
Normal file
97
internal/api/handlers/user_project_quota_handler.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"goalfymax-admin/internal/models"
|
||||
"goalfymax-admin/internal/services"
|
||||
"goalfymax-admin/internal/storage"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type UserProjectQuotaHandler struct {
|
||||
svc services.UserProjectQuotaService
|
||||
resp *utils.Response
|
||||
}
|
||||
|
||||
func NewUserProjectQuotaHandler(s services.UserProjectQuotaService) *UserProjectQuotaHandler {
|
||||
return &UserProjectQuotaHandler{svc: s, resp: utils.NewResponse()}
|
||||
}
|
||||
|
||||
func (h *UserProjectQuotaHandler) Create(c *gin.Context) {
|
||||
var req models.UserProjectQuota
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.resp.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
out, err := h.svc.Create(&req)
|
||||
if err != nil {
|
||||
h.resp.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.resp.Success(c, out)
|
||||
}
|
||||
|
||||
func (h *UserProjectQuotaHandler) Update(c *gin.Context) {
|
||||
id64, _ := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
var req models.UserProjectQuota
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.resp.ValidateError(c, err)
|
||||
return
|
||||
}
|
||||
out, err := h.svc.Update(uint(id64), &req)
|
||||
if err != nil {
|
||||
h.resp.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.resp.Success(c, out)
|
||||
}
|
||||
|
||||
func (h *UserProjectQuotaHandler) Delete(c *gin.Context) {
|
||||
id64, _ := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
if err := h.svc.Delete(uint(id64)); err != nil {
|
||||
h.resp.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.resp.Success(c, gin.H{"message": "deleted"})
|
||||
}
|
||||
|
||||
func (h *UserProjectQuotaHandler) GetByID(c *gin.Context) {
|
||||
id64, _ := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||
out, err := h.svc.GetByID(uint(id64))
|
||||
if err != nil {
|
||||
h.resp.NotFound(c, "not found")
|
||||
return
|
||||
}
|
||||
h.resp.Success(c, out)
|
||||
}
|
||||
|
||||
func (h *UserProjectQuotaHandler) List(c *gin.Context) {
|
||||
var filter storage.UserProjectQuotaFilter
|
||||
filter.UserID = c.Query("user_id")
|
||||
if v := c.Query("enabled"); v != "" {
|
||||
if v == "true" {
|
||||
b := true
|
||||
filter.Enabled = &b
|
||||
} else if v == "false" {
|
||||
b := false
|
||||
filter.Enabled = &b
|
||||
}
|
||||
}
|
||||
if p := c.Query("page"); p != "" {
|
||||
if v, err := strconv.Atoi(p); err == nil {
|
||||
filter.Page = v
|
||||
}
|
||||
}
|
||||
if s := c.Query("size"); s != "" {
|
||||
if v, err := strconv.Atoi(s); err == nil {
|
||||
filter.Size = v
|
||||
}
|
||||
}
|
||||
items, total, err := h.svc.List(filter)
|
||||
if err != nil {
|
||||
h.resp.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
h.resp.Page(c, items, total, filter.Page, filter.Size)
|
||||
}
|
||||
170
internal/api/handlers/vendor_model_pricing_handler.go
Normal file
170
internal/api/handlers/vendor_model_pricing_handler.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// VendorModelPricingHandler 供应商模型价格配置处理器
|
||||
type VendorModelPricingHandler struct {
|
||||
db *gorm.DB
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
// NewVendorModelPricingHandler 创建处理器
|
||||
func NewVendorModelPricingHandler(db *gorm.DB) *VendorModelPricingHandler {
|
||||
return &VendorModelPricingHandler{
|
||||
db: db,
|
||||
response: utils.NewResponse(),
|
||||
}
|
||||
}
|
||||
|
||||
// VendorModelPricingResponse 供应商模型价格配置响应
|
||||
type VendorModelPricingResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Provider string `json:"provider"`
|
||||
Account string `json:"account"`
|
||||
ModelName string `json:"model_name"`
|
||||
InputPrice float64 `json:"input_price"`
|
||||
OutputPrice float64 `json:"output_price"`
|
||||
CacheReadPrice float64 `json:"cache_read_price"`
|
||||
CacheCreatePrice float64 `json:"cache_create_price"`
|
||||
PriceRatio float64 `json:"price_ratio"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// PriceUpdateRequest 价格更新请求
|
||||
type PriceUpdateRequest struct {
|
||||
InputPrice *float64 `json:"input_price"`
|
||||
OutputPrice *float64 `json:"output_price"`
|
||||
CacheReadPrice *float64 `json:"cache_read_price"`
|
||||
CacheCreatePrice *float64 `json:"cache_create_price"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
PriceRatio *float64 `json:"price_ratio"`
|
||||
}
|
||||
|
||||
// GetVendorModelPricing 获取供应商模型价格配置列表
|
||||
func (h *VendorModelPricingHandler) GetVendorModelPricing(c *gin.Context) {
|
||||
var models []VendorModelPricingResponse
|
||||
|
||||
// 构建查询条件
|
||||
// 使用 v2 表:gw_model_config_v2,直接返回数据,无需联查
|
||||
// 为兼容前端字段类型,account 字段返回空串
|
||||
query := h.db.Table("gw_model_config_v2 mc").
|
||||
Select("mc.id, mc.provider, '' as account, mc.model_name, " +
|
||||
"mc.prompt_price as input_price, " +
|
||||
"mc.output_price as output_price, " +
|
||||
"mc.cache_read_price, mc.cache_create_price, " +
|
||||
"mc.price_ratio, " +
|
||||
"mc.enabled, mc.created_at, mc.updated_at")
|
||||
|
||||
// 添加筛选条件
|
||||
if provider := c.Query("provider"); provider != "" {
|
||||
query = query.Where("mc.provider = ?", provider)
|
||||
}
|
||||
if model := c.Query("model"); model != "" {
|
||||
query = query.Where("mc.model_name LIKE ?", "%"+model+"%")
|
||||
}
|
||||
if status := c.Query("status"); status != "" {
|
||||
if status == "enabled" {
|
||||
query = query.Where("mc.enabled = ?", true)
|
||||
} else if status == "disabled" {
|
||||
query = query.Where("mc.enabled = ?", false)
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
|
||||
offset := (page - 1) * size
|
||||
|
||||
// 先获取总数(在应用分页之前)
|
||||
var total int64
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 然后获取分页数据
|
||||
err = query.Offset(offset).Limit(size).Find(&models).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Page(c, models, total, page, size)
|
||||
}
|
||||
|
||||
// UpdateModelPricing 更新单个模型价格
|
||||
func (h *VendorModelPricingHandler) UpdateModelPricing(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var req PriceUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 构建更新字段(v2 列)
|
||||
updates := make(map[string]interface{})
|
||||
if req.InputPrice != nil {
|
||||
updates["prompt_price"] = *req.InputPrice
|
||||
}
|
||||
if req.OutputPrice != nil {
|
||||
updates["output_price"] = *req.OutputPrice
|
||||
}
|
||||
if req.CacheReadPrice != nil {
|
||||
updates["cache_read_price"] = *req.CacheReadPrice
|
||||
}
|
||||
if req.CacheCreatePrice != nil {
|
||||
updates["cache_create_price"] = *req.CacheCreatePrice
|
||||
}
|
||||
if req.Enabled != nil {
|
||||
updates["enabled"] = *req.Enabled
|
||||
}
|
||||
if req.PriceRatio != nil {
|
||||
updates["price_ratio"] = *req.PriceRatio
|
||||
}
|
||||
|
||||
// 检查模型是否存在(v2 表)
|
||||
var count int64
|
||||
err := h.db.Table("gw_model_config_v2").Where("id = ?", id).Count(&count).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
if count == 0 {
|
||||
h.response.NotFound(c, "模型不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新模型价格(v2 表)
|
||||
err = h.db.Table("gw_model_config_v2").Where("id = ?", id).Updates(updates).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "价格更新成功")
|
||||
}
|
||||
|
||||
// GetProviders 获取供应商列表(用于筛选)
|
||||
func (h *VendorModelPricingHandler) GetProviders(c *gin.Context) {
|
||||
var providers []string
|
||||
err := h.db.Table("gw_providers").
|
||||
Select("DISTINCT name").
|
||||
Where("status = ?", "active").
|
||||
Find(&providers).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, providers)
|
||||
}
|
||||
403
internal/api/handlers/vm_pricing_handler.go
Normal file
403
internal/api/handlers/vm_pricing_handler.go
Normal file
@@ -0,0 +1,403 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"goalfymax-admin/pkg/utils"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// VmPricingHandler 虚拟机价格配置处理器
|
||||
type VmPricingHandler struct {
|
||||
db *gorm.DB
|
||||
response *utils.Response
|
||||
}
|
||||
|
||||
// NewVmPricingHandler 创建处理器
|
||||
func NewVmPricingHandler(db *gorm.DB) *VmPricingHandler {
|
||||
return &VmPricingHandler{
|
||||
db: db,
|
||||
response: utils.NewResponse(),
|
||||
}
|
||||
}
|
||||
|
||||
// VmSpecResponse 虚拟机规格响应
|
||||
type VmSpecResponse struct {
|
||||
ID uint `json:"id"`
|
||||
SpecType string `json:"spec_type"`
|
||||
CPUCores int `json:"cpu_cores"`
|
||||
MemoryGB int `json:"memory_gb"`
|
||||
Description *string `json:"description"`
|
||||
CostPricePerMinute float64 `json:"cost_price_per_minute"`
|
||||
MarkupRate float64 `json:"markup_rate"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// VmTemplateResponse 虚拟机模板响应
|
||||
type VmTemplateResponse struct {
|
||||
ID uint `json:"id"`
|
||||
SpecType string `json:"spec_type"`
|
||||
TemplateID string `json:"template_id"`
|
||||
IsDefault bool `json:"is_default"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// VmSpecCreateRequest 规格创建请求
|
||||
type VmSpecCreateRequest struct {
|
||||
SpecType string `json:"spec_type" binding:"required"`
|
||||
CPUCores int `json:"cpu_cores" binding:"required"`
|
||||
MemoryGB int `json:"memory_gb" binding:"required"`
|
||||
Description *string `json:"description"`
|
||||
CostPricePerMinute float64 `json:"cost_price_per_minute" binding:"required"`
|
||||
MarkupRate *float64 `json:"markup_rate"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
// VmSpecUpdateRequest 规格更新请求
|
||||
type VmSpecUpdateRequest struct {
|
||||
CostPricePerMinute *float64 `json:"cost_price_per_minute"`
|
||||
MarkupRate *float64 `json:"markup_rate"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
// VmTemplateCreateRequest 模板创建请求
|
||||
type VmTemplateCreateRequest struct {
|
||||
SpecType string `json:"spec_type" binding:"required"`
|
||||
TemplateID string `json:"template_id" binding:"required"`
|
||||
IsDefault bool `json:"is_default"`
|
||||
}
|
||||
|
||||
// VmTemplateUpdateRequest 模板更新请求
|
||||
type VmTemplateUpdateRequest struct {
|
||||
IsDefault *bool `json:"is_default"`
|
||||
}
|
||||
|
||||
// GetVmSpecs 获取虚拟机规格列表
|
||||
func (h *VmPricingHandler) GetVmSpecs(c *gin.Context) {
|
||||
var specs []VmSpecResponse
|
||||
|
||||
// 构建查询条件
|
||||
query := h.db.Table("sb_sandbox_specs")
|
||||
|
||||
// 添加筛选条件
|
||||
if specType := c.Query("spec_type"); specType != "" {
|
||||
query = query.Where("spec_type LIKE ?", "%"+specType+"%")
|
||||
}
|
||||
if status := c.Query("status"); status != "" {
|
||||
if status == "active" {
|
||||
query = query.Where("is_active = ?", true)
|
||||
} else if status == "inactive" {
|
||||
query = query.Where("is_active = ?", false)
|
||||
}
|
||||
}
|
||||
|
||||
// 分页
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "10"))
|
||||
offset := (page - 1) * size
|
||||
|
||||
// 先获取总数
|
||||
var total int64
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 然后获取分页数据
|
||||
err = query.Order("created_at DESC").Offset(offset).Limit(size).Find(&specs).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Page(c, specs, total, page, size)
|
||||
}
|
||||
|
||||
// UpdateVmSpec 更新虚拟机规格
|
||||
func (h *VmPricingHandler) UpdateVmSpec(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var req VmSpecUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 构建更新字段
|
||||
updates := make(map[string]interface{})
|
||||
if req.CostPricePerMinute != nil {
|
||||
updates["cost_price_per_minute"] = *req.CostPricePerMinute
|
||||
}
|
||||
if req.MarkupRate != nil {
|
||||
updates["markup_rate"] = *req.MarkupRate
|
||||
}
|
||||
if req.IsActive != nil {
|
||||
updates["is_active"] = *req.IsActive
|
||||
}
|
||||
|
||||
if len(updates) == 0 {
|
||||
h.response.BadRequest(c, "没有需要更新的字段")
|
||||
return
|
||||
}
|
||||
|
||||
// 检查规格是否存在
|
||||
var count int64
|
||||
err := h.db.Table("sb_sandbox_specs").Where("id = ?", id).Count(&count).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
if count == 0 {
|
||||
h.response.NotFound(c, "规格不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 更新规格
|
||||
err = h.db.Table("sb_sandbox_specs").Where("id = ?", id).Updates(updates).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "规格更新成功")
|
||||
}
|
||||
|
||||
// DeleteVmSpec 删除虚拟机规格
|
||||
func (h *VmPricingHandler) DeleteVmSpec(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
// 检查规格是否存在
|
||||
var count int64
|
||||
err := h.db.Table("sb_sandbox_specs").Where("id = ?", id).Count(&count).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
if count == 0 {
|
||||
h.response.NotFound(c, "规格不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 删除规格
|
||||
err = h.db.Table("sb_sandbox_specs").Where("id = ?", id).Delete(nil).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "规格删除成功")
|
||||
}
|
||||
|
||||
// CreateVmSpec 创建虚拟机规格
|
||||
func (h *VmPricingHandler) CreateVmSpec(c *gin.Context) {
|
||||
var req VmSpecCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 检查规格类型是否已存在
|
||||
var count int64
|
||||
err := h.db.Table("sb_sandbox_specs").Where("spec_type = ?", req.SpecType).Count(&count).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
if count > 0 {
|
||||
h.response.BadRequest(c, "该配置类型已存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
markupRate := 0.3000 // 默认30%
|
||||
if req.MarkupRate != nil {
|
||||
markupRate = *req.MarkupRate
|
||||
}
|
||||
isActive := true
|
||||
if req.IsActive != nil {
|
||||
isActive = *req.IsActive
|
||||
}
|
||||
|
||||
// 创建规格
|
||||
insertData := map[string]interface{}{
|
||||
"spec_type": req.SpecType,
|
||||
"cpu_cores": req.CPUCores,
|
||||
"memory_gb": req.MemoryGB,
|
||||
"cost_price_per_minute": req.CostPricePerMinute,
|
||||
"markup_rate": markupRate,
|
||||
"is_active": isActive,
|
||||
}
|
||||
if req.Description != nil {
|
||||
insertData["description"] = *req.Description
|
||||
}
|
||||
|
||||
err = h.db.Table("sb_sandbox_specs").Create(insertData).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "规格创建成功")
|
||||
}
|
||||
|
||||
// GetVmTemplates 获取虚拟机模板列表
|
||||
func (h *VmPricingHandler) GetVmTemplates(c *gin.Context) {
|
||||
var templates []VmTemplateResponse
|
||||
|
||||
// 构建查询条件
|
||||
query := h.db.Table("sb_sandbox_templates")
|
||||
|
||||
// 添加筛选条件
|
||||
if specType := c.Query("spec_type"); specType != "" {
|
||||
query = query.Where("spec_type = ?", specType)
|
||||
}
|
||||
|
||||
// 分页
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
size, _ := strconv.Atoi(c.DefaultQuery("size", "10"))
|
||||
offset := (page - 1) * size
|
||||
|
||||
// 先获取总数
|
||||
var total int64
|
||||
err := query.Count(&total).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 然后获取分页数据
|
||||
err = query.Order("spec_type ASC, created_at DESC").Offset(offset).Limit(size).Find(&templates).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Page(c, templates, total, page, size)
|
||||
}
|
||||
|
||||
// CreateVmTemplate 创建虚拟机模板
|
||||
func (h *VmPricingHandler) CreateVmTemplate(c *gin.Context) {
|
||||
var req VmTemplateCreateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 检查规格是否存在
|
||||
var specCount int64
|
||||
err := h.db.Table("sb_sandbox_specs").Where("spec_type = ?", req.SpecType).Count(&specCount).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
if specCount == 0 {
|
||||
h.response.BadRequest(c, "规格类型不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 如果设置为默认模板,需要先取消同规格的其他默认模板
|
||||
if req.IsDefault {
|
||||
err = h.db.Table("sb_sandbox_templates").
|
||||
Where("spec_type = ? AND is_default = ?", req.SpecType, true).
|
||||
Update("is_default", false).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否已存在相同的规格-模板组合
|
||||
var existingCount int64
|
||||
err = h.db.Table("sb_sandbox_templates").
|
||||
Where("spec_type = ? AND template_id = ?", req.SpecType, req.TemplateID).
|
||||
Count(&existingCount).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
if existingCount > 0 {
|
||||
h.response.BadRequest(c, "该规格和模板的组合已存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 创建模板
|
||||
insertData := map[string]interface{}{
|
||||
"spec_type": req.SpecType,
|
||||
"template_id": req.TemplateID,
|
||||
"is_default": req.IsDefault,
|
||||
}
|
||||
err = h.db.Table("sb_sandbox_templates").Create(insertData).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "模板创建成功")
|
||||
}
|
||||
|
||||
// DeleteVmTemplate 删除虚拟机模板
|
||||
func (h *VmPricingHandler) DeleteVmTemplate(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
// 检查模板是否存在
|
||||
var count int64
|
||||
err := h.db.Table("sb_sandbox_templates").Where("id = ?", id).Count(&count).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
if count == 0 {
|
||||
h.response.NotFound(c, "模板不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 删除模板
|
||||
err = h.db.Table("sb_sandbox_templates").Where("id = ?", id).Delete(nil).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "模板删除成功")
|
||||
}
|
||||
|
||||
// SetDefaultVmTemplate 设置默认模板
|
||||
func (h *VmPricingHandler) SetDefaultVmTemplate(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
// 获取模板信息
|
||||
var template VmTemplateResponse
|
||||
err := h.db.Table("sb_sandbox_templates").Where("id = ?", id).First(&template).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
h.response.NotFound(c, "模板不存在")
|
||||
return
|
||||
}
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 取消同规格的其他默认模板
|
||||
err = h.db.Table("sb_sandbox_templates").
|
||||
Where("spec_type = ? AND is_default = ? AND id != ?", template.SpecType, true, id).
|
||||
Update("is_default", false).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 设置当前模板为默认
|
||||
err = h.db.Table("sb_sandbox_templates").Where("id = ?", id).Update("is_default", true).Error
|
||||
if err != nil {
|
||||
h.response.InternalServerError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, "默认模板设置成功")
|
||||
}
|
||||
Reference in New Issue
Block a user