Initial commit: 网络验证平台
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"verification-platform-backend/internal/database"
|
||||
"verification-platform-backend/internal/model"
|
||||
"verification-platform-backend/internal/service"
|
||||
"verification-platform-backend/pkg/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupPaymentRoutes(r *gin.RouterGroup) {
|
||||
r.POST("/recharge", handleAppRecharge)
|
||||
r.POST("/trial", handleAppTrial)
|
||||
}
|
||||
|
||||
func handleAppRecharge(c *gin.Context) {
|
||||
appKey := c.Param("appKey")
|
||||
var app model.Application
|
||||
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
if service.GetApplicationDisabledStatus(app.ID) {
|
||||
response.Error(c, 403, "该应用已被禁用")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Username string `json:"username"`
|
||||
CardKey string `json:"card_key"`
|
||||
DeviceID string `json:"device_id"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if blocked, reason := checkRiskControl(c, app.ID, req.DeviceID, req.Username); blocked {
|
||||
response.Error(c, 403, reason)
|
||||
return
|
||||
}
|
||||
|
||||
var card model.Card
|
||||
if err := database.DB.Preload("CardType").Where("card_key = ?", req.CardKey).First(&card).Error; err != nil {
|
||||
service.LogVerification(c, &app.ID, nil, "recharge_failed", fmt.Sprintf("充值失败: 卡密不存在 - %s", req.CardKey), "", fmt.Errorf("卡密不存在"))
|
||||
response.Error(c, 404, "卡密不存在")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("[DEBUG] 卡密信息: ID=%d, CardKey=%s, Status=%s, CardTypeID=%d\n", card.ID, card.CardKey, card.Status, card.CardTypeID)
|
||||
fmt.Printf("[DEBUG] 卡类信息: ID=%d, Name=%s, Value=%f, Price=%f\n", card.CardType.ID, card.CardType.Name, card.CardType.Value, card.CardType.Price)
|
||||
|
||||
if card.Status != "unused" {
|
||||
service.LogVerification(c, &app.ID, nil, "recharge_failed", fmt.Sprintf("充值失败: 卡密已使用 - %s", req.CardKey), "", fmt.Errorf("卡密已使用"))
|
||||
response.Error(c, 400, "卡密已使用")
|
||||
return
|
||||
}
|
||||
|
||||
var user model.AppUser
|
||||
if err := database.DB.Where("username = ? AND application_id = ?", req.Username, app.ID).First(&user).Error; err != nil {
|
||||
service.LogVerification(c, &app.ID, nil, "recharge_failed", fmt.Sprintf("充值失败: 用户不存在 - %s", req.Username), "", fmt.Errorf("用户不存在"))
|
||||
response.Error(c, 404, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
if user.Balance == -1 {
|
||||
service.LogVerification(c, &app.ID, &user.ID, "recharge_failed", fmt.Sprintf("充值失败: 用户已是永久会员 - %s", user.Username), "", fmt.Errorf("该用户已是永久会员,无法再次充值"))
|
||||
response.Error(c, 400, "该用户已是永久会员,无法再次充值")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("[DEBUG] 充值前用户信息: ID=%d, Username=%s, Balance=%f, ExpiryAt=%v\n", user.ID, user.Username, user.Balance, user.ExpiryAt)
|
||||
|
||||
tx := database.DB.Begin()
|
||||
|
||||
card.Status = "used"
|
||||
card.AppUserID = &user.ID
|
||||
now := time.Now()
|
||||
card.UsedAt = &now
|
||||
|
||||
if err := tx.Save(&card).Error; err != nil {
|
||||
tx.Rollback()
|
||||
response.Error(c, 500, "充值失败")
|
||||
return
|
||||
}
|
||||
|
||||
user.IsTrialUser = false
|
||||
|
||||
if card.CardType.Value == -1 {
|
||||
user.Balance = -1
|
||||
user.ExpiryAt = nil
|
||||
} else {
|
||||
switch card.CardType.RechargeType {
|
||||
case "subscription":
|
||||
var baseTime time.Time
|
||||
if user.ExpiryAt != nil && user.ExpiryAt.After(now) {
|
||||
baseTime = *user.ExpiryAt
|
||||
} else {
|
||||
baseTime = now
|
||||
}
|
||||
var duration time.Duration
|
||||
switch card.CardType.ValueUnit {
|
||||
case "minute":
|
||||
duration = time.Duration(card.CardType.Value) * time.Minute
|
||||
case "hour":
|
||||
duration = time.Duration(card.CardType.Value) * time.Hour
|
||||
case "day":
|
||||
duration = time.Duration(card.CardType.Value) * 24 * time.Hour
|
||||
case "month":
|
||||
duration = time.Duration(card.CardType.Value) * 30 * 24 * time.Hour
|
||||
case "year":
|
||||
duration = time.Duration(card.CardType.Value) * 365 * 24 * time.Hour
|
||||
default:
|
||||
duration = time.Duration(card.CardType.Value) * time.Second
|
||||
}
|
||||
newExpiry := baseTime.Add(duration)
|
||||
user.ExpiryAt = &newExpiry
|
||||
case "balance":
|
||||
fallthrough
|
||||
default:
|
||||
user.Balance += card.CardType.Value
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("[DEBUG] 充值后用户信息: Balance=%f, ExpiryAt=%v (CardType.Value=%f, BillingType=%s)\n", user.Balance, user.ExpiryAt, card.CardType.Value, app.BillingType)
|
||||
|
||||
if err := tx.Save(&user).Error; err != nil {
|
||||
tx.Rollback()
|
||||
response.Error(c, 500, "更新用户信息失败")
|
||||
return
|
||||
}
|
||||
|
||||
rechargeRecord := model.RechargeRecord{
|
||||
UserID: user.ID,
|
||||
OrderNo: generateOrderNo("R"),
|
||||
CardID: &card.ID,
|
||||
CardCode: card.CardKey,
|
||||
Amount: card.CardType.Price,
|
||||
Status: "success",
|
||||
PaymentType: "card",
|
||||
Remark: "卡密充值 - " + card.CardType.Name,
|
||||
}
|
||||
|
||||
if err := tx.Create(&rechargeRecord).Error; err != nil {
|
||||
tx.Rollback()
|
||||
response.Error(c, 500, "创建充值记录失败")
|
||||
return
|
||||
}
|
||||
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
response.Error(c, 500, "充值失败")
|
||||
return
|
||||
}
|
||||
|
||||
service.LogVerification(c, &app.ID, &user.ID, "recharge", fmt.Sprintf("用户充值: %s, 卡密: %s, 金额: %.2f", user.Username, card.CardKey, card.CardType.Price), "", nil)
|
||||
|
||||
response.SuccessWithMessage(c, "充值成功", gin.H{
|
||||
"message": "充值成功",
|
||||
"value": card.CardType.Value,
|
||||
})
|
||||
}
|
||||
|
||||
func handleAppTrial(c *gin.Context) {
|
||||
appKey := c.Param("appKey")
|
||||
var app model.Application
|
||||
if err := database.DB.Where("app_key = ?", appKey).First(&app).Error; err != nil {
|
||||
response.Error(c, 404, "应用不存在")
|
||||
return
|
||||
}
|
||||
|
||||
if service.GetApplicationDisabledStatus(app.ID) {
|
||||
response.Error(c, 403, "该应用已被禁用")
|
||||
return
|
||||
}
|
||||
|
||||
if !app.EnableTrial {
|
||||
response.Error(c, 400, "该应用不支持试用")
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
UserID uint `json:"user_id"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.Error(c, 400, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
var user model.AppUser
|
||||
if err := database.DB.First(&user, req.UserID).Error; err != nil {
|
||||
response.Error(c, 404, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
response.SuccessWithMessage(c, "试用成功", gin.H{
|
||||
"message": "试用成功",
|
||||
"trial_balance": app.TrialBalance,
|
||||
})
|
||||
}
|
||||
|
||||
func generateOrderNo(prefix string) string {
|
||||
return prefix + time.Now().Format("20060102150405") + randomString(6)
|
||||
}
|
||||
|
||||
func randomString(length int) string {
|
||||
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[time.Now().Nanosecond()%len(charset)]
|
||||
time.Sleep(1 * time.Nanosecond)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
Reference in New Issue
Block a user