feat: PhotoWall 毕业照存储系统初始版本
后端: Go(Gin+GORM+MySQL+Redis) - 17张业务表(yz_pw_前缀), 自动迁移 - JWT认证(3小时) + 盐+MD5密码 + 图形验证码 - 班级CRUD/加入(8人姓名验证/邀请码)/审核/30天自动清理 - 系统配置(16项)/菜单管理(动态路由)/数据统计 - 文件MD5去重/数据隔离/账号封禁/敏感词DFA检测 前端: Vue3+Vite+Element Plus+Less+ECharts+FontAwesome - 动态路由(数据库菜单驱动) - 蓝白配色, H5响应式 - 登录/注册/忘记密码/个人中心 - 班级创建向导/详情/加入/列表 - 管理后台: 审核/配置/菜单/统计/用户/敏感词 数据库: MySQL 10.31.100.3:3306/photowall 管理员: hero920103 / 920103
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"photowall/internal/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UserService struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewUserService(db *gorm.DB) *UserService {
|
||||
return &UserService{db: db}
|
||||
}
|
||||
|
||||
// ProfileResp 用户完整资料
|
||||
type ProfileResp struct {
|
||||
User model.User `json:"user"`
|
||||
Contacts []model.UserContact `json:"contacts"`
|
||||
Education []model.EducationHistory `json:"education"`
|
||||
}
|
||||
|
||||
func (s *UserService) GetProfile(userID uint) (*ProfileResp, error) {
|
||||
var user model.User
|
||||
if err := s.db.First(&user, userID).Error; err != nil {
|
||||
return nil, errors.New("用户不存在")
|
||||
}
|
||||
var contacts []model.UserContact
|
||||
s.db.Where("user_id = ?", userID).Order("type, is_primary desc, id").Find(&contacts)
|
||||
var edu []model.EducationHistory
|
||||
s.db.Where("user_id = ?", userID).Order("start_year desc, id desc").Find(&edu)
|
||||
return &ProfileResp{User: user, Contacts: contacts, Education: edu}, nil
|
||||
}
|
||||
|
||||
type UpdateProfileReq struct {
|
||||
Nickname string `json:"nickname"`
|
||||
Bio string `json:"bio"`
|
||||
Avatar string `json:"avatar"`
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateProfile(userID uint, req *UpdateProfileReq) error {
|
||||
updates := map[string]interface{}{}
|
||||
if req.Nickname != "" {
|
||||
updates["nickname"] = req.Nickname
|
||||
}
|
||||
if req.Bio != "" {
|
||||
updates["bio"] = req.Bio
|
||||
}
|
||||
if req.Avatar != "" {
|
||||
updates["avatar"] = req.Avatar
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
}
|
||||
return s.db.Model(&model.User{}).Where("id = ?", userID).Updates(updates).Error
|
||||
}
|
||||
|
||||
// AddContact 添加联系方式,校验各类型数量上限
|
||||
func (s *UserService) AddContact(userID uint, contactType model.ContactType, value string, isPrimary bool) (*model.UserContact, error) {
|
||||
if value == "" {
|
||||
return nil, errors.New("联系方式不能为空")
|
||||
}
|
||||
max, ok := model.ContactMaxCount[contactType]
|
||||
if !ok {
|
||||
return nil, errors.New("不支持的联系方式类型")
|
||||
}
|
||||
var count int64
|
||||
s.db.Model(&model.UserContact{}).Where("user_id = ? AND type = ?", userID, contactType).Count(&count)
|
||||
if int(count) >= max {
|
||||
return nil, fmt.Errorf("%s 最多只能添加 %d 个", contactType, max)
|
||||
}
|
||||
// 如果设为主,先取消同类型其他主
|
||||
if isPrimary {
|
||||
s.db.Model(&model.UserContact{}).Where("user_id = ? AND type = ?", userID, contactType).Update("is_primary", false)
|
||||
}
|
||||
c := &model.UserContact{
|
||||
UserID: userID,
|
||||
Type: contactType,
|
||||
Value: value,
|
||||
IsPrimary: isPrimary,
|
||||
}
|
||||
if err := s.db.Create(c).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateContact(userID, contactID uint, value string, isPrimary *bool) error {
|
||||
var c model.UserContact
|
||||
if err := s.db.Where("id = ? AND user_id = ?", contactID, userID).First(&c).Error; err != nil {
|
||||
return errors.New("联系方式不存在")
|
||||
}
|
||||
if value != "" {
|
||||
c.Value = value
|
||||
}
|
||||
if isPrimary != nil && *isPrimary {
|
||||
s.db.Model(&model.UserContact{}).Where("user_id = ? AND type = ?", userID, c.Type).Update("is_primary", false)
|
||||
c.IsPrimary = true
|
||||
}
|
||||
return s.db.Save(&c).Error
|
||||
}
|
||||
|
||||
func (s *UserService) DeleteContact(userID, contactID uint) error {
|
||||
res := s.db.Where("id = ? AND user_id = ?", contactID, userID).Delete(&model.UserContact{})
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
return errors.New("联系方式不存在")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddEducation 添加学习履历
|
||||
func (s *UserService) AddEducation(userID uint, e *model.EducationHistory) error {
|
||||
e.UserID = userID
|
||||
e.ID = 0
|
||||
return s.db.Create(e).Error
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateEducation(userID, id uint, e *model.EducationHistory) error {
|
||||
res := s.db.Model(&model.EducationHistory{}).
|
||||
Where("id = ? AND user_id = ?", id, userID).
|
||||
Updates(map[string]interface{}{
|
||||
"school_id": e.SchoolID,
|
||||
"college_id": e.CollegeID,
|
||||
"class_id": e.ClassID,
|
||||
"school_name": e.SchoolName,
|
||||
"college_name": e.CollegeName,
|
||||
"major": e.Major,
|
||||
"degree": e.Degree,
|
||||
"start_year": e.StartYear,
|
||||
"end_year": e.EndYear,
|
||||
"description": e.Description,
|
||||
})
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
return errors.New("履历不存在")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *UserService) DeleteEducation(userID, id uint) error {
|
||||
res := s.db.Where("id = ? AND user_id = ?", id, userID).Delete(&model.EducationHistory{})
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
}
|
||||
if res.RowsAffected == 0 {
|
||||
return errors.New("履历不存在")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasEducation 检查用户是否有至少一条学习履历(创建班级前置条件)
|
||||
func (s *UserService) HasEducation(userID uint) bool {
|
||||
var count int64
|
||||
s.db.Model(&model.EducationHistory{}).Where("user_id = ?", userID).Count(&count)
|
||||
return count > 0
|
||||
}
|
||||
|
||||
// GetUserByID 公开用户信息(班级成员查看)
|
||||
func (s *UserService) GetUserByID(userID uint) (*model.User, error) {
|
||||
var u model.User
|
||||
if err := s.db.First(&u, userID).Error; err != nil {
|
||||
return nil, errors.New("用户不存在")
|
||||
}
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
// GetUserContacts 公开用户联系方式(同班同学可查看)
|
||||
func (s *UserService) GetUserContacts(userID uint) []model.UserContact {
|
||||
var list []model.UserContact
|
||||
s.db.Where("user_id = ?", userID).Order("type, is_primary desc").Find(&list)
|
||||
return list
|
||||
}
|
||||
Reference in New Issue
Block a user