diff --git a/bff/internal/response/user.go b/bff/internal/response/user.go index 8286970..d40b454 100644 --- a/bff/internal/response/user.go +++ b/bff/internal/response/user.go @@ -14,21 +14,41 @@ import ( type ctxKey string const ( - CtxUserId ctxKey = "X-User-Id" - CtxUserName ctxKey = "X-User-Name" - CtxRefresh ctxKey = "X-Refresh" - CtxClientIP ctxKey = "X-Client-Ip" - CtxUserAgent ctxKey = "X-User-Agent" + CtxUserId ctxKey = "X-User-Id" + CtxUserName ctxKey = "X-User-Name" + CtxRefresh ctxKey = "X-Refresh" + CtxClientIP ctxKey = "X-Client-Ip" + CtxUserAgent ctxKey = "X-User-Agent" + CtxClientCode ctxKey = "X-Client-Code" + CtxSaleId ctxKey = "X-Sale-Id" + CtxSaleName ctxKey = "X-Sale-Name" + CtxSaleMobile ctxKey = "X-Sale-Mobile" + CtxSaleProvince ctxKey = "X-Sale-Province" + CtxStoreId ctxKey = "X-Store-Id" + CtxStoreName ctxKey = "X-Store-Name" + CtxGroupId ctxKey = "X-Group-Id" + CtxGroupName ctxKey = "X-Group-Name" + CtxUserType ctxKey = "X-User-Type" ) type UserInfo struct { - ID int64 - Name string - RawUID string - Refresh string - ClientIP string - UserAgent string - Valid bool + ID int64 + Name string + RawUID string + Refresh string + ClientIP string + UserAgent string + Type string + ClientCode string + SaleId string + SaleName string + SaleMobile string + SaleProvince string + StoreId string + StoreName string + GroupId string + GroupName string + Valid bool } func GetUserInfo(ctx context.Context) UserInfo { @@ -37,13 +57,33 @@ func GetUserInfo(ctx context.Context) UserInfo { refresh, _ := ctx.Value(CtxRefresh).(string) clientIP, _ := ctx.Value(CtxClientIP).(string) userAgent, _ := ctx.Value(CtxUserAgent).(string) + userType, _ := ctx.Value(CtxUserType).(string) + clientCode, _ := ctx.Value(CtxClientCode).(string) + saleId, _ := ctx.Value(CtxSaleId).(string) + saleName, _ := ctx.Value(CtxSaleName).(string) + saleMobile, _ := ctx.Value(CtxSaleMobile).(string) + saleProvince, _ := ctx.Value(CtxSaleProvince).(string) + storeId, _ := ctx.Value(CtxStoreId).(string) + storeName, _ := ctx.Value(CtxStoreName).(string) + groupId, _ := ctx.Value(CtxGroupId).(string) + groupName, _ := ctx.Value(CtxGroupName).(string) info := UserInfo{ - RawUID: rawUID, - Name: name, - Refresh: refresh, - ClientIP: clientIP, - UserAgent: userAgent, + RawUID: rawUID, + Name: name, + Refresh: refresh, + ClientIP: clientIP, + UserAgent: userAgent, + Type: userType, + ClientCode: clientCode, + SaleId: saleId, + SaleName: saleName, + SaleMobile: saleMobile, + SaleProvince: saleProvince, + StoreId: storeId, + StoreName: storeName, + GroupId: groupId, + GroupName: groupName, } if rawUID == "" { return info @@ -58,7 +98,6 @@ func GetUserInfo(ctx context.Context) UserInfo { return info } -// getRealClientIP 获取真实客户端IP,优先 X‑Forwarded‑For,其次 X‑Real‑IP,最后 RemoteAddr func getRealClientIP(r *http.Request) string { xff := r.Header.Get("X-Forwarded-For") if xff != "" { @@ -79,10 +118,26 @@ func UserReadMiddleware(next http.HandlerFunc) http.HandlerFunc { newCtx = context.WithValue(newCtx, CtxRefresh, r.Header.Get("X-Refresh")) newCtx = context.WithValue(newCtx, CtxClientIP, getRealClientIP(r)) newCtx = context.WithValue(newCtx, CtxUserAgent, r.UserAgent()) + newCtx = context.WithValue(newCtx, CtxUserType, r.Header.Get("X-User-Type")) + newCtx = context.WithValue(newCtx, CtxClientCode, r.Header.Get("X-Client-Code")) + newCtx = context.WithValue(newCtx, CtxSaleId, r.Header.Get("X-Sale-Id")) + newCtx = context.WithValue(newCtx, CtxSaleName, r.Header.Get("X-Sale-Name")) + newCtx = context.WithValue(newCtx, CtxSaleMobile, r.Header.Get("X-Sale-Mobile")) + newCtx = context.WithValue(newCtx, CtxSaleProvince, r.Header.Get("X-Sale-Province")) + newCtx = context.WithValue(newCtx, CtxStoreId, r.Header.Get("X-Store-Id")) + newCtx = context.WithValue(newCtx, CtxStoreName, r.Header.Get("X-Store-Name")) + newCtx = context.WithValue(newCtx, CtxGroupId, r.Header.Get("X-Group-Id")) + newCtx = context.WithValue(newCtx, CtxGroupName, r.Header.Get("X-Group-Name")) next(w, r.WithContext(newCtx)) } } +func setMDIfNotEmpty(md metadata.MD, key, value string) { + if value != utils.StringEmpty { + md.Set(key, value) + } +} + func UserClientInterceptor(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { user := GetUserInfo(ctx) md := metadata.New(map[string]string{}) @@ -92,15 +147,27 @@ func UserClientInterceptor(ctx context.Context, method string, req, reply any, c md.Set("x-user-name", url.QueryEscape(user.Name)) } - if user.Refresh != utils.StringEmpty { - md.Set("x-refresh", user.Refresh) - } - if user.ClientIP != utils.StringEmpty { - md.Set("x-client-ip", user.ClientIP) - } + setMDIfNotEmpty(md, "x-refresh", user.Refresh) + setMDIfNotEmpty(md, "x-client-ip", user.ClientIP) if user.UserAgent != utils.StringEmpty { md.Set("x-user-agent", url.QueryEscape(user.UserAgent)) } + setMDIfNotEmpty(md, "x-user-type", user.Type) + setMDIfNotEmpty(md, "x-client-code", user.ClientCode) + setMDIfNotEmpty(md, "x-sale-id", user.SaleId) + if user.SaleName != utils.StringEmpty { + md.Set("x-sale-name", url.QueryEscape(user.SaleName)) + } + setMDIfNotEmpty(md, "x-sale-mobile", user.SaleMobile) + setMDIfNotEmpty(md, "x-sale-province", user.SaleProvince) + setMDIfNotEmpty(md, "x-store-id", user.StoreId) + if user.StoreName != utils.StringEmpty { + md.Set("x-store-name", url.QueryEscape(user.StoreName)) + } + setMDIfNotEmpty(md, "x-group-id", user.GroupId) + if user.GroupName != utils.StringEmpty { + md.Set("x-group-name", url.QueryEscape(user.GroupName)) + } ctx = metadata.NewOutgoingContext(ctx, md) return invoker(ctx, method, req, reply, cc, opts...) diff --git a/deploy/apisix/lua/auth.lua b/deploy/apisix/lua/auth.lua index e4cab0c..fefe3e7 100644 --- a/deploy/apisix/lua/auth.lua +++ b/deploy/apisix/lua/auth.lua @@ -110,7 +110,7 @@ function _M.access(conf, ctx) ngx.req.set_header("X-Store-Id", tostring(json.store_id)) end if json.sale_province then - ngx.req.set_header("X-Sale-Province", tostring(json.province)) + ngx.req.set_header("X-Sale-Province", tostring(json.sale_province)) end if json.sale_mobile then ngx.req.set_header("X-Sale-Mobile", tostring(json.sale_mobile)) @@ -130,6 +130,9 @@ function _M.access(conf, ctx) if json.type then ngx.req.set_header("X-User-Type", tostring(json.type)) end + if json.client_code then + ngx.req.set_header("X-Client-Code", tostring(json.client_code)) + end end ngx.req.set_header("X-Refresh", refresh or "") diff --git a/pkg/utils/jwt.go b/pkg/utils/jwt.go index 8c9871d..eee7b9e 100644 --- a/pkg/utils/jwt.go +++ b/pkg/utils/jwt.go @@ -2,76 +2,94 @@ package utils import ( "errors" - "github.com/golang-jwt/jwt/v4" + "fmt" "strconv" "time" + + "github.com/golang-jwt/jwt/v4" ) -type Jwt struct { +const ( + TokenTypeAccess = "access" + TokenTypeRefresh = "refresh" +) + +type JWT struct { Secret string - Ttl int + TTL int Issuer string } -type JwtInfo struct { - Id int `gorm:"column:id;type:int(11);primary_key;AUTO_INCREMENT" json:"id"` - NickName string `json:"nick_name"` - DepartmentId int `gorm:"column:department_id;type:int(11);default:0;comment:部门ID" json:"department_id"` - PostId int `gorm:"column:post_id;type:int(11);default:0;comment:岗位ID;NOT NULL" json:"post_id"` - LastTime CustomTime `gorm:"column:last_time;type:datetime;comment:最后一次登录时间" json:"last_time"` +func NewJWT(secret, issuer string, ttlSeconds int) (*JWT, error) { + if secret == "" { + return nil, errors.New("jwt secret empty") + } + if ttlSeconds < 1 { + return nil, errors.New("jwt ttl invalid") + } + return &JWT{ + Secret: secret, + TTL: ttlSeconds, + Issuer: issuer, + }, nil +} + +type Claims struct { + UserID int64 `json:"user_id"` + Name string `json:"name"` + Avatar string `json:"avatar"` + Mobile string `json:"mobile"` + Gender uint8 `json:"gender"` + Birthday string `json:"birthday"` + Type uint8 `json:"type"` // 1销售 2门店 3普通用户 + ClientCode string `json:"client_code"` + SaleId int64 `json:"sale_id,omitempty"` + StoreId int64 `json:"store_id,omitempty"` + TokenType string `json:"token_type"` // access | refresh jwt.RegisteredClaims } -type Token struct { - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` -} +func (j *JWT) Sign(claims Claims) (string, error) { + if j == nil { + return "", errors.New("jwt not initialized") + } + now := time.Now() + claims.Issuer = j.Issuer + claims.IssuedAt = jwt.NewNumericDate(now) + claims.ExpiresAt = jwt.NewNumericDate(now.Add(time.Duration(j.TTL) * time.Second)) + claims.ID = strconv.FormatInt(claims.UserID, NumberTen) -// GetToken 获取token -// -// access is true 获取登录token -// access is false 获取置换token -func (j *Jwt) GetToken(user JwtInfo, access bool) (string, error) { - j.setJwtConfig(access) - // 创建 Claims - user.Issuer = j.Issuer - user.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Duration(j.Ttl) * time.Second)) // 过期时间 - user.ID = strconv.Itoa(user.Id) - // 生成token对象 - token := jwt.NewWithClaims(jwt.SigningMethodHS256, user) - // 生成签名字符串 + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString([]byte(j.Secret)) } -// ParseToken 校验token -// -// access is true 校验登录token -// access is false 校验置换token -func (j *Jwt) ParseToken(tokenString string, access bool) (*JwtInfo, error) { - j.setJwtConfig(access) - // 解析token - token, err := jwt.ParseWithClaims(tokenString, &JwtInfo{}, func(token *jwt.Token) (interface{}, error) { +func (j *JWT) Parse(tokenString string) (*Claims, error) { + if j == nil { + return nil, errors.New("jwt not initialized") + } + token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } return []byte(j.Secret), nil }) - if err != nil { // 解析token失败 + if err != nil { return nil, err } - //对token对象中的Claim进行类型断言 - claims, ok := token.Claims.(*JwtInfo) - if ok && token.Valid { // 校验token - claims.LastTime = Now() - return claims, nil + claims, ok := token.Claims.(*Claims) + if !ok || !token.Valid { + return nil, errors.New("invalid token") } - return nil, errors.New("is check false") + return claims, nil } -func (j *Jwt) setJwtConfig(access bool) { - j.Ttl = GetConfigInt("jwt.access_ttl") - j.Issuer = GetConfigString("jwt.issuer") - j.Secret = GetConfigString("jwt.access_secret") - - if !access { - j.Ttl = GetConfigInt("jwt.refresh_ttl") - j.Secret = GetConfigString("jwt.refresh_secret") +func (j *JWT) ParseExpect(tokenString, expectType string) (*Claims, error) { + claims, err := j.Parse(tokenString) + if err != nil { + return nil, err } + if claims.TokenType != expectType { + return nil, fmt.Errorf("unexpected token type: %s", claims.TokenType) + } + return claims, nil } diff --git a/pkg/utils/loginInfo.go b/pkg/utils/loginInfo.go index 25a4919..5daaf57 100644 --- a/pkg/utils/loginInfo.go +++ b/pkg/utils/loginInfo.go @@ -27,78 +27,58 @@ type UserInfo struct { GroupId int64 // 分组ID GroupName string // 分组名称 Type uint8 // 用户类型 + ClientCode string Valid bool } +func firstMD(md metadata.MD, keys ...string) string { + for _, key := range keys { + vals := md.Get(key) + if len(vals) > NumberZero && vals[NumberZero] != StringEmpty { + return vals[NumberZero] + } + } + return StringEmpty +} + +func parseInt64MD(md metadata.MD, keys ...string) int64 { + raw := firstMD(md, keys...) + if raw == StringEmpty { + return NumberZero + } + v, _ := strconv.ParseInt(raw, NumberTen, NumberSixtyFourth) + return v +} + func GetUserFromCtx(ctx context.Context) UserInfo { md, ok := metadata.FromIncomingContext(ctx) if !ok { return UserInfo{Valid: false} } - uidList := md.Get("x-user-id") - nameList := md.Get("x-user-name") - refreshList := md.Get("x-refresh") - ipList := md.Get("x-client-ip") - userAgentList := md.Get("x-user-agent") - storeName := md.Get("x-store-name") - storeId := md.Get("x-store-id") - saleName := md.Get("x-sale-name") - saleId := md.Get("x-sale-id") - groupId := md.Get("x-group-id") - groupName := md.Get("x-group-name") - Type := md.Get("x-user-type") - province := md.Get("x-sale-province") - mobile := md.Get("x-sale-mobile") - - if len(refreshList) == NumberZero { - refreshList = md.Get("X-Refresh") - } - var userInfo UserInfo - if len(uidList) > NumberZero { - userInfo.RawUID = uidList[NumberZero] - } - if len(nameList) > NumberZero { - userInfo.Name = nameList[NumberZero] - } - if len(storeName) > NumberZero { - userInfo.StoreName = storeName[NumberZero] + userInfo := UserInfo{ + RawUID: firstMD(md, "x-user-id"), + Name: firstMD(md, "x-user-name"), + Refresh: firstMD(md, "x-refresh", "X-Refresh"), + ClientIP: firstMD(md, "x-client-ip"), + UserAgent: firstMD(md, "x-user-agent"), + StoreName: firstMD(md, "x-store-name"), + StoreId: parseInt64MD(md, "x-store-id"), + SaleName: firstMD(md, "x-sale-name"), + SaleId: parseInt64MD(md, "x-sale-id"), + SaleMobile: firstMD(md, "x-sale-mobile"), + SaleProvince: parseInt64MD(md, "x-sale-province"), + GroupId: parseInt64MD(md, "x-group-id"), + GroupName: firstMD(md, "x-group-name"), + ClientCode: firstMD(md, "x-client-code"), } - if len(groupName) > NumberZero { - userInfo.GroupName = groupName[NumberZero] - } - if len(Type) > NumberZero { - TypeInt, _ := strconv.ParseInt(Type[NumberZero], NumberTen, NumberSixtyFourth) - userInfo.Type = uint8(TypeInt) + if typeRaw := firstMD(md, "x-user-type"); typeRaw != StringEmpty { + typeInt, _ := strconv.ParseInt(typeRaw, NumberTen, NumberSixtyFourth) + userInfo.Type = uint8(typeInt) } - if len(storeId) > NumberZero { - userInfo.StoreId, _ = strconv.ParseInt(storeId[NumberZero], NumberTen, NumberSixtyFourth) - } - if len(saleName) > NumberZero { - userInfo.SaleName = saleName[NumberZero] - } - if len(province) > NumberZero { - userInfo.SaleProvince, _ = strconv.ParseInt(province[NumberZero], NumberTen, NumberSixtyFourth) - } - if len(mobile) > NumberZero { - userInfo.SaleMobile = mobile[NumberZero] - } - if len(saleId) > NumberZero { - userInfo.SaleId, _ = strconv.ParseInt(saleId[NumberZero], NumberTen, NumberSixtyFourth) - } - if len(groupId) > NumberZero { - userInfo.GroupId, _ = strconv.ParseInt(groupId[NumberZero], NumberTen, NumberSixtyFourth) - } - if len(refreshList) > NumberZero { - userInfo.Refresh = refreshList[NumberZero] - } - if len(ipList) > NumberZero { - userInfo.ClientIP = ipList[NumberZero] - } - if len(userAgentList) > NumberZero { - userInfo.UserAgent = userAgentList[NumberZero] + if userInfo.UserAgent != StringEmpty { userInfo.UserAgent, _ = url.QueryUnescape(userInfo.UserAgent) ua := user_agent.New(userInfo.UserAgent) userInfo.BrowserName, userInfo.BrowserVer = ua.Browser() @@ -116,6 +96,15 @@ func GetUserFromCtx(ctx context.Context) UserInfo { userName, _ := url.QueryUnescape(userInfo.Name) userInfo.ID = uid userInfo.Name = userName + if userInfo.SaleName != StringEmpty { + userInfo.SaleName, _ = url.QueryUnescape(userInfo.SaleName) + } + if userInfo.StoreName != StringEmpty { + userInfo.StoreName, _ = url.QueryUnescape(userInfo.StoreName) + } + if userInfo.GroupName != StringEmpty { + userInfo.GroupName, _ = url.QueryUnescape(userInfo.GroupName) + } userInfo.Valid = true return userInfo diff --git a/pkg/utils/time.go b/pkg/utils/time.go index c5f224e..1011801 100644 --- a/pkg/utils/time.go +++ b/pkg/utils/time.go @@ -217,3 +217,23 @@ func ParseCustomTime(s string) (CustomTime, error) { } return ct, nil } + +// ParseDateOnly 解析 YYYY-MM-DD;空串返回零值(写入 DB 为 NULL) +func ParseDateOnly(s string) (CustomTime, error) { + if s == "" { + return CustomTime{}, nil + } + t, err := time.ParseInLocation(time.DateOnly, s, AsiaShanghai) + if err != nil { + return CustomTime{}, fmt.Errorf("invalid date format: %s", s) + } + return CustomTime{Time: t}, nil +} + +// DateString 返回 YYYY-MM-DD;零值返回空串 +func (ct CustomTime) DateString() string { + if ct.IsZero() { + return "" + } + return ct.Time.Format(time.DateOnly) +} diff --git a/pkg/wechat/auth/client.go b/pkg/wechat/auth/client.go new file mode 100644 index 0000000..dd2be0c --- /dev/null +++ b/pkg/wechat/auth/client.go @@ -0,0 +1,13 @@ +package auth + +type Client struct { + AppID string + Secret string +} + +func NewClient(appID, secret string) *Client { + return &Client{ + AppID: appID, + Secret: secret, + } +} diff --git a/pkg/wechat/auth/phone.go b/pkg/wechat/auth/phone.go new file mode 100644 index 0000000..183cdba --- /dev/null +++ b/pkg/wechat/auth/phone.go @@ -0,0 +1,78 @@ +package auth + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + "lone-services/pkg/utils" +) + +const phoneNumberURL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber" + +type PhoneNumberRequest struct { + Code string `json:"code"` +} + +type PhoneInfo struct { + PhoneNumber string `json:"phoneNumber"` + PurePhoneNumber string `json:"purePhoneNumber"` + CountryCode string `json:"countryCode"` +} + +type PhoneNumberResult struct { + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` + PhoneInfo PhoneInfo `json:"phone_info"` +} + +type APIError struct { + ErrCode int + ErrMsg string +} + +func (e *APIError) Error() string { + return fmt.Sprintf("errcode=%d errmsg=%s", e.ErrCode, e.ErrMsg) +} + +func (c *Client) GetPhoneNumber(accessToken, code string) (*PhoneInfo, error) { + if accessToken == utils.StringEmpty { + return nil, fmt.Errorf("wechat access_token empty") + } + if code == utils.StringEmpty { + return nil, fmt.Errorf("wechat phone code empty") + } + + payload, err := json.Marshal(PhoneNumberRequest{Code: code}) + if err != nil { + return nil, err + } + + url := fmt.Sprintf("%s?access_token=%s", phoneNumberURL, accessToken) + client := &http.Client{Timeout: 10 * time.Second} + resp, err := client.Post(url, "application/json", bytes.NewReader(payload)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var result PhoneNumberResult + if err := json.Unmarshal(body, &result); err != nil { + return nil, err + } + if result.ErrCode != utils.NumberZero { + return nil, &APIError{ErrCode: result.ErrCode, ErrMsg: result.ErrMsg} + } + if result.PhoneInfo.PhoneNumber == utils.StringEmpty && result.PhoneInfo.PurePhoneNumber == utils.StringEmpty { + return nil, fmt.Errorf("wechat phone number empty") + } + return &result.PhoneInfo, nil +} diff --git a/pkg/wechat/auth/session.go b/pkg/wechat/auth/session.go new file mode 100644 index 0000000..90f6633 --- /dev/null +++ b/pkg/wechat/auth/session.go @@ -0,0 +1,50 @@ +package auth + +import ( + "fmt" + + "lone-services/pkg/utils" + + jsoniter "github.com/json-iterator/go" +) + +const code2SessionURL = "https://api.weixin.qq.com/sns/jscode2session" + +type Session struct { + OpenID string `json:"openid"` + UnionID string `json:"unionid"` + SessionKey string `json:"session_key"` + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` +} + +func (c *Client) Code2Session(code string) (*Session, error) { + if c == nil || c.AppID == utils.StringEmpty || c.Secret == utils.StringEmpty { + return nil, fmt.Errorf("wechat app config missing") + } + if code == utils.StringEmpty { + return nil, fmt.Errorf("wechat code empty") + } + + body, err := utils.Curl(code2SessionURL).SetData(map[string]string{ + "appid": c.AppID, + "secret": c.Secret, + "js_code": code, + "grant_type": "authorization_code", + }).Get("") + if err != nil { + return nil, err + } + + var session Session + if err := jsoniter.UnmarshalFromString(body, &session); err != nil { + return nil, err + } + if session.ErrCode != utils.NumberZero { + return nil, fmt.Errorf("wechat code2session: %d %s", session.ErrCode, session.ErrMsg) + } + if session.OpenID == utils.StringEmpty { + return nil, fmt.Errorf("wechat openid empty") + } + return &session, nil +} diff --git a/pkg/wechat/auth/token.go b/pkg/wechat/auth/token.go new file mode 100644 index 0000000..21078dc --- /dev/null +++ b/pkg/wechat/auth/token.go @@ -0,0 +1,45 @@ +package auth + +import ( + "fmt" + + "lone-services/pkg/utils" + + jsoniter "github.com/json-iterator/go" +) + +const accessTokenURL = "https://api.weixin.qq.com/cgi-bin/token" + +type AccessTokenResult struct { + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + ErrCode int `json:"errcode"` + ErrMsg string `json:"errmsg"` +} + +func (c *Client) AccessToken() (*AccessTokenResult, error) { + if c == nil || c.AppID == utils.StringEmpty || c.Secret == utils.StringEmpty { + return nil, fmt.Errorf("wechat app config missing") + } + + body, err := utils.Curl(accessTokenURL).SetData(map[string]string{ + "grant_type": "client_credential", + "appid": c.AppID, + "secret": c.Secret, + }).Get("") + if err != nil { + return nil, err + } + + var result AccessTokenResult + if err := jsoniter.UnmarshalFromString(body, &result); err != nil { + return nil, err + } + if result.ErrCode != utils.NumberZero { + return nil, fmt.Errorf("wechat access_token: %d %s", result.ErrCode, result.ErrMsg) + } + if result.AccessToken == utils.StringEmpty { + return nil, fmt.Errorf("wechat access_token empty") + } + return &result, nil +} diff --git a/rpc/sale/pb/sale.pb.go b/rpc/sale/pb/sale.pb.go index a317eb9..1e92daf 100644 --- a/rpc/sale/pb/sale.pb.go +++ b/rpc/sale/pb/sale.pb.go @@ -774,6 +774,50 @@ func (x *InfoReq) GetId() int64 { return 0 } +type InfoByUserIdReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InfoByUserIdReq) Reset() { + *x = InfoByUserIdReq{} + mi := &file_sale_sale_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InfoByUserIdReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InfoByUserIdReq) ProtoMessage() {} + +func (x *InfoByUserIdReq) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InfoByUserIdReq.ProtoReflect.Descriptor instead. +func (*InfoByUserIdReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{10} +} + +func (x *InfoByUserIdReq) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + type Region struct { state protoimpl.MessageState `protogen:"open.v1"` Province string `protobuf:"bytes,1,opt,name=province,proto3" json:"province,omitempty"` @@ -785,7 +829,7 @@ type Region struct { func (x *Region) Reset() { *x = Region{} - mi := &file_sale_sale_proto_msgTypes[10] + mi := &file_sale_sale_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -797,7 +841,7 @@ func (x *Region) String() string { func (*Region) ProtoMessage() {} func (x *Region) ProtoReflect() protoreflect.Message { - mi := &file_sale_sale_proto_msgTypes[10] + mi := &file_sale_sale_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -810,7 +854,7 @@ func (x *Region) ProtoReflect() protoreflect.Message { // Deprecated: Use Region.ProtoReflect.Descriptor instead. func (*Region) Descriptor() ([]byte, []int) { - return file_sale_sale_proto_rawDescGZIP(), []int{10} + return file_sale_sale_proto_rawDescGZIP(), []int{11} } func (x *Region) GetProvince() string { @@ -844,7 +888,7 @@ type GroupItem struct { func (x *GroupItem) Reset() { *x = GroupItem{} - mi := &file_sale_sale_proto_msgTypes[11] + mi := &file_sale_sale_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -856,7 +900,7 @@ func (x *GroupItem) String() string { func (*GroupItem) ProtoMessage() {} func (x *GroupItem) ProtoReflect() protoreflect.Message { - mi := &file_sale_sale_proto_msgTypes[11] + mi := &file_sale_sale_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -869,7 +913,7 @@ func (x *GroupItem) ProtoReflect() protoreflect.Message { // Deprecated: Use GroupItem.ProtoReflect.Descriptor instead. func (*GroupItem) Descriptor() ([]byte, []int) { - return file_sale_sale_proto_rawDescGZIP(), []int{11} + return file_sale_sale_proto_rawDescGZIP(), []int{12} } func (x *GroupItem) GetId() int64 { @@ -916,13 +960,14 @@ type InfoData struct { CreateTime string `protobuf:"bytes,26,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` UpdateTime string `protobuf:"bytes,27,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` Group *GroupItem `protobuf:"bytes,28,opt,name=group,proto3" json:"group,omitempty"` + UserId int64 `protobuf:"varint,29,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *InfoData) Reset() { *x = InfoData{} - mi := &file_sale_sale_proto_msgTypes[12] + mi := &file_sale_sale_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -934,7 +979,7 @@ func (x *InfoData) String() string { func (*InfoData) ProtoMessage() {} func (x *InfoData) ProtoReflect() protoreflect.Message { - mi := &file_sale_sale_proto_msgTypes[12] + mi := &file_sale_sale_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -947,7 +992,7 @@ func (x *InfoData) ProtoReflect() protoreflect.Message { // Deprecated: Use InfoData.ProtoReflect.Descriptor instead. func (*InfoData) Descriptor() ([]byte, []int) { - return file_sale_sale_proto_rawDescGZIP(), []int{12} + return file_sale_sale_proto_rawDescGZIP(), []int{13} } func (x *InfoData) GetId() int64 { @@ -1146,6 +1191,13 @@ func (x *InfoData) GetGroup() *GroupItem { return nil } +func (x *InfoData) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + type ItemsReq struct { state protoimpl.MessageState `protogen:"open.v1"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -1160,7 +1212,7 @@ type ItemsReq struct { func (x *ItemsReq) Reset() { *x = ItemsReq{} - mi := &file_sale_sale_proto_msgTypes[13] + mi := &file_sale_sale_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1172,7 +1224,7 @@ func (x *ItemsReq) String() string { func (*ItemsReq) ProtoMessage() {} func (x *ItemsReq) ProtoReflect() protoreflect.Message { - mi := &file_sale_sale_proto_msgTypes[13] + mi := &file_sale_sale_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1185,7 +1237,7 @@ func (x *ItemsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use ItemsReq.ProtoReflect.Descriptor instead. func (*ItemsReq) Descriptor() ([]byte, []int) { - return file_sale_sale_proto_rawDescGZIP(), []int{13} + return file_sale_sale_proto_rawDescGZIP(), []int{14} } func (x *ItemsReq) GetName() string { @@ -1241,7 +1293,7 @@ type StatusReq struct { func (x *StatusReq) Reset() { *x = StatusReq{} - mi := &file_sale_sale_proto_msgTypes[14] + mi := &file_sale_sale_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1253,7 +1305,7 @@ func (x *StatusReq) String() string { func (*StatusReq) ProtoMessage() {} func (x *StatusReq) ProtoReflect() protoreflect.Message { - mi := &file_sale_sale_proto_msgTypes[14] + mi := &file_sale_sale_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1266,7 +1318,7 @@ func (x *StatusReq) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusReq.ProtoReflect.Descriptor instead. func (*StatusReq) Descriptor() ([]byte, []int) { - return file_sale_sale_proto_rawDescGZIP(), []int{14} + return file_sale_sale_proto_rawDescGZIP(), []int{15} } func (x *StatusReq) GetId() int64 { @@ -1299,7 +1351,7 @@ type NamesByIdsReq struct { func (x *NamesByIdsReq) Reset() { *x = NamesByIdsReq{} - mi := &file_sale_sale_proto_msgTypes[15] + mi := &file_sale_sale_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1311,7 +1363,7 @@ func (x *NamesByIdsReq) String() string { func (*NamesByIdsReq) ProtoMessage() {} func (x *NamesByIdsReq) ProtoReflect() protoreflect.Message { - mi := &file_sale_sale_proto_msgTypes[15] + mi := &file_sale_sale_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1324,7 +1376,7 @@ func (x *NamesByIdsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use NamesByIdsReq.ProtoReflect.Descriptor instead. func (*NamesByIdsReq) Descriptor() ([]byte, []int) { - return file_sale_sale_proto_rawDescGZIP(), []int{15} + return file_sale_sale_proto_rawDescGZIP(), []int{16} } func (x *NamesByIdsReq) GetIds() []int64 { @@ -1344,7 +1396,7 @@ type NamesByIdsItem struct { func (x *NamesByIdsItem) Reset() { *x = NamesByIdsItem{} - mi := &file_sale_sale_proto_msgTypes[16] + mi := &file_sale_sale_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1356,7 +1408,7 @@ func (x *NamesByIdsItem) String() string { func (*NamesByIdsItem) ProtoMessage() {} func (x *NamesByIdsItem) ProtoReflect() protoreflect.Message { - mi := &file_sale_sale_proto_msgTypes[16] + mi := &file_sale_sale_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1369,7 +1421,7 @@ func (x *NamesByIdsItem) ProtoReflect() protoreflect.Message { // Deprecated: Use NamesByIdsItem.ProtoReflect.Descriptor instead. func (*NamesByIdsItem) Descriptor() ([]byte, []int) { - return file_sale_sale_proto_rawDescGZIP(), []int{16} + return file_sale_sale_proto_rawDescGZIP(), []int{17} } func (x *NamesByIdsItem) GetId() int64 { @@ -1395,7 +1447,7 @@ type NamesByIdsData struct { func (x *NamesByIdsData) Reset() { *x = NamesByIdsData{} - mi := &file_sale_sale_proto_msgTypes[17] + mi := &file_sale_sale_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1407,7 +1459,7 @@ func (x *NamesByIdsData) String() string { func (*NamesByIdsData) ProtoMessage() {} func (x *NamesByIdsData) ProtoReflect() protoreflect.Message { - mi := &file_sale_sale_proto_msgTypes[17] + mi := &file_sale_sale_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1420,7 +1472,7 @@ func (x *NamesByIdsData) ProtoReflect() protoreflect.Message { // Deprecated: Use NamesByIdsData.ProtoReflect.Descriptor instead. func (*NamesByIdsData) Descriptor() ([]byte, []int) { - return file_sale_sale_proto_rawDescGZIP(), []int{17} + return file_sale_sale_proto_rawDescGZIP(), []int{18} } func (x *NamesByIdsData) GetItems() []*NamesByIdsItem { @@ -1503,14 +1555,16 @@ const file_sale_sale_proto_rawDesc = "" + "idCardBack\x12)\n" + "\x10business_license\x18\x15 \x01(\tR\x0fbusinessLicense\"\x19\n" + "\aInfoReq\x12\x0e\n" + - "\x02id\x18\x01 \x01(\x03R\x02id\"T\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\"*\n" + + "\x0fInfoByUserIdReq\x12\x17\n" + + "\auser_id\x18\x01 \x01(\x03R\x06userId\"T\n" + "\x06Region\x12\x1a\n" + "\bprovince\x18\x01 \x01(\tR\bprovince\x12\x12\n" + "\x04city\x18\x02 \x01(\tR\x04city\x12\x1a\n" + "\bdistrict\x18\x03 \x01(\tR\bdistrict\"/\n" + "\tGroupItem\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + - "\x04name\x18\x02 \x01(\tR\x04name\"\xbf\x06\n" + + "\x04name\x18\x02 \x01(\tR\x04name\"\xd8\x06\n" + "\bInfoData\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x17\n" + "\asale_id\x18\x02 \x01(\x03R\x06saleId\x12\x16\n" + @@ -1547,7 +1601,8 @@ const file_sale_sale_proto_rawDesc = "" + "createTime\x12\x1f\n" + "\vupdate_time\x18\x1b \x01(\tR\n" + "updateTime\x12%\n" + - "\x05group\x18\x1c \x01(\v2\x0f.sale.GroupItemR\x05group\"\x94\x01\n" + + "\x05group\x18\x1c \x01(\v2\x0f.sale.GroupItemR\x05group\x12\x17\n" + + "\auser_id\x18\x1d \x01(\x03R\x06userId\"\x94\x01\n" + "\bItemsReq\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x12\n" + "\x04page\x18\x02 \x01(\rR\x04page\x12\x1b\n" + @@ -1565,7 +1620,7 @@ const file_sale_sale_proto_rawDesc = "" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\"<\n" + "\x0eNamesByIdsData\x12*\n" + - "\x05items\x18\x01 \x03(\v2\x14.sale.NamesByIdsItemR\x05items2\xa7\a\n" + + "\x05items\x18\x01 \x03(\v2\x14.sale.NamesByIdsItemR\x05items2\xde\a\n" + "\x04Sale\x12S\n" + "\n" + "GroupItems\x12\x13.sale.GroupItemsReq\x1a\x0e.sale.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\x12\x15/admin/v3/sales/group\x12U\n" + @@ -1580,7 +1635,8 @@ const file_sale_sale_proto_rawDesc = "" + "\x04Info\x12\r.sale.InfoReq\x1a\x0e.sale.Response\"\x1f\x82\xd3\xe4\x93\x02\x19:\x01*\x12\x14/admin/v3/sales/info\x12C\n" + "\x05Items\x12\x0e.sale.ItemsReq\x1a\x0e.sale.Response\"\x1a\x82\xd3\xe4\x93\x02\x14:\x01*\x12\x0f/admin/v3/sales\x12L\n" + "\x06Status\x12\x0f.sale.StatusReq\x1a\x0e.sale.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x1a\x16/admin/v3/sales/status\x12-\n" + - "\fInfoInternal\x12\r.sale.InfoReq\x1a\x0e.sale.InfoData\x127\n" + + "\fInfoInternal\x12\r.sale.InfoReq\x1a\x0e.sale.InfoData\x125\n" + + "\fInfoByUserId\x12\x15.sale.InfoByUserIdReq\x1a\x0e.sale.InfoData\x127\n" + "\n" + "NamesByIds\x12\x13.sale.NamesByIdsReq\x1a\x14.sale.NamesByIdsDataB\x18Z\x16lone-services/rpc/saleb\x06proto3" @@ -1596,32 +1652,33 @@ func file_sale_sale_proto_rawDescGZIP() []byte { return file_sale_sale_proto_rawDescData } -var file_sale_sale_proto_msgTypes = make([]protoimpl.MessageInfo, 18) +var file_sale_sale_proto_msgTypes = make([]protoimpl.MessageInfo, 19) var file_sale_sale_proto_goTypes = []any{ - (*Response)(nil), // 0: sale.Response - (*GroupEmptyReq)(nil), // 1: sale.GroupEmptyReq - (*GroupItemsReq)(nil), // 2: sale.GroupItemsReq - (*GroupCreateReq)(nil), // 3: sale.GroupCreateReq - (*NamesReq)(nil), // 4: sale.NamesReq - (*NameItem)(nil), // 5: sale.NameItem - (*NamesData)(nil), // 6: sale.NamesData - (*CreateReq)(nil), // 7: sale.CreateReq - (*EditReq)(nil), // 8: sale.EditReq - (*InfoReq)(nil), // 9: sale.InfoReq - (*Region)(nil), // 10: sale.Region - (*GroupItem)(nil), // 11: sale.GroupItem - (*InfoData)(nil), // 12: sale.InfoData - (*ItemsReq)(nil), // 13: sale.ItemsReq - (*StatusReq)(nil), // 14: sale.StatusReq - (*NamesByIdsReq)(nil), // 15: sale.NamesByIdsReq - (*NamesByIdsItem)(nil), // 16: sale.NamesByIdsItem - (*NamesByIdsData)(nil), // 17: sale.NamesByIdsData + (*Response)(nil), // 0: sale.Response + (*GroupEmptyReq)(nil), // 1: sale.GroupEmptyReq + (*GroupItemsReq)(nil), // 2: sale.GroupItemsReq + (*GroupCreateReq)(nil), // 3: sale.GroupCreateReq + (*NamesReq)(nil), // 4: sale.NamesReq + (*NameItem)(nil), // 5: sale.NameItem + (*NamesData)(nil), // 6: sale.NamesData + (*CreateReq)(nil), // 7: sale.CreateReq + (*EditReq)(nil), // 8: sale.EditReq + (*InfoReq)(nil), // 9: sale.InfoReq + (*InfoByUserIdReq)(nil), // 10: sale.InfoByUserIdReq + (*Region)(nil), // 11: sale.Region + (*GroupItem)(nil), // 12: sale.GroupItem + (*InfoData)(nil), // 13: sale.InfoData + (*ItemsReq)(nil), // 14: sale.ItemsReq + (*StatusReq)(nil), // 15: sale.StatusReq + (*NamesByIdsReq)(nil), // 16: sale.NamesByIdsReq + (*NamesByIdsItem)(nil), // 17: sale.NamesByIdsItem + (*NamesByIdsData)(nil), // 18: sale.NamesByIdsData } var file_sale_sale_proto_depIdxs = []int32{ 5, // 0: sale.NamesData.items:type_name -> sale.NameItem - 10, // 1: sale.InfoData.region:type_name -> sale.Region - 11, // 2: sale.InfoData.group:type_name -> sale.GroupItem - 16, // 3: sale.NamesByIdsData.items:type_name -> sale.NamesByIdsItem + 11, // 1: sale.InfoData.region:type_name -> sale.Region + 12, // 2: sale.InfoData.group:type_name -> sale.GroupItem + 17, // 3: sale.NamesByIdsData.items:type_name -> sale.NamesByIdsItem 2, // 4: sale.Sale.GroupItems:input_type -> sale.GroupItemsReq 3, // 5: sale.Sale.GroupCreate:input_type -> sale.GroupCreateReq 1, // 6: sale.Sale.GroupNames:input_type -> sale.GroupEmptyReq @@ -1631,25 +1688,27 @@ var file_sale_sale_proto_depIdxs = []int32{ 7, // 10: sale.Sale.Create:input_type -> sale.CreateReq 8, // 11: sale.Sale.Edit:input_type -> sale.EditReq 9, // 12: sale.Sale.Info:input_type -> sale.InfoReq - 13, // 13: sale.Sale.Items:input_type -> sale.ItemsReq - 14, // 14: sale.Sale.Status:input_type -> sale.StatusReq + 14, // 13: sale.Sale.Items:input_type -> sale.ItemsReq + 15, // 14: sale.Sale.Status:input_type -> sale.StatusReq 9, // 15: sale.Sale.InfoInternal:input_type -> sale.InfoReq - 15, // 16: sale.Sale.NamesByIds:input_type -> sale.NamesByIdsReq - 0, // 17: sale.Sale.GroupItems:output_type -> sale.Response - 0, // 18: sale.Sale.GroupCreate:output_type -> sale.Response - 0, // 19: sale.Sale.GroupNames:output_type -> sale.Response - 0, // 20: sale.Sale.Types:output_type -> sale.Response - 0, // 21: sale.Sale.Names:output_type -> sale.Response - 6, // 22: sale.Sale.NamesInternal:output_type -> sale.NamesData - 0, // 23: sale.Sale.Create:output_type -> sale.Response - 0, // 24: sale.Sale.Edit:output_type -> sale.Response - 0, // 25: sale.Sale.Info:output_type -> sale.Response - 0, // 26: sale.Sale.Items:output_type -> sale.Response - 0, // 27: sale.Sale.Status:output_type -> sale.Response - 12, // 28: sale.Sale.InfoInternal:output_type -> sale.InfoData - 17, // 29: sale.Sale.NamesByIds:output_type -> sale.NamesByIdsData - 17, // [17:30] is the sub-list for method output_type - 4, // [4:17] is the sub-list for method input_type + 10, // 16: sale.Sale.InfoByUserId:input_type -> sale.InfoByUserIdReq + 16, // 17: sale.Sale.NamesByIds:input_type -> sale.NamesByIdsReq + 0, // 18: sale.Sale.GroupItems:output_type -> sale.Response + 0, // 19: sale.Sale.GroupCreate:output_type -> sale.Response + 0, // 20: sale.Sale.GroupNames:output_type -> sale.Response + 0, // 21: sale.Sale.Types:output_type -> sale.Response + 0, // 22: sale.Sale.Names:output_type -> sale.Response + 6, // 23: sale.Sale.NamesInternal:output_type -> sale.NamesData + 0, // 24: sale.Sale.Create:output_type -> sale.Response + 0, // 25: sale.Sale.Edit:output_type -> sale.Response + 0, // 26: sale.Sale.Info:output_type -> sale.Response + 0, // 27: sale.Sale.Items:output_type -> sale.Response + 0, // 28: sale.Sale.Status:output_type -> sale.Response + 13, // 29: sale.Sale.InfoInternal:output_type -> sale.InfoData + 13, // 30: sale.Sale.InfoByUserId:output_type -> sale.InfoData + 18, // 31: sale.Sale.NamesByIds:output_type -> sale.NamesByIdsData + 18, // [18:32] is the sub-list for method output_type + 4, // [4:18] is the sub-list for method input_type 4, // [4:4] is the sub-list for extension type_name 4, // [4:4] is the sub-list for extension extendee 0, // [0:4] is the sub-list for field type_name @@ -1666,7 +1725,7 @@ func file_sale_sale_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_sale_sale_proto_rawDesc), len(file_sale_sale_proto_rawDesc)), NumEnums: 0, - NumMessages: 18, + NumMessages: 19, NumExtensions: 0, NumServices: 1, }, diff --git a/rpc/sale/pb/sale_grpc.pb.go b/rpc/sale/pb/sale_grpc.pb.go index 0cdbecf..ed375a6 100644 --- a/rpc/sale/pb/sale_grpc.pb.go +++ b/rpc/sale/pb/sale_grpc.pb.go @@ -31,6 +31,7 @@ const ( Sale_Items_FullMethodName = "/sale.Sale/Items" Sale_Status_FullMethodName = "/sale.Sale/Status" Sale_InfoInternal_FullMethodName = "/sale.Sale/InfoInternal" + Sale_InfoByUserId_FullMethodName = "/sale.Sale/InfoByUserId" Sale_NamesByIds_FullMethodName = "/sale.Sale/NamesByIds" ) @@ -53,7 +54,9 @@ type SaleClient interface { Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) // 销售详情 InfoInternal(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*InfoData, error) - // 按 id 批量查销售 id+name(内部) + // 按 user_id 查销售详情(内部) + InfoByUserId(ctx context.Context, in *InfoByUserIdReq, opts ...grpc.CallOption) (*InfoData, error) + // ids 批量查销售 NamesByIds(ctx context.Context, in *NamesByIdsReq, opts ...grpc.CallOption) (*NamesByIdsData, error) } @@ -185,6 +188,16 @@ func (c *saleClient) InfoInternal(ctx context.Context, in *InfoReq, opts ...grpc return out, nil } +func (c *saleClient) InfoByUserId(ctx context.Context, in *InfoByUserIdReq, opts ...grpc.CallOption) (*InfoData, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(InfoData) + err := c.cc.Invoke(ctx, Sale_InfoByUserId_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *saleClient) NamesByIds(ctx context.Context, in *NamesByIdsReq, opts ...grpc.CallOption) (*NamesByIdsData, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(NamesByIdsData) @@ -214,7 +227,9 @@ type SaleServer interface { Status(context.Context, *StatusReq) (*Response, error) // 销售详情 InfoInternal(context.Context, *InfoReq) (*InfoData, error) - // 按 id 批量查销售 id+name(内部) + // 按 user_id 查销售详情(内部) + InfoByUserId(context.Context, *InfoByUserIdReq) (*InfoData, error) + // ids 批量查销售 NamesByIds(context.Context, *NamesByIdsReq) (*NamesByIdsData, error) mustEmbedUnimplementedSaleServer() } @@ -262,6 +277,9 @@ func (UnimplementedSaleServer) Status(context.Context, *StatusReq) (*Response, e func (UnimplementedSaleServer) InfoInternal(context.Context, *InfoReq) (*InfoData, error) { return nil, status.Error(codes.Unimplemented, "method InfoInternal not implemented") } +func (UnimplementedSaleServer) InfoByUserId(context.Context, *InfoByUserIdReq) (*InfoData, error) { + return nil, status.Error(codes.Unimplemented, "method InfoByUserId not implemented") +} func (UnimplementedSaleServer) NamesByIds(context.Context, *NamesByIdsReq) (*NamesByIdsData, error) { return nil, status.Error(codes.Unimplemented, "method NamesByIds not implemented") } @@ -502,6 +520,24 @@ func _Sale_InfoInternal_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Sale_InfoByUserId_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InfoByUserIdReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).InfoByUserId(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_InfoByUserId_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).InfoByUserId(ctx, req.(*InfoByUserIdReq)) + } + return interceptor(ctx, in, info, handler) +} + func _Sale_NamesByIds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(NamesByIdsReq) if err := dec(in); err != nil { @@ -575,6 +611,10 @@ var Sale_ServiceDesc = grpc.ServiceDesc{ MethodName: "InfoInternal", Handler: _Sale_InfoInternal_Handler, }, + { + MethodName: "InfoByUserId", + Handler: _Sale_InfoByUserId_Handler, + }, { MethodName: "NamesByIds", Handler: _Sale_NamesByIds_Handler, diff --git a/rpc/sale/sale.pb b/rpc/sale/sale.pb index dfad0f3..ad77b67 100644 Binary files a/rpc/sale/sale.pb and b/rpc/sale/sale.pb differ diff --git a/rpc/sale/sale.proto b/rpc/sale/sale.proto index b57db00..cb1b34b 100644 --- a/rpc/sale/sale.proto +++ b/rpc/sale/sale.proto @@ -72,6 +72,8 @@ service Sale { // 销售详情 rpc InfoInternal(InfoReq) returns (InfoData); + // 按 user_id 查销售详情(内部) + rpc InfoByUserId(InfoByUserIdReq) returns (InfoData); // ids 批量查销售 rpc NamesByIds(NamesByIdsReq) returns (NamesByIdsData); } @@ -154,6 +156,10 @@ message InfoReq { int64 id = 1; } +message InfoByUserIdReq { + int64 user_id = 1; +} + message Region { string province = 1; string city = 2; @@ -194,6 +200,7 @@ message InfoData { string create_time = 26; string update_time = 27; GroupItem group = 28; + int64 user_id = 29; } message ItemsReq { diff --git a/rpc/user/pb/user.pb.go b/rpc/user/pb/user.pb.go index 0a1316c..03be1f0 100644 --- a/rpc/user/pb/user.pb.go +++ b/rpc/user/pb/user.pb.go @@ -82,195 +82,22 @@ func (x *Response) GetData() string { return "" } -// 小程序注册 -type RegisterReq struct { - state protoimpl.MessageState `protogen:"open.v1"` - Openid string `protobuf:"bytes,1,opt,name=openid,proto3" json:"openid,omitempty"` // 可空;空则服务端模拟 - Nickname string `protobuf:"bytes,2,opt,name=nickname,proto3" json:"nickname,omitempty"` - Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` - Mobile string `protobuf:"bytes,4,opt,name=mobile,proto3" json:"mobile,omitempty"` - Gender uint32 `protobuf:"varint,5,opt,name=gender,proto3" json:"gender,omitempty"` // 1男 2女 - Birthday string `protobuf:"bytes,6,opt,name=birthday,proto3" json:"birthday,omitempty"` - Username string `protobuf:"bytes,7,opt,name=username,proto3" json:"username,omitempty"` - AppId uint32 `protobuf:"varint,8,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"` // 应用标识 - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *RegisterReq) Reset() { - *x = RegisterReq{} - mi := &file_user_user_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *RegisterReq) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RegisterReq) ProtoMessage() {} - -func (x *RegisterReq) ProtoReflect() protoreflect.Message { - mi := &file_user_user_proto_msgTypes[1] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RegisterReq.ProtoReflect.Descriptor instead. -func (*RegisterReq) Descriptor() ([]byte, []int) { - return file_user_user_proto_rawDescGZIP(), []int{1} -} - -func (x *RegisterReq) GetOpenid() string { - if x != nil { - return x.Openid - } - return "" -} - -func (x *RegisterReq) GetNickname() string { - if x != nil { - return x.Nickname - } - return "" -} - -func (x *RegisterReq) GetAvatar() string { - if x != nil { - return x.Avatar - } - return "" -} - -func (x *RegisterReq) GetMobile() string { - if x != nil { - return x.Mobile - } - return "" -} - -func (x *RegisterReq) GetGender() uint32 { - if x != nil { - return x.Gender - } - return 0 -} - -func (x *RegisterReq) GetBirthday() string { - if x != nil { - return x.Birthday - } - return "" -} - -func (x *RegisterReq) GetUsername() string { - if x != nil { - return x.Username - } - return "" -} - -func (x *RegisterReq) GetAppId() uint32 { - if x != nil { - return x.AppId - } - return 0 -} - -// 账号密码注册 -type RegisterByUserReq struct { - state protoimpl.MessageState `protogen:"open.v1"` - Type uint32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` // 1手机号 2邮箱 - Account string `protobuf:"bytes,2,opt,name=account,proto3" json:"account,omitempty"` - Pwd string `protobuf:"bytes,3,opt,name=pwd,proto3" json:"pwd,omitempty"` - Code string `protobuf:"bytes,4,opt,name=code,proto3" json:"code,omitempty"` - AppId uint32 `protobuf:"varint,5,opt,name=app_id,json=appId,proto3" json:"app_id,omitempty"` // 应用标识 - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *RegisterByUserReq) Reset() { - *x = RegisterByUserReq{} - mi := &file_user_user_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *RegisterByUserReq) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RegisterByUserReq) ProtoMessage() {} - -func (x *RegisterByUserReq) ProtoReflect() protoreflect.Message { - mi := &file_user_user_proto_msgTypes[2] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RegisterByUserReq.ProtoReflect.Descriptor instead. -func (*RegisterByUserReq) Descriptor() ([]byte, []int) { - return file_user_user_proto_rawDescGZIP(), []int{2} -} - -func (x *RegisterByUserReq) GetType() uint32 { - if x != nil { - return x.Type - } - return 0 -} - -func (x *RegisterByUserReq) GetAccount() string { - if x != nil { - return x.Account - } - return "" -} - -func (x *RegisterByUserReq) GetPwd() string { - if x != nil { - return x.Pwd - } - return "" -} - -func (x *RegisterByUserReq) GetCode() string { - if x != nil { - return x.Code - } - return "" -} - -func (x *RegisterByUserReq) GetAppId() uint32 { - if x != nil { - return x.AppId - } - return 0 -} - -// openid 登录 +// 统一登录:grant_type = openid | password | sms type LoginReq struct { state protoimpl.MessageState `protogen:"open.v1"` - Openid string `protobuf:"bytes,1,opt,name=openid,proto3" json:"openid,omitempty"` + ClientCode string `protobuf:"bytes,1,opt,name=client_code,json=clientCode,proto3" json:"client_code,omitempty"` // 端编码,如 user_skin / user_o2 / sale_beauty + GrantType string `protobuf:"bytes,2,opt,name=grant_type,json=grantType,proto3" json:"grant_type,omitempty"` // openid | password | sms + Code string `protobuf:"bytes,3,opt,name=code,proto3" json:"code,omitempty"` // grant_type=openid 时传微信 login code + Mobile string `protobuf:"bytes,4,opt,name=mobile,proto3" json:"mobile,omitempty"` // grant_type=password|sms + Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"` // grant_type=password + SmsCode string `protobuf:"bytes,6,opt,name=sms_code,json=smsCode,proto3" json:"sms_code,omitempty"` // grant_type=sms unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *LoginReq) Reset() { *x = LoginReq{} - mi := &file_user_user_proto_msgTypes[3] + mi := &file_user_user_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -282,7 +109,7 @@ func (x *LoginReq) String() string { func (*LoginReq) ProtoMessage() {} func (x *LoginReq) ProtoReflect() protoreflect.Message { - mi := &file_user_user_proto_msgTypes[3] + mi := &file_user_user_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -295,12 +122,47 @@ func (x *LoginReq) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginReq.ProtoReflect.Descriptor instead. func (*LoginReq) Descriptor() ([]byte, []int) { - return file_user_user_proto_rawDescGZIP(), []int{3} + return file_user_user_proto_rawDescGZIP(), []int{1} } -func (x *LoginReq) GetOpenid() string { +func (x *LoginReq) GetClientCode() string { if x != nil { - return x.Openid + return x.ClientCode + } + return "" +} + +func (x *LoginReq) GetGrantType() string { + if x != nil { + return x.GrantType + } + return "" +} + +func (x *LoginReq) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *LoginReq) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +func (x *LoginReq) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *LoginReq) GetSmsCode() string { + if x != nil { + return x.SmsCode } return "" } @@ -317,7 +179,7 @@ type UserItemsReq struct { func (x *UserItemsReq) Reset() { *x = UserItemsReq{} - mi := &file_user_user_proto_msgTypes[4] + mi := &file_user_user_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -329,7 +191,7 @@ func (x *UserItemsReq) String() string { func (*UserItemsReq) ProtoMessage() {} func (x *UserItemsReq) ProtoReflect() protoreflect.Message { - mi := &file_user_user_proto_msgTypes[4] + mi := &file_user_user_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -342,7 +204,7 @@ func (x *UserItemsReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UserItemsReq.ProtoReflect.Descriptor instead. func (*UserItemsReq) Descriptor() ([]byte, []int) { - return file_user_user_proto_rawDescGZIP(), []int{4} + return file_user_user_proto_rawDescGZIP(), []int{2} } func (x *UserItemsReq) GetMobile() string { @@ -377,7 +239,7 @@ type UserStatusReq struct { func (x *UserStatusReq) Reset() { *x = UserStatusReq{} - mi := &file_user_user_proto_msgTypes[5] + mi := &file_user_user_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -389,7 +251,7 @@ func (x *UserStatusReq) String() string { func (*UserStatusReq) ProtoMessage() {} func (x *UserStatusReq) ProtoReflect() protoreflect.Message { - mi := &file_user_user_proto_msgTypes[5] + mi := &file_user_user_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -402,7 +264,7 @@ func (x *UserStatusReq) ProtoReflect() protoreflect.Message { // Deprecated: Use UserStatusReq.ProtoReflect.Descriptor instead. func (*UserStatusReq) Descriptor() ([]byte, []int) { - return file_user_user_proto_rawDescGZIP(), []int{5} + return file_user_user_proto_rawDescGZIP(), []int{3} } func (x *UserStatusReq) GetId() int64 { @@ -419,6 +281,598 @@ func (x *UserStatusReq) GetStatus() int32 { return 0 } +type EnsureBizIdentityReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Mobile string `protobuf:"bytes,1,opt,name=mobile,proto3" json:"mobile,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Avatar string `protobuf:"bytes,3,opt,name=avatar,proto3" json:"avatar,omitempty"` + Gender uint32 `protobuf:"varint,4,opt,name=gender,proto3" json:"gender,omitempty"` + Birthday string `protobuf:"bytes,5,opt,name=birthday,proto3" json:"birthday,omitempty"` + ClientCode string `protobuf:"bytes,6,opt,name=client_code,json=clientCode,proto3" json:"client_code,omitempty"` + CredentialType string `protobuf:"bytes,7,opt,name=credential_type,json=credentialType,proto3" json:"credential_type,omitempty"` + Identifier string `protobuf:"bytes,8,opt,name=identifier,proto3" json:"identifier,omitempty"` + Secret string `protobuf:"bytes,9,opt,name=secret,proto3" json:"secret,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EnsureBizIdentityReq) Reset() { + *x = EnsureBizIdentityReq{} + mi := &file_user_user_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EnsureBizIdentityReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EnsureBizIdentityReq) ProtoMessage() {} + +func (x *EnsureBizIdentityReq) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EnsureBizIdentityReq.ProtoReflect.Descriptor instead. +func (*EnsureBizIdentityReq) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{4} +} + +func (x *EnsureBizIdentityReq) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +func (x *EnsureBizIdentityReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *EnsureBizIdentityReq) GetAvatar() string { + if x != nil { + return x.Avatar + } + return "" +} + +func (x *EnsureBizIdentityReq) GetGender() uint32 { + if x != nil { + return x.Gender + } + return 0 +} + +func (x *EnsureBizIdentityReq) GetBirthday() string { + if x != nil { + return x.Birthday + } + return "" +} + +func (x *EnsureBizIdentityReq) GetClientCode() string { + if x != nil { + return x.ClientCode + } + return "" +} + +func (x *EnsureBizIdentityReq) GetCredentialType() string { + if x != nil { + return x.CredentialType + } + return "" +} + +func (x *EnsureBizIdentityReq) GetIdentifier() string { + if x != nil { + return x.Identifier + } + return "" +} + +func (x *EnsureBizIdentityReq) GetSecret() string { + if x != nil { + return x.Secret + } + return "" +} + +type EnsureBizIdentityData struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Created bool `protobuf:"varint,2,opt,name=created,proto3" json:"created,omitempty"` + Mobile string `protobuf:"bytes,3,opt,name=mobile,proto3" json:"mobile,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EnsureBizIdentityData) Reset() { + *x = EnsureBizIdentityData{} + mi := &file_user_user_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EnsureBizIdentityData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EnsureBizIdentityData) ProtoMessage() {} + +func (x *EnsureBizIdentityData) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EnsureBizIdentityData.ProtoReflect.Descriptor instead. +func (*EnsureBizIdentityData) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{5} +} + +func (x *EnsureBizIdentityData) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *EnsureBizIdentityData) GetCreated() bool { + if x != nil { + return x.Created + } + return false +} + +func (x *EnsureBizIdentityData) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +func (x *EnsureBizIdentityData) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type UsersByIdsReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Ids []int64 `protobuf:"varint,1,rep,packed,name=ids,proto3" json:"ids,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UsersByIdsReq) Reset() { + *x = UsersByIdsReq{} + mi := &file_user_user_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UsersByIdsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UsersByIdsReq) ProtoMessage() {} + +func (x *UsersByIdsReq) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UsersByIdsReq.ProtoReflect.Descriptor instead. +func (*UsersByIdsReq) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{6} +} + +func (x *UsersByIdsReq) GetIds() []int64 { + if x != nil { + return x.Ids + } + return nil +} + +type UserBriefItem struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Mobile string `protobuf:"bytes,2,opt,name=mobile,proto3" json:"mobile,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Avatar string `protobuf:"bytes,4,opt,name=avatar,proto3" json:"avatar,omitempty"` + Gender uint32 `protobuf:"varint,5,opt,name=gender,proto3" json:"gender,omitempty"` + Birthday string `protobuf:"bytes,6,opt,name=birthday,proto3" json:"birthday,omitempty"` + Status uint32 `protobuf:"varint,7,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UserBriefItem) Reset() { + *x = UserBriefItem{} + mi := &file_user_user_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UserBriefItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserBriefItem) ProtoMessage() {} + +func (x *UserBriefItem) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserBriefItem.ProtoReflect.Descriptor instead. +func (*UserBriefItem) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{7} +} + +func (x *UserBriefItem) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *UserBriefItem) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +func (x *UserBriefItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *UserBriefItem) GetAvatar() string { + if x != nil { + return x.Avatar + } + return "" +} + +func (x *UserBriefItem) GetGender() uint32 { + if x != nil { + return x.Gender + } + return 0 +} + +func (x *UserBriefItem) GetBirthday() string { + if x != nil { + return x.Birthday + } + return "" +} + +func (x *UserBriefItem) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +type UsersByIdsData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Items []*UserBriefItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UsersByIdsData) Reset() { + *x = UsersByIdsData{} + mi := &file_user_user_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UsersByIdsData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UsersByIdsData) ProtoMessage() {} + +func (x *UsersByIdsData) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UsersByIdsData.ProtoReflect.Descriptor instead. +func (*UsersByIdsData) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{8} +} + +func (x *UsersByIdsData) GetItems() []*UserBriefItem { + if x != nil { + return x.Items + } + return nil +} + +type UpdateMobileReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Mobile string `protobuf:"bytes,2,opt,name=mobile,proto3" json:"mobile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateMobileReq) Reset() { + *x = UpdateMobileReq{} + mi := &file_user_user_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateMobileReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateMobileReq) ProtoMessage() {} + +func (x *UpdateMobileReq) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[9] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateMobileReq.ProtoReflect.Descriptor instead. +func (*UpdateMobileReq) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{9} +} + +func (x *UpdateMobileReq) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *UpdateMobileReq) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +type UpdateMobileData struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Mobile string `protobuf:"bytes,2,opt,name=mobile,proto3" json:"mobile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateMobileData) Reset() { + *x = UpdateMobileData{} + mi := &file_user_user_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateMobileData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateMobileData) ProtoMessage() {} + +func (x *UpdateMobileData) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[10] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateMobileData.ProtoReflect.Descriptor instead. +func (*UpdateMobileData) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{10} +} + +func (x *UpdateMobileData) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *UpdateMobileData) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +type RevokeBizClientReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ClientCode string `protobuf:"bytes,2,opt,name=client_code,json=clientCode,proto3" json:"client_code,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RevokeBizClientReq) Reset() { + *x = RevokeBizClientReq{} + mi := &file_user_user_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RevokeBizClientReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevokeBizClientReq) ProtoMessage() {} + +func (x *RevokeBizClientReq) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[11] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RevokeBizClientReq.ProtoReflect.Descriptor instead. +func (*RevokeBizClientReq) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{11} +} + +func (x *RevokeBizClientReq) GetUserId() int64 { + if x != nil { + return x.UserId + } + return 0 +} + +func (x *RevokeBizClientReq) GetClientCode() string { + if x != nil { + return x.ClientCode + } + return "" +} + +type RevokeBizClientData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Revoked bool `protobuf:"varint,1,opt,name=revoked,proto3" json:"revoked,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RevokeBizClientData) Reset() { + *x = RevokeBizClientData{} + mi := &file_user_user_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RevokeBizClientData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevokeBizClientData) ProtoMessage() {} + +func (x *RevokeBizClientData) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[12] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RevokeBizClientData.ProtoReflect.Descriptor instead. +func (*RevokeBizClientData) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{12} +} + +func (x *RevokeBizClientData) GetRevoked() bool { + if x != nil { + return x.Revoked + } + return false +} + +type InfoReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InfoReq) Reset() { + *x = InfoReq{} + mi := &file_user_user_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InfoReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InfoReq) ProtoMessage() {} + +func (x *InfoReq) ProtoReflect() protoreflect.Message { + mi := &file_user_user_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InfoReq.ProtoReflect.Descriptor instead. +func (*InfoReq) Descriptor() ([]byte, []int) { + return file_user_user_proto_rawDescGZIP(), []int{13} +} + var File_user_user_proto protoreflect.FileDescriptor const file_user_user_proto_rawDesc = "" + @@ -427,38 +881,77 @@ const file_user_user_proto_rawDesc = "" + "\bResponse\x12\x12\n" + "\x04code\x18\x01 \x01(\x05R\x04code\x12\x10\n" + "\x03msg\x18\x02 \x01(\tR\x03msg\x12\x12\n" + - "\x04data\x18\x03 \x01(\tR\x04data\"\xd8\x01\n" + - "\vRegisterReq\x12\x16\n" + - "\x06openid\x18\x01 \x01(\tR\x06openid\x12\x1a\n" + - "\bnickname\x18\x02 \x01(\tR\bnickname\x12\x16\n" + - "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12\x16\n" + - "\x06mobile\x18\x04 \x01(\tR\x06mobile\x12\x16\n" + - "\x06gender\x18\x05 \x01(\rR\x06gender\x12\x1a\n" + - "\bbirthday\x18\x06 \x01(\tR\bbirthday\x12\x1a\n" + - "\busername\x18\a \x01(\tR\busername\x12\x15\n" + - "\x06app_id\x18\b \x01(\rR\x05appId\"~\n" + - "\x11RegisterByUserReq\x12\x12\n" + - "\x04type\x18\x01 \x01(\rR\x04type\x12\x18\n" + - "\aaccount\x18\x02 \x01(\tR\aaccount\x12\x10\n" + - "\x03pwd\x18\x03 \x01(\tR\x03pwd\x12\x12\n" + - "\x04code\x18\x04 \x01(\tR\x04code\x12\x15\n" + - "\x06app_id\x18\x05 \x01(\rR\x05appId\"\"\n" + - "\bLoginReq\x12\x16\n" + - "\x06openid\x18\x01 \x01(\tR\x06openid\"N\n" + + "\x04data\x18\x03 \x01(\tR\x04data\"\xad\x01\n" + + "\bLoginReq\x12\x1f\n" + + "\vclient_code\x18\x01 \x01(\tR\n" + + "clientCode\x12\x1d\n" + + "\n" + + "grant_type\x18\x02 \x01(\tR\tgrantType\x12\x12\n" + + "\x04code\x18\x03 \x01(\tR\x04code\x12\x16\n" + + "\x06mobile\x18\x04 \x01(\tR\x06mobile\x12\x1a\n" + + "\bpassword\x18\x05 \x01(\tR\bpassword\x12\x19\n" + + "\bsms_code\x18\x06 \x01(\tR\asmsCode\"N\n" + "\fUserItemsReq\x12\x16\n" + "\x06mobile\x18\x01 \x01(\tR\x06mobile\x12\x12\n" + "\x04page\x18\x02 \x01(\x05R\x04page\x12\x12\n" + "\x04size\x18\x03 \x01(\x05R\x04size\"7\n" + "\rUserStatusReq\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + - "\x06status\x18\x02 \x01(\x05R\x06status2\xa8\x03\n" + - "\x04User\x12O\n" + - "\bRegister\x12\x11.user.RegisterReq\x1a\x0e.user.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\"\x15/customer/v3/register\x12`\n" + - "\x0eRegisterByUser\x12\x17.user.RegisterByUserReq\x1a\x0e.user.Response\"%\x82\xd3\xe4\x93\x02\x1f:\x01*\"\x1a/customer/v3/register/user\x12F\n" + - "\x05Login\x12\x0e.user.LoginReq\x1a\x0e.user.Response\"\x1d\x82\xd3\xe4\x93\x02\x17:\x01*\"\x12/customer/v3/login\x12P\n" + + "\x06status\x18\x02 \x01(\x05R\x06status\"\x90\x02\n" + + "\x14EnsureBizIdentityReq\x12\x16\n" + + "\x06mobile\x18\x01 \x01(\tR\x06mobile\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x16\n" + + "\x06avatar\x18\x03 \x01(\tR\x06avatar\x12\x16\n" + + "\x06gender\x18\x04 \x01(\rR\x06gender\x12\x1a\n" + + "\bbirthday\x18\x05 \x01(\tR\bbirthday\x12\x1f\n" + + "\vclient_code\x18\x06 \x01(\tR\n" + + "clientCode\x12'\n" + + "\x0fcredential_type\x18\a \x01(\tR\x0ecredentialType\x12\x1e\n" + + "\n" + + "identifier\x18\b \x01(\tR\n" + + "identifier\x12\x16\n" + + "\x06secret\x18\t \x01(\tR\x06secret\"v\n" + + "\x15EnsureBizIdentityData\x12\x17\n" + + "\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x18\n" + + "\acreated\x18\x02 \x01(\bR\acreated\x12\x16\n" + + "\x06mobile\x18\x03 \x01(\tR\x06mobile\x12\x12\n" + + "\x04name\x18\x04 \x01(\tR\x04name\"!\n" + + "\rUsersByIdsReq\x12\x10\n" + + "\x03ids\x18\x01 \x03(\x03R\x03ids\"\xaf\x01\n" + + "\rUserBriefItem\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + + "\x06mobile\x18\x02 \x01(\tR\x06mobile\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\x12\x16\n" + + "\x06avatar\x18\x04 \x01(\tR\x06avatar\x12\x16\n" + + "\x06gender\x18\x05 \x01(\rR\x06gender\x12\x1a\n" + + "\bbirthday\x18\x06 \x01(\tR\bbirthday\x12\x16\n" + + "\x06status\x18\a \x01(\rR\x06status\";\n" + + "\x0eUsersByIdsData\x12)\n" + + "\x05items\x18\x01 \x03(\v2\x13.user.UserBriefItemR\x05items\"B\n" + + "\x0fUpdateMobileReq\x12\x17\n" + + "\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x16\n" + + "\x06mobile\x18\x02 \x01(\tR\x06mobile\"C\n" + + "\x10UpdateMobileData\x12\x17\n" + + "\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x16\n" + + "\x06mobile\x18\x02 \x01(\tR\x06mobile\"N\n" + + "\x12RevokeBizClientReq\x12\x17\n" + + "\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x1f\n" + + "\vclient_code\x18\x02 \x01(\tR\n" + + "clientCode\"/\n" + + "\x13RevokeBizClientData\x12\x18\n" + + "\arevoked\x18\x01 \x01(\bR\arevoked\"\t\n" + + "\aInfoReq2\xc3\x04\n" + + "\x04User\x12A\n" + + "\x05Login\x12\x0e.user.LoginReq\x1a\x0e.user.Response\"\x18\x82\xd3\xe4\x93\x02\x12:\x01*\"\r/api/v3/login\x12C\n" + + "\x04Info\x12\r.user.InfoReq\x1a\x0e.user.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\x12\x11/api/v3/user/info\x12P\n" + "\tUserItems\x12\x12.user.UserItemsReq\x1a\x0e.user.Response\"\x1f\x82\xd3\xe4\x93\x02\x19:\x01*\x12\x14/admin/v3/user/items\x12S\n" + "\n" + - "UserStatus\x12\x13.user.UserStatusReq\x1a\x0e.user.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\x1a\x15/admin/v3/user/statusB\x18Z\x16lone-services/rpc/userb\x06proto3" + "UserStatus\x12\x13.user.UserStatusReq\x1a\x0e.user.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\x1a\x15/admin/v3/user/status\x12L\n" + + "\x11EnsureBizIdentity\x12\x1a.user.EnsureBizIdentityReq\x1a\x1b.user.EnsureBizIdentityData\x127\n" + + "\n" + + "UsersByIds\x12\x13.user.UsersByIdsReq\x1a\x14.user.UsersByIdsData\x12=\n" + + "\fUpdateMobile\x12\x15.user.UpdateMobileReq\x1a\x16.user.UpdateMobileData\x12F\n" + + "\x0fRevokeBizClient\x12\x18.user.RevokeBizClientReq\x1a\x19.user.RevokeBizClientDataB\x18Z\x16lone-services/rpc/userb\x06proto3" var ( file_user_user_proto_rawDescOnce sync.Once @@ -472,31 +965,46 @@ func file_user_user_proto_rawDescGZIP() []byte { return file_user_user_proto_rawDescData } -var file_user_user_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_user_user_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_user_user_proto_goTypes = []any{ - (*Response)(nil), // 0: user.Response - (*RegisterReq)(nil), // 1: user.RegisterReq - (*RegisterByUserReq)(nil), // 2: user.RegisterByUserReq - (*LoginReq)(nil), // 3: user.LoginReq - (*UserItemsReq)(nil), // 4: user.UserItemsReq - (*UserStatusReq)(nil), // 5: user.UserStatusReq + (*Response)(nil), // 0: user.Response + (*LoginReq)(nil), // 1: user.LoginReq + (*UserItemsReq)(nil), // 2: user.UserItemsReq + (*UserStatusReq)(nil), // 3: user.UserStatusReq + (*EnsureBizIdentityReq)(nil), // 4: user.EnsureBizIdentityReq + (*EnsureBizIdentityData)(nil), // 5: user.EnsureBizIdentityData + (*UsersByIdsReq)(nil), // 6: user.UsersByIdsReq + (*UserBriefItem)(nil), // 7: user.UserBriefItem + (*UsersByIdsData)(nil), // 8: user.UsersByIdsData + (*UpdateMobileReq)(nil), // 9: user.UpdateMobileReq + (*UpdateMobileData)(nil), // 10: user.UpdateMobileData + (*RevokeBizClientReq)(nil), // 11: user.RevokeBizClientReq + (*RevokeBizClientData)(nil), // 12: user.RevokeBizClientData + (*InfoReq)(nil), // 13: user.InfoReq } var file_user_user_proto_depIdxs = []int32{ - 1, // 0: user.User.Register:input_type -> user.RegisterReq - 2, // 1: user.User.RegisterByUser:input_type -> user.RegisterByUserReq - 3, // 2: user.User.Login:input_type -> user.LoginReq - 4, // 3: user.User.UserItems:input_type -> user.UserItemsReq - 5, // 4: user.User.UserStatus:input_type -> user.UserStatusReq - 0, // 5: user.User.Register:output_type -> user.Response - 0, // 6: user.User.RegisterByUser:output_type -> user.Response - 0, // 7: user.User.Login:output_type -> user.Response - 0, // 8: user.User.UserItems:output_type -> user.Response - 0, // 9: user.User.UserStatus:output_type -> user.Response - 5, // [5:10] is the sub-list for method output_type - 0, // [0:5] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 7, // 0: user.UsersByIdsData.items:type_name -> user.UserBriefItem + 1, // 1: user.User.Login:input_type -> user.LoginReq + 13, // 2: user.User.Info:input_type -> user.InfoReq + 2, // 3: user.User.UserItems:input_type -> user.UserItemsReq + 3, // 4: user.User.UserStatus:input_type -> user.UserStatusReq + 4, // 5: user.User.EnsureBizIdentity:input_type -> user.EnsureBizIdentityReq + 6, // 6: user.User.UsersByIds:input_type -> user.UsersByIdsReq + 9, // 7: user.User.UpdateMobile:input_type -> user.UpdateMobileReq + 11, // 8: user.User.RevokeBizClient:input_type -> user.RevokeBizClientReq + 0, // 9: user.User.Login:output_type -> user.Response + 0, // 10: user.User.Info:output_type -> user.Response + 0, // 11: user.User.UserItems:output_type -> user.Response + 0, // 12: user.User.UserStatus:output_type -> user.Response + 5, // 13: user.User.EnsureBizIdentity:output_type -> user.EnsureBizIdentityData + 8, // 14: user.User.UsersByIds:output_type -> user.UsersByIdsData + 10, // 15: user.User.UpdateMobile:output_type -> user.UpdateMobileData + 12, // 16: user.User.RevokeBizClient:output_type -> user.RevokeBizClientData + 9, // [9:17] is the sub-list for method output_type + 1, // [1:9] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_user_user_proto_init() } @@ -510,7 +1018,7 @@ func file_user_user_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_user_user_proto_rawDesc), len(file_user_user_proto_rawDesc)), NumEnums: 0, - NumMessages: 6, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, diff --git a/rpc/user/pb/user_grpc.pb.go b/rpc/user/pb/user_grpc.pb.go index 64ea666..063ab4a 100644 --- a/rpc/user/pb/user_grpc.pb.go +++ b/rpc/user/pb/user_grpc.pb.go @@ -19,22 +19,28 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - User_Register_FullMethodName = "/user.User/Register" - User_RegisterByUser_FullMethodName = "/user.User/RegisterByUser" - User_Login_FullMethodName = "/user.User/Login" - User_UserItems_FullMethodName = "/user.User/UserItems" - User_UserStatus_FullMethodName = "/user.User/UserStatus" + User_Login_FullMethodName = "/user.User/Login" + User_Info_FullMethodName = "/user.User/Info" + User_UserItems_FullMethodName = "/user.User/UserItems" + User_UserStatus_FullMethodName = "/user.User/UserStatus" + User_EnsureBizIdentity_FullMethodName = "/user.User/EnsureBizIdentity" + User_UsersByIds_FullMethodName = "/user.User/UsersByIds" + User_UpdateMobile_FullMethodName = "/user.User/UpdateMobile" + User_RevokeBizClient_FullMethodName = "/user.User/RevokeBizClient" ) // UserClient is the client API for User service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type UserClient interface { - Register(ctx context.Context, in *RegisterReq, opts ...grpc.CallOption) (*Response, error) - RegisterByUser(ctx context.Context, in *RegisterByUserReq, opts ...grpc.CallOption) (*Response, error) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error) + Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error) UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error) UserStatus(ctx context.Context, in *UserStatusReq, opts ...grpc.CallOption) (*Response, error) + EnsureBizIdentity(ctx context.Context, in *EnsureBizIdentityReq, opts ...grpc.CallOption) (*EnsureBizIdentityData, error) + UsersByIds(ctx context.Context, in *UsersByIdsReq, opts ...grpc.CallOption) (*UsersByIdsData, error) + UpdateMobile(ctx context.Context, in *UpdateMobileReq, opts ...grpc.CallOption) (*UpdateMobileData, error) + RevokeBizClient(ctx context.Context, in *RevokeBizClientReq, opts ...grpc.CallOption) (*RevokeBizClientData, error) } type userClient struct { @@ -45,26 +51,6 @@ func NewUserClient(cc grpc.ClientConnInterface) UserClient { return &userClient{cc} } -func (c *userClient) Register(ctx context.Context, in *RegisterReq, opts ...grpc.CallOption) (*Response, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(Response) - err := c.cc.Invoke(ctx, User_Register_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *userClient) RegisterByUser(ctx context.Context, in *RegisterByUserReq, opts ...grpc.CallOption) (*Response, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(Response) - err := c.cc.Invoke(ctx, User_RegisterByUser_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *userClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) @@ -75,6 +61,16 @@ func (c *userClient) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallO return out, nil } +func (c *userClient) Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, User_Info_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *userClient) UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Response) @@ -95,15 +91,58 @@ func (c *userClient) UserStatus(ctx context.Context, in *UserStatusReq, opts ... return out, nil } +func (c *userClient) EnsureBizIdentity(ctx context.Context, in *EnsureBizIdentityReq, opts ...grpc.CallOption) (*EnsureBizIdentityData, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(EnsureBizIdentityData) + err := c.cc.Invoke(ctx, User_EnsureBizIdentity_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) UsersByIds(ctx context.Context, in *UsersByIdsReq, opts ...grpc.CallOption) (*UsersByIdsData, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UsersByIdsData) + err := c.cc.Invoke(ctx, User_UsersByIds_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) UpdateMobile(ctx context.Context, in *UpdateMobileReq, opts ...grpc.CallOption) (*UpdateMobileData, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(UpdateMobileData) + err := c.cc.Invoke(ctx, User_UpdateMobile_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *userClient) RevokeBizClient(ctx context.Context, in *RevokeBizClientReq, opts ...grpc.CallOption) (*RevokeBizClientData, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RevokeBizClientData) + err := c.cc.Invoke(ctx, User_RevokeBizClient_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // UserServer is the server API for User service. // All implementations must embed UnimplementedUserServer // for forward compatibility. type UserServer interface { - Register(context.Context, *RegisterReq) (*Response, error) - RegisterByUser(context.Context, *RegisterByUserReq) (*Response, error) Login(context.Context, *LoginReq) (*Response, error) + Info(context.Context, *InfoReq) (*Response, error) UserItems(context.Context, *UserItemsReq) (*Response, error) UserStatus(context.Context, *UserStatusReq) (*Response, error) + EnsureBizIdentity(context.Context, *EnsureBizIdentityReq) (*EnsureBizIdentityData, error) + UsersByIds(context.Context, *UsersByIdsReq) (*UsersByIdsData, error) + UpdateMobile(context.Context, *UpdateMobileReq) (*UpdateMobileData, error) + RevokeBizClient(context.Context, *RevokeBizClientReq) (*RevokeBizClientData, error) mustEmbedUnimplementedUserServer() } @@ -114,21 +153,30 @@ type UserServer interface { // pointer dereference when methods are called. type UnimplementedUserServer struct{} -func (UnimplementedUserServer) Register(context.Context, *RegisterReq) (*Response, error) { - return nil, status.Error(codes.Unimplemented, "method Register not implemented") -} -func (UnimplementedUserServer) RegisterByUser(context.Context, *RegisterByUserReq) (*Response, error) { - return nil, status.Error(codes.Unimplemented, "method RegisterByUser not implemented") -} func (UnimplementedUserServer) Login(context.Context, *LoginReq) (*Response, error) { return nil, status.Error(codes.Unimplemented, "method Login not implemented") } +func (UnimplementedUserServer) Info(context.Context, *InfoReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Info not implemented") +} func (UnimplementedUserServer) UserItems(context.Context, *UserItemsReq) (*Response, error) { return nil, status.Error(codes.Unimplemented, "method UserItems not implemented") } func (UnimplementedUserServer) UserStatus(context.Context, *UserStatusReq) (*Response, error) { return nil, status.Error(codes.Unimplemented, "method UserStatus not implemented") } +func (UnimplementedUserServer) EnsureBizIdentity(context.Context, *EnsureBizIdentityReq) (*EnsureBizIdentityData, error) { + return nil, status.Error(codes.Unimplemented, "method EnsureBizIdentity not implemented") +} +func (UnimplementedUserServer) UsersByIds(context.Context, *UsersByIdsReq) (*UsersByIdsData, error) { + return nil, status.Error(codes.Unimplemented, "method UsersByIds not implemented") +} +func (UnimplementedUserServer) UpdateMobile(context.Context, *UpdateMobileReq) (*UpdateMobileData, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateMobile not implemented") +} +func (UnimplementedUserServer) RevokeBizClient(context.Context, *RevokeBizClientReq) (*RevokeBizClientData, error) { + return nil, status.Error(codes.Unimplemented, "method RevokeBizClient not implemented") +} func (UnimplementedUserServer) mustEmbedUnimplementedUserServer() {} func (UnimplementedUserServer) testEmbeddedByValue() {} @@ -150,42 +198,6 @@ func RegisterUserServer(s grpc.ServiceRegistrar, srv UserServer) { s.RegisterService(&User_ServiceDesc, srv) } -func _User_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(RegisterReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UserServer).Register(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: User_Register_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UserServer).Register(ctx, req.(*RegisterReq)) - } - return interceptor(ctx, in, info, handler) -} - -func _User_RegisterByUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(RegisterByUserReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(UserServer).RegisterByUser(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: User_RegisterByUser_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(UserServer).RegisterByUser(ctx, req.(*RegisterByUserReq)) - } - return interceptor(ctx, in, info, handler) -} - func _User_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(LoginReq) if err := dec(in); err != nil { @@ -204,6 +216,24 @@ func _User_Login_Handler(srv interface{}, ctx context.Context, dec func(interfac return interceptor(ctx, in, info, handler) } +func _User_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InfoReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).Info(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_Info_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).Info(ctx, req.(*InfoReq)) + } + return interceptor(ctx, in, info, handler) +} + func _User_UserItems_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(UserItemsReq) if err := dec(in); err != nil { @@ -240,6 +270,78 @@ func _User_UserStatus_Handler(srv interface{}, ctx context.Context, dec func(int return interceptor(ctx, in, info, handler) } +func _User_EnsureBizIdentity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EnsureBizIdentityReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).EnsureBizIdentity(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_EnsureBizIdentity_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).EnsureBizIdentity(ctx, req.(*EnsureBizIdentityReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_UsersByIds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UsersByIdsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).UsersByIds(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_UsersByIds_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).UsersByIds(ctx, req.(*UsersByIdsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_UpdateMobile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateMobileReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).UpdateMobile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_UpdateMobile_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).UpdateMobile(ctx, req.(*UpdateMobileReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _User_RevokeBizClient_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RevokeBizClientReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).RevokeBizClient(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: User_RevokeBizClient_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).RevokeBizClient(ctx, req.(*RevokeBizClientReq)) + } + return interceptor(ctx, in, info, handler) +} + // User_ServiceDesc is the grpc.ServiceDesc for User service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -247,18 +349,14 @@ var User_ServiceDesc = grpc.ServiceDesc{ ServiceName: "user.User", HandlerType: (*UserServer)(nil), Methods: []grpc.MethodDesc{ - { - MethodName: "Register", - Handler: _User_Register_Handler, - }, - { - MethodName: "RegisterByUser", - Handler: _User_RegisterByUser_Handler, - }, { MethodName: "Login", Handler: _User_Login_Handler, }, + { + MethodName: "Info", + Handler: _User_Info_Handler, + }, { MethodName: "UserItems", Handler: _User_UserItems_Handler, @@ -267,6 +365,22 @@ var User_ServiceDesc = grpc.ServiceDesc{ MethodName: "UserStatus", Handler: _User_UserStatus_Handler, }, + { + MethodName: "EnsureBizIdentity", + Handler: _User_EnsureBizIdentity_Handler, + }, + { + MethodName: "UsersByIds", + Handler: _User_UsersByIds_Handler, + }, + { + MethodName: "UpdateMobile", + Handler: _User_UpdateMobile_Handler, + }, + { + MethodName: "RevokeBizClient", + Handler: _User_RevokeBizClient_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "user/user.proto", diff --git a/rpc/user/user.pb b/rpc/user/user.pb index f97c4bf..8472f73 100644 Binary files a/rpc/user/user.pb and b/rpc/user/user.pb differ diff --git a/rpc/user/user.proto b/rpc/user/user.proto index 0b76625..6871232 100644 --- a/rpc/user/user.proto +++ b/rpc/user/user.proto @@ -11,61 +11,94 @@ message Response { string data = 3; } -// 小程序注册 -message RegisterReq { - string openid = 1; // 可空;空则服务端模拟 - string nickname = 2; - string avatar = 3; - string mobile = 4; - uint32 gender = 5; // 1男 2女 - string birthday = 6; - string username = 7; - uint32 app_id = 8; // 应用标识 -} - -// 账号密码注册 -message RegisterByUserReq { - uint32 type = 1; // 1手机号 2邮箱 - string account = 2; - string pwd = 3; - string code = 4; - uint32 app_id = 5; // 应用标识 -} - -// openid 登录 message LoginReq { - string openid = 1; + string client_code = 1; + string grant_type = 2; + string code = 3; + string mobile = 4; + string password = 5; + string sms_code = 6; } -// 管理端用户列表 message UserItemsReq { string mobile = 1; int32 page = 2; int32 size = 3; } -// 管理端修改用户状态 message UserStatusReq { int64 id = 1; int32 status = 2; } +message EnsureBizIdentityReq { + string mobile = 1; + string name = 2; + string avatar = 3; + uint32 gender = 4; + string birthday = 5; + string client_code = 6; + string credential_type = 7; + string identifier = 8; + string secret = 9; +} + +message EnsureBizIdentityData { + int64 user_id = 1; + bool created = 2; + string mobile = 3; + string name = 4; +} + +message UsersByIdsReq { + repeated int64 ids = 1; +} + +message UserBriefItem { + int64 id = 1; + string mobile = 2; + string name = 3; + string avatar = 4; + uint32 gender = 5; + string birthday = 6; + uint32 status = 7; +} + +message UsersByIdsData { + repeated UserBriefItem items = 1; +} + +message UpdateMobileReq { + int64 user_id = 1; + string mobile = 2; +} + +message UpdateMobileData { + int64 user_id = 1; + string mobile = 2; +} + +message RevokeBizClientReq { + int64 user_id = 1; + string client_code = 2; +} + +message RevokeBizClientData { + bool revoked = 1; +} + +message InfoReq {} + service User { - rpc Register(RegisterReq) returns (Response) { - option (google.api.http) = { - post: "/customer/v3/register" - body: "*" - }; - } - rpc RegisterByUser(RegisterByUserReq) returns (Response) { - option (google.api.http) = { - post: "/customer/v3/register/user" - body: "*" - }; - } rpc Login(LoginReq) returns (Response) { option (google.api.http) = { - post: "/customer/v3/login" + post: "/api/v3/login" + body: "*" + }; + } + rpc Info(InfoReq) returns (Response) { + option (google.api.http) = { + get: "/api/v3/user/info" body: "*" }; } @@ -81,4 +114,9 @@ service User { body: "*" }; } + + rpc EnsureBizIdentity(EnsureBizIdentityReq) returns (EnsureBizIdentityData); + rpc UsersByIds(UsersByIdsReq) returns (UsersByIdsData); + rpc UpdateMobile(UpdateMobileReq) returns (UpdateMobileData); + rpc RevokeBizClient(RevokeBizClientReq) returns (RevokeBizClientData); } diff --git a/services/sale/internal/dao/sale.go b/services/sale/internal/dao/sale.go index 6761c01..1329f8b 100644 --- a/services/sale/internal/dao/sale.go +++ b/services/sale/internal/dao/sale.go @@ -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"` diff --git a/services/sale/internal/logic/createLogic.go b/services/sale/internal/logic/createLogic.go index 85c5990..00b5db3 100644 --- a/services/sale/internal/logic/createLogic.go +++ b/services/sale/internal/logic/createLogic.go @@ -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, } diff --git a/services/sale/internal/logic/editLogic.go b/services/sale/internal/logic/editLogic.go index 0074003..ccbabad 100644 --- a/services/sale/internal/logic/editLogic.go +++ b/services/sale/internal/logic/editLogic.go @@ -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 diff --git a/services/sale/internal/logic/helper.go b/services/sale/internal/logic/helper.go index c998717..8056c33 100644 --- a/services/sale/internal/logic/helper.go +++ b/services/sale/internal/logic/helper.go @@ -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{}, } @@ -101,13 +101,17 @@ func maskSaleMobile(info *dao.SaleInfo) { info.Mobile = utils.DecryptPhoneReplace(mobile) } -// querySaleInfo 查询销售详情并附带分组;mobile 脱敏,origin_mobile 为加密串。 -// 未找到时返回 (nil, nil)。 func querySaleInfo(id int64) (*dao.SaleInfo, error) { + return querySaleInfoByEq(map[string]string{"id": strconv.FormatInt(id, 10)}) +} + +func querySaleInfoByUserId(userId int64) (*dao.SaleInfo, error) { + return querySaleInfoByEq(map[string]string{"user_id": strconv.FormatInt(userId, 10)}) +} + +func querySaleInfoByEq(eq map[string]string) (*dao.SaleInfo, error) { var info dao.SaleInfo - if err := (model.SaleModel{}.Init().GetOne(modelbase.Params{ - Eq: map[string]string{"id": strconv.FormatInt(id, 10)}, - }, &info)); err != nil { + if err := (model.SaleModel{}.Init().GetOne(modelbase.Params{Eq: eq}, &info)); err != nil { return nil, err } if info.Id < utils.NumberOne { diff --git a/services/sale/internal/logic/infoByUserIdLogic.go b/services/sale/internal/logic/infoByUserIdLogic.go new file mode 100644 index 0000000..c12199e --- /dev/null +++ b/services/sale/internal/logic/infoByUserIdLogic.go @@ -0,0 +1,47 @@ +package logic + +import ( + "context" + + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/svc" + "lone-services/services/sale/validator" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type InfoByUserIdLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewInfoByUserIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InfoByUserIdLogic { + return &InfoByUserIdLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *InfoByUserIdLogic) InfoByUserId(in *sale.InfoByUserIdReq) (*sale.InfoData, error) { + var req validator.InfoByUserIdValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return nil, status.Error(codes.InvalidArgument, msg) + } + + info, err := querySaleInfoByUserId(req.UserId) + if err != nil { + l.Errorf("sale InfoByUserId: %v", err) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + if info == nil { + return nil, status.Error(codes.NotFound, utils.ErrorNotFund.Msg) + } + + return toSaleInfoData(info), nil +} diff --git a/services/sale/internal/logic/infoInternalLogic.go b/services/sale/internal/logic/infoInternalLogic.go index 98a963b..2338cf4 100644 --- a/services/sale/internal/logic/infoInternalLogic.go +++ b/services/sale/internal/logic/infoInternalLogic.go @@ -50,6 +50,7 @@ func (l *InfoInternalLogic) InfoInternal(in *sale.InfoReq) (*sale.InfoData, erro func toSaleInfoData(info *dao.SaleInfo) *sale.InfoData { data := &sale.InfoData{ Id: info.Id, + UserId: info.UserId, SaleId: info.SaleId, Mobile: info.Mobile, OriginMobile: info.OriginMobile, @@ -74,7 +75,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, diff --git a/services/sale/internal/logic/itemsLogic.go b/services/sale/internal/logic/itemsLogic.go index 09b18e0..8de9b36 100644 --- a/services/sale/internal/logic/itemsLogic.go +++ b/services/sale/internal/logic/itemsLogic.go @@ -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)), }, }, diff --git a/services/sale/internal/logic/statusLogic.go b/services/sale/internal/logic/statusLogic.go index 50158c1..9c0680a 100644 --- a/services/sale/internal/logic/statusLogic.go +++ b/services/sale/internal/logic/statusLogic.go @@ -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 diff --git a/services/sale/internal/logic/userIdentity.go b/services/sale/internal/logic/userIdentity.go new file mode 100644 index 0000000..784970d --- /dev/null +++ b/services/sale/internal/logic/userIdentity.go @@ -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 +} diff --git a/services/sale/internal/server/saleServer.go b/services/sale/internal/server/saleServer.go index 04d9ff5..3b671bc 100644 --- a/services/sale/internal/server/saleServer.go +++ b/services/sale/internal/server/saleServer.go @@ -86,7 +86,13 @@ func (s *SaleServer) InfoInternal(ctx context.Context, in *sale.InfoReq) (*sale. return l.InfoInternal(in) } -// 按 id 批量查销售 id+name(内部) +// 按 user_id 查销售详情(内部) +func (s *SaleServer) InfoByUserId(ctx context.Context, in *sale.InfoByUserIdReq) (*sale.InfoData, error) { + l := logic.NewInfoByUserIdLogic(ctx, s.svcCtx) + return l.InfoByUserId(in) +} + +// ids 批量查销售 func (s *SaleServer) NamesByIds(ctx context.Context, in *sale.NamesByIdsReq) (*sale.NamesByIdsData, error) { l := logic.NewNamesByIdsLogic(ctx, s.svcCtx) return l.NamesByIds(in) diff --git a/services/sale/internal/svc/serviceContext.go b/services/sale/internal/svc/serviceContext.go index e5ebfba..6ff1734 100644 --- a/services/sale/internal/svc/serviceContext.go +++ b/services/sale/internal/svc/serviceContext.go @@ -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, } } diff --git a/services/sale/run.toml b/services/sale/run.toml index 05a692a..6f83ec6 100644 --- a/services/sale/run.toml +++ b/services/sale/run.toml @@ -2,7 +2,7 @@ login_out_time=43200 #api接口超时时间分 login_refresh_out_time=83200 name = "sale-service" - listenOn = "0.0.0.0:10900" + listenOn = "0.0.0.0:10300" mode = "dev" [log] path = "logs" @@ -52,4 +52,8 @@ db = 0 [encrypt] - data_key = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a" \ No newline at end of file + data_key = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a" + +[services] + chore = "chore-service" + user = "user-service" \ No newline at end of file diff --git a/services/sale/saleClient/sale.go b/services/sale/saleClient/sale.go index 9ab2af6..a2ca156 100644 --- a/services/sale/saleClient/sale.go +++ b/services/sale/saleClient/sale.go @@ -14,24 +14,25 @@ import ( ) type ( - CreateReq = sale.CreateReq - EditReq = sale.EditReq - GroupCreateReq = sale.GroupCreateReq - GroupEmptyReq = sale.GroupEmptyReq - GroupItem = sale.GroupItem - GroupItemsReq = sale.GroupItemsReq - InfoData = sale.InfoData - InfoReq = sale.InfoReq - ItemsReq = sale.ItemsReq - NameItem = sale.NameItem - NamesByIdsData = sale.NamesByIdsData - NamesByIdsItem = sale.NamesByIdsItem - NamesByIdsReq = sale.NamesByIdsReq - NamesData = sale.NamesData - NamesReq = sale.NamesReq - Region = sale.Region - Response = sale.Response - StatusReq = sale.StatusReq + CreateReq = sale.CreateReq + EditReq = sale.EditReq + GroupCreateReq = sale.GroupCreateReq + GroupEmptyReq = sale.GroupEmptyReq + GroupItem = sale.GroupItem + GroupItemsReq = sale.GroupItemsReq + InfoByUserIdReq = sale.InfoByUserIdReq + InfoData = sale.InfoData + InfoReq = sale.InfoReq + ItemsReq = sale.ItemsReq + NameItem = sale.NameItem + NamesByIdsData = sale.NamesByIdsData + NamesByIdsItem = sale.NamesByIdsItem + NamesByIdsReq = sale.NamesByIdsReq + NamesData = sale.NamesData + NamesReq = sale.NamesReq + Region = sale.Region + Response = sale.Response + StatusReq = sale.StatusReq Sale interface { // 销售分组 @@ -49,7 +50,9 @@ type ( Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) // 销售详情 InfoInternal(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*InfoData, error) - // 按 id 批量查销售 id+name(内部) + // 按 user_id 查销售详情(内部) + InfoByUserId(ctx context.Context, in *InfoByUserIdReq, opts ...grpc.CallOption) (*InfoData, error) + // ids 批量查销售 NamesByIds(ctx context.Context, in *NamesByIdsReq, opts ...grpc.CallOption) (*NamesByIdsData, error) } @@ -127,7 +130,13 @@ func (m *defaultSale) InfoInternal(ctx context.Context, in *InfoReq, opts ...grp return client.InfoInternal(ctx, in, opts...) } -// 按 id 批量查销售 id+name(内部) +// 按 user_id 查销售详情(内部) +func (m *defaultSale) InfoByUserId(ctx context.Context, in *InfoByUserIdReq, opts ...grpc.CallOption) (*InfoData, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.InfoByUserId(ctx, in, opts...) +} + +// ids 批量查销售 func (m *defaultSale) NamesByIds(ctx context.Context, in *NamesByIdsReq, opts ...grpc.CallOption) (*NamesByIdsData, error) { client := sale.NewSaleClient(m.cli.Conn()) return client.NamesByIds(ctx, in, opts...) diff --git a/services/sale/validator/validator.go b/services/sale/validator/validator.go index ff0be34..1797c2b 100644 --- a/services/sale/validator/validator.go +++ b/services/sale/validator/validator.go @@ -147,13 +147,24 @@ func (p InfoValidator) GetMessage() validate.ValidatorMessages { } } +type InfoByUserIdValidator struct { + UserId int64 `validate:"required,gt=0"` +} + +func (p InfoByUserIdValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "UserId.required": "用户ID不能为空", + "UserId.gt": "用户ID必须大于0", + } +} + type ItemsValidator struct { Name string `validate:"omitempty,max=256"` Page uint32 `validate:"omitempty,min=1"` PageSize uint32 `validate:"omitempty,min=1,max=100"` SaleId int64 `validate:"omitempty,gte=0"` Type uint32 `validate:"omitempty,oneof=1 2 3"` - Status uint32 `validate:"omitempty,oneof=1 2 3 9"` + Status uint32 `validate:"omitempty,oneof=1 2"` } func (p ItemsValidator) GetMessage() validate.ValidatorMessages { @@ -168,8 +179,8 @@ func (p ItemsValidator) GetMessage() validate.ValidatorMessages { type StatusValidator struct { Id int64 `validate:"required,gt=0"` - Status uint32 `validate:"required,oneof=1 2 3"` - Reason string `validate:"required_if=Status 2 required_if=Status 3,max=255"` + Status uint32 `validate:"required,oneof=1 2"` + Reason string `validate:"required_if=Status 2,max=255"` } func (p StatusValidator) GetMessage() validate.ValidatorMessages { @@ -177,8 +188,8 @@ func (p StatusValidator) GetMessage() validate.ValidatorMessages { "Id.required": "ID不能为空", "Id.gt": "ID必须大于0", "Status.required": "状态不能为空", - "Status.oneof": "状态不对", - "Reason.required_if": "未通过或禁用状态,理由不能为空", + "Status.oneof": "状态不对,仅支持1开启或2禁用", + "Reason.required_if": "禁用时理由不能为空", "Reason.max": "理由长度不能超过255", } } diff --git a/services/task/tmp/runner-build b/services/task/tmp/runner-build deleted file mode 100644 index 51e032d..0000000 Binary files a/services/task/tmp/runner-build and /dev/null differ diff --git a/services/user/internal/config/jwt.go b/services/user/internal/config/jwt.go new file mode 100644 index 0000000..0b7e4fc --- /dev/null +++ b/services/user/internal/config/jwt.go @@ -0,0 +1,43 @@ +package config + +import ( + "fmt" + + "lone-services/pkg/utils" +) + +// JWTAuth 由服务配置初始化的 access / refresh 两套 JWT。 +type JWTAuth struct { + Access *utils.JWT + Refresh *utils.JWT +} + +func LoadJWTAuth() (*JWTAuth, error) { + issuer := utils.GetConfigString("jwt.issuer") + if issuer == utils.StringEmpty { + issuer = "lone-user" + } + + access, err := utils.NewJWT( + utils.GetConfigString("jwt.access_secret"), + issuer, + utils.GetConfigInt("jwt.access_ttl"), + ) + if err != nil { + return nil, fmt.Errorf("jwt access: %w", err) + } + + refresh, err := utils.NewJWT( + utils.GetConfigString("jwt.refresh_secret"), + issuer, + utils.GetConfigInt("jwt.refresh_ttl"), + ) + if err != nil { + return nil, fmt.Errorf("jwt refresh: %w", err) + } + + return &JWTAuth{ + Access: access, + Refresh: refresh, + }, nil +} diff --git a/services/user/internal/config/wechat.go b/services/user/internal/config/wechat.go new file mode 100644 index 0000000..38f5a0a --- /dev/null +++ b/services/user/internal/config/wechat.go @@ -0,0 +1,18 @@ +package config + +import ( + "fmt" + + "lone-services/pkg/utils" + "lone-services/pkg/wechat/auth" +) + +func NewWechatClient(clientCode string) (*auth.Client, error) { + prefix := "wechat." + clientCode + appID := utils.GetConfigString(prefix + ".app_id") + secret := utils.GetConfigString(prefix + ".app_secret") + if appID == utils.StringEmpty || secret == utils.StringEmpty { + return nil, fmt.Errorf("wechat config missing for client %s", clientCode) + } + return auth.NewClient(appID, secret), nil +} diff --git a/services/user/internal/dao/client.go b/services/user/internal/dao/client.go new file mode 100644 index 0000000..d5b7211 --- /dev/null +++ b/services/user/internal/dao/client.go @@ -0,0 +1,11 @@ +package dao + +type Client struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + Code string `gorm:"column:code" json:"code"` + Name string `gorm:"column:name" json:"name"` + AllowedGrants string `gorm:"column:allowed_grants;type:json" json:"allowed_grants"` + SubjectType string `gorm:"column:subject_type" json:"subject_type"` + StoreStaff uint8 `gorm:"column:store_staff" json:"store_staff"` + Status uint8 `gorm:"column:status" json:"status"` +} diff --git a/services/user/internal/dao/const.go b/services/user/internal/dao/const.go new file mode 100644 index 0000000..0f43155 --- /dev/null +++ b/services/user/internal/dao/const.go @@ -0,0 +1,27 @@ +package dao + +const ( + StatusEnabled uint8 = 1 + StatusDisabled uint8 = 2 + + CredentialTypePassword = "password" + CredentialTypeWecom = "wecom" + CredentialTypeOpenid = "openid" + CredentialTypeUnionid = "unionid" + + GrantTypeOpenid = "openid" + GrantTypePassword = "password" + GrantTypeSms = "sms" + + // Type* 登录身份(写入 session.type / X-User-Type),与订单侧约定一致 + TypeSale uint8 = 1 // 销售 + TypeStore uint8 = 2 // 门店 + TypeUser uint8 = 3 // 普通用户 + + SubjectTypeSale = "sale" + SubjectTypeStore = "store" + SubjectTypeUser = "user" + + // ExtraJsonEmpty MySQL JSON 列不能写空串,无扩展字段时用 {} + ExtraJsonEmpty = "{}" +) diff --git a/services/user/internal/dao/session.go b/services/user/internal/dao/session.go new file mode 100644 index 0000000..ab5ad62 --- /dev/null +++ b/services/user/internal/dao/session.go @@ -0,0 +1,70 @@ +package dao + +type Token struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + Info UserLoginSession `json:"info"` +} + +type UserLoginSession struct { + Id int64 `json:"id"` + Name string `json:"name"` + Avatar string `json:"avatar"` + Mobile string `json:"mobile"` + Gender uint8 `json:"gender"` + Birthday string `json:"birthday"` + Type uint8 `json:"type"` // 1销售 2门店 3普通用户 + ClientCode string `json:"client_code"` + SaleId int64 `json:"sale_id,omitempty"` + StoreId int64 `json:"store_id,omitempty"` +} + +// ProfileData 当前登录用户详情(按 type 填充扩展字段) +type ProfileData struct { + Type uint8 `json:"type"` + Base ProfileBase `json:"base"` + Sale *ProfileSaleData `json:"sale,omitempty"` + Store any `json:"store,omitempty"` // 门店详情暂未开放 +} + +type ProfileBase struct { + UserId int64 `json:"user_id"` + Name string `json:"name"` + Avatar string `json:"avatar"` + Mobile string `json:"mobile"` + Gender uint8 `json:"gender"` + Birthday string `json:"birthday"` + Status uint8 `json:"status"` +} + +type ProfileSaleData struct { + Id int64 `json:"id"` + SaleId int64 `json:"sale_id"` + Name string `json:"name"` + Mobile string `json:"mobile"` + OriginMobile string `json:"origin_mobile"` + Avatar string `json:"avatar"` + Account string `json:"account"` + Type uint32 `json:"type"` + Sex uint32 `json:"sex"` + BirthDate string `json:"birth_date"` + Status uint32 `json:"status"` + GroupId int64 `json:"group_id"` + GroupName string `json:"group_name"` + Address string `json:"address"` + ProvinceId int64 `json:"province_id"` + CityId int64 `json:"city_id"` + DistrictId int64 `json:"district_id"` + TerritoryId int64 `json:"territory_id"` + TerritoryName string `json:"territory_name"` + Region *ProfileSaleRegion `json:"region,omitempty"` + IdCardFront string `json:"id_card_front"` + IdCardBack string `json:"id_card_back"` + BusinessLicense string `json:"business_license"` +} + +type ProfileSaleRegion struct { + Province string `json:"province"` + City string `json:"city"` + District string `json:"district"` +} diff --git a/services/user/internal/dao/user.go b/services/user/internal/dao/user.go index 9c3192e..5b724b3 100644 --- a/services/user/internal/dao/user.go +++ b/services/user/internal/dao/user.go @@ -2,107 +2,37 @@ package dao import "lone-services/pkg/utils" +// UserRow 主用户(表 users) +type UserRow struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + Mobile string `gorm:"column:mobile" json:"mobile"` + Name string `gorm:"column:name" json:"name"` + Avatar string `gorm:"column:avatar" json:"avatar"` + Gender uint8 `gorm:"column:gender" json:"gender"` + Birthday utils.CustomTime `gorm:"column:birthday;type:date" json:"birthday"` + Status uint8 `gorm:"column:status" json:"status"` + CreatedAt utils.CustomTime `gorm:"column:created_at" json:"created_at"` + UpdatedAt utils.CustomTime `gorm:"column:updated_at" json:"updated_at"` +} + +// UserCreate 新建用户 type UserCreate struct { - Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` - Openid string `gorm:"column:openid" json:"openid"` - Username string `gorm:"column:username" json:"username"` - Nickname string `gorm:"column:nickname" json:"nickname"` - Avatar string `gorm:"column:avatar" json:"avatar"` - Mobile string `gorm:"column:mobile" json:"mobile"` - Gender uint8 `gorm:"column:gender" json:"gender"` - Birthday string `gorm:"column:birthday" json:"birthday"` - AppId uint32 `gorm:"column:app_id" json:"app_id"` - Status uint8 `gorm:"column:status" json:"status"` - IsRegistered uint8 `gorm:"column:is_registered" json:"is_registered"` - IsFaceVerified uint8 `gorm:"column:is_face_verified" json:"is_face_verified"` - IsProfileCompleted uint8 `gorm:"column:is_profile_completed" json:"is_profile_completed"` - OnTrialNum int `gorm:"column:on_trial_num" json:"on_trial_num"` -} - -type UserCreateByPwd struct { - Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` - Type uint8 `gorm:"column:type" json:"type"` - Account string `gorm:"column:account" json:"account"` - Password string `gorm:"column:password" json:"password"` - Salt string `gorm:"column:salt" json:"salt"` - Mobile string `gorm:"column:mobile" json:"mobile"` - AppId uint32 `gorm:"column:app_id" json:"app_id"` - Status uint8 `gorm:"column:status" json:"status"` - IsRegistered uint8 `gorm:"column:is_registered" json:"is_registered"` - IsFaceVerified uint8 `gorm:"column:is_face_verified" json:"is_face_verified"` - IsProfileCompleted uint8 `gorm:"column:is_profile_completed" json:"is_profile_completed"` - OnTrialNum int `gorm:"column:on_trial_num" json:"on_trial_num"` -} - -type UserExist struct { - Id int64 `gorm:"column:id" json:"id"` -} - -type UserInfo struct { - Id int64 `gorm:"column:id" json:"id"` - Openid string `gorm:"column:openid" json:"openid"` - Username string `gorm:"column:username" json:"username"` - Nickname string `gorm:"column:nickname" json:"nickname"` - Avatar string `gorm:"column:avatar" json:"avatar"` - Mobile string `gorm:"column:mobile" json:"mobile"` - Gender uint8 `gorm:"column:gender" json:"gender"` - Birthday string `gorm:"column:birthday" json:"birthday"` - Type uint8 `gorm:"column:type" json:"type"` - Account string `gorm:"column:account" json:"account"` - AppId uint32 `gorm:"column:app_id" json:"app_id"` - Status uint8 `gorm:"column:status" json:"status"` -} - -type UserLoginRow struct { - UserInfo - Salt string `gorm:"column:salt" json:"-"` - Password string `gorm:"column:password" json:"-"` -} - -type Token struct { - Token string `json:"token"` - Refresh string `json:"refresh"` - Info UserLoginSession `json:"info"` -} - -type UserLoginSession struct { - Id int64 `json:"id"` - Openid string `json:"openid"` - Username string `json:"username"` - Nickname string `json:"nickname"` - Avatar string `json:"avatar"` - Mobile string `json:"mobile"` - Gender uint8 `json:"gender"` - Birthday string `json:"birthday"` - Type uint8 `json:"type"` - Account string `json:"account"` - AppId uint32 `json:"app_id"` - LastTime utils.CustomTime `json:"last_time"` -} - -type UserListRow struct { - Id int64 `gorm:"column:id" json:"id"` - Username string `gorm:"column:username" json:"username"` - Nickname string `gorm:"column:nickname" json:"nickname"` - Avatar string `gorm:"column:avatar" json:"avatar"` - Mobile string `gorm:"column:mobile" json:"mobile"` - OnTrialNum int `gorm:"column:on_trial_num" json:"on_trial_num"` - Gender int `gorm:"column:gender" json:"gender"` - Birthday string `gorm:"column:birthday" json:"birthday"` - Status uint8 `gorm:"column:status" json:"status"` - CreatedAt utils.CustomTime `gorm:"column:created_at" json:"created_at"` - UpdatedAt utils.CustomTime `gorm:"column:updated_at" json:"updated_at"` + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + Mobile string `gorm:"column:mobile" json:"mobile"` + Name string `gorm:"column:name" json:"name"` + Avatar string `gorm:"column:avatar" json:"avatar"` + Gender uint8 `gorm:"column:gender" json:"gender"` + Birthday utils.CustomTime `gorm:"column:birthday;type:date" json:"birthday"` + Status uint8 `gorm:"column:status" json:"status"` } type UserListItem struct { Id int64 `json:"id"` - Username string `json:"username"` - Nickname string `json:"nickname"` + Name string `json:"name"` HeadPortrait string `json:"head_portrait"` Mobile string `json:"mobile"` OriginMobile string `json:"origin_mobile"` - OnTrialNum int `json:"on_trial_num"` - Gender int `json:"gender"` + Gender uint8 `json:"gender"` Birthday string `json:"birthday"` Status uint8 `json:"status"` CreatedAt utils.CustomTime `json:"created_at"` diff --git a/services/user/internal/dao/user_client.go b/services/user/internal/dao/user_client.go new file mode 100644 index 0000000..fece24b --- /dev/null +++ b/services/user/internal/dao/user_client.go @@ -0,0 +1,11 @@ +package dao + +import "lone-services/pkg/utils" + +type UserClient struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + UserId int64 `gorm:"column:user_id" json:"user_id"` + ClientCode string `gorm:"column:client_code" json:"client_code"` + Status uint8 `gorm:"column:status" json:"status"` + OpenedAt utils.CustomTime `gorm:"column:opened_at" json:"opened_at"` +} diff --git a/services/user/internal/dao/user_credential.go b/services/user/internal/dao/user_credential.go new file mode 100644 index 0000000..463bff0 --- /dev/null +++ b/services/user/internal/dao/user_credential.go @@ -0,0 +1,11 @@ +package dao + +type UserCredential struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + UserId int64 `gorm:"column:user_id" json:"user_id"` + CredentialType string `gorm:"column:credential_type" json:"credential_type"` + Identifier string `gorm:"column:identifier" json:"identifier"` + Secret string `gorm:"column:secret" json:"secret"` + ExtraJson string `gorm:"column:extra_json;type:json" json:"extra_json"` + Status uint8 `gorm:"column:status" json:"status"` +} diff --git a/services/user/internal/logic/authHelper.go b/services/user/internal/logic/authHelper.go new file mode 100644 index 0000000..c2f8d9b --- /dev/null +++ b/services/user/internal/logic/authHelper.go @@ -0,0 +1,227 @@ +package logic + +import ( + "context" + "errors" + "strconv" + "strings" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/services/user/internal/config" + "lone-services/services/user/internal/dao" + "lone-services/services/user/internal/model" + + jsoniter "github.com/json-iterator/go" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "gorm.io/gorm" +) + +func clientAllowsGrant(allowedGrants, grantType string) bool { + if allowedGrants == utils.StringEmpty { + return false + } + var grants []string + if err := jsoniter.UnmarshalFromString(allowedGrants, &grants); err != nil { + return strings.Contains(allowedGrants, grantType) + } + for _, g := range grants { + if g == grantType { + return true + } + } + return false +} + +func loadEnabledClient(clientCode string) (*dao.Client, error) { + var client dao.Client + clientModel := model.ClientModel{}.Init() + if err := clientModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "code": clientCode, + "status": strconv.Itoa(int(dao.StatusEnabled)), + }, + }, &client); err != nil { + return nil, err + } + if client.Id < utils.NumberOne { + return nil, status.Error(codes.InvalidArgument, "端配置不存在或已禁用") + } + return &client, nil +} + +func findCredential(credentialType, identifier string) (*dao.UserCredential, error) { + var cred dao.UserCredential + credModel := model.UserCredentialModel{}.Init() + if err := credModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "credential_type": credentialType, + "identifier": identifier, + }, + }, &cred); err != nil { + return nil, err + } + if cred.Id < utils.NumberOne { + return nil, nil + } + return &cred, nil +} + +func loadEnabledUser(userId int64) (*dao.UserRow, error) { + var row dao.UserRow + userModel := model.UserModel{}.Init() + if err := userModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "id": strconv.FormatInt(userId, utils.NumberTen), + "status": strconv.Itoa(int(dao.StatusEnabled)), + }, + }, &row); err != nil { + return nil, err + } + if row.Id < utils.NumberOne { + return nil, status.Error(codes.NotFound, utils.ErrorNotFund.Msg) + } + return &row, nil +} + +func resolveOrCreateWechatUser(ctx context.Context, db *gorm.DB, openid, unionid, clientCode string) (int64, error) { + openCred, err := findCredential(dao.CredentialTypeOpenid, openid) + if err != nil { + return utils.NumberZero, err + } + if openCred != nil { + if openCred.Status == dao.StatusDisabled { + return utils.NumberZero, status.Error(codes.FailedPrecondition, "登录凭证已禁用") + } + if err := ensureUserClient(db, openCred.UserId, clientCode); err != nil { + return utils.NumberZero, err + } + return openCred.UserId, nil + } + + var userId int64 + if unionid != utils.StringEmpty { + unionCred, uErr := findCredential(dao.CredentialTypeUnionid, unionid) + if uErr != nil { + return utils.NumberZero, uErr + } + if unionCred != nil { + if unionCred.Status == dao.StatusDisabled { + return utils.NumberZero, status.Error(codes.FailedPrecondition, "登录凭证已禁用") + } + userId = unionCred.UserId + } + } + + txErr := db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + if userId < utils.NumberOne { + userModel := model.UserModel{}.Init() + userModel.Base = userModel.Base.WithTX(tx) + add := dao.UserCreate{Status: dao.StatusEnabled} + if err := userModel.Create(&add); err != nil { + return err + } + userId = add.Id + } + + if err := createWechatCredentials(tx, userId, openid, unionid); err != nil { + return err + } + return ensureUserClient(tx, userId, clientCode) + }) + if txErr != nil { + if st, ok := status.FromError(txErr); ok { + return utils.NumberZero, st.Err() + } + return utils.NumberZero, txErr + } + return userId, nil +} + +func createWechatCredentials(tx *gorm.DB, userId int64, openid, unionid string) error { + credModel := model.UserCredentialModel{}.Init() + credModel.Base = credModel.Base.WithTX(tx) + + var existOpen dao.UserCredential + if err := credModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "credential_type": dao.CredentialTypeOpenid, + "identifier": openid, + }, + }, &existOpen); err != nil { + return err + } + if existOpen.Id < utils.NumberOne { + if err := credModel.Create(&dao.UserCredential{ + UserId: userId, + CredentialType: dao.CredentialTypeOpenid, + Identifier: openid, + ExtraJson: dao.ExtraJsonEmpty, + Status: dao.StatusEnabled, + }); err != nil { + return err + } + } else if existOpen.UserId != userId { + return status.Error(codes.AlreadyExists, "openid已被其他用户占用") + } + + if unionid == utils.StringEmpty { + return nil + } + + var existUnion dao.UserCredential + if err := credModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "credential_type": dao.CredentialTypeUnionid, + "identifier": unionid, + }, + }, &existUnion); err != nil { + return err + } + if existUnion.Id < utils.NumberOne { + return credModel.Create(&dao.UserCredential{ + UserId: userId, + CredentialType: dao.CredentialTypeUnionid, + Identifier: unionid, + ExtraJson: dao.ExtraJsonEmpty, + Status: dao.StatusEnabled, + }) + } + if existUnion.UserId != userId { + return status.Error(codes.AlreadyExists, "unionid 已被其他用户占用") + } + return nil +} + +func issueLoginToken(ctx context.Context, jwtAuth *config.JWTAuth, saleSvcName string, row *dao.UserRow, client *dao.Client) (*dao.Token, error) { + if jwtAuth == nil || jwtAuth.Access == nil || jwtAuth.Refresh == nil { + return nil, errors.New("jwt not initialized") + } + mobile := decryptMobile(row.Mobile) + + var saleId int64 + userType := dao.TypeUser + if client != nil { + userType = subjectTypeToUserType(client.SubjectType) + } + if userType == dao.TypeSale { + saleInfo, err := fetchSaleByUserId(ctx, saleSvcName, row.Id) + if err != nil { + return nil, err + } + if saleInfo != nil { + saleId = saleInfo.Id + } + } + + session := toSession(*row, mobile, client, saleId) + ret, err := buildJwtToken(jwtAuth, session) + if err != nil { + return nil, err + } + if st := setLogin(jwtAuth, ret.AccessToken, ret.RefreshToken, session); st.Code != utils.Ok.Code { + return nil, errors.New(st.Msg) + } + return &ret, nil +} diff --git a/services/user/internal/logic/ensureBizIdentityLogic.go b/services/user/internal/logic/ensureBizIdentityLogic.go new file mode 100644 index 0000000..a356ef5 --- /dev/null +++ b/services/user/internal/logic/ensureBizIdentityLogic.go @@ -0,0 +1,215 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + user "lone-services/rpc/user/pb" + "lone-services/services/user/internal/dao" + "lone-services/services/user/internal/model" + "lone-services/services/user/internal/svc" + "lone-services/services/user/validator" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "gorm.io/gorm" +) + +type EnsureBizIdentityLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewEnsureBizIdentityLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EnsureBizIdentityLogic { + return &EnsureBizIdentityLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *EnsureBizIdentityLogic) EnsureBizIdentity(in *user.EnsureBizIdentityReq) (*user.EnsureBizIdentityData, error) { + var req validator.EnsureBizIdentityValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return nil, status.Error(codes.InvalidArgument, msg) + } + + var client dao.Client + clientModel := model.ClientModel{}.Init() + if err := clientModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "code": req.ClientCode, + "status": strconv.Itoa(int(dao.StatusEnabled)), + }, + }, &client); err != nil { + l.Errorf("ensure identity client: %v", err) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + if client.Id < utils.NumberOne { + return nil, status.Error(codes.InvalidArgument, "端配置不存在或已禁用") + } + + encryptMobile, encErr := utils.EncryptPhone(req.Mobile) + if encErr != nil { + l.Errorf("ensure identity encrypt mobile: %v", encErr) + return nil, status.Error(codes.Internal, utils.ErrorEncryptAesError.Msg) + } + + var ( + userId int64 + created bool + name = req.Name + ) + + txErr := l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error { + userModel := model.UserModel{}.Init() + userModel.Base = userModel.Base.WithTX(tx) + + var exist dao.UserRow + if err := userModel.GetOne(modelbase.Params{ + Eq: map[string]string{"mobile": encryptMobile}, + }, &exist); err != nil { + return err + } + + if exist.Id > utils.NumberZero { + userId = exist.Id + if name == utils.StringEmpty { + name = exist.Name + } + if exist.Status == dao.StatusDisabled { + return status.Error(codes.FailedPrecondition, "用户已禁用") + } + } else { + birthday, bErr := utils.ParseDateOnly(req.Birthday) + if bErr != nil { + return status.Error(codes.InvalidArgument, "生日格式不正确") + } + add := dao.UserCreate{ + Mobile: encryptMobile, + Name: req.Name, + Avatar: req.Avatar, + Gender: uint8(req.Gender), + Birthday: birthday, + Status: dao.StatusEnabled, + } + if err := userModel.Create(&add); err != nil { + return err + } + userId = add.Id + created = true + } + + if req.CredentialType != utils.StringEmpty { + if err := ensureCredential(tx, userId, req, encryptMobile); err != nil { + return err + } + } + + return ensureUserClient(tx, userId, req.ClientCode) + }) + if txErr != nil { + if st, ok := status.FromError(txErr); ok { + return nil, st.Err() + } + l.Errorf("ensure identity tx: %v", txErr) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + + return &user.EnsureBizIdentityData{ + UserId: userId, + Created: created, + Mobile: encryptMobile, + Name: name, + }, nil +} + +func ensureCredential(tx *gorm.DB, userId int64, req validator.EnsureBizIdentityValidator, encryptMobile string) error { + identifier := req.Identifier + if identifier == utils.StringEmpty { + identifier = encryptMobile + } + + secret := utils.StringEmpty + if req.Secret != utils.StringEmpty { + hashed, err := utils.EncryptPassword(req.Secret) + if err != nil { + return err + } + secret = hashed + } + + credModel := model.UserCredentialModel{}.Init() + credModel.Base = credModel.Base.WithTX(tx) + + var exist dao.UserCredential + if err := credModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "credential_type": req.CredentialType, + "identifier": identifier, + }, + }, &exist); err != nil { + return err + } + + if exist.Id > utils.NumberZero { + if exist.UserId != userId { + return status.Error(codes.AlreadyExists, "登录凭证已被其他用户占用") + } + if secret == utils.StringEmpty { + return nil + } + _, err := credModel.Edit(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(exist.Id, utils.NumberTen)}, + }, map[string]interface{}{ + "secret": secret, + "status": dao.StatusEnabled, + }) + return err + } + + return credModel.Create(&dao.UserCredential{ + UserId: userId, + CredentialType: req.CredentialType, + Identifier: identifier, + Secret: secret, + ExtraJson: dao.ExtraJsonEmpty, + Status: dao.StatusEnabled, + }) +} + +func ensureUserClient(tx *gorm.DB, userId int64, clientCode string) error { + clientModel := model.UserClientModel{}.Init() + clientModel.Base = clientModel.Base.WithTX(tx) + + var exist dao.UserClient + if err := clientModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "user_id": strconv.FormatInt(userId, utils.NumberTen), + "client_code": clientCode, + }, + }, &exist); err != nil { + return err + } + if exist.Id > utils.NumberZero { + if exist.Status == dao.StatusEnabled { + return nil + } + _, err := clientModel.Edit(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(exist.Id, utils.NumberTen)}, + }, map[string]interface{}{"status": dao.StatusEnabled}) + return err + } + + return clientModel.Create(&dao.UserClient{ + UserId: userId, + ClientCode: clientCode, + Status: dao.StatusEnabled, + OpenedAt: utils.Now(), + }) +} diff --git a/services/user/internal/logic/infoLogic.go b/services/user/internal/logic/infoLogic.go new file mode 100644 index 0000000..c12c9cb --- /dev/null +++ b/services/user/internal/logic/infoLogic.go @@ -0,0 +1,94 @@ +package logic + +import ( + "context" + + "lone-services/pkg/utils" + user "lone-services/rpc/user/pb" + "lone-services/services/user/internal/dao" + "lone-services/services/user/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type InfoLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InfoLogic { + return &InfoLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *InfoLogic) Info(in *user.InfoReq) (*user.Response, error) { + loginUser := utils.GetUserFromCtx(l.ctx) + if loginUser.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + row, err := loadEnabledUser(loginUser.ID) + if err != nil { + l.Errorf("info load user: %v", err) + return failResponse(utils.ErrorNotFund), nil + } + + userType := loginUser.Type + if userType < utils.NumberOne { + userType = dao.TypeUser + } + + ret := dao.ProfileData{ + Type: userType, + Base: dao.ProfileBase{ + UserId: row.Id, + Name: row.Name, + Avatar: row.Avatar, + Mobile: decryptMobile(row.Mobile), + Gender: row.Gender, + Birthday: row.Birthday.DateString(), + Status: row.Status, + }, + } + + switch userType { + case dao.TypeUser: + return okResponse(ret), nil + case dao.TypeSale: + saleData, saleErr := l.loadSaleProfile(loginUser) + if saleErr != nil { + l.Errorf("info load sale: %v", saleErr) + return failResponse(utils.Fail), nil + } + if saleData == nil { + return outResponse(utils.ErrorNotFund, "销售信息不存在"), nil + } + ret.Sale = saleData + return okResponse(ret), nil + case dao.TypeStore: + return outResponse(utils.Fail, "门店详情暂未开放"), nil + default: + return outResponse(utils.ErrorParams, "未知的用户类型"), nil + } +} + +func (l *InfoLogic) loadSaleProfile(loginUser utils.UserInfo) (*dao.ProfileSaleData, error) { + if loginUser.SaleId > utils.NumberZero { + data, err := fetchSaleById(l.ctx, l.svcCtx.SaleSvcName, loginUser.SaleId) + if err != nil { + return nil, err + } + if data != nil { + return toProfileSale(data), nil + } + } + data, err := fetchSaleByUserId(l.ctx, l.svcCtx.SaleSvcName, loginUser.ID) + if err != nil { + return nil, err + } + return toProfileSale(data), nil +} diff --git a/services/user/internal/logic/loginLogic.go b/services/user/internal/logic/loginLogic.go index fb6af88..f3f5870 100644 --- a/services/user/internal/logic/loginLogic.go +++ b/services/user/internal/logic/loginLogic.go @@ -2,16 +2,17 @@ package logic import ( "context" - "lone-services/pkg/modelbase" + "lone-services/pkg/utils" "lone-services/pkg/validate" user "lone-services/rpc/user/pb" + userconfig "lone-services/services/user/internal/config" "lone-services/services/user/internal/dao" - "lone-services/services/user/internal/model" "lone-services/services/user/internal/svc" "lone-services/services/user/validator" "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/status" ) type LoginLogic struct { @@ -29,31 +30,64 @@ func NewLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginLogic } func (l *LoginLogic) Login(in *user.LoginReq) (*user.Response, error) { - var v validator.LoginValidator - if msg := validate.ValidateFromProto(in, &v); msg != utils.StringEmpty { + var req validator.LoginValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { return outResponse(utils.ErrorParams, msg), nil } - var row dao.UserLoginRow - err := model.UserModel{}.Init().GetOne(modelbase.Params{ - Eq: map[string]string{ - "openid": v.Openid, - "status": utils.StringStatusOk, - }, - }, &row) + switch req.GrantType { + case dao.GrantTypeOpenid: + return l.loginByOpenid(req) + case dao.GrantTypePassword: + return outResponse(utils.ErrorParams, "密码登录暂未开放"), nil + case dao.GrantTypeSms: + return outResponse(utils.ErrorParams, "验证码登录暂未开放"), nil + default: + return outResponse(utils.ErrorParams, "不支持的登录方式"), nil + } +} + +func (l *LoginLogic) loginByOpenid(req validator.LoginValidator) (*user.Response, error) { + client, err := loadEnabledClient(req.ClientCode) if err != nil { - l.Errorf("login by openid: %v", err) + l.Errorf("login load client: %v", err) return failResponse(utils.Fail), nil } - if row.Id < utils.NumberOne { + if !clientAllowsGrant(client.AllowedGrants, dao.GrantTypeOpenid) { + return outResponse(utils.ErrorParams, "该端不支持微信登录"), nil + } + + wxClient, cfgErr := userconfig.NewWechatClient(req.ClientCode) + if cfgErr != nil { + l.Errorf("login wechat config: %v", cfgErr) + return outResponse(utils.Fail, "微信配置缺失"), nil + } + + session, wxErr := wxClient.Code2Session(req.Code) + if wxErr != nil { + l.Errorf("login code2session: %v", wxErr) + return outResponse(utils.Fail, "微信登录失败"), nil + } + + userId, resolveErr := resolveOrCreateWechatUser(l.ctx, l.svcCtx.DB, session.OpenID, session.UnionID, req.ClientCode) + if resolveErr != nil { + l.Errorf("login resolve wechat user: %v", resolveErr) + if st, ok := status.FromError(resolveErr); ok { + return outResponse(utils.Fail, st.Message()), nil + } + return failResponse(utils.Fail), nil + } + + row, userErr := loadEnabledUser(userId) + if userErr != nil { + l.Errorf("login load user: %v", userErr) return failResponse(utils.ErrorNotFund), nil } - mobile := decryptMobile(row.Mobile) - session := toSession(row.UserInfo, mobile) - ret := buildToken(session) - if status := setLogin(ret.Token, ret.Refresh, session); status.Code != utils.Ok.Code { - return failResponse(status), nil + ret, tokenErr := issueLoginToken(l.ctx, l.svcCtx.JWT, l.svcCtx.SaleSvcName, row, client) + if tokenErr != nil { + l.Errorf("login issue token: %v", tokenErr) + return failResponse(utils.Fail), nil } return okResponse(ret), nil } diff --git a/services/user/internal/logic/registerByUserLogic.go b/services/user/internal/logic/registerByUserLogic.go deleted file mode 100644 index 4adf11b..0000000 --- a/services/user/internal/logic/registerByUserLogic.go +++ /dev/null @@ -1,102 +0,0 @@ -package logic - -import ( - "context" - "lone-services/pkg/modelbase" - "lone-services/pkg/redis" - "lone-services/pkg/utils" - "lone-services/pkg/validate" - user "lone-services/rpc/user/pb" - "lone-services/services/user/internal/dao" - "lone-services/services/user/internal/model" - "lone-services/services/user/internal/svc" - "lone-services/services/user/validator" - "strconv" - - "github.com/zeromicro/go-zero/core/logx" -) - -type RegisterByUserLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewRegisterByUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterByUserLogic { - return &RegisterByUserLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -func (l *RegisterByUserLogic) RegisterByUser(in *user.RegisterByUserReq) (*user.Response, error) { - var v validator.RegisterByUserValidator - if msg := validate.ValidateFromProto(in, &v); msg != utils.StringEmpty { - return outResponse(utils.ErrorParams, msg), nil - } - - codePrefix := utils.StringEmpty - if v.Type == utils.NumberTwo { - codePrefix = "1:" - } - - test := utils.GetConfigBool("sms.sms_test") - isTest := test && v.Code == utils.GetConfigString("sms.sms_test_code") - codeKey := utils.CodeKey + codePrefix + v.Account - code, err := redis.Client.Get(l.ctx, codeKey).Result() - if (err != nil || code != v.Code) && !isTest { - return outResponse(utils.ErrorMissingParams, "验证码错误"), nil - } - - var old dao.UserExist - err = model.UserModel{}.Init().GetOne(modelbase.Params{ - Eq: map[string]string{ - "account": v.Account, - "type": strconv.FormatUint(uint64(v.Type), utils.NumberTen), - }, - }, &old) - if err != nil { - l.Errorf("registerByUser check account: %v", err) - return failResponse(utils.Fail), nil - } - if old.Id > utils.NumberZero { - return failResponse(utils.ErrorDataIsExist), nil - } - - add := dao.UserCreateByPwd{ - Type: uint8(v.Type), - Account: v.Account, - Salt: utils.GetRandString(utils.NumberFive), - AppId: v.AppId, - Status: utils.NumberOne, - IsRegistered: utils.NumberOne, - IsFaceVerified: utils.NumberTwo, - IsProfileCompleted: utils.NumberTwo, - OnTrialNum: utils.NumberOne, - } - pwd := utils.GetSaltPassword(add.Salt, v.Pwd) - add.Password, err = utils.EncryptPassword(pwd) - if err != nil { - l.Errorf("registerByUser encrypt password: %v", err) - return failResponse(utils.Fail), nil - } - - if v.Type == utils.NumberOne { - encryptMobile, cErr := utils.EncryptPhone(v.Account) - if cErr != nil { - l.Errorf("registerByUser encrypt mobile: %v", cErr) - return failResponse(utils.ErrorEncryptAesError), nil - } - add.Mobile = encryptMobile - } - - err = model.UserModel{}.Init().CreateByPwd(&add) - if err != nil || add.Id < utils.NumberOne { - l.Errorf("registerByUser create: %v", err) - return failResponse(utils.Fail), nil - } - - redis.Client.Del(l.ctx, codeKey) - return okResponse(map[string]any{"id": add.Id}), nil -} diff --git a/services/user/internal/logic/registerLogic.go b/services/user/internal/logic/registerLogic.go deleted file mode 100644 index 8598bae..0000000 --- a/services/user/internal/logic/registerLogic.go +++ /dev/null @@ -1,97 +0,0 @@ -package logic - -import ( - "context" - "lone-services/pkg/modelbase" - "lone-services/pkg/utils" - "lone-services/pkg/validate" - user "lone-services/rpc/user/pb" - "lone-services/services/user/internal/dao" - "lone-services/services/user/internal/model" - "lone-services/services/user/internal/svc" - "lone-services/services/user/validator" - - "github.com/zeromicro/go-zero/core/logx" -) - -type RegisterLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger -} - -func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic { - return &RegisterLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -func (l *RegisterLogic) Register(in *user.RegisterReq) (*user.Response, error) { - var v validator.RegisterValidator - if msg := validate.ValidateFromProto(in, &v); msg != utils.StringEmpty { - return outResponse(utils.ErrorParams, msg), nil - } - - openid := v.Openid - if openid == utils.StringEmpty { - openid = "mock_" + utils.MD5Encrypt(v.Mobile+utils.Now().String()) - } - - var exist dao.UserExist - err := model.UserModel{}.Init().GetOne(modelbase.Params{ - Eq: map[string]string{"openid": openid}, - }, &exist) - if err != nil { - l.Errorf("register check openid: %v", err) - return failResponse(utils.Fail), nil - } - if exist.Id > utils.NumberZero { - return failResponse(utils.ErrorExist), nil - } - - encryptMobile, cErr := utils.EncryptPhone(v.Mobile) - if cErr != nil { - l.Errorf("register encrypt mobile: %v", cErr) - return failResponse(utils.ErrorEncryptAesError), nil - } - - add := dao.UserCreate{ - Openid: openid, - Username: v.Username, - Nickname: v.Nickname, - Avatar: v.Avatar, - Mobile: encryptMobile, - Gender: uint8(v.Gender), - Birthday: v.Birthday, - AppId: v.AppId, - Status: utils.NumberOne, - IsRegistered: utils.NumberOne, - IsFaceVerified: utils.NumberTwo, - IsProfileCompleted: utils.NumberTwo, - OnTrialNum: utils.NumberOne, - } - err = model.UserModel{}.Init().Create(&add) - if err != nil { - l.Errorf("register create: %v", err) - return failResponse(utils.Fail), nil - } - - session := toSession(dao.UserInfo{ - Id: add.Id, - Openid: add.Openid, - Username: add.Username, - Nickname: add.Nickname, - Avatar: add.Avatar, - Gender: add.Gender, - Birthday: add.Birthday, - AppId: add.AppId, - Status: add.Status, - }, v.Mobile) - ret := buildToken(session) - if status := setLogin(ret.Token, ret.Refresh, session); status.Code != utils.Ok.Code { - return failResponse(status), nil - } - return okResponse(ret), nil -} diff --git a/services/user/internal/logic/response.go b/services/user/internal/logic/response.go index 12e7aea..2068407 100644 --- a/services/user/internal/logic/response.go +++ b/services/user/internal/logic/response.go @@ -2,12 +2,14 @@ package logic import ( "context" + "strconv" + "time" + "lone-services/pkg/redis" "lone-services/pkg/utils" user "lone-services/rpc/user/pb" + "lone-services/services/user/internal/config" "lone-services/services/user/internal/dao" - "strconv" - "time" jsoniter "github.com/json-iterator/go" ) @@ -46,44 +48,80 @@ func decryptMobile(mobile string) string { return plain } -func toSession(info dao.UserInfo, mobilePlain string) dao.UserLoginSession { +func subjectTypeToUserType(subjectType string) uint8 { + switch subjectType { + case dao.SubjectTypeSale: + return dao.TypeSale + case dao.SubjectTypeStore: + return dao.TypeStore + case dao.SubjectTypeUser: + return dao.TypeUser + default: + return dao.TypeUser + } +} + +func toSession(info dao.UserRow, mobilePlain string, client *dao.Client, saleId int64) dao.UserLoginSession { + userType := dao.TypeUser + clientCode := utils.StringEmpty + if client != nil { + clientCode = client.Code + userType = subjectTypeToUserType(client.SubjectType) + } return dao.UserLoginSession{ - Id: info.Id, - Openid: info.Openid, - Username: info.Username, - Nickname: info.Nickname, - Avatar: info.Avatar, - Mobile: mobilePlain, - Gender: info.Gender, - Birthday: info.Birthday, - Type: info.Type, - Account: info.Account, - AppId: info.AppId, - LastTime: utils.Now(), + Id: info.Id, + Name: info.Name, + Avatar: info.Avatar, + Mobile: mobilePlain, + Gender: info.Gender, + Birthday: info.Birthday.DateString(), + Type: userType, + ClientCode: clientCode, + SaleId: saleId, } } -func buildToken(session dao.UserLoginSession) dao.Token { - seed := session.Mobile + session.Openid + utils.Now().String() - token := utils.MD5Encrypt(seed) +func sessionClaims(session dao.UserLoginSession, tokenType string) utils.Claims { + return utils.Claims{ + UserID: session.Id, + Name: session.Name, + Avatar: session.Avatar, + Mobile: session.Mobile, + Gender: session.Gender, + Birthday: session.Birthday, + Type: session.Type, + ClientCode: session.ClientCode, + SaleId: session.SaleId, + StoreId: session.StoreId, + TokenType: tokenType, + } +} + +func buildJwtToken(jwtAuth *config.JWTAuth, session dao.UserLoginSession) (dao.Token, error) { + accessToken, err := jwtAuth.Access.Sign(sessionClaims(session, utils.TokenTypeAccess)) + if err != nil { + return dao.Token{}, err + } + refreshToken, err := jwtAuth.Refresh.Sign(sessionClaims(session, utils.TokenTypeRefresh)) + if err != nil { + return dao.Token{}, err + } return dao.Token{ - Token: token, - Refresh: utils.MD5Encrypt(seed + token), - Info: session, - } + AccessToken: accessToken, + RefreshToken: refreshToken, + Info: session, + }, nil } -func setLogin(token, refresh string, session dao.UserLoginSession) utils.Status { - expireMin := utils.GetConfigInt("base.login_out_time") - expire := time.Duration(expireMin) * time.Minute - refreshMin := utils.GetConfigInt("base.login_refresh_out_time") - refreshExpire := time.Duration(refreshMin) * time.Minute +func setLogin(jwtAuth *config.JWTAuth, accessToken, refreshToken string, session dao.UserLoginSession) utils.Status { + accessExpire := time.Duration(jwtAuth.Access.TTL) * time.Second + refreshExpire := time.Duration(jwtAuth.Refresh.TTL) * time.Second ctx := context.Background() userStr, _ := jsoniter.Marshal(session) - redisKey := utils.GetLoginKey(utils.LoginTypeUser, token) - if err := redis.Client.Set(ctx, redisKey, userStr, expire).Err(); err != nil { + redisKey := utils.GetLoginKey(utils.LoginTypeUser, accessToken) + if err := redis.Client.Set(ctx, redisKey, userStr, accessExpire).Err(); err != nil { return utils.Fail } @@ -99,14 +137,14 @@ func setLogin(token, refresh string, session dao.UserLoginSession) utils.Status } } - loginInfo.Token = token - loginInfo.Refresh = refresh + loginInfo.Token = accessToken + loginInfo.Refresh = refreshToken loginInfo.Info = userStr newStr, _ := jsoniter.Marshal(loginInfo) if err := redis.Client.Set(ctx, redisKeysKey, newStr, refreshExpire).Err(); err != nil { return utils.Fail } - refreshKey := utils.GetLoginRefreshKey(utils.LoginTypeUser, refresh) + refreshKey := utils.GetLoginRefreshKey(utils.LoginTypeUser, refreshToken) if err := redis.Client.Set(ctx, refreshKey, strconv.FormatInt(session.Id, utils.NumberTen), refreshExpire).Err(); err != nil { return utils.Fail } diff --git a/services/user/internal/logic/revokeBizClientLogic.go b/services/user/internal/logic/revokeBizClientLogic.go new file mode 100644 index 0000000..24cab10 --- /dev/null +++ b/services/user/internal/logic/revokeBizClientLogic.go @@ -0,0 +1,68 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + user "lone-services/rpc/user/pb" + "lone-services/services/user/internal/dao" + "lone-services/services/user/internal/model" + "lone-services/services/user/internal/svc" + "lone-services/services/user/validator" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type RevokeBizClientLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewRevokeBizClientLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RevokeBizClientLogic { + return &RevokeBizClientLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// RevokeBizClient 内部:撤销某业务端开通(不删 users,保留其他端) +func (l *RevokeBizClientLogic) RevokeBizClient(in *user.RevokeBizClientReq) (*user.RevokeBizClientData, error) { + var req validator.RevokeBizClientValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return nil, status.Error(codes.InvalidArgument, msg) + } + + clientModel := model.UserClientModel{}.Init() + var row dao.UserClient + if err := clientModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "user_id": strconv.FormatInt(req.UserId, utils.NumberTen), + "client_code": req.ClientCode, + }, + }, &row); err != nil { + l.Errorf("revoke biz client get: %v", err) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + if row.Id < utils.NumberOne { + return &user.RevokeBizClientData{Revoked: false}, nil + } + if row.Status == dao.StatusDisabled { + return &user.RevokeBizClientData{Revoked: true}, nil + } + + if _, err := clientModel.Edit(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(row.Id, utils.NumberTen)}, + }, map[string]interface{}{"status": dao.StatusDisabled}); err != nil { + l.Errorf("revoke biz client edit: %v", err) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + + return &user.RevokeBizClientData{Revoked: true}, nil +} diff --git a/services/user/internal/logic/saleClient.go b/services/user/internal/logic/saleClient.go new file mode 100644 index 0000000..75a602a --- /dev/null +++ b/services/user/internal/logic/saleClient.go @@ -0,0 +1,89 @@ +package logic + +import ( + "context" + + "lone-services/pkg/rpcclient" + "lone-services/pkg/utils" + salepb "lone-services/rpc/sale/pb" + "lone-services/services/user/internal/dao" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func fetchSaleByUserId(ctx context.Context, saleSvcName string, userId int64) (*salepb.InfoData, error) { + if saleSvcName == utils.StringEmpty || userId < utils.NumberOne { + return nil, nil + } + cli, err := rpcclient.Get(saleSvcName) + if err != nil { + return nil, err + } + data, err := salepb.NewSaleClient(cli.Conn()).InfoByUserId(ctx, &salepb.InfoByUserIdReq{UserId: userId}) + if err != nil { + if st, ok := status.FromError(err); ok && st.Code() == codes.NotFound { + return nil, nil + } + return nil, err + } + return data, nil +} + +func fetchSaleById(ctx context.Context, saleSvcName string, saleId int64) (*salepb.InfoData, error) { + if saleSvcName == utils.StringEmpty || saleId < utils.NumberOne { + return nil, nil + } + cli, err := rpcclient.Get(saleSvcName) + if err != nil { + return nil, err + } + data, err := salepb.NewSaleClient(cli.Conn()).InfoInternal(ctx, &salepb.InfoReq{Id: saleId}) + if err != nil { + if st, ok := status.FromError(err); ok && st.Code() == codes.NotFound { + return nil, nil + } + return nil, err + } + return data, nil +} + +func toProfileSale(data *salepb.InfoData) *dao.ProfileSaleData { + if data == nil { + return nil + } + out := &dao.ProfileSaleData{ + Id: data.Id, + SaleId: data.SaleId, + Name: data.Name, + Mobile: data.Mobile, + OriginMobile: data.OriginMobile, + Avatar: data.Avatar, + Account: data.Account, + Type: data.Type, + Sex: data.Sex, + BirthDate: data.BirthDate, + Status: data.Status, + GroupId: data.GroupId, + Address: data.Address, + ProvinceId: data.ProvinceId, + CityId: data.CityId, + DistrictId: data.DistrictId, + TerritoryId: data.TerritoryId, + TerritoryName: data.TerritoryName, + IdCardFront: data.IdCardFront, + IdCardBack: data.IdCardBack, + BusinessLicense: data.BusinessLicense, + } + if data.Group != nil { + out.GroupName = data.Group.Name + } + if data.Region != nil { + out.Region = &dao.ProfileSaleRegion{ + Province: data.Region.Province, + City: data.Region.City, + District: data.Region.District, + } + } + return out +} diff --git a/services/user/internal/logic/updateMobileLogic.go b/services/user/internal/logic/updateMobileLogic.go new file mode 100644 index 0000000..6d36782 --- /dev/null +++ b/services/user/internal/logic/updateMobileLogic.go @@ -0,0 +1,111 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + user "lone-services/rpc/user/pb" + "lone-services/services/user/internal/dao" + "lone-services/services/user/internal/model" + "lone-services/services/user/internal/svc" + "lone-services/services/user/validator" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "gorm.io/gorm" +) + +type UpdateMobileLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewUpdateMobileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateMobileLogic { + return &UpdateMobileLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +// UpdateMobile 内部:修改用户手机号,并同步 password 凭证的 identifier +func (l *UpdateMobileLogic) UpdateMobile(in *user.UpdateMobileReq) (*user.UpdateMobileData, error) { + var req validator.UpdateMobileValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return nil, status.Error(codes.InvalidArgument, msg) + } + + userModel := model.UserModel{}.Init() + var row dao.UserRow + if err := userModel.GetOne(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(req.UserId, utils.NumberTen)}, + }, &row); err != nil { + l.Errorf("update mobile get user: %v", err) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + if row.Id < utils.NumberOne { + return nil, status.Error(codes.NotFound, utils.ErrorNotFund.Msg) + } + + newEncrypt, encErr := utils.EncryptPhone(req.Mobile) + if encErr != nil { + l.Errorf("update mobile encrypt: %v", encErr) + return nil, status.Error(codes.Internal, utils.ErrorEncryptAesError.Msg) + } + if newEncrypt == row.Mobile { + return &user.UpdateMobileData{UserId: row.Id, Mobile: row.Mobile}, nil + } + + var occupied dao.UserRow + if err := userModel.GetOne(modelbase.Params{ + Eq: map[string]string{"mobile": newEncrypt}, + }, &occupied); err != nil { + l.Errorf("update mobile unique check: %v", err) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + if occupied.Id > utils.NumberZero && occupied.Id != row.Id { + return nil, status.Error(codes.AlreadyExists, utils.ErrorDataIsExist.Msg) + } + + oldMobile := row.Mobile + txErr := l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error { + um := model.UserModel{}.Init() + um.Base = um.Base.WithTX(tx) + if _, err := um.Edit(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(row.Id, utils.NumberTen)}, + }, map[string]interface{}{"mobile": newEncrypt}); err != nil { + return err + } + + credModel := model.UserCredentialModel{}.Init() + credModel.Base = credModel.Base.WithTX(tx) + var cred dao.UserCredential + if err := credModel.GetOne(modelbase.Params{ + Eq: map[string]string{ + "user_id": strconv.FormatInt(row.Id, utils.NumberTen), + "credential_type": dao.CredentialTypePassword, + "identifier": oldMobile, + }, + }, &cred); err != nil { + return err + } + if cred.Id < utils.NumberOne { + return nil + } + _, err := credModel.Edit(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(cred.Id, utils.NumberTen)}, + }, map[string]interface{}{"identifier": newEncrypt}) + return err + }) + if txErr != nil { + l.Errorf("update mobile tx: %v", txErr) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + + return &user.UpdateMobileData{UserId: row.Id, Mobile: newEncrypt}, nil +} diff --git a/services/user/internal/logic/userItemsLogic.go b/services/user/internal/logic/userItemsLogic.go index c430cec..60c2d43 100644 --- a/services/user/internal/logic/userItemsLogic.go +++ b/services/user/internal/logic/userItemsLogic.go @@ -63,8 +63,9 @@ func (l *UserItemsLogic) UserItems(in *user.UserItemsReq) (*user.Response, error } } - var list []dao.UserListRow - result, err := model.UserModel{}.Init().Page(params, &list) + var list []dao.UserRow + userModel := model.UserModel{}.Init() + result, err := userModel.Page(params, &list) if err != nil { l.Errorf("user items: %v", err) return failResponse(utils.Fail), nil @@ -79,14 +80,12 @@ func (l *UserItemsLogic) UserItems(in *user.UserItemsReq) (*user.Response, error } items = append(items, dao.UserListItem{ Id: row.Id, - Username: row.Username, - Nickname: row.Nickname, + Name: row.Name, HeadPortrait: headPortrait, Mobile: mobile, OriginMobile: row.Mobile, - OnTrialNum: row.OnTrialNum, Gender: row.Gender, - Birthday: row.Birthday, + Birthday: row.Birthday.DateString(), Status: row.Status, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt, diff --git a/services/user/internal/logic/usersByIdsLogic.go b/services/user/internal/logic/usersByIdsLogic.go new file mode 100644 index 0000000..05da653 --- /dev/null +++ b/services/user/internal/logic/usersByIdsLogic.go @@ -0,0 +1,79 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + user "lone-services/rpc/user/pb" + "lone-services/services/user/internal/dao" + "lone-services/services/user/internal/model" + "lone-services/services/user/internal/svc" + "lone-services/services/user/validator" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type UsersByIdsLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewUsersByIdsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UsersByIdsLogic { + return &UsersByIdsLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *UsersByIdsLogic) UsersByIds(in *user.UsersByIdsReq) (*user.UsersByIdsData, error) { + var req validator.UsersByIdsValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return nil, status.Error(codes.InvalidArgument, msg) + } + + ids := make([]string, 0, len(req.Ids)) + seen := make(map[int64]struct{}, len(req.Ids)) + for _, id := range req.Ids { + if id < utils.NumberOne { + continue + } + if _, ok := seen[id]; ok { + continue + } + seen[id] = struct{}{} + ids = append(ids, strconv.FormatInt(id, utils.NumberTen)) + } + if len(ids) < utils.NumberOne { + return &user.UsersByIdsData{Items: []*user.UserBriefItem{}}, nil + } + + var rows []dao.UserRow + userModel := model.UserModel{}.Init() + if err := userModel.Items(modelbase.Params{ + In: map[string][]string{"id": ids}, + }, &rows); err != nil { + l.Errorf("users by ids: %v", err) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + + items := make([]*user.UserBriefItem, 0, len(rows)) + for i := range rows { + items = append(items, &user.UserBriefItem{ + Id: rows[i].Id, + Mobile: rows[i].Mobile, + Name: rows[i].Name, + Avatar: rows[i].Avatar, + Gender: uint32(rows[i].Gender), + Birthday: rows[i].Birthday.DateString(), + Status: uint32(rows[i].Status), + }) + } + return &user.UsersByIdsData{Items: items}, nil +} diff --git a/services/user/internal/model/client.go b/services/user/internal/model/client.go new file mode 100644 index 0000000..3930a8f --- /dev/null +++ b/services/user/internal/model/client.go @@ -0,0 +1,16 @@ +package model + +import "lone-services/pkg/modelbase" + +type ClientModel struct { + modelbase.Base +} + +func (m ClientModel) TableName() string { + return modelbase.Prefix() + "client" +} + +func (m ClientModel) Init() ClientModel { + m.Table = m.TableName() + return m +} diff --git a/services/user/internal/model/user.go b/services/user/internal/model/user.go index d8c1272..d19f484 100644 --- a/services/user/internal/model/user.go +++ b/services/user/internal/model/user.go @@ -21,7 +21,3 @@ func (m UserModel) Init() UserModel { func (m UserModel) Create(data *dao.UserCreate) error { return m.Base.Create(data) } - -func (m UserModel) CreateByPwd(data *dao.UserCreateByPwd) error { - return m.Base.Create(data) -} diff --git a/services/user/internal/model/user_client.go b/services/user/internal/model/user_client.go new file mode 100644 index 0000000..a631be9 --- /dev/null +++ b/services/user/internal/model/user_client.go @@ -0,0 +1,23 @@ +package model + +import ( + "lone-services/pkg/modelbase" + "lone-services/services/user/internal/dao" +) + +type UserClientModel struct { + modelbase.Base +} + +func (m UserClientModel) TableName() string { + return modelbase.Prefix() + "user_client" +} + +func (m UserClientModel) Init() UserClientModel { + m.Table = m.TableName() + return m +} + +func (m UserClientModel) Create(data *dao.UserClient) error { + return m.Base.Create(data) +} diff --git a/services/user/internal/model/user_credential.go b/services/user/internal/model/user_credential.go new file mode 100644 index 0000000..bdaad57 --- /dev/null +++ b/services/user/internal/model/user_credential.go @@ -0,0 +1,23 @@ +package model + +import ( + "lone-services/pkg/modelbase" + "lone-services/services/user/internal/dao" +) + +type UserCredentialModel struct { + modelbase.Base +} + +func (m UserCredentialModel) TableName() string { + return modelbase.Prefix() + "user_credential" +} + +func (m UserCredentialModel) Init() UserCredentialModel { + m.Table = m.TableName() + return m +} + +func (m UserCredentialModel) Create(data *dao.UserCredential) error { + return m.Base.Create(data) +} diff --git a/services/user/internal/server/userserver.go b/services/user/internal/server/userserver.go index 7bb8099..9fe7e8a 100644 --- a/services/user/internal/server/userserver.go +++ b/services/user/internal/server/userserver.go @@ -23,21 +23,16 @@ func NewUserServer(svcCtx *svc.ServiceContext) *UserServer { } } -func (s *UserServer) Register(ctx context.Context, in *user.RegisterReq) (*user.Response, error) { - l := logic.NewRegisterLogic(ctx, s.svcCtx) - return l.Register(in) -} - -func (s *UserServer) RegisterByUser(ctx context.Context, in *user.RegisterByUserReq) (*user.Response, error) { - l := logic.NewRegisterByUserLogic(ctx, s.svcCtx) - return l.RegisterByUser(in) -} - func (s *UserServer) Login(ctx context.Context, in *user.LoginReq) (*user.Response, error) { l := logic.NewLoginLogic(ctx, s.svcCtx) return l.Login(in) } +func (s *UserServer) Info(ctx context.Context, in *user.InfoReq) (*user.Response, error) { + l := logic.NewInfoLogic(ctx, s.svcCtx) + return l.Info(in) +} + func (s *UserServer) UserItems(ctx context.Context, in *user.UserItemsReq) (*user.Response, error) { l := logic.NewUserItemsLogic(ctx, s.svcCtx) return l.UserItems(in) @@ -47,3 +42,23 @@ func (s *UserServer) UserStatus(ctx context.Context, in *user.UserStatusReq) (*u l := logic.NewUserStatusLogic(ctx, s.svcCtx) return l.UserStatus(in) } + +func (s *UserServer) EnsureBizIdentity(ctx context.Context, in *user.EnsureBizIdentityReq) (*user.EnsureBizIdentityData, error) { + l := logic.NewEnsureBizIdentityLogic(ctx, s.svcCtx) + return l.EnsureBizIdentity(in) +} + +func (s *UserServer) UsersByIds(ctx context.Context, in *user.UsersByIdsReq) (*user.UsersByIdsData, error) { + l := logic.NewUsersByIdsLogic(ctx, s.svcCtx) + return l.UsersByIds(in) +} + +func (s *UserServer) UpdateMobile(ctx context.Context, in *user.UpdateMobileReq) (*user.UpdateMobileData, error) { + l := logic.NewUpdateMobileLogic(ctx, s.svcCtx) + return l.UpdateMobile(in) +} + +func (s *UserServer) RevokeBizClient(ctx context.Context, in *user.RevokeBizClientReq) (*user.RevokeBizClientData, error) { + l := logic.NewRevokeBizClientLogic(ctx, s.svcCtx) + return l.RevokeBizClient(in) +} diff --git a/services/user/internal/svc/servicecontext.go b/services/user/internal/svc/servicecontext.go index b708f4b..9a3a232 100644 --- a/services/user/internal/svc/servicecontext.go +++ b/services/user/internal/svc/servicecontext.go @@ -4,19 +4,28 @@ import ( "lone-services/pkg/utils" "lone-services/services/user/internal/config" + "github.com/zeromicro/go-zero/core/logx" "gorm.io/gorm" ) type ServiceContext struct { - Config config.Config - DB *gorm.DB - Prefix string + Config config.Config + DB *gorm.DB + Prefix string + JWT *config.JWTAuth + SaleSvcName string } -func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { +func NewServiceContext(c config.Config, db *gorm.DB, jwtAuth *config.JWTAuth) *ServiceContext { + saleSvc := utils.GetConfigString("services.sale") + if saleSvc == utils.StringEmpty { + logx.Error("config services.sale empty") + } return &ServiceContext{ - Config: c, - DB: db, - Prefix: utils.GetConfigString("mysql.prefix"), + Config: c, + DB: db, + Prefix: utils.GetConfigString("mysql.prefix"), + JWT: jwtAuth, + SaleSvcName: saleSvc, } } diff --git a/services/user/user.go b/services/user/user.go index 3390db4..b3eb305 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -121,12 +121,18 @@ func main() { debug := utils.GetConfigBool("mysql.debug") modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) + jwtAuth, err := config.LoadJWTAuth() + if err != nil { + logx.Errorf("jwt init: %v", err) + os.Exit(1) + } + rpcConf := zrpc.RpcServerConf{ ListenOn: listenOn, } rpcConf.Mode = mode - ctx := svc.NewServiceContext(c, db) + ctx := svc.NewServiceContext(c, db, jwtAuth) s := zrpc.MustNewServer(rpcConf, func(grpcServer *grpc.Server) { user.RegisterUserServer(grpcServer, server.NewUserServer(ctx)) diff --git a/services/user/userClient/user.go b/services/user/userClient/user.go index 7b62baf..b50ffa9 100644 --- a/services/user/userClient/user.go +++ b/services/user/userClient/user.go @@ -14,19 +14,30 @@ import ( ) type ( - LoginReq = user.LoginReq - RegisterByUserReq = user.RegisterByUserReq - RegisterReq = user.RegisterReq - Response = user.Response - UserItemsReq = user.UserItemsReq - UserStatusReq = user.UserStatusReq + EnsureBizIdentityData = user.EnsureBizIdentityData + EnsureBizIdentityReq = user.EnsureBizIdentityReq + InfoReq = user.InfoReq + LoginReq = user.LoginReq + Response = user.Response + RevokeBizClientData = user.RevokeBizClientData + RevokeBizClientReq = user.RevokeBizClientReq + UpdateMobileData = user.UpdateMobileData + UpdateMobileReq = user.UpdateMobileReq + UserBriefItem = user.UserBriefItem + UserItemsReq = user.UserItemsReq + UserStatusReq = user.UserStatusReq + UsersByIdsData = user.UsersByIdsData + UsersByIdsReq = user.UsersByIdsReq User interface { - Register(ctx context.Context, in *RegisterReq, opts ...grpc.CallOption) (*Response, error) - RegisterByUser(ctx context.Context, in *RegisterByUserReq, opts ...grpc.CallOption) (*Response, error) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error) + Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error) UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error) UserStatus(ctx context.Context, in *UserStatusReq, opts ...grpc.CallOption) (*Response, error) + EnsureBizIdentity(ctx context.Context, in *EnsureBizIdentityReq, opts ...grpc.CallOption) (*EnsureBizIdentityData, error) + UsersByIds(ctx context.Context, in *UsersByIdsReq, opts ...grpc.CallOption) (*UsersByIdsData, error) + UpdateMobile(ctx context.Context, in *UpdateMobileReq, opts ...grpc.CallOption) (*UpdateMobileData, error) + RevokeBizClient(ctx context.Context, in *RevokeBizClientReq, opts ...grpc.CallOption) (*RevokeBizClientData, error) } defaultUser struct { @@ -40,21 +51,16 @@ func NewUser(cli zrpc.Client) User { } } -func (m *defaultUser) Register(ctx context.Context, in *RegisterReq, opts ...grpc.CallOption) (*Response, error) { - client := user.NewUserClient(m.cli.Conn()) - return client.Register(ctx, in, opts...) -} - -func (m *defaultUser) RegisterByUser(ctx context.Context, in *RegisterByUserReq, opts ...grpc.CallOption) (*Response, error) { - client := user.NewUserClient(m.cli.Conn()) - return client.RegisterByUser(ctx, in, opts...) -} - func (m *defaultUser) Login(ctx context.Context, in *LoginReq, opts ...grpc.CallOption) (*Response, error) { client := user.NewUserClient(m.cli.Conn()) return client.Login(ctx, in, opts...) } +func (m *defaultUser) Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.Info(ctx, in, opts...) +} + func (m *defaultUser) UserItems(ctx context.Context, in *UserItemsReq, opts ...grpc.CallOption) (*Response, error) { client := user.NewUserClient(m.cli.Conn()) return client.UserItems(ctx, in, opts...) @@ -64,3 +70,23 @@ func (m *defaultUser) UserStatus(ctx context.Context, in *UserStatusReq, opts .. client := user.NewUserClient(m.cli.Conn()) return client.UserStatus(ctx, in, opts...) } + +func (m *defaultUser) EnsureBizIdentity(ctx context.Context, in *EnsureBizIdentityReq, opts ...grpc.CallOption) (*EnsureBizIdentityData, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.EnsureBizIdentity(ctx, in, opts...) +} + +func (m *defaultUser) UsersByIds(ctx context.Context, in *UsersByIdsReq, opts ...grpc.CallOption) (*UsersByIdsData, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.UsersByIds(ctx, in, opts...) +} + +func (m *defaultUser) UpdateMobile(ctx context.Context, in *UpdateMobileReq, opts ...grpc.CallOption) (*UpdateMobileData, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.UpdateMobile(ctx, in, opts...) +} + +func (m *defaultUser) RevokeBizClient(ctx context.Context, in *RevokeBizClientReq, opts ...grpc.CallOption) (*RevokeBizClientData, error) { + client := user.NewUserClient(m.cli.Conn()) + return client.RevokeBizClient(ctx, in, opts...) +} diff --git a/services/user/validator/user.go b/services/user/validator/user.go index bb63466..99e5714 100644 --- a/services/user/validator/user.go +++ b/services/user/validator/user.go @@ -2,56 +2,25 @@ package validator import "lone-services/pkg/validate" -type RegisterValidator struct { - Openid string - Nickname string `validate:"required"` - Avatar string `validate:"required"` - Mobile string `validate:"required"` - Gender uint32 `validate:"required,oneof=1 2"` - Birthday string `validate:"required"` - Username string `validate:"required"` - AppId uint32 `validate:"required"` -} - -func (p RegisterValidator) GetMessage() validate.ValidatorMessages { - return validate.ValidatorMessages{ - "Nickname.required": "昵称不能为空", - "Avatar.required": "头像不能为空", - "Mobile.required": "手机号不能为空", - "Gender.required": "性别不能为空", - "Gender.oneof": "性别传值不对", - "Birthday.required": "生日不能为空", - "Username.required": "姓名不能为空", - "AppId.required": "应用标识不能为空", - } -} - -type RegisterByUserValidator struct { - Type uint32 `validate:"required,oneof=1 2"` - Account string `validate:"required"` - Pwd string `validate:"required"` - Code string `validate:"required"` - AppId uint32 `validate:"required"` -} - -func (p RegisterByUserValidator) GetMessage() validate.ValidatorMessages { - return validate.ValidatorMessages{ - "Type.required": "类型不能为空", - "Type.oneof": "类型传值不对", - "Account.required": "账号不能为空", - "Pwd.required": "密码不能为空", - "Code.required": "验证码不能为空", - "AppId.required": "应用标识不能为空", - } -} - type LoginValidator struct { - Openid string `validate:"required"` + ClientCode string `validate:"required,max=32"` + GrantType string `validate:"required,oneof=openid password sms"` + Code string `validate:"required_if=GrantType openid,omitempty,max=128"` + Mobile string `validate:"required_if=GrantType password,omitempty,required_if=GrantType sms,omitempty,max=20"` + Password string `validate:"required_if=GrantType password,omitempty,max=64"` + SmsCode string `validate:"required_if=GrantType sms,omitempty,max=8"` } func (p LoginValidator) GetMessage() validate.ValidatorMessages { return validate.ValidatorMessages{ - "Openid.required": "Openid不能为空", + "ClientCode.required": "端编码不能为空", + "ClientCode.max": "端编码过长", + "GrantType.required": "登录方式不能为空", + "GrantType.oneof": "登录方式不正确", + "Code.required_if": "微信code不能为空", + "Mobile.required_if": "手机号不能为空", + "Password.required_if": "密码不能为空", + "SmsCode.required_if": "验证码不能为空", } } @@ -81,3 +50,63 @@ func (p UserStatusValidator) GetMessage() validate.ValidatorMessages { "Status.oneof": "状态传值不对", } } + +type EnsureBizIdentityValidator struct { + Mobile string `validate:"required,max=20"` + Name string `validate:"omitempty,max=64"` + Avatar string `validate:"omitempty,max=255"` + Gender uint32 `validate:"omitempty,oneof=0 1 2 3"` + Birthday string `validate:"omitempty,max=12"` + ClientCode string `validate:"required,max=32"` + CredentialType string `validate:"omitempty,max=32"` + Identifier string `validate:"omitempty,max=128"` + Secret string `validate:"omitempty,max=255"` +} + +func (p EnsureBizIdentityValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Mobile.required": "手机号不能为空", + "Mobile.max": "手机号过长", + "ClientCode.required": "端编码不能为空", + "ClientCode.max": "端编码过长", + } +} + +type UsersByIdsValidator struct { + Ids []int64 `validate:"required,min=1,dive,gt=0"` +} + +func (p UsersByIdsValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Ids.required": "用户ID不能为空", + "Ids.min": "用户ID不能为空", + } +} + +type UpdateMobileValidator struct { + UserId int64 `validate:"required,gt=0"` + Mobile string `validate:"required,max=20"` +} + +func (p UpdateMobileValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "UserId.required": "用户ID不能为空", + "UserId.gt": "用户ID必须大于0", + "Mobile.required": "手机号不能为空", + "Mobile.max": "手机号过长", + } +} + +type RevokeBizClientValidator struct { + UserId int64 `validate:"required,gt=0"` + ClientCode string `validate:"required,max=32"` +} + +func (p RevokeBizClientValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "UserId.required": "用户ID不能为空", + "UserId.gt": "用户ID必须大于0", + "ClientCode.required": "端编码不能为空", + "ClientCode.max": "端编码过长", + } +} diff --git a/services/wecom/run.toml b/services/wecom/run.toml index 035630f..bd86fad 100644 --- a/services/wecom/run.toml +++ b/services/wecom/run.toml @@ -16,7 +16,7 @@ compress = false [wecom] - skip = false + skip = true department_id = 1 corp_id = "wwb83e24dcf1946e3e" icon_url = "https://skin-test-api.ailuowan.com/images/20260509/1778321760824864613.png"