企业授权增强与资产列表扩展
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m9s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m9s
- 企业卡授权唯一约束:新增 DB 迁移(000154),卡级部分唯一索引防止同一张卡被多个企业同时持有,Service 层新增跨企业冲突检测 - 单卡列表新增 network_status 过滤参数 - 单卡/设备列表新增 asset_status、asset_status_name、generation 响应字段 - 单卡/设备列表新增企业维度过滤(authorized_enterprise_id、is_authorized_to_enterprise)及响应中企业授权信息(批量加载,无 N+1) - 主钱包流水/退款列表新增 asset_identifier 精确过滤参数 - 企业卡授权/收回接口升级为三模式(list/range/filter),企业设备授权/收回升级为双模式(list/filter) - 升级 sonic v1.14.2 → v1.15.2 以兼容 Go 1.26 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -46,7 +46,7 @@ func New(
|
||||
}
|
||||
}
|
||||
|
||||
// AllocateDevices 授权设备给企业
|
||||
// AllocateDevices 授权设备给企业,支持 list/filter 两种模式
|
||||
func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *dto.AllocateDevicesReq) (*dto.AllocateDevicesResp, error) {
|
||||
currentUserID := middleware.GetUserIDFromContext(ctx)
|
||||
if currentUserID == 0 {
|
||||
@@ -59,9 +59,15 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
|
||||
return nil, errors.New(errors.CodeEnterpriseNotFound, "企业不存在")
|
||||
}
|
||||
|
||||
// 根据选取模式解析候选设备号列表
|
||||
deviceNos, err := s.resolveDeviceNosForAllocate(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 查询所有设备
|
||||
var devices []model.Device
|
||||
if err := s.db.WithContext(ctx).Where("virtual_no IN ?", req.DeviceNos).Find(&devices).Error; err != nil {
|
||||
if err := s.db.WithContext(ctx).Where("virtual_no IN ?", deviceNos).Find(&devices).Error; err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备信息失败")
|
||||
}
|
||||
|
||||
@@ -88,8 +94,8 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
|
||||
}
|
||||
|
||||
devicesToAllocate := make([]*model.Device, 0)
|
||||
seenDeviceNos := make(map[string]struct{}, len(req.DeviceNos))
|
||||
for _, deviceNo := range req.DeviceNos {
|
||||
seenDeviceNos := make(map[string]struct{}, len(deviceNos))
|
||||
for _, deviceNo := range deviceNos {
|
||||
if _, exists := seenDeviceNos[deviceNo]; exists {
|
||||
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
|
||||
VirtualNo: deviceNo,
|
||||
@@ -267,7 +273,62 @@ func isUniqueConstraintViolation(err error, constraintName string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// RecallDevices 撤销设备授权
|
||||
// resolveDeviceNosForAllocate 根据选取模式解析授权候选设备号列表
|
||||
// list 模式:直接使用请求中的 device_nos
|
||||
// filter 模式:按过滤条件从 store 查询,代理用户的店铺限制由 ApplyShopFilter 自动应用
|
||||
func (s *Service) resolveDeviceNosForAllocate(ctx context.Context, req *dto.AllocateDevicesReq) ([]string, error) {
|
||||
if req.SelectionType == "list" {
|
||||
return req.DeviceNos, nil
|
||||
}
|
||||
filters := make(map[string]any)
|
||||
if req.VirtualNo != "" {
|
||||
filters["virtual_no"] = req.VirtualNo
|
||||
}
|
||||
if req.BatchNo != "" {
|
||||
filters["batch_no"] = req.BatchNo
|
||||
}
|
||||
if req.ShopID != nil {
|
||||
filters["shop_id"] = req.ShopID
|
||||
}
|
||||
devices, err := s.deviceStore.GetByFilters(ctx, filters)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "按条件查询设备失败")
|
||||
}
|
||||
nos := make([]string, 0, len(devices))
|
||||
for _, d := range devices {
|
||||
nos = append(nos, d.VirtualNo)
|
||||
}
|
||||
return nos, nil
|
||||
}
|
||||
|
||||
// resolveDeviceNosForRecall 根据选取模式解析收回候选设备号列表
|
||||
// filter 模式仅返回当前企业有效授权的设备(通过子查询限定)
|
||||
func (s *Service) resolveDeviceNosForRecall(ctx context.Context, enterpriseID uint, req *dto.RecallDevicesReq) ([]string, error) {
|
||||
if req.SelectionType == "list" {
|
||||
return req.DeviceNos, nil
|
||||
}
|
||||
// filter 模式:只查询已授权给该企业的设备
|
||||
filters := make(map[string]any)
|
||||
if req.VirtualNo != "" {
|
||||
filters["virtual_no"] = req.VirtualNo
|
||||
}
|
||||
if req.BatchNo != "" {
|
||||
filters["batch_no"] = req.BatchNo
|
||||
}
|
||||
// 仅返回有效授权给该企业的设备
|
||||
filters["authorized_enterprise_id"] = enterpriseID
|
||||
devices, err := s.deviceStore.GetByFilters(ctx, filters)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "按条件查询设备失败")
|
||||
}
|
||||
nos := make([]string, 0, len(devices))
|
||||
for _, d := range devices {
|
||||
nos = append(nos, d.VirtualNo)
|
||||
}
|
||||
return nos, nil
|
||||
}
|
||||
|
||||
// RecallDevices 撤销设备授权,支持 list/filter 两种模式
|
||||
func (s *Service) RecallDevices(ctx context.Context, enterpriseID uint, req *dto.RecallDevicesReq) (*dto.RecallDevicesResp, error) {
|
||||
currentUserID := middleware.GetUserIDFromContext(ctx)
|
||||
if currentUserID == 0 {
|
||||
@@ -280,9 +341,15 @@ func (s *Service) RecallDevices(ctx context.Context, enterpriseID uint, req *dto
|
||||
return nil, errors.New(errors.CodeEnterpriseNotFound, "企业不存在")
|
||||
}
|
||||
|
||||
// 根据选取模式解析候选设备号列表
|
||||
deviceNos, err := s.resolveDeviceNosForRecall(ctx, enterpriseID, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 查询设备
|
||||
var devices []model.Device
|
||||
if err := s.db.WithContext(ctx).Where("virtual_no IN ?", req.DeviceNos).Find(&devices).Error; err != nil {
|
||||
if err := s.db.WithContext(ctx).Where("virtual_no IN ?", deviceNos).Find(&devices).Error; err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备信息失败")
|
||||
}
|
||||
|
||||
@@ -304,7 +371,7 @@ func (s *Service) RecallDevices(ctx context.Context, enterpriseID uint, req *dto
|
||||
}
|
||||
|
||||
deviceAuthsToRevoke := make([]uint, 0)
|
||||
for _, deviceNo := range req.DeviceNos {
|
||||
for _, deviceNo := range deviceNos {
|
||||
device, exists := deviceMap[deviceNo]
|
||||
if !exists {
|
||||
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
|
||||
|
||||
Reference in New Issue
Block a user