806 lines
20 KiB
Go
806 lines
20 KiB
Go
package frontend
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
"verification-platform-backend/internal/database"
|
|
"verification-platform-backend/internal/model"
|
|
"verification-platform-backend/internal/service"
|
|
"verification-platform-backend/internal/service/payment"
|
|
"verification-platform-backend/pkg/response"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func SetupRoutes(r *gin.Engine) {
|
|
auth := r.Group("/api/v1/auth")
|
|
{
|
|
auth.POST("/register", handleRegister)
|
|
auth.POST("/login", handleLogin)
|
|
auth.POST("/logout", handleLogout)
|
|
auth.POST("/refresh", handleRefreshToken)
|
|
}
|
|
|
|
api := r.Group("/api/v1")
|
|
{
|
|
api.POST("/login", handleLogin)
|
|
api.POST("/register", handleRegister)
|
|
api.POST("/logout", handleLogout)
|
|
api.POST("/refresh", handleRefreshToken)
|
|
api.POST("/forgot-password", handleForgotPassword)
|
|
api.POST("/reset-password", handleResetPassword)
|
|
api.POST("/send-sms", handleSendSms)
|
|
api.POST("/verify", handleCardVerification)
|
|
api.GET("/verify/status", handleGetVerificationStatus)
|
|
}
|
|
|
|
docs := r.Group("/api/v1/docs")
|
|
{
|
|
docs.GET("", handleGetDocs)
|
|
docs.GET("/:id", handleGetDoc)
|
|
docs.GET("/slug/:slug", handleGetDocBySlug)
|
|
}
|
|
|
|
docCategories := r.Group("/api/v1/doc-categories")
|
|
{
|
|
docCategories.GET("", handleGetDocCategories)
|
|
}
|
|
|
|
pricing := r.Group("/api/v1/pricing")
|
|
{
|
|
pricing.GET("", handleGetPricing)
|
|
}
|
|
|
|
packages := r.Group("/api/v1/packages")
|
|
{
|
|
packages.GET("", handleGetPricing)
|
|
}
|
|
|
|
site := r.Group("/api/v1/site")
|
|
{
|
|
site.GET("/info", handleGetSiteInfo)
|
|
site.GET("/contact", handleGetContact)
|
|
}
|
|
|
|
captcha := r.Group("/api/v1/captcha")
|
|
{
|
|
captcha.GET("", handleGetCaptcha)
|
|
}
|
|
|
|
settings := r.Group("/api/v1/settings")
|
|
{
|
|
settings.GET("", handleGetSettings)
|
|
settings.GET("/payment-channels", handleGetActivePaymentChannels)
|
|
}
|
|
|
|
public := r.Group("/api/v1/public")
|
|
{
|
|
public.GET("/stats", handleGetPublicStats)
|
|
}
|
|
}
|
|
|
|
func handleGetCaptcha(c *gin.Context) {
|
|
authService := service.NewAuthService()
|
|
result, err := authService.GetCaptcha()
|
|
if err != nil {
|
|
response.Error(c, 500, "获取验证码失败")
|
|
return
|
|
}
|
|
response.Success(c, result)
|
|
}
|
|
|
|
func handleGetSettings(c *gin.Context) {
|
|
settingService := service.NewSettingService()
|
|
settings, err := settingService.GetSettings()
|
|
if err != nil {
|
|
response.Error(c, 500, "获取设置失败")
|
|
return
|
|
}
|
|
response.Success(c, settings)
|
|
}
|
|
|
|
func handleGetActivePaymentChannels(c *gin.Context) {
|
|
var channels []model.PaymentChannel
|
|
if err := database.DB.Where("status = ?", "active").Order("sort asc, id asc").Find(&channels).Error; err != nil {
|
|
response.Error(c, 500, "获取支付通道失败")
|
|
return
|
|
}
|
|
response.Success(c, gin.H{"channels": channels})
|
|
}
|
|
|
|
func handleRegister(c *gin.Context) {
|
|
var req struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
Email string `json:"email"`
|
|
Phone string `json:"phone"`
|
|
Role string `json:"role"`
|
|
Type string `json:"type"`
|
|
Code string `json:"code"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
fmt.Printf("注册参数错误: %v\n", err)
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("注册请求: username=%s, email=%s, phone=%s, role=%s, type=%s\n",
|
|
req.Username, req.Email, req.Phone, req.Role, req.Type)
|
|
|
|
if req.Role == "" {
|
|
req.Role = "developer"
|
|
}
|
|
|
|
username := req.Username
|
|
email := req.Email
|
|
phone := req.Phone
|
|
password := req.Password
|
|
|
|
if req.Type == "email" {
|
|
username = email
|
|
email = req.Email
|
|
password = req.Password
|
|
} else if req.Type == "sms" {
|
|
username = phone
|
|
phone = req.Phone
|
|
password = req.Password
|
|
}
|
|
|
|
fmt.Printf("处理后的注册数据: username=%s, email=%s, phone=%s, password_len=%d, role=%s\n",
|
|
username, email, phone, len(password), req.Role)
|
|
|
|
authService := service.NewAuthService()
|
|
err := authService.RegisterWithRole(username, email, phone, password, req.Role)
|
|
if err != nil {
|
|
fmt.Printf("注册失败: %v\n", err)
|
|
response.Error(c, 400, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "注册成功",
|
|
})
|
|
}
|
|
|
|
func handleLogin(c *gin.Context) {
|
|
var req struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
AgentPath string `json:"agent_path"`
|
|
CaptchaID string `json:"captcha_id"`
|
|
Captcha string `json:"captcha"`
|
|
Type string `json:"type"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
fmt.Printf("登录参数错误: %v\n", err)
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
fmt.Printf("登录请求: username=%s, password_len=%d, agent_path=%s\n",
|
|
req.Username, len(req.Password), req.AgentPath)
|
|
|
|
// 检查是否启用了验证码
|
|
var enableCaptchaSetting model.Setting
|
|
err := database.DB.Where("category = ? AND key = ?", "basic", "enableCaptcha").First(&enableCaptchaSetting).Error
|
|
enableCaptcha := false
|
|
if err == nil && enableCaptchaSetting.Value == "true" {
|
|
enableCaptcha = true
|
|
}
|
|
|
|
// 如果启用了验证码,验证验证码
|
|
if enableCaptcha {
|
|
if req.CaptchaID == "" || req.Captcha == "" {
|
|
response.Error(c, 400, "请输入验证码")
|
|
return
|
|
}
|
|
|
|
// 查询验证码
|
|
var captcha model.Captcha
|
|
if err := database.DB.Where("captcha_id = ?", req.CaptchaID).First(&captcha).Error; err != nil {
|
|
response.Error(c, 400, "验证码错误或已过期")
|
|
return
|
|
}
|
|
|
|
// 检查验证码是否过期
|
|
if time.Now().After(captcha.ExpiresAt) {
|
|
database.DB.Delete(&captcha)
|
|
response.Error(c, 400, "验证码已过期")
|
|
return
|
|
}
|
|
|
|
// 验证码比较(忽略大小写和空格)
|
|
if strings.ToLower(strings.TrimSpace(req.Captcha)) != strings.ToLower(strings.TrimSpace(captcha.Code)) {
|
|
database.DB.Delete(&captcha)
|
|
response.Error(c, 400, "验证码错误")
|
|
return
|
|
}
|
|
|
|
// 删除已使用的验证码
|
|
database.DB.Delete(&captcha)
|
|
}
|
|
|
|
authService := service.NewAuthService()
|
|
result, err := authService.Login(req.Username, req.Password, req.AgentPath)
|
|
if err != nil {
|
|
fmt.Printf("登录失败: %v\n", err)
|
|
response.Error(c, 401, err.Error())
|
|
return
|
|
}
|
|
|
|
fmt.Printf("登录成功: username=%s\n", req.Username)
|
|
response.Success(c, result)
|
|
}
|
|
|
|
func handleLogout(c *gin.Context) {
|
|
response.Success(c, gin.H{
|
|
"message": "登出成功",
|
|
})
|
|
}
|
|
|
|
func handleRefreshToken(c *gin.Context) {
|
|
response.Success(c, gin.H{
|
|
"token": "",
|
|
})
|
|
}
|
|
|
|
func handleGetDocs(c *gin.Context) {
|
|
var docs []model.Doc
|
|
if err := database.DB.Where("status = ?", "published").Preload("Category").Find(&docs).Error; err != nil {
|
|
response.Error(c, 500, "获取文档列表失败")
|
|
return
|
|
}
|
|
response.Success(c, docs)
|
|
}
|
|
|
|
func handleGetDoc(c *gin.Context) {
|
|
id := c.Param("id")
|
|
var doc model.Doc
|
|
if err := database.DB.Where("id = ? AND status = ?", id, "published").Preload("Category").First(&doc).Error; err != nil {
|
|
response.Error(c, 404, "文档不存在")
|
|
return
|
|
}
|
|
response.Success(c, doc)
|
|
}
|
|
|
|
func handleGetDocBySlug(c *gin.Context) {
|
|
slug := c.Param("slug")
|
|
var doc model.Doc
|
|
if err := database.DB.Where("slug = ? AND status = ?", slug, "published").Preload("Category").First(&doc).Error; err != nil {
|
|
response.Error(c, 404, "文档不存在")
|
|
return
|
|
}
|
|
response.Success(c, doc)
|
|
}
|
|
|
|
func handleGetDocCategories(c *gin.Context) {
|
|
var categories []model.DocCategory
|
|
if err := database.DB.Find(&categories).Error; err != nil {
|
|
response.Error(c, 500, "获取文档分类失败")
|
|
return
|
|
}
|
|
response.Success(c, categories)
|
|
}
|
|
|
|
func handleGetPricing(c *gin.Context) {
|
|
var packages []model.Package
|
|
if err := database.DB.Where("status = ?", "active").Find(&packages).Error; err != nil {
|
|
response.Error(c, 500, "获取价格信息失败")
|
|
return
|
|
}
|
|
|
|
var result []gin.H
|
|
for _, pkg := range packages {
|
|
var permission model.PackagePermission
|
|
database.DB.Where("package_id = ?", pkg.ID).First(&permission)
|
|
|
|
result = append(result, gin.H{
|
|
"id": pkg.ID,
|
|
"name": pkg.Name,
|
|
"name_en": pkg.NameEn,
|
|
"price": pkg.Price,
|
|
"currency": pkg.Currency,
|
|
"period": pkg.Period,
|
|
"description": pkg.Description,
|
|
"description_en": pkg.DescriptionEn,
|
|
"status": pkg.Status,
|
|
"sort": pkg.Sort,
|
|
"is_recommended": pkg.IsRecommended,
|
|
"allow_upgrade": pkg.AllowUpgrade,
|
|
"created_at": pkg.CreatedAt,
|
|
"updated_at": pkg.UpdatedAt,
|
|
"permissions": permission,
|
|
})
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"packages": result,
|
|
})
|
|
}
|
|
|
|
func handleGetSiteInfo(c *gin.Context) {
|
|
response.Success(c, gin.H{
|
|
"site_name": "验证平台",
|
|
"site_url": "http://localhost:3000",
|
|
"description": "专业的应用验证平台",
|
|
"contact_email": "admin@example.com",
|
|
})
|
|
}
|
|
|
|
func handleGetContact(c *gin.Context) {
|
|
response.Success(c, gin.H{
|
|
"email": "admin@example.com",
|
|
"qq": "123456789",
|
|
"wechat": "example_wechat",
|
|
"phone": "400-123-4567",
|
|
})
|
|
}
|
|
|
|
func handleForgotPassword(c *gin.Context) {
|
|
var req struct {
|
|
Email string `json:"email"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
authService := service.NewAuthService()
|
|
err := authService.ForgotPassword(req.Email)
|
|
if err != nil {
|
|
response.Error(c, 400, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "重置链接已发送到您的邮箱",
|
|
})
|
|
}
|
|
|
|
func handleResetPassword(c *gin.Context) {
|
|
var req struct {
|
|
Token string `json:"token"`
|
|
Password string `json:"password"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
authService := service.NewAuthService()
|
|
err := authService.ResetPassword(req.Token, req.Password)
|
|
if err != nil {
|
|
response.Error(c, 400, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "密码重置成功",
|
|
})
|
|
}
|
|
|
|
func handleSendSms(c *gin.Context) {
|
|
var req struct {
|
|
Phone string `json:"phone"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "验证码已发送",
|
|
})
|
|
}
|
|
|
|
func HandleGetProfile(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
response.Error(c, 401, "未授权")
|
|
return
|
|
}
|
|
|
|
authService := service.NewAuthService()
|
|
user, err := authService.GetProfile(userID.(uint))
|
|
if err != nil {
|
|
response.Error(c, 404, "用户不存在")
|
|
return
|
|
}
|
|
|
|
response.Success(c, user)
|
|
}
|
|
|
|
func HandleUpdateProfile(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
response.Error(c, 401, "未授权")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Email string `json:"email"`
|
|
Phone string `json:"phone"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
authService := service.NewAuthService()
|
|
err := authService.UpdateProfile(userID.(uint), req.Email, req.Phone)
|
|
if err != nil {
|
|
response.Error(c, 400, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "资料更新成功",
|
|
})
|
|
}
|
|
|
|
func HandleChangePassword(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
response.Error(c, 401, "未授权")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
OldPassword string `json:"old_password"`
|
|
NewPassword string `json:"new_password"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
authService := service.NewAuthService()
|
|
err := authService.ChangePassword(userID.(uint), req.OldPassword, req.NewPassword)
|
|
if err != nil {
|
|
response.Error(c, 400, err.Error())
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "密码修改成功",
|
|
})
|
|
}
|
|
|
|
func HandleUploadAvatar(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
response.Error(c, 401, "未授权")
|
|
return
|
|
}
|
|
|
|
file, err := c.FormFile("avatar")
|
|
if err != nil {
|
|
response.Error(c, 400, "请上传文件")
|
|
return
|
|
}
|
|
|
|
filename := fmt.Sprintf("avatar_%d_%s", userID, file.Filename)
|
|
if err := c.SaveUploadedFile(file, "uploads/"+filename); err != nil {
|
|
response.Error(c, 500, "文件保存失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"avatar": "/uploads/" + filename,
|
|
})
|
|
}
|
|
|
|
func handleCardVerification(c *gin.Context) {
|
|
var req struct {
|
|
CardKey string `json:"card_key"`
|
|
Username string `json:"username"`
|
|
DeviceID string `json:"device_id"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
var card model.Card
|
|
if err := database.DB.Where("card_key = ?", req.CardKey).First(&card).Error; err != nil {
|
|
response.Error(c, 404, "卡密不存在")
|
|
return
|
|
}
|
|
|
|
if card.Status != "unused" {
|
|
response.Error(c, 400, "卡密已被使用或已禁用")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"message": "验证成功",
|
|
"card_id": card.ID,
|
|
"card_type": card.CardType,
|
|
})
|
|
}
|
|
|
|
func handleGetVerificationStatus(c *gin.Context) {
|
|
cardKey := c.Query("card_key")
|
|
if cardKey == "" {
|
|
response.Error(c, 400, "请提供卡密")
|
|
return
|
|
}
|
|
|
|
var card model.Card
|
|
if err := database.DB.Where("card_key = ?", cardKey).First(&card).Error; err != nil {
|
|
response.Error(c, 404, "卡密不存在")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"status": card.Status,
|
|
"card_id": card.ID,
|
|
"used_at": card.UsedAt,
|
|
})
|
|
}
|
|
|
|
func HandleCreateOrder(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
response.Error(c, 401, "请先登录")
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
PackageID uint `json:"package_id"`
|
|
PaymentChannelID uint `json:"payment_channel_id"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.Error(c, 400, "参数错误")
|
|
return
|
|
}
|
|
|
|
if req.PackageID == 0 {
|
|
response.Error(c, 400, "请选择套餐")
|
|
return
|
|
}
|
|
|
|
var pkg model.Package
|
|
if err := database.DB.Where("id = ? AND status = ?", req.PackageID, "active").First(&pkg).Error; err != nil {
|
|
response.Error(c, 404, "套餐不存在或已下架")
|
|
return
|
|
}
|
|
|
|
orderNo := fmt.Sprintf("ORD%d%d", time.Now().Unix(), userID.(uint))
|
|
|
|
if pkg.Price == 0 {
|
|
now := time.Now()
|
|
pkgID := pkg.ID
|
|
order := model.Order{
|
|
OrderNo: orderNo,
|
|
UserID: userID.(uint),
|
|
PackageID: &pkgID,
|
|
OrderType: "package",
|
|
Title: fmt.Sprintf("领取套餐 - %s", pkg.Name),
|
|
Amount: 0,
|
|
PaymentType: "free",
|
|
Status: "paid",
|
|
PaymentAt: &now,
|
|
Description: fmt.Sprintf("免费套餐: %s, 周期: %s", pkg.Name, pkg.Period),
|
|
}
|
|
|
|
if err := database.DB.Create(&order).Error; err != nil {
|
|
response.Error(c, 500, "创建订单失败")
|
|
return
|
|
}
|
|
|
|
var expiredAt *time.Time
|
|
if pkg.Period != "" && pkg.Period != "permanent" {
|
|
duration := parsePeriod(pkg.Period)
|
|
if duration > 0 {
|
|
exp := now.Add(duration)
|
|
expiredAt = &exp
|
|
}
|
|
}
|
|
|
|
userPackage := model.UserPackage{
|
|
UserID: userID.(uint),
|
|
PackageID: pkg.ID,
|
|
ExpiredAt: expiredAt,
|
|
Status: "active",
|
|
}
|
|
|
|
if err := database.DB.Create(&userPackage).Error; err != nil {
|
|
response.Error(c, 500, "创建套餐授权失败")
|
|
return
|
|
}
|
|
|
|
if err := database.DB.Model(&model.User{}).Where("id = ?", userID).Update("current_package_id", pkg.ID).Error; err != nil {
|
|
response.Error(c, 500, "更新用户套餐失败")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"order_no": order.OrderNo,
|
|
"order_id": order.ID,
|
|
"amount": 0,
|
|
"status": "paid",
|
|
"message": "免费套餐领取成功",
|
|
})
|
|
return
|
|
}
|
|
|
|
if req.PaymentChannelID == 0 {
|
|
response.Error(c, 400, "请选择支付方式")
|
|
return
|
|
}
|
|
|
|
var paymentChannel model.PaymentChannel
|
|
if err := database.DB.Where("id = ? AND status = ?", req.PaymentChannelID, "active").First(&paymentChannel).Error; err != nil {
|
|
response.Error(c, 404, "支付通道不存在或已禁用")
|
|
return
|
|
}
|
|
|
|
pkgID := pkg.ID
|
|
order := model.Order{
|
|
OrderNo: orderNo,
|
|
UserID: userID.(uint),
|
|
PackageID: &pkgID,
|
|
OrderType: "package",
|
|
Title: fmt.Sprintf("购买套餐 - %s", pkg.Name),
|
|
Amount: pkg.Price,
|
|
PaymentType: paymentChannel.Type,
|
|
PaymentMethod: paymentChannel.Type,
|
|
Status: "pending",
|
|
Description: fmt.Sprintf("套餐ID: %d, 套餐名称: %s, 周期: %s, 支付通道: %s", pkg.ID, pkg.Name, pkg.Period, paymentChannel.Name),
|
|
}
|
|
|
|
if err := database.DB.Create(&order).Error; err != nil {
|
|
response.Error(c, 500, "创建订单失败")
|
|
return
|
|
}
|
|
|
|
scheme := "http"
|
|
if c.Request.TLS != nil {
|
|
scheme = "https"
|
|
}
|
|
host := c.Request.Host
|
|
callbackBaseURL := fmt.Sprintf("%s://%s", scheme, host)
|
|
|
|
switch paymentChannel.Type {
|
|
case "bepusdt":
|
|
paymentService, err := payment.GetPaymentService(paymentChannel, callbackBaseURL)
|
|
if err != nil {
|
|
response.Error(c, 500, "支付服务初始化失败: "+err.Error())
|
|
return
|
|
}
|
|
|
|
notifyURL := fmt.Sprintf("%s/api/v1/payment/callback/bepusdt", callbackBaseURL)
|
|
redirectURL := fmt.Sprintf("%s/developer/finance?order=%s", callbackBaseURL, orderNo)
|
|
|
|
result, err := paymentService.CreateOrder(orderNo, pkg.Price, notifyURL, redirectURL, order.Title)
|
|
if err != nil {
|
|
response.Error(c, 500, "创建支付订单失败: "+err.Error())
|
|
return
|
|
}
|
|
|
|
extraData := map[string]interface{}{
|
|
"trade_id": result.TradeID,
|
|
"payment_url": result.PaymentURL,
|
|
"actual_amount": result.ActualAmount,
|
|
"token": result.Token,
|
|
"expiration_time": result.ExpirationTime,
|
|
"channel_id": paymentChannel.ID,
|
|
}
|
|
extraJSON, _ := json.Marshal(extraData)
|
|
order.ExtraData = string(extraJSON)
|
|
database.DB.Save(&order)
|
|
|
|
response.Success(c, gin.H{
|
|
"order_no": order.OrderNo,
|
|
"order_id": order.ID,
|
|
"amount": order.Amount,
|
|
"actual_amount": result.ActualAmount,
|
|
"payment_url": result.PaymentURL,
|
|
"trade_id": result.TradeID,
|
|
"token": result.Token,
|
|
"expiration_time": result.ExpirationTime,
|
|
})
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"order_no": order.OrderNo,
|
|
"order_id": order.ID,
|
|
"amount": order.Amount,
|
|
"pay_url": "",
|
|
})
|
|
}
|
|
|
|
func HandleGetOrder(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
response.Error(c, 401, "请先登录")
|
|
return
|
|
}
|
|
|
|
orderNo := c.Param("order_no")
|
|
if orderNo == "" {
|
|
response.Error(c, 400, "订单号不能为空")
|
|
return
|
|
}
|
|
|
|
var order model.Order
|
|
if err := database.DB.Where("order_no = ? AND user_id = ?", orderNo, userID).First(&order).Error; err != nil {
|
|
response.Error(c, 404, "订单不存在")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"order": gin.H{
|
|
"id": order.ID,
|
|
"order_no": order.OrderNo,
|
|
"amount": order.Amount,
|
|
"status": order.Status,
|
|
"payment_type": order.PaymentType,
|
|
"title": order.Title,
|
|
"extra_data": order.ExtraData,
|
|
"created_at": order.CreatedAt,
|
|
"payment_at": order.PaymentAt,
|
|
},
|
|
})
|
|
}
|
|
|
|
func HandleGetOrderStatus(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
response.Error(c, 401, "请先登录")
|
|
return
|
|
}
|
|
|
|
orderNo := c.Param("order_no")
|
|
if orderNo == "" {
|
|
response.Error(c, 400, "订单号不能为空")
|
|
return
|
|
}
|
|
|
|
var order model.Order
|
|
if err := database.DB.Where("order_no = ? AND user_id = ?", orderNo, userID).First(&order).Error; err != nil {
|
|
response.Error(c, 404, "订单不存在")
|
|
return
|
|
}
|
|
|
|
response.Success(c, gin.H{
|
|
"status": order.Status,
|
|
"payment_at": order.PaymentAt,
|
|
})
|
|
}
|
|
|
|
func parsePeriod(period string) time.Duration {
|
|
switch period {
|
|
case "daily":
|
|
return 24 * time.Hour
|
|
case "weekly":
|
|
return 7 * 24 * time.Hour
|
|
case "monthly":
|
|
return 30 * 24 * time.Hour
|
|
case "quarterly":
|
|
return 90 * 24 * time.Hour
|
|
case "yearly":
|
|
return 365 * 24 * time.Hour
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func handleGetPublicStats(c *gin.Context) {
|
|
var totalApps, totalUsers, totalVerifications int64
|
|
|
|
database.DB.Model(&model.Application{}).Count(&totalApps)
|
|
database.DB.Model(&model.User{}).Where("role = ?", "developer").Count(&totalUsers)
|
|
database.DB.Model(&model.Card{}).Where("status = ?", "used").Count(&totalVerifications)
|
|
|
|
response.Success(c, gin.H{
|
|
"totalApps": totalApps,
|
|
"totalUsers": totalUsers,
|
|
"totalVerifications": totalVerifications,
|
|
})
|
|
}
|