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 = "admin" } 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 = ?", "admin").Count(&totalUsers) database.DB.Model(&model.Card{}).Where("status = ?", "used").Count(&totalVerifications) response.Success(c, gin.H{ "totalApps": totalApps, "totalUsers": totalUsers, "totalVerifications": totalVerifications, }) }