feat: 实现运营商模块重构,添加冗余字段优化查询性能
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m16s

主要变更:
- 新增 Carrier CRUD API(创建、列表、详情、更新、删除、状态更新)
- IotCard/IotCardImportTask 添加 carrier_type/carrier_name 冗余字段
- 移除 Carrier 表的 channel_name/channel_code 字段
- 查询时直接使用冗余字段,避免 JOIN Carrier 表
- 添加数据库迁移脚本(000021-000023)
- 添加单元测试和集成测试
- 同步更新 OpenAPI 文档和 specs
This commit is contained in:
2026-01-27 12:18:19 +08:00
parent 5a179ba16b
commit d104d297ca
42 changed files with 2431 additions and 122 deletions

View File

@@ -0,0 +1,182 @@
package carrier
import (
"context"
"fmt"
"time"
"gorm.io/gorm"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/model/dto"
"github.com/break/junhong_cmp_fiber/internal/store"
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
)
type Service struct {
carrierStore *postgres.CarrierStore
}
func New(carrierStore *postgres.CarrierStore) *Service {
return &Service{carrierStore: carrierStore}
}
func (s *Service) Create(ctx context.Context, req *dto.CreateCarrierRequest) (*dto.CarrierResponse, error) {
currentUserID := middleware.GetUserIDFromContext(ctx)
if currentUserID == 0 {
return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
}
existing, _ := s.carrierStore.GetByCode(ctx, req.CarrierCode)
if existing != nil {
return nil, errors.New(errors.CodeCarrierCodeExists, "运营商编码已存在")
}
carrier := &model.Carrier{
CarrierCode: req.CarrierCode,
CarrierName: req.CarrierName,
CarrierType: req.CarrierType,
Description: req.Description,
Status: constants.StatusEnabled,
}
carrier.Creator = currentUserID
if err := s.carrierStore.Create(ctx, carrier); err != nil {
return nil, fmt.Errorf("创建运营商失败: %w", err)
}
return s.toResponse(carrier), nil
}
func (s *Service) Get(ctx context.Context, id uint) (*dto.CarrierResponse, error) {
carrier, err := s.carrierStore.GetByID(ctx, id)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeCarrierNotFound, "运营商不存在")
}
return nil, fmt.Errorf("获取运营商失败: %w", err)
}
return s.toResponse(carrier), nil
}
func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateCarrierRequest) (*dto.CarrierResponse, error) {
currentUserID := middleware.GetUserIDFromContext(ctx)
if currentUserID == 0 {
return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
}
carrier, err := s.carrierStore.GetByID(ctx, id)
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, errors.New(errors.CodeCarrierNotFound, "运营商不存在")
}
return nil, fmt.Errorf("获取运营商失败: %w", err)
}
if req.CarrierName != nil {
carrier.CarrierName = *req.CarrierName
}
if req.Description != nil {
carrier.Description = *req.Description
}
carrier.Updater = currentUserID
if err := s.carrierStore.Update(ctx, carrier); err != nil {
return nil, fmt.Errorf("更新运营商失败: %w", err)
}
return s.toResponse(carrier), nil
}
func (s *Service) Delete(ctx context.Context, id uint) error {
_, err := s.carrierStore.GetByID(ctx, id)
if err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New(errors.CodeCarrierNotFound, "运营商不存在")
}
return fmt.Errorf("获取运营商失败: %w", err)
}
if err := s.carrierStore.Delete(ctx, id); err != nil {
return fmt.Errorf("删除运营商失败: %w", err)
}
return nil
}
func (s *Service) List(ctx context.Context, req *dto.CarrierListRequest) ([]*dto.CarrierResponse, int64, error) {
opts := &store.QueryOptions{
Page: req.Page,
PageSize: req.PageSize,
OrderBy: "id DESC",
}
if opts.Page == 0 {
opts.Page = 1
}
if opts.PageSize == 0 {
opts.PageSize = constants.DefaultPageSize
}
filters := make(map[string]interface{})
if req.CarrierType != nil {
filters["carrier_type"] = *req.CarrierType
}
if req.CarrierName != nil {
filters["carrier_name"] = *req.CarrierName
}
if req.Status != nil {
filters["status"] = *req.Status
}
carriers, total, err := s.carrierStore.List(ctx, opts, filters)
if err != nil {
return nil, 0, fmt.Errorf("查询运营商列表失败: %w", err)
}
responses := make([]*dto.CarrierResponse, len(carriers))
for i, c := range carriers {
responses[i] = s.toResponse(c)
}
return responses, total, nil
}
func (s *Service) UpdateStatus(ctx context.Context, id uint, status int) error {
currentUserID := middleware.GetUserIDFromContext(ctx)
if currentUserID == 0 {
return errors.New(errors.CodeUnauthorized, "未授权访问")
}
carrier, err := s.carrierStore.GetByID(ctx, id)
if err != nil {
if err == gorm.ErrRecordNotFound {
return errors.New(errors.CodeCarrierNotFound, "运营商不存在")
}
return fmt.Errorf("获取运营商失败: %w", err)
}
carrier.Status = status
carrier.Updater = currentUserID
if err := s.carrierStore.Update(ctx, carrier); err != nil {
return fmt.Errorf("更新运营商状态失败: %w", err)
}
return nil
}
func (s *Service) toResponse(c *model.Carrier) *dto.CarrierResponse {
return &dto.CarrierResponse{
ID: c.ID,
CarrierCode: c.CarrierCode,
CarrierName: c.CarrierName,
CarrierType: c.CarrierType,
Description: c.Description,
Status: c.Status,
CreatedAt: c.CreatedAt.Format(time.RFC3339),
UpdatedAt: c.UpdatedAt.Format(time.RFC3339),
}
}