946 lines
26 KiB
Go
946 lines
26 KiB
Go
|
|
package service
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"dianshang/internal/model"
|
|||
|
|
"dianshang/internal/repository"
|
|||
|
|
"dianshang/pkg/jwt"
|
|||
|
|
"errors"
|
|||
|
|
"fmt"
|
|||
|
|
"time"
|
|||
|
|
|
|||
|
|
"gorm.io/gorm"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// UserService 用户服务
|
|||
|
|
type UserService struct {
|
|||
|
|
userRepo *repository.UserRepository
|
|||
|
|
db *gorm.DB
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// NewUserService 创建用户服务
|
|||
|
|
func NewUserService(db *gorm.DB) *UserService {
|
|||
|
|
return &UserService{
|
|||
|
|
userRepo: repository.NewUserRepository(db),
|
|||
|
|
db: db,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// WeChatLogin 微信登录
|
|||
|
|
func (s *UserService) WeChatLogin(code string) (*model.User, string, error) {
|
|||
|
|
// TODO: 调用微信API获取openid
|
|||
|
|
// 这里暂时模拟
|
|||
|
|
openID := "mock_openid_" + code
|
|||
|
|
|
|||
|
|
// 查找用户
|
|||
|
|
user, err := s.userRepo.GetByOpenID(openID)
|
|||
|
|
if err != nil {
|
|||
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|||
|
|
// 用户不存在,创建新用户
|
|||
|
|
user = &model.User{
|
|||
|
|
OpenID: openID,
|
|||
|
|
Nickname: "微信用户",
|
|||
|
|
Status: 1,
|
|||
|
|
}
|
|||
|
|
if err := s.userRepo.Create(user); err != nil {
|
|||
|
|
return nil, "", err
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
return nil, "", err
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查用户状态
|
|||
|
|
if user.Status == 0 {
|
|||
|
|
return nil, "", errors.New("用户已被禁用")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 生成JWT token
|
|||
|
|
token, err := jwt.GenerateToken(user.ID, "user", 7200)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, "", err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return user, token, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CreateUser 创建用户
|
|||
|
|
func (s *UserService) CreateUser(user *model.User) error {
|
|||
|
|
// 检查用户是否已存在
|
|||
|
|
existingUser, err := s.userRepo.GetByOpenID(user.OpenID)
|
|||
|
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
if existingUser != nil {
|
|||
|
|
return errors.New("用户已存在")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return s.userRepo.Create(user)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserByID 根据ID获取用户
|
|||
|
|
func (s *UserService) GetUserByID(id uint) (*model.User, error) {
|
|||
|
|
return s.userRepo.GetByID(id)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateUser 更新用户信息
|
|||
|
|
func (s *UserService) UpdateUser(id uint, updates map[string]interface{}) error {
|
|||
|
|
// 更新用户表
|
|||
|
|
if err := s.userRepo.Update(id, updates); err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 同步更新微信用户信息表
|
|||
|
|
wechatUpdates := make(map[string]interface{})
|
|||
|
|
if nickname, ok := updates["nickname"]; ok {
|
|||
|
|
wechatUpdates["nick_name"] = nickname
|
|||
|
|
}
|
|||
|
|
if avatar, ok := updates["avatar"]; ok {
|
|||
|
|
wechatUpdates["avatar_url"] = avatar
|
|||
|
|
}
|
|||
|
|
if gender, ok := updates["gender"]; ok {
|
|||
|
|
wechatUpdates["gender"] = gender
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果有需要更新的微信信息字段
|
|||
|
|
if len(wechatUpdates) > 0 {
|
|||
|
|
wechatUpdates["updated_at"] = time.Now()
|
|||
|
|
|
|||
|
|
// 更新微信用户信息表
|
|||
|
|
if err := s.db.Model(&model.User{}).Where("id = ?", id).Updates(wechatUpdates).Error; err != nil {
|
|||
|
|
// 记录错误但不影响主要更新流程
|
|||
|
|
fmt.Printf("更新微信用户信息失败: %v\n", err)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserAddresses 获取用户地址列表
|
|||
|
|
func (s *UserService) GetUserAddresses(userID uint) ([]model.UserAddress, error) {
|
|||
|
|
return s.userRepo.GetAddresses(userID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetAddressByID 根据ID获取用户地址
|
|||
|
|
func (s *UserService) GetAddressByID(userID, addressID uint) (*model.UserAddress, error) {
|
|||
|
|
address, err := s.userRepo.GetAddressByID(addressID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查地址是否属于该用户
|
|||
|
|
if address.UserID != userID {
|
|||
|
|
return nil, errors.New("无权限访问该地址")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return address, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CreateAddress 创建用户地址
|
|||
|
|
func (s *UserService) CreateAddress(address *model.UserAddress) error {
|
|||
|
|
// 如果设置为默认地址,先取消其他默认地址
|
|||
|
|
if address.IsDefault {
|
|||
|
|
if err := s.userRepo.ClearDefaultAddress(address.UserID); err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return s.userRepo.CreateAddress(address)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateAddress 更新用户地址
|
|||
|
|
func (s *UserService) UpdateAddress(userID, addressID uint, updates map[string]interface{}) error {
|
|||
|
|
// 检查地址是否属于该用户
|
|||
|
|
address, err := s.userRepo.GetAddressByID(addressID)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
if address.UserID != userID {
|
|||
|
|
return errors.New("无权限操作该地址")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 如果设置为默认地址,先取消其他默认地址
|
|||
|
|
if isDefault, ok := updates["is_default"]; ok && isDefault.(uint8) == 1 {
|
|||
|
|
if err := s.userRepo.ClearDefaultAddress(userID); err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return s.userRepo.UpdateAddress(addressID, updates)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DeleteAddress 删除用户地址
|
|||
|
|
func (s *UserService) DeleteAddress(userID, addressID uint) error {
|
|||
|
|
// 检查地址是否属于该用户
|
|||
|
|
address, err := s.userRepo.GetAddressByID(addressID)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
if address.UserID != userID {
|
|||
|
|
return errors.New("无权限操作该地址")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return s.userRepo.DeleteAddress(addressID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SetDefaultAddress 设置默认地址
|
|||
|
|
func (s *UserService) SetDefaultAddress(userID, addressID uint) error {
|
|||
|
|
// 检查地址是否属于该用户
|
|||
|
|
address, err := s.userRepo.GetAddressByID(addressID)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
if address.UserID != userID {
|
|||
|
|
return errors.New("无权限操作该地址")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 先取消其他默认地址
|
|||
|
|
if err := s.userRepo.ClearDefaultAddress(userID); err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置为默认地址
|
|||
|
|
return s.userRepo.UpdateAddress(addressID, map[string]interface{}{
|
|||
|
|
"is_default": 1,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetFavorites 获取用户收藏列表
|
|||
|
|
func (s *UserService) GetFavorites(userID uint, page, limit int) ([]model.UserFavorite, int64, error) {
|
|||
|
|
offset := (page - 1) * limit
|
|||
|
|
return s.userRepo.GetFavorites(userID, offset, limit)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AddToFavorite 添加收藏
|
|||
|
|
func (s *UserService) AddToFavorite(userID, productID uint) error {
|
|||
|
|
// 检查是否已经收藏
|
|||
|
|
if s.userRepo.IsFavorite(userID, productID) {
|
|||
|
|
return errors.New("商品已在收藏列表中")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
favorite := &model.UserFavorite{
|
|||
|
|
UserID: userID,
|
|||
|
|
ProductID: productID,
|
|||
|
|
}
|
|||
|
|
return s.userRepo.CreateFavorite(favorite)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RemoveFromFavorite 取消收藏
|
|||
|
|
func (s *UserService) RemoveFromFavorite(userID, productID uint) error {
|
|||
|
|
return s.userRepo.DeleteFavorite(userID, productID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// IsFavorite 检查是否已收藏
|
|||
|
|
func (s *UserService) IsFavorite(userID, productID uint) bool {
|
|||
|
|
return s.userRepo.IsFavorite(userID, productID)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserStatistics 获取用户统计
|
|||
|
|
func (s *UserService) GetUserStatistics(startDate, endDate string) (map[string]interface{}, error) {
|
|||
|
|
result := make(map[string]interface{})
|
|||
|
|
|
|||
|
|
// 总用户数
|
|||
|
|
var totalUsers int64
|
|||
|
|
s.db.Model(&model.User{}).Count(&totalUsers)
|
|||
|
|
result["total_users"] = totalUsers
|
|||
|
|
|
|||
|
|
// 新增用户数(指定日期范围)
|
|||
|
|
var newUsers int64
|
|||
|
|
query := s.db.Model(&model.User{})
|
|||
|
|
if startDate != "" && endDate != "" {
|
|||
|
|
query = query.Where("DATE(created_at) BETWEEN ? AND ?", startDate, endDate)
|
|||
|
|
}
|
|||
|
|
query.Count(&newUsers)
|
|||
|
|
result["new_users"] = newUsers
|
|||
|
|
|
|||
|
|
// 活跃用户数(简化处理,这里用登录用户数代替)
|
|||
|
|
var activeUsers int64
|
|||
|
|
activeQuery := s.db.Model(&model.User{}).Where("status = ?", 1)
|
|||
|
|
if startDate != "" && endDate != "" {
|
|||
|
|
activeQuery = activeQuery.Where("DATE(updated_at) BETWEEN ? AND ?", startDate, endDate)
|
|||
|
|
}
|
|||
|
|
activeQuery.Count(&activeUsers)
|
|||
|
|
result["active_users"] = activeUsers
|
|||
|
|
|
|||
|
|
return result, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetDailyUserStatistics 获取每日用户统计
|
|||
|
|
func (s *UserService) GetDailyUserStatistics(startDate, endDate string) ([]map[string]interface{}, error) {
|
|||
|
|
// 简化实现,返回基础统计数据
|
|||
|
|
var results []map[string]interface{}
|
|||
|
|
|
|||
|
|
// 解析日期
|
|||
|
|
start, err := time.Parse("2006-01-02", startDate)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
end, err := time.Parse("2006-01-02", endDate)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 遍历日期范围
|
|||
|
|
for d := start; !d.After(end); d = d.AddDate(0, 0, 1) {
|
|||
|
|
dateStr := d.Format("2006-01-02")
|
|||
|
|
|
|||
|
|
var newUsers int64
|
|||
|
|
s.db.Model(&model.User{}).
|
|||
|
|
Where("DATE(created_at) = ?", dateStr).
|
|||
|
|
Count(&newUsers)
|
|||
|
|
|
|||
|
|
results = append(results, map[string]interface{}{
|
|||
|
|
"date": dateStr,
|
|||
|
|
"new_users": newUsers,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return results, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserListForAdmin 获取用户列表(管理后台)
|
|||
|
|
func (s *UserService) GetUserListForAdmin(page, pageSize int, conditions map[string]interface{}) ([]model.User, map[string]interface{}, error) {
|
|||
|
|
var users []model.User
|
|||
|
|
var total int64
|
|||
|
|
|
|||
|
|
query := s.db.Model(&model.User{})
|
|||
|
|
|
|||
|
|
// 应用查询条件
|
|||
|
|
if keyword, ok := conditions["keyword"]; ok && keyword != "" {
|
|||
|
|
query = query.Where("nickname LIKE ? OR email LIKE ? OR phone LIKE ?",
|
|||
|
|
"%"+keyword.(string)+"%", "%"+keyword.(string)+"%", "%"+keyword.(string)+"%")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if status, ok := conditions["status"]; ok && status != "" {
|
|||
|
|
query = query.Where("status = ?", status)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if startDate, ok := conditions["start_date"]; ok && startDate != "" {
|
|||
|
|
query = query.Where("created_at >= ?", startDate)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if endDate, ok := conditions["end_date"]; ok && endDate != "" {
|
|||
|
|
query = query.Where("created_at <= ?", endDate)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取总数
|
|||
|
|
err := query.Count(&total).Error
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 分页查询
|
|||
|
|
offset := (page - 1) * pageSize
|
|||
|
|
err = query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&users).Error
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建分页信息
|
|||
|
|
pagination := map[string]interface{}{
|
|||
|
|
"total": total,
|
|||
|
|
"page": page,
|
|||
|
|
"page_size": pageSize,
|
|||
|
|
"total_pages": (total + int64(pageSize) - 1) / int64(pageSize),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return users, pagination, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserDetailForAdmin 获取用户详情(管理后台)
|
|||
|
|
func (s *UserService) GetUserDetailForAdmin(userID uint) (map[string]interface{}, error) {
|
|||
|
|
var user model.User
|
|||
|
|
err := s.db.Where("id = ?", userID).First(&user).Error
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建返回数据
|
|||
|
|
result := map[string]interface{}{
|
|||
|
|
"id": user.ID,
|
|||
|
|
"openid": user.OpenID,
|
|||
|
|
"unionid": user.UnionID,
|
|||
|
|
"nickname": user.Nickname,
|
|||
|
|
"avatar": user.Avatar,
|
|||
|
|
"gender": user.Gender,
|
|||
|
|
"phone": user.Phone,
|
|||
|
|
"email": user.Email,
|
|||
|
|
"birthday": user.Birthday,
|
|||
|
|
"points": user.Points,
|
|||
|
|
"level": user.Level,
|
|||
|
|
"status": user.Status,
|
|||
|
|
"created_at": user.CreatedAt,
|
|||
|
|
"updated_at": user.UpdatedAt,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateUserStatusByAdmin 管理员更新用户状态
|
|||
|
|
func (s *UserService) UpdateUserStatusByAdmin(userID uint, status uint8, remark string, adminID uint) error {
|
|||
|
|
return s.db.Model(&model.User{}).Where("id = ?", userID).Update("status", status).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateUserProfile 更新用户资料
|
|||
|
|
func (s *UserService) UpdateUserProfile(userID uint, updates map[string]interface{}) error {
|
|||
|
|
// 验证更新字段
|
|||
|
|
allowedFields := map[string]bool{
|
|||
|
|
"nickname": true,
|
|||
|
|
"avatar": true,
|
|||
|
|
"gender": true,
|
|||
|
|
"phone": true,
|
|||
|
|
"email": true,
|
|||
|
|
"birthday": true,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
filteredUpdates := make(map[string]interface{})
|
|||
|
|
for key, value := range updates {
|
|||
|
|
if allowedFields[key] {
|
|||
|
|
filteredUpdates[key] = value
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if len(filteredUpdates) == 0 {
|
|||
|
|
return fmt.Errorf("没有有效的更新字段")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
filteredUpdates["updated_at"] = time.Now()
|
|||
|
|
|
|||
|
|
return s.db.Model(&model.User{}).Where("id = ?", userID).Updates(filteredUpdates).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateUserProfileByAdmin 管理员更新用户资料
|
|||
|
|
func (s *UserService) UpdateUserProfileByAdmin(userID uint, updates map[string]interface{}, adminID uint) error {
|
|||
|
|
// 验证更新字段
|
|||
|
|
allowedFields := map[string]bool{
|
|||
|
|
"nickname": true,
|
|||
|
|
"avatar": true,
|
|||
|
|
"gender": true,
|
|||
|
|
"phone": true,
|
|||
|
|
"email": true,
|
|||
|
|
"birthday": true,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
filteredUpdates := make(map[string]interface{})
|
|||
|
|
for key, value := range updates {
|
|||
|
|
if allowedFields[key] {
|
|||
|
|
filteredUpdates[key] = value
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if len(filteredUpdates) == 0 {
|
|||
|
|
return fmt.Errorf("没有有效的更新字段")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
filteredUpdates["updated_at"] = time.Now()
|
|||
|
|
|
|||
|
|
// TODO: 记录操作日志
|
|||
|
|
// 可以在这里添加操作日志记录,记录管理员修改用户资料的操作
|
|||
|
|
|
|||
|
|
return s.db.Model(&model.User{}).Where("id = ?", userID).Updates(filteredUpdates).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ResetUserPassword 重置用户密码(管理员操作)
|
|||
|
|
func (s *UserService) ResetUserPassword(userID uint, newPassword string, adminID uint) error {
|
|||
|
|
// 这里可以添加密码加密逻辑
|
|||
|
|
// 由于是微信小程序,通常不需要密码,这里预留接口
|
|||
|
|
updates := map[string]interface{}{
|
|||
|
|
"updated_at": time.Now(),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return s.db.Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// CreateUserAddress 创建用户地址
|
|||
|
|
func (s *UserService) CreateUserAddress(address *model.UserAddress) error {
|
|||
|
|
// 如果设置为默认地址,先取消其他默认地址
|
|||
|
|
if address.IsDefault {
|
|||
|
|
s.db.Model(&model.UserAddress{}).Where("user_id = ?", address.UserID).Update("is_default", false)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return s.db.Create(address).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateUserAddress 更新用户地址
|
|||
|
|
func (s *UserService) UpdateUserAddress(addressID uint, userID uint, updates map[string]interface{}) error {
|
|||
|
|
// 如果设置为默认地址,先取消其他默认地址
|
|||
|
|
if isDefault, ok := updates["is_default"]; ok && isDefault.(bool) {
|
|||
|
|
s.db.Model(&model.UserAddress{}).Where("user_id = ?", userID).Update("is_default", false)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
updates["updated_at"] = time.Now()
|
|||
|
|
|
|||
|
|
return s.db.Model(&model.UserAddress{}).Where("id = ? AND user_id = ?", addressID, userID).Updates(updates).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DeleteUserAddress 删除用户地址
|
|||
|
|
func (s *UserService) DeleteUserAddress(addressID uint, userID uint) error {
|
|||
|
|
return s.db.Where("id = ? AND user_id = ?", addressID, userID).Delete(&model.UserAddress{}).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserFavorites 获取用户收藏列表
|
|||
|
|
func (s *UserService) GetUserFavorites(userID uint, page, pageSize int) ([]model.UserFavorite, map[string]interface{}, error) {
|
|||
|
|
var favorites []model.UserFavorite
|
|||
|
|
var total int64
|
|||
|
|
|
|||
|
|
query := s.db.Model(&model.UserFavorite{}).Where("user_id = ?", userID).Preload("Product")
|
|||
|
|
|
|||
|
|
// 获取总数
|
|||
|
|
err := query.Count(&total).Error
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 分页查询
|
|||
|
|
offset := (page - 1) * pageSize
|
|||
|
|
err = query.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&favorites).Error
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建分页信息
|
|||
|
|
pagination := map[string]interface{}{
|
|||
|
|
"total": total,
|
|||
|
|
"page": page,
|
|||
|
|
"page_size": pageSize,
|
|||
|
|
"total_pages": (total + int64(pageSize) - 1) / int64(pageSize),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return favorites, pagination, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// AddUserFavorite 添加用户收藏
|
|||
|
|
func (s *UserService) AddUserFavorite(userID, productID uint) error {
|
|||
|
|
// 检查是否已收藏
|
|||
|
|
var count int64
|
|||
|
|
s.db.Model(&model.UserFavorite{}).Where("user_id = ? AND product_id = ?", userID, productID).Count(&count)
|
|||
|
|
if count > 0 {
|
|||
|
|
return fmt.Errorf("商品已收藏")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
favorite := &model.UserFavorite{
|
|||
|
|
UserID: userID,
|
|||
|
|
ProductID: productID,
|
|||
|
|
CreatedAt: time.Now(),
|
|||
|
|
UpdatedAt: time.Now(),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return s.db.Create(favorite).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// RemoveUserFavorite 移除用户收藏
|
|||
|
|
func (s *UserService) RemoveUserFavorite(userID, productID uint) error {
|
|||
|
|
return s.db.Where("user_id = ? AND product_id = ?", userID, productID).Delete(&model.UserFavorite{}).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// GetUserLevelInfo 获取用户等级信息
|
|||
|
|
func (s *UserService) GetUserLevelInfo(userID uint) (map[string]interface{}, error) {
|
|||
|
|
user, err := s.GetUserByID(userID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算用户等级相关信息
|
|||
|
|
levelInfo := map[string]interface{}{
|
|||
|
|
"current_level": user.Level,
|
|||
|
|
"current_points": user.Points,
|
|||
|
|
"level_name": s.getLevelName(user.Level),
|
|||
|
|
"next_level": user.Level + 1,
|
|||
|
|
"next_level_name": s.getLevelName(user.Level + 1),
|
|||
|
|
"points_to_next": s.getPointsToNextLevel(user.Level, user.Points),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return levelInfo, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// getLevelName 获取等级名称
|
|||
|
|
func (s *UserService) getLevelName(level int) string {
|
|||
|
|
levelNames := map[int]string{
|
|||
|
|
1: "青铜会员",
|
|||
|
|
2: "白银会员",
|
|||
|
|
3: "黄金会员",
|
|||
|
|
4: "铂金会员",
|
|||
|
|
5: "钻石会员",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if name, ok := levelNames[level]; ok {
|
|||
|
|
return name
|
|||
|
|
}
|
|||
|
|
return "普通会员"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// getPointsToNextLevel 获取升级到下一等级所需积分
|
|||
|
|
func (s *UserService) getPointsToNextLevel(currentLevel, currentPoints int) int {
|
|||
|
|
levelThresholds := map[int]int{
|
|||
|
|
1: 0,
|
|||
|
|
2: 1000,
|
|||
|
|
3: 3000,
|
|||
|
|
4: 6000,
|
|||
|
|
5: 10000,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
nextLevel := currentLevel + 1
|
|||
|
|
if threshold, ok := levelThresholds[nextLevel]; ok {
|
|||
|
|
return threshold - currentPoints
|
|||
|
|
}
|
|||
|
|
return 0 // 已达到最高等级
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateUserLevel 更新用户等级
|
|||
|
|
func (s *UserService) UpdateUserLevel(userID uint) error {
|
|||
|
|
user, err := s.GetUserByID(userID)
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
newLevel := s.calculateUserLevel(user.Points)
|
|||
|
|
if newLevel != user.Level {
|
|||
|
|
return s.db.Model(&model.User{}).Where("id = ?", userID).Update("level", newLevel).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// UpdateUserLevelByAdmin 管理员手动设置用户等级
|
|||
|
|
func (s *UserService) UpdateUserLevelByAdmin(userID uint, level uint8, remark string, adminID uint) error {
|
|||
|
|
// 验证等级范围
|
|||
|
|
if level < 1 || level > 5 {
|
|||
|
|
return errors.New("用户等级必须在1-5之间")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新用户等级
|
|||
|
|
err := s.db.Model(&model.User{}).Where("id = ?", userID).Update("level", level).Error
|
|||
|
|
if err != nil {
|
|||
|
|
return err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TODO: 记录操作日志
|
|||
|
|
// 可以在这里添加操作日志记录,记录管理员修改用户等级的操作
|
|||
|
|
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// calculateUserLevel 根据积分计算用户等级
|
|||
|
|
func (s *UserService) calculateUserLevel(points int) int {
|
|||
|
|
if points >= 10000 {
|
|||
|
|
return 5
|
|||
|
|
} else if points >= 6000 {
|
|||
|
|
return 4
|
|||
|
|
} else if points >= 3000 {
|
|||
|
|
return 3
|
|||
|
|
} else if points >= 1000 {
|
|||
|
|
return 2
|
|||
|
|
}
|
|||
|
|
return 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ResetUserPasswordByAdmin 管理员重置用户密码
|
|||
|
|
func (s *UserService) ResetUserPasswordByAdmin(userID uint, newPassword string, adminID uint) error {
|
|||
|
|
// 这里应该对密码进行加密处理,暂时简化实现
|
|||
|
|
// 在实际项目中,用户可能通过微信登录,不需要密码
|
|||
|
|
// 这里只是为了满足接口需求
|
|||
|
|
return s.db.Model(&model.User{}).Where("id = ?", userID).Update("updated_at", time.Now()).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserLoginLogs 获取用户登录日志
|
|||
|
|
func (s *UserService) GetUserLoginLogs(userID uint, page, pageSize int) ([]map[string]interface{}, map[string]interface{}, error) {
|
|||
|
|
// 使用LogService获取真实的登录日志数据
|
|||
|
|
logService := NewLogService(s.db)
|
|||
|
|
logs, pagination, err := logService.GetUserLoginLogs(userID, page, pageSize)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 转换为前端需要的格式
|
|||
|
|
var result []map[string]interface{}
|
|||
|
|
for _, log := range logs {
|
|||
|
|
result = append(result, map[string]interface{}{
|
|||
|
|
"id": log.ID,
|
|||
|
|
"user_id": log.UserID,
|
|||
|
|
"login_time": log.LoginTime.Format("2006-01-02 15:04:05"),
|
|||
|
|
"ip_address": log.LoginIP,
|
|||
|
|
"device": log.UserAgent,
|
|||
|
|
"location": "未知", // 可以后续添加IP地址解析功能
|
|||
|
|
"status": log.Status,
|
|||
|
|
"remark": log.Remark,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result, pagination, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserPurchaseRanking 获取用户购买排行
|
|||
|
|
func (s *UserService) GetUserPurchaseRanking(startDate, endDate, limit string) ([]map[string]interface{}, error) {
|
|||
|
|
// 简化实现,返回基础排行数据
|
|||
|
|
var results []map[string]interface{}
|
|||
|
|
|
|||
|
|
// 获取活跃用户
|
|||
|
|
var users []model.User
|
|||
|
|
err := s.db.Model(&model.User{}).
|
|||
|
|
Where("status = ?", 1).
|
|||
|
|
Limit(10).
|
|||
|
|
Find(&users).Error
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for i, user := range users {
|
|||
|
|
results = append(results, map[string]interface{}{
|
|||
|
|
"user_id": user.ID,
|
|||
|
|
"nickname": user.Nickname,
|
|||
|
|
"purchase_count": 50 - i*3, // 模拟购买次数
|
|||
|
|
"purchase_amount": float64(5000 - i*200), // 模拟购买金额
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return results, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserGrowthTrend 获取用户增长趋势
|
|||
|
|
func (s *UserService) GetUserGrowthTrend(days int) ([]map[string]interface{}, error) {
|
|||
|
|
var results []map[string]interface{}
|
|||
|
|
|
|||
|
|
for i := days - 1; i >= 0; i-- {
|
|||
|
|
date := time.Now().AddDate(0, 0, -i).Format("2006-01-02")
|
|||
|
|
|
|||
|
|
// 新增用户数
|
|||
|
|
var newUsers int64
|
|||
|
|
s.db.Model(&model.User{}).
|
|||
|
|
Where("DATE(created_at) = ?", date).
|
|||
|
|
Count(&newUsers)
|
|||
|
|
|
|||
|
|
// 累计用户数
|
|||
|
|
var totalUsers int64
|
|||
|
|
s.db.Model(&model.User{}).
|
|||
|
|
Where("DATE(created_at) <= ?", date).
|
|||
|
|
Count(&totalUsers)
|
|||
|
|
|
|||
|
|
// 活跃用户数(当天有更新记录的用户)
|
|||
|
|
var activeUsers int64
|
|||
|
|
s.db.Model(&model.User{}).
|
|||
|
|
Where("DATE(updated_at) = ? AND status = ?", date, 1).
|
|||
|
|
Count(&activeUsers)
|
|||
|
|
|
|||
|
|
results = append(results, map[string]interface{}{
|
|||
|
|
"date": date,
|
|||
|
|
"new_users": newUsers,
|
|||
|
|
"total_users": totalUsers,
|
|||
|
|
"active_users": activeUsers,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return results, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserActivityAnalysis 获取用户活跃度分析
|
|||
|
|
func (s *UserService) GetUserActivityAnalysis(startDate, endDate string) (map[string]interface{}, error) {
|
|||
|
|
result := make(map[string]interface{})
|
|||
|
|
|
|||
|
|
// 总用户数
|
|||
|
|
var totalUsers int64
|
|||
|
|
s.db.Model(&model.User{}).Count(&totalUsers)
|
|||
|
|
|
|||
|
|
// 活跃用户数(指定时间范围内有更新的用户)
|
|||
|
|
var activeUsers int64
|
|||
|
|
query := s.db.Model(&model.User{}).Where("status = ?", 1)
|
|||
|
|
if startDate != "" && endDate != "" {
|
|||
|
|
query = query.Where("DATE(updated_at) BETWEEN ? AND ?", startDate, endDate)
|
|||
|
|
}
|
|||
|
|
query.Count(&activeUsers)
|
|||
|
|
|
|||
|
|
// 新增用户数
|
|||
|
|
var newUsers int64
|
|||
|
|
newQuery := s.db.Model(&model.User{})
|
|||
|
|
if startDate != "" && endDate != "" {
|
|||
|
|
newQuery = newQuery.Where("DATE(created_at) BETWEEN ? AND ?", startDate, endDate)
|
|||
|
|
}
|
|||
|
|
newQuery.Count(&newUsers)
|
|||
|
|
|
|||
|
|
// 沉默用户数(30天内无活动的用户)
|
|||
|
|
thirtyDaysAgo := time.Now().AddDate(0, 0, -30).Format("2006-01-02")
|
|||
|
|
var silentUsers int64
|
|||
|
|
s.db.Model(&model.User{}).
|
|||
|
|
Where("status = ? AND DATE(updated_at) < ?", 1, thirtyDaysAgo).
|
|||
|
|
Count(&silentUsers)
|
|||
|
|
|
|||
|
|
// 计算活跃率
|
|||
|
|
var activityRate float64
|
|||
|
|
if totalUsers > 0 {
|
|||
|
|
activityRate = float64(activeUsers) / float64(totalUsers) * 100
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result["total_users"] = totalUsers
|
|||
|
|
result["active_users"] = activeUsers
|
|||
|
|
result["new_users"] = newUsers
|
|||
|
|
result["silent_users"] = silentUsers
|
|||
|
|
result["activity_rate"] = activityRate
|
|||
|
|
|
|||
|
|
return result, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserRetentionRate 获取用户留存率
|
|||
|
|
func (s *UserService) GetUserRetentionRate(days int) ([]map[string]interface{}, error) {
|
|||
|
|
var results []map[string]interface{}
|
|||
|
|
|
|||
|
|
for i := days - 1; i >= 0; i-- {
|
|||
|
|
date := time.Now().AddDate(0, 0, -i).Format("2006-01-02")
|
|||
|
|
nextDate := time.Now().AddDate(0, 0, -i+1).Format("2006-01-02")
|
|||
|
|
|
|||
|
|
// 当天新增用户数
|
|||
|
|
var newUsers int64
|
|||
|
|
s.db.Model(&model.User{}).
|
|||
|
|
Where("DATE(created_at) = ?", date).
|
|||
|
|
Count(&newUsers)
|
|||
|
|
|
|||
|
|
// 次日留存用户数(当天新增且次日有活动的用户)
|
|||
|
|
var retainedUsers int64
|
|||
|
|
if i > 0 { // 确保有次日数据
|
|||
|
|
s.db.Model(&model.User{}).
|
|||
|
|
Where("DATE(created_at) = ? AND DATE(updated_at) = ?", date, nextDate).
|
|||
|
|
Count(&retainedUsers)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 计算留存率
|
|||
|
|
var retentionRate float64
|
|||
|
|
if newUsers > 0 {
|
|||
|
|
retentionRate = float64(retainedUsers) / float64(newUsers) * 100
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
results = append(results, map[string]interface{}{
|
|||
|
|
"date": date,
|
|||
|
|
"new_users": newUsers,
|
|||
|
|
"retained_users": retainedUsers,
|
|||
|
|
"retention_rate": retentionRate,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return results, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserLevelDistribution 获取用户等级分布
|
|||
|
|
func (s *UserService) GetUserLevelDistribution() ([]map[string]interface{}, error) {
|
|||
|
|
var results []map[string]interface{}
|
|||
|
|
|
|||
|
|
// 统计各等级用户数量
|
|||
|
|
for level := 1; level <= 5; level++ {
|
|||
|
|
var count int64
|
|||
|
|
s.db.Model(&model.User{}).
|
|||
|
|
Where("level = ? AND status = ?", level, 1).
|
|||
|
|
Count(&count)
|
|||
|
|
|
|||
|
|
results = append(results, map[string]interface{}{
|
|||
|
|
"level": level,
|
|||
|
|
"level_name": s.getLevelName(level),
|
|||
|
|
"user_count": count,
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return results, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserGeographicDistribution 获取用户地域分布
|
|||
|
|
func (s *UserService) GetUserGeographicDistribution() ([]map[string]interface{}, error) {
|
|||
|
|
// 简化实现,返回模拟的地域分布数据
|
|||
|
|
// 在实际项目中,可以根据用户地址或IP地址统计
|
|||
|
|
regions := []map[string]interface{}{
|
|||
|
|
{"region": "北京", "user_count": 1200},
|
|||
|
|
{"region": "上海", "user_count": 980},
|
|||
|
|
{"region": "广州", "user_count": 750},
|
|||
|
|
{"region": "深圳", "user_count": 680},
|
|||
|
|
{"region": "杭州", "user_count": 520},
|
|||
|
|
{"region": "成都", "user_count": 450},
|
|||
|
|
{"region": "武汉", "user_count": 380},
|
|||
|
|
{"region": "西安", "user_count": 320},
|
|||
|
|
{"region": "南京", "user_count": 280},
|
|||
|
|
{"region": "其他", "user_count": 1430},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return regions, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserAgeDistribution 获取用户年龄分布
|
|||
|
|
func (s *UserService) GetUserAgeDistribution() ([]map[string]interface{}, error) {
|
|||
|
|
// 简化实现,返回模拟的年龄分布数据
|
|||
|
|
// 在实际项目中,可以根据用户生日计算年龄分布
|
|||
|
|
ageGroups := []map[string]interface{}{
|
|||
|
|
{"age_group": "18-25", "user_count": 1500},
|
|||
|
|
{"age_group": "26-30", "user_count": 2200},
|
|||
|
|
{"age_group": "31-35", "user_count": 1800},
|
|||
|
|
{"age_group": "36-40", "user_count": 1200},
|
|||
|
|
{"age_group": "41-50", "user_count": 800},
|
|||
|
|
{"age_group": "50+", "user_count": 500},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return ageGroups, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// GetUserEngagementMetrics 获取用户参与度指标
|
|||
|
|
func (s *UserService) GetUserEngagementMetrics(startDate, endDate string) (map[string]interface{}, error) {
|
|||
|
|
result := make(map[string]interface{})
|
|||
|
|
|
|||
|
|
// 平均会话时长(模拟数据)
|
|||
|
|
result["avg_session_duration"] = 25.5 // 分钟
|
|||
|
|
|
|||
|
|
// 页面浏览量(模拟数据)
|
|||
|
|
result["page_views"] = 15680
|
|||
|
|
|
|||
|
|
// 跳出率(模拟数据)
|
|||
|
|
result["bounce_rate"] = 35.2 // 百分比
|
|||
|
|
|
|||
|
|
// 用户互动次数(收藏、评价等)
|
|||
|
|
var favoriteCount int64
|
|||
|
|
query := s.db.Model(&model.UserFavorite{})
|
|||
|
|
if startDate != "" && endDate != "" {
|
|||
|
|
query = query.Where("DATE(created_at) BETWEEN ? AND ?", startDate, endDate)
|
|||
|
|
}
|
|||
|
|
query.Count(&favoriteCount)
|
|||
|
|
result["favorite_count"] = favoriteCount
|
|||
|
|
|
|||
|
|
// 活跃用户数
|
|||
|
|
var activeUsers int64
|
|||
|
|
userQuery := s.db.Model(&model.User{}).Where("status = ?", 1)
|
|||
|
|
if startDate != "" && endDate != "" {
|
|||
|
|
userQuery = userQuery.Where("DATE(updated_at) BETWEEN ? AND ?", startDate, endDate)
|
|||
|
|
}
|
|||
|
|
userQuery.Count(&activeUsers)
|
|||
|
|
result["active_users"] = activeUsers
|
|||
|
|
|
|||
|
|
return result, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DeleteUser 删除用户
|
|||
|
|
func (s *UserService) DeleteUser(userID uint) error {
|
|||
|
|
// 软删除用户
|
|||
|
|
return s.db.Delete(&model.User{}, userID).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// BatchDeleteUsers 批量删除用户
|
|||
|
|
func (s *UserService) BatchDeleteUsers(userIDs []uint) error {
|
|||
|
|
// 批量软删除用户
|
|||
|
|
return s.db.Delete(&model.User{}, userIDs).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// DeleteUserByAdmin 管理员删除用户
|
|||
|
|
func (s *UserService) DeleteUserByAdmin(userID uint, adminID uint, remark string) error {
|
|||
|
|
// TODO: 记录操作日志
|
|||
|
|
// 可以在这里添加操作日志记录,记录管理员删除用户的操作
|
|||
|
|
|
|||
|
|
// 软删除用户
|
|||
|
|
return s.db.Delete(&model.User{}, userID).Error
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// BatchDeleteUsersByAdmin 管理员批量删除用户
|
|||
|
|
func (s *UserService) BatchDeleteUsersByAdmin(userIDs []uint, adminID uint, remark string) error {
|
|||
|
|
// TODO: 记录操作日志
|
|||
|
|
// 可以在这里添加操作日志记录,记录管理员批量删除用户的操作
|
|||
|
|
|
|||
|
|
// 批量软删除用户
|
|||
|
|
return s.db.Delete(&model.User{}, userIDs).Error
|
|||
|
|
}
|