v0.1
This commit is contained in:
322
internal/infrastructure/http/handlers/api_handler.go
Normal file
322
internal/infrastructure/http/handlers/api_handler.go
Normal file
@@ -0,0 +1,322 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
"tyapi-server/internal/application/api"
|
||||
"tyapi-server/internal/application/api/commands"
|
||||
"tyapi-server/internal/application/api/dto"
|
||||
"tyapi-server/internal/shared/crypto"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ApiHandler API调用HTTP处理器
|
||||
type ApiHandler struct {
|
||||
appService api.ApiApplicationService
|
||||
responseBuilder interfaces.ResponseBuilder
|
||||
validator interfaces.RequestValidator
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewApiHandler 创建API调用HTTP处理器
|
||||
func NewApiHandler(
|
||||
appService api.ApiApplicationService,
|
||||
responseBuilder interfaces.ResponseBuilder,
|
||||
validator interfaces.RequestValidator,
|
||||
logger *zap.Logger,
|
||||
) *ApiHandler {
|
||||
return &ApiHandler{
|
||||
appService: appService,
|
||||
responseBuilder: responseBuilder,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// HandleApiCall 统一API调用入口
|
||||
// @Summary API调用
|
||||
// @Description 统一API调用入口,参数加密传输
|
||||
// @Tags API调用
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body commands.ApiCallCommand true "API调用请求"
|
||||
// @Success 200 {object} dto.ApiCallResponse "调用成功"
|
||||
// @Failure 400 {object} dto.ApiCallResponse "请求参数错误"
|
||||
// @Failure 401 {object} dto.ApiCallResponse "未授权"
|
||||
// @Failure 429 {object} dto.ApiCallResponse "请求过于频繁"
|
||||
// @Failure 500 {object} dto.ApiCallResponse "服务器内部错误"
|
||||
// @Router /api/v1/:api_name [post]
|
||||
func (h *ApiHandler) HandleApiCall(c *gin.Context) {
|
||||
// 1. 基础参数校验
|
||||
accessId := c.GetHeader("Access-Id")
|
||||
if accessId == "" {
|
||||
response := dto.NewErrorResponse(1005, "缺少Access-Id", "")
|
||||
c.JSON(200, response)
|
||||
return
|
||||
}
|
||||
|
||||
// 2. 绑定和校验请求参数
|
||||
var cmd commands.ApiCallCommand
|
||||
cmd.ClientIP = c.ClientIP()
|
||||
cmd.AccessId = accessId
|
||||
cmd.ApiName = c.Param("api_name")
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
response := dto.NewErrorResponse(1003, "请求参数结构不正确", "")
|
||||
c.JSON(200, response)
|
||||
return
|
||||
}
|
||||
|
||||
// 3. 调用应用服务
|
||||
transactionId, encryptedResp, err := h.appService.CallApi(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
// 根据错误类型返回对应的错误码
|
||||
errorCode := api.GetErrorCode(err)
|
||||
response := dto.NewErrorResponse(errorCode, err.Error(), transactionId)
|
||||
c.JSON(200, response) // API调用接口统一返回200状态码
|
||||
return
|
||||
}
|
||||
|
||||
// 4. 返回成功响应
|
||||
response := dto.NewSuccessResponse(transactionId, encryptedResp)
|
||||
c.JSON(200, response)
|
||||
}
|
||||
|
||||
// GetUserApiKeys 获取用户API密钥
|
||||
func (h *ApiHandler) GetUserApiKeys(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetUserApiKeys(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户API密钥失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取API密钥成功")
|
||||
}
|
||||
|
||||
// GetUserWhiteList 获取用户白名单列表
|
||||
func (h *ApiHandler) GetUserWhiteList(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetUserWhiteList(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户白名单失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取白名单成功")
|
||||
}
|
||||
|
||||
// AddWhiteListIP 添加白名单IP
|
||||
func (h *ApiHandler) AddWhiteListIP(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var req dto.WhiteListRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
err := h.appService.AddWhiteListIP(c.Request.Context(), userID, req.IPAddress)
|
||||
if err != nil {
|
||||
h.logger.Error("添加白名单IP失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "添加白名单IP成功")
|
||||
}
|
||||
|
||||
// DeleteWhiteListIP 删除白名单IP
|
||||
func (h *ApiHandler) DeleteWhiteListIP(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
ipAddress := c.Param("ip")
|
||||
if ipAddress == "" {
|
||||
h.responseBuilder.BadRequest(c, "IP地址不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
err := h.appService.DeleteWhiteListIP(c.Request.Context(), userID, ipAddress)
|
||||
if err != nil {
|
||||
h.logger.Error("删除白名单IP失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "删除白名单IP成功")
|
||||
}
|
||||
|
||||
// EncryptParams 加密参数接口(用于前端调试)
|
||||
// @Summary 加密参数
|
||||
// @Description 用于前端调试时加密API调用参数
|
||||
// @Tags API调试
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body commands.EncryptCommand true "加密请求"
|
||||
// @Success 200 {object} dto.EncryptResponse "加密成功"
|
||||
// @Failure 400 {object} dto.EncryptResponse "请求参数错误"
|
||||
// @Failure 401 {object} dto.EncryptResponse "未授权"
|
||||
// @Router /api/v1/encrypt [post]
|
||||
func (h *ApiHandler) EncryptParams(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.EncryptCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
h.responseBuilder.BadRequest(c, "请求参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户的SecretKey
|
||||
apiKeys, err := h.appService.GetUserApiKeys(c.Request.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户API密钥失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, "获取API密钥失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 将JSON对象转换为字节数组
|
||||
jsonData, err := json.Marshal(cmd.Data)
|
||||
if err != nil {
|
||||
h.logger.Error("序列化参数失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, "参数序列化失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 加密参数
|
||||
encryptedData, err := crypto.AesEncrypt(jsonData, apiKeys.SecretKey)
|
||||
if err != nil {
|
||||
h.logger.Error("加密参数失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, "加密参数失败")
|
||||
return
|
||||
}
|
||||
|
||||
response := dto.EncryptResponse{
|
||||
EncryptedData: encryptedData,
|
||||
}
|
||||
h.responseBuilder.Success(c, response, "加密成功")
|
||||
}
|
||||
|
||||
// getCurrentUserID 获取当前用户ID
|
||||
func (h *ApiHandler) getCurrentUserID(c *gin.Context) string {
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
if id, ok := userID.(string); ok {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetUserApiCalls 获取用户API调用记录
|
||||
// @Summary 获取用户API调用记录
|
||||
// @Description 获取当前用户的API调用记录列表,支持分页和筛选
|
||||
// @Tags API管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param start_time query string false "开始时间 (格式: 2006-01-02 15:04:05)"
|
||||
// @Param end_time query string false "结束时间 (格式: 2006-01-02 15:04:05)"
|
||||
// @Param transaction_id query string false "交易ID"
|
||||
// @Param product_name query string false "产品名称"
|
||||
// @Param status query string false "状态 (pending/success/failed)"
|
||||
// @Success 200 {object} dto.ApiCallListResponse "获取成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/my/api-calls [get]
|
||||
func (h *ApiHandler) GetUserApiCalls(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
// 解析查询参数
|
||||
page := h.getIntQuery(c, "page", 1)
|
||||
pageSize := h.getIntQuery(c, "page_size", 10)
|
||||
|
||||
// 构建筛选条件
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
// 时间范围筛选
|
||||
if startTime := c.Query("start_time"); startTime != "" {
|
||||
if t, err := time.Parse("2006-01-02 15:04:05", startTime); err == nil {
|
||||
filters["start_time"] = t
|
||||
}
|
||||
}
|
||||
if endTime := c.Query("end_time"); endTime != "" {
|
||||
if t, err := time.Parse("2006-01-02 15:04:05", endTime); err == nil {
|
||||
filters["end_time"] = t
|
||||
}
|
||||
}
|
||||
|
||||
// 交易ID筛选
|
||||
if transactionId := c.Query("transaction_id"); transactionId != "" {
|
||||
filters["transaction_id"] = transactionId
|
||||
}
|
||||
|
||||
// 产品名称筛选
|
||||
if productName := c.Query("product_name"); productName != "" {
|
||||
filters["product_name"] = productName
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if status := c.Query("status"); status != "" {
|
||||
filters["status"] = status
|
||||
}
|
||||
|
||||
// 构建分页选项
|
||||
options := interfaces.ListOptions{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Sort: "created_at",
|
||||
Order: "desc",
|
||||
}
|
||||
|
||||
result, err := h.appService.GetUserApiCalls(c.Request.Context(), userID, filters, options)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户API调用记录失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, "获取API调用记录失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取API调用记录成功")
|
||||
}
|
||||
|
||||
// getIntQuery 获取整数查询参数
|
||||
func (h *ApiHandler) getIntQuery(c *gin.Context, key string, defaultValue int) int {
|
||||
if value := c.Query(key); value != "" {
|
||||
if intValue, err := strconv.Atoi(value); err == nil && intValue > 0 {
|
||||
return intValue
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
@@ -38,38 +43,6 @@ func NewCertificationHandler(
|
||||
}
|
||||
|
||||
// ================ 认证申请管理 ================
|
||||
|
||||
// CreateCertification 创建认证申请
|
||||
// @Summary 创建认证申请
|
||||
// @Description 为用户创建企业认证申请
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.CreateCertificationCommand true "创建认证申请请求"
|
||||
// @Success 201 {object} responses.CertificationResponse "认证申请创建成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications [post]
|
||||
func (h *CertificationHandler) CreateCertification(c *gin.Context) {
|
||||
var cmd commands.CreateCertificationCommand
|
||||
cmd.UserID = h.getCurrentUserID(c)
|
||||
if cmd.UserID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.CreateCertification(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("创建认证申请失败", zap.Error(err), zap.String("user_id", cmd.UserID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Created(c, result, "认证申请创建成功")
|
||||
}
|
||||
|
||||
// GetCertification 获取认证详情
|
||||
// @Summary 获取认证详情
|
||||
// @Description 根据认证ID获取认证详情
|
||||
@@ -77,13 +50,12 @@ func (h *CertificationHandler) CreateCertification(c *gin.Context) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "认证ID"
|
||||
// @Success 200 {object} responses.CertificationResponse "获取认证详情成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/{id} [get]
|
||||
// @Router /api/v1/certifications/details [get]
|
||||
func (h *CertificationHandler) GetCertification(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
@@ -91,21 +63,14 @@ func (h *CertificationHandler) GetCertification(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
certificationID := c.Param("id")
|
||||
if certificationID == "" {
|
||||
h.response.BadRequest(c, "认证ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
query := &queries.GetCertificationQuery{
|
||||
CertificationID: certificationID,
|
||||
UserID: userID,
|
||||
UserID: userID,
|
||||
}
|
||||
|
||||
result, err := h.appService.GetCertification(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证详情失败", zap.Error(err), zap.String("certification_id", certificationID))
|
||||
h.response.NotFound(c, "认证记录不存在")
|
||||
h.logger.Error("获取认证详情失败", zap.Error(err), zap.String("user_id", userID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -121,14 +86,13 @@ func (h *CertificationHandler) GetCertification(c *gin.Context) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "认证ID"
|
||||
// @Param request body commands.SubmitEnterpriseInfoCommand true "提交企业信息请求"
|
||||
// @Success 200 {object} responses.CertificationResponse "企业信息提交成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/{id}/enterprise-info [post]
|
||||
// @Router /api/v1/certifications/enterprise-info [post]
|
||||
func (h *CertificationHandler) SubmitEnterpriseInfo(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
@@ -136,22 +100,15 @@ func (h *CertificationHandler) SubmitEnterpriseInfo(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
certificationID := c.Param("id")
|
||||
if certificationID == "" {
|
||||
h.response.BadRequest(c, "认证ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.SubmitEnterpriseInfoCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
cmd.CertificationID = certificationID
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.SubmitEnterpriseInfo(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("提交企业信息失败", zap.Error(err), zap.String("certification_id", certificationID))
|
||||
h.logger.Error("提交企业信息失败", zap.Error(err), zap.String("user_id", userID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -159,6 +116,69 @@ func (h *CertificationHandler) SubmitEnterpriseInfo(c *gin.Context) {
|
||||
h.response.Success(c, result, "企业信息提交成功")
|
||||
}
|
||||
|
||||
// ConfirmAuth 前端确认是否完成认证
|
||||
// @Summary 前端确认认证状态
|
||||
// @Description 前端轮询确认企业认证是否完成
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.ConfirmAuthCommand true "确认状态请求"
|
||||
// @Success 200 {object} responses.ConfirmStatusResponse "状态确认成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/confirm-auth [post]
|
||||
func (h *CertificationHandler) ConfirmAuth(c *gin.Context) {
|
||||
var cmd queries.ConfirmAuthCommand
|
||||
cmd.UserID = h.getCurrentUserID(c)
|
||||
if cmd.UserID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.ConfirmAuth(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("确认认证/签署状态失败", zap.Error(err), zap.String("user_id", cmd.UserID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "状态确认成功")
|
||||
}
|
||||
|
||||
// ConfirmSign 前端确认是否完成签署
|
||||
// @Summary 前端确认签署状态
|
||||
// @Description 前端轮询确认合同签署是否完成
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.ConfirmSignCommand true "确认状态请求"
|
||||
// @Success 200 {object} responses.ConfirmStatusResponse "状态确认成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/confirm-sign [post]
|
||||
func (h *CertificationHandler) ConfirmSign(c *gin.Context) {
|
||||
var cmd queries.ConfirmSignCommand
|
||||
cmd.UserID = h.getCurrentUserID(c)
|
||||
if cmd.UserID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
result, err := h.appService.ConfirmSign(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("确认认证/签署状态失败", zap.Error(err), zap.String("user_id", cmd.UserID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "状态确认成功")
|
||||
}
|
||||
|
||||
// ================ 合同管理 ================
|
||||
|
||||
// ApplyContract 申请合同签署
|
||||
@@ -176,21 +196,16 @@ func (h *CertificationHandler) SubmitEnterpriseInfo(c *gin.Context) {
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/apply-contract [post]
|
||||
func (h *CertificationHandler) ApplyContract(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
var cmd commands.ApplyContractCommand
|
||||
cmd.UserID = h.getCurrentUserID(c)
|
||||
if cmd.UserID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.ApplyContractCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.ApplyContract(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("申请合同失败", zap.Error(err), zap.String("certification_id", cmd.CertificationID))
|
||||
h.logger.Error("申请合同失败", zap.Error(err), zap.String("user_id", cmd.UserID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
@@ -198,86 +213,6 @@ func (h *CertificationHandler) ApplyContract(c *gin.Context) {
|
||||
h.response.Success(c, result, "合同申请成功")
|
||||
}
|
||||
|
||||
// ================ 重试操作 ================
|
||||
|
||||
// RetryOperation 重试操作
|
||||
// @Summary 重试操作
|
||||
// @Description 重试失败的企业认证或合同申请操作
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.RetryOperationCommand true "重试操作请求"
|
||||
// @Success 200 {object} responses.CertificationResponse "重试操作成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "认证记录不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/retry [post]
|
||||
func (h *CertificationHandler) RetryOperation(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.RetryOperationCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.RetryOperation(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("重试操作失败", zap.Error(err), zap.String("certification_id", cmd.CertificationID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "重试操作成功")
|
||||
}
|
||||
|
||||
// ================ 查询操作 ================
|
||||
|
||||
// GetUserCertifications 获取用户认证列表
|
||||
// @Summary 获取用户认证列表
|
||||
// @Description 获取当前用户的认证申请列表
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param status query string false "认证状态"
|
||||
// @Param include_completed query bool false "是否包含已完成"
|
||||
// @Param include_failed query bool false "是否包含失败"
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Success 200 {object} responses.CertificationListResponse "获取用户认证列表成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/user [get]
|
||||
func (h *CertificationHandler) GetUserCertifications(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var query queries.GetUserCertificationsQuery
|
||||
if err := h.validator.BindAndValidate(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
query.UserID = userID
|
||||
|
||||
result, err := h.appService.GetUserCertifications(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户认证列表失败", zap.Error(err), zap.String("user_id", userID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取用户认证列表成功")
|
||||
}
|
||||
|
||||
// ListCertifications 获取认证列表(管理员)
|
||||
// @Summary 获取认证列表
|
||||
// @Description 管理员获取认证申请列表
|
||||
@@ -321,46 +256,6 @@ func (h *CertificationHandler) ListCertifications(c *gin.Context) {
|
||||
h.response.Success(c, result, "获取认证列表成功")
|
||||
}
|
||||
|
||||
// GetCertificationStatistics 获取认证统计
|
||||
// @Summary 获取认证统计
|
||||
// @Description 获取认证相关的统计数据
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param start_date query string true "开始日期" format(date)
|
||||
// @Param end_date query string true "结束日期" format(date)
|
||||
// @Param period query string false "统计周期" Enums(daily, weekly, monthly, yearly) default(daily)
|
||||
// @Param group_by query []string false "分组字段"
|
||||
// @Param user_ids query []string false "用户ID列表"
|
||||
// @Param statuses query []string false "状态列表"
|
||||
// @Success 200 {object} responses.CertificationStatisticsResponse "获取认证统计成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/statistics [get]
|
||||
func (h *CertificationHandler) GetCertificationStatistics(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var query queries.GetCertificationStatisticsQuery
|
||||
if err := h.validator.BindAndValidate(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetCertificationStatistics(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取认证统计失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取认证统计成功")
|
||||
}
|
||||
|
||||
// ================ 回调处理 ================
|
||||
|
||||
// HandleEsignCallback 处理e签宝回调
|
||||
@@ -373,97 +268,118 @@ func (h *CertificationHandler) GetCertificationStatistics(c *gin.Context) {
|
||||
// @Success 200 {object} responses.CallbackResponse "回调处理成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/callbacks [post]
|
||||
// @Router /api/v1/certifications/callbacks/esign [post]
|
||||
func (h *CertificationHandler) HandleEsignCallback(c *gin.Context) {
|
||||
var cmd commands.EsignCallbackCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
// 记录请求基本信息
|
||||
h.logger.Info("收到e签宝回调请求",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.String("remote_addr", c.ClientIP()),
|
||||
zap.String("user_agent", c.GetHeader("User-Agent")),
|
||||
)
|
||||
|
||||
// 记录所有请求头
|
||||
headers := make(map[string]string)
|
||||
for key, values := range c.Request.Header {
|
||||
if len(values) > 0 {
|
||||
headers[key] = values[0]
|
||||
}
|
||||
}
|
||||
h.logger.Info("回调请求头信息", zap.Any("headers", headers))
|
||||
|
||||
// 记录URL查询参数
|
||||
queryParams := make(map[string]string)
|
||||
for key, values := range c.Request.URL.Query() {
|
||||
if len(values) > 0 {
|
||||
queryParams[key] = values[0]
|
||||
}
|
||||
}
|
||||
if len(queryParams) > 0 {
|
||||
h.logger.Info("回调URL查询参数", zap.Any("query_params", queryParams))
|
||||
}
|
||||
|
||||
result, err := h.appService.HandleEsignCallback(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("处理e签宝回调失败", zap.Error(err), zap.String("certification_id", cmd.CertificationID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
// 读取并记录请求体
|
||||
var callbackData *commands.EsignCallbackData
|
||||
if c.Request.Body != nil {
|
||||
bodyBytes, err := c.GetRawData()
|
||||
if err != nil {
|
||||
h.logger.Error("读取回调请求体失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "读取请求体失败")
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(bodyBytes, &callbackData); err != nil {
|
||||
h.logger.Error("回调请求体不是有效的JSON格式", zap.Error(err))
|
||||
h.response.BadRequest(c, "请求体格式错误")
|
||||
return
|
||||
}
|
||||
h.logger.Info("回调请求体内容", zap.Any("body", callbackData))
|
||||
|
||||
// 如果后续还需要用 c.Request.Body
|
||||
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "回调处理成功")
|
||||
}
|
||||
// 记录Content-Type
|
||||
contentType := c.GetHeader("Content-Type")
|
||||
h.logger.Info("回调请求Content-Type", zap.String("content_type", contentType))
|
||||
|
||||
// ================ 管理员操作 ================
|
||||
|
||||
// ForceTransitionStatus 强制状态转换(管理员)
|
||||
// @Summary 强制状态转换
|
||||
// @Description 管理员强制转换认证状态
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.ForceTransitionStatusCommand true "强制状态转换请求"
|
||||
// @Success 200 {object} responses.CertificationResponse "状态转换成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 403 {object} map[string]interface{} "权限不足"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/force-transition [post]
|
||||
func (h *CertificationHandler) ForceTransitionStatus(c *gin.Context) {
|
||||
adminID := h.getCurrentUserID(c)
|
||||
if adminID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
// 记录Content-Length
|
||||
contentLength := c.GetHeader("Content-Length")
|
||||
if contentLength != "" {
|
||||
h.logger.Info("回调请求Content-Length", zap.String("content_length", contentLength))
|
||||
}
|
||||
|
||||
var cmd commands.ForceTransitionStatusCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
cmd.AdminID = adminID
|
||||
// 记录时间戳
|
||||
h.logger.Info("回调请求时间",
|
||||
zap.Time("request_time", time.Now()),
|
||||
zap.String("request_id", c.GetHeader("X-Request-ID")),
|
||||
)
|
||||
|
||||
result, err := h.appService.ForceTransitionStatus(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("强制状态转换失败", zap.Error(err), zap.String("certification_id", cmd.CertificationID))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
// 记录完整的请求信息摘要
|
||||
h.logger.Info("e签宝回调完整信息摘要",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.String("client_ip", c.ClientIP()),
|
||||
zap.String("content_type", contentType),
|
||||
zap.Any("headers", headers),
|
||||
zap.Any("query_params", queryParams),
|
||||
zap.Any("body", callbackData),
|
||||
)
|
||||
|
||||
// 处理回调数据
|
||||
if callbackData != nil {
|
||||
// 构建请求头映射
|
||||
headers := make(map[string]string)
|
||||
for key, values := range c.Request.Header {
|
||||
if len(values) > 0 {
|
||||
headers[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
// 构建查询参数映射
|
||||
queryParams := make(map[string]string)
|
||||
for key, values := range c.Request.URL.Query() {
|
||||
if len(values) > 0 {
|
||||
queryParams[key] = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.appService.HandleEsignCallback(c.Request.Context(), &commands.EsignCallbackCommand{
|
||||
Data: callbackData,
|
||||
Headers: headers,
|
||||
QueryParams: queryParams,
|
||||
}); err != nil {
|
||||
h.logger.Error("处理e签宝回调失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "回调处理失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "状态转换成功")
|
||||
}
|
||||
|
||||
// GetSystemMonitoring 获取系统监控数据
|
||||
// @Summary 获取系统监控数据
|
||||
// @Description 获取认证系统的监控数据
|
||||
// @Tags 认证管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param time_range query string false "时间范围" Enums(1h, 6h, 24h, 7d, 30d) default(24h)
|
||||
// @Param metrics query []string false "监控指标"
|
||||
// @Success 200 {object} responses.SystemMonitoringResponse "获取系统监控数据成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 403 {object} map[string]interface{} "权限不足"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/certifications/monitoring [get]
|
||||
func (h *CertificationHandler) GetSystemMonitoring(c *gin.Context) {
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var query queries.GetSystemMonitoringQuery
|
||||
if err := h.validator.BindAndValidate(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetSystemMonitoring(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取系统监控数据失败", zap.Error(err))
|
||||
h.response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, result, "获取系统监控数据成功")
|
||||
// 返回成功响应
|
||||
c.JSON(200, map[string]interface{}{
|
||||
"code": "200",
|
||||
"msg": "success",
|
||||
})
|
||||
}
|
||||
|
||||
// ================ 辅助方法 ================
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
@@ -33,34 +38,6 @@ func NewFinanceHandler(
|
||||
}
|
||||
}
|
||||
|
||||
// CreateWallet 创建钱包
|
||||
// @Summary 创建钱包
|
||||
// @Description 为用户创建新的钱包账户
|
||||
// @Tags 钱包管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body commands.CreateWalletCommand true "创建钱包请求"
|
||||
// @Success 201 {object} responses.WalletResponse "钱包创建成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 409 {object} map[string]interface{} "钱包已存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/wallet [post]
|
||||
func (h *FinanceHandler) CreateWallet(c *gin.Context) {
|
||||
var cmd commands.CreateWalletCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
response, err := h.appService.CreateWallet(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("创建钱包失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Created(c, response, "钱包创建成功")
|
||||
}
|
||||
|
||||
// GetWallet 获取钱包信息
|
||||
// @Summary 获取钱包信息
|
||||
// @Description 获取当前用户的钱包详细信息
|
||||
@@ -94,333 +71,486 @@ func (h *FinanceHandler) GetWallet(c *gin.Context) {
|
||||
h.responseBuilder.Success(c, result, "获取钱包信息成功")
|
||||
}
|
||||
|
||||
// UpdateWallet 更新钱包
|
||||
// @Summary 更新钱包信息
|
||||
// @Description 更新当前用户的钱包基本信息
|
||||
// GetUserWalletTransactions 获取用户钱包交易记录
|
||||
// @Summary 获取用户钱包交易记录
|
||||
// @Description 获取当前用户的钱包交易记录列表,支持分页和筛选
|
||||
// @Tags 钱包管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.UpdateWalletCommand true "更新钱包请求"
|
||||
// @Success 200 {object} map[string]interface{} "钱包更新成功"
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param start_time query string false "开始时间 (格式: 2006-01-02 15:04:05)"
|
||||
// @Param end_time query string false "结束时间 (格式: 2006-01-02 15:04:05)"
|
||||
// @Param transaction_id query string false "交易ID"
|
||||
// @Param product_name query string false "产品名称"
|
||||
// @Param min_amount query string false "最小金额"
|
||||
// @Param max_amount query string false "最大金额"
|
||||
// @Success 200 {object} responses.WalletTransactionListResponse "获取成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/wallet [put]
|
||||
func (h *FinanceHandler) UpdateWallet(c *gin.Context) {
|
||||
// @Router /api/v1/finance/wallet/transactions [get]
|
||||
func (h *FinanceHandler) GetUserWalletTransactions(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.UpdateWalletCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
// 解析查询参数
|
||||
page := h.getIntQuery(c, "page", 1)
|
||||
pageSize := h.getIntQuery(c, "page_size", 10)
|
||||
|
||||
// 构建筛选条件
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
// 时间范围筛选
|
||||
if startTime := c.Query("start_time"); startTime != "" {
|
||||
if t, err := time.Parse("2006-01-02 15:04:05", startTime); err == nil {
|
||||
filters["start_time"] = t
|
||||
}
|
||||
}
|
||||
if endTime := c.Query("end_time"); endTime != "" {
|
||||
if t, err := time.Parse("2006-01-02 15:04:05", endTime); err == nil {
|
||||
filters["end_time"] = t
|
||||
}
|
||||
}
|
||||
|
||||
cmd.UserID = userID
|
||||
// 交易ID筛选
|
||||
if transactionId := c.Query("transaction_id"); transactionId != "" {
|
||||
filters["transaction_id"] = transactionId
|
||||
}
|
||||
|
||||
err := h.appService.UpdateWallet(c.Request.Context(), &cmd)
|
||||
// 产品名称筛选
|
||||
if productName := c.Query("product_name"); productName != "" {
|
||||
filters["product_name"] = productName
|
||||
}
|
||||
|
||||
// 金额范围筛选
|
||||
if minAmount := c.Query("min_amount"); minAmount != "" {
|
||||
filters["min_amount"] = minAmount
|
||||
}
|
||||
if maxAmount := c.Query("max_amount"); maxAmount != "" {
|
||||
filters["max_amount"] = maxAmount
|
||||
}
|
||||
|
||||
// 构建分页选项
|
||||
options := interfaces.ListOptions{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Sort: "created_at",
|
||||
Order: "desc",
|
||||
}
|
||||
|
||||
result, err := h.appService.GetUserWalletTransactions(c.Request.Context(), userID, filters, options)
|
||||
if err != nil {
|
||||
h.logger.Error("更新钱包失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
h.logger.Error("获取用户钱包交易记录失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, "获取钱包交易记录失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "钱包更新成功")
|
||||
h.responseBuilder.Success(c, result, "获取钱包交易记录成功")
|
||||
}
|
||||
|
||||
// Recharge 充值
|
||||
// @Summary 钱包充值
|
||||
// @Description 为钱包进行充值操作
|
||||
// getIntQuery 获取整数查询参数
|
||||
func (h *FinanceHandler) getIntQuery(c *gin.Context, key string, defaultValue int) int {
|
||||
if value := c.Query(key); value != "" {
|
||||
if intValue, err := strconv.Atoi(value); err == nil && intValue > 0 {
|
||||
return intValue
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// HandleAlipayCallback 处理支付宝支付回调
|
||||
// @Summary 支付宝支付回调
|
||||
// @Description 处理支付宝异步支付通知
|
||||
// @Tags 支付管理
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce text/plain
|
||||
// @Success 200 {string} string "success"
|
||||
// @Failure 400 {string} string "fail"
|
||||
// @Router /api/v1/finance/alipay/callback [post]
|
||||
func (h *FinanceHandler) HandleAlipayCallback(c *gin.Context) {
|
||||
// 记录回调请求信息
|
||||
h.logger.Info("收到支付宝回调请求",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.String("remote_addr", c.ClientIP()),
|
||||
zap.String("user_agent", c.GetHeader("User-Agent")),
|
||||
)
|
||||
|
||||
// 通过应用服务处理支付宝回调
|
||||
err := h.appService.HandleAlipayCallback(c.Request.Context(), c.Request)
|
||||
if err != nil {
|
||||
h.logger.Error("支付宝回调处理失败", zap.Error(err))
|
||||
c.String(400, "fail")
|
||||
return
|
||||
}
|
||||
|
||||
// 返回成功响应(支付宝要求返回success)
|
||||
c.String(200, "success")
|
||||
}
|
||||
|
||||
// HandleAlipayReturn 处理支付宝同步回调
|
||||
// @Summary 支付宝同步回调
|
||||
// @Description 处理支付宝同步支付通知,跳转到前端成功页面
|
||||
// @Tags 支付管理
|
||||
// @Accept application/x-www-form-urlencoded
|
||||
// @Produce text/html
|
||||
// @Success 200 {string} string "支付成功页面"
|
||||
// @Failure 400 {string} string "支付失败页面"
|
||||
// @Router /api/v1/finance/alipay/return [get]
|
||||
func (h *FinanceHandler) HandleAlipayReturn(c *gin.Context) {
|
||||
// 记录同步回调请求信息
|
||||
h.logger.Info("收到支付宝同步回调请求",
|
||||
zap.String("method", c.Request.Method),
|
||||
zap.String("url", c.Request.URL.String()),
|
||||
zap.String("remote_addr", c.ClientIP()),
|
||||
zap.String("user_agent", c.GetHeader("User-Agent")),
|
||||
)
|
||||
|
||||
// 获取查询参数
|
||||
outTradeNo := c.Query("out_trade_no")
|
||||
tradeNo := c.Query("trade_no")
|
||||
totalAmount := c.Query("total_amount")
|
||||
|
||||
h.logger.Info("支付宝同步回调参数",
|
||||
zap.String("out_trade_no", outTradeNo),
|
||||
zap.String("trade_no", tradeNo),
|
||||
zap.String("total_amount", totalAmount),
|
||||
)
|
||||
|
||||
// 验证必要参数
|
||||
if outTradeNo == "" {
|
||||
h.logger.Error("支付宝同步回调缺少商户订单号")
|
||||
h.redirectToFailPage(c, "", "缺少商户订单号")
|
||||
return
|
||||
}
|
||||
|
||||
// 通过应用服务处理同步回调,查询订单状态
|
||||
orderStatus, err := h.appService.HandleAlipayReturn(c.Request.Context(), outTradeNo)
|
||||
if err != nil {
|
||||
h.logger.Error("支付宝同步回调处理失败",
|
||||
zap.String("out_trade_no", outTradeNo),
|
||||
zap.Error(err))
|
||||
h.redirectToFailPage(c, outTradeNo, "订单处理失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 根据环境确定前端域名
|
||||
frontendDomain := "https://www.tianyuanapi.com"
|
||||
if gin.Mode() == gin.DebugMode {
|
||||
frontendDomain = "http://localhost:5173"
|
||||
}
|
||||
|
||||
// 根据订单状态跳转到相应页面
|
||||
switch orderStatus {
|
||||
case "TRADE_SUCCESS":
|
||||
// 支付成功,跳转到前端成功页面
|
||||
successURL := fmt.Sprintf("%s/finance/wallet/success?out_trade_no=%s&trade_no=%s&amount=%s",
|
||||
frontendDomain, outTradeNo, tradeNo, totalAmount)
|
||||
c.Redirect(http.StatusFound, successURL)
|
||||
case "WAIT_BUYER_PAY":
|
||||
// 支付处理中,跳转到处理中页面
|
||||
h.redirectToProcessingPage(c, outTradeNo, totalAmount)
|
||||
default:
|
||||
// 支付失败或取消,跳转到前端失败页面
|
||||
h.redirectToFailPage(c, outTradeNo, orderStatus)
|
||||
}
|
||||
}
|
||||
|
||||
// redirectToFailPage 跳转到失败页面
|
||||
func (h *FinanceHandler) redirectToFailPage(c *gin.Context, outTradeNo, reason string) {
|
||||
frontendDomain := "https://www.tianyuanapi.com"
|
||||
if gin.Mode() == gin.DebugMode {
|
||||
frontendDomain = "http://localhost:5173"
|
||||
}
|
||||
|
||||
failURL := fmt.Sprintf("%s/finance/wallet/fail?out_trade_no=%s&reason=%s",
|
||||
frontendDomain, outTradeNo, reason)
|
||||
c.Redirect(http.StatusFound, failURL)
|
||||
}
|
||||
|
||||
// redirectToProcessingPage 跳转到处理中页面
|
||||
func (h *FinanceHandler) redirectToProcessingPage(c *gin.Context, outTradeNo, amount string) {
|
||||
frontendDomain := "https://www.tianyuanapi.com"
|
||||
if gin.Mode() == gin.DebugMode {
|
||||
frontendDomain = "http://localhost:5173"
|
||||
}
|
||||
|
||||
processingURL := fmt.Sprintf("%s/finance/wallet/processing?out_trade_no=%s&amount=%s",
|
||||
frontendDomain, outTradeNo, amount)
|
||||
c.Redirect(http.StatusFound, processingURL)
|
||||
}
|
||||
|
||||
// CreateAlipayRecharge 创建支付宝充值订单
|
||||
// @Summary 创建支付宝充值订单
|
||||
// @Description 创建支付宝充值订单并返回支付链接
|
||||
// @Tags 钱包管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.RechargeWalletCommand true "充值请求"
|
||||
// @Success 200 {object} responses.TransactionResponse "充值成功"
|
||||
// @Param request body commands.CreateAlipayRechargeCommand true "充值请求"
|
||||
// @Success 200 {object} responses.AlipayRechargeOrderResponse "创建充值订单成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/wallet/recharge [post]
|
||||
func (h *FinanceHandler) Recharge(c *gin.Context) {
|
||||
// @Router /api/v1/finance/wallet/alipay-recharge [post]
|
||||
func (h *FinanceHandler) CreateAlipayRecharge(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.RechargeWalletCommand
|
||||
var cmd commands.CreateAlipayRechargeCommand
|
||||
cmd.UserID = userID
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.Recharge(c.Request.Context(), &cmd)
|
||||
// 调用应用服务进行完整的业务流程编排
|
||||
result, err := h.appService.CreateAlipayRechargeOrder(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("充值失败",
|
||||
h.logger.Error("创建支付宝充值订单失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.String("amount", cmd.Amount),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, "创建支付宝充值订单失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("支付宝充值订单创建成功",
|
||||
zap.String("user_id", userID),
|
||||
zap.String("out_trade_no", result.OutTradeNo),
|
||||
zap.String("amount", cmd.Amount),
|
||||
zap.String("platform", cmd.Platform),
|
||||
)
|
||||
|
||||
// 返回支付链接和订单信息
|
||||
h.responseBuilder.Success(c, result, "支付宝充值订单创建成功")
|
||||
}
|
||||
|
||||
// TransferRecharge 管理员对公转账充值
|
||||
func (h *FinanceHandler) TransferRecharge(c *gin.Context) {
|
||||
var cmd commands.TransferRechargeCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if cmd.UserID == "" {
|
||||
h.responseBuilder.BadRequest(c, "缺少用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.TransferRecharge(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("对公转账充值失败",
|
||||
zap.String("user_id", cmd.UserID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "充值成功")
|
||||
h.responseBuilder.Success(c, result, "对公转账充值成功")
|
||||
}
|
||||
|
||||
// Withdraw 提现
|
||||
// @Summary 钱包提现
|
||||
// @Description 从钱包进行提现操作
|
||||
// GiftRecharge 管理员赠送充值
|
||||
func (h *FinanceHandler) GiftRecharge(c *gin.Context) {
|
||||
var cmd commands.GiftRechargeCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if cmd.UserID == "" {
|
||||
h.responseBuilder.BadRequest(c, "缺少用户ID")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GiftRecharge(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("赠送充值失败",
|
||||
zap.String("user_id", cmd.UserID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "赠送充值成功")
|
||||
}
|
||||
|
||||
// GetUserRechargeRecords 用户获取自己充值记录分页
|
||||
func (h *FinanceHandler) GetUserRechargeRecords(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
// 解析查询参数
|
||||
page := h.getIntQuery(c, "page", 1)
|
||||
pageSize := h.getIntQuery(c, "page_size", 10)
|
||||
|
||||
// 构建筛选条件
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
// 时间范围筛选
|
||||
if startTime := c.Query("start_time"); startTime != "" {
|
||||
if t, err := time.Parse("2006-01-02 15:04:05", startTime); err == nil {
|
||||
filters["start_time"] = t
|
||||
}
|
||||
}
|
||||
if endTime := c.Query("end_time"); endTime != "" {
|
||||
if t, err := time.Parse("2006-01-02 15:04:05", endTime); err == nil {
|
||||
filters["end_time"] = t
|
||||
}
|
||||
}
|
||||
|
||||
// 充值类型筛选
|
||||
if rechargeType := c.Query("recharge_type"); rechargeType != "" {
|
||||
filters["recharge_type"] = rechargeType
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if status := c.Query("status"); status != "" {
|
||||
filters["status"] = status
|
||||
}
|
||||
|
||||
// 构建分页选项
|
||||
options := interfaces.ListOptions{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Sort: "created_at",
|
||||
Order: "desc",
|
||||
}
|
||||
|
||||
result, err := h.appService.GetUserRechargeRecords(c.Request.Context(), userID, filters, options)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户充值记录失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, "获取充值记录失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取充值记录成功")
|
||||
}
|
||||
|
||||
// GetAdminRechargeRecords 管理员获取充值记录分页
|
||||
func (h *FinanceHandler) GetAdminRechargeRecords(c *gin.Context) {
|
||||
// 解析查询参数
|
||||
page := h.getIntQuery(c, "page", 1)
|
||||
pageSize := h.getIntQuery(c, "page_size", 10)
|
||||
|
||||
// 构建筛选条件
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
// 用户ID筛选
|
||||
if userID := c.Query("user_id"); userID != "" {
|
||||
filters["user_id"] = userID
|
||||
}
|
||||
|
||||
// 时间范围筛选
|
||||
if startTime := c.Query("start_time"); startTime != "" {
|
||||
if t, err := time.Parse("2006-01-02 15:04:05", startTime); err == nil {
|
||||
filters["start_time"] = t
|
||||
}
|
||||
}
|
||||
if endTime := c.Query("end_time"); endTime != "" {
|
||||
if t, err := time.Parse("2006-01-02 15:04:05", endTime); err == nil {
|
||||
filters["end_time"] = t
|
||||
}
|
||||
}
|
||||
|
||||
// 充值类型筛选
|
||||
if rechargeType := c.Query("recharge_type"); rechargeType != "" {
|
||||
filters["recharge_type"] = rechargeType
|
||||
}
|
||||
|
||||
// 状态筛选
|
||||
if status := c.Query("status"); status != "" {
|
||||
filters["status"] = status
|
||||
}
|
||||
|
||||
// 构建分页选项
|
||||
options := interfaces.ListOptions{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Sort: "created_at",
|
||||
Order: "desc",
|
||||
}
|
||||
|
||||
result, err := h.appService.GetAdminRechargeRecords(c.Request.Context(), filters, options)
|
||||
if err != nil {
|
||||
h.logger.Error("获取充值记录失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, "获取充值记录失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取充值记录成功")
|
||||
}
|
||||
|
||||
// GetRechargeConfig 获取充值配置
|
||||
// @Summary 获取充值配置
|
||||
// @Description 获取当前环境的充值配置信息(最低充值金额、最高充值金额等)
|
||||
// @Tags 钱包管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} responses.RechargeConfigResponse "获取充值配置成功"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/wallet/recharge-config [get]
|
||||
func (h *FinanceHandler) GetRechargeConfig(c *gin.Context) {
|
||||
result, err := h.appService.GetRechargeConfig(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("获取充值配置失败", zap.Error(err))
|
||||
h.responseBuilder.BadRequest(c, "获取充值配置失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取充值配置成功")
|
||||
}
|
||||
|
||||
// GetAlipayOrderStatus 获取支付宝订单状态
|
||||
// @Summary 获取支付宝订单状态
|
||||
// @Description 获取支付宝订单的当前状态,用于轮询查询
|
||||
// @Tags 钱包管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.WithdrawWalletCommand true "提现请求"
|
||||
// @Success 200 {object} responses.TransactionResponse "提现申请已提交"
|
||||
// @Param out_trade_no query string true "商户订单号"
|
||||
// @Success 200 {object} responses.AlipayOrderStatusResponse "获取订单状态成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "订单不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/wallet/withdraw [post]
|
||||
func (h *FinanceHandler) Withdraw(c *gin.Context) {
|
||||
// @Router /api/v1/finance/wallet/alipay-order-status [get]
|
||||
func (h *FinanceHandler) GetAlipayOrderStatus(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.WithdrawWalletCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
outTradeNo := c.Query("out_trade_no")
|
||||
if outTradeNo == "" {
|
||||
h.responseBuilder.BadRequest(c, "缺少商户订单号")
|
||||
return
|
||||
}
|
||||
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.Withdraw(c.Request.Context(), &cmd)
|
||||
result, err := h.appService.GetAlipayOrderStatus(c.Request.Context(), outTradeNo)
|
||||
if err != nil {
|
||||
h.logger.Error("提现失败",
|
||||
h.logger.Error("获取支付宝订单状态失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.String("out_trade_no", outTradeNo),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
h.responseBuilder.BadRequest(c, "获取订单状态失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "提现申请已提交")
|
||||
}
|
||||
|
||||
// WalletTransaction 钱包交易
|
||||
// @Summary 钱包交易
|
||||
// @Description 执行钱包内部交易操作
|
||||
// @Tags 钱包管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.WalletTransactionCommand true "交易请求"
|
||||
// @Success 200 {object} responses.TransactionResponse "交易成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/wallet/transaction [post]
|
||||
func (h *FinanceHandler) WalletTransaction(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.WalletTransactionCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.WalletTransaction(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("钱包交易失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "交易成功")
|
||||
}
|
||||
|
||||
// GetWalletStats 获取钱包统计
|
||||
// @Summary 获取钱包统计
|
||||
// @Description 获取钱包相关的统计数据
|
||||
// @Tags 钱包管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.WalletStatsResponse "获取钱包统计成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/wallet/stats [get]
|
||||
func (h *FinanceHandler) GetWalletStats(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.appService.GetWalletStats(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("获取钱包统计失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.InternalError(c, "获取钱包统计失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取钱包统计成功")
|
||||
}
|
||||
|
||||
// CreateUserSecrets 创建用户密钥
|
||||
// @Summary 创建用户密钥
|
||||
// @Description 为用户创建API访问密钥
|
||||
// @Tags 用户密钥管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param request body commands.CreateUserSecretsCommand true "创建密钥请求"
|
||||
// @Success 201 {object} responses.UserSecretsResponse "用户密钥创建成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 409 {object} map[string]interface{} "密钥已存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/secrets [post]
|
||||
func (h *FinanceHandler) CreateUserSecrets(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.CreateUserSecretsCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cmd.UserID = userID
|
||||
|
||||
result, err := h.appService.CreateUserSecrets(c.Request.Context(), &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("创建用户密钥失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Created(c, result, "用户密钥创建成功")
|
||||
}
|
||||
|
||||
// GetUserSecrets 获取用户密钥
|
||||
// @Summary 获取用户密钥
|
||||
// @Description 获取当前用户的API访问密钥信息
|
||||
// @Tags 用户密钥管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.UserSecretsResponse "获取用户密钥成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "密钥不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/secrets [get]
|
||||
func (h *FinanceHandler) GetUserSecrets(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
query := &queries.GetUserSecretsQuery{UserID: userID}
|
||||
result, err := h.appService.GetUserSecrets(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户密钥失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取用户密钥成功")
|
||||
}
|
||||
|
||||
// RegenerateAccessKey 重新生成访问密钥
|
||||
// @Summary 重新生成访问密钥
|
||||
// @Description 重新生成用户的API访问密钥
|
||||
// @Tags 用户密钥管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.UserSecretsResponse "访问密钥重新生成成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "密钥不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/secrets/regenerate [post]
|
||||
func (h *FinanceHandler) RegenerateAccessKey(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
cmd := &commands.RegenerateAccessKeyCommand{UserID: userID}
|
||||
result, err := h.appService.RegenerateAccessKey(c.Request.Context(), cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("重新生成访问密钥失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "访问密钥重新生成成功")
|
||||
}
|
||||
|
||||
// DeactivateUserSecrets 停用用户密钥
|
||||
// @Summary 停用用户密钥
|
||||
// @Description 停用用户的API访问密钥
|
||||
// @Tags 用户密钥管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} map[string]interface{} "用户密钥停用成功"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "密钥不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/finance/secrets/deactivate [post]
|
||||
func (h *FinanceHandler) DeactivateUserSecrets(c *gin.Context) {
|
||||
userID := c.GetString("user_id")
|
||||
if userID == "" {
|
||||
h.responseBuilder.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
cmd := &commands.DeactivateUserSecretsCommand{UserID: userID}
|
||||
err := h.appService.DeactivateUserSecrets(c.Request.Context(), cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("停用用户密钥失败",
|
||||
zap.String("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "用户密钥停用成功")
|
||||
h.responseBuilder.Success(c, result, "获取订单状态成功")
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"tyapi-server/internal/application/product"
|
||||
"tyapi-server/internal/application/product/dto/commands"
|
||||
"tyapi-server/internal/application/product/dto/queries"
|
||||
"tyapi-server/internal/application/product/dto/responses"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -84,7 +86,9 @@ func (h *ProductAdminHandler) CreateProduct(c *gin.Context) {
|
||||
// @Router /api/v1/admin/products/{id} [put]
|
||||
func (h *ProductAdminHandler) UpdateProduct(c *gin.Context) {
|
||||
var cmd commands.UpdateProductCommand
|
||||
if err := h.validator.ValidateParam(c, &cmd); err != nil {
|
||||
cmd.ID = c.Param("id")
|
||||
if cmd.ID == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||||
return
|
||||
}
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
@@ -254,7 +258,7 @@ func (h *ProductAdminHandler) UpdateSubscriptionPrice(c *gin.Context) {
|
||||
|
||||
// ListProducts 获取产品列表(管理员)
|
||||
// @Summary 获取产品列表
|
||||
// @Description 管理员获取产品列表,支持筛选
|
||||
// @Description 管理员获取产品列表,支持筛选和分页
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
@@ -263,30 +267,76 @@ func (h *ProductAdminHandler) UpdateSubscriptionPrice(c *gin.Context) {
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param keyword query string false "搜索关键词"
|
||||
// @Param category_id query string false "分类ID"
|
||||
// @Param status query string false "产品状态"
|
||||
// @Param is_enabled query bool false "是否启用"
|
||||
// @Param is_visible query bool false "是否可见"
|
||||
// @Param is_package query bool false "是否组合包"
|
||||
// @Param sort_by query string false "排序字段"
|
||||
// @Param sort_order query string false "排序方向" Enums(asc, desc)
|
||||
// @Success 200 {object} responses.ProductListResponse "获取产品列表成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products [get]
|
||||
func (h *ProductAdminHandler) ListProducts(c *gin.Context) {
|
||||
var query queries.ListProductsQuery
|
||||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||||
return
|
||||
// 解析查询参数
|
||||
page := h.getIntQuery(c, "page", 1)
|
||||
pageSize := h.getIntQuery(c, "page_size", 10)
|
||||
|
||||
// 构建筛选条件
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
// 搜索关键词筛选
|
||||
if keyword := c.Query("keyword"); keyword != "" {
|
||||
filters["keyword"] = keyword
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 10
|
||||
}
|
||||
if query.PageSize > 100 {
|
||||
query.PageSize = 100
|
||||
// 分类ID筛选
|
||||
if categoryID := c.Query("category_id"); categoryID != "" {
|
||||
filters["category_id"] = categoryID
|
||||
}
|
||||
|
||||
result, err := h.productAppService.ListProducts(c.Request.Context(), &query)
|
||||
// 启用状态筛选
|
||||
if isEnabled := c.Query("is_enabled"); isEnabled != "" {
|
||||
if enabled, err := strconv.ParseBool(isEnabled); err == nil {
|
||||
filters["is_enabled"] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// 可见状态筛选
|
||||
if isVisible := c.Query("is_visible"); isVisible != "" {
|
||||
if visible, err := strconv.ParseBool(isVisible); err == nil {
|
||||
filters["is_visible"] = visible
|
||||
}
|
||||
}
|
||||
|
||||
// 产品类型筛选
|
||||
if isPackage := c.Query("is_package"); isPackage != "" {
|
||||
if pkg, err := strconv.ParseBool(isPackage); err == nil {
|
||||
filters["is_package"] = pkg
|
||||
}
|
||||
}
|
||||
|
||||
// 排序字段
|
||||
sortBy := c.Query("sort_by")
|
||||
if sortBy == "" {
|
||||
sortBy = "created_at"
|
||||
}
|
||||
|
||||
// 排序方向
|
||||
sortOrder := c.Query("sort_order")
|
||||
if sortOrder == "" {
|
||||
sortOrder = "desc"
|
||||
}
|
||||
|
||||
// 构建分页选项
|
||||
options := interfaces.ListOptions{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Sort: sortBy,
|
||||
Order: sortOrder,
|
||||
}
|
||||
|
||||
result, err := h.productAppService.ListProducts(c.Request.Context(), filters, options)
|
||||
if err != nil {
|
||||
h.logger.Error("获取产品列表失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取产品列表失败")
|
||||
@@ -296,6 +346,16 @@ func (h *ProductAdminHandler) ListProducts(c *gin.Context) {
|
||||
h.responseBuilder.Success(c, result, "获取产品列表成功")
|
||||
}
|
||||
|
||||
// getIntQuery 获取整数查询参数
|
||||
func (h *ProductAdminHandler) getIntQuery(c *gin.Context, key string, defaultValue int) int {
|
||||
if value := c.Query(key); value != "" {
|
||||
if intValue, err := strconv.Atoi(value); err == nil && intValue > 0 {
|
||||
return intValue
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// GetProductDetail 获取产品详情(管理员)
|
||||
// @Summary 获取产品详情
|
||||
// @Description 管理员获取产品详细信息
|
||||
@@ -329,6 +389,233 @@ func (h *ProductAdminHandler) GetProductDetail(c *gin.Context) {
|
||||
h.responseBuilder.Success(c, result, "获取产品详情成功")
|
||||
}
|
||||
|
||||
// GetAvailableProducts 获取可选子产品列表
|
||||
// @Summary 获取可选子产品列表
|
||||
// @Description 管理员获取可选作组合包子产品的产品列表
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param exclude_package_id query string false "排除的组合包ID"
|
||||
// @Param keyword query string false "搜索关键词"
|
||||
// @Param category_id query string false "分类ID"
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(20)
|
||||
// @Success 200 {object} responses.ProductListResponse "获取可选产品列表成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/available [get]
|
||||
func (h *ProductAdminHandler) GetAvailableProducts(c *gin.Context) {
|
||||
var query queries.GetAvailableProductsQuery
|
||||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 20
|
||||
}
|
||||
if query.PageSize > 100 {
|
||||
query.PageSize = 100
|
||||
}
|
||||
|
||||
result, err := h.productAppService.GetAvailableProducts(c.Request.Context(), &query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取可选产品列表失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取可选产品列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取可选产品列表成功")
|
||||
}
|
||||
|
||||
// AddPackageItem 添加组合包子产品
|
||||
// @Summary 添加组合包子产品
|
||||
// @Description 管理员向组合包添加子产品
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "组合包ID"
|
||||
// @Param command body commands.AddPackageItemCommand true "添加子产品命令"
|
||||
// @Success 200 {object} map[string]interface{} "添加成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/package-items [post]
|
||||
func (h *ProductAdminHandler) AddPackageItem(c *gin.Context) {
|
||||
packageID := c.Param("id")
|
||||
if packageID == "" {
|
||||
h.responseBuilder.BadRequest(c, "组合包ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.AddPackageItemCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := h.productAppService.AddPackageItem(c.Request.Context(), packageID, &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("添加组合包子产品失败", zap.Error(err), zap.String("package_id", packageID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "添加组合包子产品成功")
|
||||
}
|
||||
|
||||
// UpdatePackageItem 更新组合包子产品
|
||||
// @Summary 更新组合包子产品
|
||||
// @Description 管理员更新组合包子产品信息
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "组合包ID"
|
||||
// @Param item_id path string true "子产品项目ID"
|
||||
// @Param command body commands.UpdatePackageItemCommand true "更新子产品命令"
|
||||
// @Success 200 {object} map[string]interface{} "更新成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/package-items/{item_id} [put]
|
||||
func (h *ProductAdminHandler) UpdatePackageItem(c *gin.Context) {
|
||||
packageID := c.Param("id")
|
||||
itemID := c.Param("item_id")
|
||||
if packageID == "" || itemID == "" {
|
||||
h.responseBuilder.BadRequest(c, "参数不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.UpdatePackageItemCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := h.productAppService.UpdatePackageItem(c.Request.Context(), packageID, itemID, &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("更新组合包子产品失败", zap.Error(err), zap.String("package_id", packageID), zap.String("item_id", itemID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "更新组合包子产品成功")
|
||||
}
|
||||
|
||||
// RemovePackageItem 移除组合包子产品
|
||||
// @Summary 移除组合包子产品
|
||||
// @Description 管理员从组合包移除子产品
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "组合包ID"
|
||||
// @Param item_id path string true "子产品项目ID"
|
||||
// @Success 200 {object} map[string]interface{} "移除成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/package-items/{item_id} [delete]
|
||||
func (h *ProductAdminHandler) RemovePackageItem(c *gin.Context) {
|
||||
packageID := c.Param("id")
|
||||
itemID := c.Param("item_id")
|
||||
if packageID == "" || itemID == "" {
|
||||
h.responseBuilder.BadRequest(c, "参数不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
err := h.productAppService.RemovePackageItem(c.Request.Context(), packageID, itemID)
|
||||
if err != nil {
|
||||
h.logger.Error("移除组合包子产品失败", zap.Error(err), zap.String("package_id", packageID), zap.String("item_id", itemID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "移除组合包子产品成功")
|
||||
}
|
||||
|
||||
// ReorderPackageItems 重新排序组合包子产品
|
||||
// @Summary 重新排序组合包子产品
|
||||
// @Description 管理员重新排序组合包子产品
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "组合包ID"
|
||||
// @Param command body commands.ReorderPackageItemsCommand true "重新排序命令"
|
||||
// @Success 200 {object} map[string]interface{} "排序成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/package-items/reorder [put]
|
||||
func (h *ProductAdminHandler) ReorderPackageItems(c *gin.Context) {
|
||||
packageID := c.Param("id")
|
||||
if packageID == "" {
|
||||
h.responseBuilder.BadRequest(c, "组合包ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.ReorderPackageItemsCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := h.productAppService.ReorderPackageItems(c.Request.Context(), packageID, &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("重新排序组合包子产品失败", zap.Error(err), zap.String("package_id", packageID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "重新排序组合包子产品成功")
|
||||
}
|
||||
|
||||
// UpdatePackageItems 批量更新组合包子产品
|
||||
// @Summary 批量更新组合包子产品
|
||||
// @Description 管理员批量更新组合包子产品配置
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "组合包ID"
|
||||
// @Param command body commands.UpdatePackageItemsCommand true "批量更新命令"
|
||||
// @Success 200 {object} map[string]interface{} "更新成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/package-items/batch [put]
|
||||
func (h *ProductAdminHandler) UpdatePackageItems(c *gin.Context) {
|
||||
packageID := c.Param("id")
|
||||
if packageID == "" {
|
||||
h.responseBuilder.BadRequest(c, "组合包ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var cmd commands.UpdatePackageItemsCommand
|
||||
if err := h.validator.BindAndValidate(c, &cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err := h.productAppService.UpdatePackageItems(c.Request.Context(), packageID, &cmd)
|
||||
if err != nil {
|
||||
h.logger.Error("批量更新组合包子产品失败", zap.Error(err), zap.String("package_id", packageID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "批量更新组合包子产品成功")
|
||||
}
|
||||
|
||||
// ListCategories 获取分类列表(管理员)
|
||||
// @Summary 获取分类列表
|
||||
// @Description 管理员获取产品分类列表
|
||||
@@ -467,3 +754,166 @@ func (h *ProductAdminHandler) GetSubscriptionStats(c *gin.Context) {
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取订阅统计成功")
|
||||
}
|
||||
|
||||
// GetProductApiConfig 获取产品API配置
|
||||
// @Summary 获取产品API配置
|
||||
// @Description 管理员获取产品的API配置信息,如果不存在则返回空配置
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "产品ID"
|
||||
// @Success 200 {object} responses.ProductApiConfigResponse "获取API配置成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/api-config [get]
|
||||
func (h *ProductAdminHandler) GetProductApiConfig(c *gin.Context) {
|
||||
productID := c.Param("id")
|
||||
if productID == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.productAppService.GetProductApiConfig(c.Request.Context(), productID)
|
||||
if err != nil {
|
||||
// 如果是配置不存在的错误,返回空配置而不是错误
|
||||
if err.Error() == "record not found" || err.Error() == "产品API配置不存在" {
|
||||
// 返回空的配置结构,让前端可以创建新配置
|
||||
emptyConfig := &responses.ProductApiConfigResponse{
|
||||
ID: "",
|
||||
ProductID: productID,
|
||||
RequestParams: []responses.RequestParamResponse{},
|
||||
ResponseFields: []responses.ResponseFieldResponse{},
|
||||
ResponseExample: map[string]interface{}{},
|
||||
}
|
||||
h.responseBuilder.Success(c, emptyConfig, "获取API配置成功")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Error("获取产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||||
h.responseBuilder.NotFound(c, "产品不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, result, "获取API配置成功")
|
||||
}
|
||||
|
||||
// CreateProductApiConfig 创建产品API配置
|
||||
// @Summary 创建产品API配置
|
||||
// @Description 管理员为产品创建API配置
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "产品ID"
|
||||
// @Param request body responses.ProductApiConfigResponse true "API配置信息"
|
||||
// @Success 201 {object} map[string]interface{} "API配置创建成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 409 {object} map[string]interface{} "API配置已存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/api-config [post]
|
||||
func (h *ProductAdminHandler) CreateProductApiConfig(c *gin.Context) {
|
||||
productID := c.Param("id")
|
||||
if productID == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var configResponse responses.ProductApiConfigResponse
|
||||
if err := h.validator.BindAndValidate(c, &configResponse); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.productAppService.CreateProductApiConfig(c.Request.Context(), productID, &configResponse); err != nil {
|
||||
h.logger.Error("创建产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Created(c, nil, "API配置创建成功")
|
||||
}
|
||||
|
||||
// UpdateProductApiConfig 更新产品API配置
|
||||
// @Summary 更新产品API配置
|
||||
// @Description 管理员更新产品的API配置
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "产品ID"
|
||||
// @Param request body responses.ProductApiConfigResponse true "API配置信息"
|
||||
// @Success 200 {object} map[string]interface{} "API配置更新成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品或配置不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/api-config [put]
|
||||
func (h *ProductAdminHandler) UpdateProductApiConfig(c *gin.Context) {
|
||||
productID := c.Param("id")
|
||||
if productID == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
var configResponse responses.ProductApiConfigResponse
|
||||
if err := h.validator.BindAndValidate(c, &configResponse); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 先获取现有配置以获取配置ID
|
||||
existingConfig, err := h.productAppService.GetProductApiConfig(c.Request.Context(), productID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取现有API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||||
h.responseBuilder.NotFound(c, "产品API配置不存在")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.productAppService.UpdateProductApiConfig(c.Request.Context(), existingConfig.ID, &configResponse); err != nil {
|
||||
h.logger.Error("更新产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "API配置更新成功")
|
||||
}
|
||||
|
||||
// DeleteProductApiConfig 删除产品API配置
|
||||
// @Summary 删除产品API配置
|
||||
// @Description 管理员删除产品的API配置
|
||||
// @Tags 产品管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param id path string true "产品ID"
|
||||
// @Success 200 {object} map[string]interface{} "API配置删除成功"
|
||||
// @Failure 400 {object} map[string]interface{} "请求参数错误"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 404 {object} map[string]interface{} "产品或配置不存在"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/admin/products/{id}/api-config [delete]
|
||||
func (h *ProductAdminHandler) DeleteProductApiConfig(c *gin.Context) {
|
||||
productID := c.Param("id")
|
||||
if productID == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 先获取现有配置以获取配置ID
|
||||
existingConfig, err := h.productAppService.GetProductApiConfig(c.Request.Context(), productID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取现有API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||||
h.responseBuilder.NotFound(c, "产品API配置不存在")
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.productAppService.DeleteProductApiConfig(c.Request.Context(), existingConfig.ID); err != nil {
|
||||
h.logger.Error("删除产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||||
h.responseBuilder.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, nil, "API配置删除成功")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"tyapi-server/internal/application/product"
|
||||
"tyapi-server/internal/application/product/dto/commands"
|
||||
"tyapi-server/internal/application/product/dto/queries"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
// ProductHandler 产品相关HTTP处理器
|
||||
type ProductHandler struct {
|
||||
appService product.ProductApplicationService
|
||||
apiConfigService product.ProductApiConfigApplicationService
|
||||
categoryService product.CategoryApplicationService
|
||||
subAppService product.SubscriptionApplicationService
|
||||
responseBuilder interfaces.ResponseBuilder
|
||||
@@ -23,6 +25,7 @@ type ProductHandler struct {
|
||||
// NewProductHandler 创建产品HTTP处理器
|
||||
func NewProductHandler(
|
||||
appService product.ProductApplicationService,
|
||||
apiConfigService product.ProductApiConfigApplicationService,
|
||||
categoryService product.CategoryApplicationService,
|
||||
subAppService product.SubscriptionApplicationService,
|
||||
responseBuilder interfaces.ResponseBuilder,
|
||||
@@ -31,6 +34,7 @@ func NewProductHandler(
|
||||
) *ProductHandler {
|
||||
return &ProductHandler{
|
||||
appService: appService,
|
||||
apiConfigService: apiConfigService,
|
||||
categoryService: categoryService,
|
||||
subAppService: subAppService,
|
||||
responseBuilder: responseBuilder,
|
||||
@@ -49,8 +53,6 @@ func NewProductHandler(
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param keyword query string false "搜索关键词"
|
||||
// @Param category_id query string false "分类ID"
|
||||
// @Param min_price query number false "最低价格"
|
||||
// @Param max_price query number false "最高价格"
|
||||
// @Param is_enabled query bool false "是否启用"
|
||||
// @Param is_visible query bool false "是否可见"
|
||||
// @Param is_package query bool false "是否组合包"
|
||||
@@ -61,23 +63,65 @@ func NewProductHandler(
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/products [get]
|
||||
func (h *ProductHandler) ListProducts(c *gin.Context) {
|
||||
var query queries.ListProductsQuery
|
||||
if err := h.validator.ValidateQuery(c, &query); err != nil {
|
||||
return
|
||||
// 解析查询参数
|
||||
page := h.getIntQuery(c, "page", 1)
|
||||
pageSize := h.getIntQuery(c, "page_size", 10)
|
||||
|
||||
// 构建筛选条件
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
// 搜索关键词筛选
|
||||
if keyword := c.Query("keyword"); keyword != "" {
|
||||
filters["keyword"] = keyword
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if query.Page <= 0 {
|
||||
query.Page = 1
|
||||
}
|
||||
if query.PageSize <= 0 {
|
||||
query.PageSize = 10
|
||||
}
|
||||
if query.PageSize > 100 {
|
||||
query.PageSize = 100
|
||||
// 分类ID筛选
|
||||
if categoryID := c.Query("category_id"); categoryID != "" {
|
||||
filters["category_id"] = categoryID
|
||||
}
|
||||
|
||||
result, err := h.appService.ListProducts(c.Request.Context(), &query)
|
||||
// 启用状态筛选
|
||||
if isEnabled := c.Query("is_enabled"); isEnabled != "" {
|
||||
if enabled, err := strconv.ParseBool(isEnabled); err == nil {
|
||||
filters["is_enabled"] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// 可见状态筛选
|
||||
if isVisible := c.Query("is_visible"); isVisible != "" {
|
||||
if visible, err := strconv.ParseBool(isVisible); err == nil {
|
||||
filters["is_visible"] = visible
|
||||
}
|
||||
}
|
||||
|
||||
// 产品类型筛选
|
||||
if isPackage := c.Query("is_package"); isPackage != "" {
|
||||
if pkg, err := strconv.ParseBool(isPackage); err == nil {
|
||||
filters["is_package"] = pkg
|
||||
}
|
||||
}
|
||||
|
||||
// 排序字段
|
||||
sortBy := c.Query("sort_by")
|
||||
if sortBy == "" {
|
||||
sortBy = "created_at"
|
||||
}
|
||||
|
||||
// 排序方向
|
||||
sortOrder := c.Query("sort_order")
|
||||
if sortOrder == "" {
|
||||
sortOrder = "desc"
|
||||
}
|
||||
|
||||
// 构建分页选项
|
||||
options := interfaces.ListOptions{
|
||||
Page: page,
|
||||
PageSize: pageSize,
|
||||
Sort: sortBy,
|
||||
Order: sortOrder,
|
||||
}
|
||||
|
||||
result, err := h.appService.ListProducts(c.Request.Context(), filters, options)
|
||||
if err != nil {
|
||||
h.logger.Error("获取产品列表失败", zap.Error(err))
|
||||
h.responseBuilder.InternalError(c, "获取产品列表失败")
|
||||
@@ -87,6 +131,16 @@ func (h *ProductHandler) ListProducts(c *gin.Context) {
|
||||
h.responseBuilder.Success(c, result, "获取产品列表成功")
|
||||
}
|
||||
|
||||
// getIntQuery 获取整数查询参数
|
||||
func (h *ProductHandler) getIntQuery(c *gin.Context, key string, defaultValue int) int {
|
||||
if value := c.Query(key); value != "" {
|
||||
if intValue, err := strconv.Atoi(value); err == nil && intValue > 0 {
|
||||
return intValue
|
||||
}
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// GetProductDetail 获取产品详情
|
||||
// @Summary 获取产品详情
|
||||
// @Description 根据产品ID获取产品详细信息
|
||||
@@ -176,6 +230,62 @@ func (h *ProductHandler) GetProductStats(c *gin.Context) {
|
||||
h.responseBuilder.Success(c, result, "获取产品统计成功")
|
||||
}
|
||||
|
||||
// GetProductApiConfig 获取产品API配置
|
||||
// @Summary 获取产品API配置
|
||||
// @Description 根据产品ID获取API配置信息
|
||||
// @Tags 产品API配置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "产品ID"
|
||||
// @Success 200 {object} responses.ProductApiConfigResponse "获取成功"
|
||||
// @Failure 400 {object} interfaces.APIResponse "请求参数错误"
|
||||
// @Failure 404 {object} interfaces.APIResponse "配置不存在"
|
||||
// @Router /api/v1/products/{id}/api-config [get]
|
||||
func (h *ProductHandler) GetProductApiConfig(c *gin.Context) {
|
||||
productID := c.Param("id")
|
||||
if productID == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品ID不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.apiConfigService.GetProductApiConfig(c.Request.Context(), productID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取产品API配置失败", zap.Error(err), zap.String("product_id", productID))
|
||||
h.responseBuilder.NotFound(c, "产品API配置不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, config, "获取产品API配置成功")
|
||||
}
|
||||
|
||||
// GetProductApiConfigByCode 根据产品代码获取API配置
|
||||
// @Summary 根据产品代码获取API配置
|
||||
// @Description 根据产品代码获取API配置信息
|
||||
// @Tags 产品API配置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param product_code path string true "产品代码"
|
||||
// @Success 200 {object} responses.ProductApiConfigResponse "获取成功"
|
||||
// @Failure 400 {object} interfaces.APIResponse "请求参数错误"
|
||||
// @Failure 404 {object} interfaces.APIResponse "配置不存在"
|
||||
// @Router /api/v1/products/code/{product_code}/api-config [get]
|
||||
func (h *ProductHandler) GetProductApiConfigByCode(c *gin.Context) {
|
||||
productCode := c.Param("product_code")
|
||||
if productCode == "" {
|
||||
h.responseBuilder.BadRequest(c, "产品代码不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
config, err := h.apiConfigService.GetProductApiConfigByCode(c.Request.Context(), productCode)
|
||||
if err != nil {
|
||||
h.logger.Error("根据产品代码获取API配置失败", zap.Error(err), zap.String("product_code", productCode))
|
||||
h.responseBuilder.NotFound(c, "产品API配置不存在")
|
||||
return
|
||||
}
|
||||
|
||||
h.responseBuilder.Success(c, config, "获取产品API配置成功")
|
||||
}
|
||||
|
||||
// ================ 分类相关方法 ================
|
||||
|
||||
// ListCategories 获取分类列表
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"tyapi-server/internal/application/user"
|
||||
"tyapi-server/internal/application/user/dto/commands"
|
||||
"tyapi-server/internal/application/user/dto/queries"
|
||||
"tyapi-server/internal/shared/interfaces"
|
||||
"tyapi-server/internal/shared/middleware"
|
||||
)
|
||||
@@ -240,6 +243,109 @@ func (h *UserHandler) ResetPassword(c *gin.Context) {
|
||||
h.response.Success(c, nil, "密码重置成功")
|
||||
}
|
||||
|
||||
// ListUsers 管理员查看用户列表
|
||||
// @Summary 管理员查看用户列表
|
||||
// @Description 管理员查看用户列表,支持分页和筛选
|
||||
// @Tags 用户管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Param page query int false "页码" default(1)
|
||||
// @Param page_size query int false "每页数量" default(10)
|
||||
// @Param phone query string false "手机号筛选"
|
||||
// @Param user_type query string false "用户类型筛选" Enums(user,admin)
|
||||
// @Param is_active query bool false "是否激活筛选"
|
||||
// @Param is_certified query bool false "是否已认证筛选"
|
||||
// @Param company_name query string false "企业名称筛选"
|
||||
// @Param start_date query string false "开始日期" format(date)
|
||||
// @Param end_date query string false "结束日期" format(date)
|
||||
// @Success 200 {object} responses.UserListResponse "用户列表"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 403 {object} map[string]interface{} "权限不足"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/users/admin/list [get]
|
||||
func (h *UserHandler) ListUsers(c *gin.Context) {
|
||||
// 检查管理员权限
|
||||
userID := h.getCurrentUserID(c)
|
||||
if userID == "" {
|
||||
h.response.Unauthorized(c, "用户未登录")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 构建查询参数
|
||||
query := &queries.ListUsersQuery{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
}
|
||||
|
||||
// 从查询参数中获取筛选条件
|
||||
if page := c.Query("page"); page != "" {
|
||||
if pageNum, err := strconv.Atoi(page); err == nil && pageNum > 0 {
|
||||
query.Page = pageNum
|
||||
}
|
||||
}
|
||||
|
||||
if pageSize := c.Query("page_size"); pageSize != "" {
|
||||
if size, err := strconv.Atoi(pageSize); err == nil && size > 0 && size <= 100 {
|
||||
query.PageSize = size
|
||||
}
|
||||
}
|
||||
|
||||
query.Phone = c.Query("phone")
|
||||
query.UserType = c.Query("user_type")
|
||||
query.CompanyName = c.Query("company_name")
|
||||
query.StartDate = c.Query("start_date")
|
||||
query.EndDate = c.Query("end_date")
|
||||
|
||||
// 处理布尔值参数
|
||||
if isActive := c.Query("is_active"); isActive != "" {
|
||||
if active, err := strconv.ParseBool(isActive); err == nil {
|
||||
query.IsActive = &active
|
||||
}
|
||||
}
|
||||
|
||||
if isCertified := c.Query("is_certified"); isCertified != "" {
|
||||
if certified, err := strconv.ParseBool(isCertified); err == nil {
|
||||
query.IsCertified = &certified
|
||||
}
|
||||
}
|
||||
|
||||
// 调用应用服务
|
||||
resp, err := h.appService.ListUsers(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户列表失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "获取用户列表失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, resp, "获取用户列表成功")
|
||||
}
|
||||
|
||||
// GetUserStats 管理员获取用户统计信息
|
||||
// @Summary 管理员获取用户统计信息
|
||||
// @Description 管理员获取用户统计信息,包括总用户数、活跃用户数、已认证用户数
|
||||
// @Tags 用户管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security Bearer
|
||||
// @Success 200 {object} responses.UserStatsResponse "用户统计信息"
|
||||
// @Failure 401 {object} map[string]interface{} "未认证"
|
||||
// @Failure 403 {object} map[string]interface{} "权限不足"
|
||||
// @Failure 500 {object} map[string]interface{} "服务器内部错误"
|
||||
// @Router /api/v1/users/admin/stats [get]
|
||||
func (h *UserHandler) GetUserStats(c *gin.Context) {
|
||||
// 调用应用服务
|
||||
resp, err := h.appService.GetUserStats(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("获取用户统计信息失败", zap.Error(err))
|
||||
h.response.BadRequest(c, "获取用户统计信息失败")
|
||||
return
|
||||
}
|
||||
|
||||
h.response.Success(c, resp, "获取用户统计信息成功")
|
||||
}
|
||||
|
||||
// getCurrentUserID 获取当前用户ID
|
||||
func (h *UserHandler) getCurrentUserID(c *gin.Context) string {
|
||||
if userID, exists := c.Get("user_id"); exists {
|
||||
|
||||
59
internal/infrastructure/http/routes/api_routes.go
Normal file
59
internal/infrastructure/http/routes/api_routes.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"tyapi-server/internal/infrastructure/http/handlers"
|
||||
sharedhttp "tyapi-server/internal/shared/http"
|
||||
"tyapi-server/internal/shared/middleware"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// ApiRoutes API路由注册器
|
||||
type ApiRoutes struct {
|
||||
apiHandler *handlers.ApiHandler
|
||||
authMiddleware *middleware.JWTAuthMiddleware
|
||||
domainAuthMiddleware *middleware.DomainAuthMiddleware
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewApiRoutes 创建API路由注册器
|
||||
func NewApiRoutes(
|
||||
apiHandler *handlers.ApiHandler,
|
||||
authMiddleware *middleware.JWTAuthMiddleware,
|
||||
domainAuthMiddleware *middleware.DomainAuthMiddleware,
|
||||
logger *zap.Logger,
|
||||
) *ApiRoutes {
|
||||
return &ApiRoutes{
|
||||
apiHandler: apiHandler,
|
||||
authMiddleware: authMiddleware,
|
||||
domainAuthMiddleware: domainAuthMiddleware,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Register 注册相关路由
|
||||
func (r *ApiRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// API路由组,需要用户认证
|
||||
engine := router.GetEngine()
|
||||
apiGroup := engine.Group("/api/v1")
|
||||
|
||||
{
|
||||
apiGroup.POST("/:api_name", r.domainAuthMiddleware.Handle(""), r.apiHandler.HandleApiCall)
|
||||
|
||||
// 加密接口(用于前端调试)
|
||||
apiGroup.POST("/encrypt", r.authMiddleware.Handle(), r.apiHandler.EncryptParams)
|
||||
|
||||
// API密钥管理接口
|
||||
apiGroup.GET("/api-keys", r.authMiddleware.Handle(), r.apiHandler.GetUserApiKeys)
|
||||
|
||||
// 白名单管理接口
|
||||
apiGroup.GET("/white-list", r.authMiddleware.Handle(), r.apiHandler.GetUserWhiteList)
|
||||
apiGroup.POST("/white-list", r.authMiddleware.Handle(), r.apiHandler.AddWhiteListIP)
|
||||
apiGroup.DELETE("/white-list/:ip", r.authMiddleware.Handle(), r.apiHandler.DeleteWhiteListIP)
|
||||
|
||||
// API调用记录接口
|
||||
apiGroup.GET("/my/api-calls", r.authMiddleware.Handle(), r.apiHandler.GetUserApiCalls)
|
||||
}
|
||||
|
||||
r.logger.Info("API路由注册完成")
|
||||
}
|
||||
@@ -43,31 +43,29 @@ func (r *CertificationRoutes) Register(router *http.GinRouter) {
|
||||
authGroup := certificationGroup.Group("")
|
||||
authGroup.Use(r.auth.Handle())
|
||||
{
|
||||
authGroup.GET("/user", r.handler.GetUserCertifications) // 获取用户认证列表
|
||||
authGroup.GET("", r.handler.ListCertifications) // 查询认证列表(管理员)
|
||||
authGroup.GET("/statistics", r.handler.GetCertificationStatistics) // 获取认证统计
|
||||
authGroup.GET("", r.handler.ListCertifications) // 查询认证列表(管理员)
|
||||
|
||||
// 1. 获取认证详情
|
||||
authGroup.GET("/:id", r.handler.GetCertification)
|
||||
authGroup.GET("/details", r.handler.GetCertification)
|
||||
|
||||
// 2. 提交企业信息
|
||||
authGroup.POST("/:id/enterprise-info", r.handler.SubmitEnterpriseInfo)
|
||||
authGroup.POST("/enterprise-info", r.handler.SubmitEnterpriseInfo)
|
||||
|
||||
// 合同管理
|
||||
authGroup.POST("/apply-contract", r.handler.ApplyContract) // 申请合同签署
|
||||
// 3. 申请合同签署
|
||||
authGroup.POST("/apply-contract", r.handler.ApplyContract)
|
||||
|
||||
// 重试操作
|
||||
authGroup.POST("/retry", r.handler.RetryOperation) // 重试操作
|
||||
// 前端确认是否完成认证
|
||||
authGroup.POST("/confirm-auth", r.handler.ConfirmAuth)
|
||||
|
||||
// 前端确认是否完成签署
|
||||
authGroup.POST("/confirm-sign", r.handler.ConfirmSign)
|
||||
|
||||
// 管理员操作
|
||||
authGroup.POST("/force-transition", r.handler.ForceTransitionStatus) // 强制状态转换
|
||||
authGroup.GET("/monitoring", r.handler.GetSystemMonitoring) // 获取系统监控数据
|
||||
}
|
||||
|
||||
// 回调路由(不需要认证,但需要验证签名)
|
||||
callbackGroup := certificationGroup.Group("/callbacks")
|
||||
{
|
||||
callbackGroup.POST("", r.handler.HandleEsignCallback) // e签宝回调(统一处理企业认证和合同签署回调)
|
||||
callbackGroup.POST("/esign", r.handler.HandleEsignCallback) // e签宝回调(统一处理企业认证和合同签署回调)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +85,7 @@ func (r *CertificationRoutes) GetRoutes() []RouteInfo {
|
||||
{Method: "POST", Path: "/api/v1/certifications/retry", Handler: "RetryOperation", Auth: true},
|
||||
{Method: "POST", Path: "/api/v1/certifications/force-transition", Handler: "ForceTransitionStatus", Auth: true},
|
||||
{Method: "GET", Path: "/api/v1/certifications/monitoring", Handler: "GetSystemMonitoring", Auth: true},
|
||||
{Method: "POST", Path: "/api/v1/certifications/callbacks", Handler: "HandleEsignCallback", Auth: false},
|
||||
{Method: "POST", Path: "/api/v1/certifications/callbacks/esign", Handler: "HandleEsignCallback", Auth: false},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,51 +10,61 @@ import (
|
||||
|
||||
// FinanceRoutes 财务路由注册器
|
||||
type FinanceRoutes struct {
|
||||
financeHandler *handlers.FinanceHandler
|
||||
authMiddleware *middleware.JWTAuthMiddleware
|
||||
logger *zap.Logger
|
||||
financeHandler *handlers.FinanceHandler
|
||||
authMiddleware *middleware.JWTAuthMiddleware
|
||||
adminAuthMiddleware *middleware.AdminAuthMiddleware
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewFinanceRoutes 创建财务路由注册器
|
||||
func NewFinanceRoutes(
|
||||
financeHandler *handlers.FinanceHandler,
|
||||
authMiddleware *middleware.JWTAuthMiddleware,
|
||||
adminAuthMiddleware *middleware.AdminAuthMiddleware,
|
||||
logger *zap.Logger,
|
||||
) *FinanceRoutes {
|
||||
return &FinanceRoutes{
|
||||
financeHandler: financeHandler,
|
||||
authMiddleware: authMiddleware,
|
||||
logger: logger,
|
||||
financeHandler: financeHandler,
|
||||
authMiddleware: authMiddleware,
|
||||
adminAuthMiddleware: adminAuthMiddleware,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Register 注册财务相关路由
|
||||
func (r *FinanceRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// 财务路由组,需要用户认证
|
||||
engine := router.GetEngine()
|
||||
|
||||
// 支付宝回调路由(不需要认证)
|
||||
alipayGroup := engine.Group("/api/v1/finance/alipay")
|
||||
{
|
||||
alipayGroup.POST("/callback", r.financeHandler.HandleAlipayCallback) // 支付宝异步回调
|
||||
alipayGroup.GET("/return", r.financeHandler.HandleAlipayReturn) // 支付宝同步回调
|
||||
}
|
||||
|
||||
// 财务路由组,需要用户认证
|
||||
financeGroup := engine.Group("/api/v1/finance")
|
||||
financeGroup.Use(r.authMiddleware.Handle())
|
||||
{
|
||||
// 钱包相关路由
|
||||
walletGroup := financeGroup.Group("/wallet")
|
||||
{
|
||||
walletGroup.POST("", r.financeHandler.CreateWallet) // 创建钱包
|
||||
walletGroup.GET("", r.financeHandler.GetWallet) // 获取钱包信息
|
||||
walletGroup.PUT("", r.financeHandler.UpdateWallet) // 更新钱包
|
||||
walletGroup.POST("/recharge", r.financeHandler.Recharge) // 充值
|
||||
walletGroup.POST("/withdraw", r.financeHandler.Withdraw) // 提现
|
||||
walletGroup.POST("/transaction", r.financeHandler.WalletTransaction) // 钱包交易
|
||||
walletGroup.GET("/stats", r.financeHandler.GetWalletStats) // 获取钱包统计
|
||||
walletGroup.GET("", r.financeHandler.GetWallet) // 获取钱包信息
|
||||
walletGroup.GET("/transactions", r.financeHandler.GetUserWalletTransactions) // 获取钱包交易记录
|
||||
walletGroup.GET("/recharge-config", r.financeHandler.GetRechargeConfig) // 获取充值配置
|
||||
walletGroup.POST("/alipay-recharge", r.financeHandler.CreateAlipayRecharge) // 创建支付宝充值订单
|
||||
walletGroup.GET("/recharge-records", r.financeHandler.GetUserRechargeRecords) // 用户充值记录分页
|
||||
walletGroup.GET("/alipay-order-status", r.financeHandler.GetAlipayOrderStatus) // 获取支付宝订单状态
|
||||
}
|
||||
}
|
||||
|
||||
// 用户密钥相关路由
|
||||
secretsGroup := financeGroup.Group("/secrets")
|
||||
{
|
||||
secretsGroup.POST("", r.financeHandler.CreateUserSecrets) // 创建用户密钥
|
||||
secretsGroup.GET("", r.financeHandler.GetUserSecrets) // 获取用户密钥
|
||||
secretsGroup.POST("/regenerate", r.financeHandler.RegenerateAccessKey) // 重新生成访问密钥
|
||||
secretsGroup.POST("/deactivate", r.financeHandler.DeactivateUserSecrets) // 停用用户密钥
|
||||
}
|
||||
// 管理员财务路由组
|
||||
adminFinanceGroup := engine.Group("/api/v1/admin/finance")
|
||||
adminFinanceGroup.Use(r.adminAuthMiddleware.Handle())
|
||||
{
|
||||
adminFinanceGroup.POST("/transfer-recharge", r.financeHandler.TransferRecharge) // 对公转账充值
|
||||
adminFinanceGroup.POST("/gift-recharge", r.financeHandler.GiftRecharge) // 赠送充值
|
||||
adminFinanceGroup.GET("/recharge-records", r.financeHandler.GetAdminRechargeRecords) // 管理员充值记录分页
|
||||
}
|
||||
|
||||
r.logger.Info("财务路由注册完成")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package routes
|
||||
|
||||
|
||||
import (
|
||||
"tyapi-server/internal/infrastructure/http/handlers"
|
||||
sharedhttp "tyapi-server/internal/shared/http"
|
||||
@@ -31,19 +31,33 @@ func (r *ProductAdminRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// 管理员路由组
|
||||
engine := router.GetEngine()
|
||||
adminGroup := engine.Group("/api/v1/admin")
|
||||
adminGroup.Use(r.auth.Handle()) // JWT认证
|
||||
adminGroup.Use(r.auth.Handle()) // JWT认证
|
||||
adminGroup.Use(r.admin.Handle()) // 管理员权限验证
|
||||
{
|
||||
// 产品管理
|
||||
products := adminGroup.Group("/products")
|
||||
{
|
||||
products.GET("", r.handler.ListProducts)
|
||||
products.GET("/available", r.handler.GetAvailableProducts)
|
||||
products.GET("/:id", r.handler.GetProductDetail)
|
||||
products.POST("", r.handler.CreateProduct)
|
||||
products.PUT("/:id", r.handler.UpdateProduct)
|
||||
products.DELETE("/:id", r.handler.DeleteProduct)
|
||||
|
||||
// 组合包管理
|
||||
products.POST("/:id/package-items", r.handler.AddPackageItem)
|
||||
products.PUT("/:id/package-items/:item_id", r.handler.UpdatePackageItem)
|
||||
products.DELETE("/:id/package-items/:item_id", r.handler.RemovePackageItem)
|
||||
products.PUT("/:id/package-items/reorder", r.handler.ReorderPackageItems)
|
||||
products.PUT("/:id/package-items/batch", r.handler.UpdatePackageItems)
|
||||
|
||||
// API配置管理
|
||||
products.GET("/:id/api-config", r.handler.GetProductApiConfig)
|
||||
products.POST("/:id/api-config", r.handler.CreateProductApiConfig)
|
||||
products.PUT("/:id/api-config", r.handler.UpdateProductApiConfig)
|
||||
products.DELETE("/:id/api-config", r.handler.DeleteProductApiConfig)
|
||||
}
|
||||
|
||||
|
||||
// 分类管理
|
||||
categories := adminGroup.Group("/product-categories")
|
||||
{
|
||||
@@ -53,7 +67,7 @@ func (r *ProductAdminRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
categories.PUT("/:id", r.handler.UpdateCategory)
|
||||
categories.DELETE("/:id", r.handler.DeleteCategory)
|
||||
}
|
||||
|
||||
|
||||
// 订阅管理
|
||||
subscriptions := adminGroup.Group("/subscriptions")
|
||||
{
|
||||
@@ -62,4 +76,4 @@ func (r *ProductAdminRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
subscriptions.PUT("/:id/price", r.handler.UpdateSubscriptionPrice)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,12 +38,16 @@ func (r *ProductRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
// 获取产品列表(分页+筛选)
|
||||
products.GET("", r.productHandler.ListProducts)
|
||||
|
||||
// 获取产品详情
|
||||
products.GET("/:id", r.productHandler.GetProductDetail)
|
||||
|
||||
// 获取产品统计
|
||||
products.GET("/stats", r.productHandler.GetProductStats)
|
||||
|
||||
// 根据产品代码获取API配置
|
||||
products.GET("/code/:product_code/api-config", r.productHandler.GetProductApiConfigByCode)
|
||||
|
||||
// 产品详情和API配置 - 使用具体路径避免冲突
|
||||
products.GET("/:id", r.productHandler.GetProductDetail)
|
||||
products.GET("/:id/api-config", r.productHandler.GetProductApiConfig)
|
||||
|
||||
// 订阅产品(需要认证)
|
||||
products.POST("/:id/subscribe", r.auth.Handle(), r.productHandler.SubscribeProduct)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
type UserRoutes struct {
|
||||
handler *handlers.UserHandler
|
||||
authMiddleware *middleware.JWTAuthMiddleware
|
||||
adminAuthMiddleware *middleware.AdminAuthMiddleware
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
@@ -19,11 +20,13 @@ type UserRoutes struct {
|
||||
func NewUserRoutes(
|
||||
handler *handlers.UserHandler,
|
||||
authMiddleware *middleware.JWTAuthMiddleware,
|
||||
adminAuthMiddleware *middleware.AdminAuthMiddleware,
|
||||
logger *zap.Logger,
|
||||
) *UserRoutes {
|
||||
return &UserRoutes{
|
||||
handler: handler,
|
||||
authMiddleware: authMiddleware,
|
||||
adminAuthMiddleware: adminAuthMiddleware,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
@@ -48,6 +51,14 @@ func (r *UserRoutes) Register(router *sharedhttp.GinRouter) {
|
||||
authenticated.GET("/me", r.handler.GetProfile) // 获取当前用户信息
|
||||
authenticated.PUT("/me/password", r.handler.ChangePassword) // 修改密码
|
||||
}
|
||||
|
||||
// 管理员路由
|
||||
adminGroup := usersGroup.Group("/admin")
|
||||
adminGroup.Use(r.adminAuthMiddleware.Handle())
|
||||
{
|
||||
adminGroup.GET("/list", r.handler.ListUsers) // 管理员查看用户列表
|
||||
adminGroup.GET("/stats", r.handler.GetUserStats) // 管理员获取用户统计信息
|
||||
}
|
||||
}
|
||||
|
||||
r.logger.Info("用户路由注册完成")
|
||||
|
||||
Reference in New Issue
Block a user