Files
cid/service/mapping/data_mapping_service.go
2026-03-23 14:08:11 +08:00

307 lines
8.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mapping
import (
consts "cid/consts/mapping"
dao "cid/dao/mapping"
dto "cid/model/dto/mapping"
entity "cid/model/entity/mapping"
"context"
"errors"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
)
type dataMappingService struct{}
// DataMapping 数据映射服务
var DataMapping = new(dataMappingService)
// Create 创建数据映射
func (s *dataMappingService) Create(ctx context.Context, req *dto.CreateDataMappingReq) (res *dto.CreateDataMappingRes, err error) {
// 检查接口是否存在
// TODO: 这里需要调用data层的ApiInterface服务暂时跳过
// 检查同一接口下目标字段是否重复
existing, err := dao.DataMapping.GetByInterfaceIdAndTargetField(ctx, req.InterfaceId, req.TargetField)
if err == nil && existing != nil {
return nil, errors.New("该接口下目标字段已存在")
}
// 插入数据库
id, err := dao.DataMapping.Insert(ctx, req)
if err != nil {
return
}
res = &dto.CreateDataMappingRes{
Id: id,
}
return
}
// BatchCreate 批量创建数据映射
func (s *dataMappingService) BatchCreate(ctx context.Context, req *dto.BatchCreateDataMappingReq) (res *dto.BatchCreateDataMappingRes, err error) {
var ids []int64
successCount := 0
failedCount := 0
for _, mappingReq := range req.Mappings {
// 设置平台和接口ID
mappingReq.PlatformId = req.PlatformId
mappingReq.InterfaceId = req.InterfaceId
createRes, err := s.Create(ctx, &mappingReq)
if err != nil {
failedCount++
g.Log().Error(ctx, "批量创建映射失败", g.Map{
"sourceField": mappingReq.SourceField,
"targetField": mappingReq.TargetField,
"error": err.Error(),
})
} else {
successCount++
ids = append(ids, createRes.Id)
}
}
return &dto.BatchCreateDataMappingRes{
SuccessCount: successCount,
FailedCount: failedCount,
Ids: ids,
}, nil
}
// List 获取数据映射列表
func (s *dataMappingService) List(ctx context.Context, req *dto.ListDataMappingReq) (res *dto.ListDataMappingRes, err error) {
mappingList, total, err := dao.DataMapping.List(ctx, req)
if err != nil {
return
}
// 获取平台和接口ID列表
platformIds := make([]int64, 0)
interfaceIds := make([]int64, 0)
for _, item := range mappingList {
if item.PlatformId > 0 {
platformIds = append(platformIds, item.PlatformId)
}
if item.InterfaceId > 0 {
interfaceIds = append(interfaceIds, item.InterfaceId)
}
}
// TODO: 批量获取平台和接口信息需要调用data层服务
platformMap := make(map[int64]string)
interfaceMap := make(map[int64]string)
// 组装响应数据
list := make([]dto.DataMappingItem, 0, len(mappingList))
for _, item := range mappingList {
platformName := ""
if name, ok := platformMap[item.PlatformId]; ok {
platformName = name
}
interfaceName := ""
if name, ok := interfaceMap[item.InterfaceId]; ok {
interfaceName = name
}
list = append(list, dto.DataMappingItem{
Id: item.Id,
PlatformId: item.PlatformId,
PlatformName: platformName,
InterfaceId: item.InterfaceId,
InterfaceName: interfaceName,
SourceField: item.SourceField,
TargetField: item.TargetField,
FieldType: item.FieldType,
DefaultValue: item.DefaultValue,
TransformRule: item.TransformRule,
Priority: item.Priority,
Status: item.Status,
StatusName: s.getStatusName(item.Status),
CreatedAt: item.CreatedAt.Unix(),
UpdatedAt: item.UpdatedAt.Unix(),
})
}
res = &dto.ListDataMappingRes{
List: list,
Total: total,
}
return
}
// GetOne 获取单个数据映射
func (s *dataMappingService) GetOne(ctx context.Context, req *dto.GetDataMappingReq) (res *dto.GetDataMappingRes, err error) {
mapping, err := dao.DataMapping.GetOne(ctx, req)
if err != nil {
return
}
// TODO: 获取平台和接口名称
platformName := ""
interfaceName := ""
return &dto.GetDataMappingRes{
DataMapping: mapping,
PlatformName: platformName,
InterfaceName: interfaceName,
}, nil
}
// Update 更新数据映射
func (s *dataMappingService) Update(ctx context.Context, req *dto.UpdateDataMappingReq) (err error) {
// 检查映射是否存在
exist, err := dao.DataMapping.GetOne(ctx, &dto.GetDataMappingReq{Id: req.Id})
if err != nil || exist == nil {
return errors.New("映射不存在")
}
// 如果修改了目标字段,检查是否重复
if req.TargetField != "" && req.TargetField != exist.TargetField {
interfaceId := req.InterfaceId
if interfaceId == 0 {
interfaceId = exist.InterfaceId
}
existing, err := dao.DataMapping.GetByInterfaceIdAndTargetField(ctx, interfaceId, req.TargetField)
if err == nil && existing != nil && existing.Id != req.Id {
return errors.New("该接口下目标字段已存在")
}
}
_, err = dao.DataMapping.Update(ctx, req)
return
}
// Delete 删除数据映射
func (s *dataMappingService) Delete(ctx context.Context, req *dto.DeleteDataMappingReq) (err error) {
_, err = dao.DataMapping.Delete(ctx, req)
return
}
// Execute 执行数据映射
func (s *dataMappingService) Execute(ctx context.Context, req *dto.ExecuteDataMappingReq) (res *dto.ExecuteDataMappingRes, err error) {
// 获取接口的所有映射规则
mappings, err := dao.DataMapping.GetByInterfaceId(ctx, req.InterfaceId)
if err != nil {
return nil, err
}
if len(mappings) == 0 {
return &dto.ExecuteDataMappingRes{
TargetData: map[string]interface{}{},
AppliedRules: []string{},
}, nil
}
// 初始化目标数据
targetData := make(map[string]interface{})
appliedRules := make([]string, 0)
// 遍历映射规则进行转换
for _, mapping := range mappings {
if mapping.Status != consts.MappingStatusActive {
continue
}
// 获取源数据值
sourceValue, exists := req.SourceData[mapping.SourceField]
// 应用转换规则
targetValue := s.applyTransformRule(ctx, sourceValue, exists, mapping)
// 设置目标数据
targetData[mapping.TargetField] = targetValue
appliedRules = append(appliedRules, gconv.String(mapping.SourceField)+" -> "+gconv.String(mapping.TargetField))
}
return &dto.ExecuteDataMappingRes{
TargetData: targetData,
AppliedRules: appliedRules,
}, nil
}
// applyTransformRule 应用转换规则
func (s *dataMappingService) applyTransformRule(ctx context.Context, sourceValue interface{}, exists bool, mapping entity.DataMapping) interface{} {
// 如果源字段不存在,使用默认值
if !exists {
if mapping.DefaultValue != "" {
return mapping.DefaultValue
}
return nil
}
// 如果没有转换规则,直接返回源值
if mapping.TransformRule == nil || len(mapping.TransformRule) == 0 {
return sourceValue
}
// 获取转换类型
transformType := ""
if t, ok := mapping.TransformRule["type"].(string); ok {
transformType = t
}
// 根据转换类型应用不同的转换逻辑
switch consts.TransformType(transformType) {
case consts.TransformTypeFixed:
// 固定值
if v, ok := mapping.TransformRule["rule"].(string); ok {
return v
}
case consts.TransformTypeMapping:
// 值映射
if mappingMap, ok := mapping.TransformRule["mappingMap"].(map[string]interface{}); ok {
if sourceKey := gconv.String(sourceValue); sourceKey != "" {
if v, ok := mappingMap[sourceKey]; ok {
return v
}
}
}
case consts.TransformTypeRegex:
// 正则转换
if regex, ok := mapping.TransformRule["regex"].(string); ok {
// TODO: 实现正则替换逻辑
g.Log().Warning(ctx, "正则转换暂未实现", g.Map{
"regex": regex,
"sourceValue": sourceValue,
})
}
case consts.TransformTypeFunction:
// 函数转换
if functionName, ok := mapping.TransformRule["functionName"].(string); ok {
// TODO: 实现函数调用逻辑
g.Log().Warning(ctx, "函数转换暂未实现", g.Map{
"function": functionName,
"sourceValue": sourceValue,
})
}
case consts.TransformTypeScript:
// 脚本转换
if script, ok := mapping.TransformRule["script"].(string); ok {
// TODO: 实现脚本执行逻辑
g.Log().Warning(ctx, "脚本转换暂未实现", g.Map{
"script": script,
"sourceValue": sourceValue,
})
}
}
// 默认返回源值
return sourceValue
}
// getStatusName 获取状态名称
func (s *dataMappingService) getStatusName(status consts.MappingStatus) string {
statusNames := map[consts.MappingStatus]string{
consts.MappingStatusActive: "启用",
consts.MappingStatusInactive: "停用",
}
if name, ok := statusNames[status]; ok {
return name
}
return string(status)
}