代码初始化

This commit is contained in:
2026-04-02 11:51:44 +08:00
commit b87244638f
83 changed files with 13084 additions and 0 deletions

396
service/api_service.go Normal file
View File

@@ -0,0 +1,396 @@
package service
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"math"
"net/http"
"time"
entities "cid/entities"
)
// APIService API服务接口
type APIService interface {
GetCampaignReport(params *entities.RequestParams) (*entities.APIResponse, error)
GetCampaignReportByTimeRange(advertiserID int64, startTime, endTime int64) (*entities.APIResponse, error)
GetAllCampaignReport(params *entities.RequestParams) (*entities.APIResponse, error)
GetAllCampaignReportByTimeRange(advertiserID int64, startTime, endTime int64) (*entities.APIResponse, error)
GetCampaignReportWithCallback(params *entities.RequestParams, callback func(*entities.APIResponse, error) bool) error
}
// KuaishouAPIService 快手API服务实现
type KuaishouAPIService struct {
BaseURL string
AccessToken string
HTTPClient *http.Client
MaxRetries int
RetryDelay time.Duration
RateLimit time.Duration // 请求间隔,避免触发限流
}
// NewKuaishouAPIService 创建API服务实例
func NewKuaishouAPIService(accessToken string) *KuaishouAPIService {
return &KuaishouAPIService{
BaseURL: "https://ad.e.kuaishou.com/rest/openapi/gw/esp/report",
AccessToken: accessToken,
HTTPClient: &http.Client{
Timeout: 30 * time.Second,
},
MaxRetries: 3,
RetryDelay: 2 * time.Second,
RateLimit: 200 * time.Millisecond, // 默认200ms间隔
}
}
// SetRateLimit 设置请求间隔
func (s *KuaishouAPIService) SetRateLimit(delay time.Duration) {
s.RateLimit = delay
}
// GetCampaignReport 获取广告计划报表(单页)
func (s *KuaishouAPIService) GetCampaignReport(params *entities.RequestParams) (*entities.APIResponse, error) {
for retry := 0; retry <= s.MaxRetries; retry++ {
response, err := s.doRequest(params)
if err == nil {
return response, nil
}
// 判断是否重试
if retry < s.MaxRetries {
time.Sleep(s.RetryDelay)
continue
}
return nil, err
}
return nil, fmt.Errorf("请求失败,已达到最大重试次数")
}
// doRequest 执行实际请求
func (s *KuaishouAPIService) doRequest(params *entities.RequestParams) (*entities.APIResponse, error) {
// 序列化请求参数
jsonData, err := json.Marshal(params)
if err != nil {
return nil, fmt.Errorf("序列化失败: %v", err)
}
// 创建HTTP请求
url := fmt.Sprintf("%s/campaignReport", s.BaseURL)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("创建请求失败: %v", err)
}
// 设置请求头
s.setHeaders(req)
// 发送请求
resp, err := s.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("请求失败: %v", err)
}
defer resp.Body.Close()
// 检查HTTP状态码
if resp.StatusCode != http.StatusOK {
body, _ := ioutil.ReadAll(resp.Body)
return nil, fmt.Errorf("HTTP状态码错误: %d, 响应: %s", resp.StatusCode, string(body))
}
// 读取响应
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %v", err)
}
// 解析响应
var apiResponse entities.APIResponse
err = json.Unmarshal(body, &apiResponse)
if err != nil {
return nil, fmt.Errorf("解析响应失败: %v", err)
}
// 检查API返回码
if apiResponse.Code != 0 {
return nil, fmt.Errorf("API返回错误: %s (code: %d)", apiResponse.Message, apiResponse.Code)
}
return &apiResponse, nil
}
// GetAllCampaignReport 获取所有分页数据
func (s *KuaishouAPIService) GetAllCampaignReport(params *entities.RequestParams) (*entities.APIResponse, error) {
// 1. 先获取第一页数据,得到总数
params.ResetPage()
firstPage, err := s.GetCampaignReport(params)
if err != nil {
return nil, fmt.Errorf("获取第一页数据失败: %v", err)
}
if firstPage.Data == nil {
return firstPage, nil // 没有数据
}
totalCount := firstPage.Data.TotalCount
pageSize := params.PageInfo.PageSize
// 2. 如果只有一页,直接返回
if totalCount <= pageSize {
return firstPage, nil
}
// 3. 计算总页数
totalPages := int(math.Ceil(float64(totalCount) / float64(pageSize)))
// 4. 创建结果集
allResponses := make([]*entities.APIResponse, 0, totalPages)
allResponses = append(allResponses, firstPage)
// 5. 并发获取剩余页数据
pageChan := make(chan *pageResult, totalPages-1)
// 启动goroutine获取剩余页
for page := 2; page <= totalPages; page++ {
go func(currentPage int) {
// 复制参数并设置页码
pageParams := *params
pageParams.PageInfo = &entities.PageInfo{
CurrentPage: currentPage,
PageSize: pageSize,
}
response, err := s.GetCampaignReport(&pageParams)
pageChan <- &pageResult{
Page: currentPage,
Response: response,
Error: err,
}
// 控制请求频率
time.Sleep(s.RateLimit)
}(page)
}
// 6. 收集结果
errors := make([]error, 0)
for i := 0; i < totalPages-1; i++ {
result := <-pageChan
if result.Error != nil {
errors = append(errors, fmt.Errorf("第%d页获取失败: %v", result.Page, result.Error))
} else {
allResponses = append(allResponses, result.Response)
}
}
// 7. 合并数据
mergedResponse := entities.MergeData(allResponses)
// 8. 如果有错误,返回错误信息
if len(errors) > 0 {
// 可以记录错误日志,但继续返回已获取的数据
fmt.Printf("部分页面获取失败: %v\n", errors)
}
return mergedResponse, nil
}
// GetAllCampaignReportByTimeRange 根据时间范围获取所有数据
func (s *KuaishouAPIService) GetAllCampaignReportByTimeRange(advertiserID int64, startTime, endTime int64) (*entities.APIResponse, error) {
params := entities.NewRequestParams()
params.AdvertiserID = advertiserID
params.StartTime = startTime
params.EndTime = endTime
return s.GetAllCampaignReport(params)
}
// GetCampaignReportWithCallback 使用回调函数获取所有数据(流式处理,避免内存占用过大)
func (s *KuaishouAPIService) GetCampaignReportWithCallback(params *entities.RequestParams, callback func(*entities.APIResponse, error) bool) error {
// 1. 先获取第一页数据,得到总数
params.ResetPage()
firstPage, err := s.GetCampaignReport(params)
if err != nil {
return fmt.Errorf("获取第一页数据失败: %v", err)
}
// 调用回调处理第一页
if !callback(firstPage, nil) {
return nil // 回调要求停止
}
if firstPage.Data == nil || firstPage.Data.TotalCount <= params.PageInfo.PageSize {
return nil // 只有一页
}
totalCount := firstPage.Data.TotalCount
pageSize := params.PageInfo.PageSize
totalPages := int(math.Ceil(float64(totalCount) / float64(pageSize)))
// 2. 顺序获取剩余页数据避免并发导致API限流
for page := 2; page <= totalPages; page++ {
// 复制参数并设置页码
pageParams := *params
pageParams.PageInfo = &entities.PageInfo{
CurrentPage: page,
PageSize: pageSize,
}
response, err := s.GetCampaignReport(&pageParams)
if !callback(response, err) {
return nil // 回调要求停止
}
// 控制请求频率
time.Sleep(s.RateLimit)
}
return nil
}
// GetCampaignReportSequential 顺序获取所有数据(简单实现)
func (s *KuaishouAPIService) GetCampaignReportSequential(params *entities.RequestParams) (*entities.APIResponse, error) {
// 1. 先获取第一页数据,得到总数
params.ResetPage()
firstPage, err := s.GetCampaignReport(params)
if err != nil {
return nil, fmt.Errorf("获取第一页数据失败: %v", err)
}
if firstPage.Data == nil {
return firstPage, nil
}
totalCount := firstPage.Data.TotalCount
pageSize := params.PageInfo.PageSize
// 2. 如果只有一页,直接返回
if totalCount <= pageSize {
return firstPage, nil
}
// 3. 顺序获取所有数据
allDetails := make([]*entities.ReportDetail, 0, totalCount)
if firstPage.Data.Detail != nil {
allDetails = append(allDetails, firstPage.Data.Detail...)
}
totalPages := int(math.Ceil(float64(totalCount) / float64(pageSize)))
for page := 2; page <= totalPages; page++ {
// 复制参数并设置页码
pageParams := *params
pageParams.PageInfo = &entities.PageInfo{
CurrentPage: page,
PageSize: pageSize,
}
response, err := s.GetCampaignReport(&pageParams)
if err != nil {
// 记录错误但继续获取
fmt.Printf("第%d页获取失败: %v\n", page, err)
continue
}
if response.Data != nil && response.Data.Detail != nil {
allDetails = append(allDetails, response.Data.Detail...)
}
// 控制请求频率
time.Sleep(s.RateLimit)
}
// 4. 构建完整响应
completeResponse := &entities.APIResponse{
Code: firstPage.Code,
Message: firstPage.Message,
Data: &entities.ReportData{
Sum: firstPage.Data.Sum,
Detail: allDetails,
TotalCount: totalCount,
},
}
return completeResponse, nil
}
// setHeaders 设置请求头
func (s *KuaishouAPIService) setHeaders(req *http.Request) {
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
if s.AccessToken != "" {
req.Header.Set("Access-Token", s.AccessToken)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", s.AccessToken))
}
}
// pageResult 分页结果
type pageResult struct {
Page int
Response *entities.APIResponse
Error error
}
// ReportStatistics 报表统计
type ReportStatistics struct {
TotalImpression int64
TotalClick int64
TotalCost float64
TotalGMV float64
TotalT0GMV float64
TotalT0OrderCnt int64
PageCount int
RecordCount int
}
// CalculateStatistics 计算统计信息
func CalculateStatistics(response *entities.APIResponse) *ReportStatistics {
stats := &ReportStatistics{}
if response.Data == nil {
return stats
}
stats.PageCount = 1 // 默认值
stats.RecordCount = response.Data.TotalCount
if response.Data.Detail != nil {
for _, detail := range response.Data.Detail {
stats.TotalImpression += detail.Impression
stats.TotalClick += detail.Click
stats.TotalCost += detail.CostTotal
stats.TotalGMV += detail.GMV
stats.TotalT0GMV += detail.T0GMV
stats.TotalT0OrderCnt += detail.T0OrderCnt
}
}
return stats
}
// GetAverageMetrics 获取平均指标
func (stats *ReportStatistics) GetAverageMetrics() map[string]float64 {
metrics := make(map[string]float64)
if stats.TotalImpression > 0 {
metrics["ctr"] = float64(stats.TotalClick) / float64(stats.TotalImpression) * 100
}
if stats.TotalClick > 0 {
metrics["cpc"] = stats.TotalCost / float64(stats.TotalClick)
}
if stats.TotalCost > 0 {
metrics["roi"] = stats.TotalGMV / stats.TotalCost
metrics["t0_roi"] = stats.TotalT0GMV / stats.TotalCost
}
if stats.TotalImpression > 0 {
metrics["cpm"] = stats.TotalCost / float64(stats.TotalImpression) * 1000
}
return metrics
}

View File

@@ -0,0 +1,113 @@
package copydata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
"context"
"errors"
"gitea.com/red-future/common/beans"
)
type cidAccountReportDetailService struct{}
// CidAccountReportDetail 广告数据报表详情服务
var CidAccountReportDetail = new(cidAccountReportDetailService)
// Create 创建广告数据报表详情
func (s *cidAccountReportDetailService) Create(ctx context.Context, req *dto.CidAccountReportDetailItem) (res *dto.CreateCidAccountReportDetailRes, err error) {
// 验证必要字段
if req.DataType == "" {
return nil, errors.New("数据类型不能为空")
}
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
// 插入数据库
id, err := dao.CidAccountReportDetail.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateCidAccountReportDetailRes{
Id: id,
}
return
}
// BatchCreate 批量创建广告数据报表详情
func (s *cidAccountReportDetailService) BatchCreate(ctx context.Context, req *dto.BatchCreateCidAccountReportDetailReq) (res *dto.BatchCreateCidAccountReportDetailRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
//// 验证每条数据
//for i, item := range req.Items {
// if item.DataType == "" {
// return nil, errors.New("第" + string(rune(i+1)) + "条数据的数据类型不能为空")
// }
// if item.ReportDateStr == "" {
// return nil, errors.New("第" + string(rune(i+1)) + "条数据的报告日期不能为空")
// }
//}
// 批量插入数据库
successCount, failCount, failedIndexes, err := dao.CidAccountReportDetail.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateCidAccountReportDetailRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}
// Create 创建广告数据报表汇总
func (s *cidAccountReportDetailService) CreateSum(ctx context.Context, req *dto.CidAccountReportSumItem) (res *dto.CreateCidAccountReportSumRes, err error) {
// 验证必要字段
if req.DataType == "" {
return nil, errors.New("数据类型不能为空")
}
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
// 插入数据库
id, err := dao.CidAccountReportSum.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateCidAccountReportSumRes{
Id: id,
}
return
}
// BatchCreate 批量创建广告数据报表汇总
func (s *cidAccountReportDetailService) BatchCreateSum(ctx context.Context, req *dto.BatchCreateCidAccountReportSumReq) (res *dto.BatchCreateCidAccountReportSumRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
// 批量插入数据库
successCount, failCount, failedIndexes, err := dao.CidAccountReportSum.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateCidAccountReportSumRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}

View File

@@ -0,0 +1,91 @@
package copydata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
"context"
"errors"
"gitea.com/red-future/common/beans"
)
type creativeReportSumService struct{}
// CreativeReportSum 广告效果指标表服务
var CreativeReportSum = new(creativeReportSumService)
// Create 创建广告效果指标表
func (s *creativeReportSumService) Create(ctx context.Context, req *dto.CreativeReportSumItem) (res *dto.CreateCreativeReportSumRes, err error) {
// 验证必要字段
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
// 插入数据库
id, err := dao.CreativeReportSum.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateCreativeReportSumRes{
Id: id,
}
return
}
// BatchCreate 批量创建广告效果指标表
func (s *creativeReportSumService) BatchCreate(ctx context.Context, req *dto.BatchCreateCreativeReportSumReq) (res *dto.BatchCreateCreativeReportSumRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
// 批量插入数据库
successCount, failCount, failedIndexes, err := dao.CreativeReportSum.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateCreativeReportSumRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}
func (s *creativeReportSumService) CreateDetail(ctx context.Context, req *dto.CreativeReportDetailItem) (res *dto.CreateCreativeReportDetailRes, err error) {
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
id, err := dao.CreativeReportDetail.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateCreativeReportDetailRes{
Id: id,
}
return
}
func (s *creativeReportSumService) BatchCreateDetail(ctx context.Context, req *dto.BatchCreateCreativeReportDetailReq) (res *dto.BatchCreateCreativeReportDetailRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
successCount, failCount, failedIndexes, err := dao.CreativeReportDetail.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateCreativeReportDetailRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}

View File

@@ -0,0 +1,261 @@
package copydata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
entity "cid/model/entity/copydata"
"context"
"errors"
"gitea.com/red-future/common/beans"
)
type materialReportService struct{}
// MaterialReport 素材报表数据服务
var MaterialReport = new(materialReportService)
// Create 创建素材报表数据
func (s *materialReportService) Create(ctx context.Context, req *dto.MaterialReportItem) (res *dto.CreateMaterialReportRes, err error) {
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
id, err := dao.MaterialReport.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateMaterialReportRes{
Id: id,
}
return
}
// BatchCreate 批量创建素材报表数据
func (s *materialReportService) BatchCreate(ctx context.Context, req *dto.BatchCreateMaterialReportReq) (res *dto.BatchCreateMaterialReportRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
successCount, failCount, failedIndexes, err := dao.MaterialReport.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateMaterialReportRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}
// List 获取素材报表数据列表
func (s *materialReportService) List(ctx context.Context, req *dto.ListMaterialReportReq) (res *dto.ListMaterialReportRes, err error) {
list, total, err := dao.MaterialReport.List(ctx, req)
if err != nil {
return nil, err
}
items := make([]*dto.MaterialReportItem, len(list))
for i, item := range list {
items[i] = convertMaterialEntityToDTO(item)
}
res = &dto.ListMaterialReportRes{
List: items,
Total: total,
}
return
}
// convertEntityToDTO 将实体转换为 DTO
func convertMaterialEntityToDTO(entity *entity.MaterialReport) *dto.MaterialReportItem {
return &dto.MaterialReportItem{
CreatedBy: entity.CreatedBy,
UpdatedBy: entity.UpdatedBy,
T0OrderPaymentAmt: entity.T0OrderPaymentAmt,
CreativeMaterialType: entity.CreativeMaterialType,
LiveName: entity.LiveName,
AuthorId: entity.AuthorId,
PicUrl: entity.PicUrl,
PicName: entity.PicName,
PicId: entity.PicId,
CoverUrl: entity.CoverUrl,
CoverId: entity.CoverId,
ItemOrderConversionRatio: entity.ItemOrderConversionRatio,
ItemCardClickRatio: entity.ItemCardClickRatio,
ItemCardClkCnt: entity.ItemCardClkCnt,
LivePlayCntCost: entity.LivePlayCntCost,
AdMerchantFollowCost: entity.AdMerchantFollowCost,
AdMerchantFollow: entity.AdMerchantFollow,
NetT0OrderCnt: entity.NetT0OrderCnt,
NetT0Roi: entity.NetT0Roi,
NetT0Gmv: entity.NetT0Gmv,
PhotoName: entity.PhotoName,
PhotoIdStr: entity.PhotoIdStr,
PhotoId: entity.PhotoId,
ModPriceSegment: entity.ModPriceSegment,
AgeSegment: entity.AgeSegment,
Province: entity.Province,
Gender: entity.Gender,
AdPhotoPlayedFiveRatio: entity.AdPhotoPlayedFiveRatio,
AdPhotoPlayedThreeRatio: entity.AdPhotoPlayedThreeRatio,
OrderSubmitRoi: entity.OrderSubmitRoi,
OrderSubmitAmt: entity.OrderSubmitAmt,
EventOrderSubmitCost: entity.EventOrderSubmitCost,
EventOrderSubmit: entity.EventOrderSubmit,
EventOrderPaidRoi: entity.EventOrderPaidRoi,
EventAppInvoked: entity.EventAppInvoked,
EventAddShoppingCart: entity.EventAddShoppingCart,
ConversionNumCost: entity.ConversionNumCost,
AdEffectivePlayNum: entity.AdEffectivePlayNum,
AdItemClick: entity.AdItemClick,
MerchantProductId: entity.MerchantProductId,
CostTotal: entity.CostTotal,
AdShow: entity.AdShow,
AdShow1kCost: entity.AdShow1kCost,
Impression: entity.Impression,
PhotoClick: entity.PhotoClick,
PhotoClickRatio: entity.PhotoClickRatio,
Click: entity.Click,
ActionbarClick: entity.ActionbarClick,
ActionbarClickCost: entity.ActionbarClickCost,
EspClickRatio: entity.EspClickRatio,
ActionRatio: entity.ActionRatio,
AdItemCount: entity.AdItemCount,
EspLivePlayedSeconds: entity.EspLivePlayedSeconds,
PlayedThreeSeconds: entity.PlayedThreeSeconds,
Play3sRatio: entity.Play3sRatio,
PlayedFiveSeconds: entity.PlayedFiveSeconds,
Play5sRatio: entity.Play5sRatio,
PlayedEnd: entity.PlayedEnd,
PlayEndRatio: entity.PlayEndRatio,
Share: entity.Share,
Comment: entity.Comment,
Likes: entity.Likes,
Report: entity.Report,
Block: entity.Block,
ItemNegative: entity.ItemNegative,
LiveShare: entity.LiveShare,
LiveComment: entity.LiveComment,
LiveReward: entity.LiveReward,
EffectivePlayCount: entity.EffectivePlayCount,
EffectivePlayRatio: entity.EffectivePlayRatio,
ConversionNum: entity.ConversionNum,
ConversionCostEsp: entity.ConversionCostEsp,
Roi: entity.Roi,
Gmv: entity.Gmv,
T0Gmv: entity.T0Gmv,
T1Gmv: entity.T1Gmv,
T7Gmv: entity.T7Gmv,
T15Gmv: entity.T15Gmv,
T30Gmv: entity.T30Gmv,
T0Roi: entity.T0Roi,
T1Roi: entity.T1Roi,
T7Roi: entity.T7Roi,
T15Roi: entity.T15Roi,
T30Roi: entity.T30Roi,
PaiedOrder: entity.PaiedOrder,
OrderRatio: entity.OrderRatio,
T0OrderCnt: entity.T0OrderCnt,
T0OrderCntCost: entity.T0OrderCntCost,
T0OrderCntRatio: entity.T0OrderCntRatio,
T1OrderCnt: entity.T1OrderCnt,
T7OrderCnt: entity.T7OrderCnt,
T15OrderCnt: entity.T15OrderCnt,
T30OrderCnt: entity.T30OrderCnt,
MerchantRecoFans: entity.MerchantRecoFans,
T1Retention: entity.T1Retention,
T7Retention: entity.T7Retention,
T15Retention: entity.T15Retention,
T30Retention: entity.T30Retention,
T1RetentionRatio: entity.T1RetentionRatio,
T7RetentionRatio: entity.T7RetentionRatio,
T15RetentionRatio: entity.T15RetentionRatio,
T30RetentionRatio: entity.T30RetentionRatio,
ReservationSuccess: entity.ReservationSuccess,
ReservationCost: entity.ReservationCost,
StandardLivePlayedStarted: entity.StandardLivePlayedStarted,
AdLivePlayCnt: entity.AdLivePlayCnt,
AdLivePlayCntCost: entity.AdLivePlayCntCost,
LiveAudienceCost: entity.LiveAudienceCost,
LiveEventGoodsView: entity.LiveEventGoodsView,
GoodsClickRatio: entity.GoodsClickRatio,
DirectAttrPlatNewBuyerCnt: entity.DirectAttrPlatNewBuyerCnt,
T30AttrPlatTotalBuyerCnt: entity.T30AttrPlatTotalBuyerCnt,
DirectAttrSellerNewBuyerCnt: entity.DirectAttrSellerNewBuyerCnt,
T30AttrSellerTotalBuyerCnt: entity.T30AttrSellerTotalBuyerCnt,
T3Gmv: entity.T3Gmv,
T3OrderCnt: entity.T3OrderCnt,
T3Roi: entity.T3Roi,
T7IndirectOrderAmt: entity.T7IndirectOrderAmt,
T7IndirectOrderCnt: entity.T7IndirectOrderCnt,
FansT0GmvPerFans: entity.FansT0GmvPerFans,
FansT3GmvPerFans: entity.FansT3GmvPerFans,
FansT7GmvPerFans: entity.FansT7GmvPerFans,
FansT15GmvPerFans: entity.FansT15GmvPerFans,
FansT30GmvPerFans: entity.FansT30GmvPerFans,
RecoFansCost: entity.RecoFansCost,
QcpxWhiteboxDirectOrderPaymentAmt: entity.QcpxWhiteboxDirectOrderPaymentAmt,
QcpxWhiteboxDirectOrderCnt: entity.QcpxWhiteboxDirectOrderCnt,
FansT0Gmv: entity.FansT0Gmv,
FansT1Gmv: entity.FansT1Gmv,
FansT7Gmv: entity.FansT7Gmv,
FansT15Gmv: entity.FansT15Gmv,
FansT30Gmv: entity.FansT30Gmv,
FansT0Roi: entity.FansT0Roi,
FansT1Roi: entity.FansT1Roi,
FansT7Roi: entity.FansT7Roi,
FansT15Roi: entity.FansT15Roi,
FansT30Roi: entity.FansT30Roi,
T0ShopNewBuyerOrderPaymentAmt: entity.T0ShopNewBuyerOrderPaymentAmt,
T1ShopNewBuyerOrderPaymentAmt: entity.T1ShopNewBuyerOrderPaymentAmt,
T3ShopNewBuyerOrderPaymentAmt: entity.T3ShopNewBuyerOrderPaymentAmt,
T7ShopNewBuyerOrderPaymentAmt: entity.T7ShopNewBuyerOrderPaymentAmt,
T15ShopNewBuyerOrderPaymentAmt: entity.T15ShopNewBuyerOrderPaymentAmt,
T30ShopNewBuyerOrderPaymentAmt: entity.T30ShopNewBuyerOrderPaymentAmt,
T0ShopNewBuyerOrderCnt: entity.T0ShopNewBuyerOrderCnt,
T1ShopNewBuyerOrderCnt: entity.T1ShopNewBuyerOrderCnt,
T3ShopNewBuyerOrderCnt: entity.T3ShopNewBuyerOrderCnt,
T7ShopNewBuyerOrderCnt: entity.T7ShopNewBuyerOrderCnt,
T15ShopNewBuyerOrderCnt: entity.T15ShopNewBuyerOrderCnt,
T30ShopNewBuyerOrderCnt: entity.T30ShopNewBuyerOrderCnt,
T1NewBuyerRepurchaseRatio: entity.T1NewBuyerRepurchaseRatio,
T3NewBuyerRepurchaseRatio: entity.T3NewBuyerRepurchaseRatio,
T7NewBuyerRepurchaseRatio: entity.T7NewBuyerRepurchaseRatio,
T15NewBuyerRepurchaseRatio: entity.T15NewBuyerRepurchaseRatio,
T30NewBuyerRepurchaseRatio: entity.T30NewBuyerRepurchaseRatio,
T0ShopNewBuyerRoi: entity.T0ShopNewBuyerRoi,
T1ShopNewBuyerRoi: entity.T1ShopNewBuyerRoi,
T3ShopNewBuyerRoi: entity.T3ShopNewBuyerRoi,
T7ShopNewBuyerRoi: entity.T7ShopNewBuyerRoi,
T15ShopNewBuyerRoi: entity.T15ShopNewBuyerRoi,
T30ShopNewBuyerRoi: entity.T30ShopNewBuyerRoi,
CreateCardOrderCnt: entity.CreateCardOrderCnt,
ForwardTsCreateCardOrderCnt: entity.ForwardTsCreateCardOrderCnt,
CreateCardOrderCost: entity.CreateCardOrderCost,
ForwardTsCreateCardOrderCost: entity.ForwardTsCreateCardOrderCost,
ActivateCardOrderCnt: entity.ActivateCardOrderCnt,
ForwardTsActivateCardOrderCnt: entity.ForwardTsActivateCardOrderCnt,
ActivateCardOrderCost: entity.ActivateCardOrderCost,
ForwardTsActivateCardOrderCost: entity.ForwardTsActivateCardOrderCost,
CreateCardOrderRatio: entity.CreateCardOrderRatio,
ForwardTsCreateCardOrderRatio: entity.ForwardTsCreateCardOrderRatio,
ActivateCardOrderCntRatio: entity.ActivateCardOrderCntRatio,
ForwardTsActivateCardOrderRatio: entity.ForwardTsActivateCardOrderRatio,
LivePlayCnt: entity.LivePlayCnt,
ItemEntranceClkCnt: entity.ItemEntranceClkCnt,
ShowCnt: entity.ShowCnt,
ReportDateStr: entity.ReportDateStr,
CampaignId: entity.CampaignId,
CampaignName: entity.CampaignName,
UnitId: entity.UnitId,
UnitName: entity.UnitName,
CreativeId: entity.CreativeId,
CreativeName: entity.CreativeName,
}
}

View File

@@ -0,0 +1,237 @@
package copydata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
entity "cid/model/entity/copydata"
"context"
"errors"
)
var PopulationReportService = new(populationReportService)
type populationReportService struct{}
// Create 创建人群报表数据
func (s *populationReportService) Create(ctx context.Context, req *dto.PopulationReportItem) (*dto.CreatePopulationReportRes, error) {
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
id, err := dao.PopulationReport.Insert(ctx, req)
if err != nil {
return nil, err
}
return &dto.CreatePopulationReportRes{Id: id}, nil
}
// BatchCreate 批量创建人群报表数据
func (s *populationReportService) BatchCreate(ctx context.Context, req []*dto.PopulationReportItem) (*dto.BatchCreatePopulationReportRes, error) {
if len(req) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
successCount, failCount, failedIndexes, err := dao.PopulationReport.BatchInsert(ctx, req)
if err != nil {
return nil, err
}
return &dto.BatchCreatePopulationReportRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}, nil
}
// List 查询人群报表数据列表
func (s *populationReportService) List(ctx context.Context, req *dto.ListPopulationReportReq) (*dto.ListPopulationReportRes, error) {
list, total, err := dao.PopulationReport.List(ctx, req)
if err != nil {
return nil, err
}
// 转换为 DTO
items := s.convertToDTOs(list)
return &dto.ListPopulationReportRes{
List: items,
Total: total,
}, nil
}
// convertToDTOs 将实体列表转换为 DTO 列表
func (s *populationReportService) convertToDTOs(entities []*entity.PopulationReport) []*dto.PopulationReportItem {
items := make([]*dto.PopulationReportItem, 0, len(entities))
for _, e := range entities {
items = append(items, s.convertToDTO(e))
}
return items
}
// convertToDTO 将实体转换为 DTO
func (s *populationReportService) convertToDTO(e *entity.PopulationReport) *dto.PopulationReportItem {
return &dto.PopulationReportItem{
PhotoName: e.PhotoName,
PhotoIdStr: e.PhotoIdStr,
PhotoId: e.PhotoId,
ModPriceSegment: e.ModPriceSegment,
AgeSegment: e.AgeSegment,
Province: e.Province,
Gender: e.Gender,
MerchantProductId: e.MerchantProductId,
ReportDateStr: e.ReportDateStr,
CampaignId: e.CampaignId,
CampaignName: e.CampaignName,
UnitId: e.UnitId,
UnitName: e.UnitName,
CreativeId: e.CreativeId,
CreativeName: e.CreativeName,
AdPhotoPlayedFiveRatio: e.AdPhotoPlayedFiveRatio,
AdPhotoPlayedThreeRatio: e.AdPhotoPlayedThreeRatio,
OrderSubmitRoi: e.OrderSubmitRoi,
OrderSubmitAmt: e.OrderSubmitAmt,
EventOrderSubmitCost: e.EventOrderSubmitCost,
EventOrderSubmit: e.EventOrderSubmit,
EventOrderPaidRoi: e.EventOrderPaidRoi,
EventAppInvoked: e.EventAppInvoked,
EventAddShoppingCart: e.EventAddShoppingCart,
ConversionNumCost: e.ConversionNumCost,
AdEffectivePlayNum: e.AdEffectivePlayNum,
AdItemClick: e.AdItemClick,
CostTotal: e.CostTotal,
AdShow: e.AdShow,
AdShow1kCost: e.AdShow1kCost,
Impression: e.Impression,
PhotoClick: e.PhotoClick,
PhotoClickRatio: e.PhotoClickRatio,
Click: e.Click,
ActionbarClick: e.ActionbarClick,
ActionbarClickCost: e.ActionbarClickCost,
EspClickRatio: e.EspClickRatio,
ActionRatio: e.ActionRatio,
AdItemClickCount: e.AdItemClickCount,
EspLivePlayedSeconds: e.EspLivePlayedSeconds,
PlayedThreeSeconds: e.PlayedThreeSeconds,
Play3sRatio: e.Play3sRatio,
PlayedFiveSeconds: e.PlayedFiveSeconds,
Play5sRatio: e.Play5sRatio,
PlayedEnd: e.PlayedEnd,
PlayEndRatio: e.PlayEndRatio,
Share: e.Share,
Comment: e.Comment,
Likes: e.Likes,
Report: e.Report,
Block: e.Block,
ItemNegative: e.ItemNegative,
LiveShare: e.LiveShare,
LiveComment: e.LiveComment,
LiveReward: e.LiveReward,
EffectivePlayCount: e.EffectivePlayCount,
EffectivePlayRatio: e.EffectivePlayRatio,
ConversionNum: e.ConversionNum,
ConversionCostEsp: e.ConversionCostEsp,
Roi: e.Roi,
Gmv: e.Gmv,
T0Gmv: e.T0Gmv,
T1Gmv: e.T1Gmv,
T3Gmv: e.T3Gmv,
T7Gmv: e.T7Gmv,
T15Gmv: e.T15Gmv,
T30Gmv: e.T30Gmv,
T0Roi: e.T0Roi,
T1Roi: e.T1Roi,
T3Roi: e.T3Roi,
T7Roi: e.T7Roi,
T15Roi: e.T15Roi,
T30Roi: e.T30Roi,
PaiedOrder: e.PaiedOrder,
OrderRatio: e.OrderRatio,
T0OrderCnt: e.T0OrderCnt,
T0OrderCntCost: e.T0OrderCntCost,
T0OrderCntRatio: e.T0OrderCntRatio,
T1OrderCnt: e.T1OrderCnt,
T7OrderCnt: e.T7OrderCnt,
T15OrderCnt: e.T15OrderCnt,
T30OrderCnt: e.T30OrderCnt,
MerchantRecoFans: e.MerchantRecoFans,
T1Retention: e.T1Retention,
T7Retention: e.T7Retention,
T15Retention: e.T15Retention,
T30Retention: e.T30Retention,
T1RetentionRatio: e.T1RetentionRatio,
T7RetentionRatio: e.T7RetentionRatio,
T15RetentionRatio: e.T15RetentionRatio,
T30RetentionRatio: e.T30RetentionRatio,
ReservationSuccess: e.ReservationSuccess,
ReservationCost: e.ReservationCost,
StandardLivePlayedStarted: e.StandardLivePlayedStarted,
AdLivePlayCnt: e.AdLivePlayCnt,
AdLivePlayCntCost: e.AdLivePlayCntCost,
LiveAudienceCost: e.LiveAudienceCost,
LiveEventGoodsView: e.LiveEventGoodsView,
GoodsClickRatio: e.GoodsClickRatio,
DirectAttrPlatNewBuyerCnt: e.DirectAttrPlatNewBuyerCnt,
T30AttrPlatTotalBuyerCnt: e.T30AttrPlatTotalBuyerCnt,
DirectAttrSellerNewBuyerCnt: e.DirectAttrSellerNewBuyerCnt,
T30AttrSellerTotalBuyerCnt: e.T30AttrSellerTotalBuyerCnt,
T7IndirectOrderAmt: e.T7IndirectOrderAmt,
T7IndirectOrderCnt: e.T7IndirectOrderCnt,
FansT0GmvPerFans: e.FansT0GmvPerFans,
FansT3GmvPerFans: e.FansT3GmvPerFans,
FansT7GmvPerFans: e.FansT7GmvPerFans,
FansT15GmvPerFans: e.FansT15GmvPerFans,
FansT30GmvPerFans: e.FansT30GmvPerFans,
RecoFansCost: e.RecoFansCost,
QcpxWhiteboxDirectOrderPaymentAmt: e.QcpxWhiteboxDirectOrderPaymentAmt,
QcpxWhiteboxDirectOrderCnt: e.QcpxWhiteboxDirectOrderCnt,
FansT0Gmv: e.FansT0Gmv,
FansT1Gmv: e.FansT1Gmv,
FansT7Gmv: e.FansT7Gmv,
FansT15Gmv: e.FansT15Gmv,
FansT30Gmv: e.FansT30Gmv,
FansT0Roi: e.FansT0Roi,
FansT1Roi: e.FansT1Roi,
FansT7Roi: e.FansT7Roi,
FansT15Roi: e.FansT15Roi,
FansT30Roi: e.FansT30Roi,
T0ShopNewBuyerOrderPaymentAmt: e.T0ShopNewBuyerOrderPaymentAmt,
T1ShopNewBuyerOrderPaymentAmt: e.T1ShopNewBuyerOrderPaymentAmt,
T3ShopNewBuyerOrderPaymentAmt: e.T3ShopNewBuyerOrderPaymentAmt,
T7ShopNewBuyerOrderPaymentAmt: e.T7ShopNewBuyerOrderPaymentAmt,
T15ShopNewBuyerOrderPaymentAmt: e.T15ShopNewBuyerOrderPaymentAmt,
T30ShopNewBuyerOrderPaymentAmt: e.T30ShopNewBuyerOrderPaymentAmt,
T0ShopNewBuyerOrderCnt: e.T0ShopNewBuyerOrderCnt,
T1ShopNewBuyerOrderCnt: e.T1ShopNewBuyerOrderCnt,
T3ShopNewBuyerOrderCnt: e.T3ShopNewBuyerOrderCnt,
T7ShopNewBuyerOrderCnt: e.T7ShopNewBuyerOrderCnt,
T15ShopNewBuyerOrderCnt: e.T15ShopNewBuyerOrderCnt,
T30ShopNewBuyerOrderCnt: e.T30ShopNewBuyerOrderCnt,
T1NewBuyerRepurchaseRatio: e.T1NewBuyerRepurchaseRatio,
T3NewBuyerRepurchaseRatio: e.T3NewBuyerRepurchaseRatio,
T7NewBuyerRepurchaseRatio: e.T7NewBuyerRepurchaseRatio,
T15NewBuyerRepurchaseRatio: e.T15NewBuyerRepurchaseRatio,
T30NewBuyerRepurchaseRatio: e.T30NewBuyerRepurchaseRatio,
T0ShopNewBuyerRoi: e.T0ShopNewBuyerRoi,
T1ShopNewBuyerRoi: e.T1ShopNewBuyerRoi,
T3ShopNewBuyerRoi: e.T3ShopNewBuyerRoi,
T7ShopNewBuyerRoi: e.T7ShopNewBuyerRoi,
T15ShopNewBuyerRoi: e.T15ShopNewBuyerRoi,
T30ShopNewBuyerRoi: e.T30ShopNewBuyerRoi,
CreateCardOrderCnt: e.CreateCardOrderCnt,
ForwardTsCreateCardOrderCnt: e.ForwardTsCreateCardOrderCnt,
CreateCardOrderCost: e.CreateCardOrderCost,
ForwardTsCreateCardOrderCost: e.ForwardTsCreateCardOrderCost,
ActivateCardOrderCnt: e.ActivateCardOrderCnt,
ForwardTsActivateCardOrderCnt: e.ForwardTsActivateCardOrderCnt,
ActivateCardOrderCost: e.ActivateCardOrderCost,
ForwardTsActivateCardOrderCost: e.ForwardTsActivateCardOrderCost,
CreateCardOrderRatio: e.CreateCardOrderRatio,
ForwardTsCreateCardOrderRatio: e.ForwardTsCreateCardOrderRatio,
ActivateCardOrderCntRatio: e.ActivateCardOrderCntRatio,
ForwardTsActivateCardOrderRatio: e.ForwardTsActivateCardOrderRatio,
LivePlayCnt: e.LivePlayCnt,
ItemEntranceClkCnt: e.ItemEntranceClkCnt,
ShowCnt: e.ShowCnt,
}
}

View File

@@ -0,0 +1,97 @@
package copydata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
"context"
"errors"
"gitea.com/red-future/common/beans"
)
type storewideReportService struct{}
// StorewideReportSum 广告效果指标表服务
var StorewideReportSum = new(storewideReportService)
// Create 创建广告效果指标表
func (s *storewideReportService) Create(ctx context.Context, req *dto.StorewideReportSumItem) (res *dto.CreateStorewideReportSumRes, err error) {
// 验证必要字段
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
// 插入数据库
id, err := dao.StorewideReportSum.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateStorewideReportSumRes{
Id: id,
}
return
}
// BatchCreate 批量创建广告效果指标表
func (s *storewideReportService) BatchCreate(ctx context.Context, req *dto.BatchCreateStorewideReportSumReq) (res *dto.BatchCreateStorewideReportSumRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
// 批量插入数据库
successCount, failCount, failedIndexes, err := dao.StorewideReportSum.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateStorewideReportSumRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}
// Create 创建广告效果指标表
func (s *storewideReportService) CreateDetail(ctx context.Context, req *dto.StorewideReportDetailItem) (res *dto.CreateStorewideReportDetailRes, err error) {
// 验证必要字段
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
// 插入数据库
id, err := dao.StorewideReportDetail.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateStorewideReportDetailRes{
Id: id,
}
return
}
// BatchCreate 批量创建广告效果指标表
func (s *storewideReportService) BatchCreateDetail(ctx context.Context, req *dto.BatchCreateStorewideReportDetailReq) (res *dto.BatchCreateStorewideReportDetailRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
// 批量插入数据库
successCount, failCount, failedIndexes, err := dao.StorewideReportDetail.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateStorewideReportDetailRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}

View File

@@ -0,0 +1,113 @@
package copydata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
entity "cid/model/entity/copydata"
"context"
"errors"
"gitea.com/red-future/common/beans"
)
type taskReportService struct{}
// TaskReport 调控任务数据服务
var TaskReport = new(taskReportService)
// Create 创建调控任务数据
func (s *taskReportService) Create(ctx context.Context, req *dto.TaskReportItem) (res *dto.CreateTaskReportRes, err error) {
// 验证必要字段
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
// 插入数据库
id, err := dao.TaskReport.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateTaskReportRes{
Id: id,
}
return
}
// BatchCreate 批量创建调控任务数据
func (s *taskReportService) BatchCreate(ctx context.Context, req *dto.BatchCreateTaskReportReq) (res *dto.BatchCreateTaskReportRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
// 验证数据
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
// 批量插入数据库
successCount, failCount, failedIndexes, err := dao.TaskReport.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateTaskReportRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}
// List 获取调控任务数据列表
func (s *taskReportService) List(ctx context.Context, req *dto.ListTaskReportReq) (res *dto.ListTaskReportRes, err error) {
list, total, err := dao.TaskReport.List(ctx, req)
if err != nil {
return nil, err
}
// 转换为 DTO 格式
items := make([]*dto.TaskReportItem, len(list))
for i, item := range list {
items[i] = convertEntityToDTO(item)
}
res = &dto.ListTaskReportRes{
List: items,
Total: total,
}
return
}
// convertEntityToDTO 将实体转换为 DTO
func convertEntityToDTO(entity *entity.TaskReport) *dto.TaskReportItem {
return &dto.TaskReportItem{
ItemOrderConversionRatio: entity.ItemOrderConversionRatio,
ItemCardClickRatio: entity.ItemCardClickRatio,
ItemCardClkCnt: entity.ItemCardClkCnt,
LivePlayCntCost: entity.LivePlayCntCost,
AdMerchantFollowCost: entity.AdMerchantFollowCost,
AdMerchantFollow: entity.AdMerchantFollow,
NetT0OrderCnt: entity.NetT0OrderCnt,
NetT0Roi: entity.NetT0Roi,
NetT0Gmv: entity.NetT0Gmv,
PhotoName: entity.PhotoName,
PhotoId: entity.PhotoId,
CostTotal: entity.CostTotal,
T0Gmv: entity.T0Gmv,
T0Roi: entity.T0Roi,
T0OrderCnt: entity.T0OrderCnt,
T0OrderCntCost: entity.T0OrderCntCost,
FansT0Gmv: entity.FansT0Gmv,
FansT1Gmv: entity.FansT1Gmv,
FansT7Gmv: entity.FansT7Gmv,
FansT15Gmv: entity.FansT15Gmv,
FansT30Gmv: entity.FansT30Gmv,
FansT0Roi: entity.FansT0Roi,
FansT1Roi: entity.FansT1Roi,
FansT7Roi: entity.FansT7Roi,
FansT15Roi: entity.FansT15Roi,
FansT30Roi: entity.FansT30Roi,
LivePlayCnt: entity.LivePlayCnt,
ItemEntranceClkCnt: entity.ItemEntranceClkCnt,
ShowCnt: entity.ShowCnt,
ReportDateStr: entity.ReportDateStr,
}
}

View File

@@ -0,0 +1,90 @@
package copydata
import (
dao "cid/dao/copydata"
dto "cid/model/dto/copydata"
"context"
"errors"
"gitea.com/red-future/common/beans"
)
type unitReportSumService struct{}
// UnitReportSumService 广告效果指标服务
var UnitReportSumService = new(unitReportSumService)
// Create 创建广告效果指标
func (s *unitReportSumService) Create(ctx context.Context, req *dto.UnitReportSumItem) (res *dto.CreateUnitReportSumRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
id, err := dao.UnitReportSum.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateUnitReportSumRes{
Id: id,
}
return
}
// BatchCreate 批量创建广告效果指标
func (s *unitReportSumService) BatchCreate(ctx context.Context, req *dto.BatchCreateUnitReportSumReq) (res *dto.BatchCreateUnitReportSumRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
successCount, failCount, failedIndexes, err := dao.UnitReportSum.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateUnitReportSumRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}
// Create 创建广告效果指标详情
func (s *unitReportSumService) CreateDetail(ctx context.Context, req *dto.UnitReportDetailItem) (res *dto.CreateUnitReportDetailRes, err error) {
if req.ReportDateStr == "" {
return nil, errors.New("报告日期不能为空")
}
id, err := dao.UnitReportDetail.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateUnitReportDetailRes{
Id: id,
}
return
}
// BatchCreate 批量创建广告效果指标详情
func (s *unitReportSumService) BatchCreateDetail(ctx context.Context, req *dto.BatchCreateUnitReportDetailReq) (res *dto.BatchCreateUnitReportDetailRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
if len(req.Items) == 0 {
return nil, errors.New("批量创建数据不能为空")
}
successCount, failCount, failedIndexes, err := dao.UnitReportDetail.BatchInsert(ctx, req.Items)
if err != nil {
return nil, err
}
res = &dto.BatchCreateUnitReportDetailRes{
SuccessCount: successCount,
FailCount: failCount,
FailedItems: failedIndexes,
}
return
}

View File

@@ -0,0 +1,305 @@
package dict
import (
api_feature "cid/consts/api-feature"
dao "cid/dao/dict"
dto "cid/model/dto/dict"
entity "cid/model/entity/dict"
"context"
"strconv"
"time"
"github.com/gogf/gf/v2/util/gconv"
"github.com/olekukonko/errors"
)
type datasourcePlatformService struct{}
// DatasourcePlatform 数据源平台服务
var DatasourcePlatform = new(datasourcePlatformService)
// Create 创建数据源平台
func (s *datasourcePlatformService) Create(ctx context.Context, req *dto.CreateDatasourcePlatformReq) (res *dto.CreateDatasourcePlatformRes, err error) {
// 检查平台编码是否重复
exists, err := dao.DatasourcePlatform.ExistsByPlatformCode(ctx, req.PlatformCode)
if err != nil {
return nil, err
}
if exists {
return nil, errors.New("平台编码已存在")
}
// 验证认证类型相关的必填字段
if err = s.validateAuthFields(req); err != nil {
return nil, err
}
// 设置创建时间为当前时间
if req.CreatedAt == "" {
req.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
}
req.UpdatedAt = req.CreatedAt
// 插入数据库
id, err := dao.DatasourcePlatform.Insert(ctx, req)
if err != nil {
return nil, err
}
res = &dto.CreateDatasourcePlatformRes{
Id: id,
}
return res, nil
}
// List 获取数据源平台列表
func (s *datasourcePlatformService) List(ctx context.Context, req *dto.ListDatasourcePlatformReq) (res *dto.ListDatasourcePlatformRes, err error) {
platformList, total, err := dao.DatasourcePlatform.List(ctx, req)
if err != nil {
return nil, err
}
// 组装响应数据
list := make([]dto.DatasourcePlatformItem, 0, len(platformList))
for _, item := range platformList {
list = append(list, dto.DatasourcePlatformItem{
Id: item.ID,
PlatformCode: item.PlatformCode,
PlatformName: item.PlatformName,
Description: item.Description,
Status: api_feature.PlatformStatus(item.Status),
StatusName: s.getStatusName(api_feature.PlatformStatus(item.Status)),
ApiBaseUrl: item.ApiBaseUrl,
AuthType: item.AuthType,
AuthTypeName: s.getAuthTypeName(item.AuthType),
RateLimitPerMinute: item.RateLimitPerMinute,
RateLimitPerHour: item.RateLimitPerHour,
ConcurrencyLimit: item.ConcurrencyLimit,
RequestTimeoutMs: item.RequestTimeoutMs,
MaxRetries: item.MaxRetries,
RetryDelayMs: item.RetryDelayMs,
CreatedBy: item.CreatedBy,
CreatedAt: item.CreatedAt.Unix(),
UpdatedBy: item.UpdatedBy,
UpdatedAt: item.UpdatedAt.Unix(),
})
}
res = &dto.ListDatasourcePlatformRes{
List: list,
Total: total,
}
return res, nil
}
// GetOne 获取单个数据源平台
func (s *datasourcePlatformService) GetOne(ctx context.Context, req *dto.GetDatasourcePlatformReq) (res *dto.GetDatasourcePlatformRes, err error) {
platform, err := dao.DatasourcePlatform.GetOne(ctx, req)
if err != nil {
return nil, err
}
if platform == nil {
return nil, errors.New("数据源平台不存在")
}
var platformEntity *entity.DatasourcePlatform
if err = gconv.Struct(platform, &platformEntity); err != nil {
return nil, err
}
// 隐藏敏感信息
platformEntity.Token = ""
platformEntity.ClientSecret = ""
platformEntity.ApiKey = ""
return &dto.GetDatasourcePlatformRes{
DatasourcePlatform: platformEntity,
}, nil
}
// GetByPlatformCode 根据平台编码获取数据源平台
func (s *datasourcePlatformService) GetByPlatformCode(ctx context.Context, platformCode string) (res *entity.DatasourcePlatform, err error) {
platform, err := dao.DatasourcePlatform.GetByPlatformCode(ctx, platformCode)
if err != nil {
return nil, err
}
if platform == nil {
return nil, errors.New("数据源平台不存在")
}
return platform, nil
}
// Update 更新数据源平台
func (s *datasourcePlatformService) Update(ctx context.Context, req *dto.UpdateDatasourcePlatformReq) (err error) {
// 检查平台是否存在
exist, err := dao.DatasourcePlatform.GetOne(ctx, &dto.GetDatasourcePlatformReq{Id: req.Id})
if err != nil {
return err
}
if exist == nil {
return errors.New("数据源平台不存在")
}
// 如果修改了平台编码,检查新编码是否重复
if req.PlatformCode != "" && req.PlatformCode != exist.PlatformCode {
exists, err := dao.DatasourcePlatform.ExistsByPlatformCode(ctx, req.PlatformCode, req.Id)
if err != nil {
return err
}
if exists {
return errors.New("平台编码已存在")
}
}
// 验证认证类型相关的必填字段
if req.AuthType != "" {
authReq := &dto.CreateDatasourcePlatformReq{
AuthType: req.AuthType,
Token: req.Token,
ApiKey: req.ApiKey,
ClientId: req.ClientId,
ClientSecret: req.ClientSecret,
}
if err = s.validateAuthFields(authReq); err != nil {
return err
}
}
// 设置更新时间
req.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
_, err = dao.DatasourcePlatform.Update(ctx, req)
return err
}
// UpdateStatus 更新数据源平台状态
func (s *datasourcePlatformService) UpdateStatus(ctx context.Context, req *dto.UpdateDatasourcePlatformStatusReq) (err error) {
// 检查平台是否存在
exist, err := dao.DatasourcePlatform.GetOne(ctx, &dto.GetDatasourcePlatformReq{Id: req.Id})
if err != nil {
return err
}
if exist == nil {
return errors.New("数据源平台不存在")
}
// 如果状态没有变化,直接返回
if string(exist.Status) == req.Status.String() {
return nil
}
_, err = dao.DatasourcePlatform.UpdateStatus(ctx, req.Id, req.Status.String(), req.UpdatedBy)
return err
}
// Delete 删除数据源平台
func (s *datasourcePlatformService) Delete(ctx context.Context, req *dto.DeleteDatasourcePlatformReq) (err error) {
// 检查平台是否存在
exist, err := dao.DatasourcePlatform.GetOne(ctx, &dto.GetDatasourcePlatformReq{Id: req.Id})
if err != nil {
return err
}
if exist == nil {
return errors.New("数据源平台不存在")
}
// TODO: 检查是否存在关联的数据,防止误删
// 例如:检查该平台是否有关联的接口配置等
_, err = dao.DatasourcePlatform.Delete(ctx, req)
return err
}
// GetStatistics 获取平台统计信息
func (s *datasourcePlatformService) GetStatistics(ctx context.Context) (res *dto.GetPlatformStatisticsRes, err error) {
stats, err := dao.DatasourcePlatform.GetPlatformStatistics(ctx)
if err != nil {
return nil, err
}
res = &dto.GetPlatformStatisticsRes{
TotalPlatforms: int(stats["totalPlatforms"]),
ActivePlatforms: int(stats["activePlatforms"]),
InactivePlatforms: int(stats["inactivePlatforms"]),
TokenAuthPlatforms: int(stats["TOKENAuthPlatforms"]),
ApiKeyAuthPlatforms: int(stats["API_KEYAuthPlatforms"]),
OAuth2AuthPlatforms: int(stats["OAUTH2AuthPlatforms"]),
BasicAuthPlatforms: int(stats["BASICAuthPlatforms"]),
}
return res, nil
}
// ListActivePlatforms 获取所有启用的平台
func (s *datasourcePlatformService) ListActivePlatforms(ctx context.Context) (platforms []entity.DatasourcePlatform, err error) {
return dao.DatasourcePlatform.ListActivePlatforms(ctx)
}
// validateAuthFields 验证认证类型相关的必填字段
func (s *datasourcePlatformService) validateAuthFields(req *dto.CreateDatasourcePlatformReq) error {
switch req.AuthType {
case "TOKEN":
if req.Token == "" {
return errors.New("TOKEN认证类型必须填写token字段")
}
case "API_KEY":
if req.ApiKey == "" {
return errors.New("API_KEY认证类型必须填写apiKey字段")
}
case "OAUTH2":
if req.ClientId == "" || req.ClientSecret == "" {
return errors.New("OAUTH2认证类型必须填写clientId和clientSecret字段")
}
case "BASIC":
// BASIC认证通常需要用户名和密码这里可以添加相应验证
if req.Token == "" && req.ApiKey == "" {
return errors.New("BASIC认证类型需要填写认证信息")
}
default:
return errors.New("不支持的认证类型")
}
return nil
}
// performConnectionTest 执行连接测试(示例实现)
func (s *datasourcePlatformService) performConnectionTest(platform *entity.DatasourcePlatform) (success bool, message string) {
// 这里应该实现实际的连接测试逻辑
// 例如发送HTTP请求到api_base_url验证响应
// 暂时返回模拟结果
return true, "连接测试成功"
}
// getStatusName 获取状态名称
func (s *datasourcePlatformService) getStatusName(status api_feature.PlatformStatus) string {
statusNames := map[api_feature.PlatformStatus]string{
api_feature.PlatformStatusActive: "启用",
api_feature.PlatformStatusInactive: "停用",
}
if name, ok := statusNames[status]; ok {
return name
}
return string(status)
}
// getAuthTypeName 获取认证类型名称
func (s *datasourcePlatformService) getAuthTypeName(authType string) string {
authTypeNames := map[string]string{
"TOKEN": "Token认证",
"API_KEY": "API Key认证",
"OAUTH2": "OAuth2认证",
"BASIC": "Basic认证",
}
if name, ok := authTypeNames[authType]; ok {
return name
}
return authType
}
// BatchUpdateStatus 批量更新平台状态
func (s *datasourcePlatformService) BatchUpdateStatus(ctx context.Context, ids []int64, status string, updatedBy string) (err error) {
if len(ids) == 0 {
return errors.New("请选择要更新的平台")
}
_, err = dao.DatasourcePlatform.BatchUpdateStatus(ctx, ids, status, updatedBy)
return err
}

View File

@@ -0,0 +1,396 @@
package dict
import (
consts "cid/consts/dict"
"cid/dao/dict"
dto "cid/model/dto/dict"
entity "cid/model/entity/dict"
"context"
"errors"
"fmt"
"time"
"gitea.com/red-future/common/beans"
)
type fieldMappingConfigService struct{}
// FieldMappingConfig 字段映射配置服务
var FieldMappingConfig = new(fieldMappingConfigService)
// Create 创建字段映射配置
func (s *fieldMappingConfigService) Create(ctx context.Context, req *dto.CreateFieldMappingConfigReq) (res *dto.CreateFieldMappingConfigRes, err error) {
// 验证必填字段
if err = s.validateRequiredFields(req); err != nil {
return nil, err
}
// 检查重复配置
exists, err := dict.FieldMappingConfig.CheckDuplicate(ctx, req.VendorName, req.ApiName, req.SourceField, req.TargetField, 0)
if err != nil {
return nil, errors.New("检查配置重复性失败")
}
if exists {
return nil, errors.New("相同厂商、接口、源字段和目标字段的配置已存在")
}
// 验证转换参数
if err = s.validateTransformParams(req.TransformType, req.TransformParams); err != nil {
return nil, fmt.Errorf("转换参数验证失败: %v", err)
}
// 验证业务域
if req.BusinessDomain != "" && !s.isValidBusinessDomain(req.BusinessDomain) {
return nil, errors.New("无效的业务域")
}
// 验证生效时间和失效时间
if req.EffectiveDate != nil && req.ExpiryDate != nil && req.EffectiveDate.After(*req.ExpiryDate) {
return nil, errors.New("生效时间不能晚于失效时间")
}
// 插入数据库
id, err := dict.FieldMappingConfig.Insert(ctx, req)
if err != nil {
return nil, errors.New("创建配置失败")
}
res = &dto.CreateFieldMappingConfigRes{
Id: id,
}
return
}
// List 获取字段映射配置列表
func (s *fieldMappingConfigService) List(ctx context.Context, req *dto.ListFieldMappingConfigReq) (res *dto.ListFieldMappingConfigRes, err error) {
configs, total, err := dict.FieldMappingConfig.List(ctx, req)
if err != nil {
return nil, errors.New("查询配置列表失败")
}
// 组装响应数据
list := make([]dto.FieldMappingConfigItem, 0, len(configs))
for _, item := range configs {
list = append(list, dto.FieldMappingConfigItem{
Id: item.Id,
ConfigName: item.ConfigName,
VendorName: item.VendorName,
ApiName: item.ApiName,
ApiVersion: item.ApiVersion,
SourceField: item.SourceField,
TargetField: item.TargetField,
TargetFieldType: item.TargetFieldType,
TransformType: item.TransformType,
TransformTypeName: s.getTransformTypeName(item.TransformType),
IsActive: item.IsActive,
Priority: item.Priority,
BusinessDomain: item.BusinessDomain,
BusinessDomainName: s.getBusinessDomainName(item.BusinessDomain),
FieldGroup: item.FieldGroup,
ConfigVersion: item.ConfigVersion,
CreatedBy: item.CreatedBy,
CreatedTime: item.CreatedTime,
UpdatedBy: item.UpdatedBy,
UpdatedTime: item.UpdatedTime,
})
}
res = &dto.ListFieldMappingConfigRes{
List: list,
Total: total,
}
return
}
// GetOne 获取单个字段映射配置
func (s *fieldMappingConfigService) GetOne(ctx context.Context, req *dto.GetFieldMappingConfigReq) (res *dto.GetFieldMappingConfigRes, err error) {
config, err := dict.FieldMappingConfig.GetOne(ctx, req)
if err != nil {
return nil, errors.New("获取配置详情失败")
}
if config == nil {
return nil, errors.New("配置不存在")
}
return &dto.GetFieldMappingConfigRes{
FieldMappingConfig: config,
TransformTypeName: s.getTransformTypeName(config.TransformType),
BusinessDomainName: s.getBusinessDomainName(config.BusinessDomain),
}, nil
}
// Update 更新字段映射配置
func (s *fieldMappingConfigService) Update(ctx context.Context, req *dto.UpdateFieldMappingConfigReq) (err error) {
// 检查配置是否存在
exist, err := dict.FieldMappingConfig.GetOne(ctx, &dto.GetFieldMappingConfigReq{Id: req.Id})
if err != nil || exist == nil {
return errors.New("配置不存在")
}
// 如果修改了关键字段,检查重复性
if (req.VendorName != "" && req.VendorName != exist.VendorName) ||
(req.ApiName != "" && req.ApiName != exist.ApiName) ||
(req.SourceField != "" && req.SourceField != exist.SourceField) ||
(req.TargetField != "" && req.TargetField != exist.TargetField) {
vendorName := req.VendorName
if vendorName == "" {
vendorName = exist.VendorName
}
apiName := req.ApiName
if apiName == "" {
apiName = exist.ApiName
}
sourceField := req.SourceField
if sourceField == "" {
sourceField = exist.SourceField
}
targetField := req.TargetField
if targetField == "" {
targetField = exist.TargetField
}
exists, err := dict.FieldMappingConfig.CheckDuplicate(ctx, vendorName, apiName, sourceField, targetField, req.Id)
if err != nil {
return errors.New("检查配置重复性失败")
}
if exists {
return errors.New("相同厂商、接口、源字段和目标字段的配置已存在")
}
}
// 验证转换参数
if req.TransformType != "" && req.TransformParams != nil {
if err = s.validateTransformParams(req.TransformType, req.TransformParams); err != nil {
return fmt.Errorf("转换参数验证失败: %v", err)
}
}
// 验证生效时间和失效时间
if req.EffectiveDate != nil && req.ExpiryDate != nil && req.EffectiveDate.After(*req.ExpiryDate) {
return errors.New("生效时间不能晚于失效时间")
}
// 更新数据库
_, err = dict.FieldMappingConfig.Update(ctx, req)
if err != nil {
return errors.New("更新配置失败")
}
return nil
}
// UpdateStatus 更新字段映射配置状态
func (s *fieldMappingConfigService) UpdateStatus(ctx context.Context, req *dto.UpdateFieldMappingConfigStatusReq) (err error) {
_, err = dict.FieldMappingConfig.UpdateStatus(ctx, req.Id, req.IsActive)
if err != nil {
return errors.New("更新配置状态失败")
}
return nil
}
// Delete 删除字段映射配置
func (s *fieldMappingConfigService) Delete(ctx context.Context, req *dto.DeleteFieldMappingConfigReq) (err error) {
_, err = dict.FieldMappingConfig.Delete(ctx, req)
if err != nil {
return errors.New("删除配置失败")
}
return nil
}
// QueryByVendorApi 根据厂商和接口查询字段映射
func (s *fieldMappingConfigService) QueryByVendorApi(ctx context.Context, req *dto.QueryFieldMappingByVendorApiReq) (res *dto.QueryFieldMappingByVendorApiRes, err error) {
configs, err := dict.FieldMappingConfig.GetByVendorAndApi(ctx, req.VendorName, req.ApiName, req.ApiVersion, req.IsActive)
if err != nil {
return nil, errors.New("查询字段映射配置失败")
}
// 过滤掉已过期的配置
var validConfigs []*entity.FieldMappingConfig
now := time.Now()
for _, config := range configs {
if (config.EffectiveDate == nil || !config.EffectiveDate.After(now)) &&
(config.ExpiryDate == nil || config.ExpiryDate.After(now)) {
validConfigs = append(validConfigs, config)
}
}
res = &dto.QueryFieldMappingByVendorApiRes{
List: validConfigs,
}
return
}
// Validate 验证字段映射配置
func (s *fieldMappingConfigService) Validate(ctx context.Context, req *dto.ValidateFieldMappingReq) (res *dto.ValidateFieldMappingRes, err error) {
ctx = context.WithValue(ctx, "user", &beans.User{UserName: "admin"})
res = &dto.ValidateFieldMappingRes{
IsValid: false,
}
// 验证基本配置
if req.ConfigName == "" || req.VendorName == "" || req.ApiName == "" || req.SourceField == "" || req.TargetField == "" {
res.Error = "配置名称、厂商名称、接口名称、源字段和目标字段不能为空"
return
}
// 检查重复配置
exists, err := dict.FieldMappingConfig.CheckDuplicate(ctx, req.VendorName, req.ApiName, req.SourceField, req.TargetField, 0)
if err != nil {
res.Error = "检查配置重复性失败"
return
}
if exists {
res.Error = "相同厂商、接口、源字段和目标字段的配置已存在"
return
}
// 如果有测试值,尝试转换
if req.TestValue != nil {
// 这里可以实现具体的转换逻辑
// 例如:根据转换类型和参数进行值转换
res.TransformedValue = req.TestValue
res.Warnings = []string{"转换逻辑需要根据具体业务实现"}
}
res.IsValid = true
return
}
// validateRequiredFields 验证必填字段
func (s *fieldMappingConfigService) validateRequiredFields(req *dto.CreateFieldMappingConfigReq) error {
if req.ConfigName == "" {
return errors.New("配置名称不能为空")
}
if req.VendorName == "" {
return errors.New("厂商名称不能为空")
}
if req.ApiName == "" {
return errors.New("接口名称不能为空")
}
if req.SourceField == "" {
return errors.New("源字段不能为空")
}
if req.TargetField == "" {
return errors.New("目标字段不能为空")
}
if req.TargetFieldType == "" {
return errors.New("目标字段类型不能为空")
}
return nil
}
// validateRequiredFieldsForBatch 批量创建的字段验证
func (s *fieldMappingConfigService) validateRequiredFieldsForBatch(config *dto.BatchFieldMappingConfigItem) error {
if config.ConfigName == "" {
return errors.New("配置名称不能为空")
}
if config.VendorName == "" {
return errors.New("厂商名称不能为空")
}
if config.ApiName == "" {
return errors.New("接口名称不能为空")
}
if config.SourceField == "" {
return errors.New("源字段不能为空")
}
if config.TargetField == "" {
return errors.New("目标字段不能为空")
}
if config.TargetFieldType == "" {
return errors.New("目标字段类型不能为空")
}
return nil
}
// validateTransformParams 验证转换参数
func (s *fieldMappingConfigService) validateTransformParams(transformType string, params map[string]interface{}) error {
if params == nil {
return nil
}
switch transformType {
case consts.TransformTypeFormatDate:
if _, ok := params["source_format"]; !ok {
return errors.New("日期格式化转换需要source_format参数")
}
if _, ok := params["target_format"]; !ok {
return errors.New("日期格式化转换需要target_format参数")
}
case consts.TransformTypeMapValue:
if len(params) == 0 {
return errors.New("值映射转换需要映射规则参数")
}
case consts.TransformTypeConcat:
if _, ok := params["fields"]; !ok {
return errors.New("拼接转换需要fields参数")
}
case consts.TransformTypeRegex:
if _, ok := params["pattern"]; !ok {
return errors.New("正则提取转换需要pattern参数")
}
}
return nil
}
// isValidBusinessDomain 验证业务域是否有效
func (s *fieldMappingConfigService) isValidBusinessDomain(domain string) bool {
validDomains := []string{
consts.BusinessDomainUser,
consts.BusinessDomainOrder,
consts.BusinessDomainProduct,
consts.BusinessDomainPayment,
}
for _, valid := range validDomains {
if domain == valid {
return true
}
}
return false
}
// getTransformTypeName 获取转换类型名称
func (s *fieldMappingConfigService) getTransformTypeName(transformType string) string {
typeNames := map[string]string{
consts.TransformTypeDirect: "直接映射",
consts.TransformTypeFormatDate: "日期格式化",
consts.TransformTypeMapValue: "值映射",
consts.TransformTypeConcat: "拼接",
consts.TransformTypeCalc: "计算",
consts.TransformTypeRegex: "正则提取",
}
if name, ok := typeNames[transformType]; ok {
return name
}
return transformType
}
// getBusinessDomainName 获取业务域名称
func (s *fieldMappingConfigService) getBusinessDomainName(domain string) string {
domainNames := map[string]string{
consts.BusinessDomainUser: "用户",
consts.BusinessDomainOrder: "订单",
consts.BusinessDomainProduct: "商品",
consts.BusinessDomainPayment: "支付",
}
if name, ok := domainNames[domain]; ok {
return name
}
return domain
}
// GetActiveConfigsByBusinessDomain 根据业务域获取启用的配置
func (s *fieldMappingConfigService) GetActiveConfigsByBusinessDomain(ctx context.Context, businessDomain string) ([]entity.FieldMappingConfig, error) {
return dict.FieldMappingConfig.GetActiveConfigsByBusinessDomain(ctx, businessDomain)
}
// GetFieldGroupsByVendorApi 获取指定厂商接口的字段分组
func (s *fieldMappingConfigService) GetFieldGroupsByVendorApi(ctx context.Context, vendorName, apiName string) ([]string, error) {
return dict.FieldMappingConfig.GetFieldGroupsByVendorApi(ctx, vendorName, apiName)
}
// CleanExpiredConfigs 清理过期配置
func (s *fieldMappingConfigService) CleanExpiredConfigs(ctx context.Context) (int64, error) {
return dict.FieldMappingConfig.DeleteExpiredConfigs(ctx)
}

View File

@@ -0,0 +1,183 @@
package dict
import (
consts "cid/consts/api-feature"
"cid/dao/dict"
dto "cid/model/dto/dict"
entity "cid/model/entity/dict"
"context"
"errors"
)
type apiInterfaceService struct{}
// ApiInterface 接口服务
var ApiInterface = new(apiInterfaceService)
// Create 创建接口
func (s *apiInterfaceService) Create(ctx context.Context, req *dto.CreateApiInterfaceReq) (res *dto.CreateApiInterfaceRes, err error) {
_, err = DatasourcePlatform.GetOne(ctx, &dto.GetDatasourcePlatformReq{Id: req.PlatformId})
if err != nil {
return nil, errors.New("平台不存在")
}
// 检查接口编码在同一平台下是否重复
interfaces, _, err := dict.ApiInterface.List(ctx, &dto.ListApiInterfaceReq{
PlatformId: req.PlatformId,
Code: req.Code,
})
if err != nil {
return
}
if len(interfaces) > 0 {
return nil, errors.New("接口编码在该平台下已存在")
}
// 插入数据库
id, err := dict.ApiInterface.Insert(ctx, req)
if err != nil {
return
}
res = &dto.CreateApiInterfaceRes{
Id: id,
}
return
}
// List 获取接口列表
func (s *apiInterfaceService) List(ctx context.Context, req *dto.ListApiInterfaceReq) (res *dto.ListApiInterfaceRes, err error) {
apiList, total, err := dict.ApiInterface.List(ctx, req)
if err != nil {
return
}
platformIds := make([]int64, 0)
for _, item := range apiList {
if item.PlatformId > 0 {
platformIds = append(platformIds, item.PlatformId)
}
}
platformMap := make(map[int64]string)
if len(platformIds) > 0 {
res, err := DatasourcePlatform.List(ctx, &dto.ListDatasourcePlatformReq{})
if err == nil && res != nil {
for _, p := range res.List {
platformMap[p.Id] = p.PlatformName
}
}
}
list := make([]dto.ApiInterfaceItem, 0, len(apiList))
for _, item := range apiList {
platformName := ""
if name, ok := platformMap[item.PlatformId]; ok {
platformName = name
}
list = append(list, dto.ApiInterfaceItem{
Id: item.Id,
PlatformId: item.PlatformId,
PlatformName: platformName,
Name: item.Name,
Code: item.Code,
Url: item.Url,
Method: item.Method,
Status: item.Status,
StatusName: s.getStatusName(item.Status),
CreatedAt: item.CreatedAt.Unix(),
UpdatedAt: item.UpdatedAt.Unix(),
})
}
res = &dto.ListApiInterfaceRes{
List: list,
Total: total,
}
return
}
// GetOne 获取单个接口
func (s *apiInterfaceService) GetOne(ctx context.Context, req *dto.GetApiInterfaceReq) (res *dto.GetApiInterfaceRes, err error) {
apiInterface, err := dict.ApiInterface.GetOne(ctx, req)
if err != nil {
return
}
var platformName string
if apiInterface.PlatformId > 0 {
platform, _ := DatasourcePlatform.GetOne(ctx, &dto.GetDatasourcePlatformReq{Id: apiInterface.PlatformId})
if platform != nil {
platformName = platform.PlatformName
}
}
return &dto.GetApiInterfaceRes{
ApiInterface: apiInterface,
PlatformName: platformName,
}, nil
}
// Update 更新接口
func (s *apiInterfaceService) Update(ctx context.Context, req *dto.UpdateApiInterfaceReq) (err error) {
exist, err := dict.ApiInterface.GetOne(ctx, &dto.GetApiInterfaceReq{Id: req.Id})
if err != nil || exist == nil {
return errors.New("接口不存在")
}
if req.PlatformId > 0 && req.PlatformId != exist.PlatformId {
_, err := DatasourcePlatform.GetOne(ctx, &dto.GetDatasourcePlatformReq{Id: req.PlatformId})
if err != nil {
return errors.New("平台不存在")
}
}
if req.Code != "" && req.Code != exist.Code {
platformId := req.PlatformId
if platformId == 0 {
platformId = exist.PlatformId
}
interfaces, _, err := dict.ApiInterface.List(ctx, &dto.ListApiInterfaceReq{
PlatformId: platformId,
Code: req.Code,
})
if err != nil {
return err
}
if len(interfaces) > 0 {
return errors.New("接口编码在该平台下已存在")
}
}
_, err = dict.ApiInterface.Update(ctx, req)
return
}
// UpdateStatus 更新接口状态
func (s *apiInterfaceService) UpdateStatus(ctx context.Context, req *dto.UpdateApiInterfaceStatusReq) (err error) {
_, err = dict.ApiInterface.UpdateStatus(ctx, req.Id, req.Status.String())
return
}
// Delete 删除接口
func (s *apiInterfaceService) Delete(ctx context.Context, req *dto.DeleteApiInterfaceReq) (err error) {
_, err = dict.ApiInterface.Delete(ctx, req)
return
}
// GetByIds 根据ID列表获取接口
func (s *apiInterfaceService) GetByIds(ctx context.Context, ids []int64) (res []entity.ApiInterface, err error) {
return dict.ApiInterface.GetByIds(ctx, ids)
}
// getStatusName 获取状态名称
func (s *apiInterfaceService) getStatusName(status consts.PlatformStatus) string {
statusNames := map[consts.PlatformStatus]string{
consts.PlatformStatusActive: "启用",
consts.PlatformStatusInactive: "停用",
}
if name, ok := statusNames[status]; ok {
return name
}
return string(status)
}