diff --git a/.gitea/workflows/cd-test.yml b/.gitea/workflows/cd-test.yml index 536194a..ac1fedc 100644 --- a/.gitea/workflows/cd-test.yml +++ b/.gitea/workflows/cd-test.yml @@ -39,5 +39,8 @@ jobs: docker pull ${{ vars.REGISTRY }}/lone/product:latest docker pull ${{ vars.REGISTRY }}/lone/admin:latest docker pull ${{ vars.REGISTRY }}/lone/user:latest + docker pull ${{ vars.REGISTRY }}/lone/ad:latest + docker pull ${{ vars.REGISTRY }}/lone/chore:latest docker pull ${{ vars.REGISTRY }}/lone/express:latest + docker pull ${{ vars.REGISTRY }}/lone/sale:latest docker compose up -d diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 5935876..eeda492 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -12,12 +12,14 @@ on: - "services/ad/**" - "services/chore/**" - "services/express/**" + - "services/sale/**" - "rpc/product/**" - "rpc/admin/**" - "rpc/user/**" - "rpc/ad/**" - "rpc/chore/**" - "rpc/express/**" + - "rpc/sale/**" - "pkg/**" - ".gitea/workflows/ci.yml" workflow_dispatch: @@ -33,6 +35,7 @@ jobs: ad: ${{ steps.filter.outputs.ad }} chore: ${{ steps.filter.outputs.chore }} express: ${{ steps.filter.outputs.express }} + sale: ${{ steps.filter.outputs.sale }} steps: - name: Checkout uses: https://git.ailuowan.com/deploy/checkout@v4 @@ -49,6 +52,7 @@ jobs: ad=false chore=false express=false + sale=false if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then bff=true @@ -58,6 +62,7 @@ jobs: ad=true chore=true express=true + sale=true else before="${{ github.event.before }}" if [ -z "$before" ] || [ "$before" = "0000000000000000000000000000000000000000" ]; then @@ -76,6 +81,7 @@ jobs: echo "$changed" | grep -qE '^(services/ad|rpc/ad|pkg)/|^\.gitea/workflows/ci\.yml$' && ad=true || true echo "$changed" | grep -qE '^(services/chore|rpc/chore|pkg)/|^\.gitea/workflows/ci\.yml$' && chore=true || true echo "$changed" | grep -qE '^(services/express|rpc/express|pkg)/|^\.gitea/workflows/ci\.yml$' && express=true || true + echo "$changed" | grep -qE '^(services/sale|rpc/sale|pkg)/|^\.gitea/workflows/ci\.yml$' && sale=true || true fi echo "bff=$bff" >> "$GITHUB_OUTPUT" @@ -84,8 +90,9 @@ jobs: echo "user=$user" >> "$GITHUB_OUTPUT" echo "ad=$ad" >> "$GITHUB_OUTPUT" echo "chore=$chore" >> "$GITHUB_OUTPUT" - echo "chore=express" >> "$GITHUB_OUTPUT" - echo "bff=$bff product=$product admin=$admin user=$user ad=$ad chore=$chore" + echo "express=$express" >> "$GITHUB_OUTPUT" + echo "sale=$sale" >> "$GITHUB_OUTPUT" + echo "bff=$bff product=$product admin=$admin user=$user ad=$ad chore=$chore express=$express sale=$sale" docker-bff: needs: changes @@ -268,3 +275,29 @@ jobs: - name: Docker push run: | docker push ${{ vars.REGISTRY }}/$NAME:latest + + docker-sale: + needs: changes + if: needs.changes.outputs.sale == 'true' + runs-on: runner + env: + NAME: lone/sale + steps: + - name: Checkout + uses: https://git.ailuowan.com/deploy/checkout@v4 + + - name: Login Registry + run: | + echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ vars.REGISTRY }} -u "${{ vars.REGISTRY_USERNAME }}" --password-stdin + + - name: Docker build + run: | + docker buildx use default + docker buildx build --builder default --load \ + -f services/sale/Dockerfile \ + -t ${{ vars.REGISTRY }}/$NAME:latest \ + . + + - name: Docker push + run: | + docker push ${{ vars.REGISTRY }}/$NAME:latest \ No newline at end of file diff --git a/README.md b/README.md index 5e8ba58..881089a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ D:\Git\bin\bash.exe rpc/scripts/gen-rpc.sh order rpc/scripts/gen-rpc.sh order ``` -加一个服务需要在bff/etc/bff.yaml 加 Upstreams ,docker.compose.prod.yaml 加服务,nacos 加配置 +加一个服务需要在bff/etc/bff.yaml 加 Upstreams ,docker.compose.prod.yaml 加服务,nacos 加配置,Dockerfile 文件 ## 如何加一个新服务 diff --git a/pkg/modelbase/base.go b/pkg/modelbase/base.go index 6b4935f..5ded0e8 100644 --- a/pkg/modelbase/base.go +++ b/pkg/modelbase/base.go @@ -128,6 +128,11 @@ func (m Base) session() *gorm.DB { return o } +// Session returns the DB session for this model (honors WithTX). +func (m Base) Session() *gorm.DB { + return m.session() +} + // Create inserts a row. func (m Base) Create(data interface{}) error { return m.session().Create(data).Error @@ -139,6 +144,13 @@ func (m Base) Edit(w Params, data interface{}) (int64, error) { update := make(map[string]interface{}) jsonBytes, _ := jsoniter.Marshal(data) _ = jsoniter.Unmarshal(jsonBytes, &update) + for k, v := range update { + if nested, ok := v.(map[string]interface{}); ok { + if b, err := jsoniter.Marshal(nested); err == nil { + update[k] = string(b) + } + } + } ret := o.Updates(update) return ret.RowsAffected, ignoreNotFound(ret.Error) } diff --git a/rpc/chore/chore.pb b/rpc/chore/chore.pb index 896cfa5..cd54c0a 100644 Binary files a/rpc/chore/chore.pb and b/rpc/chore/chore.pb differ diff --git a/rpc/chore/chore.proto b/rpc/chore/chore.proto index 66de98d..c4b3e41 100644 --- a/rpc/chore/chore.proto +++ b/rpc/chore/chore.proto @@ -17,6 +17,16 @@ service Chore { body: "*" }; } + rpc DecryptMobile(DecryptMobileReq) returns (Response) { + option (google.api.http) = { + get: "/api/v3/chore/decrypt/mobile" + }; + } + rpc Regions(RegionsReq) returns (Response) { + option (google.api.http) = { + get: "/api/v3/chore/regions" + }; + } } message Response { @@ -33,4 +43,12 @@ message TestReq { int32 id = 1; repeated int64 ids = 2; uint32 number = 3; +} + +message DecryptMobileReq { + string origin_mobile = 1; +} + +message RegionsReq { + int32 parent_id = 1; } \ No newline at end of file diff --git a/rpc/chore/pb/chore.pb.go b/rpc/chore/pb/chore.pb.go index b688f13..2b17b87 100644 --- a/rpc/chore/pb/chore.pb.go +++ b/rpc/chore/pb/chore.pb.go @@ -186,6 +186,94 @@ func (x *TestReq) GetNumber() uint32 { return 0 } +type DecryptMobileReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + OriginMobile string `protobuf:"bytes,1,opt,name=origin_mobile,json=originMobile,proto3" json:"origin_mobile,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DecryptMobileReq) Reset() { + *x = DecryptMobileReq{} + mi := &file_chore_chore_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DecryptMobileReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DecryptMobileReq) ProtoMessage() {} + +func (x *DecryptMobileReq) ProtoReflect() protoreflect.Message { + mi := &file_chore_chore_proto_msgTypes[3] + 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 DecryptMobileReq.ProtoReflect.Descriptor instead. +func (*DecryptMobileReq) Descriptor() ([]byte, []int) { + return file_chore_chore_proto_rawDescGZIP(), []int{3} +} + +func (x *DecryptMobileReq) GetOriginMobile() string { + if x != nil { + return x.OriginMobile + } + return "" +} + +type RegionsReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + ParentId int32 `protobuf:"varint,1,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RegionsReq) Reset() { + *x = RegionsReq{} + mi := &file_chore_chore_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RegionsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegionsReq) ProtoMessage() {} + +func (x *RegionsReq) ProtoReflect() protoreflect.Message { + mi := &file_chore_chore_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 RegionsReq.ProtoReflect.Descriptor instead. +func (*RegionsReq) Descriptor() ([]byte, []int) { + return file_chore_chore_proto_rawDescGZIP(), []int{4} +} + +func (x *RegionsReq) GetParentId() int32 { + if x != nil { + return x.ParentId + } + return 0 +} + var File_chore_chore_proto protoreflect.FileDescriptor const file_chore_chore_proto_rawDesc = "" + @@ -200,10 +288,17 @@ const file_chore_chore_proto_rawDesc = "" + "\aTestReq\x12\x0e\n" + "\x02id\x18\x01 \x01(\x05R\x02id\x12\x10\n" + "\x03ids\x18\x02 \x03(\x03R\x03ids\x12\x16\n" + - "\x06number\x18\x03 \x01(\rR\x06number2\xa1\x01\n" + + "\x06number\x18\x03 \x01(\rR\x06number\"7\n" + + "\x10DecryptMobileReq\x12#\n" + + "\rorigin_mobile\x18\x01 \x01(\tR\foriginMobile\")\n" + + "\n" + + "RegionsReq\x12\x1b\n" + + "\tparent_id\x18\x01 \x01(\x05R\bparentId2\xd0\x02\n" + "\x05Chore\x12P\n" + "\x06Policy\x12\x10.chore.PolicyReq\x1a\x0f.chore.Response\"#\x82\xd3\xe4\x93\x02\x1d:\x01*\x12\x18/api/v3/chore/oss/policy\x12F\n" + - "\x04Test\x12\x0e.chore.TestReq\x1a\x0f.chore.Response\"\x1d\x82\xd3\xe4\x93\x02\x17:\x01*\"\x12/api/v3/chore/testB\x19Z\x17lone-services/rpc/choreb\x06proto3" + "\x04Test\x12\x0e.chore.TestReq\x1a\x0f.chore.Response\"\x1d\x82\xd3\xe4\x93\x02\x17:\x01*\"\x12/api/v3/chore/test\x12_\n" + + "\rDecryptMobile\x12\x17.chore.DecryptMobileReq\x1a\x0f.chore.Response\"$\x82\xd3\xe4\x93\x02\x1e\x12\x1c/api/v3/chore/decrypt/mobile\x12L\n" + + "\aRegions\x12\x11.chore.RegionsReq\x1a\x0f.chore.Response\"\x1d\x82\xd3\xe4\x93\x02\x17\x12\x15/api/v3/chore/regionsB\x19Z\x17lone-services/rpc/choreb\x06proto3" var ( file_chore_chore_proto_rawDescOnce sync.Once @@ -217,19 +312,25 @@ func file_chore_chore_proto_rawDescGZIP() []byte { return file_chore_chore_proto_rawDescData } -var file_chore_chore_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_chore_chore_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_chore_chore_proto_goTypes = []any{ - (*Response)(nil), // 0: chore.Response - (*PolicyReq)(nil), // 1: chore.PolicyReq - (*TestReq)(nil), // 2: chore.TestReq + (*Response)(nil), // 0: chore.Response + (*PolicyReq)(nil), // 1: chore.PolicyReq + (*TestReq)(nil), // 2: chore.TestReq + (*DecryptMobileReq)(nil), // 3: chore.DecryptMobileReq + (*RegionsReq)(nil), // 4: chore.RegionsReq } var file_chore_chore_proto_depIdxs = []int32{ 1, // 0: chore.Chore.Policy:input_type -> chore.PolicyReq 2, // 1: chore.Chore.Test:input_type -> chore.TestReq - 0, // 2: chore.Chore.Policy:output_type -> chore.Response - 0, // 3: chore.Chore.Test:output_type -> chore.Response - 2, // [2:4] is the sub-list for method output_type - 0, // [0:2] is the sub-list for method input_type + 3, // 2: chore.Chore.DecryptMobile:input_type -> chore.DecryptMobileReq + 4, // 3: chore.Chore.Regions:input_type -> chore.RegionsReq + 0, // 4: chore.Chore.Policy:output_type -> chore.Response + 0, // 5: chore.Chore.Test:output_type -> chore.Response + 0, // 6: chore.Chore.DecryptMobile:output_type -> chore.Response + 0, // 7: chore.Chore.Regions:output_type -> chore.Response + 4, // [4:8] is the sub-list for method output_type + 0, // [0:4] 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 @@ -246,7 +347,7 @@ func file_chore_chore_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_chore_chore_proto_rawDesc), len(file_chore_chore_proto_rawDesc)), NumEnums: 0, - NumMessages: 3, + NumMessages: 5, NumExtensions: 0, NumServices: 1, }, diff --git a/rpc/chore/pb/chore_grpc.pb.go b/rpc/chore/pb/chore_grpc.pb.go index 6b84e16..0cae512 100644 --- a/rpc/chore/pb/chore_grpc.pb.go +++ b/rpc/chore/pb/chore_grpc.pb.go @@ -19,8 +19,10 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - Chore_Policy_FullMethodName = "/chore.Chore/Policy" - Chore_Test_FullMethodName = "/chore.Chore/Test" + Chore_Policy_FullMethodName = "/chore.Chore/Policy" + Chore_Test_FullMethodName = "/chore.Chore/Test" + Chore_DecryptMobile_FullMethodName = "/chore.Chore/DecryptMobile" + Chore_Regions_FullMethodName = "/chore.Chore/Regions" ) // ChoreClient is the client API for Chore service. @@ -29,6 +31,8 @@ const ( type ChoreClient interface { Policy(ctx context.Context, in *PolicyReq, opts ...grpc.CallOption) (*Response, error) Test(ctx context.Context, in *TestReq, opts ...grpc.CallOption) (*Response, error) + DecryptMobile(ctx context.Context, in *DecryptMobileReq, opts ...grpc.CallOption) (*Response, error) + Regions(ctx context.Context, in *RegionsReq, opts ...grpc.CallOption) (*Response, error) } type choreClient struct { @@ -59,12 +63,34 @@ func (c *choreClient) Test(ctx context.Context, in *TestReq, opts ...grpc.CallOp return out, nil } +func (c *choreClient) DecryptMobile(ctx context.Context, in *DecryptMobileReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Chore_DecryptMobile_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *choreClient) Regions(ctx context.Context, in *RegionsReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Chore_Regions_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // ChoreServer is the server API for Chore service. // All implementations must embed UnimplementedChoreServer // for forward compatibility. type ChoreServer interface { Policy(context.Context, *PolicyReq) (*Response, error) Test(context.Context, *TestReq) (*Response, error) + DecryptMobile(context.Context, *DecryptMobileReq) (*Response, error) + Regions(context.Context, *RegionsReq) (*Response, error) mustEmbedUnimplementedChoreServer() } @@ -81,6 +107,12 @@ func (UnimplementedChoreServer) Policy(context.Context, *PolicyReq) (*Response, func (UnimplementedChoreServer) Test(context.Context, *TestReq) (*Response, error) { return nil, status.Error(codes.Unimplemented, "method Test not implemented") } +func (UnimplementedChoreServer) DecryptMobile(context.Context, *DecryptMobileReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method DecryptMobile not implemented") +} +func (UnimplementedChoreServer) Regions(context.Context, *RegionsReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Regions not implemented") +} func (UnimplementedChoreServer) mustEmbedUnimplementedChoreServer() {} func (UnimplementedChoreServer) testEmbeddedByValue() {} @@ -138,6 +170,42 @@ func _Chore_Test_Handler(srv interface{}, ctx context.Context, dec func(interfac return interceptor(ctx, in, info, handler) } +func _Chore_DecryptMobile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DecryptMobileReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChoreServer).DecryptMobile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chore_DecryptMobile_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChoreServer).DecryptMobile(ctx, req.(*DecryptMobileReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Chore_Regions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegionsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ChoreServer).Regions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Chore_Regions_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ChoreServer).Regions(ctx, req.(*RegionsReq)) + } + return interceptor(ctx, in, info, handler) +} + // Chore_ServiceDesc is the grpc.ServiceDesc for Chore service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -153,6 +221,14 @@ var Chore_ServiceDesc = grpc.ServiceDesc{ MethodName: "Test", Handler: _Chore_Test_Handler, }, + { + MethodName: "DecryptMobile", + Handler: _Chore_DecryptMobile_Handler, + }, + { + MethodName: "Regions", + Handler: _Chore_Regions_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "chore/chore.proto", diff --git a/rpc/product/pb/product.pb.go b/rpc/product/pb/product.pb.go index 075acd7..58e288f 100644 --- a/rpc/product/pb/product.pb.go +++ b/rpc/product/pb/product.pb.go @@ -1263,6 +1263,111 @@ func (x *NumberReq) GetNumber() uint32 { return 0 } +type NumberItem struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Number uint32 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NumberItem) Reset() { + *x = NumberItem{} + mi := &file_product_product_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NumberItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NumberItem) ProtoMessage() {} + +func (x *NumberItem) ProtoReflect() protoreflect.Message { + mi := &file_product_product_proto_msgTypes[17] + 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 NumberItem.ProtoReflect.Descriptor instead. +func (*NumberItem) Descriptor() ([]byte, []int) { + return file_product_product_proto_rawDescGZIP(), []int{17} +} + +func (x *NumberItem) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *NumberItem) GetNumber() uint32 { + if x != nil { + return x.Number + } + return 0 +} + +// type: 1 增加, 2 减少 +type NumberItemsReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type uint32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` + Items []*NumberItem `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NumberItemsReq) Reset() { + *x = NumberItemsReq{} + mi := &file_product_product_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NumberItemsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NumberItemsReq) ProtoMessage() {} + +func (x *NumberItemsReq) ProtoReflect() protoreflect.Message { + mi := &file_product_product_proto_msgTypes[18] + 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 NumberItemsReq.ProtoReflect.Descriptor instead. +func (*NumberItemsReq) Descriptor() ([]byte, []int) { + return file_product_product_proto_rawDescGZIP(), []int{18} +} + +func (x *NumberItemsReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *NumberItemsReq) GetItems() []*NumberItem { + if x != nil { + return x.Items + } + return nil +} + type NumberAddReq struct { state protoimpl.MessageState `protogen:"open.v1"` Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` @@ -1273,7 +1378,7 @@ type NumberAddReq struct { func (x *NumberAddReq) Reset() { *x = NumberAddReq{} - mi := &file_product_product_proto_msgTypes[17] + mi := &file_product_product_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1285,7 +1390,7 @@ func (x *NumberAddReq) String() string { func (*NumberAddReq) ProtoMessage() {} func (x *NumberAddReq) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[17] + mi := &file_product_product_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1298,7 +1403,7 @@ func (x *NumberAddReq) ProtoReflect() protoreflect.Message { // Deprecated: Use NumberAddReq.ProtoReflect.Descriptor instead. func (*NumberAddReq) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{17} + return file_product_product_proto_rawDescGZIP(), []int{19} } func (x *NumberAddReq) GetId() int64 { @@ -1325,7 +1430,7 @@ type ItemsData struct { func (x *ItemsData) Reset() { *x = ItemsData{} - mi := &file_product_product_proto_msgTypes[18] + mi := &file_product_product_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1337,7 +1442,7 @@ func (x *ItemsData) String() string { func (*ItemsData) ProtoMessage() {} func (x *ItemsData) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[18] + mi := &file_product_product_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1350,7 +1455,7 @@ func (x *ItemsData) ProtoReflect() protoreflect.Message { // Deprecated: Use ItemsData.ProtoReflect.Descriptor instead. func (*ItemsData) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{18} + return file_product_product_proto_rawDescGZIP(), []int{20} } func (x *ItemsData) GetCount() int64 { @@ -1377,7 +1482,7 @@ type VerifyItemsData struct { func (x *VerifyItemsData) Reset() { *x = VerifyItemsData{} - mi := &file_product_product_proto_msgTypes[19] + mi := &file_product_product_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1389,7 +1494,7 @@ func (x *VerifyItemsData) String() string { func (*VerifyItemsData) ProtoMessage() {} func (x *VerifyItemsData) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[19] + mi := &file_product_product_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1402,7 +1507,7 @@ func (x *VerifyItemsData) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyItemsData.ProtoReflect.Descriptor instead. func (*VerifyItemsData) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{19} + return file_product_product_proto_rawDescGZIP(), []int{21} } func (x *VerifyItemsData) GetCount() int64 { @@ -1439,7 +1544,7 @@ type VerifyParams struct { func (x *VerifyParams) Reset() { *x = VerifyParams{} - mi := &file_product_product_proto_msgTypes[20] + mi := &file_product_product_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1451,7 +1556,7 @@ func (x *VerifyParams) String() string { func (*VerifyParams) ProtoMessage() {} func (x *VerifyParams) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[20] + mi := &file_product_product_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1464,7 +1569,7 @@ func (x *VerifyParams) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyParams.ProtoReflect.Descriptor instead. func (*VerifyParams) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{20} + return file_product_product_proto_rawDescGZIP(), []int{22} } func (x *VerifyParams) GetId() int64 { @@ -1563,7 +1668,7 @@ type VerifyItem struct { func (x *VerifyItem) Reset() { *x = VerifyItem{} - mi := &file_product_product_proto_msgTypes[21] + mi := &file_product_product_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1575,7 +1680,7 @@ func (x *VerifyItem) String() string { func (*VerifyItem) ProtoMessage() {} func (x *VerifyItem) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[21] + mi := &file_product_product_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1588,7 +1693,7 @@ func (x *VerifyItem) ProtoReflect() protoreflect.Message { // Deprecated: Use VerifyItem.ProtoReflect.Descriptor instead. func (*VerifyItem) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{21} + return file_product_product_proto_rawDescGZIP(), []int{23} } func (x *VerifyItem) GetName() string { @@ -1629,7 +1734,7 @@ type NameItem struct { func (x *NameItem) Reset() { *x = NameItem{} - mi := &file_product_product_proto_msgTypes[22] + mi := &file_product_product_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1641,7 +1746,7 @@ func (x *NameItem) String() string { func (*NameItem) ProtoMessage() {} func (x *NameItem) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[22] + mi := &file_product_product_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1654,7 +1759,7 @@ func (x *NameItem) ProtoReflect() protoreflect.Message { // Deprecated: Use NameItem.ProtoReflect.Descriptor instead. func (*NameItem) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{22} + return file_product_product_proto_rawDescGZIP(), []int{24} } func (x *NameItem) GetId() int64 { @@ -1715,7 +1820,7 @@ type Item struct { func (x *Item) Reset() { *x = Item{} - mi := &file_product_product_proto_msgTypes[23] + mi := &file_product_product_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1727,7 +1832,7 @@ func (x *Item) String() string { func (*Item) ProtoMessage() {} func (x *Item) ProtoReflect() protoreflect.Message { - mi := &file_product_product_proto_msgTypes[23] + mi := &file_product_product_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1740,7 +1845,7 @@ func (x *Item) ProtoReflect() protoreflect.Message { // Deprecated: Use Item.ProtoReflect.Descriptor instead. func (*Item) Descriptor() ([]byte, []int) { - return file_product_product_proto_rawDescGZIP(), []int{23} + return file_product_product_proto_rawDescGZIP(), []int{25} } func (x *Item) GetId() int64 { @@ -2116,7 +2221,14 @@ const file_product_product_proto_rawDesc = "" + "\tNumberReq\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x12\n" + "\x04type\x18\x02 \x01(\rR\x04type\x12\x16\n" + - "\x06number\x18\x03 \x01(\rR\x06number\"6\n" + + "\x06number\x18\x03 \x01(\rR\x06number\"4\n" + + "\n" + + "NumberItem\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + + "\x06number\x18\x02 \x01(\rR\x06number\"O\n" + + "\x0eNumberItemsReq\x12\x12\n" + + "\x04type\x18\x01 \x01(\rR\x04type\x12)\n" + + "\x05items\x18\x02 \x03(\v2\x13.product.NumberItemR\x05items\"6\n" + "\fNumberAddReq\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + "\x06number\x18\x02 \x01(\rR\x06number\"F\n" + @@ -2205,7 +2317,7 @@ const file_product_product_proto_rawDesc = "" + "\x06reason\x18\" \x01(\tR\x06reason\x12\x1d\n" + "\n" + "admin_name\x18# \x01(\tR\tadminName\x12\x12\n" + - "\x04edit\x18$ \x01(\rR\x04edit2\xa8\v\n" + + "\x04edit\x18$ \x01(\rR\x04edit2\xe8\v\n" + "\aProduct\x12M\n" + "\x06Create\x12\x12.product.CreateReq\x1a\x11.product.Response\"\x1c\x82\xd3\xe4\x93\x02\x16:\x01*\"\x11/admin/v3/product\x12N\n" + "\x04Info\x12\x10.product.InfoReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x12\x16/admin/v3/product/info\x12K\n" + @@ -2220,7 +2332,8 @@ const file_product_product_proto_rawDesc = "" + "\bEditBase\x12\x14.product.EditBaseReq\x1a\x11.product.Response\"!\x82\xd3\xe4\x93\x02\x1b:\x01*\x1a\x16/admin/v3/product/base\x12k\n" + "\x0fEditSusceptible\x12\x1b.product.EditSusceptibleReq\x1a\x11.product.Response\"(\x82\xd3\xe4\x93\x02\":\x01*\x1a\x1d/admin/v3/product/susceptible\x12k\n" + "\rEditApplyPass\x12\x19.product.EditApplyPassReq\x1a\x11.product.Response\",\x82\xd3\xe4\x93\x02&:\x01*\x1a!/admin/v3/product/edit/apply/pass\x124\n" + - "\x06Number\x12\x12.product.NumberReq\x1a\x16.google.protobuf.Empty\x12/\n" + + "\x06Number\x12\x12.product.NumberReq\x1a\x16.google.protobuf.Empty\x12>\n" + + "\vNumberItems\x12\x17.product.NumberItemsReq\x1a\x16.google.protobuf.Empty\x12/\n" + "\bInfoById\x12\x14.product.InfoByIdReq\x1a\r.product.Item\x12=\n" + "\n" + "ItemsByIds\x12\x16.product.ItemsByIdsReq\x1a\x17.product.ItemsByIdsData\x12Z\n" + @@ -2238,7 +2351,7 @@ func file_product_product_proto_rawDescGZIP() []byte { return file_product_product_proto_rawDescData } -var file_product_product_proto_msgTypes = make([]protoimpl.MessageInfo, 24) +var file_product_product_proto_msgTypes = make([]protoimpl.MessageInfo, 26) var file_product_product_proto_goTypes = []any{ (*Response)(nil), // 0: product.Response (*InfoByIdReq)(nil), // 1: product.InfoByIdReq @@ -2257,60 +2370,65 @@ var file_product_product_proto_goTypes = []any{ (*EditBaseReq)(nil), // 14: product.EditBaseReq (*EditSusceptibleReq)(nil), // 15: product.EditSusceptibleReq (*NumberReq)(nil), // 16: product.NumberReq - (*NumberAddReq)(nil), // 17: product.NumberAddReq - (*ItemsData)(nil), // 18: product.ItemsData - (*VerifyItemsData)(nil), // 19: product.VerifyItemsData - (*VerifyParams)(nil), // 20: product.VerifyParams - (*VerifyItem)(nil), // 21: product.VerifyItem - (*NameItem)(nil), // 22: product.NameItem - (*Item)(nil), // 23: product.Item - (*emptypb.Empty)(nil), // 24: google.protobuf.Empty + (*NumberItem)(nil), // 17: product.NumberItem + (*NumberItemsReq)(nil), // 18: product.NumberItemsReq + (*NumberAddReq)(nil), // 19: product.NumberAddReq + (*ItemsData)(nil), // 20: product.ItemsData + (*VerifyItemsData)(nil), // 21: product.VerifyItemsData + (*VerifyParams)(nil), // 22: product.VerifyParams + (*VerifyItem)(nil), // 23: product.VerifyItem + (*NameItem)(nil), // 24: product.NameItem + (*Item)(nil), // 25: product.Item + (*emptypb.Empty)(nil), // 26: google.protobuf.Empty } var file_product_product_proto_depIdxs = []int32{ - 23, // 0: product.ItemsByIdsData.items:type_name -> product.Item - 23, // 1: product.ItemsData.items:type_name -> product.Item - 21, // 2: product.VerifyItemsData.items:type_name -> product.VerifyItem - 20, // 3: product.VerifyItem.new:type_name -> product.VerifyParams - 20, // 4: product.VerifyItem.old:type_name -> product.VerifyParams - 4, // 5: product.Product.Create:input_type -> product.CreateReq - 5, // 6: product.Product.Info:input_type -> product.InfoReq - 6, // 7: product.Product.Items:input_type -> product.ItemsReq - 7, // 8: product.Product.Names:input_type -> product.NamesReq - 8, // 9: product.Product.Status:input_type -> product.StatusReq - 9, // 10: product.Product.Sort:input_type -> product.SortReq - 10, // 11: product.Product.Verify:input_type -> product.VerifyReq - 11, // 12: product.Product.VerifyFirst:input_type -> product.VerifyStatusReq - 11, // 13: product.Product.VerifySecond:input_type -> product.VerifyStatusReq - 12, // 14: product.Product.EditApply:input_type -> product.EditApplyReq - 14, // 15: product.Product.EditBase:input_type -> product.EditBaseReq - 15, // 16: product.Product.EditSusceptible:input_type -> product.EditSusceptibleReq - 13, // 17: product.Product.EditApplyPass:input_type -> product.EditApplyPassReq - 16, // 18: product.Product.Number:input_type -> product.NumberReq - 1, // 19: product.Product.InfoById:input_type -> product.InfoByIdReq - 2, // 20: product.Product.ItemsByIds:input_type -> product.ItemsByIdsReq - 17, // 21: product.Product.NumberAdd:input_type -> product.NumberAddReq - 0, // 22: product.Product.Create:output_type -> product.Response - 0, // 23: product.Product.Info:output_type -> product.Response - 0, // 24: product.Product.Items:output_type -> product.Response - 0, // 25: product.Product.Names:output_type -> product.Response - 0, // 26: product.Product.Status:output_type -> product.Response - 0, // 27: product.Product.Sort:output_type -> product.Response - 0, // 28: product.Product.Verify:output_type -> product.Response - 0, // 29: product.Product.VerifyFirst:output_type -> product.Response - 0, // 30: product.Product.VerifySecond:output_type -> product.Response - 0, // 31: product.Product.EditApply:output_type -> product.Response - 0, // 32: product.Product.EditBase:output_type -> product.Response - 0, // 33: product.Product.EditSusceptible:output_type -> product.Response - 0, // 34: product.Product.EditApplyPass:output_type -> product.Response - 24, // 35: product.Product.Number:output_type -> google.protobuf.Empty - 23, // 36: product.Product.InfoById:output_type -> product.Item - 3, // 37: product.Product.ItemsByIds:output_type -> product.ItemsByIdsData - 0, // 38: product.Product.NumberAdd:output_type -> product.Response - 22, // [22:39] is the sub-list for method output_type - 5, // [5:22] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 25, // 0: product.ItemsByIdsData.items:type_name -> product.Item + 17, // 1: product.NumberItemsReq.items:type_name -> product.NumberItem + 25, // 2: product.ItemsData.items:type_name -> product.Item + 23, // 3: product.VerifyItemsData.items:type_name -> product.VerifyItem + 22, // 4: product.VerifyItem.new:type_name -> product.VerifyParams + 22, // 5: product.VerifyItem.old:type_name -> product.VerifyParams + 4, // 6: product.Product.Create:input_type -> product.CreateReq + 5, // 7: product.Product.Info:input_type -> product.InfoReq + 6, // 8: product.Product.Items:input_type -> product.ItemsReq + 7, // 9: product.Product.Names:input_type -> product.NamesReq + 8, // 10: product.Product.Status:input_type -> product.StatusReq + 9, // 11: product.Product.Sort:input_type -> product.SortReq + 10, // 12: product.Product.Verify:input_type -> product.VerifyReq + 11, // 13: product.Product.VerifyFirst:input_type -> product.VerifyStatusReq + 11, // 14: product.Product.VerifySecond:input_type -> product.VerifyStatusReq + 12, // 15: product.Product.EditApply:input_type -> product.EditApplyReq + 14, // 16: product.Product.EditBase:input_type -> product.EditBaseReq + 15, // 17: product.Product.EditSusceptible:input_type -> product.EditSusceptibleReq + 13, // 18: product.Product.EditApplyPass:input_type -> product.EditApplyPassReq + 16, // 19: product.Product.Number:input_type -> product.NumberReq + 18, // 20: product.Product.NumberItems:input_type -> product.NumberItemsReq + 1, // 21: product.Product.InfoById:input_type -> product.InfoByIdReq + 2, // 22: product.Product.ItemsByIds:input_type -> product.ItemsByIdsReq + 19, // 23: product.Product.NumberAdd:input_type -> product.NumberAddReq + 0, // 24: product.Product.Create:output_type -> product.Response + 0, // 25: product.Product.Info:output_type -> product.Response + 0, // 26: product.Product.Items:output_type -> product.Response + 0, // 27: product.Product.Names:output_type -> product.Response + 0, // 28: product.Product.Status:output_type -> product.Response + 0, // 29: product.Product.Sort:output_type -> product.Response + 0, // 30: product.Product.Verify:output_type -> product.Response + 0, // 31: product.Product.VerifyFirst:output_type -> product.Response + 0, // 32: product.Product.VerifySecond:output_type -> product.Response + 0, // 33: product.Product.EditApply:output_type -> product.Response + 0, // 34: product.Product.EditBase:output_type -> product.Response + 0, // 35: product.Product.EditSusceptible:output_type -> product.Response + 0, // 36: product.Product.EditApplyPass:output_type -> product.Response + 26, // 37: product.Product.Number:output_type -> google.protobuf.Empty + 26, // 38: product.Product.NumberItems:output_type -> google.protobuf.Empty + 25, // 39: product.Product.InfoById:output_type -> product.Item + 3, // 40: product.Product.ItemsByIds:output_type -> product.ItemsByIdsData + 0, // 41: product.Product.NumberAdd:output_type -> product.Response + 24, // [24:42] is the sub-list for method output_type + 6, // [6:24] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_product_product_proto_init() } @@ -2324,7 +2442,7 @@ func file_product_product_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_product_product_proto_rawDesc), len(file_product_product_proto_rawDesc)), NumEnums: 0, - NumMessages: 24, + NumMessages: 26, NumExtensions: 0, NumServices: 1, }, diff --git a/rpc/product/pb/product_grpc.pb.go b/rpc/product/pb/product_grpc.pb.go index 9aec8d9..315aba0 100644 --- a/rpc/product/pb/product_grpc.pb.go +++ b/rpc/product/pb/product_grpc.pb.go @@ -8,6 +8,7 @@ package product import ( context "context" + grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -34,6 +35,7 @@ const ( Product_EditSusceptible_FullMethodName = "/product.Product/EditSusceptible" Product_EditApplyPass_FullMethodName = "/product.Product/EditApplyPass" Product_Number_FullMethodName = "/product.Product/Number" + Product_NumberItems_FullMethodName = "/product.Product/NumberItems" Product_InfoById_FullMethodName = "/product.Product/InfoById" Product_ItemsByIds_FullMethodName = "/product.Product/ItemsByIds" Product_NumberAdd_FullMethodName = "/product.Product/NumberAdd" @@ -66,6 +68,8 @@ type ProductClient interface { // 增减库存 // type: 1 增加, 2 减少 Number(ctx context.Context, in *NumberReq, opts ...grpc.CallOption) (*emptypb.Empty, error) + // 批量增减库存 + NumberItems(ctx context.Context, in *NumberItemsReq, opts ...grpc.CallOption) (*emptypb.Empty, error) InfoById(ctx context.Context, in *InfoByIdReq, opts ...grpc.CallOption) (*Item, error) ItemsByIds(ctx context.Context, in *ItemsByIdsReq, opts ...grpc.CallOption) (*ItemsByIdsData, error) // 增加库存 @@ -220,6 +224,16 @@ func (c *productClient) Number(ctx context.Context, in *NumberReq, opts ...grpc. return out, nil } +func (c *productClient) NumberItems(ctx context.Context, in *NumberItemsReq, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, Product_NumberItems_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *productClient) InfoById(ctx context.Context, in *InfoByIdReq, opts ...grpc.CallOption) (*Item, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Item) @@ -277,6 +291,8 @@ type ProductServer interface { // 增减库存 // type: 1 增加, 2 减少 Number(context.Context, *NumberReq) (*emptypb.Empty, error) + // 批量增减库存(服务内按 id 排序后在同一事务中执行,防死锁) + NumberItems(context.Context, *NumberItemsReq) (*emptypb.Empty, error) InfoById(context.Context, *InfoByIdReq) (*Item, error) ItemsByIds(context.Context, *ItemsByIdsReq) (*ItemsByIdsData, error) // 增加库存 @@ -333,6 +349,9 @@ func (UnimplementedProductServer) EditApplyPass(context.Context, *EditApplyPassR func (UnimplementedProductServer) Number(context.Context, *NumberReq) (*emptypb.Empty, error) { return nil, status.Error(codes.Unimplemented, "method Number not implemented") } +func (UnimplementedProductServer) NumberItems(context.Context, *NumberItemsReq) (*emptypb.Empty, error) { + return nil, status.Error(codes.Unimplemented, "method NumberItems not implemented") +} func (UnimplementedProductServer) InfoById(context.Context, *InfoByIdReq) (*Item, error) { return nil, status.Error(codes.Unimplemented, "method InfoById not implemented") } @@ -615,6 +634,24 @@ func _Product_Number_Handler(srv interface{}, ctx context.Context, dec func(inte return interceptor(ctx, in, info, handler) } +func _Product_NumberItems_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NumberItemsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProductServer).NumberItems(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Product_NumberItems_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProductServer).NumberItems(ctx, req.(*NumberItemsReq)) + } + return interceptor(ctx, in, info, handler) +} + func _Product_InfoById_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(InfoByIdReq) if err := dec(in); err != nil { @@ -732,6 +769,10 @@ var Product_ServiceDesc = grpc.ServiceDesc{ MethodName: "Number", Handler: _Product_Number_Handler, }, + { + MethodName: "NumberItems", + Handler: _Product_NumberItems_Handler, + }, { MethodName: "InfoById", Handler: _Product_InfoById_Handler, diff --git a/rpc/product/product.pb b/rpc/product/product.pb index 38d091a..8d10079 100644 Binary files a/rpc/product/product.pb and b/rpc/product/product.pb differ diff --git a/rpc/product/product.proto b/rpc/product/product.proto index ff186c8..0bc766f 100644 --- a/rpc/product/product.proto +++ b/rpc/product/product.proto @@ -97,6 +97,8 @@ service Product { // 增减库存 // type: 1 增加, 2 减少 rpc Number(NumberReq) returns (google.protobuf.Empty); + // 批量增减库存(服务内按 id 排序后在同一事务中执行,防死锁) + rpc NumberItems(NumberItemsReq) returns (google.protobuf.Empty); rpc InfoById(InfoByIdReq) returns (Item); rpc ItemsByIds(ItemsByIdsReq) returns (ItemsByIdsData); @@ -242,6 +244,17 @@ message NumberReq { uint32 number = 3; } +message NumberItem { + int64 id = 1; + uint32 number = 2; +} + +// type: 1 增加, 2 减少 +message NumberItemsReq { + uint32 type = 1; + repeated NumberItem items = 2; +} + message NumberAddReq { int64 id = 1; uint32 number = 2; diff --git a/rpc/sale/pb/sale.pb.go b/rpc/sale/pb/sale.pb.go new file mode 100644 index 0000000..874cd8a --- /dev/null +++ b/rpc/sale/pb/sale.pb.go @@ -0,0 +1,1175 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.11 +// protoc v3.19.4 +// source: sale/sale.proto + +package sale + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Response struct { + state protoimpl.MessageState `protogen:"open.v1"` + Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` + Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Response) Reset() { + *x = Response{} + mi := &file_sale_sale_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_proto_msgTypes[0] + 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 Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{0} +} + +func (x *Response) GetCode() int32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *Response) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +func (x *Response) GetData() string { + if x != nil { + return x.Data + } + return "" +} + +type GroupEmptyReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupEmptyReq) Reset() { + *x = GroupEmptyReq{} + mi := &file_sale_sale_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupEmptyReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupEmptyReq) ProtoMessage() {} + +func (x *GroupEmptyReq) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_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 GroupEmptyReq.ProtoReflect.Descriptor instead. +func (*GroupEmptyReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{1} +} + +type GroupItemsReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Page uint32 `protobuf:"varint,1,opt,name=page,proto3" json:"page,omitempty"` + PageSize uint32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupItemsReq) Reset() { + *x = GroupItemsReq{} + mi := &file_sale_sale_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupItemsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupItemsReq) ProtoMessage() {} + +func (x *GroupItemsReq) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_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 GroupItemsReq.ProtoReflect.Descriptor instead. +func (*GroupItemsReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{2} +} + +func (x *GroupItemsReq) GetPage() uint32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *GroupItemsReq) GetPageSize() uint32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *GroupItemsReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type GroupCreateReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GroupCreateReq) Reset() { + *x = GroupCreateReq{} + mi := &file_sale_sale_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GroupCreateReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GroupCreateReq) ProtoMessage() {} + +func (x *GroupCreateReq) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_proto_msgTypes[3] + 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 GroupCreateReq.ProtoReflect.Descriptor instead. +func (*GroupCreateReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{3} +} + +func (x *GroupCreateReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type NamesReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Type uint32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Level uint32 `protobuf:"varint,3,opt,name=level,proto3" json:"level,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NamesReq) Reset() { + *x = NamesReq{} + mi := &file_sale_sale_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NamesReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NamesReq) ProtoMessage() {} + +func (x *NamesReq) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_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 NamesReq.ProtoReflect.Descriptor instead. +func (*NamesReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{4} +} + +func (x *NamesReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *NamesReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *NamesReq) GetLevel() uint32 { + if x != nil { + return x.Level + } + return 0 +} + +type NameItem 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"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NameItem) Reset() { + *x = NameItem{} + mi := &file_sale_sale_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NameItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NameItem) ProtoMessage() {} + +func (x *NameItem) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_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 NameItem.ProtoReflect.Descriptor instead. +func (*NameItem) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{5} +} + +func (x *NameItem) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *NameItem) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +func (x *NameItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type NamesData struct { + state protoimpl.MessageState `protogen:"open.v1"` + Items []*NameItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *NamesData) Reset() { + *x = NamesData{} + mi := &file_sale_sale_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *NamesData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NamesData) ProtoMessage() {} + +func (x *NamesData) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_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 NamesData.ProtoReflect.Descriptor instead. +func (*NamesData) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{6} +} + +func (x *NamesData) GetItems() []*NameItem { + if x != nil { + return x.Items + } + return nil +} + +type CreateReq 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"` + IdCardFront string `protobuf:"bytes,3,opt,name=id_card_front,json=idCardFront,proto3" json:"id_card_front,omitempty"` + Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"` + Account string `protobuf:"bytes,5,opt,name=account,proto3" json:"account,omitempty"` + Sex uint32 `protobuf:"varint,6,opt,name=sex,proto3" json:"sex,omitempty"` + GroupId int64 `protobuf:"varint,7,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` + BirthDate string `protobuf:"bytes,8,opt,name=birth_date,json=birthDate,proto3" json:"birth_date,omitempty"` + SaleId int64 `protobuf:"varint,9,opt,name=sale_id,json=saleId,proto3" json:"sale_id,omitempty"` + Type uint32 `protobuf:"varint,10,opt,name=type,proto3" json:"type,omitempty"` + TerritoryId int64 `protobuf:"varint,11,opt,name=territory_id,json=territoryId,proto3" json:"territory_id,omitempty"` + TerritoryName string `protobuf:"bytes,12,opt,name=territory_name,json=territoryName,proto3" json:"territory_name,omitempty"` + ProvinceId int64 `protobuf:"varint,13,opt,name=province_id,json=provinceId,proto3" json:"province_id,omitempty"` + CityId int64 `protobuf:"varint,14,opt,name=city_id,json=cityId,proto3" json:"city_id,omitempty"` + DistrictId int64 `protobuf:"varint,15,opt,name=district_id,json=districtId,proto3" json:"district_id,omitempty"` + RegionProvince string `protobuf:"bytes,16,opt,name=region_province,json=regionProvince,proto3" json:"region_province,omitempty"` + RegionCity string `protobuf:"bytes,17,opt,name=region_city,json=regionCity,proto3" json:"region_city,omitempty"` + RegionDistrict string `protobuf:"bytes,18,opt,name=region_district,json=regionDistrict,proto3" json:"region_district,omitempty"` + Address string `protobuf:"bytes,19,opt,name=address,proto3" json:"address,omitempty"` + IdCardBack string `protobuf:"bytes,20,opt,name=id_card_back,json=idCardBack,proto3" json:"id_card_back,omitempty"` + BusinessLicense string `protobuf:"bytes,21,opt,name=business_license,json=businessLicense,proto3" json:"business_license,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateReq) Reset() { + *x = CreateReq{} + mi := &file_sale_sale_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateReq) ProtoMessage() {} + +func (x *CreateReq) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_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 CreateReq.ProtoReflect.Descriptor instead. +func (*CreateReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{7} +} + +func (x *CreateReq) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +func (x *CreateReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CreateReq) GetIdCardFront() string { + if x != nil { + return x.IdCardFront + } + return "" +} + +func (x *CreateReq) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *CreateReq) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *CreateReq) GetSex() uint32 { + if x != nil { + return x.Sex + } + return 0 +} + +func (x *CreateReq) GetGroupId() int64 { + if x != nil { + return x.GroupId + } + return 0 +} + +func (x *CreateReq) GetBirthDate() string { + if x != nil { + return x.BirthDate + } + return "" +} + +func (x *CreateReq) GetSaleId() int64 { + if x != nil { + return x.SaleId + } + return 0 +} + +func (x *CreateReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *CreateReq) GetTerritoryId() int64 { + if x != nil { + return x.TerritoryId + } + return 0 +} + +func (x *CreateReq) GetTerritoryName() string { + if x != nil { + return x.TerritoryName + } + return "" +} + +func (x *CreateReq) GetProvinceId() int64 { + if x != nil { + return x.ProvinceId + } + return 0 +} + +func (x *CreateReq) GetCityId() int64 { + if x != nil { + return x.CityId + } + return 0 +} + +func (x *CreateReq) GetDistrictId() int64 { + if x != nil { + return x.DistrictId + } + return 0 +} + +func (x *CreateReq) GetRegionProvince() string { + if x != nil { + return x.RegionProvince + } + return "" +} + +func (x *CreateReq) GetRegionCity() string { + if x != nil { + return x.RegionCity + } + return "" +} + +func (x *CreateReq) GetRegionDistrict() string { + if x != nil { + return x.RegionDistrict + } + return "" +} + +func (x *CreateReq) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *CreateReq) GetIdCardBack() string { + if x != nil { + return x.IdCardBack + } + return "" +} + +func (x *CreateReq) GetBusinessLicense() string { + if x != nil { + return x.BusinessLicense + } + return "" +} + +type EditReq 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"` + IdCardFront string `protobuf:"bytes,4,opt,name=id_card_front,json=idCardFront,proto3" json:"id_card_front,omitempty"` + Account string `protobuf:"bytes,5,opt,name=account,proto3" json:"account,omitempty"` + Sex uint32 `protobuf:"varint,6,opt,name=sex,proto3" json:"sex,omitempty"` + GroupId int64 `protobuf:"varint,7,opt,name=group_id,json=groupId,proto3" json:"group_id,omitempty"` + BirthDate string `protobuf:"bytes,8,opt,name=birth_date,json=birthDate,proto3" json:"birth_date,omitempty"` + SaleId int64 `protobuf:"varint,9,opt,name=sale_id,json=saleId,proto3" json:"sale_id,omitempty"` + Type uint32 `protobuf:"varint,10,opt,name=type,proto3" json:"type,omitempty"` + TerritoryId int64 `protobuf:"varint,11,opt,name=territory_id,json=territoryId,proto3" json:"territory_id,omitempty"` + TerritoryName string `protobuf:"bytes,12,opt,name=territory_name,json=territoryName,proto3" json:"territory_name,omitempty"` + ProvinceId int64 `protobuf:"varint,13,opt,name=province_id,json=provinceId,proto3" json:"province_id,omitempty"` + CityId int64 `protobuf:"varint,14,opt,name=city_id,json=cityId,proto3" json:"city_id,omitempty"` + DistrictId int64 `protobuf:"varint,15,opt,name=district_id,json=districtId,proto3" json:"district_id,omitempty"` + RegionProvince string `protobuf:"bytes,16,opt,name=region_province,json=regionProvince,proto3" json:"region_province,omitempty"` + RegionCity string `protobuf:"bytes,17,opt,name=region_city,json=regionCity,proto3" json:"region_city,omitempty"` + RegionDistrict string `protobuf:"bytes,18,opt,name=region_district,json=regionDistrict,proto3" json:"region_district,omitempty"` + Address string `protobuf:"bytes,19,opt,name=address,proto3" json:"address,omitempty"` + IdCardBack string `protobuf:"bytes,20,opt,name=id_card_back,json=idCardBack,proto3" json:"id_card_back,omitempty"` + BusinessLicense string `protobuf:"bytes,21,opt,name=business_license,json=businessLicense,proto3" json:"business_license,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EditReq) Reset() { + *x = EditReq{} + mi := &file_sale_sale_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EditReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EditReq) ProtoMessage() {} + +func (x *EditReq) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_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 EditReq.ProtoReflect.Descriptor instead. +func (*EditReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{8} +} + +func (x *EditReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *EditReq) GetMobile() string { + if x != nil { + return x.Mobile + } + return "" +} + +func (x *EditReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *EditReq) GetIdCardFront() string { + if x != nil { + return x.IdCardFront + } + return "" +} + +func (x *EditReq) GetAccount() string { + if x != nil { + return x.Account + } + return "" +} + +func (x *EditReq) GetSex() uint32 { + if x != nil { + return x.Sex + } + return 0 +} + +func (x *EditReq) GetGroupId() int64 { + if x != nil { + return x.GroupId + } + return 0 +} + +func (x *EditReq) GetBirthDate() string { + if x != nil { + return x.BirthDate + } + return "" +} + +func (x *EditReq) GetSaleId() int64 { + if x != nil { + return x.SaleId + } + return 0 +} + +func (x *EditReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *EditReq) GetTerritoryId() int64 { + if x != nil { + return x.TerritoryId + } + return 0 +} + +func (x *EditReq) GetTerritoryName() string { + if x != nil { + return x.TerritoryName + } + return "" +} + +func (x *EditReq) GetProvinceId() int64 { + if x != nil { + return x.ProvinceId + } + return 0 +} + +func (x *EditReq) GetCityId() int64 { + if x != nil { + return x.CityId + } + return 0 +} + +func (x *EditReq) GetDistrictId() int64 { + if x != nil { + return x.DistrictId + } + return 0 +} + +func (x *EditReq) GetRegionProvince() string { + if x != nil { + return x.RegionProvince + } + return "" +} + +func (x *EditReq) GetRegionCity() string { + if x != nil { + return x.RegionCity + } + return "" +} + +func (x *EditReq) GetRegionDistrict() string { + if x != nil { + return x.RegionDistrict + } + return "" +} + +func (x *EditReq) GetAddress() string { + if x != nil { + return x.Address + } + return "" +} + +func (x *EditReq) GetIdCardBack() string { + if x != nil { + return x.IdCardBack + } + return "" +} + +func (x *EditReq) GetBusinessLicense() string { + if x != nil { + return x.BusinessLicense + } + return "" +} + +type InfoReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InfoReq) Reset() { + *x = InfoReq{} + mi := &file_sale_sale_proto_msgTypes[9] + 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_sale_sale_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 InfoReq.ProtoReflect.Descriptor instead. +func (*InfoReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{9} +} + +func (x *InfoReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +type ItemsReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Page uint32 `protobuf:"varint,2,opt,name=page,proto3" json:"page,omitempty"` + PageSize uint32 `protobuf:"varint,3,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + SaleId int64 `protobuf:"varint,4,opt,name=sale_id,json=saleId,proto3" json:"sale_id,omitempty"` + Type uint32 `protobuf:"varint,5,opt,name=type,proto3" json:"type,omitempty"` + Status uint32 `protobuf:"varint,6,opt,name=status,proto3" json:"status,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ItemsReq) Reset() { + *x = ItemsReq{} + mi := &file_sale_sale_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ItemsReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ItemsReq) ProtoMessage() {} + +func (x *ItemsReq) 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 ItemsReq.ProtoReflect.Descriptor instead. +func (*ItemsReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{10} +} + +func (x *ItemsReq) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ItemsReq) GetPage() uint32 { + if x != nil { + return x.Page + } + return 0 +} + +func (x *ItemsReq) GetPageSize() uint32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ItemsReq) GetSaleId() int64 { + if x != nil { + return x.SaleId + } + return 0 +} + +func (x *ItemsReq) GetType() uint32 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *ItemsReq) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +type StatusReq struct { + state protoimpl.MessageState `protogen:"open.v1"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Status uint32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` + Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *StatusReq) Reset() { + *x = StatusReq{} + mi := &file_sale_sale_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StatusReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusReq) ProtoMessage() {} + +func (x *StatusReq) ProtoReflect() protoreflect.Message { + mi := &file_sale_sale_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 StatusReq.ProtoReflect.Descriptor instead. +func (*StatusReq) Descriptor() ([]byte, []int) { + return file_sale_sale_proto_rawDescGZIP(), []int{11} +} + +func (x *StatusReq) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *StatusReq) GetStatus() uint32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *StatusReq) GetReason() string { + if x != nil { + return x.Reason + } + return "" +} + +var File_sale_sale_proto protoreflect.FileDescriptor + +const file_sale_sale_proto_rawDesc = "" + + "\n" + + "\x0fsale/sale.proto\x12\x04sale\x1a\x1cgoogle/api/annotations.proto\"D\n" + + "\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\"\x0f\n" + + "\rGroupEmptyReq\"T\n" + + "\rGroupItemsReq\x12\x12\n" + + "\x04page\x18\x01 \x01(\rR\x04page\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\rR\bpageSize\x12\x12\n" + + "\x04name\x18\x03 \x01(\tR\x04name\"$\n" + + "\x0eGroupCreateReq\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"H\n" + + "\bNamesReq\x12\x12\n" + + "\x04type\x18\x01 \x01(\rR\x04type\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" + + "\x05level\x18\x03 \x01(\rR\x05level\"F\n" + + "\bNameItem\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\"1\n" + + "\tNamesData\x12$\n" + + "\x05items\x18\x01 \x03(\v2\x0e.sale.NameItemR\x05items\"\x89\x05\n" + + "\tCreateReq\x12\x16\n" + + "\x06mobile\x18\x01 \x01(\tR\x06mobile\x12\x12\n" + + "\x04name\x18\x02 \x01(\tR\x04name\x12\"\n" + + "\rid_card_front\x18\x03 \x01(\tR\vidCardFront\x12\x1a\n" + + "\bpassword\x18\x04 \x01(\tR\bpassword\x12\x18\n" + + "\aaccount\x18\x05 \x01(\tR\aaccount\x12\x10\n" + + "\x03sex\x18\x06 \x01(\rR\x03sex\x12\x19\n" + + "\bgroup_id\x18\a \x01(\x03R\agroupId\x12\x1d\n" + + "\n" + + "birth_date\x18\b \x01(\tR\tbirthDate\x12\x17\n" + + "\asale_id\x18\t \x01(\x03R\x06saleId\x12\x12\n" + + "\x04type\x18\n" + + " \x01(\rR\x04type\x12!\n" + + "\fterritory_id\x18\v \x01(\x03R\vterritoryId\x12%\n" + + "\x0eterritory_name\x18\f \x01(\tR\rterritoryName\x12\x1f\n" + + "\vprovince_id\x18\r \x01(\x03R\n" + + "provinceId\x12\x17\n" + + "\acity_id\x18\x0e \x01(\x03R\x06cityId\x12\x1f\n" + + "\vdistrict_id\x18\x0f \x01(\x03R\n" + + "districtId\x12'\n" + + "\x0fregion_province\x18\x10 \x01(\tR\x0eregionProvince\x12\x1f\n" + + "\vregion_city\x18\x11 \x01(\tR\n" + + "regionCity\x12'\n" + + "\x0fregion_district\x18\x12 \x01(\tR\x0eregionDistrict\x12\x18\n" + + "\aaddress\x18\x13 \x01(\tR\aaddress\x12 \n" + + "\fid_card_back\x18\x14 \x01(\tR\n" + + "idCardBack\x12)\n" + + "\x10business_license\x18\x15 \x01(\tR\x0fbusinessLicense\"\xfb\x04\n" + + "\aEditReq\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\"\n" + + "\rid_card_front\x18\x04 \x01(\tR\vidCardFront\x12\x18\n" + + "\aaccount\x18\x05 \x01(\tR\aaccount\x12\x10\n" + + "\x03sex\x18\x06 \x01(\rR\x03sex\x12\x19\n" + + "\bgroup_id\x18\a \x01(\x03R\agroupId\x12\x1d\n" + + "\n" + + "birth_date\x18\b \x01(\tR\tbirthDate\x12\x17\n" + + "\asale_id\x18\t \x01(\x03R\x06saleId\x12\x12\n" + + "\x04type\x18\n" + + " \x01(\rR\x04type\x12!\n" + + "\fterritory_id\x18\v \x01(\x03R\vterritoryId\x12%\n" + + "\x0eterritory_name\x18\f \x01(\tR\rterritoryName\x12\x1f\n" + + "\vprovince_id\x18\r \x01(\x03R\n" + + "provinceId\x12\x17\n" + + "\acity_id\x18\x0e \x01(\x03R\x06cityId\x12\x1f\n" + + "\vdistrict_id\x18\x0f \x01(\x03R\n" + + "districtId\x12'\n" + + "\x0fregion_province\x18\x10 \x01(\tR\x0eregionProvince\x12\x1f\n" + + "\vregion_city\x18\x11 \x01(\tR\n" + + "regionCity\x12'\n" + + "\x0fregion_district\x18\x12 \x01(\tR\x0eregionDistrict\x12\x18\n" + + "\aaddress\x18\x13 \x01(\tR\aaddress\x12 \n" + + "\fid_card_back\x18\x14 \x01(\tR\n" + + "idCardBack\x12)\n" + + "\x10business_license\x18\x15 \x01(\tR\x0fbusinessLicense\"\x19\n" + + "\aInfoReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\"\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" + + "\tpage_size\x18\x03 \x01(\rR\bpageSize\x12\x17\n" + + "\asale_id\x18\x04 \x01(\x03R\x06saleId\x12\x12\n" + + "\x04type\x18\x05 \x01(\rR\x04type\x12\x16\n" + + "\x06status\x18\x06 \x01(\rR\x06status\"K\n" + + "\tStatusReq\x12\x0e\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x16\n" + + "\x06status\x18\x02 \x01(\rR\x06status\x12\x16\n" + + "\x06reason\x18\x03 \x01(\tR\x06reason2\xbf\x06\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" + + "\vGroupCreate\x12\x14.sale.GroupCreateReq\x1a\x0e.sale.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\"\x15/admin/v3/sales/group\x12Y\n" + + "\n" + + "GroupNames\x12\x13.sale.GroupEmptyReq\x1a\x0e.sale.Response\"&\x82\xd3\xe4\x93\x02 :\x01*\x12\x1b/admin/v3/sales/group/names\x12N\n" + + "\x05Types\x12\x13.sale.GroupEmptyReq\x1a\x0e.sale.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\x12\x15/admin/v3/sales/types\x12I\n" + + "\x05Names\x12\x0e.sale.NamesReq\x1a\x0e.sale.Response\" \x82\xd3\xe4\x93\x02\x1a:\x01*\x12\x15/admin/v3/sales/names\x120\n" + + "\rNamesInternal\x12\x0e.sale.NamesReq\x1a\x0f.sale.NamesData\x12E\n" + + "\x06Create\x12\x0f.sale.CreateReq\x1a\x0e.sale.Response\"\x1a\x82\xd3\xe4\x93\x02\x14:\x01*\"\x0f/admin/v3/sales\x12A\n" + + "\x04Edit\x12\r.sale.EditReq\x1a\x0e.sale.Response\"\x1a\x82\xd3\xe4\x93\x02\x14:\x01*\x1a\x0f/admin/v3/sales\x12F\n" + + "\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/statusB\x18Z\x16lone-services/rpc/saleb\x06proto3" + +var ( + file_sale_sale_proto_rawDescOnce sync.Once + file_sale_sale_proto_rawDescData []byte +) + +func file_sale_sale_proto_rawDescGZIP() []byte { + file_sale_sale_proto_rawDescOnce.Do(func() { + file_sale_sale_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_sale_sale_proto_rawDesc), len(file_sale_sale_proto_rawDesc))) + }) + return file_sale_sale_proto_rawDescData +} + +var file_sale_sale_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +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 + (*ItemsReq)(nil), // 10: sale.ItemsReq + (*StatusReq)(nil), // 11: sale.StatusReq +} +var file_sale_sale_proto_depIdxs = []int32{ + 5, // 0: sale.NamesData.items:type_name -> sale.NameItem + 2, // 1: sale.Sale.GroupItems:input_type -> sale.GroupItemsReq + 3, // 2: sale.Sale.GroupCreate:input_type -> sale.GroupCreateReq + 1, // 3: sale.Sale.GroupNames:input_type -> sale.GroupEmptyReq + 1, // 4: sale.Sale.Types:input_type -> sale.GroupEmptyReq + 4, // 5: sale.Sale.Names:input_type -> sale.NamesReq + 4, // 6: sale.Sale.NamesInternal:input_type -> sale.NamesReq + 7, // 7: sale.Sale.Create:input_type -> sale.CreateReq + 8, // 8: sale.Sale.Edit:input_type -> sale.EditReq + 9, // 9: sale.Sale.Info:input_type -> sale.InfoReq + 10, // 10: sale.Sale.Items:input_type -> sale.ItemsReq + 11, // 11: sale.Sale.Status:input_type -> sale.StatusReq + 0, // 12: sale.Sale.GroupItems:output_type -> sale.Response + 0, // 13: sale.Sale.GroupCreate:output_type -> sale.Response + 0, // 14: sale.Sale.GroupNames:output_type -> sale.Response + 0, // 15: sale.Sale.Types:output_type -> sale.Response + 0, // 16: sale.Sale.Names:output_type -> sale.Response + 6, // 17: sale.Sale.NamesInternal:output_type -> sale.NamesData + 0, // 18: sale.Sale.Create:output_type -> sale.Response + 0, // 19: sale.Sale.Edit:output_type -> sale.Response + 0, // 20: sale.Sale.Info:output_type -> sale.Response + 0, // 21: sale.Sale.Items:output_type -> sale.Response + 0, // 22: sale.Sale.Status:output_type -> sale.Response + 12, // [12:23] is the sub-list for method output_type + 1, // [1:12] 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_sale_sale_proto_init() } +func file_sale_sale_proto_init() { + if File_sale_sale_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_sale_sale_proto_rawDesc), len(file_sale_sale_proto_rawDesc)), + NumEnums: 0, + NumMessages: 12, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_sale_sale_proto_goTypes, + DependencyIndexes: file_sale_sale_proto_depIdxs, + MessageInfos: file_sale_sale_proto_msgTypes, + }.Build() + File_sale_sale_proto = out.File + file_sale_sale_proto_goTypes = nil + file_sale_sale_proto_depIdxs = nil +} diff --git a/rpc/sale/pb/sale_grpc.pb.go b/rpc/sale/pb/sale_grpc.pb.go new file mode 100644 index 0000000..0f2a681 --- /dev/null +++ b/rpc/sale/pb/sale_grpc.pb.go @@ -0,0 +1,505 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.6.2 +// - protoc v3.19.4 +// source: sale/sale.proto + +package sale + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + Sale_GroupItems_FullMethodName = "/sale.Sale/GroupItems" + Sale_GroupCreate_FullMethodName = "/sale.Sale/GroupCreate" + Sale_GroupNames_FullMethodName = "/sale.Sale/GroupNames" + Sale_Types_FullMethodName = "/sale.Sale/Types" + Sale_Names_FullMethodName = "/sale.Sale/Names" + Sale_NamesInternal_FullMethodName = "/sale.Sale/NamesInternal" + Sale_Create_FullMethodName = "/sale.Sale/Create" + Sale_Edit_FullMethodName = "/sale.Sale/Edit" + Sale_Info_FullMethodName = "/sale.Sale/Info" + Sale_Items_FullMethodName = "/sale.Sale/Items" + Sale_Status_FullMethodName = "/sale.Sale/Status" +) + +// SaleClient is the client API for Sale 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 SaleClient interface { + // 销售分组 + GroupItems(ctx context.Context, in *GroupItemsReq, opts ...grpc.CallOption) (*Response, error) + GroupCreate(ctx context.Context, in *GroupCreateReq, opts ...grpc.CallOption) (*Response, error) + GroupNames(ctx context.Context, in *GroupEmptyReq, opts ...grpc.CallOption) (*Response, error) + // 销售管理 + Types(ctx context.Context, in *GroupEmptyReq, opts ...grpc.CallOption) (*Response, error) + Names(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*Response, error) + NamesInternal(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*NamesData, error) + Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) + Edit(ctx context.Context, in *EditReq, opts ...grpc.CallOption) (*Response, error) + Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error) + Items(ctx context.Context, in *ItemsReq, opts ...grpc.CallOption) (*Response, error) + Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) +} + +type saleClient struct { + cc grpc.ClientConnInterface +} + +func NewSaleClient(cc grpc.ClientConnInterface) SaleClient { + return &saleClient{cc} +} + +func (c *saleClient) GroupItems(ctx context.Context, in *GroupItemsReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_GroupItems_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) GroupCreate(ctx context.Context, in *GroupCreateReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_GroupCreate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) GroupNames(ctx context.Context, in *GroupEmptyReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_GroupNames_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) Types(ctx context.Context, in *GroupEmptyReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_Types_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) Names(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_Names_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) NamesInternal(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*NamesData, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(NamesData) + err := c.cc.Invoke(ctx, Sale_NamesInternal_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_Create_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) Edit(ctx context.Context, in *EditReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_Edit_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) 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, Sale_Info_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) Items(ctx context.Context, in *ItemsReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_Items_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *saleClient) Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Response) + err := c.cc.Invoke(ctx, Sale_Status_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// SaleServer is the server API for Sale service. +// All implementations must embed UnimplementedSaleServer +// for forward compatibility. +type SaleServer interface { + // 销售分组 + GroupItems(context.Context, *GroupItemsReq) (*Response, error) + GroupCreate(context.Context, *GroupCreateReq) (*Response, error) + GroupNames(context.Context, *GroupEmptyReq) (*Response, error) + // 销售管理 + Types(context.Context, *GroupEmptyReq) (*Response, error) + Names(context.Context, *NamesReq) (*Response, error) + NamesInternal(context.Context, *NamesReq) (*NamesData, error) + Create(context.Context, *CreateReq) (*Response, error) + Edit(context.Context, *EditReq) (*Response, error) + Info(context.Context, *InfoReq) (*Response, error) + Items(context.Context, *ItemsReq) (*Response, error) + Status(context.Context, *StatusReq) (*Response, error) + mustEmbedUnimplementedSaleServer() +} + +// UnimplementedSaleServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedSaleServer struct{} + +func (UnimplementedSaleServer) GroupItems(context.Context, *GroupItemsReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method GroupItems not implemented") +} +func (UnimplementedSaleServer) GroupCreate(context.Context, *GroupCreateReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method GroupCreate not implemented") +} +func (UnimplementedSaleServer) GroupNames(context.Context, *GroupEmptyReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method GroupNames not implemented") +} +func (UnimplementedSaleServer) Types(context.Context, *GroupEmptyReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Types not implemented") +} +func (UnimplementedSaleServer) Names(context.Context, *NamesReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Names not implemented") +} +func (UnimplementedSaleServer) NamesInternal(context.Context, *NamesReq) (*NamesData, error) { + return nil, status.Error(codes.Unimplemented, "method NamesInternal not implemented") +} +func (UnimplementedSaleServer) Create(context.Context, *CreateReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Create not implemented") +} +func (UnimplementedSaleServer) Edit(context.Context, *EditReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Edit not implemented") +} +func (UnimplementedSaleServer) Info(context.Context, *InfoReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Info not implemented") +} +func (UnimplementedSaleServer) Items(context.Context, *ItemsReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Items not implemented") +} +func (UnimplementedSaleServer) Status(context.Context, *StatusReq) (*Response, error) { + return nil, status.Error(codes.Unimplemented, "method Status not implemented") +} +func (UnimplementedSaleServer) mustEmbedUnimplementedSaleServer() {} +func (UnimplementedSaleServer) testEmbeddedByValue() {} + +// UnsafeSaleServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to SaleServer will +// result in compilation errors. +type UnsafeSaleServer interface { + mustEmbedUnimplementedSaleServer() +} + +func RegisterSaleServer(s grpc.ServiceRegistrar, srv SaleServer) { + // If the following call panics, it indicates UnimplementedSaleServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&Sale_ServiceDesc, srv) +} + +func _Sale_GroupItems_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GroupItemsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).GroupItems(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_GroupItems_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).GroupItems(ctx, req.(*GroupItemsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_GroupCreate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GroupCreateReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).GroupCreate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_GroupCreate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).GroupCreate(ctx, req.(*GroupCreateReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_GroupNames_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GroupEmptyReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).GroupNames(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_GroupNames_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).GroupNames(ctx, req.(*GroupEmptyReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_Types_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GroupEmptyReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).Types(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_Types_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).Types(ctx, req.(*GroupEmptyReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_Names_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NamesReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).Names(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_Names_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).Names(ctx, req.(*NamesReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_NamesInternal_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(NamesReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).NamesInternal(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_NamesInternal_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).NamesInternal(ctx, req.(*NamesReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_Create_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).Create(ctx, req.(*CreateReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_Edit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EditReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).Edit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_Edit_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).Edit(ctx, req.(*EditReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_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.(SaleServer).Info(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_Info_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).Info(ctx, req.(*InfoReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_Items_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ItemsReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).Items(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_Items_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).Items(ctx, req.(*ItemsReq)) + } + return interceptor(ctx, in, info, handler) +} + +func _Sale_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StatusReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SaleServer).Status(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Sale_Status_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SaleServer).Status(ctx, req.(*StatusReq)) + } + return interceptor(ctx, in, info, handler) +} + +// Sale_ServiceDesc is the grpc.ServiceDesc for Sale service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Sale_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "sale.Sale", + HandlerType: (*SaleServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GroupItems", + Handler: _Sale_GroupItems_Handler, + }, + { + MethodName: "GroupCreate", + Handler: _Sale_GroupCreate_Handler, + }, + { + MethodName: "GroupNames", + Handler: _Sale_GroupNames_Handler, + }, + { + MethodName: "Types", + Handler: _Sale_Types_Handler, + }, + { + MethodName: "Names", + Handler: _Sale_Names_Handler, + }, + { + MethodName: "NamesInternal", + Handler: _Sale_NamesInternal_Handler, + }, + { + MethodName: "Create", + Handler: _Sale_Create_Handler, + }, + { + MethodName: "Edit", + Handler: _Sale_Edit_Handler, + }, + { + MethodName: "Info", + Handler: _Sale_Info_Handler, + }, + { + MethodName: "Items", + Handler: _Sale_Items_Handler, + }, + { + MethodName: "Status", + Handler: _Sale_Status_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "sale/sale.proto", +} diff --git a/rpc/sale/sale.pb b/rpc/sale/sale.pb new file mode 100644 index 0000000..767894e Binary files /dev/null and b/rpc/sale/sale.pb differ diff --git a/rpc/sale/sale.proto b/rpc/sale/sale.proto new file mode 100644 index 0000000..4705e8b --- /dev/null +++ b/rpc/sale/sale.proto @@ -0,0 +1,173 @@ +syntax = "proto3"; + +package sale; +option go_package = "lone-services/rpc/sale"; +import "google/api/annotations.proto"; + +service Sale { + // 销售分组 + rpc GroupItems(GroupItemsReq) returns (Response) { + option (google.api.http) = { + get: "/admin/v3/sales/group" + body: "*" + }; + } + rpc GroupCreate(GroupCreateReq) returns (Response) { + option (google.api.http) = { + post: "/admin/v3/sales/group" + body: "*" + }; + } + rpc GroupNames(GroupEmptyReq) returns (Response) { + option (google.api.http) = { + get: "/admin/v3/sales/group/names" + body: "*" + }; + } + + // 销售管理 + rpc Types(GroupEmptyReq) returns (Response) { + option (google.api.http) = { + get: "/admin/v3/sales/types" + body: "*" + }; + } + rpc Names(NamesReq) returns (Response) { + option (google.api.http) = { + get: "/admin/v3/sales/names" + body: "*" + }; + } + rpc NamesInternal(NamesReq) returns (NamesData); + rpc Create(CreateReq) returns (Response) { + option (google.api.http) = { + post: "/admin/v3/sales" + body: "*" + }; + } + rpc Edit(EditReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/sales" + body: "*" + }; + } + rpc Info(InfoReq) returns (Response) { + option (google.api.http) = { + get: "/admin/v3/sales/info" + body: "*" + }; + } + rpc Items(ItemsReq) returns (Response) { + option (google.api.http) = { + get: "/admin/v3/sales" + body: "*" + }; + } + rpc Status(StatusReq) returns (Response) { + option (google.api.http) = { + put: "/admin/v3/sales/status" + body: "*" + }; + } +} + +message Response { + int32 code = 1; + string msg = 2; + string data = 3; +} + +message GroupEmptyReq {} + +message GroupItemsReq { + uint32 page = 1; + uint32 page_size = 2; + string name = 3; +} + +message GroupCreateReq { + string name = 1; +} + +message NamesReq { + uint32 type = 1; + string name = 2; + uint32 level = 3; +} + +message NameItem { + int64 id = 1; + string mobile = 2; + string name = 3; +} + +message NamesData { + repeated NameItem items = 1; +} + +message CreateReq { + string mobile = 1; + string name = 2; + string id_card_front = 3; + string password = 4; + string account = 5; + uint32 sex = 6; + int64 group_id = 7; + string birth_date = 8; + int64 sale_id = 9; + uint32 type = 10; + int64 territory_id = 11; + string territory_name = 12; + int64 province_id = 13; + int64 city_id = 14; + int64 district_id = 15; + string region_province = 16; + string region_city = 17; + string region_district = 18; + string address = 19; + string id_card_back = 20; + string business_license = 21; +} + +message EditReq { + int64 id = 1; + string mobile = 2; + string name = 3; + string id_card_front = 4; + string account = 5; + uint32 sex = 6; + int64 group_id = 7; + string birth_date = 8; + int64 sale_id = 9; + uint32 type = 10; + int64 territory_id = 11; + string territory_name = 12; + int64 province_id = 13; + int64 city_id = 14; + int64 district_id = 15; + string region_province = 16; + string region_city = 17; + string region_district = 18; + string address = 19; + string id_card_back = 20; + string business_license = 21; +} + +message InfoReq { + int64 id = 1; +} + +message ItemsReq { + string name = 1; + uint32 page = 2; + uint32 page_size = 3; + int64 sale_id = 4; + uint32 type = 5; + uint32 status = 6; +} + +message StatusReq { + int64 id = 1; + uint32 status = 2; + string reason = 3; +} diff --git a/services/ad/internal/logic/createLogic.go b/services/ad/internal/logic/createLogic.go index 8b30a10..1fd5a92 100644 --- a/services/ad/internal/logic/createLogic.go +++ b/services/ad/internal/logic/createLogic.go @@ -52,5 +52,5 @@ func (l *CreateLogic) Create(in *ad.CreateReq) (*ad.Response, error) { return failResponse(utils.Fail), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } diff --git a/services/ad/internal/logic/editLogic.go b/services/ad/internal/logic/editLogic.go index eeed63e..c3c99be 100644 --- a/services/ad/internal/logic/editLogic.go +++ b/services/ad/internal/logic/editLogic.go @@ -64,5 +64,5 @@ func (l *EditLogic) Edit(in *ad.EditReq) (*ad.Response, error) { return failResponse(utils.Fail), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } diff --git a/services/ad/internal/logic/itemsLogic.go b/services/ad/internal/logic/itemsLogic.go index 261e201..f99df8d 100644 --- a/services/ad/internal/logic/itemsLogic.go +++ b/services/ad/internal/logic/itemsLogic.go @@ -62,8 +62,8 @@ func (l *ItemsLogic) Items(in *ad.ItemsReq) (*ad.Response, error) { items = append(items, toAdItem(row)) } - return okResponse(utils.StructToJson(&ad.ItemsData{ + return okResponse(&ad.ItemsData{ Count: result.Count, Items: items, - })), nil + }), nil } diff --git a/services/ad/internal/logic/response.go b/services/ad/internal/logic/response.go index 9059ef5..61c4c3f 100644 --- a/services/ad/internal/logic/response.go +++ b/services/ad/internal/logic/response.go @@ -3,13 +3,16 @@ package logic import ( "lone-services/pkg/utils" ad "lone-services/rpc/ad/pb" + + jsoniter "github.com/json-iterator/go" ) -func okResponse(data string) *ad.Response { +func okResponse(data any) *ad.Response { + buf, _ := jsoniter.Marshal(data) return &ad.Response{ Code: utils.Ok.Code, Msg: utils.Ok.Msg, - Data: data, + Data: string(buf), } } diff --git a/services/ad/internal/logic/statusLogic.go b/services/ad/internal/logic/statusLogic.go index 3c09c55..cdb1ff4 100644 --- a/services/ad/internal/logic/statusLogic.go +++ b/services/ad/internal/logic/statusLogic.go @@ -62,5 +62,5 @@ func (l *StatusLogic) Status(in *ad.StatusReq) (*ad.Response, error) { return failResponse(utils.Fail), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } diff --git a/services/ad/internal/logic/webItemsLogic.go b/services/ad/internal/logic/webItemsLogic.go index db91a7b..8275168 100644 --- a/services/ad/internal/logic/webItemsLogic.go +++ b/services/ad/internal/logic/webItemsLogic.go @@ -64,5 +64,5 @@ func (l *WebItemsLogic) WebItems(in *ad.WebItemsReq) (*ad.Response, error) { items = append(items, toAdWebItem(row)) } - return okResponse(utils.StructToJson(items)), nil + return okResponse(items), nil } diff --git a/services/chore/chore.go b/services/chore/chore.go index 7382b33..d603e78 100644 --- a/services/chore/chore.go +++ b/services/chore/chore.go @@ -7,6 +7,8 @@ import ( "strconv" "lone-services/pkg/discovery" + "lone-services/pkg/modelbase" + "lone-services/pkg/mysql" "lone-services/pkg/redis" "lone-services/pkg/utils" "lone-services/pkg/validate" @@ -88,24 +90,24 @@ func main() { } }() - // db, err := mysql.New(mysql.Config{ - // Host: utils.GetConfigString("mysql.host"), - // Port: utils.GetConfigInt("mysql.port"), - // User: utils.GetConfigString("mysql.user"), - // Password: utils.GetConfigString("mysql.password"), - // Database: utils.GetConfigString("mysql.database"), - // Charset: utils.GetConfigString("mysql.charset"), - // Prefix: utils.GetConfigString("mysql.prefix"), - // ReadHost: utils.GetConfigString("mysql_read.host"), - // ReadPort: utils.GetConfigInt("mysql_read.port"), - // ReadUser: utils.GetConfigString("mysql_read.user"), - // ReadPassword: utils.GetConfigString("mysql_read.password"), - // ReadDatabase: utils.GetConfigString("mysql_read.database"), - // }) - // if err != nil { - // logx.Errorf("mysql init: %v", err) - // os.Exit(1) - // } + db, err := mysql.New(mysql.Config{ + Host: utils.GetConfigString("mysql.host"), + Port: utils.GetConfigInt("mysql.port"), + User: utils.GetConfigString("mysql.user"), + Password: utils.GetConfigString("mysql.password"), + Database: utils.GetConfigString("mysql.database"), + Charset: utils.GetConfigString("mysql.charset"), + Prefix: utils.GetConfigString("mysql.prefix"), + ReadHost: utils.GetConfigString("mysql_read.host"), + ReadPort: utils.GetConfigInt("mysql_read.port"), + ReadUser: utils.GetConfigString("mysql_read.user"), + ReadPassword: utils.GetConfigString("mysql_read.password"), + ReadDatabase: utils.GetConfigString("mysql_read.database"), + }) + if err != nil { + logx.Errorf("mysql init: %v", err) + os.Exit(1) + } if err := redis.Init(redis.Config{ Host: utils.GetConfigString("redis.host"), @@ -117,16 +119,15 @@ func main() { os.Exit(1) } - // debug := utils.GetConfigBool("mysql.debug")test - // modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) + debug := utils.GetConfigBool("mysql.debug") + modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) rpcConf := zrpc.RpcServerConf{ ListenOn: listenOn, } rpcConf.Mode = mode - // ctx := svc.NewServiceContext(c, db) - ctx := svc.NewServiceContext(c) + ctx := svc.NewServiceContext(c, db) s := zrpc.MustNewServer(rpcConf, func(grpcServer *grpc.Server) { chore.RegisterChoreServer(grpcServer, server.NewChoreServer(ctx)) diff --git a/services/chore/choreclient/chore.go b/services/chore/choreclient/chore.go index 2c5ae83..f8f96a7 100644 --- a/services/chore/choreclient/chore.go +++ b/services/chore/choreclient/chore.go @@ -14,13 +14,17 @@ import ( ) type ( - PolicyReq = chore.PolicyReq - Response = chore.Response - TestReq = chore.TestReq + DecryptMobileReq = chore.DecryptMobileReq + PolicyReq = chore.PolicyReq + RegionsReq = chore.RegionsReq + Response = chore.Response + TestReq = chore.TestReq Chore interface { Policy(ctx context.Context, in *PolicyReq, opts ...grpc.CallOption) (*Response, error) Test(ctx context.Context, in *TestReq, opts ...grpc.CallOption) (*Response, error) + DecryptMobile(ctx context.Context, in *DecryptMobileReq, opts ...grpc.CallOption) (*Response, error) + Regions(ctx context.Context, in *RegionsReq, opts ...grpc.CallOption) (*Response, error) } defaultChore struct { @@ -43,3 +47,13 @@ func (m *defaultChore) Test(ctx context.Context, in *TestReq, opts ...grpc.CallO client := chore.NewChoreClient(m.cli.Conn()) return client.Test(ctx, in, opts...) } + +func (m *defaultChore) DecryptMobile(ctx context.Context, in *DecryptMobileReq, opts ...grpc.CallOption) (*Response, error) { + client := chore.NewChoreClient(m.cli.Conn()) + return client.DecryptMobile(ctx, in, opts...) +} + +func (m *defaultChore) Regions(ctx context.Context, in *RegionsReq, opts ...grpc.CallOption) (*Response, error) { + client := chore.NewChoreClient(m.cli.Conn()) + return client.Regions(ctx, in, opts...) +} diff --git a/services/chore/internal/dao/region.go b/services/chore/internal/dao/region.go new file mode 100644 index 0000000..84d1d9a --- /dev/null +++ b/services/chore/internal/dao/region.go @@ -0,0 +1,10 @@ +package dao + +type Region struct { + Id uint `gorm:"column:id" json:"id"` + ParentId *uint `gorm:"column:parent_id" json:"parent_id"` + Code string `gorm:"column:code" json:"code"` + Name string `gorm:"column:name" json:"name"` + Level uint8 `gorm:"column:level" json:"level"` + CityCode string `gorm:"column:city_code" json:"city_code"` +} diff --git a/services/chore/internal/logic/decryptMobileLogic.go b/services/chore/internal/logic/decryptMobileLogic.go new file mode 100644 index 0000000..404c76f --- /dev/null +++ b/services/chore/internal/logic/decryptMobileLogic.go @@ -0,0 +1,52 @@ +package logic + +import ( + "context" + + "lone-services/pkg/utils" + chore "lone-services/rpc/chore/pb" + "lone-services/services/chore/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type DecryptMobileLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +type DecryptMobileData struct { + Mobile string `json:"mobile"` +} + +func NewDecryptMobileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DecryptMobileLogic { + return &DecryptMobileLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *DecryptMobileLogic) DecryptMobile(in *chore.DecryptMobileReq) (*chore.Response, error) { + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + originMobile := in.GetOriginMobile() + if originMobile == utils.StringEmpty { + return failResponse(utils.ErrorParams), nil + } + + mobile, err := utils.DecryptPhone(originMobile) + if err != nil { + l.Errorf("decrypt mobile: %v", err) + return &chore.Response{ + Code: int32(utils.ErrorDecryptAesError.GetCode()), + Msg: utils.ErrorDecryptAesError.GetMsg(), + }, nil + } + + return okResponse(DecryptMobileData{Mobile: mobile}), nil +} diff --git a/services/chore/internal/logic/regionsLogic.go b/services/chore/internal/logic/regionsLogic.go new file mode 100644 index 0000000..1bf05e3 --- /dev/null +++ b/services/chore/internal/logic/regionsLogic.go @@ -0,0 +1,54 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + chore "lone-services/rpc/chore/pb" + "lone-services/services/chore/internal/dao" + "lone-services/services/chore/internal/model" + "lone-services/services/chore/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type RegionsLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewRegionsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegionsLogic { + return &RegionsLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *RegionsLogic) Regions(in *chore.RegionsReq) (*chore.Response, error) { + params := modelbase.Params{ + Order: "id ASC", + } + + parentID := in.GetParentId() + if parentID < utils.NumberOne { + params.Eq = map[string]string{"level": strconv.Itoa(int(utils.NumberOne))} + } else { + params.Eq = map[string]string{"parent_id": strconv.Itoa(int(parentID))} + } + + var list []dao.Region + if err := (model.RegionModel{}.Init().Items(params, &list)); err != nil { + l.Errorf("regions list: %v", err) + return failResponse(utils.Fail), nil + } + + if list == nil { + list = []dao.Region{} + } + + return okResponse(list), nil +} diff --git a/services/chore/internal/logic/testLogic.go b/services/chore/internal/logic/testLogic.go index b83397b..2f3bcaf 100644 --- a/services/chore/internal/logic/testLogic.go +++ b/services/chore/internal/logic/testLogic.go @@ -2,12 +2,11 @@ package logic import ( "context" - "fmt" "lone-services/pkg/rpcclient" "lone-services/pkg/utils" chore "lone-services/rpc/chore/pb" - product "lone-services/rpc/product/pb" + sale "lone-services/rpc/sale/pb" "lone-services/services/chore/internal/svc" "github.com/zeromicro/go-zero/core/logx" @@ -33,8 +32,10 @@ func NewTestLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TestLogic { func (l *TestLogic) Test(in *chore.TestReq) (*chore.Response, error) { cli, err := rpcclient.Get(l.svcCtx.ProductSvcName) + // cli, err := rpcclient.Get(l.svcCtx.SaleSvcName) + if err != nil { - l.Errorf("get product rpc: %v", err) + l.Errorf("get rpc: %v", err) return failResponse(utils.ErrorInternalServer), nil } @@ -53,21 +54,40 @@ func (l *TestLogic) Test(in *chore.TestReq) (*chore.Response, error) { // fmt.Println(res.GetName()) // 获取多个产品详情 - res, err := product.NewProductClient(cli.Conn()).ItemsByIds(l.ctx, &product.ItemsByIdsReq{ - Ids: in.GetIds(), + // res, err := product.NewProductClient(cli.Conn()).ItemsByIds(l.ctx, &product.ItemsByIdsReq{ + // Ids: in.GetIds(), + // }) + // for _, item := range res.GetItems() { + // fmt.Println(item.GetName()) + // } + + // 销售 names + res, err := sale.NewSaleClient(cli.Conn()).NamesInternal(l.ctx, &sale.NamesReq{ + Type: in.GetNumber(), + Level: uint32(in.GetId()), }) - for _, item := range res.GetItems() { - fmt.Println(item.GetName()) - } + + // TODO: 批量扣减库存 + // items := make([]*product.NumberItem, 0, len(in.GetIds())) + // for _, id := range in.GetIds() { + // items = append(items, &product.NumberItem{ + // Id: id, + // Number: in.GetNumber(), + // }) + // } + // _, err = product.NewProductClient(cli.Conn()).NumberItems(l.ctx, &product.NumberItemsReq{ + // Type: productNumberTypeDecr, + // Items: items, + // }) if err != nil { - l.Errorf("错误信息: %v", err) + l.Errorf("XXXXXXXXXXX: %v", err) return failResponse(utils.ErrorInternalServer), nil } - if res == nil { - l.Errorf("res为空") + l.Errorf("XXXXXXXXXXX res为空") return failResponse(utils.Fail), nil } - return okResponse(res), nil + + return okResponse(nil), nil } diff --git a/services/chore/internal/model/region.go b/services/chore/internal/model/region.go new file mode 100644 index 0000000..400c2f5 --- /dev/null +++ b/services/chore/internal/model/region.go @@ -0,0 +1,18 @@ +package model + +import ( + "lone-services/pkg/modelbase" +) + +type RegionModel struct { + modelbase.Base +} + +func (m RegionModel) TableName() string { + return modelbase.Prefix() + "regions" +} + +func (m RegionModel) Init() RegionModel { + m.Table = m.TableName() + return m +} diff --git a/services/chore/internal/server/choreServer.go b/services/chore/internal/server/choreServer.go index a115572..68390ab 100644 --- a/services/chore/internal/server/choreServer.go +++ b/services/chore/internal/server/choreServer.go @@ -32,3 +32,13 @@ func (s *ChoreServer) Test(ctx context.Context, in *chore.TestReq) (*chore.Respo l := logic.NewTestLogic(ctx, s.svcCtx) return l.Test(in) } + +func (s *ChoreServer) DecryptMobile(ctx context.Context, in *chore.DecryptMobileReq) (*chore.Response, error) { + l := logic.NewDecryptMobileLogic(ctx, s.svcCtx) + return l.DecryptMobile(in) +} + +func (s *ChoreServer) Regions(ctx context.Context, in *chore.RegionsReq) (*chore.Response, error) { + l := logic.NewRegionsLogic(ctx, s.svcCtx) + return l.Regions(in) +} diff --git a/services/chore/internal/svc/servicecontext.go b/services/chore/internal/svc/servicecontext.go index ecfa91d..0f198b7 100644 --- a/services/chore/internal/svc/servicecontext.go +++ b/services/chore/internal/svc/servicecontext.go @@ -5,21 +5,30 @@ import ( "lone-services/services/chore/internal/config" "github.com/zeromicro/go-zero/core/logx" + "gorm.io/gorm" ) type ServiceContext struct { Config config.Config + DB *gorm.DB ProductSvcName string + SaleSvcName string } -func NewServiceContext(c config.Config) *ServiceContext { +func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { productSvc := utils.GetConfigString("services.product") if productSvc == utils.StringEmpty { logx.Error("config services.product empty") } + saleSvc := utils.GetConfigString("services.sale") + if saleSvc == utils.StringEmpty { + logx.Error("config services.sale empty") + } return &ServiceContext{ Config: c, + DB: db, ProductSvcName: productSvc, + SaleSvcName: saleSvc, } } diff --git a/services/chore/run.toml b/services/chore/run.toml index e56c906..08b1e59 100644 --- a/services/chore/run.toml +++ b/services/chore/run.toml @@ -27,6 +27,24 @@ dir = "upload/" expireSeconds = 3600 +[mysql] + host = '39.106.171.204' + port = 33066 + user = 'root' + password = 'MOLXRZNOU4Y4' + database = 'dms-chore' + charset = 'utf8mb4' + prefix = '' + debug = true +[mysql_read] + host = '39.106.171.204' + port = 33066 + user = 'root' + password = 'MOLXRZNOU4Y4' + database = 'dms-chore' + charset = 'utf8mb4' + prefix = '' + [redis] host = '39.106.171.204' password = 'lLMLcuPpzSj' @@ -37,4 +55,5 @@ data_key = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a" [services] - product = "product-service" \ No newline at end of file + product = "product-service" + sale = "sale-service" \ No newline at end of file diff --git a/services/express/Dockerfile b/services/express/Dockerfile new file mode 100644 index 0000000..90c3df1 --- /dev/null +++ b/services/express/Dockerfile @@ -0,0 +1,39 @@ +FROM golang:1.26.5-alpine AS builder + +WORKDIR /src + +ENV GOPROXY=https://goproxy.cn,direct \ + CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 + +COPY pkg ./pkg +COPY go.mod go.sum ./ + +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod download + +COPY rpc/ ./rpc +COPY services/express/ ./services/express/ + +WORKDIR /src/services/express + +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + go build -ldflags="-s -w" -o /out/main ./ + +FROM alpine:3.22 + +WORKDIR /app + +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +COPY --from=builder /out/main . + +EXPOSE 10600 + +CMD ["./main", "-f", "etc/express.yaml"] diff --git a/services/product/internal/logic/createlogic.go b/services/product/internal/logic/createlogic.go index df25005..0be4c82 100644 --- a/services/product/internal/logic/createlogic.go +++ b/services/product/internal/logic/createlogic.go @@ -155,7 +155,7 @@ func (l *CreateLogic) Create(in *product.CreateReq) (*product.Response, error) { return failResponse(utils.Fail), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } func parsePublishTime(s string) (time.Time, error) { diff --git a/services/product/internal/logic/editapplylogic.go b/services/product/internal/logic/editapplylogic.go index 8089f23..4c433d1 100644 --- a/services/product/internal/logic/editapplylogic.go +++ b/services/product/internal/logic/editapplylogic.go @@ -68,7 +68,7 @@ func (l *EditApplyLogic) EditApply(in *product.EditApplyReq) (*product.Response, return failResponse(utils.Fail), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } // EditApplyPass TODO: 临时接口,企微编辑申请审批对接后删除 @@ -104,5 +104,5 @@ func (l *EditApplyLogic) EditApplyPass(in *product.EditApplyPassReq) (*product.R return failResponse(utils.Fail), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } diff --git a/services/product/internal/logic/editbaselogic.go b/services/product/internal/logic/editbaselogic.go index 064f3a8..29563e7 100644 --- a/services/product/internal/logic/editbaselogic.go +++ b/services/product/internal/logic/editbaselogic.go @@ -123,5 +123,5 @@ func (l *EditBaseLogic) EditBase(in *product.EditBaseReq) (*product.Response, er }) _ = apply.Del(l.ctx, adminId, int(req.Id)) - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } diff --git a/services/product/internal/logic/editsusceptiblelogic.go b/services/product/internal/logic/editsusceptiblelogic.go index d482959..c5b346c 100644 --- a/services/product/internal/logic/editsusceptiblelogic.go +++ b/services/product/internal/logic/editsusceptiblelogic.go @@ -127,5 +127,5 @@ func (l *EditSusceptibleLogic) EditSusceptible(in *product.EditSusceptibleReq) ( }) _ = apply.Del(l.ctx, adminId, int(req.Id)) - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } diff --git a/services/product/internal/logic/infologic.go b/services/product/internal/logic/infologic.go index 6aaa9df..410ec09 100644 --- a/services/product/internal/logic/infologic.go +++ b/services/product/internal/logic/infologic.go @@ -57,5 +57,5 @@ func (l *InfoLogic) Info(in *product.InfoReq) (*product.Response, error) { info.Edit = applyData.Status } - return okResponse(utils.StructToJson(toProductItem(info))), nil + return okResponse(toProductItem(info)), nil } diff --git a/services/product/internal/logic/itemslogic.go b/services/product/internal/logic/itemslogic.go index 66615c2..e22e3d7 100644 --- a/services/product/internal/logic/itemslogic.go +++ b/services/product/internal/logic/itemslogic.go @@ -76,8 +76,8 @@ func (l *ItemsLogic) Items(in *product.ItemsReq) (*product.Response, error) { items = append(items, toProductItem(row)) } - return okResponse(utils.StructToJson(&product.ItemsData{ + return okResponse(&product.ItemsData{ Count: result.Count, Items: items, - })), nil + }), nil } diff --git a/services/product/internal/logic/nameslogic.go b/services/product/internal/logic/nameslogic.go index 2ce916e..05b8717 100644 --- a/services/product/internal/logic/nameslogic.go +++ b/services/product/internal/logic/nameslogic.go @@ -44,5 +44,5 @@ func (l *NamesLogic) Names(_ *product.NamesReq) (*product.Response, error) { Name: row.Name, }) } - return okResponse(utils.StructToJson(items)), nil + return okResponse(items), nil } diff --git a/services/product/internal/logic/numberAddLogic.go b/services/product/internal/logic/numberAddLogic.go index 9f8b3fa..fdf9cb6 100644 --- a/services/product/internal/logic/numberAddLogic.go +++ b/services/product/internal/logic/numberAddLogic.go @@ -7,6 +7,7 @@ import ( "lone-services/pkg/validate" product "lone-services/rpc/product/pb" "lone-services/services/product/internal/dao" + "lone-services/services/product/internal/model" "lone-services/services/product/internal/svc" "lone-services/services/product/validator" @@ -40,10 +41,10 @@ func (l *NumberAddLogic) NumberAdd(in *product.NumberAddReq) (*product.Response, return failResponse(utils.ErrorNoLoginInfo), nil } - if err := changeProductNumber(l.Logger, req.Id, dao.NumberTypeAdd, req.Number); err != nil { + if err := changeProductNumber(l.Logger, model.ProductModel{}.Init(), req.Id, dao.NumberTypeAdd, req.Number); err != nil { return mapNumberErr(err), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } func mapNumberErr(err error) *product.Response { diff --git a/services/product/internal/logic/numberItemsLogic.go b/services/product/internal/logic/numberItemsLogic.go new file mode 100644 index 0000000..2a5dec7 --- /dev/null +++ b/services/product/internal/logic/numberItemsLogic.go @@ -0,0 +1,78 @@ +package logic + +import ( + "context" + "sort" + + "lone-services/pkg/utils" + "lone-services/pkg/validate" + product "lone-services/rpc/product/pb" + "lone-services/services/product/internal/model" + "lone-services/services/product/internal/svc" + "lone-services/services/product/validator" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" + "gorm.io/gorm" +) + +type NumberItemsLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewNumberItemsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NumberItemsLogic { + return &NumberItemsLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *NumberItemsLogic) NumberItems(in *product.NumberItemsReq) (*emptypb.Empty, error) { + var req validator.ProductNumberItemsValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return nil, status.Error(codes.InvalidArgument, msg) + } + if len(in.GetItems()) < 1 { + return nil, status.Error(codes.InvalidArgument, "产品列表不能为空") + } + + items := make([]*product.NumberItem, 0, len(in.GetItems())) + for _, item := range in.GetItems() { + if item == nil { + continue + } + if item.GetId() < 1 { + return nil, status.Error(codes.InvalidArgument, "产品ID必须大于0") + } + if item.GetNumber() < 1 { + return nil, status.Error(codes.InvalidArgument, "数量必须大于0") + } + items = append(items, item) + } + if len(items) < 1 { + return nil, status.Error(codes.InvalidArgument, "产品列表不能为空") + } + + sort.Slice(items, func(i, j int) bool { + return items[i].GetId() < items[j].GetId() + }) + + err := l.svcCtx.DB.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error { + m := model.ProductModel{}.Init().WithTX(tx) + for _, item := range items { + if err := changeProductNumber(l.Logger, m, item.GetId(), req.Type, item.GetNumber()); err != nil { + return err + } + } + return nil + }) + if err != nil { + return nil, err + } + return &emptypb.Empty{}, nil +} diff --git a/services/product/internal/logic/numberLogic.go b/services/product/internal/logic/numberLogic.go index bdc42e8..ae077e4 100644 --- a/services/product/internal/logic/numberLogic.go +++ b/services/product/internal/logic/numberLogic.go @@ -40,18 +40,17 @@ func (l *NumberLogic) Number(in *product.NumberReq) (*emptypb.Empty, error) { return nil, status.Error(codes.InvalidArgument, msg) } - if err := changeProductNumber(l.Logger, req.Id, req.Type, req.Number); err != nil { + if err := changeProductNumber(l.Logger, model.ProductModel{}.Init(), req.Id, req.Type, req.Number); err != nil { return nil, err } return &emptypb.Empty{}, nil } -func changeProductNumber(logger logx.Logger, id int64, typ uint32, number uint32) error { +func changeProductNumber(logger logx.Logger, m model.ProductModel, id int64, typ uint32, number uint32) error { var info dao.NumberInfo w := modelbase.Params{ Eq: map[string]string{"id": strconv.FormatInt(id, 10)}, } - m := model.ProductModel{}.Init() if err := m.GetOne(w, &info); err != nil { logger.Errorf("product number get: %v", err) return status.Error(codes.Internal, utils.Fail.Msg) diff --git a/services/product/internal/logic/response.go b/services/product/internal/logic/response.go index 358fc3c..7e319cf 100644 --- a/services/product/internal/logic/response.go +++ b/services/product/internal/logic/response.go @@ -3,13 +3,16 @@ package logic import ( "lone-services/pkg/utils" product "lone-services/rpc/product/pb" + + jsoniter "github.com/json-iterator/go" ) -func okResponse(data string) *product.Response { +func okResponse(data any) *product.Response { + buf, _ := jsoniter.Marshal(data) return &product.Response{ Code: utils.Ok.Code, Msg: utils.Ok.Msg, - Data: data, + Data: string(buf), } } diff --git a/services/product/internal/logic/sortlogic.go b/services/product/internal/logic/sortlogic.go index 9418471..224cf30 100644 --- a/services/product/internal/logic/sortlogic.go +++ b/services/product/internal/logic/sortlogic.go @@ -63,5 +63,5 @@ func (l *SortLogic) Sort(in *product.SortReq) (*product.Response, error) { return failResponse(utils.Fail), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } diff --git a/services/product/internal/logic/statuslogic.go b/services/product/internal/logic/statuslogic.go index a1a17f8..4b0f18f 100644 --- a/services/product/internal/logic/statuslogic.go +++ b/services/product/internal/logic/statuslogic.go @@ -72,5 +72,5 @@ func (l *StatusLogic) Status(in *product.StatusReq) (*product.Response, error) { return failResponse(utils.Fail), nil } - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } diff --git a/services/product/internal/logic/verifylogic.go b/services/product/internal/logic/verifylogic.go index d9d57bb..ff07d62 100644 --- a/services/product/internal/logic/verifylogic.go +++ b/services/product/internal/logic/verifylogic.go @@ -67,10 +67,10 @@ func (l *VerifyLogic) Verify(in *product.VerifyReq) (*product.Response, error) { items := make([]*product.VerifyItem, 0) if len(rows) == 0 { - return okResponse(utils.StructToJson(&product.VerifyItemsData{ + return okResponse(&product.VerifyItemsData{ Count: result.Count, Items: items, - })), nil + }), nil } ids := make([]string, 0, len(rows)) @@ -142,8 +142,8 @@ func (l *VerifyLogic) Verify(in *product.VerifyReq) (*product.Response, error) { }) } - return okResponse(utils.StructToJson(&product.VerifyItemsData{ + return okResponse(&product.VerifyItemsData{ Count: result.Count, Items: items, - })), nil + }), nil } diff --git a/services/product/internal/logic/verifystatuslogic.go b/services/product/internal/logic/verifystatuslogic.go index b8479d7..b26e77b 100644 --- a/services/product/internal/logic/verifystatuslogic.go +++ b/services/product/internal/logic/verifystatuslogic.go @@ -183,7 +183,7 @@ func (l *VerifyStatusLogic) verifyStatus(expectStatus uint8, in *product.VerifyS Reason: reason, }) - return okResponse(utils.StringEmpty), nil + return okResponse(nil), nil } func isJSONError(err error) bool { diff --git a/services/product/internal/model/product_model.go b/services/product/internal/model/product_model.go index ba50dd4..63d3483 100644 --- a/services/product/internal/model/product_model.go +++ b/services/product/internal/model/product_model.go @@ -20,19 +20,24 @@ func (m ProductModel) Init() ProductModel { return m } +func (m ProductModel) WithTX(tx *gorm.DB) ProductModel { + m.Base = m.Base.WithTX(tx) + return m +} + func (m ProductModel) Create(data *dao.Create) error { return m.Base.Create(data) } func (m ProductModel) IncrNumber(id int64, n uint32) (int64, error) { - ret := modelbase.DB().Table(m.TableName()). + ret := m.Session(). Where("id = ?", id). Update("number", gorm.Expr("number + ?", n)) return ret.RowsAffected, ret.Error } func (m ProductModel) DecrNumber(id int64, n uint32) (int64, error) { - ret := modelbase.DB().Table(m.TableName()). + ret := m.Session(). Where("id = ? AND number >= ?", id, n). Update("number", gorm.Expr("number - ?", n)) return ret.RowsAffected, ret.Error diff --git a/services/product/internal/server/productserver.go b/services/product/internal/server/productserver.go index eae7bcc..be62e49 100644 --- a/services/product/internal/server/productserver.go +++ b/services/product/internal/server/productserver.go @@ -102,6 +102,12 @@ func (s *ProductServer) Number(ctx context.Context, in *product.NumberReq) (*emp return l.Number(in) } +// 批量增减库存(服务内按 id 排序后在同一事务中执行,防死锁) +func (s *ProductServer) NumberItems(ctx context.Context, in *product.NumberItemsReq) (*emptypb.Empty, error) { + l := logic.NewNumberItemsLogic(ctx, s.svcCtx) + return l.NumberItems(in) +} + func (s *ProductServer) InfoById(ctx context.Context, in *product.InfoByIdReq) (*product.Item, error) { l := logic.NewInfoByIdLogic(ctx, s.svcCtx) return l.InfoById(in) diff --git a/services/product/productClient/product.go b/services/product/productClient/product.go index 4c1ac92..9a52541 100644 --- a/services/product/productClient/product.go +++ b/services/product/productClient/product.go @@ -31,6 +31,8 @@ type ( NameItem = product.NameItem NamesReq = product.NamesReq NumberAddReq = product.NumberAddReq + NumberItem = product.NumberItem + NumberItemsReq = product.NumberItemsReq NumberReq = product.NumberReq Response = product.Response SortReq = product.SortReq @@ -64,6 +66,8 @@ type ( EditApplyPass(ctx context.Context, in *EditApplyPassReq, opts ...grpc.CallOption) (*Response, error) // 增减库存 Number(ctx context.Context, in *NumberReq, opts ...grpc.CallOption) (*emptypb.Empty, error) + // 批量增减库存(服务内按 id 排序后在同一事务中执行,防死锁) + NumberItems(ctx context.Context, in *NumberItemsReq, opts ...grpc.CallOption) (*emptypb.Empty, error) InfoById(ctx context.Context, in *InfoByIdReq, opts ...grpc.CallOption) (*Item, error) ItemsByIds(ctx context.Context, in *ItemsByIdsReq, opts ...grpc.CallOption) (*ItemsByIdsData, error) // 增加库存 @@ -159,6 +163,12 @@ func (m *defaultProduct) Number(ctx context.Context, in *NumberReq, opts ...grpc return client.Number(ctx, in, opts...) } +// 批量增减库存(服务内按 id 排序后在同一事务中执行,防死锁) +func (m *defaultProduct) NumberItems(ctx context.Context, in *NumberItemsReq, opts ...grpc.CallOption) (*emptypb.Empty, error) { + client := product.NewProductClient(m.cli.Conn()) + return client.NumberItems(ctx, in, opts...) +} + func (m *defaultProduct) InfoById(ctx context.Context, in *InfoByIdReq, opts ...grpc.CallOption) (*Item, error) { client := product.NewProductClient(m.cli.Conn()) return client.InfoById(ctx, in, opts...) diff --git a/services/product/validator/validator.go b/services/product/validator/validator.go index e4bdc8c..1fd3c3c 100644 --- a/services/product/validator/validator.go +++ b/services/product/validator/validator.go @@ -252,6 +252,17 @@ func (p ProductNumberAddValidator) GetMessage() validate.ValidatorMessages { } } +type ProductNumberItemsValidator struct { + Type uint32 `validate:"required,oneof=1 2"` +} + +func (p ProductNumberItemsValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Type.required": "类型不能为空", + "Type.oneof": "类型不对", + } +} + type ProductItemsByIdsValidator struct { Ids []int64 `validate:"required,min=1"` } diff --git a/services/sale/.gitignore b/services/sale/.gitignore new file mode 100644 index 0000000..d05f1c7 --- /dev/null +++ b/services/sale/.gitignore @@ -0,0 +1,2 @@ +services/sale/logs/ +services/sale/run.toml diff --git a/services/sale/Dockerfile b/services/sale/Dockerfile new file mode 100644 index 0000000..fccddc7 --- /dev/null +++ b/services/sale/Dockerfile @@ -0,0 +1,39 @@ +FROM golang:1.26.5-alpine AS builder + +WORKDIR /src + +ENV GOPROXY=https://goproxy.cn,direct \ + CGO_ENABLED=0 \ + GOOS=linux \ + GOARCH=amd64 + +COPY pkg ./pkg +COPY go.mod go.sum ./ + +RUN --mount=type=cache,target=/go/pkg/mod \ + go mod download + +COPY rpc/ ./rpc +COPY services/sale/ ./services/sale/ + +WORKDIR /src/services/sale + +RUN --mount=type=cache,target=/go/pkg/mod \ + --mount=type=cache,target=/root/.cache/go-build \ + go build -ldflags="-s -w" -o /out/main ./ + +FROM alpine:3.22 + +WORKDIR /app + +ENV TZ=Asia/Shanghai + +RUN apk add --no-cache tzdata \ + && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +COPY --from=builder /out/main . + +EXPOSE 10700 + +CMD ["./main", "-f", "etc/sale.yaml"] diff --git a/services/sale/etc/sale.yaml b/services/sale/etc/sale.yaml new file mode 100644 index 0000000..98c1249 --- /dev/null +++ b/services/sale/etc/sale.yaml @@ -0,0 +1,7 @@ +Nacos: + Hosts: + - rnacos:8848 + NamespaceId: test + Group: LONE_SERVICES + RegisterIP: sale + ConfigID: sale diff --git a/services/sale/internal/config/config.go b/services/sale/internal/config/config.go new file mode 100644 index 0000000..a1979dd --- /dev/null +++ b/services/sale/internal/config/config.go @@ -0,0 +1,13 @@ +package config + +type Config struct { + Nacos NacosConf +} + +type NacosConf struct { + Hosts []string + NamespaceId string `json:",optional"` + Group string `json:",optional"` + RegisterIP string `json:",optional"` + ConfigID string `json:",optional"` +} diff --git a/services/sale/internal/dao/sale.go b/services/sale/internal/dao/sale.go new file mode 100644 index 0000000..db8bbfc --- /dev/null +++ b/services/sale/internal/dao/sale.go @@ -0,0 +1,131 @@ +package dao + +import ( + "database/sql/driver" + "encoding/json" + "fmt" + + "lone-services/pkg/utils" +) + +const ( + SaleTypeStaff uint8 = 1 // 销售人员 + SaleTypeAgentCorp uint8 = 2 // 销售商(法人) + SaleTypeAgentPerson uint8 = 3 // 销售商(个人) + + SaleStatusPending uint8 = 9 // 待处理 + SaleStatusApproved uint8 = 1 // 已通过 + SaleStatusRejected uint8 = 2 // 未通过 + SaleStatusDisabled uint8 = 3 // 禁用 +) + +type RegionNames struct { + Province string `json:"province"` + City string `json:"city"` + District string `json:"district"` +} + +func (r RegionNames) Value() (driver.Value, error) { + buf, err := json.Marshal(r) + if err != nil { + return nil, err + } + return string(buf), nil +} + +func (r *RegionNames) Scan(value interface{}) error { + if value == nil { + *r = RegionNames{} + return nil + } + var raw []byte + switch v := value.(type) { + case []byte: + raw = v + case string: + raw = []byte(v) + default: + return fmt.Errorf("unsupported region type: %T", value) + } + if len(raw) == 0 { + *r = RegionNames{} + return nil + } + return json.Unmarshal(raw, r) +} + +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"` +} + +type SaleInfo struct { + Id int64 `gorm:"column:id" 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"` + 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"` + CreateTime utils.CustomTime `gorm:"column:create_time" json:"create_time"` + UpdateTime utils.CustomTime `gorm:"column:update_time" json:"update_time"` + OriginMobile string `gorm:"-" json:"origin_mobile"` +} + +type SaleStatusUpdate struct { + Id int64 `gorm:"column:id;primaryKey" json:"id"` + Name string `gorm:"column:name" json:"name"` + Status uint8 `gorm:"column:status" json:"status"` + 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"` +} + +type SaleNameItem struct { + Id int64 `gorm:"column:id" json:"id"` + Mobile string `gorm:"column:mobile" json:"mobile"` + Name string `gorm:"column:name" json:"name"` +} + +type SaleTypeOption struct { + Value uint8 `json:"value"` + Label string `json:"label"` +} diff --git a/services/sale/internal/dao/sale_group.go b/services/sale/internal/dao/sale_group.go new file mode 100644 index 0000000..05f8727 --- /dev/null +++ b/services/sale/internal/dao/sale_group.go @@ -0,0 +1,22 @@ +package dao + +import "lone-services/pkg/utils" + +type SaleGroup struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + Name string `gorm:"column:name" json:"name"` + CreatedAt utils.CustomTime `gorm:"column:created_at" json:"created_at"` + UpdatedAt utils.CustomTime `gorm:"column:updated_at" json:"updated_at"` +} + +type SaleGroupCreate struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` + Name string `gorm:"column:name" json:"name"` + CreatedAt utils.CustomTime `gorm:"column:created_at" json:"created_at"` + UpdatedAt utils.CustomTime `gorm:"column:updated_at" json:"updated_at"` +} + +type SaleGroupNameItem struct { + Id int64 `json:"id"` + Name string `json:"name"` +} diff --git a/services/sale/internal/logic/createLogic.go b/services/sale/internal/logic/createLogic.go new file mode 100644 index 0000000..394a772 --- /dev/null +++ b/services/sale/internal/logic/createLogic.go @@ -0,0 +1,91 @@ +package logic + +import ( + "context" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/internal/svc" + "lone-services/services/sale/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type CreateLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateLogic { + return &CreateLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *CreateLogic) Create(in *sale.CreateReq) (*sale.Response, error) { + var req validator.CreateValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + if msg := validateSaleTypeRules(req.Type, req.Account, req.BusinessLicense); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + encryptMobile, err := utils.EncryptPhone(req.Mobile) + if err != nil { + l.Errorf("encrypt mobile: %v", err) + 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) + return failResponse(utils.Fail), nil + } + if existing.Id > utils.NumberZero { + return failResponse(utils.ErrorDataIsExist), nil + } + + data := dao.SaleCreate{ + SaleId: req.SaleId, + Mobile: encryptMobile, + Name: req.Name, + IdCardFront: req.IdCardFront, + IdCardBack: req.IdCardBack, + BusinessLicense: req.BusinessLicense, + Region: buildRegion(req.RegionProvince, req.RegionCity, req.RegionDistrict), + ProvinceId: req.ProvinceId, + CityId: req.CityId, + DistrictId: req.DistrictId, + TerritoryId: req.TerritoryId, + TerritoryName: req.TerritoryName, + GroupId: req.GroupId, + Address: req.Address, + Status: dao.SaleStatusApproved, + Account: req.Account, + Type: uint8(req.Type), + Sex: uint8(req.Sex), + BirthDate: req.BirthDate, + AdminId: adminInfo.ID, + AdminName: adminInfo.Name, + } + if err := m.Create(&data); err != nil { + l.Errorf("sale create: %v", err) + return failResponse(utils.Fail), nil + } + + return okResponse(nil), nil +} diff --git a/services/sale/internal/logic/editLogic.go b/services/sale/internal/logic/editLogic.go new file mode 100644 index 0000000..de63da2 --- /dev/null +++ b/services/sale/internal/logic/editLogic.go @@ -0,0 +1,97 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/internal/svc" + "lone-services/services/sale/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type EditLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewEditLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditLogic { + return &EditLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *EditLogic) Edit(in *sale.EditReq) (*sale.Response, error) { + var req validator.EditValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + if msg := validateSaleTypeRules(req.Type, req.Account, req.BusinessLicense); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + w := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}} + m := model.SaleModel{}.Init() + var info dao.SaleCreate + if err := m.GetOne(w, &info); err != nil || info.Id < utils.NumberOne { + 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 { + 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) + return failResponse(utils.Fail), nil + } + if check.Id > utils.NumberZero && check.Id != req.Id { + return failResponse(utils.ErrorDataIsExist), nil + } + } + + info.SaleId = req.SaleId + info.Mobile = encryptMobile + info.Name = req.Name + info.IdCardFront = req.IdCardFront + info.IdCardBack = req.IdCardBack + info.BusinessLicense = req.BusinessLicense + info.Region = buildRegion(req.RegionProvince, req.RegionCity, req.RegionDistrict) + info.ProvinceId = req.ProvinceId + info.CityId = req.CityId + info.DistrictId = req.DistrictId + info.TerritoryId = req.TerritoryId + info.TerritoryName = req.TerritoryName + info.GroupId = req.GroupId + info.Address = req.Address + info.Type = uint8(req.Type) + info.Sex = uint8(req.Sex) + info.BirthDate = req.BirthDate + info.Account = req.Account + info.AdminId = adminInfo.ID + info.AdminName = adminInfo.Name + + if _, err := m.Edit(w, &info); err != nil { + l.Errorf("sale edit: %v", err) + return failResponse(utils.Fail), nil + } + + return okStringResponse(utils.StringEmpty), nil +} diff --git a/services/sale/internal/logic/groupCreateLogic.go b/services/sale/internal/logic/groupCreateLogic.go new file mode 100644 index 0000000..99463eb --- /dev/null +++ b/services/sale/internal/logic/groupCreateLogic.go @@ -0,0 +1,65 @@ +package logic + +import ( + "context" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/internal/svc" + "lone-services/services/sale/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GroupCreateLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGroupCreateLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GroupCreateLogic { + return &GroupCreateLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *GroupCreateLogic) GroupCreate(in *sale.GroupCreateReq) (*sale.Response, error) { + var req validator.GroupCreateValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + m := model.SaleGroupModel{}.Init() + var existing dao.SaleGroup + if err := m.GetOne(modelbase.Params{Eq: map[string]string{"name": req.Name}}, &existing); err != nil { + l.Errorf("group create check: %v", err) + return failResponse(utils.Fail), nil + } + if existing.Id > utils.NumberZero { + return failResponse(utils.ErrorDataIsExist), nil + } + + now := utils.Now() + data := dao.SaleGroupCreate{ + Name: req.Name, + CreatedAt: now, + UpdatedAt: now, + } + if err := m.Create(&data); err != nil { + l.Errorf("group create: %v", err) + return failResponse(utils.Fail), nil + } + + return okResponse(nil), nil +} diff --git a/services/sale/internal/logic/groupItemsLogic.go b/services/sale/internal/logic/groupItemsLogic.go new file mode 100644 index 0000000..7cb0356 --- /dev/null +++ b/services/sale/internal/logic/groupItemsLogic.go @@ -0,0 +1,68 @@ +package logic + +import ( + "context" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/internal/svc" + "lone-services/services/sale/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GroupItemsLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGroupItemsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GroupItemsLogic { + return &GroupItemsLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *GroupItemsLogic) GroupItems(in *sale.GroupItemsReq) (*sale.Response, error) { + var req validator.GroupItemsValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + page := int(req.Page) + size := int(req.PageSize) + if page < modelbase.DefaultPage { + page = modelbase.DefaultPage + } + if size < modelbase.DefaultPage { + size = modelbase.DefaultSize + } + + w := modelbase.Params{ + Page: page, + Size: size, + Order: "id desc", + Like: map[string]string{}, + } + if req.Name != utils.StringEmpty { + w.Like["name LIKE ?"] = "%" + req.Name + "%" + } + + var list []dao.SaleGroup + result, err := model.SaleGroupModel{}.Init().Page(w, &list) + if err != nil { + l.Errorf("group items: %v", err) + return failResponse(utils.Fail), nil + } + + return okResponse(map[string]any{ + "count": result.Count, + "items": list, + }), nil +} diff --git a/services/sale/internal/logic/groupNamesLogic.go b/services/sale/internal/logic/groupNamesLogic.go new file mode 100644 index 0000000..352ac01 --- /dev/null +++ b/services/sale/internal/logic/groupNamesLogic.go @@ -0,0 +1,41 @@ +package logic + +import ( + "context" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/internal/svc" + + sale "lone-services/rpc/sale/pb" + + "github.com/zeromicro/go-zero/core/logx" +) + +type GroupNamesLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewGroupNamesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GroupNamesLogic { + return &GroupNamesLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *GroupNamesLogic) GroupNames(_ *sale.GroupEmptyReq) (*sale.Response, error) { + var list []dao.SaleGroupNameItem + if err := (model.SaleGroupModel{}.Init().Items(modelbase.Params{Order: "id ASC"}, &list)); err != nil { + l.Errorf("group names: %v", err) + return failResponse(utils.Fail), nil + } + if list == nil { + list = []dao.SaleGroupNameItem{} + } + return okResponse(list), nil +} diff --git a/services/sale/internal/logic/helper.go b/services/sale/internal/logic/helper.go new file mode 100644 index 0000000..ea224af --- /dev/null +++ b/services/sale/internal/logic/helper.go @@ -0,0 +1,94 @@ +package logic + +import ( + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/validator" +) + +func saleTypeOptions() []dao.SaleTypeOption { + return []dao.SaleTypeOption{ + {Value: dao.SaleTypeStaff, Label: "销售人员"}, + {Value: dao.SaleTypeAgentCorp, Label: "销售商(法人)"}, + {Value: dao.SaleTypeAgentPerson, Label: "销售商(个人)"}, + } +} + +func buildRegion(province, city, district string) dao.RegionNames { + return dao.RegionNames{ + Province: province, + City: city, + District: district, + } +} + +func querySaleNames(req validator.NamesValidator) ([]dao.SaleNameItem, error) { + w := modelbase.Params{ + Eq: map[string]string{"status": strconv.Itoa(int(dao.SaleStatusApproved))}, + Order: "id desc", + Like: map[string]string{}, + } + if req.Type > utils.NumberZero { + w.Eq["type"] = strconv.Itoa(int(req.Type)) + } + if req.Level == utils.NumberOne { + w.Eq["sale_id"] = strconv.Itoa(utils.NumberZero) + } + if req.Name != utils.StringEmpty { + w.Like["name LIKE ?"] = "%" + req.Name + "%" + } + + var items []dao.SaleNameItem + m := model.SaleModel{}.Init() + if err := m.Items(w, &items); err != nil { + return nil, err + } + if items == nil { + items = []dao.SaleNameItem{} + } + maskSaleNameItems(items) + return items, nil +} + +func maskSaleMobile(info *dao.SaleInfo) { + if info == nil { + return + } + info.OriginMobile = info.Mobile + mobile, err := utils.DecryptPhone(info.Mobile) + if err != nil { + return + } + info.Mobile = utils.DecryptPhoneReplace(mobile) +} + +func maskSaleNameItems(items []dao.SaleNameItem) { + for i := range items { + mobile, err := utils.DecryptPhone(items[i].Mobile) + if err != nil { + continue + } + items[i].Mobile = utils.DecryptPhoneReplace(mobile) + } +} + +func validateSaleTypeRules(saleType uint32, account, businessLicense string) string { + switch uint8(saleType) { + case dao.SaleTypeAgentCorp: + if account == utils.StringEmpty { + return "缺少账户信息" + } + if businessLicense == utils.StringEmpty { + return "缺少营业执照" + } + case dao.SaleTypeAgentPerson: + if account == utils.StringEmpty { + return "缺少账户信息" + } + } + return utils.StringEmpty +} diff --git a/services/sale/internal/logic/infoLogic.go b/services/sale/internal/logic/infoLogic.go new file mode 100644 index 0000000..aa46ae5 --- /dev/null +++ b/services/sale/internal/logic/infoLogic.go @@ -0,0 +1,51 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/internal/svc" + "lone-services/services/sale/validator" + + "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 *sale.InfoReq) (*sale.Response, error) { + var req validator.InfoValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + var info dao.SaleInfo + if err := (model.SaleModel{}.Init().GetOne(modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}, + }, &info)); err != nil { + l.Errorf("sale info: %v", err) + return failResponse(utils.Fail), nil + } + if info.Id < utils.NumberOne { + return failResponse(utils.ErrorNotFund), nil + } + maskSaleMobile(&info) + return okResponse(info), nil +} diff --git a/services/sale/internal/logic/itemsLogic.go b/services/sale/internal/logic/itemsLogic.go new file mode 100644 index 0000000..09b18e0 --- /dev/null +++ b/services/sale/internal/logic/itemsLogic.go @@ -0,0 +1,89 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/internal/svc" + "lone-services/services/sale/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type ItemsLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewItemsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ItemsLogic { + return &ItemsLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *ItemsLogic) Items(in *sale.ItemsReq) (*sale.Response, error) { + var req validator.ItemsValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + page := int(req.Page) + size := int(req.PageSize) + if page < modelbase.DefaultPage { + page = modelbase.DefaultPage + } + if size < modelbase.DefaultPage { + size = modelbase.DefaultSize + } + + w := modelbase.Params{ + Eq: map[string]string{}, + Page: page, + Size: size, + Order: "id desc", + Like: map[string]string{}, + In: map[string][]string{ + "status": { + strconv.Itoa(int(dao.SaleStatusApproved)), + strconv.Itoa(int(dao.SaleStatusDisabled)), + }, + }, + } + if req.Type > utils.NumberZero { + w.Eq["type"] = strconv.Itoa(int(req.Type)) + } + if req.SaleId > utils.NumberZero { + w.Eq["sale_id"] = strconv.FormatInt(req.SaleId, 10) + } + if req.Status > utils.NumberZero { + delete(w.In, "status") + w.Eq["status"] = strconv.Itoa(int(req.Status)) + } + if req.Name != utils.StringEmpty { + w.Like["name LIKE ?"] = "%" + req.Name + "%" + } + + var list []dao.SaleInfo + result, err := model.SaleModel{}.Init().Page(w, &list) + if err != nil { + l.Errorf("sale items: %v", err) + return failResponse(utils.Fail), nil + } + for i := range list { + maskSaleMobile(&list[i]) + } + + return okResponse(map[string]any{ + "count": result.Count, + "items": list, + }), nil +} diff --git a/services/sale/internal/logic/namesInternalLogic.go b/services/sale/internal/logic/namesInternalLogic.go new file mode 100644 index 0000000..8aab260 --- /dev/null +++ b/services/sale/internal/logic/namesInternalLogic.go @@ -0,0 +1,57 @@ +package logic + +import ( + "context" + + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/dao" + "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 NamesInternalLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewNamesInternalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NamesInternalLogic { + return &NamesInternalLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *NamesInternalLogic) NamesInternal(in *sale.NamesReq) (*sale.NamesData, error) { + var req validator.NamesValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return nil, status.Error(codes.InvalidArgument, msg) + } + + items, err := querySaleNames(req) + if err != nil { + l.Errorf("sale NamesInternal: %v", err) + return nil, status.Error(codes.Internal, utils.Fail.Msg) + } + + return &sale.NamesData{Items: toSaleNameItems(items)}, nil +} + +func toSaleNameItems(items []dao.SaleNameItem) []*sale.NameItem { + result := make([]*sale.NameItem, 0, len(items)) + for _, item := range items { + result = append(result, &sale.NameItem{ + Id: item.Id, + Mobile: item.Mobile, + Name: item.Name, + }) + } + return result +} diff --git a/services/sale/internal/logic/namesLogic.go b/services/sale/internal/logic/namesLogic.go new file mode 100644 index 0000000..304f675 --- /dev/null +++ b/services/sale/internal/logic/namesLogic.go @@ -0,0 +1,41 @@ +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" +) + +type NamesLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewNamesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NamesLogic { + return &NamesLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *NamesLogic) Names(in *sale.NamesReq) (*sale.Response, error) { + var req validator.NamesValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + items, err := querySaleNames(req) + if err != nil { + l.Errorf("sale names: %v", err) + return failResponse(utils.Fail), nil + } + return okResponse(items), nil +} diff --git a/services/sale/internal/logic/response.go b/services/sale/internal/logic/response.go new file mode 100644 index 0000000..3d75285 --- /dev/null +++ b/services/sale/internal/logic/response.go @@ -0,0 +1,39 @@ +package logic + +import ( + "lone-services/pkg/utils" + sale "lone-services/rpc/sale/pb" + + jsoniter "github.com/json-iterator/go" +) + +func okResponse(data any) *sale.Response { + buf, _ := jsoniter.Marshal(data) + return &sale.Response{ + Code: utils.Ok.Code, + Msg: utils.Ok.Msg, + Data: string(buf), + } +} + +func okStringResponse(data string) *sale.Response { + return &sale.Response{ + Code: utils.Ok.Code, + Msg: utils.Ok.Msg, + Data: data, + } +} + +func failResponse(status utils.Status) *sale.Response { + return &sale.Response{ + Code: status.Code, + Msg: status.Msg, + } +} + +func outResponse(status utils.Status, msg string) *sale.Response { + return &sale.Response{ + Code: status.Code, + Msg: msg, + } +} diff --git a/services/sale/internal/logic/statusLogic.go b/services/sale/internal/logic/statusLogic.go new file mode 100644 index 0000000..50158c1 --- /dev/null +++ b/services/sale/internal/logic/statusLogic.go @@ -0,0 +1,74 @@ +package logic + +import ( + "context" + "strconv" + + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/dao" + "lone-services/services/sale/internal/model" + "lone-services/services/sale/internal/svc" + "lone-services/services/sale/validator" + + "github.com/zeromicro/go-zero/core/logx" +) + +type StatusLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StatusLogic { + return &StatusLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *StatusLogic) Status(in *sale.StatusReq) (*sale.Response, error) { + var req validator.StatusValidator + if msg := validate.ValidateFromProto(in, &req); msg != utils.StringEmpty { + return outResponse(utils.ErrorParams, msg), nil + } + + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return failResponse(utils.ErrorNoLoginInfo), nil + } + + 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() + if err := m.GetOne(w, &info); err != nil { + l.Errorf("sale status get: %v", err) + return failResponse(utils.Fail), nil + } + if info.Id < utils.NumberOne { + return failResponse(utils.ErrorNotFund), nil + } + + info.Status = uint8(req.Status) + info.Reason = req.Reason + info.AdminId = adminInfo.ID + info.AdminName = adminInfo.Name + + if _, err := m.Edit(modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(req.Id, 10)}}, &info); err != nil { + l.Errorf("sale status edit: %v", err) + return failResponse(utils.Fail), nil + } + + return okStringResponse(utils.StringEmpty), nil +} diff --git a/services/sale/internal/logic/typesLogic.go b/services/sale/internal/logic/typesLogic.go new file mode 100644 index 0000000..c8d3f85 --- /dev/null +++ b/services/sale/internal/logic/typesLogic.go @@ -0,0 +1,28 @@ +package logic + +import ( + "context" + + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/svc" + + "github.com/zeromicro/go-zero/core/logx" +) + +type TypesLogic struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func NewTypesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *TypesLogic { + return &TypesLogic{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} + +func (l *TypesLogic) Types(_ *sale.GroupEmptyReq) (*sale.Response, error) { + return okResponse(saleTypeOptions()), nil +} diff --git a/services/sale/internal/model/sale_group_model.go b/services/sale/internal/model/sale_group_model.go new file mode 100644 index 0000000..f7a5399 --- /dev/null +++ b/services/sale/internal/model/sale_group_model.go @@ -0,0 +1,23 @@ +package model + +import ( + "lone-services/pkg/modelbase" + "lone-services/services/sale/internal/dao" +) + +type SaleGroupModel struct { + modelbase.Base +} + +func (m SaleGroupModel) TableName() string { + return modelbase.Prefix() + "group" +} + +func (m SaleGroupModel) Init() SaleGroupModel { + m.Table = m.TableName() + return m +} + +func (m SaleGroupModel) Create(data *dao.SaleGroupCreate) error { + return m.Base.Create(data) +} diff --git a/services/sale/internal/model/sale_model.go b/services/sale/internal/model/sale_model.go new file mode 100644 index 0000000..e33dd69 --- /dev/null +++ b/services/sale/internal/model/sale_model.go @@ -0,0 +1,23 @@ +package model + +import ( + "lone-services/pkg/modelbase" + "lone-services/services/sale/internal/dao" +) + +type SaleModel struct { + modelbase.Base +} + +func (m SaleModel) TableName() string { + return modelbase.Prefix() + "sales" +} + +func (m SaleModel) Init() SaleModel { + m.Table = m.TableName() + return m +} + +func (m SaleModel) Create(data *dao.SaleCreate) error { + return m.Base.Create(data) +} diff --git a/services/sale/internal/server/saleServer.go b/services/sale/internal/server/saleServer.go new file mode 100644 index 0000000..2e1b92d --- /dev/null +++ b/services/sale/internal/server/saleServer.go @@ -0,0 +1,81 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.10.1 +// Source: sale.proto + +package server + +import ( + "context" + + "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/logic" + "lone-services/services/sale/internal/svc" +) + +type SaleServer struct { + svcCtx *svc.ServiceContext + sale.UnimplementedSaleServer +} + +func NewSaleServer(svcCtx *svc.ServiceContext) *SaleServer { + return &SaleServer{ + svcCtx: svcCtx, + } +} + +// 销售分组 +func (s *SaleServer) GroupItems(ctx context.Context, in *sale.GroupItemsReq) (*sale.Response, error) { + l := logic.NewGroupItemsLogic(ctx, s.svcCtx) + return l.GroupItems(in) +} + +func (s *SaleServer) GroupCreate(ctx context.Context, in *sale.GroupCreateReq) (*sale.Response, error) { + l := logic.NewGroupCreateLogic(ctx, s.svcCtx) + return l.GroupCreate(in) +} + +func (s *SaleServer) GroupNames(ctx context.Context, in *sale.GroupEmptyReq) (*sale.Response, error) { + l := logic.NewGroupNamesLogic(ctx, s.svcCtx) + return l.GroupNames(in) +} + +// 销售管理 +func (s *SaleServer) Types(ctx context.Context, in *sale.GroupEmptyReq) (*sale.Response, error) { + l := logic.NewTypesLogic(ctx, s.svcCtx) + return l.Types(in) +} + +func (s *SaleServer) Names(ctx context.Context, in *sale.NamesReq) (*sale.Response, error) { + l := logic.NewNamesLogic(ctx, s.svcCtx) + return l.Names(in) +} + +func (s *SaleServer) NamesInternal(ctx context.Context, in *sale.NamesReq) (*sale.NamesData, error) { + l := logic.NewNamesInternalLogic(ctx, s.svcCtx) + return l.NamesInternal(in) +} + +func (s *SaleServer) Create(ctx context.Context, in *sale.CreateReq) (*sale.Response, error) { + l := logic.NewCreateLogic(ctx, s.svcCtx) + return l.Create(in) +} + +func (s *SaleServer) Edit(ctx context.Context, in *sale.EditReq) (*sale.Response, error) { + l := logic.NewEditLogic(ctx, s.svcCtx) + return l.Edit(in) +} + +func (s *SaleServer) Info(ctx context.Context, in *sale.InfoReq) (*sale.Response, error) { + l := logic.NewInfoLogic(ctx, s.svcCtx) + return l.Info(in) +} + +func (s *SaleServer) Items(ctx context.Context, in *sale.ItemsReq) (*sale.Response, error) { + l := logic.NewItemsLogic(ctx, s.svcCtx) + return l.Items(in) +} + +func (s *SaleServer) Status(ctx context.Context, in *sale.StatusReq) (*sale.Response, error) { + l := logic.NewStatusLogic(ctx, s.svcCtx) + return l.Status(in) +} diff --git a/services/sale/internal/svc/serviceContext.go b/services/sale/internal/svc/serviceContext.go new file mode 100644 index 0000000..5985725 --- /dev/null +++ b/services/sale/internal/svc/serviceContext.go @@ -0,0 +1,22 @@ +package svc + +import ( + "lone-services/pkg/utils" + "lone-services/services/sale/internal/config" + + "gorm.io/gorm" +) + +type ServiceContext struct { + Config config.Config + DB *gorm.DB + Prefix string +} + +func NewServiceContext(c config.Config, db *gorm.DB) *ServiceContext { + return &ServiceContext{ + Config: c, + DB: db, + Prefix: utils.GetConfigString("mysql.prefix"), + } +} diff --git a/services/sale/run.toml b/services/sale/run.toml new file mode 100644 index 0000000..de652ef --- /dev/null +++ b/services/sale/run.toml @@ -0,0 +1,55 @@ +[base] + login_out_time=43200 #api接口超时时间分 + login_refresh_out_time=83200 + name = "sale-service" + listenOn = "0.0.0.0:10300" + mode = "dev" +[log] + path = "logs" + serviceName = "sale-service" + mode = "file" + encoding = "plain" + level = "info" + keepDays = 7 + maxSize = 50 + maxBackups = 5 + compress = false + +[oss] + accessKeyId = "LTAI5t7U8KvxSiPE5auwQUuu" + accessKeySecret = "xjfgbQQRpL4TcIspNuClg6bYADa3pk" + roleArn = "acs:ram::1663896742753915:role/oss-upload" + roleSessionName = "oss-upload" + region = "oss-cn-hangzhou" + bucketName = "lone-images" + endpoint = "https://oss-accelerate.aliyuncs.com" + host = "https://images.ailuowan.com" + dir = "upload/" + expireSeconds = 3600 + +[mysql] + host = '39.106.171.204' + port = 33066 + user = 'root' + password = 'MOLXRZNOU4Y4' + database = 'dms-sale' + charset = 'utf8mb4' + prefix = '' + debug = true +[mysql_read] + host = '39.106.171.204' + port = 33066 + user = 'root' + password = 'MOLXRZNOU4Y4' + database = 'dms-sale' + charset = 'utf8mb4' + prefix = '' + +[redis] + host = '39.106.171.204' + password = 'lLMLcuPpzSj' + port = 6379 + db = 0 + +[encrypt] + data_key = "u2t9T3luZtoRfhBstkFN6TiIMW38BA8a" \ No newline at end of file diff --git a/services/sale/sale.go b/services/sale/sale.go new file mode 100644 index 0000000..60e4165 --- /dev/null +++ b/services/sale/sale.go @@ -0,0 +1,150 @@ +package main + +import ( + "flag" + "lone-services/pkg/discovery" + "lone-services/pkg/modelbase" + "lone-services/pkg/mysql" + "lone-services/pkg/redis" + "lone-services/pkg/utils" + "lone-services/pkg/validate" + sale "lone-services/rpc/sale/pb" + "lone-services/services/sale/internal/config" + "lone-services/services/sale/internal/server" + "lone-services/services/sale/internal/svc" + "net" + "os" + "strconv" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var configFile = flag.String("f", "etc/sale.yaml", "the config file") + +func main() { + flag.Parse() + var c config.Config + conf.MustLoad(*configFile, &c) + + nacosParam := utils.NacosConfig{ + Hosts: c.Nacos.Hosts, + NamespaceId: c.Nacos.NamespaceId, + Group: c.Nacos.Group, + ConfigID: c.Nacos.ConfigID, + } + utils.InitConfig(nacosParam) + + logConf := logx.LogConf{ + ServiceName: utils.GetConfigString("log.serviceName"), + Mode: utils.GetConfigString("log.mode"), + Encoding: utils.GetConfigString("log.encoding"), + Level: utils.GetConfigString("log.level"), + Path: utils.GetConfigString("log.path"), + KeepDays: utils.GetConfigInt("log.keepDays"), + MaxSize: utils.GetConfigInt("log.maxSize"), + MaxBackups: utils.GetConfigInt("log.maxBackups"), + Compress: utils.GetConfigBool("log.compress"), + } + logx.SetUp(logConf) + logx.AddWriter(logx.NewWriter(os.Stdout)) + + listenOn := utils.GetConfigString("base.listenOn") + mode := utils.GetConfigString("base.mode") + serviceName := utils.GetConfigString("base.name") + + if err := discovery.Init(discovery.Config{ + Hosts: c.Nacos.Hosts, + NamespaceId: c.Nacos.NamespaceId, + Group: c.Nacos.Group, + }); err != nil { + logx.Errorf("nacos init: %v", err) + os.Exit(1) + } + + port, err := listenPort(listenOn) + if err != nil { + logx.Errorf("parse ListenOn: %v", err) + os.Exit(1) + } + + if err := discovery.Register(discovery.Instance{ + ServiceName: serviceName, + IP: c.Nacos.RegisterIP, + Port: port, + Group: c.Nacos.Group, + }); err != nil { + logx.Errorf("nacos register: %v", err) + os.Exit(1) + } + logx.Infof("服务注册成功: %s:%d", c.Nacos.RegisterIP, port) + + defer func() { + if err := discovery.Deregister(); err != nil { + logx.Errorf("nacos deregister: %v", err) + } + }() + + db, err := mysql.New(mysql.Config{ + Host: utils.GetConfigString("mysql.host"), + Port: utils.GetConfigInt("mysql.port"), + User: utils.GetConfigString("mysql.user"), + Password: utils.GetConfigString("mysql.password"), + Database: utils.GetConfigString("mysql.database"), + Charset: utils.GetConfigString("mysql.charset"), + Prefix: utils.GetConfigString("mysql.prefix"), + ReadHost: utils.GetConfigString("mysql_read.host"), + ReadPort: utils.GetConfigInt("mysql_read.port"), + ReadUser: utils.GetConfigString("mysql_read.user"), + ReadPassword: utils.GetConfigString("mysql_read.password"), + ReadDatabase: utils.GetConfigString("mysql_read.database"), + }) + if err != nil { + logx.Errorf("mysql init: %v", err) + os.Exit(1) + } + + if err := redis.Init(redis.Config{ + Host: utils.GetConfigString("redis.host"), + Port: utils.GetConfigInt("redis.port"), + Password: utils.GetConfigString("redis.password"), + DB: utils.GetConfigInt("redis.db"), + }); err != nil { + logx.Errorf("redis init: %v", err) + os.Exit(1) + } + + debug := utils.GetConfigBool("mysql.debug") + modelbase.Init(db, modelbase.Config{Prefix: utils.GetConfigString("mysql.prefix"), Debug: debug}) + + rpcConf := zrpc.RpcServerConf{ + ListenOn: listenOn, + } + rpcConf.Mode = mode + ctx := svc.NewServiceContext(c, db) + + s := zrpc.MustNewServer(rpcConf, func(grpcServer *grpc.Server) { + sale.RegisterSaleServer(grpcServer, server.NewSaleServer(ctx)) + if mode == service.DevMode || mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + s.AddUnaryInterceptors(validate.UnaryServerInterceptor(validate.MustNew())) + + logx.Infof("Starting rpc server at %s...", listenOn) + s.Start() +} + +func listenPort(listenOn string) (uint64, error) { + _, portStr, err := net.SplitHostPort(listenOn) + if err != nil { + return utils.NumberZero, err + } + return strconv.ParseUint(portStr, utils.NumberTen, utils.NumberSixtyFourth) +} diff --git a/services/sale/saleClient/sale.go b/services/sale/saleClient/sale.go new file mode 100644 index 0000000..aa77181 --- /dev/null +++ b/services/sale/saleClient/sale.go @@ -0,0 +1,112 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl 1.10.1 +// Source: sale.proto + +package saleClient + +import ( + "context" + + "lone-services/rpc/sale/pb" + + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" +) + +type ( + CreateReq = sale.CreateReq + EditReq = sale.EditReq + GroupCreateReq = sale.GroupCreateReq + GroupEmptyReq = sale.GroupEmptyReq + GroupItemsReq = sale.GroupItemsReq + InfoReq = sale.InfoReq + ItemsReq = sale.ItemsReq + NameItem = sale.NameItem + NamesData = sale.NamesData + NamesReq = sale.NamesReq + Response = sale.Response + StatusReq = sale.StatusReq + + Sale interface { + // 销售分组 + GroupItems(ctx context.Context, in *GroupItemsReq, opts ...grpc.CallOption) (*Response, error) + GroupCreate(ctx context.Context, in *GroupCreateReq, opts ...grpc.CallOption) (*Response, error) + GroupNames(ctx context.Context, in *GroupEmptyReq, opts ...grpc.CallOption) (*Response, error) + // 销售管理 + Types(ctx context.Context, in *GroupEmptyReq, opts ...grpc.CallOption) (*Response, error) + Names(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*Response, error) + NamesInternal(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*NamesData, error) + Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) + Edit(ctx context.Context, in *EditReq, opts ...grpc.CallOption) (*Response, error) + Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error) + Items(ctx context.Context, in *ItemsReq, opts ...grpc.CallOption) (*Response, error) + Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) + } + + defaultSale struct { + cli zrpc.Client + } +) + +func NewSale(cli zrpc.Client) Sale { + return &defaultSale{ + cli: cli, + } +} + +// 销售分组 +func (m *defaultSale) GroupItems(ctx context.Context, in *GroupItemsReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.GroupItems(ctx, in, opts...) +} + +func (m *defaultSale) GroupCreate(ctx context.Context, in *GroupCreateReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.GroupCreate(ctx, in, opts...) +} + +func (m *defaultSale) GroupNames(ctx context.Context, in *GroupEmptyReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.GroupNames(ctx, in, opts...) +} + +// 销售管理 +func (m *defaultSale) Types(ctx context.Context, in *GroupEmptyReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.Types(ctx, in, opts...) +} + +func (m *defaultSale) Names(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.Names(ctx, in, opts...) +} + +func (m *defaultSale) NamesInternal(ctx context.Context, in *NamesReq, opts ...grpc.CallOption) (*NamesData, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.NamesInternal(ctx, in, opts...) +} + +func (m *defaultSale) Create(ctx context.Context, in *CreateReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.Create(ctx, in, opts...) +} + +func (m *defaultSale) Edit(ctx context.Context, in *EditReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.Edit(ctx, in, opts...) +} + +func (m *defaultSale) Info(ctx context.Context, in *InfoReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.Info(ctx, in, opts...) +} + +func (m *defaultSale) Items(ctx context.Context, in *ItemsReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.Items(ctx, in, opts...) +} + +func (m *defaultSale) Status(ctx context.Context, in *StatusReq, opts ...grpc.CallOption) (*Response, error) { + client := sale.NewSaleClient(m.cli.Conn()) + return client.Status(ctx, in, opts...) +} diff --git a/services/sale/validator/validator.go b/services/sale/validator/validator.go new file mode 100644 index 0000000..436185c --- /dev/null +++ b/services/sale/validator/validator.go @@ -0,0 +1,200 @@ +package validator + +import "lone-services/pkg/validate" + +type GroupItemsValidator struct { + Page uint32 `validate:"omitempty,min=1"` + PageSize uint32 `validate:"omitempty,min=1,max=100"` + Name string `validate:"omitempty,max=255"` +} + +func (p GroupItemsValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Page.min": "页码最小为1", + "PageSize.min": "每页数量最小为1", + "PageSize.max": "每页数量最大为100", + "Name.max": "名称长度不能超过255", + } +} + +type GroupCreateValidator struct { + Name string `validate:"required,max=255"` +} + +func (p GroupCreateValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Name.required": "分组名称不能为空", + "Name.max": "分组名称长度不能超过255", + } +} + +type NamesValidator struct { + Type uint32 `validate:"omitempty,oneof=1 2 3"` + Name string `validate:"omitempty,max=255"` + Level uint32 `validate:"omitempty,oneof=0 1"` +} + +func (p NamesValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Type.oneof": "类型不对", + "Name.max": "名称长度不能超过255", + "Level.oneof": "级别不对", + } +} + +type CreateValidator struct { + Mobile string `validate:"required,max=20"` + Name string `validate:"required,max=256"` + IdCardFront string `validate:"required,max=255"` + IdCardBack string `validate:"required,max=255"` + BusinessLicense string `validate:"omitempty,max=255"` + Password string `validate:"required,min=6"` + Account string `validate:"omitempty,max=255"` + Sex uint32 `validate:"omitempty,oneof=1 2 3"` + GroupId int64 `validate:"required,gt=0"` + BirthDate string `validate:"omitempty,max=12"` + SaleId int64 `validate:"omitempty,gte=0"` + Type uint32 `validate:"required,oneof=1 2 3"` + TerritoryId int64 `validate:"required,gt=0"` + TerritoryName string `validate:"required,max=255"` + ProvinceId int64 `validate:"required,gt=0"` + CityId int64 `validate:"required,gt=0"` + DistrictId int64 `validate:"required,gt=0"` + RegionProvince string `validate:"required,max=64"` + RegionCity string `validate:"required,max=64"` + RegionDistrict string `validate:"required,max=64"` + Address string `validate:"required,max=255"` +} + +func (p CreateValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Mobile.required": "手机号不能为空", + "Name.required": "姓名不能为空", + "IdCardFront.required": "身份证正面不能为空", + "IdCardFront.max": "身份证正面地址过长", + "IdCardBack.required": "身份证反面不能为空", + "IdCardBack.max": "身份证反面地址过长", + "BusinessLicense.max": "营业执照地址过长", + "Password.required": "密码不能为空", + "Password.min": "密码长度不能小于6位", + "GroupId.required": "请选择销售分组", + "GroupId.gt": "请选择销售分组", + "Type.required": "请选择类型", + "Type.oneof": "类型不对", + "TerritoryId.required": "请选择地域", + "TerritoryId.gt": "请选择地域", + "TerritoryName.required": "地域名称不能为空", + "ProvinceId.required": "请选择省份", + "ProvinceId.gt": "请选择省份", + "CityId.required": "请选择城市", + "CityId.gt": "请选择城市", + "DistrictId.required": "请选择区县", + "DistrictId.gt": "请选择区县", + "RegionProvince.required": "地区省份不能为空", + "RegionCity.required": "地区城市不能为空", + "RegionDistrict.required": "地区区县不能为空", + "Address.required": "详细地址不能为空", + } +} + +type EditValidator struct { + Id int64 `validate:"required,gt=0"` + Mobile string `validate:"required,max=20"` + Name string `validate:"required,max=256"` + IdCardFront string `validate:"required,max=255"` + IdCardBack string `validate:"required,max=255"` + BusinessLicense string `validate:"omitempty,max=255"` + Account string `validate:"omitempty,max=255"` + Sex uint32 `validate:"omitempty,oneof=1 2 3"` + GroupId int64 `validate:"required,gt=0"` + BirthDate string `validate:"omitempty,max=12"` + SaleId int64 `validate:"omitempty,gte=0"` + Type uint32 `validate:"required,oneof=1 2 3"` + TerritoryId int64 `validate:"required,gt=0"` + TerritoryName string `validate:"required,max=255"` + ProvinceId int64 `validate:"required,gt=0"` + CityId int64 `validate:"required,gt=0"` + DistrictId int64 `validate:"required,gt=0"` + RegionProvince string `validate:"required,max=64"` + RegionCity string `validate:"required,max=64"` + RegionDistrict string `validate:"required,max=64"` + Address string `validate:"required,max=255"` +} + +func (p EditValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Mobile.required": "手机号不能为空", + "Name.required": "姓名不能为空", + "IdCardFront.required": "身份证正面不能为空", + "IdCardFront.max": "身份证正面地址过长", + "IdCardBack.required": "身份证反面不能为空", + "IdCardBack.max": "身份证反面地址过长", + "BusinessLicense.max": "营业执照地址过长", + "GroupId.required": "请选择销售分组", + "GroupId.gt": "请选择销售分组", + "Type.required": "请选择类型", + "Type.oneof": "类型不对", + "TerritoryId.required": "请选择地域", + "TerritoryId.gt": "请选择地域", + "TerritoryName.required": "地域名称不能为空", + "ProvinceId.required": "请选择省份", + "ProvinceId.gt": "请选择省份", + "CityId.required": "请选择城市", + "CityId.gt": "请选择城市", + "DistrictId.required": "请选择区县", + "DistrictId.gt": "请选择区县", + "RegionProvince.required": "地区省份不能为空", + "RegionCity.required": "地区城市不能为空", + "RegionDistrict.required": "地区区县不能为空", + "Address.required": "详细地址不能为空", + } +} + +type InfoValidator struct { + Id int64 `validate:"required,gt=0"` +} + +func (p InfoValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.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"` +} + +func (p ItemsValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Page.min": "页码最小为1", + "PageSize.min": "每页数量最小为1", + "PageSize.max": "每页数量最大为100", + "Type.oneof": "类型不对", + "Status.oneof": "状态不对", + } +} + +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"` +} + +func (p StatusValidator) GetMessage() validate.ValidatorMessages { + return validate.ValidatorMessages{ + "Id.required": "ID不能为空", + "Id.gt": "ID必须大于0", + "Status.required": "状态不能为空", + "Status.oneof": "状态不对", + "Reason.required_if": "未通过或禁用状态,理由不能为空", + "Reason.max": "理由长度不能超过255", + } +} diff --git a/services/user/internal/dao/user.go b/services/user/internal/dao/user.go index e4c7350..9c3192e 100644 --- a/services/user/internal/dao/user.go +++ b/services/user/internal/dao/user.go @@ -100,6 +100,7 @@ type UserListItem struct { Nickname string `json:"nickname"` HeadPortrait string `json:"head_portrait"` Mobile string `json:"mobile"` + OriginMobile string `json:"origin_mobile"` OnTrialNum int `json:"on_trial_num"` Gender int `json:"gender"` Birthday string `json:"birthday"` diff --git a/services/user/internal/logic/registerByUserLogic.go b/services/user/internal/logic/registerByUserLogic.go index e21a37f..4adf11b 100644 --- a/services/user/internal/logic/registerByUserLogic.go +++ b/services/user/internal/logic/registerByUserLogic.go @@ -83,7 +83,7 @@ func (l *RegisterByUserLogic) RegisterByUser(in *user.RegisterByUserReq) (*user. } if v.Type == utils.NumberOne { - encryptMobile, cErr := utils.Crypto{}.AESEncryptECB(v.Account) + encryptMobile, cErr := utils.EncryptPhone(v.Account) if cErr != nil { l.Errorf("registerByUser encrypt mobile: %v", cErr) return failResponse(utils.ErrorEncryptAesError), nil diff --git a/services/user/internal/logic/registerLogic.go b/services/user/internal/logic/registerLogic.go index 7088763..8598bae 100644 --- a/services/user/internal/logic/registerLogic.go +++ b/services/user/internal/logic/registerLogic.go @@ -51,7 +51,7 @@ func (l *RegisterLogic) Register(in *user.RegisterReq) (*user.Response, error) { return failResponse(utils.ErrorExist), nil } - encryptMobile, cErr := utils.Crypto{}.AESEncryptECB(v.Mobile) + encryptMobile, cErr := utils.EncryptPhone(v.Mobile) if cErr != nil { l.Errorf("register encrypt mobile: %v", cErr) return failResponse(utils.ErrorEncryptAesError), nil diff --git a/services/user/internal/logic/response.go b/services/user/internal/logic/response.go index 26be655..12e7aea 100644 --- a/services/user/internal/logic/response.go +++ b/services/user/internal/logic/response.go @@ -39,7 +39,7 @@ func decryptMobile(mobile string) string { if mobile == utils.StringEmpty { return utils.StringEmpty } - plain, err := utils.Crypto{}.AESDecryptECB(mobile) + plain, err := utils.DecryptPhone(mobile) if err != nil { return utils.StringEmpty } diff --git a/services/user/internal/logic/userItemsLogic.go b/services/user/internal/logic/userItemsLogic.go index 3be1045..c430cec 100644 --- a/services/user/internal/logic/userItemsLogic.go +++ b/services/user/internal/logic/userItemsLogic.go @@ -49,23 +49,22 @@ func (l *UserItemsLogic) UserItems(in *user.UserItemsReq) (*user.Response, error size = modelbase.DefaultSize } - where := map[string]string{} - if v.Mobile != utils.StringEmpty { - mobile, cErr := utils.Crypto{}.AESEncryptECB(v.Mobile) - if cErr != nil { - l.Errorf("user items encrypt mobile: %v", cErr) - return failResponse(utils.ErrorEncryptAesError), nil - } - where["mobile"] = mobile - } - - var list []dao.UserListRow - result, err := model.UserModel{}.Init().Page(modelbase.Params{ - Eq: where, + params := modelbase.Params{ Order: "id DESC", Page: page, Size: size, - }, &list) + } + if v.Mobile != utils.StringEmpty { + phone := utils.GetSearchPhone(v.Mobile) + if len(phone) > utils.NumberZero { + params.Like = map[string]string{ + "mobile LIKE ? ": "%%" + phone + "%%", + } + } + } + + var list []dao.UserListRow + result, err := model.UserModel{}.Init().Page(params, &list) if err != nil { l.Errorf("user items: %v", err) return failResponse(utils.Fail), nil @@ -74,12 +73,17 @@ func (l *UserItemsLogic) UserItems(in *user.UserItemsReq) (*user.Response, error items := make([]dao.UserListItem, 0, len(list)) for _, row := range list { headPortrait, _ := utils.BuildImageURL(row.Avatar).(string) + mobile := row.Mobile + if plain, dErr := utils.DecryptPhone(row.Mobile); dErr == nil { + mobile = utils.DecryptPhoneReplace(plain) + } items = append(items, dao.UserListItem{ Id: row.Id, Username: row.Username, Nickname: row.Nickname, HeadPortrait: headPortrait, - Mobile: utils.DecryptMobile(row.Mobile), + Mobile: mobile, + OriginMobile: row.Mobile, OnTrialNum: row.OnTrialNum, Gender: row.Gender, Birthday: row.Birthday,