package app import ( "errors" "github.com/go-chi/chi/v5" "github.com/go-chi/jwtauth/v5" "gorm.io/gorm" "strings" ) var tokenAuth *jwtauth.JWTAuth func init() { tokenAuth = jwtauth.New("HS256", []byte("secret"), nil) } type userInfo struct { id uint Name string PhoneNumber string Password string } func (u *userInfo) Bind(r *Request) error { if name, ok := r.Get("name"); ok && len(name) > 0 { u.Name = name } else { return NewError(1, "缺少用户名称") } if phoneNumber, ok := r.Get("phone_number"); ok && len(phoneNumber) > 0 { if len(phoneNumber) != 11 { return NewError(2, "手机号码格式错误") } u.PhoneNumber = phoneNumber } else { return NewError(2, "缺少手机号码") } if password, ok := r.Get("password"); ok && len(password) > 0 { if len(password) < 6 { return NewError(2, "密码太短") } u.Password = password } else { return NewError(2, "缺少密码") } return nil } // CreateUser 创建用户 func CreateUser(w *ResponseWriter, r *Request) { var ui userInfo if err := ui.Bind(r); err != nil { w.Error(err) return } var count int64 if err := DB.Model(&User{}).Where("phone_number = ?", ui.PhoneNumber).Count(&count).Error; err != nil { w.Error(err) return } if count > 0 { w.Error(NewError(2, "手机号码已经被使用了")) return } hash, err := HashPassword(ui.Password) if err != nil { LogError(err) w.Error(NewError(1, "加密密码失败")) return } user := User{ Name: ui.Name, PhoneNumber: ui.PhoneNumber, Password: hash, } if err := DB.Create(&user).Error; err != nil { w.Error(err) } else { w.Ok(ui, "创建用户成功") } } // UpdateUser 更新用户 func UpdateUser(w *ResponseWriter, r *Request) { id := chi.URLParam(r.Request, "id") if len(id) == 0 { w.Error(NewError(1, "缺少用户ID")) } var ui userInfo if err := ui.Bind(r); err != nil { w.Error(err) return } // 查询用户信息 var user User if err := DB.First(&user, "id = ?", id).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { err = NewError(1, "用户不存在") } w.Error(err) return } // 用户信息未发生变化 if ui.Name == user.Name && ui.PhoneNumber == user.PhoneNumber && CheckPasswordHash(ui.Password, user.Password) { w.Ok(nil, "操作成功") return } // 检查手机号码是否被使用 var count int64 if err := DB.Model(&User{}).Where("phone_number = ? AND id != ?", ui.PhoneNumber, id).Count(&count).Error; err != nil { w.Error(err) return } if count > 0 { w.Error(NewError(1, "手机号码已被使用")) return } // 保存用户信息 user.Name = ui.Name user.PhoneNumber = ui.PhoneNumber user.Password = ui.Password if err := DB.Save(&user).Error; err != nil { w.Error(err) } else { w.Ok(nil, "操作成功") } } // DeleteUser 删除用户 func DeleteUser(w *ResponseWriter, r *Request) { id := chi.URLParam(r.Request, "id") if len(id) == 0 { w.Error(NewError(1, "缺少用户ID")) } // 查询用户信息 var user User if err := DB.First(&user, "id = ?", id).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { err = NewError(1, "用户不存在") } w.Error(err) return } // 删除用户 if err := DB.Delete(&user).Error; err != nil { LogError(err) w.Error(NewError(1, "删除用户失败")) } else { w.Ok(nil, "删除用户成功") } } // ListUser 用户列表 func ListUser(w *ResponseWriter, r *Request) { search := func(db *gorm.DB) *gorm.DB { return db. Model(&User{}). Scopes(Search(r, "name", "name LIKE ?")). Scopes(Paginate(r)) } var userList []User var total int64 var err error if err = DB.Scopes(search).Count(&total).Error; err == nil { err = DB.Scopes(search).Find(&userList).Error } if err != nil { w.Error(err) } else { w.Ok(map[string]any{ "list": userList, "total": total, }) } } // Login 用户登录 func Login(w *ResponseWriter, r *Request) { var phoneNumber string var password string var token string var ok bool // 提交的手机号码 if phoneNumber, ok = r.Get("phone_number"); ok && len(phoneNumber) > 0 { if len(phoneNumber) != 11 { w.Error(NewError(2, "手机号码格式错误")) return } } else { w.Error(NewError(2, "缺少手机号码")) return } // 提交的登陆密码 if password, ok = r.Get("password"); ok && len(password) > 0 { if len(password) < 6 { w.Error(NewError(2, "密码太短")) return } } else { w.Error(NewError(2, "缺少密码")) return } // 提交的设备码 if token, ok = r.Get("token"); !ok || len(token) == 0 { w.Error(NewError(2, "缺少设备码")) return } // 查询用户是否存在 var user User err := DB.First(&user, "phone_number = ?", phoneNumber).Error if errors.Is(err, gorm.ErrRecordNotFound) { w.Error(NewError(1, "手机号码或密码错误")) } else if err != nil { w.Error(err) } else { if !CheckPasswordHash(password, user.Password) { w.Error(NewError(1, "手机号码或密码错误")) return } _, tokenString, err := tokenAuth.Encode(map[string]any{"uid": user.ID, "tkn": token}) if err != nil { LogError(err) w.Error(NewError(1, "登录失败")) return } w.Ok(map[string]any{ "user": user, "token": tokenString, }, "登录成功") } } // CreateGoods 创建商品 func CreateGoods(w *ResponseWriter, r *Request) { name := r.Value("name") price := r.Float32("price", 0) if len(name) == 0 { w.Error(NewError(1, "商品名称错误")) return } if price <= 0 { w.Error(NewError(2, "商品价格错误")) return } var goods Goods err := DB.First(&goods, "name = ?", name).Error if errors.Is(err, gorm.ErrRecordNotFound) { goods = Goods{ Name: name, Price: price, } err = DB.Create(&goods).Error if err != nil { w.Error(NewError(3, "创建商品失败")) } else { w.Ok(goods) } } else if err != nil { w.Error(err) } else { w.Error(NewError(5, "商品已经存在")) } } // UpdateGoods 更新产品信息 func UpdateGoods(w *ResponseWriter, r *Request) { name := r.Value("name") price := r.Float32("price", 0) id := uint(r.Uint64("id", 0)) if len(name) == 0 { w.Error(NewError(1, "商品名称错误")) return } if price <= 0 { w.Error(NewError(2, "商品价格错误")) return } var goods Goods err := DB.First(&goods, "id = ?", id).Error if errors.Is(err, gorm.ErrRecordNotFound) { w.Error(NewError(2, "商品不存在")) return } else if err != nil { w.Error(err) return } // 商品名称不能重复 err = DB.Where("id <> ?", id).First(&Goods{}, "name = ?", name).Error if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { w.Error(err) return } // 信息未改变 if goods.Name == name && goods.Price == price { w.Error(NewError(2, "数据未变化")) return } // 价格未改变 if goods.Price == price { if goods.Name != name { goods.Name = name err = DB.Save(&goods).Error if err != nil { w.Error(err) return } } w.Ok(goods, "修改成功") return } // 修改商品信息并记录价格变化 err = DB.Transaction(func(tx *gorm.DB) error { goods.Name = name goods.Price = price if err = tx.Save(&goods).Error; err != nil { return err } // 记录价格变化 return tx.Create(&Price{ GoodsID: goods.ID, Price: goods.Price, }).Error }) if err != nil { w.Error(err) } else { w.Ok(goods, "修改成功") } } // GetGoodsList 查询商品列表 func GetGoodsList(w *ResponseWriter, r *Request) { search := func(db *gorm.DB) *gorm.DB { return db. Model(&Goods{}). Scopes(TimeRange(r, "created_at")). Scopes(Paginate(r)). Scopes(Search(r, "name", "name LIKE ?")) } var goodsList []Goods var total int64 var err error if err = DB.Scopes(search).Count(&total).Error; err == nil { err = DB.Scopes(search).Find(&goodsList).Error } if err != nil { w.Error(err) } else { w.Ok(map[string]any{ "list": goodsList, "total": total, }) } } func GetGoodsPrices(w *ResponseWriter, r *Request) { id := uint(r.Uint64("id", 0)) var goods Goods if err := DB.Scopes(func(db *gorm.DB) *gorm.DB { var queries []string var args []any if val, ok := r.Get("start_time"); ok { queries = append(queries, "created_at >= ?") args = append(args, val) } if val, ok := r.Get("end_time"); ok { queries = append(queries, "created_at <= ?") args = append(args, val) } if len(queries) == 0 { return db.Preload("Prices") } args = append([]any{strings.Join(queries, " AND ")}, args...) return db.Preload("Prices", args...) }).First(&goods, "id = ?", id).Error; err != nil { w.Error(err) } else { w.Ok(goods) } }