实现category service基础接口

This commit is contained in:
2025-05-31 16:27:01 +08:00
parent faa6a35475
commit e5446bf836
33 changed files with 1420 additions and 67 deletions

View File

@ -1301,6 +1301,150 @@ func (x *CheckAliasResponse) GetExistingId() string {
return ""
}
type GetSystemCategoriesRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
SystemId string `protobuf:"bytes,1,opt,name=system_id,json=systemId,proto3" json:"system_id,omitempty"` // 系统标识 (必需)
ParentId string `protobuf:"bytes,2,opt,name=parent_id,json=parentId,proto3" json:"parent_id,omitempty"` // 父分类ID (可选)
Page int32 `protobuf:"varint,3,opt,name=page,proto3" json:"page,omitempty"` // 分页参数
PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` // 分页参数
IncludeDescendants bool `protobuf:"varint,5,opt,name=include_descendants,json=includeDescendants,proto3" json:"include_descendants,omitempty"` // 是否包含后代
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetSystemCategoriesRequest) Reset() {
*x = GetSystemCategoriesRequest{}
mi := &file_rpc_category_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetSystemCategoriesRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetSystemCategoriesRequest) ProtoMessage() {}
func (x *GetSystemCategoriesRequest) ProtoReflect() protoreflect.Message {
mi := &file_rpc_category_proto_msgTypes[23]
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 GetSystemCategoriesRequest.ProtoReflect.Descriptor instead.
func (*GetSystemCategoriesRequest) Descriptor() ([]byte, []int) {
return file_rpc_category_proto_rawDescGZIP(), []int{23}
}
func (x *GetSystemCategoriesRequest) GetSystemId() string {
if x != nil {
return x.SystemId
}
return ""
}
func (x *GetSystemCategoriesRequest) GetParentId() string {
if x != nil {
return x.ParentId
}
return ""
}
func (x *GetSystemCategoriesRequest) GetPage() int32 {
if x != nil {
return x.Page
}
return 0
}
func (x *GetSystemCategoriesRequest) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
func (x *GetSystemCategoriesRequest) GetIncludeDescendants() bool {
if x != nil {
return x.IncludeDescendants
}
return false
}
type GetSystemCategoriesResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Categories []*CategoryInfo `protobuf:"bytes,1,rep,name=categories,proto3" json:"categories,omitempty"`
Total int64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"`
CurrentPage int32 `protobuf:"varint,3,opt,name=current_page,json=currentPage,proto3" json:"current_page,omitempty"`
PageSize int32 `protobuf:"varint,4,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetSystemCategoriesResponse) Reset() {
*x = GetSystemCategoriesResponse{}
mi := &file_rpc_category_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetSystemCategoriesResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetSystemCategoriesResponse) ProtoMessage() {}
func (x *GetSystemCategoriesResponse) ProtoReflect() protoreflect.Message {
mi := &file_rpc_category_proto_msgTypes[24]
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 GetSystemCategoriesResponse.ProtoReflect.Descriptor instead.
func (*GetSystemCategoriesResponse) Descriptor() ([]byte, []int) {
return file_rpc_category_proto_rawDescGZIP(), []int{24}
}
func (x *GetSystemCategoriesResponse) GetCategories() []*CategoryInfo {
if x != nil {
return x.Categories
}
return nil
}
func (x *GetSystemCategoriesResponse) GetTotal() int64 {
if x != nil {
return x.Total
}
return 0
}
func (x *GetSystemCategoriesResponse) GetCurrentPage() int32 {
if x != nil {
return x.CurrentPage
}
return 0
}
func (x *GetSystemCategoriesResponse) GetPageSize() int32 {
if x != nil {
return x.PageSize
}
return 0
}
type CategoryTreeResponse_TreeNode struct {
state protoimpl.MessageState `protogen:"open.v1"`
Category *CategoryInfo `protobuf:"bytes,1,opt,name=category,proto3" json:"category,omitempty"`
@ -1311,7 +1455,7 @@ type CategoryTreeResponse_TreeNode struct {
func (x *CategoryTreeResponse_TreeNode) Reset() {
*x = CategoryTreeResponse_TreeNode{}
mi := &file_rpc_category_proto_msgTypes[23]
mi := &file_rpc_category_proto_msgTypes[25]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -1323,7 +1467,7 @@ func (x *CategoryTreeResponse_TreeNode) String() string {
func (*CategoryTreeResponse_TreeNode) ProtoMessage() {}
func (x *CategoryTreeResponse_TreeNode) ProtoReflect() protoreflect.Message {
mi := &file_rpc_category_proto_msgTypes[23]
mi := &file_rpc_category_proto_msgTypes[25]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -1448,7 +1592,20 @@ const file_rpc_category_proto_rawDesc = "" +
"\x12CheckAliasResponse\x12!\n" +
"\fis_available\x18\x01 \x01(\bR\visAvailable\x12\x1f\n" +
"\vexisting_id\x18\x02 \x01(\tR\n" +
"existingId2\xfd\a\n" +
"existingId\"\xb8\x01\n" +
"\x1aGetSystemCategoriesRequest\x12\x1b\n" +
"\tsystem_id\x18\x01 \x01(\tR\bsystemId\x12\x1b\n" +
"\tparent_id\x18\x02 \x01(\tR\bparentId\x12\x12\n" +
"\x04page\x18\x03 \x01(\x05R\x04page\x12\x1b\n" +
"\tpage_size\x18\x04 \x01(\x05R\bpageSize\x12/\n" +
"\x13include_descendants\x18\x05 \x01(\bR\x12includeDescendants\"\xab\x01\n" +
"\x1bGetSystemCategoriesResponse\x126\n" +
"\n" +
"categories\x18\x01 \x03(\v2\x16.category.CategoryInfoR\n" +
"categories\x12\x14\n" +
"\x05total\x18\x02 \x01(\x03R\x05total\x12!\n" +
"\fcurrent_page\x18\x03 \x01(\x05R\vcurrentPage\x12\x1b\n" +
"\tpage_size\x18\x04 \x01(\x05R\bpageSize2\xe1\b\n" +
"\bCategory\x125\n" +
"\x04Ping\x12\x15.category.PingRequest\x1a\x16.category.PingResponse\x12Q\n" +
"\x0eCreateCategory\x12\x1f.category.CreateCategoryRequest\x1a\x1e.category.CategoryInfoResponse\x12Q\n" +
@ -1463,7 +1620,8 @@ const file_rpc_category_proto_rawDesc = "" +
"\x15BatchUpdateCategories\x12\x1c.category.BatchUpdateRequest\x1a\x1d.category.BatchUpdateResponse\x12O\n" +
"\x0eListCategories\x12\x1d.category.ListCategoryRequest\x1a\x1e.category.CategoryListResponse\x12G\n" +
"\n" +
"CheckAlias\x12\x1b.category.CheckAliasRequest\x1a\x1c.category.CheckAliasResponseB\fZ\n" +
"CheckAlias\x12\x1b.category.CheckAliasRequest\x1a\x1c.category.CheckAliasResponse\x12b\n" +
"\x13GetSystemCategories\x12$.category.GetSystemCategoriesRequest\x1a%.category.GetSystemCategoriesResponseB\fZ\n" +
"./categoryb\x06proto3"
var (
@ -1478,7 +1636,7 @@ func file_rpc_category_proto_rawDescGZIP() []byte {
return file_rpc_category_proto_rawDescData
}
var file_rpc_category_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
var file_rpc_category_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
var file_rpc_category_proto_goTypes = []any{
(*PingRequest)(nil), // 0: category.PingRequest
(*PingResponse)(nil), // 1: category.PingResponse
@ -1503,7 +1661,9 @@ var file_rpc_category_proto_goTypes = []any{
(*CategoryTreeResponse)(nil), // 20: category.CategoryTreeResponse
(*CheckAliasRequest)(nil), // 21: category.CheckAliasRequest
(*CheckAliasResponse)(nil), // 22: category.CheckAliasResponse
(*CategoryTreeResponse_TreeNode)(nil), // 23: category.CategoryTreeResponse.TreeNode
(*GetSystemCategoriesRequest)(nil), // 23: category.GetSystemCategoriesRequest
(*GetSystemCategoriesResponse)(nil), // 24: category.GetSystemCategoriesResponse
(*CategoryTreeResponse_TreeNode)(nil), // 25: category.CategoryTreeResponse.TreeNode
}
var file_rpc_category_proto_depIdxs = []int32{
2, // 0: category.CategoryInfoResponse.category:type_name -> category.CategoryInfo
@ -1513,40 +1673,43 @@ var file_rpc_category_proto_depIdxs = []int32{
4, // 4: category.BatchUpdateRequest.categories:type_name -> category.UpdateCategoryRequest
2, // 5: category.BatchUpdateResponse.updated_categories:type_name -> category.CategoryInfo
2, // 6: category.CategoryListResponse.categories:type_name -> category.CategoryInfo
23, // 7: category.CategoryTreeResponse.root:type_name -> category.CategoryTreeResponse.TreeNode
2, // 8: category.CategoryTreeResponse.TreeNode.category:type_name -> category.CategoryInfo
23, // 9: category.CategoryTreeResponse.TreeNode.children:type_name -> category.CategoryTreeResponse.TreeNode
0, // 10: category.Category.Ping:input_type -> category.PingRequest
3, // 11: category.Category.CreateCategory:input_type -> category.CreateCategoryRequest
4, // 12: category.Category.UpdateCategory:input_type -> category.UpdateCategoryRequest
5, // 13: category.Category.DeleteCategory:input_type -> category.DeleteCategoryRequest
7, // 14: category.Category.GetCategory:input_type -> category.GetCategoryRequest
9, // 15: category.Category.GetChildren:input_type -> category.GetChildrenRequest
10, // 16: category.Category.GetTree:input_type -> category.GetTreeRequest
11, // 17: category.Category.MoveCategory:input_type -> category.MoveCategoryRequest
12, // 18: category.Category.GetAncestorPath:input_type -> category.GetAncestorPathRequest
14, // 19: category.Category.BatchCreateCategories:input_type -> category.BatchCreateRequest
16, // 20: category.Category.BatchUpdateCategories:input_type -> category.BatchUpdateRequest
18, // 21: category.Category.ListCategories:input_type -> category.ListCategoryRequest
21, // 22: category.Category.CheckAlias:input_type -> category.CheckAliasRequest
1, // 23: category.Category.Ping:output_type -> category.PingResponse
8, // 24: category.Category.CreateCategory:output_type -> category.CategoryInfoResponse
8, // 25: category.Category.UpdateCategory:output_type -> category.CategoryInfoResponse
6, // 26: category.Category.DeleteCategory:output_type -> category.DeleteResponse
8, // 27: category.Category.GetCategory:output_type -> category.CategoryInfoResponse
19, // 28: category.Category.GetChildren:output_type -> category.CategoryListResponse
20, // 29: category.Category.GetTree:output_type -> category.CategoryTreeResponse
8, // 30: category.Category.MoveCategory:output_type -> category.CategoryInfoResponse
13, // 31: category.Category.GetAncestorPath:output_type -> category.CategoryPathResponse
15, // 32: category.Category.BatchCreateCategories:output_type -> category.BatchCreateResponse
17, // 33: category.Category.BatchUpdateCategories:output_type -> category.BatchUpdateResponse
19, // 34: category.Category.ListCategories:output_type -> category.CategoryListResponse
22, // 35: category.Category.CheckAlias:output_type -> category.CheckAliasResponse
23, // [23:36] is the sub-list for method output_type
10, // [10:23] is the sub-list for method input_type
10, // [10:10] is the sub-list for extension type_name
10, // [10:10] is the sub-list for extension extendee
0, // [0:10] is the sub-list for field type_name
25, // 7: category.CategoryTreeResponse.root:type_name -> category.CategoryTreeResponse.TreeNode
2, // 8: category.GetSystemCategoriesResponse.categories:type_name -> category.CategoryInfo
2, // 9: category.CategoryTreeResponse.TreeNode.category:type_name -> category.CategoryInfo
25, // 10: category.CategoryTreeResponse.TreeNode.children:type_name -> category.CategoryTreeResponse.TreeNode
0, // 11: category.Category.Ping:input_type -> category.PingRequest
3, // 12: category.Category.CreateCategory:input_type -> category.CreateCategoryRequest
4, // 13: category.Category.UpdateCategory:input_type -> category.UpdateCategoryRequest
5, // 14: category.Category.DeleteCategory:input_type -> category.DeleteCategoryRequest
7, // 15: category.Category.GetCategory:input_type -> category.GetCategoryRequest
9, // 16: category.Category.GetChildren:input_type -> category.GetChildrenRequest
10, // 17: category.Category.GetTree:input_type -> category.GetTreeRequest
11, // 18: category.Category.MoveCategory:input_type -> category.MoveCategoryRequest
12, // 19: category.Category.GetAncestorPath:input_type -> category.GetAncestorPathRequest
14, // 20: category.Category.BatchCreateCategories:input_type -> category.BatchCreateRequest
16, // 21: category.Category.BatchUpdateCategories:input_type -> category.BatchUpdateRequest
18, // 22: category.Category.ListCategories:input_type -> category.ListCategoryRequest
21, // 23: category.Category.CheckAlias:input_type -> category.CheckAliasRequest
23, // 24: category.Category.GetSystemCategories:input_type -> category.GetSystemCategoriesRequest
1, // 25: category.Category.Ping:output_type -> category.PingResponse
8, // 26: category.Category.CreateCategory:output_type -> category.CategoryInfoResponse
8, // 27: category.Category.UpdateCategory:output_type -> category.CategoryInfoResponse
6, // 28: category.Category.DeleteCategory:output_type -> category.DeleteResponse
8, // 29: category.Category.GetCategory:output_type -> category.CategoryInfoResponse
19, // 30: category.Category.GetChildren:output_type -> category.CategoryListResponse
20, // 31: category.Category.GetTree:output_type -> category.CategoryTreeResponse
8, // 32: category.Category.MoveCategory:output_type -> category.CategoryInfoResponse
13, // 33: category.Category.GetAncestorPath:output_type -> category.CategoryPathResponse
15, // 34: category.Category.BatchCreateCategories:output_type -> category.BatchCreateResponse
17, // 35: category.Category.BatchUpdateCategories:output_type -> category.BatchUpdateResponse
19, // 36: category.Category.ListCategories:output_type -> category.CategoryListResponse
22, // 37: category.Category.CheckAlias:output_type -> category.CheckAliasResponse
24, // 38: category.Category.GetSystemCategories:output_type -> category.GetSystemCategoriesResponse
25, // [25:39] is the sub-list for method output_type
11, // [11:25] is the sub-list for method input_type
11, // [11:11] is the sub-list for extension type_name
11, // [11:11] is the sub-list for extension extendee
0, // [0:11] is the sub-list for field type_name
}
func init() { file_rpc_category_proto_init() }
@ -1560,7 +1723,7 @@ func file_rpc_category_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_rpc_category_proto_rawDesc), len(file_rpc_category_proto_rawDesc)),
NumEnums: 0,
NumMessages: 24,
NumMessages: 26,
NumExtensions: 0,
NumServices: 1,
},

View File

@ -32,6 +32,7 @@ const (
Category_BatchUpdateCategories_FullMethodName = "/category.Category/BatchUpdateCategories"
Category_ListCategories_FullMethodName = "/category.Category/ListCategories"
Category_CheckAlias_FullMethodName = "/category.Category/CheckAlias"
Category_GetSystemCategories_FullMethodName = "/category.Category/GetSystemCategories"
)
// CategoryClient is the client API for Category service.
@ -58,6 +59,8 @@ type CategoryClient interface {
// 查询过滤
ListCategories(ctx context.Context, in *ListCategoryRequest, opts ...grpc.CallOption) (*CategoryListResponse, error)
CheckAlias(ctx context.Context, in *CheckAliasRequest, opts ...grpc.CallOption) (*CheckAliasResponse, error)
// 根据系统ID获取分类
GetSystemCategories(ctx context.Context, in *GetSystemCategoriesRequest, opts ...grpc.CallOption) (*GetSystemCategoriesResponse, error)
}
type categoryClient struct {
@ -198,6 +201,16 @@ func (c *categoryClient) CheckAlias(ctx context.Context, in *CheckAliasRequest,
return out, nil
}
func (c *categoryClient) GetSystemCategories(ctx context.Context, in *GetSystemCategoriesRequest, opts ...grpc.CallOption) (*GetSystemCategoriesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetSystemCategoriesResponse)
err := c.cc.Invoke(ctx, Category_GetSystemCategories_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// CategoryServer is the server API for Category service.
// All implementations must embed UnimplementedCategoryServer
// for forward compatibility.
@ -222,6 +235,8 @@ type CategoryServer interface {
// 查询过滤
ListCategories(context.Context, *ListCategoryRequest) (*CategoryListResponse, error)
CheckAlias(context.Context, *CheckAliasRequest) (*CheckAliasResponse, error)
// 根据系统ID获取分类
GetSystemCategories(context.Context, *GetSystemCategoriesRequest) (*GetSystemCategoriesResponse, error)
mustEmbedUnimplementedCategoryServer()
}
@ -271,6 +286,9 @@ func (UnimplementedCategoryServer) ListCategories(context.Context, *ListCategory
func (UnimplementedCategoryServer) CheckAlias(context.Context, *CheckAliasRequest) (*CheckAliasResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CheckAlias not implemented")
}
func (UnimplementedCategoryServer) GetSystemCategories(context.Context, *GetSystemCategoriesRequest) (*GetSystemCategoriesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetSystemCategories not implemented")
}
func (UnimplementedCategoryServer) mustEmbedUnimplementedCategoryServer() {}
func (UnimplementedCategoryServer) testEmbeddedByValue() {}
@ -526,6 +544,24 @@ func _Category_CheckAlias_Handler(srv interface{}, ctx context.Context, dec func
return interceptor(ctx, in, info, handler)
}
func _Category_GetSystemCategories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetSystemCategoriesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CategoryServer).GetSystemCategories(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Category_GetSystemCategories_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CategoryServer).GetSystemCategories(ctx, req.(*GetSystemCategoriesRequest))
}
return interceptor(ctx, in, info, handler)
}
// Category_ServiceDesc is the grpc.ServiceDesc for Category service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@ -585,6 +621,10 @@ var Category_ServiceDesc = grpc.ServiceDesc{
MethodName: "CheckAlias",
Handler: _Category_CheckAlias_Handler,
},
{
MethodName: "GetSystemCategories",
Handler: _Category_GetSystemCategories_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "rpc/category.proto",

View File

@ -32,6 +32,8 @@ type (
GetAncestorPathRequest = category.GetAncestorPathRequest
GetCategoryRequest = category.GetCategoryRequest
GetChildrenRequest = category.GetChildrenRequest
GetSystemCategoriesRequest = category.GetSystemCategoriesRequest
GetSystemCategoriesResponse = category.GetSystemCategoriesResponse
GetTreeRequest = category.GetTreeRequest
ListCategoryRequest = category.ListCategoryRequest
MoveCategoryRequest = category.MoveCategoryRequest
@ -58,6 +60,8 @@ type (
// 查询过滤
ListCategories(ctx context.Context, in *ListCategoryRequest, opts ...grpc.CallOption) (*CategoryListResponse, error)
CheckAlias(ctx context.Context, in *CheckAliasRequest, opts ...grpc.CallOption) (*CheckAliasResponse, error)
// 根据系统ID获取分类
GetSystemCategories(ctx context.Context, in *GetSystemCategoriesRequest, opts ...grpc.CallOption) (*GetSystemCategoriesResponse, error)
}
defaultCategory struct {
@ -140,3 +144,9 @@ func (m *defaultCategory) CheckAlias(ctx context.Context, in *CheckAliasRequest,
client := category.NewCategoryClient(m.cli.Conn())
return client.CheckAlias(ctx, in, opts...)
}
// 根据系统ID获取分类
func (m *defaultCategory) GetSystemCategories(ctx context.Context, in *GetSystemCategoriesRequest, opts ...grpc.CallOption) (*GetSystemCategoriesResponse, error) {
client := category.NewCategoryClient(m.cli.Conn())
return client.GetSystemCategories(ctx, in, opts...)
}

View File

@ -7,7 +7,7 @@ Etcd:
Key: category.rpc
DB:
DataSource: postgres://postgres:postgres@localhost:5432/godemo?sslmode=disable
DataSource: postgres://postgres:postgres@localhost:19732/godemo?sslmode=disable
MaxOpenConns: 100
MaxIdleConns: 20
ConnMaxLifetime: 3600

View File

@ -0,0 +1,167 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/model"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type GetSystemCategoriesLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetSystemCategoriesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetSystemCategoriesLogic {
return &GetSystemCategoriesLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// 根据系统ID获取分类
func (l *GetSystemCategoriesLogic) GetSystemCategories(in *category.GetSystemCategoriesRequest) (*category.GetSystemCategoriesResponse, error) {
// 1. 参数验证
if in.SystemId == "" {
return nil, status.Error(codes.InvalidArgument, "system_id is required")
}
// 2. 设置默认分页值
page, pageSize := normalizePagination(in.Page, in.PageSize)
// 3. 根据是否包含后代选择查询方式
var categories []*model.Categories
var total int64
var err error
if in.IncludeDescendants {
// 递归查询所有后代
categories, err = l.getDescendantsRecursively(in.SystemId, in.ParentId)
if err != nil {
return nil, status.Error(codes.Internal, "failed to get descendant categories")
}
total = int64(len(categories))
} else {
// 直接查询子分类
categories, total, err = l.getDirectChildren(in.SystemId, in.ParentId, page, pageSize)
if err != nil {
return nil, status.Error(codes.Internal, "failed to get categories")
}
}
// 4. 转换模型到protobuf
pbCategories := make([]*category.CategoryInfo, 0, len(categories))
for _, cat := range categories {
pbCategories = append(pbCategories, convertToPbCategory(cat))
}
// 5. 构建响应
return &category.GetSystemCategoriesResponse{
Categories: pbCategories,
Total: total,
CurrentPage: int32(page),
PageSize: int32(pageSize),
}, nil
}
// 获取直接子分类(非递归)
func (l *GetSystemCategoriesLogic) getDirectChildren(systemID, parentID string, page, pageSize int) ([]*model.Categories, int64, error) {
// 构建基础查询
query := l.svcCtx.CategoryModel.RowBuilder().
Where("system_id = $1", systemID)
// 处理父分类ID
if parentID == "" {
query = query.Where("(parent_id IS NULL OR parent_id = '')")
} else {
query = query.Where("parent_id = $2", parentID)
}
// 获取总数
total, err := l.svcCtx.CategoryModel.FindCount(l.ctx, query.RemoveColumns())
if err != nil {
return nil, 0, err
}
// 分页查询
query = query.OrderBy("created_at DESC").
Offset(uint64((page - 1) * pageSize)).
Limit(uint64(pageSize))
categories, err := l.svcCtx.CategoryModel.FindAll(l.ctx, query)
if err != nil {
return nil, 0, err
}
return categories, total, nil
}
// 递归获取所有后代分类
func (l *GetSystemCategoriesLogic) getDescendantsRecursively(systemID, parentID string) ([]*model.Categories, error) {
// 使用递归CTE查询
query := `
WITH RECURSIVE category_tree AS (
SELECT id, system_id, name, alias, parent_id, description, created_at, updated_at
FROM categories
WHERE system_id = $1
AND (
CASE
WHEN $2 = '' THEN parent_id IS NULL
ELSE parent_id = $2
END
)
UNION ALL
SELECT c.id, c.system_id, c.name, c.alias, c.parent_id, c.description, c.created_at, c.updated_at
FROM categories c
INNER JOIN category_tree ct ON c.parent_id = ct.id
)
SELECT * FROM category_tree
`
var categories []*model.Categories
err := l.svcCtx.SqlConn.QueryRowsCtx(l.ctx, &categories, query, systemID, parentID)
if err != nil && err != sqlx.ErrNotFound {
return nil, err
}
return categories, nil
}
// 转换模型到protobuf
func convertToPbCategory(cat *model.Categories) *category.CategoryInfo {
return &category.CategoryInfo{
Id: cat.Id,
SystemId: cat.SystemId,
Name: cat.Name,
Alias: cat.Alias.String,
ParentId: cat.ParentId.String,
Description: cat.Description.String,
CreatedAt: cat.CreatedAt.Unix(),
UpdatedAt: cat.UpdatedAt.Time.Unix(),
}
}
// 规范化分页参数
func normalizePagination(page, pageSize int32) (int, int) {
p := int(page)
ps := int(pageSize)
if p <= 0 {
p = 1
}
if ps <= 0 {
ps = 20
} else if ps > 100 {
ps = 100
}
return p, ps
}

View File

@ -3,6 +3,7 @@ package model
import (
"context"
"github.com/Masterminds/squirrel"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
@ -17,6 +18,11 @@ type (
Transact(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error
FindBySystemParentName(ctx context.Context, systemID string, parentID string, name string) (*Categories, error)
FindBySystemParentAlias(ctx context.Context, systemID string, parentID string, alias string) (*Categories, error)
// 新增方法
RowBuilder() squirrel.SelectBuilder
FindCount(ctx context.Context, builder squirrel.SelectBuilder) (int64, error)
FindAll(ctx context.Context, builder squirrel.SelectBuilder) ([]*Categories, error)
}
customCategoriesModel struct {
@ -72,3 +78,81 @@ func (m *customCategoriesModel) FindBySystemParentAlias(ctx context.Context, sys
}
return &resp, nil
}
// === 新增方法实现 ===
// RowBuilder 创建一个基本的SELECT查询构建器
func (m *customCategoriesModel) RowBuilder() squirrel.SelectBuilder {
return squirrel.Select(categoriesRows).From(m.table)
}
// FindCount 执行COUNT查询
func (m *customCategoriesModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder) (int64, error) {
// 将SELECT转换为COUNT
builder = builder.Columns("COUNT(1) AS count")
query, args, err := builder.ToSql()
if err != nil {
return 0, err
}
var count int64
err = m.conn.QueryRowCtx(ctx, &count, query, args...)
if err != nil {
return 0, err
}
return count, nil
}
// FindAll 执行查询并返回所有结果
func (m *customCategoriesModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder) ([]*Categories, error) {
query, args, err := builder.ToSql()
if err != nil {
return nil, err
}
var categories []*Categories
err = m.conn.QueryRowsCtx(ctx, &categories, query, args...)
if err != nil && err != sqlx.ErrNotFound {
return nil, err
}
return categories, nil
}
// === 辅助函数 ===
// 添加分页支持
func (m *customCategoriesModel) FindAllWithPagination(
ctx context.Context,
builder squirrel.SelectBuilder,
orderBy string,
page int,
pageSize int,
) ([]*Categories, int64, error) {
// 获取总数
total, err := m.FindCount(ctx, builder)
if err != nil {
return nil, 0, err
}
// 添加分页
if page > 0 && pageSize > 0 {
offset := (page - 1) * pageSize
builder = builder.Offset(uint64(offset)).Limit(uint64(pageSize))
}
// 添加排序
if orderBy != "" {
builder = builder.OrderBy(orderBy)
}
// 执行查询
categories, err := m.FindAll(ctx, builder)
if err != nil {
return nil, 0, err
}
return categories, total, nil
}

View File

@ -92,3 +92,9 @@ func (s *CategoryServer) CheckAlias(ctx context.Context, in *category.CheckAlias
l := logic.NewCheckAliasLogic(ctx, s.svcCtx)
return l.CheckAlias(in)
}
// 根据系统ID获取分类
func (s *CategoryServer) GetSystemCategories(ctx context.Context, in *category.GetSystemCategoriesRequest) (*category.GetSystemCategoriesResponse, error) {
l := logic.NewGetSystemCategoriesLogic(ctx, s.svcCtx)
return l.GetSystemCategories(in)
}

View File

@ -11,6 +11,7 @@ import (
type ServiceContext struct {
Config config.Config
CategoryModel model.CategoriesModel
SqlConn sqlx.SqlConn // 添加这个字段
}
func NewServiceContext(c config.Config) *ServiceContext {
@ -18,5 +19,6 @@ func NewServiceContext(c config.Config) *ServiceContext {
return &ServiceContext{
Config: c,
CategoryModel: model.NewCategoriesModel(conn),
SqlConn: conn, // 赋值
}
}