This commit is contained in:
yml2213
2026-07-20 14:58:57 +08:00
commit 45db0aa4b9
50 changed files with 5861 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
package service
import (
"errors"
"fmt"
"math/rand"
"time"
"affiliate_dash/internal/model"
"affiliate_dash/internal/pkg/jwt"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
type AuthService struct {
db *gorm.DB
jwt *jwt.Manager
}
func NewAuthService(db *gorm.DB, jm *jwt.Manager) *AuthService {
return &AuthService{db: db, jwt: jm}
}
type LoginResult struct {
Token string `json:"token"`
User *model.User `json:"user"`
}
func (s *AuthService) Login(username, password string) (*LoginResult, error) {
var user model.User
if err := s.db.Where("username = ?", username).First(&user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("用户名或密码错误")
}
return nil, err
}
if user.Status != 1 {
return nil, errors.New("账号已禁用")
}
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)); err != nil {
return nil, errors.New("用户名或密码错误")
}
token, err := s.jwt.Generate(user.ID, user.Username, user.Role)
if err != nil {
return nil, err
}
return &LoginResult{Token: token, User: &user}, nil
}
func (s *AuthService) Register(username, password, nickname string) (*model.User, error) {
var count int64
s.db.Model(&model.User{}).Where("username = ?", username).Count(&count)
if count > 0 {
return nil, errors.New("用户名已存在")
}
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
user := &model.User{
Username: username,
PasswordHash: string(hash),
Nickname: nickname,
Role: model.RoleDistributor,
Status: 1,
InviteCode: generateInviteCode(),
}
if user.Nickname == "" {
user.Nickname = username
}
if err := s.db.Create(user).Error; err != nil {
return nil, err
}
return user, nil
}
func (s *AuthService) GetProfile(userID uint) (*model.User, error) {
var user model.User
if err := s.db.First(&user, userID).Error; err != nil {
return nil, err
}
return &user, nil
}
func (s *AuthService) EnsureAdmin() error {
var count int64
s.db.Model(&model.User{}).Where("role = ?", model.RoleAdmin).Count(&count)
if count > 0 {
return nil
}
hash, err := bcrypt.GenerateFromPassword([]byte("admin123"), bcrypt.DefaultCost)
if err != nil {
return err
}
admin := &model.User{
Username: "admin",
PasswordHash: string(hash),
Nickname: "管理员",
Role: model.RoleAdmin,
Status: 1,
InviteCode: "ADMIN001",
}
return s.db.Create(admin).Error
}
func generateInviteCode() string {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
return fmt.Sprintf("D%06d", r.Intn(1000000))
}
+150
View File
@@ -0,0 +1,150 @@
package service
import (
"errors"
"fmt"
"time"
"affiliate_dash/internal/model"
"gorm.io/gorm"
)
type OrderService struct {
db *gorm.DB
}
func NewOrderService(db *gorm.DB) *OrderService {
return &OrderService{db: db}
}
type OrderListQuery struct {
Page int
Size int
Status string
DistributorID *uint
}
type CreateOrderInput struct {
SkinID uint
DistributorID uint
BuyerName string
Remark string
}
func (s *OrderService) List(q OrderListQuery) ([]model.Order, int64, error) {
if q.Page < 1 {
q.Page = 1
}
if q.Size < 1 || q.Size > 100 {
q.Size = 20
}
tx := s.db.Model(&model.Order{})
if q.Status != "" {
tx = tx.Where("status = ?", q.Status)
}
if q.DistributorID != nil {
tx = tx.Where("distributor_id = ?", *q.DistributorID)
}
var total int64
if err := tx.Count(&total).Error; err != nil {
return nil, 0, err
}
var list []model.Order
err := tx.Preload("Skin").Preload("Distributor").
Order("id DESC").
Offset((q.Page - 1) * q.Size).Limit(q.Size).
Find(&list).Error
return list, total, err
}
func (s *OrderService) Create(in CreateOrderInput) (*model.Order, error) {
var skin model.Skin
if err := s.db.First(&skin, in.SkinID).Error; err != nil {
return nil, errors.New("皮肤不存在")
}
if skin.Status != 1 {
return nil, errors.New("皮肤已下架")
}
if skin.Stock == 0 {
return nil, errors.New("库存不足")
}
order := &model.Order{
OrderNo: generateOrderNo(),
SkinID: in.SkinID,
DistributorID: in.DistributorID,
BuyerName: in.BuyerName,
Amount: skin.Price,
CommissionAmt: skin.Price * skin.Commission,
Status: model.OrderStatusPending,
Remark: in.Remark,
}
err := s.db.Transaction(func(tx *gorm.DB) error {
if skin.Stock > 0 {
res := tx.Model(&model.Skin{}).
Where("id = ? AND stock > 0", skin.ID).
Update("stock", gorm.Expr("stock - 1"))
if res.Error != nil {
return res.Error
}
if res.RowsAffected == 0 {
return errors.New("库存不足")
}
}
return tx.Create(order).Error
})
if err != nil {
return nil, err
}
return order, nil
}
func (s *OrderService) UpdateStatus(id uint, status string) error {
allowed := map[string]bool{
model.OrderStatusPending: true,
model.OrderStatusPaid: true,
model.OrderStatusDelivered: true,
model.OrderStatusCancelled: true,
}
if !allowed[status] {
return errors.New("无效的订单状态")
}
res := s.db.Model(&model.Order{}).Where("id = ?", id).Update("status", status)
if res.Error != nil {
return res.Error
}
if res.RowsAffected == 0 {
return errors.New("订单不存在")
}
return nil
}
type DashboardStats struct {
SkinCount int64 `json:"skin_count"`
DistributorCount int64 `json:"distributor_count"`
OrderCount int64 `json:"order_count"`
TotalSales float64 `json:"total_sales"`
TotalCommission float64 `json:"total_commission"`
PendingOrderCount int64 `json:"pending_order_count"`
}
func (s *OrderService) Dashboard() (*DashboardStats, error) {
stats := &DashboardStats{}
s.db.Model(&model.Skin{}).Count(&stats.SkinCount)
s.db.Model(&model.User{}).Where("role = ?", model.RoleDistributor).Count(&stats.DistributorCount)
s.db.Model(&model.Order{}).Count(&stats.OrderCount)
s.db.Model(&model.Order{}).Where("status = ?", model.OrderStatusPending).Count(&stats.PendingOrderCount)
s.db.Model(&model.Order{}).
Where("status IN ?", []string{model.OrderStatusPaid, model.OrderStatusDelivered}).
Select("COALESCE(SUM(amount),0)").Scan(&stats.TotalSales)
s.db.Model(&model.Order{}).
Where("status IN ?", []string{model.OrderStatusPaid, model.OrderStatusDelivered}).
Select("COALESCE(SUM(commission_amt),0)").Scan(&stats.TotalCommission)
return stats, nil
}
func generateOrderNo() string {
return fmt.Sprintf("O%s%04d", time.Now().Format("20060102150405"), time.Now().Nanosecond()%10000)
}
+106
View File
@@ -0,0 +1,106 @@
package service
import (
"errors"
"affiliate_dash/internal/model"
"gorm.io/gorm"
)
type SkinService struct {
db *gorm.DB
}
func NewSkinService(db *gorm.DB) *SkinService {
return &SkinService{db: db}
}
type SkinListQuery struct {
Page int
Size int
Keyword string
Game string
Category string
Status *int
}
func (s *SkinService) List(q SkinListQuery) ([]model.Skin, int64, error) {
if q.Page < 1 {
q.Page = 1
}
if q.Size < 1 || q.Size > 100 {
q.Size = 20
}
tx := s.db.Model(&model.Skin{})
if q.Keyword != "" {
tx = tx.Where("name LIKE ?", "%"+q.Keyword+"%")
}
if q.Game != "" {
tx = tx.Where("game = ?", q.Game)
}
if q.Category != "" {
tx = tx.Where("category = ?", q.Category)
}
if q.Status != nil {
tx = tx.Where("status = ?", *q.Status)
}
var total int64
if err := tx.Count(&total).Error; err != nil {
return nil, 0, err
}
var list []model.Skin
err := tx.Order("id DESC").Offset((q.Page - 1) * q.Size).Limit(q.Size).Find(&list).Error
return list, total, err
}
func (s *SkinService) Get(id uint) (*model.Skin, error) {
var skin model.Skin
if err := s.db.First(&skin, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("皮肤不存在")
}
return nil, err
}
return &skin, nil
}
func (s *SkinService) Create(skin *model.Skin) error {
return s.db.Create(skin).Error
}
func (s *SkinService) Update(id uint, updates map[string]interface{}) error {
res := s.db.Model(&model.Skin{}).Where("id = ?", id).Updates(updates)
if res.Error != nil {
return res.Error
}
if res.RowsAffected == 0 {
return errors.New("皮肤不存在")
}
return nil
}
func (s *SkinService) Delete(id uint) error {
res := s.db.Delete(&model.Skin{}, id)
if res.Error != nil {
return res.Error
}
if res.RowsAffected == 0 {
return errors.New("皮肤不存在")
}
return nil
}
func (s *SkinService) SeedDemo() error {
var count int64
s.db.Model(&model.Skin{}).Count(&count)
if count > 0 {
return nil
}
demos := []model.Skin{
{Name: "龙之觉醒", Game: "王者荣耀", Category: "史诗", Price: 88, CostPrice: 50, Commission: 0.15, Stock: -1, Status: 1, Description: "史诗皮肤示例"},
{Name: "星空旅人", Game: "和平精英", Category: "限定", Price: 128, CostPrice: 80, Commission: 0.12, Stock: 100, Status: 1, Description: "限定皮肤示例"},
{Name: "暗夜骑士", Game: "英雄联盟", Category: "传说", Price: 199, CostPrice: 120, Commission: 0.10, Stock: 50, Status: 1, Description: "传说皮肤示例"},
}
return s.db.Create(&demos).Error
}
+95
View File
@@ -0,0 +1,95 @@
package service
import (
"errors"
"affiliate_dash/internal/model"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
type UserService struct {
db *gorm.DB
}
func NewUserService(db *gorm.DB) *UserService {
return &UserService{db: db}
}
type UserListQuery struct {
Page int
Size int
Keyword string
Role string
Status *int
}
func (s *UserService) List(q UserListQuery) ([]model.User, int64, error) {
if q.Page < 1 {
q.Page = 1
}
if q.Size < 1 || q.Size > 100 {
q.Size = 20
}
tx := s.db.Model(&model.User{})
if q.Keyword != "" {
like := "%" + q.Keyword + "%"
tx = tx.Where("username LIKE ? OR nickname LIKE ?", like, like)
}
if q.Role != "" {
tx = tx.Where("role = ?", q.Role)
}
if q.Status != nil {
tx = tx.Where("status = ?", *q.Status)
}
var total int64
if err := tx.Count(&total).Error; err != nil {
return nil, 0, err
}
var list []model.User
err := tx.Order("id DESC").Offset((q.Page - 1) * q.Size).Limit(q.Size).Find(&list).Error
return list, total, err
}
func (s *UserService) Create(username, password, nickname, role string, parentID *uint) (*model.User, error) {
var count int64
s.db.Model(&model.User{}).Where("username = ?", username).Count(&count)
if count > 0 {
return nil, errors.New("用户名已存在")
}
if role == "" {
role = model.RoleDistributor
}
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return nil, err
}
user := &model.User{
Username: username,
PasswordHash: string(hash),
Nickname: nickname,
Role: role,
Status: 1,
InviteCode: generateInviteCode(),
ParentID: parentID,
}
if user.Nickname == "" {
user.Nickname = username
}
if err := s.db.Create(user).Error; err != nil {
return nil, err
}
return user, nil
}
func (s *UserService) UpdateStatus(id uint, status int) error {
res := s.db.Model(&model.User{}).Where("id = ?", id).Update("status", status)
if res.Error != nil {
return res.Error
}
if res.RowsAffected == 0 {
return errors.New("用户不存在")
}
return nil
}