From 41db5b56aff2f3de67ba4fe72f3f5edf5fe87e68 Mon Sep 17 00:00:00 2001 From: huang Date: Fri, 24 Apr 2026 11:20:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E7=BA=A7=E5=BA=97=E9=93=BA=E5=90=8D?= =?UTF-8?q?=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/model/dto/shop_dto.go | 31 +++---- internal/service/shop/service.go | 144 +++++++++++++++++++++---------- 2 files changed, 115 insertions(+), 60 deletions(-) diff --git a/internal/model/dto/shop_dto.go b/internal/model/dto/shop_dto.go index 6402913..5e21c78 100644 --- a/internal/model/dto/shop_dto.go +++ b/internal/model/dto/shop_dto.go @@ -39,21 +39,22 @@ type UpdateShopRequest struct { // ShopResponse 店铺响应 type ShopResponse struct { - ID uint `json:"id" description:"店铺ID"` - ShopName string `json:"shop_name" description:"店铺名称"` - ShopCode string `json:"shop_code" description:"店铺编号"` - ParentID *uint `json:"parent_id,omitempty" description:"上级店铺ID"` - Level int `json:"level" description:"店铺层级 (1-7级)"` - ContactName string `json:"contact_name" description:"联系人姓名"` - ContactPhone string `json:"contact_phone" description:"联系人电话"` - Province string `json:"province" description:"省份"` - City string `json:"city" description:"城市"` - District string `json:"district" description:"区县"` - Address string `json:"address" description:"详细地址"` - Status int `json:"status" description:"状态 (0:禁用, 1:启用)"` - StatusName string `json:"status_name" description:"状态名称(中文)"` - CreatedAt string `json:"created_at" description:"创建时间"` - UpdatedAt string `json:"updated_at" description:"更新时间"` + ID uint `json:"id" description:"店铺ID"` + ShopName string `json:"shop_name" description:"店铺名称"` + ShopCode string `json:"shop_code" description:"店铺编号"` + ParentID *uint `json:"parent_id,omitempty" description:"上级店铺ID"` + ParentShopName string `json:"parent_shop_name,omitempty" description:"上级店铺名称"` + Level int `json:"level" description:"店铺层级 (1-7级)"` + ContactName string `json:"contact_name" description:"联系人姓名"` + ContactPhone string `json:"contact_phone" description:"联系人电话"` + Province string `json:"province" description:"省份"` + City string `json:"city" description:"城市"` + District string `json:"district" description:"区县"` + Address string `json:"address" description:"详细地址"` + Status int `json:"status" description:"状态 (0:禁用, 1:启用)"` + StatusName string `json:"status_name" description:"状态名称(中文)"` + CreatedAt string `json:"created_at" description:"创建时间"` + UpdatedAt string `json:"updated_at" description:"更新时间"` } // ShopPageResult 店铺分页响应 diff --git a/internal/service/shop/service.go b/internal/service/shop/service.go index 7e2da4e..51acf4a 100644 --- a/internal/service/shop/service.go +++ b/internal/service/shop/service.go @@ -53,11 +53,13 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateShopRequest) (*dto. } level := 1 + parentShopName := "" if req.ParentID != nil { parent, err := s.shopStore.GetByID(ctx, *req.ParentID) if err != nil { return nil, errors.New(errors.CodeInvalidParentID, "上级店铺不存在或无效") } + parentShopName = parent.ShopName level = parent.Level + 1 if level > constants.ShopMaxLevel { return nil, errors.New(errors.CodeShopLevelExceeded, "店铺层级不能超过 7 级") @@ -178,21 +180,22 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateShopRequest) (*dto. } return &dto.ShopResponse{ - ID: shop.ID, - ShopName: shop.ShopName, - ShopCode: shop.ShopCode, - ParentID: shop.ParentID, - Level: shop.Level, - ContactName: shop.ContactName, - ContactPhone: shop.ContactPhone, - Province: shop.Province, - City: shop.City, - District: shop.District, - Address: shop.Address, - Status: shop.Status, - StatusName: constants.GetStatusName(shop.Status), - CreatedAt: shop.CreatedAt.Format("2006-01-02 15:04:05"), - UpdatedAt: shop.UpdatedAt.Format("2006-01-02 15:04:05"), + ID: shop.ID, + ShopName: shop.ShopName, + ShopCode: shop.ShopCode, + ParentID: shop.ParentID, + ParentShopName: parentShopName, + Level: shop.Level, + ContactName: shop.ContactName, + ContactPhone: shop.ContactPhone, + Province: shop.Province, + City: shop.City, + District: shop.District, + Address: shop.Address, + Status: shop.Status, + StatusName: constants.GetStatusName(shop.Status), + CreatedAt: shop.CreatedAt.Format("2006-01-02 15:04:05"), + UpdatedAt: shop.UpdatedAt.Format("2006-01-02 15:04:05"), }, nil } @@ -221,22 +224,31 @@ func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateShopReques return nil, err } + parentShopName := "" + if shop.ParentID != nil { + parentShop, err := s.shopStore.GetByID(ctx, *shop.ParentID) + if err == nil { + parentShopName = parentShop.ShopName + } + } + return &dto.ShopResponse{ - ID: shop.ID, - ShopName: shop.ShopName, - ShopCode: shop.ShopCode, - ParentID: shop.ParentID, - Level: shop.Level, - ContactName: shop.ContactName, - ContactPhone: shop.ContactPhone, - Province: shop.Province, - City: shop.City, - District: shop.District, - Address: shop.Address, - Status: shop.Status, - StatusName: constants.GetStatusName(shop.Status), - CreatedAt: shop.CreatedAt.Format("2006-01-02 15:04:05"), - UpdatedAt: shop.UpdatedAt.Format("2006-01-02 15:04:05"), + ID: shop.ID, + ShopName: shop.ShopName, + ShopCode: shop.ShopCode, + ParentID: shop.ParentID, + ParentShopName: parentShopName, + Level: shop.Level, + ContactName: shop.ContactName, + ContactPhone: shop.ContactPhone, + Province: shop.Province, + City: shop.City, + District: shop.District, + Address: shop.Address, + Status: shop.Status, + StatusName: constants.GetStatusName(shop.Status), + CreatedAt: shop.CreatedAt.Format("2006-01-02 15:04:05"), + UpdatedAt: shop.UpdatedAt.Format("2006-01-02 15:04:05"), }, nil } @@ -326,30 +338,72 @@ func (s *Service) ListShopResponses(ctx context.Context, req *dto.ShopListReques return nil, 0, errors.Wrap(errors.CodeInternalError, err, "查询店铺列表失败") } + parentShopNameMap, err := s.buildParentShopNameMap(ctx, shops) + if err != nil { + return nil, 0, errors.Wrap(errors.CodeInternalError, err, "查询上级店铺名称失败") + } + responses := make([]*dto.ShopResponse, 0, len(shops)) for _, shop := range shops { + parentShopName := "" + if shop.ParentID != nil { + parentShopName = parentShopNameMap[*shop.ParentID] + } + responses = append(responses, &dto.ShopResponse{ - ID: shop.ID, - ShopName: shop.ShopName, - ShopCode: shop.ShopCode, - ParentID: shop.ParentID, - Level: shop.Level, - ContactName: shop.ContactName, - ContactPhone: shop.ContactPhone, - Province: shop.Province, - City: shop.City, - District: shop.District, - Address: shop.Address, - Status: shop.Status, - StatusName: constants.GetStatusName(shop.Status), - CreatedAt: shop.CreatedAt.Format("2006-01-02 15:04:05"), - UpdatedAt: shop.UpdatedAt.Format("2006-01-02 15:04:05"), + ID: shop.ID, + ShopName: shop.ShopName, + ShopCode: shop.ShopCode, + ParentID: shop.ParentID, + ParentShopName: parentShopName, + Level: shop.Level, + ContactName: shop.ContactName, + ContactPhone: shop.ContactPhone, + Province: shop.Province, + City: shop.City, + District: shop.District, + Address: shop.Address, + Status: shop.Status, + StatusName: constants.GetStatusName(shop.Status), + CreatedAt: shop.CreatedAt.Format("2006-01-02 15:04:05"), + UpdatedAt: shop.UpdatedAt.Format("2006-01-02 15:04:05"), }) } return responses, total, nil } +// buildParentShopNameMap 批量查询店铺上级名称,避免列表接口出现 N+1 查询。 +func (s *Service) buildParentShopNameMap(ctx context.Context, shops []*model.Shop) (map[uint]string, error) { + parentIDs := make([]uint, 0, len(shops)) + parentIDSet := make(map[uint]struct{}, len(shops)) + for _, shop := range shops { + if shop.ParentID == nil { + continue + } + if _, exists := parentIDSet[*shop.ParentID]; exists { + continue + } + parentIDSet[*shop.ParentID] = struct{}{} + parentIDs = append(parentIDs, *shop.ParentID) + } + + if len(parentIDs) == 0 { + return map[uint]string{}, nil + } + + parentShops, err := s.shopStore.GetByIDs(ctx, parentIDs) + if err != nil { + return nil, err + } + + parentShopNameMap := make(map[uint]string, len(parentShops)) + for _, parentShop := range parentShops { + parentShopNameMap[parentShop.ID] = parentShop.ShopName + } + return parentShopNameMap, nil +} + func (s *Service) List(ctx context.Context, opts *store.QueryOptions, filters map[string]interface{}) ([]*model.Shop, int64, error) { return s.shopStore.List(ctx, opts, filters) }