diff --git a/api/admin.crm.api b/api/admin.crm.api index 65aae374..50237c84 100644 --- a/api/admin.crm.api +++ b/api/admin.crm.api @@ -1,5 +1,6 @@ import "admin/crm/customerdomain/lead.api" import "admin/crm/customerdomain/customer.api" +import "admin/crm/customerdomain/registercode.api" import "admin/crm/market/media.api" import "admin/crm/market/store.api" import "admin/crm/market/mgm.api" diff --git a/api/admin/crm/customerdomain/registercode.api b/api/admin/crm/customerdomain/registercode.api new file mode 100644 index 00000000..064bd3f6 --- /dev/null +++ b/api/admin/crm/customerdomain/registercode.api @@ -0,0 +1,153 @@ +syntax = "v1" + +info( + title: "注册码管理" + desc: "注册码管理" + author: "MichaelHu" + email: "matrix-x@artisan-cloud.com" + version: "v1" +) + +@server( + group: admin/crm/customerdomain/registercode + prefix: /api/v1/admin/customerdomain + middleware: EmployeeJWTAuth +) + +service PowerX { + @doc "查询注册码" + @handler GetRegisterCode + get /register-codes/:id (GetRegisterCodeReqeuest) returns (GetRegisterCodeReply) + + @doc "获取注册码分页列表" + @handler ListRegisterCodesPage + get /register-codes/page-list (ListRegisterCodesPageRequest) returns (ListRegisterCodesPageReply) + + @doc "创建注册码" + @handler CreateRegisterCode + post /register-codes (CreateRegisterCodeRequest) returns (CreateRegisterCodeReply) + + @doc "批量创建注册码" + @handler GenerateRegisterCode + post /register-codes/generate (GenerateRegisterCodeRequest) returns (GenerateRegisterCodeReply) + + @doc "全量注册码" + @handler PutRegisterCode + put /register-codes/:id (PutRegisterCodeRequest) returns (PutRegisterCodeReply) + + @doc "增量注册码" + @handler PatchRegisterCode + patch /register-codes/:id (PatchRegisterCodeRequest) returns (PatchRegisterCodeReply) + + @doc "删除注册码" + @handler DeleteRegisterCode + delete /register-codes/:id (DeleteRegisterCodeRequest) returns (DeleteRegisterCodeReply) + +} + + +type ( + RegisterCode { + Id int64 `json:"id,optional"` + Code string `json:"code,optional"` + RegisterCustomerID int64 `json:"registerCustomerID,optional"` + ExpiredAt string `json:"expiredAt,optional"` + CreatedAt string `json:"createdAt,optional"` + } +) + +type ( + GetRegisterCodeReqeuest { + Id int64 `path:"id"` + } + + GetRegisterCodeReply { + RegisterCode *RegisterCode `json:"customer"` + } +) + +type ( + ListRegisterCodesPageRequest { + LikeName string `form:"likeName,optional"` + LikeMobile string `form:"likeMobile,optional"` + Sources []int `form:"sources,optional"` + Statuses []int `form:"statuses,optional"` + OrderBy string `form:"orderBy,optional"` + PageIndex int `form:"pageIndex,optional"` + PageSize int `form:"pageSize,optional"` + } + + ListRegisterCodesPageReply { + List []RegisterCode `json:"list,optional"` + PageIndex int `json:"pageIndex,optional"` + PageSize int `json:"pageSize,optional"` + Total int64 `json:"total,optional"` + } +) + +type ( + CreateRegisterCodeRequest { + RegisterCode + } + + CreateRegisterCodeReply { + RegisterCodeId int64 `json:"id"` + } +) + +type ( + GenerateRegisterCodeRequest { + BatchCount int `json:"batchCount"` + } + + GenerateRegisterCodeReply { + result bool `json:"result"` + } +) + +type PutRegisterCodeRequest { + RegisterCodeId int64 `path:"id"` + RegisterCode +} + +type PutRegisterCodeReply { + *RegisterCode +} + + +type ( + PatchRegisterCodeRequest { + RegisterCodeId int64 `path:"id"` + Name string `json:"name,optional"` + Email string `json:"email,optional"` + InviterId int64 `json:"inviterId,optional"` + Source int `json:"source,optional"` + Type int `json:"type,optional"` + IsActivated bool `json:"isActivated,optional,omitempty"` + } + + PatchRegisterCodeReply { + *RegisterCode + } +) + +type ( + DeleteRegisterCodeRequest { + Id int64 `path:"id"` + } + + DeleteRegisterCodeReply { + RegisterCodeId int64 `json:"id"` + } +) + +type ( + AssignRegisterCodeToEmployeeRequest { + Id string `path:"id"` + EmployeeId int64 `json:"employeeId"` + } + + AssignRegisterCodeToEmployeeReply { + RegisterCodeId int64 `json:"customerId"` + } +) \ No newline at end of file diff --git a/api/web/customerdomain/auth.api b/api/web/customerdomain/auth.api index bc1c6baa..663aff7c 100644 --- a/api/web/customerdomain/auth.api +++ b/api/web/customerdomain/auth.api @@ -26,6 +26,14 @@ service PowerX { @handler RegisterCustomerByPhone post /registerByPhone (CustomerRegisterByPhoneRequest) returns (CustomerRegisterByPhoneReply) + @doc "客户手机注册,邀请码机制" + @handler RegisterCustomerByPhoneInInviteCode + post /registerByPhone/invite/:code (CustomerRegisterByPhoneInInviteCodeRequest) returns (CustomerRegisterByPhoneReply) + + @doc "客户手机注册,注册码机制" + @handler RegisterCustomerByPhoneInRegisterCode + post /registerByPhone/register/:code (CustomerRegisterByPhoneInRegisterCodeRequest) returns (CustomerRegisterByPhoneReply) + } @@ -49,8 +57,18 @@ type ( CustomerRegisterByPhoneRequest { Phone string `json:"phone"` Password string `json:"password"` - VerifyCode string `json:"verifyCode"` - InviteCode string `json:"inviteCode,optional"` + VerifyCode string `json:"verifyCode,optional"` + } + + CustomerRegisterByPhoneInInviteCodeRequest{ + *CustomerRegisterByPhoneRequest + InviteCode string `path:"code,optional"` + + } + CustomerRegisterByPhoneInRegisterCodeRequest{ + *CustomerRegisterByPhoneRequest + RegisterCode string `path:"code,optional"` + } CustomerRegisterByPhoneReply { diff --git a/cmd/ctl/database/migrate/powerx.go b/cmd/ctl/database/migrate/powerx.go index 7424e8c3..2281dfa7 100644 --- a/cmd/ctl/database/migrate/powerx.go +++ b/cmd/ctl/database/migrate/powerx.go @@ -58,7 +58,10 @@ func (m *PowerMigrator) AutoMigrate() { _ = m.db.AutoMigrate(&infoorganizatoin.PivotCategoryToObject{}) // customer domain - _ = m.db.AutoMigrate(&customerdomain.Lead{}, &customerdomain.Contact{}, &customerdomain.Customer{}, &membership.Membership{}) + _ = m.db.AutoMigrate( + &customerdomain.Lead{}, &customerdomain.Contact{}, customerdomain.RegisterCode{}, + &customerdomain.Customer{}, &membership.Membership{}, + ) _ = m.db.AutoMigrate(&wechat.WechatOACustomer{}, &wechat.WechatMPCustomer{}, &wechat.WeWorkExternalContact{}) _ = m.db.AutoMigrate( &product.PivotProductToProductCategory{}, diff --git a/internal/handler/admin/crm/customerdomain/registercode/createregistercodehandler.go b/internal/handler/admin/crm/customerdomain/registercode/createregistercodehandler.go new file mode 100644 index 00000000..d2523e3e --- /dev/null +++ b/internal/handler/admin/crm/customerdomain/registercode/createregistercodehandler.go @@ -0,0 +1,28 @@ +package registercode + +import ( + "net/http" + + "PowerX/internal/logic/admin/crm/customerdomain/registercode" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func CreateRegisterCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.CreateRegisterCodeRequest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := registercode.NewCreateRegisterCodeLogic(r.Context(), svcCtx) + resp, err := l.CreateRegisterCode(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/admin/crm/customerdomain/registercode/deleteregistercodehandler.go b/internal/handler/admin/crm/customerdomain/registercode/deleteregistercodehandler.go new file mode 100644 index 00000000..d0463b16 --- /dev/null +++ b/internal/handler/admin/crm/customerdomain/registercode/deleteregistercodehandler.go @@ -0,0 +1,28 @@ +package registercode + +import ( + "net/http" + + "PowerX/internal/logic/admin/crm/customerdomain/registercode" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func DeleteRegisterCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.DeleteRegisterCodeRequest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := registercode.NewDeleteRegisterCodeLogic(r.Context(), svcCtx) + resp, err := l.DeleteRegisterCode(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/admin/crm/customerdomain/registercode/generateregistercodehandler.go b/internal/handler/admin/crm/customerdomain/registercode/generateregistercodehandler.go new file mode 100644 index 00000000..6fb2638d --- /dev/null +++ b/internal/handler/admin/crm/customerdomain/registercode/generateregistercodehandler.go @@ -0,0 +1,28 @@ +package registercode + +import ( + "net/http" + + "PowerX/internal/logic/admin/crm/customerdomain/registercode" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func GenerateRegisterCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GenerateRegisterCodeRequest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := registercode.NewGenerateRegisterCodeLogic(r.Context(), svcCtx) + resp, err := l.GenerateRegisterCode(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/admin/crm/customerdomain/registercode/getregistercodehandler.go b/internal/handler/admin/crm/customerdomain/registercode/getregistercodehandler.go new file mode 100644 index 00000000..4edf45ea --- /dev/null +++ b/internal/handler/admin/crm/customerdomain/registercode/getregistercodehandler.go @@ -0,0 +1,28 @@ +package registercode + +import ( + "net/http" + + "PowerX/internal/logic/admin/crm/customerdomain/registercode" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func GetRegisterCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetRegisterCodeReqeuest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := registercode.NewGetRegisterCodeLogic(r.Context(), svcCtx) + resp, err := l.GetRegisterCode(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/admin/crm/customerdomain/registercode/listregistercodespagehandler.go b/internal/handler/admin/crm/customerdomain/registercode/listregistercodespagehandler.go new file mode 100644 index 00000000..44fea3d1 --- /dev/null +++ b/internal/handler/admin/crm/customerdomain/registercode/listregistercodespagehandler.go @@ -0,0 +1,28 @@ +package registercode + +import ( + "net/http" + + "PowerX/internal/logic/admin/crm/customerdomain/registercode" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func ListRegisterCodesPageHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.ListRegisterCodesPageRequest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := registercode.NewListRegisterCodesPageLogic(r.Context(), svcCtx) + resp, err := l.ListRegisterCodesPage(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/admin/crm/customerdomain/registercode/patchregistercodehandler.go b/internal/handler/admin/crm/customerdomain/registercode/patchregistercodehandler.go new file mode 100644 index 00000000..7fd65f3d --- /dev/null +++ b/internal/handler/admin/crm/customerdomain/registercode/patchregistercodehandler.go @@ -0,0 +1,28 @@ +package registercode + +import ( + "net/http" + + "PowerX/internal/logic/admin/crm/customerdomain/registercode" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func PatchRegisterCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.PatchRegisterCodeRequest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := registercode.NewPatchRegisterCodeLogic(r.Context(), svcCtx) + resp, err := l.PatchRegisterCode(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/admin/crm/customerdomain/registercode/putregistercodehandler.go b/internal/handler/admin/crm/customerdomain/registercode/putregistercodehandler.go new file mode 100644 index 00000000..5f203922 --- /dev/null +++ b/internal/handler/admin/crm/customerdomain/registercode/putregistercodehandler.go @@ -0,0 +1,28 @@ +package registercode + +import ( + "net/http" + + "PowerX/internal/logic/admin/crm/customerdomain/registercode" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func PutRegisterCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.PutRegisterCodeRequest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := registercode.NewPutRegisterCodeLogic(r.Context(), svcCtx) + resp, err := l.PutRegisterCode(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 2e97b5ca..7eca11e9 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -9,6 +9,7 @@ import ( admincrmbusinessopportunity "PowerX/internal/handler/admin/crm/business/opportunity" admincrmcustomerdomaincustomer "PowerX/internal/handler/admin/crm/customerdomain/customer" admincrmcustomerdomainleader "PowerX/internal/handler/admin/crm/customerdomain/leader" + admincrmcustomerdomainregistercode "PowerX/internal/handler/admin/crm/customerdomain/registercode" admincrmmarketmedia "PowerX/internal/handler/admin/crm/market/media" admincrmmarketmgm "PowerX/internal/handler/admin/crm/market/mgm" admincrmmarketstore "PowerX/internal/handler/admin/crm/market/store" @@ -546,6 +547,50 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { rest.WithPrefix("/api/v1/admin/customerdomain"), ) + server.AddRoutes( + rest.WithMiddlewares( + []rest.Middleware{serverCtx.EmployeeJWTAuth}, + []rest.Route{ + { + Method: http.MethodGet, + Path: "/register-codes/:id", + Handler: admincrmcustomerdomainregistercode.GetRegisterCodeHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/register-codes/page-list", + Handler: admincrmcustomerdomainregistercode.ListRegisterCodesPageHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/register-codes", + Handler: admincrmcustomerdomainregistercode.CreateRegisterCodeHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/register-codes/generate", + Handler: admincrmcustomerdomainregistercode.GenerateRegisterCodeHandler(serverCtx), + }, + { + Method: http.MethodPut, + Path: "/register-codes/:id", + Handler: admincrmcustomerdomainregistercode.PutRegisterCodeHandler(serverCtx), + }, + { + Method: http.MethodPatch, + Path: "/register-codes/:id", + Handler: admincrmcustomerdomainregistercode.PatchRegisterCodeHandler(serverCtx), + }, + { + Method: http.MethodDelete, + Path: "/register-codes/:id", + Handler: admincrmcustomerdomainregistercode.DeleteRegisterCodeHandler(serverCtx), + }, + }..., + ), + rest.WithPrefix("/api/v1/admin/customerdomain"), + ) + server.AddRoutes( rest.WithMiddlewares( []rest.Middleware{serverCtx.EmployeeJWTAuth}, @@ -2078,6 +2123,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/registerByPhone", Handler: webcustomerauth.RegisterCustomerByPhoneHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/registerByPhone/invite/:code", + Handler: webcustomerauth.RegisterCustomerByPhoneInInviteCodeHandler(serverCtx), + }, + { + Method: http.MethodPost, + Path: "/registerByPhone/register/:code", + Handler: webcustomerauth.RegisterCustomerByPhoneInRegisterCodeHandler(serverCtx), + }, }, rest.WithPrefix("/api/v1/web/customer"), ) diff --git a/internal/handler/web/customer/auth/registercustomerbyphoneininvitecodehandler.go b/internal/handler/web/customer/auth/registercustomerbyphoneininvitecodehandler.go new file mode 100644 index 00000000..0710f14b --- /dev/null +++ b/internal/handler/web/customer/auth/registercustomerbyphoneininvitecodehandler.go @@ -0,0 +1,28 @@ +package auth + +import ( + "net/http" + + "PowerX/internal/logic/web/customer/auth" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func RegisterCustomerByPhoneInInviteCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.CustomerRegisterByPhoneInInviteCodeRequest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := auth.NewRegisterCustomerByPhoneInInviteCodeLogic(r.Context(), svcCtx) + resp, err := l.RegisterCustomerByPhoneInInviteCode(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/handler/web/customer/auth/registercustomerbyphoneinregistercodehandler.go b/internal/handler/web/customer/auth/registercustomerbyphoneinregistercodehandler.go new file mode 100644 index 00000000..9d3f40a0 --- /dev/null +++ b/internal/handler/web/customer/auth/registercustomerbyphoneinregistercodehandler.go @@ -0,0 +1,28 @@ +package auth + +import ( + "net/http" + + "PowerX/internal/logic/web/customer/auth" + "PowerX/internal/svc" + "PowerX/internal/types" + "github.com/zeromicro/go-zero/rest/httpx" +) + +func RegisterCustomerByPhoneInRegisterCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.CustomerRegisterByPhoneInRegisterCodeRequest + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + l := auth.NewRegisterCustomerByPhoneInRegisterCodeLogic(r.Context(), svcCtx) + resp, err := l.RegisterCustomerByPhoneInRegisterCode(&req) + if err != nil { + httpx.ErrorCtx(r.Context(), w, err) + } else { + httpx.OkJsonCtx(r.Context(), w, resp) + } + } +} diff --git a/internal/logic/admin/crm/customerdomain/registercode/createregistercodelogic.go b/internal/logic/admin/crm/customerdomain/registercode/createregistercodelogic.go new file mode 100644 index 00000000..92bd5852 --- /dev/null +++ b/internal/logic/admin/crm/customerdomain/registercode/createregistercodelogic.go @@ -0,0 +1,49 @@ +package registercode + +import ( + "PowerX/internal/model/crm/customerdomain" + "context" + "github.com/golang-module/carbon/v2" + + "PowerX/internal/svc" + "PowerX/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CreateRegisterCodeLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewCreateRegisterCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateRegisterCodeLogic { + return &CreateRegisterCodeLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *CreateRegisterCodeLogic) CreateRegisterCode(req *types.CreateRegisterCodeRequest) (resp *types.CreateRegisterCodeReply, err error) { + + code := TransformRequestToRegisterCode(req) + + err = l.svcCtx.PowerX.RegisterCode.CreateRegisterCode(l.ctx, code) + + return &types.CreateRegisterCodeReply{ + code.Id, + }, err + +} + +func TransformRequestToRegisterCode(req *types.CreateRegisterCodeRequest) *customerdomain.RegisterCode { + expiredAt := carbon.Parse(req.ExpiredAt).ToStdTime() + mdlRegisterCode := &customerdomain.RegisterCode{ + Code: req.Code, + RegisterCustomerID: req.RegisterCustomerID, + ExpiredAt: expiredAt, + } + mdlRegisterCode.Id = req.Id + return mdlRegisterCode +} diff --git a/internal/logic/admin/crm/customerdomain/registercode/deleteregistercodelogic.go b/internal/logic/admin/crm/customerdomain/registercode/deleteregistercodelogic.go new file mode 100644 index 00000000..c9fc8641 --- /dev/null +++ b/internal/logic/admin/crm/customerdomain/registercode/deleteregistercodelogic.go @@ -0,0 +1,30 @@ +package registercode + +import ( + "context" + + "PowerX/internal/svc" + "PowerX/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type DeleteRegisterCodeLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewDeleteRegisterCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteRegisterCodeLogic { + return &DeleteRegisterCodeLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *DeleteRegisterCodeLogic) DeleteRegisterCode(req *types.DeleteRegisterCodeRequest) (resp *types.DeleteRegisterCodeReply, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/internal/logic/admin/crm/customerdomain/registercode/generateregistercodelogic.go b/internal/logic/admin/crm/customerdomain/registercode/generateregistercodelogic.go new file mode 100644 index 00000000..08b8aa23 --- /dev/null +++ b/internal/logic/admin/crm/customerdomain/registercode/generateregistercodelogic.go @@ -0,0 +1,80 @@ +package registercode + +import ( + "PowerX/internal/model/crm/customerdomain" + "PowerX/internal/svc" + "PowerX/internal/types" + "PowerX/pkg/stringx" + "context" + "sync" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GenerateRegisterCodeLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGenerateRegisterCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GenerateRegisterCodeLogic { + return &GenerateRegisterCodeLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GenerateRegisterCodeLogic) GenerateRegisterCode(req *types.GenerateRegisterCodeRequest) (resp *types.GenerateRegisterCodeReply, err error) { + + if req.BatchCount <= 0 { + req.BatchCount = 3 + } + + if req.BatchCount > 500 { + req.BatchCount = 500 + } + + registerCodes := TransformRequestToBatchGenerateRegisterCode(req.BatchCount) + //fmt.Dump(registerCodes) + registerCodes, err = l.svcCtx.PowerX.RegisterCode.UpsertRegisterCodes(l.ctx, registerCodes) + + return &types.GenerateRegisterCodeReply{ + Result: true, + }, nil +} + +func TransformRequestToBatchGenerateRegisterCode(batchCount int) []*customerdomain.RegisterCode { + var wg sync.WaitGroup + batchRegisterCodes := make([]*customerdomain.RegisterCode, batchCount) + codeChan := make(chan string, batchCount) + + // 启动协程生成注册码 + for i := 0; i < batchCount; i++ { + wg.Add(1) + go func() { + defer wg.Done() + code := GenerateRegisterCode(6) + codeChan <- code + }() + } + + // 等待所有协程完成 + go func() { + wg.Wait() + close(codeChan) + }() + + // 从通道中读取生成的注册码 + for i := 0; i < batchCount; i++ { + code := <-codeChan + batchRegisterCodes[i] = &customerdomain.RegisterCode{Code: code} + } + + return batchRegisterCodes +} + +// GenerateRegisterCode 生成指定数量的随机注册码 +func GenerateRegisterCode(num int) string { + return stringx.GenerateRandomCode(num) +} diff --git a/internal/logic/admin/crm/customerdomain/registercode/getregistercodelogic.go b/internal/logic/admin/crm/customerdomain/registercode/getregistercodelogic.go new file mode 100644 index 00000000..349794ca --- /dev/null +++ b/internal/logic/admin/crm/customerdomain/registercode/getregistercodelogic.go @@ -0,0 +1,30 @@ +package registercode + +import ( + "context" + + "PowerX/internal/svc" + "PowerX/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GetRegisterCodeLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetRegisterCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRegisterCodeLogic { + return &GetRegisterCodeLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetRegisterCodeLogic) GetRegisterCode(req *types.GetRegisterCodeReqeuest) (resp *types.GetRegisterCodeReply, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/internal/logic/admin/crm/customerdomain/registercode/listregistercodespagelogic.go b/internal/logic/admin/crm/customerdomain/registercode/listregistercodespagelogic.go new file mode 100644 index 00000000..fe7a20f0 --- /dev/null +++ b/internal/logic/admin/crm/customerdomain/registercode/listregistercodespagelogic.go @@ -0,0 +1,30 @@ +package registercode + +import ( + "context" + + "PowerX/internal/svc" + "PowerX/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type ListRegisterCodesPageLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewListRegisterCodesPageLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListRegisterCodesPageLogic { + return &ListRegisterCodesPageLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *ListRegisterCodesPageLogic) ListRegisterCodesPage(req *types.ListRegisterCodesPageRequest) (resp *types.ListRegisterCodesPageReply, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/internal/logic/admin/crm/customerdomain/registercode/patchregistercodelogic.go b/internal/logic/admin/crm/customerdomain/registercode/patchregistercodelogic.go new file mode 100644 index 00000000..1c29e32c --- /dev/null +++ b/internal/logic/admin/crm/customerdomain/registercode/patchregistercodelogic.go @@ -0,0 +1,30 @@ +package registercode + +import ( + "context" + + "PowerX/internal/svc" + "PowerX/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type PatchRegisterCodeLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewPatchRegisterCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PatchRegisterCodeLogic { + return &PatchRegisterCodeLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *PatchRegisterCodeLogic) PatchRegisterCode(req *types.PatchRegisterCodeRequest) (resp *types.PatchRegisterCodeReply, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/internal/logic/admin/crm/customerdomain/registercode/putregistercodelogic.go b/internal/logic/admin/crm/customerdomain/registercode/putregistercodelogic.go new file mode 100644 index 00000000..8241b1f0 --- /dev/null +++ b/internal/logic/admin/crm/customerdomain/registercode/putregistercodelogic.go @@ -0,0 +1,30 @@ +package registercode + +import ( + "context" + + "PowerX/internal/svc" + "PowerX/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type PutRegisterCodeLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewPutRegisterCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PutRegisterCodeLogic { + return &PutRegisterCodeLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *PutRegisterCodeLogic) PutRegisterCode(req *types.PutRegisterCodeRequest) (resp *types.PutRegisterCodeReply, err error) { + // todo: add your logic here and delete this line + + return +} diff --git a/internal/logic/web/customer/auth/registercustomerbyphoneininvitecodelogic.go b/internal/logic/web/customer/auth/registercustomerbyphoneininvitecodelogic.go new file mode 100644 index 00000000..6688af2d --- /dev/null +++ b/internal/logic/web/customer/auth/registercustomerbyphoneininvitecodelogic.go @@ -0,0 +1,112 @@ +package auth + +import ( + "PowerX/internal/model" + "PowerX/internal/model/crm/customerdomain" + "PowerX/internal/model/crm/market" + "PowerX/internal/types/errorx" + "PowerX/pkg/securityx" + "context" + + "PowerX/internal/svc" + "PowerX/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type RegisterCustomerByPhoneInInviteCodeLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewRegisterCustomerByPhoneInInviteCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterCustomerByPhoneInInviteCodeLogic { + return &RegisterCustomerByPhoneInInviteCodeLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *RegisterCustomerByPhoneInInviteCodeLogic) RegisterCustomerByPhoneInInviteCode(req *types.CustomerRegisterByPhoneInInviteCodeRequest) (resp *types.CustomerRegisterByPhoneReply, err error) { + // 邀请注册机制 + if req.InviteCode == "" { + return nil, errorx.WithCause(errorx.ErrBadRequest, "公测阶段,需要邀请码") + } + + // check customer exist or not + exist := l.svcCtx.PowerX.Customer.CheckRegisterPhoneExist(l.ctx, req.Phone) + if exist { + return nil, errorx.WithCause(errorx.ErrBadRequest, "改手机号已经注册过") + } + + // hash password + hashedPassword := securityx.HashPassword(req.Password) + + // register customer by phone + customerSourceId := l.svcCtx.PowerX.DataDictionary.GetCachedDDId(l.ctx, model.TypeSourceChannel, model.ChannelDirect) + customerTypeId := l.svcCtx.PowerX.DataDictionary.GetCachedDDId(l.ctx, customerdomain.TypeCustomerType, customerdomain.CustomerPersonal) + + // upsert 客户 + uuid := securityx.GenerateUUID() + inviteCode := securityx.GenerateInviteCode(uuid) + customer := &customerdomain.Customer{ + Mobile: req.Phone, + Password: hashedPassword, + Source: customerSourceId, + Type: customerTypeId, + Uuid: uuid, + InviteCode: inviteCode, + IsActivated: true, + } + + // 创建新注册用户 + err = l.svcCtx.PowerX.Customer.CreateCustomer(l.ctx, customer) + if err != nil { + return nil, errorx.WithCause(errorx.ErrCreateObject, "创建注册客户失败") + } + + // 如果邀请码存在,需要绑定邀请人的UUID + var record *market.InviteRecord + if req.InviteCode != "" { + customer, record, err = l.BindCustomerByInviteCode(l.ctx, req.InviteCode, customer) + if err != nil { + return nil, errorx.WithCause(errorx.ErrBadRequest, "邀请码无效") + } + } + + // 更新邀请记录的受邀者的ID + if req.InviteCode != "" { + record.InviteeID = customer.Id + l.svcCtx.PowerX.MGM.UpdateInviteRecord(l.ctx, record) + } + + return &types.CustomerRegisterByPhoneReply{ + CustomerId: customer.Id, + }, nil +} + +func (l *RegisterCustomerByPhoneInInviteCodeLogic) BindCustomerByInviteCode(ctx context.Context, + inviteCode string, customer *customerdomain.Customer, +) (*customerdomain.Customer, *market.InviteRecord, error) { + + // 通过邀请码,获取邀请人 + inviter, err := l.svcCtx.PowerX.Customer.GetCustomerByInviteCode(ctx, inviteCode) + if err != nil { + return nil, nil, err + } + + // 保存邀请记录 + // 使用默认的MGM规则,直系关系 + mgmSceneId := l.svcCtx.PowerX.DataDictionary.GetCachedDDId(ctx, market.TypeMGMScene, market.MGMSceneDirectRecruitment) + inviteCode = securityx.GenerateInviteCode(inviter.Uuid) + record, err := l.svcCtx.PowerX.MGM.CreateInviteRecord(ctx, inviter, customer, inviteCode, mgmSceneId) + + // 绑定邀请人和注册人的关系 + customer.InviterId = inviter.Id + if err != nil { + return nil, nil, err + } + + return customer, record, err +} diff --git a/internal/logic/web/customer/auth/registercustomerbyphoneinregistercodelogic.go b/internal/logic/web/customer/auth/registercustomerbyphoneinregistercodelogic.go new file mode 100644 index 00000000..80f01339 --- /dev/null +++ b/internal/logic/web/customer/auth/registercustomerbyphoneinregistercodelogic.go @@ -0,0 +1,79 @@ +package auth + +import ( + "PowerX/internal/model" + "PowerX/internal/model/crm/customerdomain" + "PowerX/internal/types/errorx" + "PowerX/pkg/securityx" + "context" + + "PowerX/internal/svc" + "PowerX/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type RegisterCustomerByPhoneInRegisterCodeLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewRegisterCustomerByPhoneInRegisterCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterCustomerByPhoneInRegisterCodeLogic { + return &RegisterCustomerByPhoneInRegisterCodeLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *RegisterCustomerByPhoneInRegisterCodeLogic) RegisterCustomerByPhoneInRegisterCode(req *types.CustomerRegisterByPhoneInRegisterCodeRequest) (resp *types.CustomerRegisterByPhoneReply, err error) { + // 限量注册机制 + if req.RegisterCode == "" { + return nil, errorx.WithCause(errorx.ErrBadRequest, "公测阶段,需要注册码") + } + + record, err := l.svcCtx.PowerX.RegisterCode.GetRegisterCodeByCode(l.ctx, req.RegisterCode) + if err != nil { + return nil, errorx.WithCause(errorx.ErrBadRequest, "注册码未找到") + } + if record == nil { + return nil, errorx.WithCause(errorx.ErrBadRequest, "注册码无效") + } + + // check customer exist or not + exist := l.svcCtx.PowerX.Customer.CheckRegisterPhoneExist(l.ctx, req.Phone) + if exist { + return nil, errorx.WithCause(errorx.ErrBadRequest, "改手机号已经注册过") + } + + // hash password + hashedPassword := securityx.HashPassword(req.Password) + + // register customer by phone + customerSourceId := l.svcCtx.PowerX.DataDictionary.GetCachedDDId(l.ctx, model.TypeSourceChannel, model.ChannelDirect) + customerTypeId := l.svcCtx.PowerX.DataDictionary.GetCachedDDId(l.ctx, customerdomain.TypeCustomerType, customerdomain.CustomerPersonal) + + // upsert 客户 + uuid := securityx.GenerateUUID() + inviteCode := securityx.GenerateInviteCode(uuid) + customer := &customerdomain.Customer{ + Mobile: req.Phone, + Password: hashedPassword, + Source: customerSourceId, + Type: customerTypeId, + Uuid: uuid, + InviteCode: inviteCode, + IsActivated: true, + } + + // 创建新注册用户 + err = l.svcCtx.PowerX.Customer.CreateCustomerByRegisterCode(l.ctx, customer, record) + if err != nil { + return nil, errorx.WithCause(errorx.ErrCreateObject, "创建注册客户失败") + } + + return &types.CustomerRegisterByPhoneReply{ + CustomerId: customer.Id, + }, nil +} diff --git a/internal/logic/web/customer/auth/registercustomerbyphonelogic.go b/internal/logic/web/customer/auth/registercustomerbyphonelogic.go index 79933bbd..2e932a3e 100644 --- a/internal/logic/web/customer/auth/registercustomerbyphonelogic.go +++ b/internal/logic/web/customer/auth/registercustomerbyphonelogic.go @@ -3,7 +3,6 @@ package auth import ( "PowerX/internal/model" "PowerX/internal/model/crm/customerdomain" - "PowerX/internal/model/crm/market" "PowerX/internal/svc" "PowerX/internal/types" "PowerX/internal/types/errorx" @@ -28,9 +27,6 @@ func NewRegisterCustomerByPhoneLogic(ctx context.Context, svcCtx *svc.ServiceCon } func (l *RegisterCustomerByPhoneLogic) RegisterCustomerByPhone(req *types.CustomerRegisterByPhoneRequest) (resp *types.CustomerRegisterByPhoneReply, err error) { - // todo: process code verify - - // todo: process phone verify // check customer exist or not exist := l.svcCtx.PowerX.Customer.CheckRegisterPhoneExist(l.ctx, req.Phone) @@ -58,53 +54,13 @@ func (l *RegisterCustomerByPhoneLogic) RegisterCustomerByPhone(req *types.Custom IsActivated: true, } - // 如果邀请码存在,需要绑定邀请人的UUID - var record *market.InviteRecord - if req.InviteCode != "" { - customer, record, err = l.BindCustomerByInviteCode(l.ctx, req.InviteCode, customer) - if err != nil { - return nil, errorx.WithCause(errorx.ErrBadRequest, "邀请码无效") - } - } - // 创建新注册用户 err = l.svcCtx.PowerX.Customer.CreateCustomer(l.ctx, customer) if err != nil { - return nil, errorx.WithCause(errorx.ErrCreateObject, "创建注册永固失败") - } - - // 更新邀请记录的受邀者的ID - if req.InviteCode != "" { - record.InviteeID = customer.Id - l.svcCtx.PowerX.MGM.UpdateInviteRecord(l.ctx, record) + return nil, errorx.WithCause(errorx.ErrCreateObject, "创建注册客户失败") } return &types.CustomerRegisterByPhoneReply{ CustomerId: customer.Id, }, nil } - -func (l *RegisterCustomerByPhoneLogic) BindCustomerByInviteCode(ctx context.Context, - inviteCode string, customer *customerdomain.Customer, -) (*customerdomain.Customer, *market.InviteRecord, error) { - - // 通过邀请码,获取邀请人 - inviter, err := l.svcCtx.PowerX.Customer.GetCustomerByInviteCode(ctx, inviteCode) - if err != nil { - return nil, nil, err - } - - // 保存邀请记录 - // 使用默认的MGM规则,直系关系 - mgmSceneId := l.svcCtx.PowerX.DataDictionary.GetCachedDDId(ctx, market.TypeMGMScene, market.MGMSceneDirectRecruitment) - inviteCode = securityx.GenerateInviteCode(inviter.Uuid) - record, err := l.svcCtx.PowerX.MGM.CreateInviteRecord(ctx, inviter, customer, inviteCode, mgmSceneId) - - // 绑定邀请人和注册人的关系 - customer.InviterId = inviter.Id - if err != nil { - return nil, nil, err - } - - return customer, record, err -} diff --git a/internal/model/crm/customerdomain/registercode.go b/internal/model/crm/customerdomain/registercode.go new file mode 100644 index 00000000..26075870 --- /dev/null +++ b/internal/model/crm/customerdomain/registercode.go @@ -0,0 +1,16 @@ +package customerdomain + +import ( + "PowerX/internal/model/powermodel" + "time" +) + +type RegisterCode struct { + powermodel.PowerModel + + Code string `gorm:"comment:邀请码;unique;index" json:"code"` + RegisterCustomerID int64 `gorm:"comment:注册客户ID" json:"registerCustomerID"` + ExpiredAt time.Time `gorm:"comment:到期时间" json:"expiredAt"` +} + +const RegisterCodeUniqueId = "code" diff --git a/internal/model/media/mediaresource.go b/internal/model/media/mediaresource.go index 4a020882..bb4ab038 100644 --- a/internal/model/media/mediaresource.go +++ b/internal/model/media/mediaresource.go @@ -11,6 +11,8 @@ type MediaResource struct { CustomerId int64 `gorm:"comment:客户Id; index" json:"customerId"` Filename string `gorm:"comment:名称" json:"filename"` Size int64 `gorm:"comment:尺寸" json:"size"` + Width int64 `gorm:"comment:宽度" json:"width"` + Height int64 `gorm:"comment:长度" json:"height"` Url string `gorm:"comment:url" json:"url"` BucketName string `gorm:"comment:Bucket名称" json:"bucketName"` IsLocalStored bool `gorm:"comment:是否本地存储" json:"isLocalStored"` diff --git a/internal/types/errorx/errors.go b/internal/types/errorx/errors.go index f154ef8c..a984c9a0 100644 --- a/internal/types/errorx/errors.go +++ b/internal/types/errorx/errors.go @@ -18,6 +18,7 @@ var ErrPhoneUnAuthorization = NewError(401, "UN_PHONE_AUTHORIZATION", "用户需 var ErrNotFoundObject = NewError(400, "OBJECT_NOT_FOUND", "对象未找到") var ErrCreateObject = NewError(400, "OBJECT_CREATE", "创建对象失败") +var ErrUpdateObject = NewError(400, "OBJECT_UPDATE", "更新对象失败") var ErrDuplicatedInsert = NewError(400, "OBJECT_DUPLICATED_INSERT", "有关键字段不能重复插入") var ErrDeleteObject = NewError(400, "OBJECT_DELETE", "删除对象失败") var ErrDeleteObjectNotFound = NewError(400, "OBJECT_NOT_FOUND", "未找到删除对象") diff --git a/internal/types/types.go b/internal/types/types.go index 54616f76..0c14a22b 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -962,6 +962,95 @@ type AssignCustomerToEmployeeReply struct { CustomerId int64 `json:"customerId"` } +type RegisterCode struct { + Id int64 `json:"id,optional"` + Code string `json:"code,optional"` + RegisterCustomerID int64 `json:"registerCustomerID,optional"` + ExpiredAt string `json:"expiredAt,optional"` + CreatedAt string `json:"createdAt,optional"` +} + +type GetRegisterCodeReqeuest struct { + Id int64 `path:"id"` +} + +type GetRegisterCodeReply struct { + RegisterCode *RegisterCode `json:"customer"` +} + +type ListRegisterCodesPageRequest struct { + LikeName string `form:"likeName,optional"` + LikeMobile string `form:"likeMobile,optional"` + Sources []int `form:"sources,optional"` + Statuses []int `form:"statuses,optional"` + OrderBy string `form:"orderBy,optional"` + PageIndex int `form:"pageIndex,optional"` + PageSize int `form:"pageSize,optional"` +} + +type ListRegisterCodesPageReply struct { + List []RegisterCode `json:"list,optional"` + PageIndex int `json:"pageIndex,optional"` + PageSize int `json:"pageSize,optional"` + Total int64 `json:"total,optional"` +} + +type CreateRegisterCodeRequest struct { + RegisterCode +} + +type CreateRegisterCodeReply struct { + RegisterCodeId int64 `json:"id"` +} + +type GenerateRegisterCodeRequest struct { + BatchCount int `json:"batchCount"` +} + +type GenerateRegisterCodeReply struct { + Result bool `json:"result"` +} + +type PutRegisterCodeRequest struct { + RegisterCodeId int64 `path:"id"` + RegisterCode +} + +type PutRegisterCodeReply struct { + *RegisterCode +} + +type PatchRegisterCodeRequest struct { + RegisterCodeId int64 `path:"id"` + Name string `json:"name,optional"` + Email string `json:"email,optional"` + InviterId int64 `json:"inviterId,optional"` + Source int `json:"source,optional"` + Type int `json:"type,optional"` + IsActivated bool `json:"isActivated,optional,omitempty"` +} + +type PatchRegisterCodeReply struct { + *RegisterCode +} + +type DeleteRegisterCodeRequest struct { + Id int64 `path:"id"` +} + +type DeleteRegisterCodeReply struct { + RegisterCodeId int64 `json:"id"` +} + +type AssignRegisterCodeToEmployeeRequest struct { + Id string `path:"id"` + EmployeeId int64 `json:"employeeId"` +} + +type AssignRegisterCodeToEmployeeReply struct { + RegisterCodeId int64 `json:"customerId"` +} + type ListMediasPageRequest struct { MediaTypes []int8 `form:"mediaTypes,optional"` Keys []string `form:"keys,optional"` @@ -3417,8 +3506,17 @@ type CustomerRegisterReply struct { type CustomerRegisterByPhoneRequest struct { Phone string `json:"phone"` Password string `json:"password"` - VerifyCode string `json:"verifyCode"` - InviteCode string `json:"inviteCode,optional"` + VerifyCode string `json:"verifyCode,optional"` +} + +type CustomerRegisterByPhoneInInviteCodeRequest struct { + *CustomerRegisterByPhoneRequest + InviteCode string `path:"code,optional"` +} + +type CustomerRegisterByPhoneInRegisterCodeRequest struct { + *CustomerRegisterByPhoneRequest + RegisterCode string `path:"code,optional"` } type CustomerRegisterByPhoneReply struct { diff --git a/internal/uc/powerx.go b/internal/uc/powerx.go index 4009e3b0..a2cf77fd 100644 --- a/internal/uc/powerx.go +++ b/internal/uc/powerx.go @@ -33,6 +33,7 @@ type PowerXUseCase struct { CustomerAuthorization *customerDomainUC.AuthorizationCustomerDomainUseCase Customer *customerDomainUC.CustomerUseCase Lead *customerDomainUC.LeadUseCase + RegisterCode *customerDomainUC.RegisterCodeUseCase Product *productUC.ProductUseCase ProductStatistics *productUC.ProductStatisticsUseCase ProductSpecific *productUC.ProductSpecificUseCase @@ -105,6 +106,7 @@ func NewPowerXUseCase(conf *config.Config) (uc *PowerXUseCase, clean func()) { uc.CustomerAuthorization = customerDomainUC.NewAuthorizationCustomerDomainUseCase(db) uc.Customer = customerDomainUC.NewCustomerUseCase(db) uc.Lead = customerDomainUC.NewLeadUseCase(db) + uc.RegisterCode = customerDomainUC.NewRegisterCodeUseCase(db) // 加载产品服务UseCase uc.ProductSpecific = productUC.NewProductSpecificUseCase(db) diff --git a/internal/uc/powerx/crm/customerdomain/customer.go b/internal/uc/powerx/crm/customerdomain/customer.go index e5f79341..32f586e5 100644 --- a/internal/uc/powerx/crm/customerdomain/customer.go +++ b/internal/uc/powerx/crm/customerdomain/customer.go @@ -97,6 +97,24 @@ func (uc *CustomerUseCase) CreateCustomer(ctx context.Context, customer *custome return nil } +func (uc *CustomerUseCase) CreateCustomerByRegisterCode(ctx context.Context, customer *customerdomain.Customer, registerCode *customerdomain.RegisterCode) error { + + err := uc.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + err := tx.Model(&customerdomain.Customer{}).Create(&customer).Error + if err != nil { + return err + } + + // 更新注册记录的受邀者的ID + registerCode.RegisterCustomerID = customer.Id + err = tx.Model(registerCode). + Update("register_customer_id", customer.Id).Error + return err + }) + + return err +} + func (uc *CustomerUseCase) UpsertCustomer(ctx context.Context, customer *customerdomain.Customer) (*customerdomain.Customer, error) { customers := []*customerdomain.Customer{customer} diff --git a/internal/uc/powerx/crm/customerdomain/registercode.go b/internal/uc/powerx/crm/customerdomain/registercode.go new file mode 100644 index 00000000..67fed9fa --- /dev/null +++ b/internal/uc/powerx/crm/customerdomain/registercode.go @@ -0,0 +1,166 @@ +package customerdomain + +import ( + "PowerX/internal/model/crm/customerdomain" + "PowerX/internal/model/powermodel" + "PowerX/internal/types" + "PowerX/internal/types/errorx" + "context" + "github.com/pkg/errors" + "gorm.io/gorm" + "strings" +) + +type RegisterCodeUseCase struct { + db *gorm.DB +} + +func NewRegisterCodeUseCase(db *gorm.DB) *RegisterCodeUseCase { + return &RegisterCodeUseCase{ + db: db, + } +} + +type FindManyRegisterCodesOption struct { + LikeName string + LikeMobile string + Statuses []int + Sources []int + OrderBy string + types.PageEmbedOption +} + +func (uc *RegisterCodeUseCase) buildFindQueryNoPage(db *gorm.DB, opt *FindManyRegisterCodesOption) *gorm.DB { + if opt.LikeName != "" { + db = db.Where("name LIKE ?", "%"+opt.LikeName+"%") + } + if opt.LikeMobile != "" { + db = db.Where("mobile LIKE ?", "%"+opt.LikeMobile+"%") + } + if len(opt.Statuses) > 0 { + db = db.Where("status IN ?", opt.Statuses) + } + if len(opt.Sources) > 0 { + db = db.Where("source IN ?", opt.Sources) + } + orderBy := "id desc" + if opt.OrderBy != "" { + orderBy = opt.OrderBy + "," + orderBy + } + db.Order(orderBy) + + return db +} + +func (uc *RegisterCodeUseCase) FindManyRegisterCodes(ctx context.Context, opt *FindManyRegisterCodesOption) (pageList types.Page[*customerdomain.RegisterCode], err error) { + var registerCodes []*customerdomain.RegisterCode + db := uc.db.WithContext(ctx).Model(&customerdomain.RegisterCode{}) + + db = uc.buildFindQueryNoPage(db, opt) + + var count int64 + if err := db.Count(&count).Error; err != nil { + panic(err) + } + + opt.DefaultPageIfNotSet() + if opt.PageIndex != 0 && opt.PageSize != 0 { + db.Offset((opt.PageIndex - 1) * opt.PageSize).Limit(opt.PageSize) + } + + if err := db. + //Debug(). + Find(®isterCodes).Error; err != nil { + panic(err) + } + + return types.Page[*customerdomain.RegisterCode]{ + List: registerCodes, + PageIndex: opt.PageIndex, + PageSize: opt.PageSize, + Total: count, + }, nil +} + +func (uc *RegisterCodeUseCase) CreateRegisterCode(ctx context.Context, registerCode *customerdomain.RegisterCode) error { + if err := uc.db.WithContext(ctx).Create(®isterCode).Error; err != nil { + if strings.Contains(err.Error(), "duplicate key value violates unique constraint") { + return errorx.WithCause(errorx.ErrDuplicatedInsert, "该对象不能重复创建") + } + panic(err) + } + return nil +} + +func (uc *RegisterCodeUseCase) UpsertRegisterCode(ctx context.Context, registerCode *customerdomain.RegisterCode) (*customerdomain.RegisterCode, error) { + + registerCodes := []*customerdomain.RegisterCode{registerCode} + + _, err := uc.UpsertRegisterCodes(ctx, registerCodes) + if err != nil { + panic(errors.Wrap(err, "upsert registerCode failed")) + } + + return registerCode, err +} + +func (uc *RegisterCodeUseCase) UpsertRegisterCodes(ctx context.Context, registerCodes []*customerdomain.RegisterCode) ([]*customerdomain.RegisterCode, error) { + + err := powermodel.UpsertModelsOnUniqueID(uc.db.WithContext(ctx), &customerdomain.RegisterCode{}, customerdomain.RegisterCodeUniqueId, registerCodes, nil, false) + + if err != nil { + panic(errors.Wrap(err, "batch upsert registerCodes failed")) + } + + return registerCodes, err +} + +func (uc *RegisterCodeUseCase) UpdateRegisterCode(ctx context.Context, id int64, registerCode *customerdomain.RegisterCode) error { + if err := uc.db.WithContext(ctx).Model(&customerdomain.RegisterCode{}). + //Debug(). + Where(id).Updates(®isterCode).Error; err != nil { + if strings.Contains(err.Error(), "duplicate key value violates unique constraint") { + return errorx.WithCause(errorx.ErrDuplicatedInsert, "该对象不能重复创建") + } + panic(err) + } + return nil +} + +func (uc *RegisterCodeUseCase) GetRegisterCodeByCode(ctx context.Context, code string) (*customerdomain.RegisterCode, error) { + var registerCode customerdomain.RegisterCode + if err := uc.db.WithContext(ctx). + //Debug(). + Where("code", code). + Where("register_customer_id=0"). + First(®isterCode). + Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, errorx.WithCause(errorx.ErrBadRequest, "未找到注册码") + } + panic(err) + } + return ®isterCode, nil +} + +func (uc *RegisterCodeUseCase) GetRegisterCode(ctx context.Context, id int64) (*customerdomain.RegisterCode, error) { + var registerCode customerdomain.RegisterCode + if err := uc.db.WithContext(ctx).First(®isterCode, id).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, errorx.WithCause(errorx.ErrBadRequest, "未找到注册码") + } + panic(err) + } + return ®isterCode, nil +} + +func (uc *RegisterCodeUseCase) DeleteRegisterCode(ctx context.Context, id int64) error { + result := uc.db.WithContext(ctx).Delete(&customerdomain.RegisterCode{}, id) + if err := result.Error; err != nil { + panic(err) + } + if result.RowsAffected == 0 { + return errorx.WithCause(errorx.ErrBadRequest, "未找到注册码") + } + return nil +} diff --git a/internal/uc/powerx/mediaresource.go b/internal/uc/powerx/mediaresource.go index 93b1cd52..92db15cb 100644 --- a/internal/uc/powerx/mediaresource.go +++ b/internal/uc/powerx/mediaresource.go @@ -217,6 +217,7 @@ func (uc *MediaResourceUseCase) MakeOSSResource(ctx context.Context, bucket stri filePath, _ := handle.Open() contentType := handle.Header.Get("Content-Type") info, err := uc.OSSClient.PutObject(ctx, bucket, objectName, filePath, handle.Size, minio.PutObjectOptions{ContentType: contentType}) + //fmt2.Dump(info) url, _ := httpx.AppendURIs(uc.OSSClient.EndpointURL().String(), bucket, info.Key) diff --git a/pkg/stringx/stringx.go b/pkg/stringx/stringx.go new file mode 100644 index 00000000..97e3de48 --- /dev/null +++ b/pkg/stringx/stringx.go @@ -0,0 +1,18 @@ +package stringx + +import ( + "math/rand" + "time" +) + +func GenerateRandomCode(num int) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + rand.Seed(time.Now().UnixNano()) + + code := make([]byte, num) + for i := 0; i < num; i++ { + code[i] = charset[rand.Intn(len(charset))] + } + + return string(code) +}