feat: sale add create user

This commit is contained in:
zzw
2026-09-02 09:47:34 +08:00
parent ad4bc7de85
commit 540f74f9b7
39 changed files with 2023 additions and 282 deletions
+30 -28
View File
@@ -13,10 +13,8 @@ const (
SaleTypeAgentCorp uint8 = 2 // 销售商(法人)
SaleTypeAgentPerson uint8 = 3 // 销售商(个人)
SaleStatusPending uint8 = 9 // 待处理
SaleStatusApproved uint8 = 1 // 已通过
SaleStatusRejected uint8 = 2 // 未通过
SaleStatusDisabled uint8 = 3 // 禁用
SaleStatusEnabled uint8 = 1 // 开启
SaleStatusDisabled uint8 = 2 // 禁用
)
type RegionNames struct {
@@ -55,33 +53,35 @@ func (r *RegionNames) Scan(value interface{}) error {
}
type SaleCreate struct {
Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
SaleId int64 `gorm:"column:sale_id" json:"sale_id"`
Mobile string `gorm:"column:mobile" json:"mobile"`
Name string `gorm:"column:name" json:"name"`
IdCardFront string `gorm:"column:id_card_front" json:"id_card_front"`
IdCardBack string `gorm:"column:id_card_back" json:"id_card_back"`
BusinessLicense string `gorm:"column:business_license" json:"business_license"`
Region RegionNames `gorm:"column:region;type:json" json:"region"`
ProvinceId int64 `gorm:"column:province_id" json:"province_id"`
CityId int64 `gorm:"column:city_id" json:"city_id"`
DistrictId int64 `gorm:"column:district_id" json:"district_id"`
TerritoryId int64 `gorm:"column:territory_id" json:"territory_id"`
TerritoryName string `gorm:"column:territory_name" json:"territory_name"`
GroupId int64 `gorm:"column:group_id" json:"group_id"`
Address string `gorm:"column:address" json:"address"`
Status uint8 `gorm:"column:status" json:"status"`
Avatar string `gorm:"column:avatar" json:"avatar"`
Account string `gorm:"column:account" json:"account"`
Type uint8 `gorm:"column:type" json:"type"`
Sex uint8 `gorm:"column:sex" json:"sex"`
BirthDate string `gorm:"column:birth_date" json:"birth_date"`
AdminId int64 `gorm:"column:admin_id" json:"admin_id"`
AdminName string `gorm:"column:admin_name" json:"admin_name"`
Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
UserId int64 `gorm:"column:user_id" json:"user_id"`
SaleId int64 `gorm:"column:sale_id" json:"sale_id"`
Mobile string `gorm:"column:mobile" json:"mobile"`
Name string `gorm:"column:name" json:"name"`
IdCardFront string `gorm:"column:id_card_front" json:"id_card_front"`
IdCardBack string `gorm:"column:id_card_back" json:"id_card_back"`
BusinessLicense string `gorm:"column:business_license" json:"business_license"`
Region RegionNames `gorm:"column:region;type:json" json:"region"`
ProvinceId int64 `gorm:"column:province_id" json:"province_id"`
CityId int64 `gorm:"column:city_id" json:"city_id"`
DistrictId int64 `gorm:"column:district_id" json:"district_id"`
TerritoryId int64 `gorm:"column:territory_id" json:"territory_id"`
TerritoryName string `gorm:"column:territory_name" json:"territory_name"`
GroupId int64 `gorm:"column:group_id" json:"group_id"`
Address string `gorm:"column:address" json:"address"`
Status uint8 `gorm:"column:status" json:"status"`
Avatar string `gorm:"column:avatar" json:"avatar"`
Account string `gorm:"column:account" json:"account"`
Type uint8 `gorm:"column:type" json:"type"`
Sex uint8 `gorm:"column:sex" json:"sex"`
BirthDate utils.CustomTime `gorm:"column:birth_date;type:date" json:"birth_date"`
AdminId int64 `gorm:"column:admin_id" json:"admin_id"`
AdminName string `gorm:"column:admin_name" json:"admin_name"`
}
type SaleInfo struct {
Id int64 `gorm:"column:id" json:"id"`
UserId int64 `gorm:"column:user_id" json:"user_id"`
SaleId int64 `gorm:"column:sale_id" json:"sale_id"`
Mobile string `gorm:"column:mobile" json:"mobile"`
Name string `gorm:"column:name" json:"name"`
@@ -101,7 +101,7 @@ type SaleInfo struct {
Account string `gorm:"column:account" json:"account"`
Type uint8 `gorm:"column:type" json:"type"`
Sex uint8 `gorm:"column:sex" json:"sex"`
BirthDate string `gorm:"column:birth_date" json:"birth_date"`
BirthDate utils.CustomTime `gorm:"column:birth_date;type:date" json:"birth_date"`
Reason string `gorm:"column:reason" json:"reason"`
AdminId int64 `gorm:"column:admin_id" json:"admin_id"`
AdminName string `gorm:"column:admin_name" json:"admin_name"`
@@ -113,6 +113,8 @@ type SaleInfo struct {
type SaleStatusUpdate struct {
Id int64 `gorm:"column:id;primaryKey" json:"id"`
UserId int64 `gorm:"column:user_id" json:"user_id"`
Mobile string `gorm:"column:mobile" json:"mobile"`
Name string `gorm:"column:name" json:"name"`
Status uint8 `gorm:"column:status" json:"status"`
Reason string `gorm:"column:reason" json:"reason"`
+23 -8
View File
@@ -2,6 +2,7 @@ package logic
import (
"context"
"strconv"
"lone-services/pkg/modelbase"
"lone-services/pkg/utils"
@@ -43,16 +44,24 @@ func (l *CreateLogic) Create(in *sale.CreateReq) (*sale.Response, error) {
return failResponse(utils.ErrorNoLoginInfo), nil
}
encryptMobile, err := utils.EncryptPhone(req.Mobile)
if err != nil {
l.Errorf("encrypt mobile: %v", err)
identity, idErr := ensureSaleIdentity(l.ctx, l.svcCtx.UserSvcName, req.Mobile, req.Password)
if idErr != nil {
l.Errorf("sale ensure identity: %v", idErr)
if msg, ok := userRPCError(idErr); ok {
return outResponse(utils.Fail, msg), nil
}
return failResponse(utils.Fail), nil
}
if identity.GetUserId() < utils.NumberOne || identity.GetMobile() == utils.StringEmpty {
return failResponse(utils.Fail), nil
}
m := model.SaleModel{}.Init()
var existing dao.SaleStatusUpdate
if err := m.GetOne(modelbase.Params{Eq: map[string]string{"mobile": encryptMobile}}, &existing); err != nil {
l.Errorf("sale create check: %v", err)
if err := m.GetOne(modelbase.Params{
Eq: map[string]string{"user_id": strconv.FormatInt(identity.GetUserId(), utils.NumberTen)},
}, &existing); err != nil {
l.Errorf("sale create check user_id: %v", err)
return failResponse(utils.Fail), nil
}
if existing.Id > utils.NumberZero {
@@ -81,9 +90,15 @@ func (l *CreateLogic) Create(in *sale.CreateReq) (*sale.Response, error) {
return outResponse(utils.ErrorParams, "请选择区县"), nil
}
birthDate, bErr := utils.ParseDateOnly(req.BirthDate)
if bErr != nil {
return outResponse(utils.ErrorParams, "生日格式不正确"), nil
}
data := dao.SaleCreate{
UserId: identity.GetUserId(),
SaleId: req.SaleId,
Mobile: encryptMobile,
Mobile: identity.GetMobile(),
Name: req.Name,
IdCardFront: req.IdCardFront,
IdCardBack: req.IdCardBack,
@@ -96,11 +111,11 @@ func (l *CreateLogic) Create(in *sale.CreateReq) (*sale.Response, error) {
TerritoryName: territoryName,
GroupId: req.GroupId,
Address: req.Address,
Status: dao.SaleStatusApproved,
Status: dao.SaleStatusEnabled,
Account: req.Account,
Type: uint8(req.Type),
Sex: uint8(req.Sex),
BirthDate: req.BirthDate,
BirthDate: birthDate,
AdminId: adminInfo.ID,
AdminName: adminInfo.Name,
}
+24 -7
View File
@@ -51,12 +51,25 @@ func (l *EditLogic) Edit(in *sale.EditReq) (*sale.Response, error) {
return failResponse(utils.ErrorNotFund), nil
}
encryptMobile, err := utils.EncryptPhone(req.Mobile)
if err != nil {
l.Errorf("encrypt mobile: %v", err)
return failResponse(utils.Fail), nil
}
if encryptMobile != info.Mobile {
encryptMobile := info.Mobile
oldPlain, _ := utils.DecryptPhone(info.Mobile)
if req.Mobile != oldPlain {
if info.UserId < utils.NumberOne {
return outResponse(utils.Fail, "销售未绑定用户,无法修改手机号"), nil
}
updated, uErr := updateSaleUserMobile(l.ctx, l.svcCtx.UserSvcName, info.UserId, req.Mobile)
if uErr != nil {
l.Errorf("sale edit sync user mobile: %v", uErr)
if msg, ok := userRPCError(uErr); ok {
return outResponse(utils.Fail, msg), nil
}
return failResponse(utils.Fail), nil
}
encryptMobile = updated.GetMobile()
if encryptMobile == utils.StringEmpty {
return failResponse(utils.Fail), nil
}
var check dao.SaleStatusUpdate
if err := m.GetOne(modelbase.Params{Eq: map[string]string{"mobile": encryptMobile}}, &check); err != nil {
l.Errorf("sale edit mobile check: %v", err)
@@ -104,7 +117,11 @@ func (l *EditLogic) Edit(in *sale.EditReq) (*sale.Response, error) {
info.Address = req.Address
info.Type = uint8(req.Type)
info.Sex = uint8(req.Sex)
info.BirthDate = req.BirthDate
birthDate, bErr := utils.ParseDateOnly(req.BirthDate)
if bErr != nil {
return outResponse(utils.ErrorParams, "生日格式不正确"), nil
}
info.BirthDate = birthDate
info.Account = req.Account
info.AdminId = adminInfo.ID
info.AdminName = adminInfo.Name
+1 -1
View File
@@ -63,7 +63,7 @@ func fetchRegionNames(ctx context.Context, choreSvcName string, ids ...int64) (m
func querySaleNames(req validator.NamesValidator) ([]dao.SaleNameItem, error) {
w := modelbase.Params{
Eq: map[string]string{"status": strconv.Itoa(int(dao.SaleStatusApproved))},
Eq: map[string]string{"status": strconv.Itoa(int(dao.SaleStatusEnabled))},
Order: "id desc",
Like: map[string]string{},
}
@@ -74,7 +74,7 @@ func toSaleInfoData(info *dao.SaleInfo) *sale.InfoData {
Account: info.Account,
Type: uint32(info.Type),
Sex: uint32(info.Sex),
BirthDate: info.BirthDate,
BirthDate: info.BirthDate.DateString(),
Reason: info.Reason,
AdminId: info.AdminId,
AdminName: info.AdminName,
+1 -1
View File
@@ -53,7 +53,7 @@ func (l *ItemsLogic) Items(in *sale.ItemsReq) (*sale.Response, error) {
Like: map[string]string{},
In: map[string][]string{
"status": {
strconv.Itoa(int(dao.SaleStatusApproved)),
strconv.Itoa(int(dao.SaleStatusEnabled)),
strconv.Itoa(int(dao.SaleStatusDisabled)),
},
},
+32 -7
View File
@@ -43,12 +43,6 @@ func (l *StatusLogic) Status(in *sale.StatusReq) (*sale.Response, error) {
w := modelbase.Params{
Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)},
In: map[string][]string{
"status": {
strconv.Itoa(int(dao.SaleStatusApproved)),
strconv.Itoa(int(dao.SaleStatusDisabled)),
},
},
}
var info dao.SaleStatusUpdate
m := model.SaleModel{}.Init()
@@ -60,7 +54,38 @@ func (l *StatusLogic) Status(in *sale.StatusReq) (*sale.Response, error) {
return failResponse(utils.ErrorNotFund), nil
}
info.Status = uint8(req.Status)
newStatus := uint8(req.Status)
if newStatus == info.Status {
return okStringResponse(utils.StringEmpty), nil
}
if info.UserId > utils.NumberZero {
switch newStatus {
case dao.SaleStatusDisabled:
if _, err := revokeSaleUserClient(l.ctx, l.svcCtx.UserSvcName, info.UserId); err != nil {
l.Errorf("sale status revoke client: %v", err)
if msg, ok := userRPCError(err); ok {
return outResponse(utils.Fail, msg), nil
}
return failResponse(utils.Fail), nil
}
case dao.SaleStatusEnabled:
plainMobile, dErr := utils.DecryptPhone(info.Mobile)
if dErr != nil || plainMobile == utils.StringEmpty {
l.Errorf("sale status decrypt mobile: %v", dErr)
return failResponse(utils.Fail), nil
}
if _, err := reopenSaleUserClient(l.ctx, l.svcCtx.UserSvcName, plainMobile); err != nil {
l.Errorf("sale status reopen client: %v", err)
if msg, ok := userRPCError(err); ok {
return outResponse(utils.Fail, msg), nil
}
return failResponse(utils.Fail), nil
}
}
}
info.Status = newStatus
info.Reason = req.Reason
info.AdminId = adminInfo.ID
info.AdminName = adminInfo.Name
@@ -0,0 +1,62 @@
package logic
import (
"context"
"lone-services/pkg/rpcclient"
"lone-services/pkg/utils"
userpb "lone-services/rpc/user/pb"
"google.golang.org/grpc/status"
)
const saleClientCode = "sale_beauty"
func ensureSaleIdentity(ctx context.Context, userSvcName, mobile, password string) (*userpb.EnsureBizIdentityData, error) {
cli, err := rpcclient.Get(userSvcName)
if err != nil {
return nil, err
}
return userpb.NewUserClient(cli.Conn()).EnsureBizIdentity(ctx, &userpb.EnsureBizIdentityReq{
Mobile: mobile,
ClientCode: saleClientCode,
CredentialType: "password",
Secret: password,
})
}
func updateSaleUserMobile(ctx context.Context, userSvcName string, userId int64, mobile string) (*userpb.UpdateMobileData, error) {
cli, err := rpcclient.Get(userSvcName)
if err != nil {
return nil, err
}
return userpb.NewUserClient(cli.Conn()).UpdateMobile(ctx, &userpb.UpdateMobileReq{
UserId: userId,
Mobile: mobile,
})
}
func revokeSaleUserClient(ctx context.Context, userSvcName string, userId int64) (*userpb.RevokeBizClientData, error) {
cli, err := rpcclient.Get(userSvcName)
if err != nil {
return nil, err
}
return userpb.NewUserClient(cli.Conn()).RevokeBizClient(ctx, &userpb.RevokeBizClientReq{
UserId: userId,
ClientCode: saleClientCode,
})
}
func reopenSaleUserClient(ctx context.Context, userSvcName, mobile string) (*userpb.EnsureBizIdentityData, error) {
return ensureSaleIdentity(ctx, userSvcName, mobile, utils.StringEmpty)
}
func userRPCError(err error) (string, bool) {
if err == nil {
return utils.StringEmpty, false
}
if st, ok := status.FromError(err); ok {
return st.Message(), true
}
return err.Error(), true
}
@@ -13,6 +13,7 @@ type ServiceContext struct {
DB *gorm.DB
Prefix string
ChoreSvcName string
UserSvcName string
}
func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
@@ -20,11 +21,16 @@ func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext {
if choreSvc == utils.StringEmpty {
logx.Error("config services.chore empty")
}
userSvc := utils.GetConfigString("services.user")
if userSvc == utils.StringEmpty {
logx.Error("config services.user empty")
}
return &ServiceContext{
Config: c,
DB: db,
Prefix: utils.GetConfigString("mysql.prefix"),
ChoreSvcName: choreSvc,
UserSvcName: userSvc,
}
}