修复企业授权报错的问题
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m57s

This commit is contained in:
2026-04-27 10:30:10 +08:00
parent 02ccf57aa3
commit 95104100c9
2 changed files with 96 additions and 23 deletions

View File

@@ -2,6 +2,7 @@ package enterprise_device
import (
"context"
stderrors "errors"
"time"
"github.com/break/junhong_cmp_fiber/internal/model"
@@ -10,6 +11,7 @@ import (
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
"github.com/jackc/pgx/v5/pgconn"
"go.uber.org/zap"
"gorm.io/gorm"
)
@@ -74,8 +76,8 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
currentShopID := middleware.GetShopIDFromContext(ctx)
userType := middleware.GetUserTypeFromContext(ctx)
// 检查已授权的设备
existingAuths, err := s.enterpriseDeviceAuthStore.GetActiveAuthsByDeviceIDs(ctx, enterpriseID, deviceIDs)
// 检查设备是否已存在有效授权(不区分企业)
activeAuthEnterpriseMap, err := s.enterpriseDeviceAuthStore.GetActiveAuthEnterpriseByDeviceIDs(ctx, deviceIDs)
if err != nil {
return nil, errors.Wrap(errors.CodeInternalError, err, "查询已有授权失败")
}
@@ -86,7 +88,17 @@ 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 {
if _, exists := seenDeviceNos[deviceNo]; exists {
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
VirtualNo: deviceNo,
Reason: "请求中设备号重复",
})
continue
}
seenDeviceNos[deviceNo] = struct{}{}
device, exists := deviceMap[deviceNo]
if !exists {
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
@@ -116,11 +128,15 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
}
}
// 检查是否已授权
if existingAuths[device.ID] {
// 检查是否已授权(同企业 / 其他企业)
if authEnterpriseID, exists := activeAuthEnterpriseMap[device.ID]; exists {
reason := "设备已授权给其他企业"
if authEnterpriseID == enterpriseID {
reason = "设备已授权给此企业"
}
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
VirtualNo: deviceNo,
Reason: "设备已授权给此企业",
Reason: reason,
})
continue
}
@@ -134,38 +150,58 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
now := time.Now()
authorizerType := userType
// 1. 创建设备授权记录
deviceAuths := make([]*model.EnterpriseDeviceAuthorization, 0, len(devicesToAllocate))
// 1. 创建设备授权记录(逐条处理,避免并发冲突导致整批失败)
deviceAuthIDMap := make(map[uint]uint, len(devicesToAllocate))
successDevices := make([]*model.Device, 0, len(devicesToAllocate))
for _, device := range devicesToAllocate {
deviceAuths = append(deviceAuths, &model.EnterpriseDeviceAuthorization{
deviceAuth := &model.EnterpriseDeviceAuthorization{
EnterpriseID: enterpriseID,
DeviceID: device.ID,
AuthorizedBy: currentUserID,
AuthorizedAt: now,
AuthorizerType: authorizerType,
Remark: req.Remark,
})
}
}
if err := tx.Create(deviceAuths).Error; err != nil {
return errors.Wrap(errors.CodeInternalError, err, "创建设备授权记录失败")
}
if err := tx.Create(deviceAuth).Error; err != nil {
if isUniqueConstraintViolation(err, "uq_active_device_auth") {
reason := "设备已授权给其他企业"
// 构建设备ID到授权ID的映射
deviceAuthIDMap := make(map[uint]uint)
for _, auth := range deviceAuths {
deviceAuthIDMap[auth.DeviceID] = auth.ID
var existingAuth model.EnterpriseDeviceAuthorization
queryErr := tx.Select("enterprise_id").
Where("device_id = ? AND revoked_at IS NULL", device.ID).
First(&existingAuth).Error
if queryErr == nil && existingAuth.EnterpriseID == enterpriseID {
reason = "设备已授权给此企业"
}
if queryErr != nil && !stderrors.Is(queryErr, gorm.ErrRecordNotFound) {
return errors.Wrap(errors.CodeInternalError, queryErr, "查询冲突授权记录失败")
}
resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
VirtualNo: device.VirtualNo,
Reason: reason,
})
continue
}
return errors.Wrap(errors.CodeInternalError, err, "创建设备授权记录失败")
}
deviceAuthIDMap[device.ID] = deviceAuth.ID
successDevices = append(successDevices, device)
}
// 2. 查询所有设备绑定的卡
deviceIDsToQuery := make([]uint, 0, len(devicesToAllocate))
for _, device := range devicesToAllocate {
deviceIDsToQuery := make([]uint, 0, len(successDevices))
for _, device := range successDevices {
deviceIDsToQuery = append(deviceIDsToQuery, device.ID)
}
var bindings []model.DeviceSimBinding
if err := tx.Where("device_id IN ? AND bind_status = 1", deviceIDsToQuery).Find(&bindings).Error; err != nil {
return errors.Wrap(errors.CodeInternalError, err, "查询设备绑定卡失败")
if len(deviceIDsToQuery) > 0 {
if err := tx.Where("device_id IN ? AND bind_status = 1", deviceIDsToQuery).Find(&bindings).Error; err != nil {
return errors.Wrap(errors.CodeInternalError, err, "查询设备绑定卡失败")
}
}
// 3. 为每张绑定的卡创建授权记录
@@ -196,7 +232,7 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
}
// 5. 构建响应
for _, device := range devicesToAllocate {
for _, device := range successDevices {
resp.AuthorizedDevices = append(resp.AuthorizedDevices, dto.AuthorizedDeviceItem{
DeviceID: device.ID,
VirtualNo: device.VirtualNo,
@@ -212,11 +248,25 @@ func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *d
}
}
resp.SuccessCount = len(devicesToAllocate)
resp.SuccessCount = len(resp.AuthorizedDevices)
resp.FailCount = len(resp.FailedItems)
return resp, nil
}
func isUniqueConstraintViolation(err error, constraintName string) bool {
var pgErr *pgconn.PgError
if stderrors.As(err, &pgErr) {
if pgErr.Code != "23505" {
return false
}
if constraintName == "" {
return true
}
return pgErr.ConstraintName == constraintName
}
return false
}
// RecallDevices 撤销设备授权
func (s *Service) RecallDevices(ctx context.Context, enterpriseID uint, req *dto.RecallDevicesReq) (*dto.RecallDevicesResp, error) {
currentUserID := middleware.GetUserIDFromContext(ctx)

View File

@@ -162,6 +162,29 @@ func (s *EnterpriseDeviceAuthorizationStore) GetActiveAuthsByDeviceIDs(ctx conte
return result, nil
}
// GetActiveAuthEnterpriseByDeviceIDs 获取设备ID列表的有效授权企业映射deviceID -> enterpriseID
func (s *EnterpriseDeviceAuthorizationStore) GetActiveAuthEnterpriseByDeviceIDs(ctx context.Context, deviceIDs []uint) (map[uint]uint, error) {
if len(deviceIDs) == 0 {
return make(map[uint]uint), nil
}
var auths []model.EnterpriseDeviceAuthorization
query := s.db.WithContext(ctx).
Select("device_id, enterprise_id").
Where("device_id IN ? AND revoked_at IS NULL", deviceIDs)
// 应用企业数据权限过滤
query = middleware.ApplyEnterpriseFilter(ctx, query)
if err := query.Find(&auths).Error; err != nil {
return nil, err
}
result := make(map[uint]uint, len(auths))
for _, auth := range auths {
result[auth.DeviceID] = auth.EnterpriseID
}
return result, nil
}
func (s *EnterpriseDeviceAuthorizationStore) ListDeviceIDsByEnterprise(ctx context.Context, enterpriseID uint) ([]uint, error) {
var deviceIDs []uint
query := s.db.WithContext(ctx).