f
This commit is contained in:
@@ -67,6 +67,23 @@ type (
|
||||
TodayProfitRate float64 `json:"today_profit_rate"` // 今日利润率
|
||||
MonthProfitRate float64 `json:"month_profit_rate"` // 当月利润率
|
||||
TotalProfitRate float64 `json:"total_profit_rate"` // 总利润率
|
||||
// 今日明细
|
||||
TodayDetail AdminProfitDetail `json:"today_detail"`
|
||||
// 当月明细
|
||||
MonthDetail AdminProfitDetail `json:"month_detail"`
|
||||
// 总计明细
|
||||
TotalDetail AdminProfitDetail `json:"total_detail"`
|
||||
}
|
||||
// 利润明细
|
||||
AdminProfitDetail {
|
||||
Revenue float64 `json:"revenue"` // 营收
|
||||
Commission float64 `json:"commission"` // 佣金
|
||||
Rebate float64 `json:"rebate"` // 返利
|
||||
CompanyTax float64 `json:"company_tax"` // 税务成本
|
||||
ApiCost float64 `json:"api_cost"` // API调用成本
|
||||
TaxIncome float64 `json:"tax_income"` // 提现收税
|
||||
Profit float64 `json:"profit"` // 利润
|
||||
ProfitRate float64 `json:"profit_rate"` // 利润率
|
||||
}
|
||||
// 趋势数据
|
||||
AdminTrendData {
|
||||
|
||||
@@ -279,6 +279,10 @@ service main {
|
||||
// 下架单个模块(创建订单并支付)
|
||||
@handler OfflineFeature
|
||||
post /whitelist/offline (OfflineFeatureReq) returns (OfflineFeatureResp)
|
||||
|
||||
// 检查订单是否属于当前代理推广
|
||||
@handler CheckOrderAgent
|
||||
get /order/agent (CheckOrderAgentReq) returns (CheckOrderAgentResp)
|
||||
}
|
||||
|
||||
type (
|
||||
@@ -705,6 +709,14 @@ type (
|
||||
NeedPay bool `json:"need_pay"` // 是否需要发起支付
|
||||
Amount float64 `json:"amount"` // 需要支付的金额(单位:元),0表示无需支付
|
||||
}
|
||||
// 检查订单是否属于当前代理请求
|
||||
CheckOrderAgentReq {
|
||||
OrderId string `form:"order_id"` // 订单ID
|
||||
}
|
||||
// 检查订单是否属于当前代理响应
|
||||
CheckOrderAgentResp {
|
||||
IsAgentOrder bool `json:"is_agent_order"` // 是否是当前代理推广的订单
|
||||
}
|
||||
)
|
||||
|
||||
// ============================================
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"ycc-server/app/main/api/internal/logic/agent"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/result"
|
||||
"ycc-server/pkg/lzkit/validator"
|
||||
)
|
||||
|
||||
func CheckOrderAgentHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req types.CheckOrderAgentReq
|
||||
if err := httpx.Parse(r, &req); err != nil {
|
||||
result.ParamErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
if err := validator.Validate(req); err != nil {
|
||||
result.ParamValidateErrorResult(r, w, err)
|
||||
return
|
||||
}
|
||||
l := agent.NewCheckOrderAgentLogic(r.Context(), svcCtx)
|
||||
resp, err := l.CheckOrderAgent(&req)
|
||||
result.HttpResult(r, w, resp, err)
|
||||
}
|
||||
}
|
||||
@@ -715,6 +715,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
Path: "/level/privilege",
|
||||
Handler: agent.GetLevelPrivilegeHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/order/agent",
|
||||
Handler: agent.CheckOrderAgentHandler(serverCtx),
|
||||
},
|
||||
{
|
||||
Method: http.MethodGet,
|
||||
Path: "/product_config",
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"ycc-server/app/main/api/internal/service"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
@@ -224,7 +225,7 @@ func (l *AdminGetDashboardStatisticsLogic) calculateAgentStatistics(todayStart,
|
||||
func (l *AdminGetDashboardStatisticsLogic) calculateProfitStatistics(todayStart, todayEnd, monthStart, monthEnd time.Time, revenueStats types.AdminRevenueStatistics) (types.AdminProfitStatistics, error) {
|
||||
var stats types.AdminProfitStatistics
|
||||
|
||||
// 公司交税比例(6%)
|
||||
// 税务成本比例(6%)
|
||||
const companyTaxRate = 0.06
|
||||
|
||||
// 今日利润计算
|
||||
@@ -244,20 +245,44 @@ func (l *AdminGetDashboardStatisticsLogic) calculateProfitStatistics(todayStart,
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
// 今日公司交税(订单金额的6%)
|
||||
// 今日税务成本(订单金额的6%)
|
||||
todayCompanyTax := todayRevenue * companyTaxRate
|
||||
// 今日平台收入税(agent_withdrawal_tax表中tax_status=2的tax_amount总和)
|
||||
// 今日提现收税(agent_withdrawal_tax表中tax_status=2的tax_amount总和)
|
||||
todayTaxIncomeBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
|
||||
Where("del_state = ? AND tax_status = ? AND create_time >= ? AND create_time < ?", globalkey.DelStateNo, 2, todayStart, todayEnd)
|
||||
todayTaxIncome, err := l.svcCtx.AgentWithdrawalTaxModel.FindSum(l.ctx, todayTaxIncomeBuilder, "tax_amount")
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
// 今日利润 = 营收 - 佣金 - 返利 - 公司交税 + 平台收入税
|
||||
stats.TodayProfit = todayRevenue - todayCommission - todayRebate - todayCompanyTax + todayTaxIncome
|
||||
// 今日API调用成本
|
||||
todayApiCost := 0.0
|
||||
if l.svcCtx.TianyuanapiCallLogService != nil {
|
||||
todayApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{
|
||||
StartDate: todayStart,
|
||||
EndDate: todayEnd,
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("获取今日API调用成本失败: %v", err)
|
||||
} else {
|
||||
todayApiCost = todayApiStats.TotalCost
|
||||
}
|
||||
}
|
||||
// 今日利润 = 营收 - 佣金 - 返利 - 税务成本 - API调用成本 + 提现收税
|
||||
stats.TodayProfit = todayRevenue - todayCommission - todayRebate - todayCompanyTax - todayApiCost + todayTaxIncome
|
||||
if todayRevenue > 0 {
|
||||
stats.TodayProfitRate = stats.TodayProfit / todayRevenue * 100
|
||||
}
|
||||
// 今日明细
|
||||
stats.TodayDetail = types.AdminProfitDetail{
|
||||
Revenue: todayRevenue,
|
||||
Commission: todayCommission,
|
||||
Rebate: todayRebate,
|
||||
CompanyTax: todayCompanyTax,
|
||||
ApiCost: todayApiCost,
|
||||
TaxIncome: todayTaxIncome,
|
||||
Profit: stats.TodayProfit,
|
||||
ProfitRate: stats.TodayProfitRate,
|
||||
}
|
||||
|
||||
// 当月利润计算
|
||||
// 当月营收
|
||||
@@ -276,20 +301,44 @@ func (l *AdminGetDashboardStatisticsLogic) calculateProfitStatistics(todayStart,
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
// 当月公司交税
|
||||
// 当月税务成本
|
||||
monthCompanyTax := monthRevenue * companyTaxRate
|
||||
// 当月平台收入税
|
||||
// 当月提现收税
|
||||
monthTaxIncomeBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
|
||||
Where("del_state = ? AND tax_status = ? AND create_time >= ? AND create_time < ?", globalkey.DelStateNo, 2, monthStart, monthEnd)
|
||||
monthTaxIncome, err := l.svcCtx.AgentWithdrawalTaxModel.FindSum(l.ctx, monthTaxIncomeBuilder, "tax_amount")
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
// 当月API调用成本
|
||||
monthApiCost := 0.0
|
||||
if l.svcCtx.TianyuanapiCallLogService != nil {
|
||||
monthApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{
|
||||
StartDate: monthStart,
|
||||
EndDate: monthEnd,
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("获取当月API调用成本失败: %v", err)
|
||||
} else {
|
||||
monthApiCost = monthApiStats.TotalCost
|
||||
}
|
||||
}
|
||||
// 当月利润
|
||||
stats.MonthProfit = monthRevenue - monthCommission - monthRebate - monthCompanyTax + monthTaxIncome
|
||||
stats.MonthProfit = monthRevenue - monthCommission - monthRebate - monthCompanyTax - monthApiCost + monthTaxIncome
|
||||
if monthRevenue > 0 {
|
||||
stats.MonthProfitRate = stats.MonthProfit / monthRevenue * 100
|
||||
}
|
||||
// 当月明细
|
||||
stats.MonthDetail = types.AdminProfitDetail{
|
||||
Revenue: monthRevenue,
|
||||
Commission: monthCommission,
|
||||
Rebate: monthRebate,
|
||||
CompanyTax: monthCompanyTax,
|
||||
ApiCost: monthApiCost,
|
||||
TaxIncome: monthTaxIncome,
|
||||
Profit: stats.MonthProfit,
|
||||
ProfitRate: stats.MonthProfitRate,
|
||||
}
|
||||
|
||||
// 总利润计算
|
||||
// 总营收
|
||||
@@ -303,25 +352,46 @@ func (l *AdminGetDashboardStatisticsLogic) calculateProfitStatistics(todayStart,
|
||||
}
|
||||
// 总返利
|
||||
totalRebateBuilder := l.svcCtx.AgentRebateModel.SelectBuilder().
|
||||
Where("del_state = ? AND status != ?", globalkey.DelStateNo, 3)
|
||||
Where("status != ?", 3)
|
||||
totalRebate, err := l.svcCtx.AgentRebateModel.FindSum(l.ctx, totalRebateBuilder, "rebate_amount")
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
// 总公司交税
|
||||
// 总税务成本
|
||||
totalCompanyTax := totalRevenue * companyTaxRate
|
||||
// 总平台收入税
|
||||
// 总提现收税
|
||||
totalTaxIncomeBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
|
||||
Where("del_state = ? AND tax_status = ?", globalkey.DelStateNo, 2)
|
||||
Where("tax_status = ?", 2)
|
||||
totalTaxIncome, err := l.svcCtx.AgentWithdrawalTaxModel.FindSum(l.ctx, totalTaxIncomeBuilder, "tax_amount")
|
||||
if err != nil {
|
||||
return stats, err
|
||||
}
|
||||
// 总API调用成本
|
||||
totalApiCost := 0.0
|
||||
if l.svcCtx.TianyuanapiCallLogService != nil {
|
||||
totalApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{})
|
||||
if err != nil {
|
||||
logx.Errorf("获取总API调用成本失败: %v", err)
|
||||
} else {
|
||||
totalApiCost = totalApiStats.TotalCost
|
||||
}
|
||||
}
|
||||
// 总利润
|
||||
stats.TotalProfit = totalRevenue - totalCommission - totalRebate - totalCompanyTax + totalTaxIncome
|
||||
stats.TotalProfit = totalRevenue - totalCommission - totalRebate - totalCompanyTax - totalApiCost + totalTaxIncome
|
||||
if totalRevenue > 0 {
|
||||
stats.TotalProfitRate = stats.TotalProfit / totalRevenue * 100
|
||||
}
|
||||
// 总计明细
|
||||
stats.TotalDetail = types.AdminProfitDetail{
|
||||
Revenue: totalRevenue,
|
||||
Commission: totalCommission,
|
||||
Rebate: totalRebate,
|
||||
CompanyTax: totalCompanyTax,
|
||||
ApiCost: totalApiCost,
|
||||
TaxIncome: totalTaxIncome,
|
||||
Profit: stats.TotalProfit,
|
||||
ProfitRate: stats.TotalProfitRate,
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
46
app/main/api/internal/logic/agent/checkorderagentlogic.go
Normal file
46
app/main/api/internal/logic/agent/checkorderagentlogic.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/logic/query"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type CheckOrderAgentLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewCheckOrderAgentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckOrderAgentLogic {
|
||||
return &CheckOrderAgentLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CheckOrderAgentLogic) CheckOrderAgent(req *types.CheckOrderAgentReq) (resp *types.CheckOrderAgentResp, err error) {
|
||||
// 获取当前用户ID
|
||||
userId, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败: %v", err)
|
||||
}
|
||||
|
||||
// 检查订单是否属于当前代理推广
|
||||
isAgent, err := query.IsOrderAgent(l.ctx, l.svcCtx, userId, req.OrderId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.CheckOrderAgentResp{
|
||||
IsAgentOrder: isAgent,
|
||||
}, nil
|
||||
}
|
||||
@@ -36,7 +36,7 @@ func (l *QuerySingleTestLogic) QuerySingleTest(req *types.QuerySingleTestReq) (r
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "单查测试, 序列化参数失败 : %d", err)
|
||||
}
|
||||
apiResp, err := l.svcCtx.ApiRequestService.PreprocessRequestApi(marshalParams, req.Api)
|
||||
apiResp, err := l.svcCtx.ApiRequestService.PreprocessRequestApi(l.ctx, marshalParams, req.Api)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "单查测试, 获取接口失败 : %d", err)
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ func (l *PaySuccessNotifyUserHandler) ProcessTask(ctx context.Context, t *asynq.
|
||||
encryptData = encryptedEmptyData
|
||||
} else {
|
||||
// 正常模式:调用API请求服务
|
||||
combinedResponse, err := l.svcCtx.ApiRequestService.ProcessRequests(decryptData, product.Id)
|
||||
combinedResponse, err := l.svcCtx.ApiRequestService.ProcessRequests(ctx, decryptData, product.Id)
|
||||
if err != nil {
|
||||
return l.handleError(ctx, err, order, query)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,61 @@ func generateAuthDateRange() string {
|
||||
return fmt.Sprintf("%s-%s", start, end)
|
||||
}
|
||||
|
||||
// callTianyuanApiWithLog 调用天元API并记录日志
|
||||
func (a *ApiRequestService) callTianyuanApiWithLog(ctx context.Context, featureID, apiID string, params map[string]interface{}) (*tianyuanapi.Response, error) {
|
||||
startTime := time.Now()
|
||||
resp, err := a.tianyuanapi.CallInterface(apiID, params)
|
||||
responseTime := time.Since(startTime).Milliseconds()
|
||||
|
||||
// 如果没有提供featureID,尝试从缓存中获取
|
||||
if featureID == "" {
|
||||
a.apiFeatureMapMutex.RLock()
|
||||
featureID = a.apiFeatureMapCache[apiID]
|
||||
a.apiFeatureMapMutex.RUnlock()
|
||||
}
|
||||
|
||||
// 构建调用记录选项
|
||||
callStatus := int64(0) // 默认失败
|
||||
errorCode := ""
|
||||
errorMessage := ""
|
||||
responseData := interface{}(nil)
|
||||
transactionID := ""
|
||||
|
||||
if err != nil {
|
||||
// 调用失败
|
||||
errorMessage = err.Error()
|
||||
// 尝试从错误信息中提取错误码
|
||||
if code := tianyuanapi.GetCodeByError(err); code != -1 {
|
||||
errorCode = fmt.Sprintf("%d", code)
|
||||
}
|
||||
} else {
|
||||
// 调用成功
|
||||
callStatus = 1
|
||||
responseData = resp.Data
|
||||
transactionID = resp.TransactionID
|
||||
}
|
||||
|
||||
// 异步记录调用日志(避免影响主流程)
|
||||
go func() {
|
||||
logOpts := CallLogOptions{
|
||||
FeatureID: featureID,
|
||||
ApiID: apiID,
|
||||
CallStatus: callStatus,
|
||||
ResponseTime: responseTime,
|
||||
ErrorCode: errorCode,
|
||||
ErrorMessage: errorMessage,
|
||||
RequestParams: params,
|
||||
ResponseData: responseData,
|
||||
TransactionID: transactionID,
|
||||
}
|
||||
if recordErr := a.tianyuanapiCallLogService.RecordCall(context.Background(), logOpts); recordErr != nil {
|
||||
logx.Errorf("记录天元API调用日志失败,api_id=%s, err=%v", apiID, recordErr)
|
||||
}
|
||||
}()
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
type ApiRequestService struct {
|
||||
config config.Config
|
||||
featureModel model.FeatureModel
|
||||
@@ -39,16 +94,22 @@ type ApiRequestService struct {
|
||||
userFeatureWhitelistModel model.UserFeatureWhitelistModel
|
||||
whitelistService *WhitelistService
|
||||
tianyuanapi *tianyuanapi.Client
|
||||
tianyuanapiCallLogService *TianyuanapiCallLogService
|
||||
apiFeatureMapCache map[string]string // apiID -> featureID 缓存
|
||||
apiFeatureMapMutex sync.RWMutex
|
||||
}
|
||||
|
||||
// NewApiRequestService 是一个构造函数,用于初始化 ApiRequestService
|
||||
func NewApiRequestService(c config.Config, featureModel model.FeatureModel, productFeatureModel model.ProductFeatureModel, userFeatureWhitelistModel model.UserFeatureWhitelistModel, tianyuanapi *tianyuanapi.Client) *ApiRequestService {
|
||||
func NewApiRequestService(c config.Config, featureModel model.FeatureModel, productFeatureModel model.ProductFeatureModel, userFeatureWhitelistModel model.UserFeatureWhitelistModel, tianyuanapi *tianyuanapi.Client, tianyuanapiCallLogService *TianyuanapiCallLogService, whitelistService *WhitelistService) *ApiRequestService {
|
||||
return &ApiRequestService{
|
||||
config: c,
|
||||
featureModel: featureModel,
|
||||
productFeatureModel: productFeatureModel,
|
||||
userFeatureWhitelistModel: userFeatureWhitelistModel,
|
||||
tianyuanapi: tianyuanapi,
|
||||
tianyuanapiCallLogService: tianyuanapiCallLogService,
|
||||
whitelistService: whitelistService,
|
||||
apiFeatureMapCache: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,15 +122,21 @@ type APIResponseData struct {
|
||||
}
|
||||
|
||||
// ProcessRequests 处理请求
|
||||
func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]byte, error) {
|
||||
var ctx, cancel = context.WithCancel(context.Background())
|
||||
func (a *ApiRequestService) ProcessRequests(ctx context.Context, params []byte, productID string) ([]byte, error) {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
// 从params中提取id_card,用于白名单检查
|
||||
idCard := gjson.GetBytes(params, "id_card").String()
|
||||
|
||||
// 查询白名单(如果提供了id_card),集中由 WhitelistService 处理
|
||||
whitelistedFeatureApiIds, _ := a.whitelistService.GetWhitelistedFeatureApisByIdCard(ctx, idCard)
|
||||
var whitelistedFeatureApiIds map[string]bool
|
||||
if a.whitelistService != nil {
|
||||
whitelistedFeatureApiIds, _ = a.whitelistService.GetWhitelistedFeatureApisByIdCard(ctx, idCard)
|
||||
} else {
|
||||
whitelistedFeatureApiIds = make(map[string]bool)
|
||||
}
|
||||
|
||||
build := a.productFeatureModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"product_id": productID,
|
||||
@@ -95,6 +162,13 @@ func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]
|
||||
if len(featureList) == 0 {
|
||||
return nil, errors.New("处理请求错误,产品无对应接口功能")
|
||||
}
|
||||
|
||||
// 缓存apiID到featureID的映射关系,供后续调用记录使用
|
||||
a.apiFeatureMapMutex.Lock()
|
||||
for _, feature := range featureList {
|
||||
a.apiFeatureMapCache[feature.ApiId] = feature.Id
|
||||
}
|
||||
a.apiFeatureMapMutex.Unlock()
|
||||
var (
|
||||
wg sync.WaitGroup
|
||||
resultsCh = make(chan APIResponseData, len(featureList))
|
||||
@@ -140,7 +214,7 @@ func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]
|
||||
tryCount := 0
|
||||
for {
|
||||
tryCount++
|
||||
resp, preprocessErr = a.PreprocessRequestApi(params, feature.ApiId)
|
||||
resp, preprocessErr = a.PreprocessRequestApi(ctx, params, feature.ApiId)
|
||||
if preprocessErr == nil {
|
||||
break
|
||||
}
|
||||
@@ -197,7 +271,7 @@ func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]
|
||||
}
|
||||
|
||||
// ------------------------------------请求处理器--------------------------
|
||||
var requestProcessors = map[string]func(*ApiRequestService, []byte) ([]byte, error){
|
||||
var requestProcessors = map[string]func(*ApiRequestService, context.Context, []byte) ([]byte, error){
|
||||
"PersonEnterprisePro": (*ApiRequestService).ProcessPersonEnterpriseProRequest,
|
||||
"BehaviorRiskScan": (*ApiRequestService).ProcessBehaviorRiskScanRequest,
|
||||
"YYSYBE08": (*ApiRequestService).ProcessYYSYBE08Request,
|
||||
@@ -232,16 +306,16 @@ var requestProcessors = map[string]func(*ApiRequestService, []byte) ([]byte, err
|
||||
}
|
||||
|
||||
// PreprocessRequestApi 调用指定的请求处理函数
|
||||
func (a *ApiRequestService) PreprocessRequestApi(params []byte, apiID string) ([]byte, error) {
|
||||
func (a *ApiRequestService) PreprocessRequestApi(ctx context.Context, params []byte, apiID string) ([]byte, error) {
|
||||
if processor, exists := requestProcessors[apiID]; exists {
|
||||
return processor(a, params) // 调用 ApiRequestService 方法
|
||||
return processor(a, ctx, params) // 调用 ApiRequestService 方法
|
||||
}
|
||||
|
||||
return nil, errors.New("api请求, 未找到相应的处理程序")
|
||||
}
|
||||
|
||||
// PersonEnterprisePro 人企业关系加强版
|
||||
func (a *ApiRequestService) ProcessPersonEnterpriseProRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessPersonEnterpriseProRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
// 设置最大调用次数上限
|
||||
maxApiCalls := 20 // 允许最多查询20个企业
|
||||
@@ -250,7 +324,7 @@ func (a *ApiRequestService) ProcessPersonEnterpriseProRequest(params []byte) ([]
|
||||
return nil, errors.New("api请求, PersonEnterprisePro, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("QYGLB4C0", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "QYGLB4C0", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
if err != nil {
|
||||
@@ -452,7 +526,7 @@ func (a *ApiRequestService) ProcessPersonEnterpriseProRequest(params []byte) ([]
|
||||
}
|
||||
|
||||
// 调用QYGL8271接口获取企业涉诉信息
|
||||
lawsuitResp, err := a.tianyuanapi.CallInterface("QYGL8271", map[string]interface{}{
|
||||
lawsuitResp, err := a.callTianyuanApiWithLog(ctx, "", "QYGL8271", map[string]interface{}{
|
||||
"ent_name": orgName.String(),
|
||||
"ent_code": creditCode.String(),
|
||||
"auth_date": generateAuthDateRange(),
|
||||
@@ -576,14 +650,14 @@ func (a *ApiRequestService) ProcessPersonEnterpriseProRequest(params []byte) ([]
|
||||
}
|
||||
|
||||
// ProcesFLXG0V4BRequest 个人司法涉诉(详版)
|
||||
func (a *ApiRequestService) ProcessFLXG0V4BRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessFLXG0V4BRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
if !name.Exists() || !idCard.Exists() {
|
||||
return nil, errors.New("api请求, FLXG0V4B, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("FLXG0V4B", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "FLXG0V4B", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"auth_date": generateAuthDateRange(),
|
||||
@@ -599,13 +673,13 @@ func (a *ApiRequestService) ProcessFLXG0V4BRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessFLXG0687Request 反诈反赌核验
|
||||
func (a *ApiRequestService) ProcessFLXG0687Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessFLXG0687Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
if !idCard.Exists() {
|
||||
return nil, errors.New("api请求, FLXG0687, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("FLXG0687", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "FLXG0687", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
|
||||
@@ -627,7 +701,7 @@ func (a *ApiRequestService) ProcessFLXG0687Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessFLXG3D56Request 违约失信
|
||||
func (a *ApiRequestService) ProcessFLXG3D56Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessFLXG3D56Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -635,7 +709,7 @@ func (a *ApiRequestService) ProcessFLXG3D56Request(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, FLXG3D56, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("FLXG3D56", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "FLXG3D56", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -682,14 +756,14 @@ func (a *ApiRequestService) ProcessFLXG3D56Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessIVYZ5733Request 婚姻状况
|
||||
func (a *ApiRequestService) ProcessIVYZ5733Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessIVYZ5733Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
name := gjson.GetBytes(params, "name")
|
||||
if !idCard.Exists() || !name.Exists() {
|
||||
return nil, errors.New("api请求, IVYZ5733, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("IVYZ5733", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "IVYZ5733", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
"name": name.String(),
|
||||
})
|
||||
@@ -738,14 +812,14 @@ func (a *ApiRequestService) ProcessIVYZ5733Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessIVYZ9A2BRequest 学历查询
|
||||
func (a *ApiRequestService) ProcessIVYZ9A2BRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessIVYZ9A2BRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
name := gjson.GetBytes(params, "name")
|
||||
if !idCard.Exists() || !name.Exists() {
|
||||
return nil, errors.New("api请求, IVYZ9A2B, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("IVYZ9A2B", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "IVYZ9A2B", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
"name": name.String(),
|
||||
})
|
||||
@@ -809,14 +883,14 @@ func (a *ApiRequestService) ProcessIVYZ9A2BRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessYYSYBE08Request 二要素
|
||||
func (a *ApiRequestService) ProcessYYSYBE08Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessYYSYBE08Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
if !name.Exists() || !idCard.Exists() {
|
||||
return nil, errors.New("api请求, YYSYBE08, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("YYSYBE08", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "YYSYBE08", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
@@ -850,7 +924,7 @@ func (a *ApiRequestService) ProcessYYSYBE08Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ0A03Request 借贷申请
|
||||
func (a *ApiRequestService) ProcessJRZQ0A03Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ0A03Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -858,7 +932,7 @@ func (a *ApiRequestService) ProcessJRZQ0A03Request(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ0A03, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ0A03", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ0A03", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -907,7 +981,7 @@ func (a *ApiRequestService) ProcessJRZQ0A03Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ8203Request 借贷行为
|
||||
func (a *ApiRequestService) ProcessJRZQ8203Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ8203Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -915,7 +989,7 @@ func (a *ApiRequestService) ProcessJRZQ8203Request(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ8203, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ8203", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ8203", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -964,7 +1038,7 @@ func (a *ApiRequestService) ProcessJRZQ8203Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ4AA8Request 还款压力
|
||||
func (a *ApiRequestService) ProcessJRZQ4AA8Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ4AA8Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
name := gjson.GetBytes(params, "name")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -972,7 +1046,7 @@ func (a *ApiRequestService) ProcessJRZQ4AA8Request(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ4AA8, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ4AA8", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ4AA8", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
"name": name.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1013,7 +1087,7 @@ func (a *ApiRequestService) ProcessJRZQ4AA8Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessQYGL8271Request 企业涉诉
|
||||
func (a *ApiRequestService) ProcessQYGL8271Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessQYGL8271Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
entName := gjson.GetBytes(params, "ent_name")
|
||||
entCode := gjson.GetBytes(params, "ent_code")
|
||||
|
||||
@@ -1021,7 +1095,7 @@ func (a *ApiRequestService) ProcessQYGL8271Request(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, QYGL8271, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("QYGL8271", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "QYGL8271", map[string]interface{}{
|
||||
"ent_name": entName.String(),
|
||||
"ent_code": entCode.String(),
|
||||
})
|
||||
@@ -1073,13 +1147,13 @@ func (a *ApiRequestService) ProcessQYGL8271Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessQYGL6F2DRequest 人企关联
|
||||
func (a *ApiRequestService) ProcessQYGL6F2DRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessQYGL6F2DRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
if !idCard.Exists() {
|
||||
return nil, errors.New("api请求, QYGL6F2D, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("QYGL6F2D", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "QYGL6F2D", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
|
||||
@@ -1114,13 +1188,13 @@ func (a *ApiRequestService) ProcessQYGL6F2DRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessQCXG7A2BRequest 名下车辆
|
||||
func (a *ApiRequestService) ProcessQCXG7A2BRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessQCXG7A2BRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
if !idCard.Exists() {
|
||||
return nil, errors.New("api请求, QCXG7A2B, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("QCXG7A2B", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "QCXG7A2B", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
|
||||
@@ -1132,7 +1206,7 @@ func (a *ApiRequestService) ProcessQCXG7A2BRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessYYSY09CDRequest 三要素
|
||||
func (a *ApiRequestService) ProcessYYSY09CDRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessYYSY09CDRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1140,7 +1214,7 @@ func (a *ApiRequestService) ProcessYYSY09CDRequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, YYSY09CD, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("YYSY09CD", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "YYSY09CD", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1175,7 +1249,7 @@ func (a *ApiRequestService) ProcessYYSY09CDRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessBehaviorRiskScanRequest 行为风险扫描
|
||||
func (a *ApiRequestService) ProcessBehaviorRiskScanRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessBehaviorRiskScanRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
|
||||
@@ -1197,7 +1271,7 @@ func (a *ApiRequestService) ProcessBehaviorRiskScanRequest(params []byte) ([]byt
|
||||
// 反赌反诈
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
respBytes, err := a.ProcessFLXG0687Request(params)
|
||||
respBytes, err := a.ProcessFLXG0687Request(ctx, params)
|
||||
results <- apiResult{name: "anti_fraud_gaming", data: respBytes, err: err}
|
||||
}()
|
||||
|
||||
@@ -1242,7 +1316,7 @@ func (a *ApiRequestService) ProcessBehaviorRiskScanRequest(params []byte) ([]byt
|
||||
}
|
||||
|
||||
// ProcessDWBG8B4DRequest 谛听多维报告
|
||||
func (a *ApiRequestService) ProcessDWBG8B4DRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessDWBG8B4DRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1251,7 +1325,7 @@ func (a *ApiRequestService) ProcessDWBG8B4DRequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, DWBG8B4D, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("DWBG8B4D", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "DWBG8B4D", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1267,7 +1341,7 @@ func (a *ApiRequestService) ProcessDWBG8B4DRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessDWBG6A2CRequest 司南报告服务
|
||||
func (a *ApiRequestService) ProcessDWBG6A2CRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessDWBG6A2CRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1276,7 +1350,7 @@ func (a *ApiRequestService) ProcessDWBG6A2CRequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, DWBG6A2C, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("DWBG6A2C", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "DWBG6A2C", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1292,7 +1366,7 @@ func (a *ApiRequestService) ProcessDWBG6A2CRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ4B6CRequest 探针C风险评估
|
||||
func (a *ApiRequestService) ProcessJRZQ4B6CRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ4B6CRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1300,7 +1374,7 @@ func (a *ApiRequestService) ProcessJRZQ4B6CRequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ4B6C, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ4B6C", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ4B6C", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1316,7 +1390,7 @@ func (a *ApiRequestService) ProcessJRZQ4B6CRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ09J8Request 收入评估
|
||||
func (a *ApiRequestService) ProcessJRZQ09J8Request(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ09J8Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1324,7 +1398,7 @@ func (a *ApiRequestService) ProcessJRZQ09J8Request(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ09J8, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ09J8", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ09J8", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1340,7 +1414,7 @@ func (a *ApiRequestService) ProcessJRZQ09J8Request(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ5E9FRequest 借选指数
|
||||
func (a *ApiRequestService) ProcessJRZQ5E9FRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ5E9FRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1348,7 +1422,7 @@ func (a *ApiRequestService) ProcessJRZQ5E9FRequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ5E9F, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ5E9F", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ5E9F", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1364,13 +1438,13 @@ func (a *ApiRequestService) ProcessJRZQ5E9FRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessQYGL3F8ERequest 人企关系加强版2
|
||||
func (a *ApiRequestService) ProcessQYGL3F8ERequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessQYGL3F8ERequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
if !idCard.Exists() {
|
||||
return nil, errors.New("api请求, QYGL3F8E, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("QYGL3F8E", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "QYGL3F8E", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
|
||||
@@ -1383,14 +1457,14 @@ func (a *ApiRequestService) ProcessQYGL3F8ERequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessIVYZ81NCRequest 婚姻,登记时间版
|
||||
func (a *ApiRequestService) ProcessIVYZ81NCRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessIVYZ81NCRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
if !name.Exists() || !idCard.Exists() {
|
||||
return nil, errors.New("api请求, IVYZ81NC, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("IVYZ81NC", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "IVYZ81NC", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
@@ -1404,14 +1478,14 @@ func (a *ApiRequestService) ProcessIVYZ81NCRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessIVYZ7F3ARequest 学历查询版B
|
||||
func (a *ApiRequestService) ProcessIVYZ7F3ARequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessIVYZ7F3ARequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
name := gjson.GetBytes(params, "name")
|
||||
if !idCard.Exists() || !name.Exists() {
|
||||
return nil, errors.New("api请求, IVYZ7F3A, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("IVYZ7F3A", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "IVYZ7F3A", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
"name": name.String(),
|
||||
"authorized": "1",
|
||||
@@ -1426,7 +1500,7 @@ func (a *ApiRequestService) ProcessIVYZ7F3ARequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessDWBG7F3ARequest 多头借贷行业风险版
|
||||
func (a *ApiRequestService) ProcessDWBG7F3ARequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessDWBG7F3ARequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1434,7 +1508,7 @@ func (a *ApiRequestService) ProcessDWBG7F3ARequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, DWBG7F3A, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("DWBG7F3A", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "DWBG7F3A", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1449,7 +1523,7 @@ func (a *ApiRequestService) ProcessDWBG7F3ARequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ8A2DRequest 特殊名单验证B
|
||||
func (a *ApiRequestService) ProcessJRZQ8A2DRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ8A2DRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1457,7 +1531,7 @@ func (a *ApiRequestService) ProcessJRZQ8A2DRequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ8A2D, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ8A2D", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ8A2D", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1473,13 +1547,13 @@ func (a *ApiRequestService) ProcessJRZQ8A2DRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessYYSY8B1CRequest 手机在网时长B
|
||||
func (a *ApiRequestService) ProcessYYSY8B1CRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessYYSY8B1CRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
if !mobile.Exists() {
|
||||
return nil, errors.New("api请求, YYSY8B1C, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("YYSY8B1C", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "YYSY8B1C", map[string]interface{}{
|
||||
"mobile_no": mobile.String(),
|
||||
})
|
||||
|
||||
@@ -1492,13 +1566,13 @@ func (a *ApiRequestService) ProcessYYSY8B1CRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessYYSY7D3ERequest 携号转网查询
|
||||
func (a *ApiRequestService) ProcessYYSY7D3ERequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessYYSY7D3ERequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
if !mobile.Exists() {
|
||||
return nil, errors.New("api请求, YYSY7D3E, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("YYSY7D3E", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "YYSY7D3E", map[string]interface{}{
|
||||
"mobile_no": mobile.String(),
|
||||
})
|
||||
|
||||
@@ -1511,7 +1585,7 @@ func (a *ApiRequestService) ProcessYYSY7D3ERequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessFLXG7E8FRequest 个人司法涉诉查询
|
||||
func (a *ApiRequestService) ProcessFLXG7E8FRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessFLXG7E8FRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
name := gjson.GetBytes(params, "name")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1519,7 +1593,7 @@ func (a *ApiRequestService) ProcessFLXG7E8FRequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, FLXG7E8F, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("FLXG7E8F", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "FLXG7E8F", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
"name": name.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1534,7 +1608,7 @@ func (a *ApiRequestService) ProcessFLXG7E8FRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessIVYZ8I9JRequest 互联网行为推测
|
||||
func (a *ApiRequestService) ProcessIVYZ8I9JRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessIVYZ8I9JRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
name := gjson.GetBytes(params, "name")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1542,7 +1616,7 @@ func (a *ApiRequestService) ProcessIVYZ8I9JRequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, IVYZ8I9J, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("IVYZ8I9J", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "IVYZ8I9J", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
"name": name.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1557,7 +1631,7 @@ func (a *ApiRequestService) ProcessIVYZ8I9JRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ7F1ARequest 全景雷达
|
||||
func (a *ApiRequestService) ProcessJRZQ7F1ARequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ7F1ARequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1565,7 +1639,7 @@ func (a *ApiRequestService) ProcessJRZQ7F1ARequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ7F1A, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ7F1A", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ7F1A", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
@@ -1581,14 +1655,14 @@ func (a *ApiRequestService) ProcessJRZQ7F1ARequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessIVYZ3P9MRequest 学历实时查询
|
||||
func (a *ApiRequestService) ProcessIVYZ3P9MRequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessIVYZ3P9MRequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
name := gjson.GetBytes(params, "name")
|
||||
if !idCard.Exists() || !name.Exists() {
|
||||
return nil, errors.New("api请求, IVYZ3P9M, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("IVYZ3P9M", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "IVYZ3P9M", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
"name": name.String(),
|
||||
})
|
||||
@@ -1601,7 +1675,7 @@ func (a *ApiRequestService) ProcessIVYZ3P9MRequest(params []byte) ([]byte, error
|
||||
}
|
||||
|
||||
// ProcessJRZQ6F2ARequest 借贷申请
|
||||
func (a *ApiRequestService) ProcessJRZQ6F2ARequest(params []byte) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessJRZQ6F2ARequest(ctx context.Context, params []byte) ([]byte, error) {
|
||||
name := gjson.GetBytes(params, "name")
|
||||
idCard := gjson.GetBytes(params, "id_card")
|
||||
mobile := gjson.GetBytes(params, "mobile")
|
||||
@@ -1609,7 +1683,7 @@ func (a *ApiRequestService) ProcessJRZQ6F2ARequest(params []byte) ([]byte, error
|
||||
return nil, errors.New("api请求, JRZQ6F2A, 获取相关参数失败")
|
||||
}
|
||||
|
||||
resp, err := a.tianyuanapi.CallInterface("JRZQ6F2A", map[string]interface{}{
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "JRZQ6F2A", map[string]interface{}{
|
||||
"name": name.String(),
|
||||
"id_card": idCard.String(),
|
||||
"mobile_no": mobile.String(),
|
||||
|
||||
201
app/main/api/internal/service/tianyuanapiCallLogService.go
Normal file
201
app/main/api/internal/service/tianyuanapiCallLogService.go
Normal file
@@ -0,0 +1,201 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
"ycc-server/app/main/model"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
// TianyuanapiCallLogService 天元API调用记录服务
|
||||
type TianyuanapiCallLogService struct {
|
||||
tianyuanapiCallLogModel model.TianyuanapiCallLogModel
|
||||
featureModel model.FeatureModel
|
||||
}
|
||||
|
||||
// NewTianyuanapiCallLogService 创建天元API调用记录服务
|
||||
func NewTianyuanapiCallLogService(
|
||||
tianyuanapiCallLogModel model.TianyuanapiCallLogModel,
|
||||
featureModel model.FeatureModel,
|
||||
) *TianyuanapiCallLogService {
|
||||
return &TianyuanapiCallLogService{
|
||||
tianyuanapiCallLogModel: tianyuanapiCallLogModel,
|
||||
featureModel: featureModel,
|
||||
}
|
||||
}
|
||||
|
||||
// CallLogOptions 调用记录选项
|
||||
type CallLogOptions struct {
|
||||
FeatureID string // 功能ID
|
||||
ApiID string // API标识(如:YYSYBE08)
|
||||
OrderID string // 订单ID(可选)
|
||||
QueryID string // 查询ID(可选)
|
||||
CallStatus int64 // 调用状态:0=失败,1=成功
|
||||
ResponseTime int64 // 响应耗时(毫秒)
|
||||
ErrorCode string // 错误码(失败时)
|
||||
ErrorMessage string // 错误信息(失败时)
|
||||
RequestParams interface{} // 请求参数(可选)
|
||||
ResponseData interface{} // 响应数据(可选)
|
||||
TransactionID string // 天元API流水号
|
||||
}
|
||||
|
||||
// RecordCall 记录天元API调用
|
||||
func (s *TianyuanapiCallLogService) RecordCall(ctx context.Context, opts CallLogOptions) error {
|
||||
// 1. 获取feature的成本价
|
||||
costPrice := 0.00
|
||||
if opts.CallStatus == 1 { // 只有成功才计算成本
|
||||
feature, err := s.featureModel.FindOne(ctx, opts.FeatureID)
|
||||
if err == nil {
|
||||
costPrice = feature.CostPrice
|
||||
} else {
|
||||
logx.Errorf("查询feature成本价失败,feature_id=%s, err=%v", opts.FeatureID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 转换参数和响应为JSON字符串
|
||||
var requestParamsStr, responseDataStr *string
|
||||
if opts.RequestParams != nil {
|
||||
if bytes, err := json.Marshal(opts.RequestParams); err == nil {
|
||||
jsonStr := string(bytes)
|
||||
requestParamsStr = &jsonStr
|
||||
}
|
||||
}
|
||||
if opts.ResponseData != nil {
|
||||
// 只记录响应数据的前1000个字符,避免存储过大
|
||||
if bytes, err := json.Marshal(opts.ResponseData); err == nil {
|
||||
jsonStr := string(bytes)
|
||||
if len(jsonStr) > 1000 {
|
||||
jsonStr = jsonStr[:1000] + "...[truncated]"
|
||||
}
|
||||
responseDataStr = &jsonStr
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 构建调用记录
|
||||
callTime := time.Now()
|
||||
deleteTime := sql.NullTime{}
|
||||
callLog := &model.TianyuanapiCallLog{
|
||||
FeatureId: opts.FeatureID,
|
||||
ApiId: opts.ApiID,
|
||||
OrderId: sql.NullString{},
|
||||
QueryId: sql.NullString{},
|
||||
CallStatus: opts.CallStatus,
|
||||
CallTime: callTime,
|
||||
ResponseTime: sql.NullInt64{},
|
||||
CostPrice: costPrice,
|
||||
ErrorCode: sql.NullString{},
|
||||
ErrorMessage: sql.NullString{},
|
||||
RequestParams: sql.NullString{},
|
||||
ResponseData: sql.NullString{},
|
||||
TransactionId: sql.NullString{},
|
||||
CreateTime: callTime,
|
||||
UpdateTime: callTime,
|
||||
DeleteTime: deleteTime,
|
||||
DelState: 0,
|
||||
Version: 0,
|
||||
}
|
||||
|
||||
// 4. 填充可选字段
|
||||
if opts.OrderID != "" {
|
||||
callLog.OrderId = sql.NullString{String: opts.OrderID, Valid: true}
|
||||
}
|
||||
if opts.QueryID != "" {
|
||||
callLog.QueryId = sql.NullString{String: opts.QueryID, Valid: true}
|
||||
}
|
||||
if opts.ResponseTime > 0 {
|
||||
callLog.ResponseTime = sql.NullInt64{Int64: opts.ResponseTime, Valid: true}
|
||||
}
|
||||
if opts.ErrorCode != "" {
|
||||
callLog.ErrorCode = sql.NullString{String: opts.ErrorCode, Valid: true}
|
||||
}
|
||||
if opts.ErrorMessage != "" {
|
||||
callLog.ErrorMessage = sql.NullString{String: opts.ErrorMessage, Valid: true}
|
||||
}
|
||||
if requestParamsStr != nil {
|
||||
callLog.RequestParams = sql.NullString{String: *requestParamsStr, Valid: true}
|
||||
}
|
||||
if responseDataStr != nil {
|
||||
callLog.ResponseData = sql.NullString{String: *responseDataStr, Valid: true}
|
||||
}
|
||||
if opts.TransactionID != "" {
|
||||
callLog.TransactionId = sql.NullString{String: opts.TransactionID, Valid: true}
|
||||
}
|
||||
|
||||
// 5. 插入记录
|
||||
_, err := s.tianyuanapiCallLogModel.Insert(ctx, nil, callLog)
|
||||
if err != nil {
|
||||
logx.Errorf("插入天元API调用记录失败,feature_id=%s, api_id=%s, err=%v", opts.FeatureID, opts.ApiID, err)
|
||||
return fmt.Errorf("插入调用记录失败: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetStatistics 获取统计信息
|
||||
type StatisticsFilter struct {
|
||||
FeatureID string // 功能ID
|
||||
ApiID string // API标识
|
||||
StartDate time.Time // 开始日期
|
||||
EndDate time.Time // 结束日期
|
||||
}
|
||||
|
||||
// Statistics 统计信息
|
||||
type Statistics struct {
|
||||
TotalCalls int64 // 总调用次数
|
||||
SuccessCalls int64 // 成功次数
|
||||
FailedCalls int64 // 失败次数
|
||||
TotalCost float64 // 总成本(成功调用的成本之和)
|
||||
}
|
||||
|
||||
// GetStatistics 获取统计信息
|
||||
func (s *TianyuanapiCallLogService) GetStatistics(ctx context.Context, filter StatisticsFilter) (*Statistics, error) {
|
||||
builder := s.tianyuanapiCallLogModel.SelectBuilder()
|
||||
|
||||
// 添加过滤条件
|
||||
if filter.FeatureID != "" {
|
||||
builder = builder.Where(squirrel.Eq{"feature_id": filter.FeatureID})
|
||||
}
|
||||
if filter.ApiID != "" {
|
||||
builder = builder.Where(squirrel.Eq{"api_id": filter.ApiID})
|
||||
}
|
||||
if !filter.StartDate.IsZero() {
|
||||
builder = builder.Where(squirrel.GtOrEq{"call_time": filter.StartDate})
|
||||
}
|
||||
if !filter.EndDate.IsZero() {
|
||||
builder = builder.Where(squirrel.Lt{"call_time": filter.EndDate})
|
||||
}
|
||||
|
||||
// 统计总调用次数
|
||||
totalCalls, err := s.tianyuanapiCallLogModel.FindCount(ctx, builder, "id")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("统计总调用次数失败: %w", err)
|
||||
}
|
||||
|
||||
// 统计成功次数
|
||||
successBuilder := builder.Where(squirrel.Eq{"call_status": 1})
|
||||
successCalls, err := s.tianyuanapiCallLogModel.FindCount(ctx, successBuilder, "id")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("统计成功次数失败: %w", err)
|
||||
}
|
||||
|
||||
// 统计失败次数
|
||||
failedCalls := totalCalls - successCalls
|
||||
|
||||
// 统计总成本(仅成功调用)
|
||||
totalCost, err := s.tianyuanapiCallLogModel.FindSum(ctx, successBuilder, "cost_price")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("统计总成本失败: %w", err)
|
||||
}
|
||||
|
||||
return &Statistics{
|
||||
TotalCalls: totalCalls,
|
||||
SuccessCalls: successCalls,
|
||||
FailedCalls: failedCalls,
|
||||
TotalCost: totalCost,
|
||||
}, nil
|
||||
}
|
||||
@@ -134,6 +134,9 @@ func (s *WhitelistService) GetWhitelistedFeatureApisByIdCard(
|
||||
idCard string,
|
||||
) (map[string]bool, error) {
|
||||
result := make(map[string]bool)
|
||||
if s == nil {
|
||||
return result, nil
|
||||
}
|
||||
if idCard == "" {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ type ServiceContext struct {
|
||||
FeatureModel model.FeatureModel
|
||||
ProductFeatureModel model.ProductFeatureModel
|
||||
|
||||
// 天元API调用记录模型
|
||||
TianyuanapiCallLogModel model.TianyuanapiCallLogModel
|
||||
TianyuanapiCallLogService *service.TianyuanapiCallLogService
|
||||
|
||||
// 白名单相关模型
|
||||
UserFeatureWhitelistModel model.UserFeatureWhitelistModel
|
||||
WhitelistOrderModel model.WhitelistOrderModel
|
||||
@@ -128,6 +132,9 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
featureModel := model.NewFeatureModel(db, cacheConf)
|
||||
productFeatureModel := model.NewProductFeatureModel(db, cacheConf)
|
||||
|
||||
// ============================== 天元API调用记录模型 ==============================
|
||||
tianyuanapiCallLogModel := model.NewTianyuanapiCallLogModel(db, cacheConf)
|
||||
|
||||
// ============================== 白名单相关模型 ==============================
|
||||
userFeatureWhitelistModel := model.NewUserFeatureWhitelistModel(db, cacheConf)
|
||||
whitelistOrderModel := model.NewWhitelistOrderModel(db, cacheConf)
|
||||
@@ -196,8 +203,10 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
alipayService := service.NewAliPayService(c)
|
||||
wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypeWxPayPubKey)
|
||||
applePayService := service.NewApplePayService(c)
|
||||
apiRequestService := service.NewApiRequestService(c, featureModel, productFeatureModel, userFeatureWhitelistModel, tianyuanapi)
|
||||
tianyuanapiCallLogService := service.NewTianyuanapiCallLogService(tianyuanapiCallLogModel, featureModel)
|
||||
// 注意:whitelistService 需要在 apiRequestService 之前创建,因为 apiRequestService 依赖它
|
||||
whitelistService := service.NewWhitelistService(c, userFeatureWhitelistModel, whitelistOrderModel, whitelistOrderItemModel, queryModel, featureModel)
|
||||
apiRequestService := service.NewApiRequestService(c, featureModel, productFeatureModel, userFeatureWhitelistModel, tianyuanapi, tianyuanapiCallLogService, whitelistService)
|
||||
verificationService := service.NewVerificationService(c, tianyuanapi, apiRequestService)
|
||||
asynqService := service.NewAsynqService(c)
|
||||
agentService := service.NewAgentService(c, orderModel, agentModel, agentWalletModel,
|
||||
|
||||
@@ -80,6 +80,14 @@ type CheckFeatureWhitelistStatusResp struct {
|
||||
DataDeleted bool `json:"data_deleted"` // 报告数据是否已删除(仅当提供了query_id时有效)
|
||||
}
|
||||
|
||||
type CheckOrderAgentReq struct {
|
||||
OrderId string `form:"order_id"` // 订单ID
|
||||
}
|
||||
|
||||
type CheckOrderAgentResp struct {
|
||||
IsAgentOrder bool `json:"is_agent_order"` // 是否是当前代理推广的订单
|
||||
}
|
||||
|
||||
type ConversionRateResp struct {
|
||||
MyConversionRate ConversionRateData `json:"my_conversion_rate"` // 我的转化率
|
||||
SubordinateConversionRate ConversionRateData `json:"subordinate_conversion_rate"` // 我的下级转化率
|
||||
|
||||
@@ -37,6 +37,17 @@ type AdminOrderStatistics struct {
|
||||
ChangeRate float64 `json:"change_rate"` // 变化率(百分比)
|
||||
}
|
||||
|
||||
type AdminProfitDetail struct {
|
||||
Revenue float64 `json:"revenue"` // 营收
|
||||
Commission float64 `json:"commission"` // 佣金
|
||||
Rebate float64 `json:"rebate"` // 返利
|
||||
CompanyTax float64 `json:"company_tax"` // 税务成本
|
||||
ApiCost float64 `json:"api_cost"` // API调用成本
|
||||
TaxIncome float64 `json:"tax_income"` // 提现收税
|
||||
Profit float64 `json:"profit"` // 利润
|
||||
ProfitRate float64 `json:"profit_rate"` // 利润率
|
||||
}
|
||||
|
||||
type AdminProfitStatistics struct {
|
||||
TodayProfit float64 `json:"today_profit"` // 今日利润
|
||||
MonthProfit float64 `json:"month_profit"` // 当月利润
|
||||
@@ -44,6 +55,9 @@ type AdminProfitStatistics struct {
|
||||
TodayProfitRate float64 `json:"today_profit_rate"` // 今日利润率
|
||||
MonthProfitRate float64 `json:"month_profit_rate"` // 当月利润率
|
||||
TotalProfitRate float64 `json:"total_profit_rate"` // 总利润率
|
||||
TodayDetail AdminProfitDetail `json:"today_detail"`
|
||||
MonthDetail AdminProfitDetail `json:"month_detail"`
|
||||
TotalDetail AdminProfitDetail `json:"total_detail"`
|
||||
}
|
||||
|
||||
type AdminQueryItem struct {
|
||||
|
||||
@@ -67,6 +67,7 @@ type (
|
||||
ApiId string `db:"api_id"` // API标识
|
||||
Name string `db:"name"` // 描述
|
||||
WhitelistPrice float64 `db:"whitelist_price"` // 白名单屏蔽价格(单位:元)
|
||||
CostPrice float64 `db:"cost_price"` // 天远API调用成本价(单位:元)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -83,11 +84,11 @@ func (m *defaultFeatureModel) Insert(ctx context.Context, session sqlx.Session,
|
||||
yccFeatureApiIdKey := fmt.Sprintf("%s%v", cacheYccFeatureApiIdPrefix, data.ApiId)
|
||||
yccFeatureIdKey := fmt.Sprintf("%s%v", cacheYccFeatureIdPrefix, data.Id)
|
||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?)", m.table, featureRowsExpectAutoSet)
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?)", m.table, featureRowsExpectAutoSet)
|
||||
if session != nil {
|
||||
return session.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.ApiId, data.Name, data.WhitelistPrice)
|
||||
return session.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.ApiId, data.Name, data.WhitelistPrice, data.CostPrice)
|
||||
}
|
||||
return conn.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.ApiId, data.Name, data.WhitelistPrice)
|
||||
return conn.ExecCtx(ctx, query, data.Id, data.DeleteTime, data.DelState, data.Version, data.ApiId, data.Name, data.WhitelistPrice, data.CostPrice)
|
||||
}, yccFeatureApiIdKey, yccFeatureIdKey)
|
||||
}
|
||||
func (m *defaultFeatureModel) insertUUID(data *Feature) {
|
||||
@@ -154,9 +155,9 @@ func (m *defaultFeatureModel) Update(ctx context.Context, session sqlx.Session,
|
||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, featureRowsWithPlaceHolder)
|
||||
if session != nil {
|
||||
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ApiId, newData.Name, newData.WhitelistPrice, newData.Id)
|
||||
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ApiId, newData.Name, newData.WhitelistPrice, newData.CostPrice, newData.Id)
|
||||
}
|
||||
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ApiId, newData.Name, newData.WhitelistPrice, newData.Id)
|
||||
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ApiId, newData.Name, newData.WhitelistPrice, newData.CostPrice, newData.Id)
|
||||
}, yccFeatureApiIdKey, yccFeatureIdKey)
|
||||
}
|
||||
|
||||
@@ -177,9 +178,9 @@ func (m *defaultFeatureModel) UpdateWithVersion(ctx context.Context, session sql
|
||||
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, featureRowsWithPlaceHolder)
|
||||
if session != nil {
|
||||
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ApiId, newData.Name, newData.WhitelistPrice, newData.Id, oldVersion)
|
||||
return session.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ApiId, newData.Name, newData.WhitelistPrice, newData.CostPrice, newData.Id, oldVersion)
|
||||
}
|
||||
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ApiId, newData.Name, newData.WhitelistPrice, newData.Id, oldVersion)
|
||||
return conn.ExecCtx(ctx, query, newData.DeleteTime, newData.DelState, newData.Version, newData.ApiId, newData.Name, newData.WhitelistPrice, newData.CostPrice, newData.Id, oldVersion)
|
||||
}, yccFeatureApiIdKey, yccFeatureIdKey)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
27
app/main/model/tianyuanapiCallLogModel.go
Normal file
27
app/main/model/tianyuanapiCallLogModel.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
var _ TianyuanapiCallLogModel = (*customTianyuanapiCallLogModel)(nil)
|
||||
|
||||
type (
|
||||
// TianyuanapiCallLogModel is an interface to be customized, add more methods here,
|
||||
// and implement the added methods in customTianyuanapiCallLogModel.
|
||||
TianyuanapiCallLogModel interface {
|
||||
tianyuanapiCallLogModel
|
||||
}
|
||||
|
||||
customTianyuanapiCallLogModel struct {
|
||||
*defaultTianyuanapiCallLogModel
|
||||
}
|
||||
)
|
||||
|
||||
// NewTianyuanapiCallLogModel returns a model for the database table.
|
||||
func NewTianyuanapiCallLogModel(conn sqlx.SqlConn, c cache.CacheConf) TianyuanapiCallLogModel {
|
||||
return &customTianyuanapiCallLogModel{
|
||||
defaultTianyuanapiCallLogModel: newTianyuanapiCallLogModel(conn, c),
|
||||
}
|
||||
}
|
||||
398
app/main/model/tianyuanapiCallLogModel_gen.go
Normal file
398
app/main/model/tianyuanapiCallLogModel_gen.go
Normal file
@@ -0,0 +1,398 @@
|
||||
// Code generated by goctl. DO NOT EDIT!
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/builder"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlc"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"github.com/zeromicro/go-zero/core/stringx"
|
||||
"ycc-server/common/globalkey"
|
||||
)
|
||||
|
||||
var (
|
||||
tianyuanapiCallLogFieldNames = builder.RawFieldNames(&TianyuanapiCallLog{})
|
||||
tianyuanapiCallLogRows = strings.Join(tianyuanapiCallLogFieldNames, ",")
|
||||
tianyuanapiCallLogRowsExpectAutoSet = strings.Join(stringx.Remove(tianyuanapiCallLogFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
|
||||
tianyuanapiCallLogRowsWithPlaceHolder = strings.Join(stringx.Remove(tianyuanapiCallLogFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
|
||||
|
||||
cacheYccTianyuanapiCallLogIdPrefix = "cache:ycc:tianyuanapiCallLog:id:"
|
||||
)
|
||||
|
||||
type (
|
||||
tianyuanapiCallLogModel interface {
|
||||
Insert(ctx context.Context, session sqlx.Session, data *TianyuanapiCallLog) (sql.Result, error)
|
||||
FindOne(ctx context.Context, id int64) (*TianyuanapiCallLog, error)
|
||||
Update(ctx context.Context, session sqlx.Session, data *TianyuanapiCallLog) (sql.Result, error)
|
||||
UpdateWithVersion(ctx context.Context, session sqlx.Session, data *TianyuanapiCallLog) error
|
||||
Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error
|
||||
SelectBuilder() squirrel.SelectBuilder
|
||||
DeleteSoft(ctx context.Context, session sqlx.Session, data *TianyuanapiCallLog) error
|
||||
FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error)
|
||||
FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error)
|
||||
FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*TianyuanapiCallLog, error)
|
||||
FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*TianyuanapiCallLog, error)
|
||||
FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*TianyuanapiCallLog, int64, error)
|
||||
FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*TianyuanapiCallLog, error)
|
||||
FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*TianyuanapiCallLog, error)
|
||||
Delete(ctx context.Context, session sqlx.Session, id int64) error
|
||||
}
|
||||
|
||||
defaultTianyuanapiCallLogModel struct {
|
||||
sqlc.CachedConn
|
||||
table string
|
||||
}
|
||||
|
||||
TianyuanapiCallLog struct {
|
||||
Id int64 `db:"id"` // 主键ID
|
||||
FeatureId string `db:"feature_id"` // 功能ID(关联feature表)
|
||||
ApiId string `db:"api_id"` // API标识(如:YYSYBE08)
|
||||
OrderId sql.NullString `db:"order_id"` // 订单ID(关联order表)
|
||||
QueryId sql.NullString `db:"query_id"` // 查询ID(关联query表)
|
||||
CallStatus int64 `db:"call_status"` // 调用状态:0=失败,1=成功
|
||||
CallTime time.Time `db:"call_time"` // 调用时间
|
||||
ResponseTime sql.NullInt64 `db:"response_time"` // 响应耗时(毫秒)
|
||||
CostPrice float64 `db:"cost_price"` // 本次调用成本(成功时从feature.cost_price获取,失败时为0)
|
||||
ErrorCode sql.NullString `db:"error_code"` // 错误码(失败时记录)
|
||||
ErrorMessage sql.NullString `db:"error_message"` // 错误信息(失败时记录)
|
||||
RequestParams sql.NullString `db:"request_params"` // 请求参数(JSON格式)
|
||||
ResponseData sql.NullString `db:"response_data"` // 响应数据(JSON格式,仅记录关键信息)
|
||||
TransactionId sql.NullString `db:"transaction_id"` // 天远API流水号
|
||||
CreateTime time.Time `db:"create_time"` // 创建时间
|
||||
UpdateTime time.Time `db:"update_time"` // 更新时间
|
||||
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
|
||||
DelState int64 `db:"del_state"` // 删除状态:0=未删除,1=已删除
|
||||
Version int64 `db:"version"` // 版本号(乐观锁)
|
||||
}
|
||||
)
|
||||
|
||||
func newTianyuanapiCallLogModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultTianyuanapiCallLogModel {
|
||||
return &defaultTianyuanapiCallLogModel{
|
||||
CachedConn: sqlc.NewConn(conn, c),
|
||||
table: "`tianyuanapi_call_log`",
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) Insert(ctx context.Context, session sqlx.Session, data *TianyuanapiCallLog) (sql.Result, error) {
|
||||
data.DelState = globalkey.DelStateNo
|
||||
m.insertUUID(data)
|
||||
yccTianyuanapiCallLogIdKey := fmt.Sprintf("%s%v", cacheYccTianyuanapiCallLogIdPrefix, data.Id)
|
||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, tianyuanapiCallLogRowsExpectAutoSet)
|
||||
if session != nil {
|
||||
return session.ExecCtx(ctx, query, data.FeatureId, data.ApiId, data.OrderId, data.QueryId, data.CallStatus, data.CallTime, data.ResponseTime, data.CostPrice, data.ErrorCode, data.ErrorMessage, data.RequestParams, data.ResponseData, data.TransactionId, data.DeleteTime, data.DelState, data.Version)
|
||||
}
|
||||
return conn.ExecCtx(ctx, query, data.FeatureId, data.ApiId, data.OrderId, data.QueryId, data.CallStatus, data.CallTime, data.ResponseTime, data.CostPrice, data.ErrorCode, data.ErrorMessage, data.RequestParams, data.ResponseData, data.TransactionId, data.DeleteTime, data.DelState, data.Version)
|
||||
}, yccTianyuanapiCallLogIdKey)
|
||||
}
|
||||
func (m *defaultTianyuanapiCallLogModel) insertUUID(data *TianyuanapiCallLog) {
|
||||
t := reflect.TypeOf(data).Elem()
|
||||
v := reflect.ValueOf(data).Elem()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
sf := t.Field(i)
|
||||
if sf.Tag.Get("db") == "id" {
|
||||
f := v.Field(i)
|
||||
if f.IsValid() && f.CanSet() && f.Kind() == reflect.String {
|
||||
if f.String() == "" {
|
||||
f.SetString(uuid.NewString())
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) FindOne(ctx context.Context, id int64) (*TianyuanapiCallLog, error) {
|
||||
yccTianyuanapiCallLogIdKey := fmt.Sprintf("%s%v", cacheYccTianyuanapiCallLogIdPrefix, id)
|
||||
var resp TianyuanapiCallLog
|
||||
err := m.QueryRowCtx(ctx, &resp, yccTianyuanapiCallLogIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", tianyuanapiCallLogRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo)
|
||||
})
|
||||
switch err {
|
||||
case nil:
|
||||
return &resp, nil
|
||||
case sqlc.ErrNotFound:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) Update(ctx context.Context, session sqlx.Session, data *TianyuanapiCallLog) (sql.Result, error) {
|
||||
yccTianyuanapiCallLogIdKey := fmt.Sprintf("%s%v", cacheYccTianyuanapiCallLogIdPrefix, data.Id)
|
||||
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, tianyuanapiCallLogRowsWithPlaceHolder)
|
||||
if session != nil {
|
||||
return session.ExecCtx(ctx, query, data.FeatureId, data.ApiId, data.OrderId, data.QueryId, data.CallStatus, data.CallTime, data.ResponseTime, data.CostPrice, data.ErrorCode, data.ErrorMessage, data.RequestParams, data.ResponseData, data.TransactionId, data.DeleteTime, data.DelState, data.Version, data.Id)
|
||||
}
|
||||
return conn.ExecCtx(ctx, query, data.FeatureId, data.ApiId, data.OrderId, data.QueryId, data.CallStatus, data.CallTime, data.ResponseTime, data.CostPrice, data.ErrorCode, data.ErrorMessage, data.RequestParams, data.ResponseData, data.TransactionId, data.DeleteTime, data.DelState, data.Version, data.Id)
|
||||
}, yccTianyuanapiCallLogIdKey)
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, data *TianyuanapiCallLog) error {
|
||||
|
||||
oldVersion := data.Version
|
||||
data.Version += 1
|
||||
|
||||
var sqlResult sql.Result
|
||||
var err error
|
||||
|
||||
yccTianyuanapiCallLogIdKey := fmt.Sprintf("%s%v", cacheYccTianyuanapiCallLogIdPrefix, data.Id)
|
||||
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, tianyuanapiCallLogRowsWithPlaceHolder)
|
||||
if session != nil {
|
||||
return session.ExecCtx(ctx, query, data.FeatureId, data.ApiId, data.OrderId, data.QueryId, data.CallStatus, data.CallTime, data.ResponseTime, data.CostPrice, data.ErrorCode, data.ErrorMessage, data.RequestParams, data.ResponseData, data.TransactionId, data.DeleteTime, data.DelState, data.Version, data.Id, oldVersion)
|
||||
}
|
||||
return conn.ExecCtx(ctx, query, data.FeatureId, data.ApiId, data.OrderId, data.QueryId, data.CallStatus, data.CallTime, data.ResponseTime, data.CostPrice, data.ErrorCode, data.ErrorMessage, data.RequestParams, data.ResponseData, data.TransactionId, data.DeleteTime, data.DelState, data.Version, data.Id, oldVersion)
|
||||
}, yccTianyuanapiCallLogIdKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateCount, err := sqlResult.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if updateCount == 0 {
|
||||
return ErrNoRowsUpdate
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *TianyuanapiCallLog) error {
|
||||
data.DelState = globalkey.DelStateYes
|
||||
data.DeleteTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||
if err := m.UpdateWithVersion(ctx, session, data); err != nil {
|
||||
return errors.Wrapf(errors.New("delete soft failed "), "TianyuanapiCallLogModel delete err : %+v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) FindSum(ctx context.Context, builder squirrel.SelectBuilder, field string) (float64, error) {
|
||||
|
||||
if len(field) == 0 {
|
||||
return 0, errors.Wrapf(errors.New("FindSum Least One Field"), "FindSum Least One Field")
|
||||
}
|
||||
|
||||
builder = builder.Columns("IFNULL(SUM(" + field + "),0)")
|
||||
|
||||
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var resp float64
|
||||
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
|
||||
switch err {
|
||||
case nil:
|
||||
return resp, nil
|
||||
default:
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder, field string) (int64, error) {
|
||||
|
||||
if len(field) == 0 {
|
||||
return 0, errors.Wrapf(errors.New("FindCount Least One Field"), "FindCount Least One Field")
|
||||
}
|
||||
|
||||
builder = builder.Columns("COUNT(" + field + ")")
|
||||
|
||||
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var resp int64
|
||||
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
|
||||
switch err {
|
||||
case nil:
|
||||
return resp, nil
|
||||
default:
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder, orderBy string) ([]*TianyuanapiCallLog, error) {
|
||||
|
||||
builder = builder.Columns(tianyuanapiCallLogRows)
|
||||
|
||||
if orderBy == "" {
|
||||
builder = builder.OrderBy("id DESC")
|
||||
} else {
|
||||
builder = builder.OrderBy(orderBy)
|
||||
}
|
||||
|
||||
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []*TianyuanapiCallLog
|
||||
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
|
||||
switch err {
|
||||
case nil:
|
||||
return resp, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*TianyuanapiCallLog, error) {
|
||||
|
||||
builder = builder.Columns(tianyuanapiCallLogRows)
|
||||
|
||||
if orderBy == "" {
|
||||
builder = builder.OrderBy("id DESC")
|
||||
} else {
|
||||
builder = builder.OrderBy(orderBy)
|
||||
}
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []*TianyuanapiCallLog
|
||||
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
|
||||
switch err {
|
||||
case nil:
|
||||
return resp, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) FindPageListByPageWithTotal(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*TianyuanapiCallLog, int64, error) {
|
||||
|
||||
total, err := m.FindCount(ctx, builder, "id")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
builder = builder.Columns(tianyuanapiCallLogRows)
|
||||
|
||||
if orderBy == "" {
|
||||
builder = builder.OrderBy("id DESC")
|
||||
} else {
|
||||
builder = builder.OrderBy(orderBy)
|
||||
}
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
|
||||
if err != nil {
|
||||
return nil, total, err
|
||||
}
|
||||
|
||||
var resp []*TianyuanapiCallLog
|
||||
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
|
||||
switch err {
|
||||
case nil:
|
||||
return resp, total, nil
|
||||
default:
|
||||
return nil, total, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) FindPageListByIdDESC(ctx context.Context, builder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*TianyuanapiCallLog, error) {
|
||||
|
||||
builder = builder.Columns(tianyuanapiCallLogRows)
|
||||
|
||||
if preMinId > 0 {
|
||||
builder = builder.Where(" id < ? ", preMinId)
|
||||
}
|
||||
|
||||
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id DESC").Limit(uint64(pageSize)).ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []*TianyuanapiCallLog
|
||||
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
|
||||
switch err {
|
||||
case nil:
|
||||
return resp, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) FindPageListByIdASC(ctx context.Context, builder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*TianyuanapiCallLog, error) {
|
||||
|
||||
builder = builder.Columns(tianyuanapiCallLogRows)
|
||||
|
||||
if preMaxId > 0 {
|
||||
builder = builder.Where(" id > ? ", preMaxId)
|
||||
}
|
||||
|
||||
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id ASC").Limit(uint64(pageSize)).ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []*TianyuanapiCallLog
|
||||
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
|
||||
switch err {
|
||||
case nil:
|
||||
return resp, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {
|
||||
|
||||
return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
return fn(ctx, session)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) SelectBuilder() squirrel.SelectBuilder {
|
||||
return squirrel.Select().From(m.table)
|
||||
}
|
||||
func (m *defaultTianyuanapiCallLogModel) Delete(ctx context.Context, session sqlx.Session, id int64) error {
|
||||
yccTianyuanapiCallLogIdKey := fmt.Sprintf("%s%v", cacheYccTianyuanapiCallLogIdPrefix, id)
|
||||
_, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
|
||||
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
|
||||
if session != nil {
|
||||
return session.ExecCtx(ctx, query, id)
|
||||
}
|
||||
return conn.ExecCtx(ctx, query, id)
|
||||
}, yccTianyuanapiCallLogIdKey)
|
||||
return err
|
||||
}
|
||||
func (m *defaultTianyuanapiCallLogModel) formatPrimary(primary interface{}) string {
|
||||
return fmt.Sprintf("%s%v", cacheYccTianyuanapiCallLogIdPrefix, primary)
|
||||
}
|
||||
func (m *defaultTianyuanapiCallLogModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error {
|
||||
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", tianyuanapiCallLogRows, m.table)
|
||||
return conn.QueryRowCtx(ctx, v, query, primary, globalkey.DelStateNo)
|
||||
}
|
||||
|
||||
func (m *defaultTianyuanapiCallLogModel) tableName() string {
|
||||
return m.table
|
||||
}
|
||||
@@ -45,7 +45,7 @@ $tables = @(
|
||||
# "agent_withdrawal_tax",
|
||||
# "authorization_document",
|
||||
# "example",
|
||||
# "feature"
|
||||
"feature"
|
||||
# "alipay_from_callback"
|
||||
# "global_notifications",
|
||||
# "order",
|
||||
@@ -61,10 +61,11 @@ $tables = @(
|
||||
# "whitelist_order",
|
||||
# "whitelist_order_item",
|
||||
# "user_feature_whitelist"
|
||||
"complaint_main",
|
||||
"complaint_alipay",
|
||||
"complaint_alipay_trade",
|
||||
"complaint_manual"
|
||||
# "complaint_main",
|
||||
# "complaint_alipay",
|
||||
# "complaint_alipay_trade",
|
||||
# "complaint_manual"
|
||||
# "tianyuanapi_call_log"
|
||||
)
|
||||
|
||||
# 为每个表生成模型
|
||||
|
||||
158
deploy/sql/Context参数优化说明.md
Normal file
158
deploy/sql/Context参数优化说明.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Context参数优化说明
|
||||
|
||||
## 优化内容
|
||||
|
||||
将 `ctx context.Context` 从 `ProcessRequests` 方法作为参数传入,而不是在每个 `ProcessXXXRequest` 方法内部创建。
|
||||
|
||||
## 优化原因
|
||||
|
||||
1. **更好的上下文管理**:可以从上层传递 context,支持超时、取消等操作
|
||||
2. **避免重复代码**:不需要在每个方法里都写 `ctx := context.Background()`
|
||||
3. **更好的可追踪性**:可以通过 context 传递请求ID、用户ID等元数据
|
||||
4. **符合Go最佳实践**:context 应该作为第一个参数传递
|
||||
|
||||
## 修改内容
|
||||
|
||||
### 1. ProcessRequests 方法签名修改
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]byte, error) {
|
||||
var ctx, cancel = context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
func (a *ApiRequestService) ProcessRequests(ctx context.Context, params []byte, productID string) ([]byte, error) {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
```
|
||||
|
||||
### 2. PreprocessRequestApi 方法修改
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
func (a *ApiRequestService) PreprocessRequestApi(params []byte, apiID string) ([]byte, error) {
|
||||
if processor, exists := requestProcessors[apiID]; exists {
|
||||
return processor(a, params)
|
||||
}
|
||||
return nil, errors.New("api请求, 未找到相应的处理程序")
|
||||
}
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
func (a *ApiRequestService) PreprocessRequestApi(ctx context.Context, params []byte, apiID string) ([]byte, error) {
|
||||
if processor, exists := requestProcessors[apiID]; exists {
|
||||
return processor(a, ctx, params)
|
||||
}
|
||||
return nil, errors.New("api请求, 未找到相应的处理程序")
|
||||
}
|
||||
```
|
||||
|
||||
### 3. requestProcessors map 类型定义修改
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
var requestProcessors = map[string]func(*ApiRequestService, []byte) ([]byte, error){
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
var requestProcessors = map[string]func(*ApiRequestService, context.Context, []byte) ([]byte, error){
|
||||
```
|
||||
|
||||
### 4. 所有 ProcessXXXRequest 方法签名修改
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
func (a *ApiRequestService) ProcessYYSYBE08Request(params []byte) ([]byte, error) {
|
||||
ctx := context.Background()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
func (a *ApiRequestService) ProcessYYSYBE08Request(ctx context.Context, params []byte) ([]byte, error) {
|
||||
// 移除了 ctx := context.Background()
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 错误码提取优化
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
if tianyuanErr, ok := err.(*tianyuanapi.Error); ok {
|
||||
errorCode = fmt.Sprintf("%d", tianyuanErr.Code)
|
||||
}
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
if code := tianyuanapi.GetCodeByError(err); code != -1 {
|
||||
errorCode = fmt.Sprintf("%d", code)
|
||||
}
|
||||
```
|
||||
|
||||
## 修改的方法列表(32个)
|
||||
|
||||
所有以下方法都已添加 `ctx context.Context` 作为第一个参数,并移除了内部的 `ctx := context.Background()` 声明:
|
||||
|
||||
1. ProcessPersonEnterpriseProRequest
|
||||
2. ProcessBehaviorRiskScanRequest
|
||||
3. ProcessYYSYBE08Request
|
||||
4. ProcessYYSY09CDRequest
|
||||
5. ProcessFLXG0687Request
|
||||
6. ProcessFLXG3D56Request
|
||||
7. ProcessFLXG0V4BRequest
|
||||
8. ProcessQYGL8271Request
|
||||
9. ProcessIVYZ5733Request
|
||||
10. ProcessIVYZ9A2BRequest
|
||||
11. ProcessJRZQ0A03Request
|
||||
12. ProcessQYGL6F2DRequest
|
||||
13. ProcessJRZQ8203Request
|
||||
14. ProcessJRZQ4AA8Request
|
||||
15. ProcessQCXG7A2BRequest
|
||||
16. ProcessDWBG8B4DRequest
|
||||
17. ProcessDWBG6A2CRequest
|
||||
18. ProcessJRZQ4B6CRequest
|
||||
19. ProcessJRZQ09J8Request
|
||||
20. ProcessJRZQ5E9FRequest
|
||||
21. ProcessQYGL3F8ERequest
|
||||
22. ProcessIVYZ81NCRequest
|
||||
23. ProcessIVYZ7F3ARequest
|
||||
24. ProcessDWBG7F3ARequest
|
||||
25. ProcessJRZQ8A2DRequest
|
||||
26. ProcessYYSY8B1CRequest
|
||||
27. ProcessYYSY7D3ERequest
|
||||
28. ProcessFLXG7E8FRequest
|
||||
29. ProcessIVYZ8I9JRequest
|
||||
30. ProcessJRZQ7F1ARequest
|
||||
31. ProcessIVYZ3P9MRequest
|
||||
32. ProcessJRZQ6F2ARequest
|
||||
|
||||
## 调用方验证
|
||||
|
||||
调用方 `paySuccessNotify.go` 已经正确传递了 `ctx`:
|
||||
|
||||
```go
|
||||
combinedResponse, err := l.svcCtx.ApiRequestService.ProcessRequests(ctx, decryptData, product.Id)
|
||||
```
|
||||
|
||||
## 优势
|
||||
|
||||
1. **统一的上下文管理**:所有API调用共享同一个 context,可以统一控制超时和取消
|
||||
2. **更好的错误追踪**:可以在 context 中传递请求ID、用户ID等信息,方便日志追踪
|
||||
3. **代码更简洁**:不需要在每个方法中重复创建 context
|
||||
4. **符合Go规范**:context 作为第一个参数是 Go 的标准做法
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 所有方法现在都依赖外部传入的 `ctx`,不再内部创建
|
||||
- `ProcessRequests` 方法内部仍然会创建一个带 cancel 的 context,用于控制并发请求的取消
|
||||
- 如果将来需要在 context 中传递元数据(如请求ID、用户ID),可以在调用 `ProcessRequests` 之前设置
|
||||
|
||||
35
deploy/sql/generate_tianyuanapi_models.sh
Normal file
35
deploy/sql/generate_tianyuanapi_models.sh
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 天元API调用记录表 - Model生成脚本
|
||||
|
||||
# 数据库配置(从main.yaml中提取)
|
||||
DB_HOST="ycc_mysql:3306"
|
||||
DB_USER="ycc"
|
||||
DB_PASS="5vg67b3UNHu8"
|
||||
DB_NAME="ycc"
|
||||
MODEL_DIR="../../app/main/model"
|
||||
TEMPLATE_DIR="./template"
|
||||
|
||||
# 生成feature表(已添加cost_price字段)
|
||||
echo "正在生成 feature 表Model..."
|
||||
goctl model mysql datasource -url="$DB_USER:$DB_PASS@tcp($DB_HOST)/$DB_NAME" -table="feature" -dir="$MODEL_DIR" -cache=true --style=goZero --home="$TEMPLATE_DIR"
|
||||
|
||||
# 生成tianyuanapi_call_log表
|
||||
echo "正在生成 tianyuanapi_call_log 表Model..."
|
||||
goctl model mysql datasource -url="$DB_USER:$DB_PASS@tcp($DB_HOST)/$DB_NAME" -table="tianyuanapi_call_log" -dir="$MODEL_DIR" -cache=true --style=goZero --home="$TEMPLATE_DIR"
|
||||
|
||||
echo "========================================="
|
||||
echo "Model生成完成!"
|
||||
echo "========================================="
|
||||
echo "生成的文件:"
|
||||
echo " 1. featureModel_gen.go (已更新)"
|
||||
echo " 2. featureModel.go (已更新)"
|
||||
echo " 3. tianyuanapiCallLogModel_gen.go (新建)"
|
||||
echo " 4. tianyuanapiCallLogModel.go (新建)"
|
||||
echo "========================================="
|
||||
echo "下一步:"
|
||||
echo " 1. 检查生成的Model文件"
|
||||
echo " 2. 更新svc/servicecontext.go,添加新Model的初始化"
|
||||
echo " 3. 在apirequestService.go中添加调用记录逻辑"
|
||||
echo "========================================="
|
||||
|
||||
64
deploy/sql/tianyuanapi_cost_migration.sql
Normal file
64
deploy/sql/tianyuanapi_cost_migration.sql
Normal file
@@ -0,0 +1,64 @@
|
||||
-- ============================================
|
||||
-- Feature表 - 添加成本价字段
|
||||
-- 说明:为 feature 表添加天远API调用成本价字段
|
||||
-- 执行时间:2025-01-13
|
||||
-- ============================================
|
||||
|
||||
-- 添加成本价字段
|
||||
ALTER TABLE `feature`
|
||||
ADD COLUMN `cost_price` decimal(10, 2) DEFAULT 0.00 COMMENT '天远API调用成本价(单位:元)' AFTER `whitelist_price`;
|
||||
|
||||
-- ============================================
|
||||
-- 说明:
|
||||
-- 1. cost_price 默认值为 0.00,表示该feature的成本价为0元
|
||||
-- 2. 后台可以在"功能管理"页面配置每个feature的调用成本
|
||||
-- 3. 成本价用于统计天远API的调用成本
|
||||
-- ============================================
|
||||
|
||||
-- ============================================
|
||||
-- 天远API调用记录表
|
||||
-- 说明:记录每次调用天远API的详细信息
|
||||
-- ============================================
|
||||
|
||||
CREATE TABLE `tianyuanapi_call_log` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`feature_id` varchar(36) NOT NULL COMMENT '功能ID(关联feature表)',
|
||||
`api_id` varchar(50) NOT NULL COMMENT 'API标识(如:YYSYBE08)',
|
||||
`order_id` varchar(36) DEFAULT NULL COMMENT '订单ID(关联order表)',
|
||||
`query_id` varchar(36) DEFAULT NULL COMMENT '查询ID(关联query表)',
|
||||
`call_status` tinyint NOT NULL DEFAULT 0 COMMENT '调用状态:0=失败,1=成功',
|
||||
`call_time` datetime NOT NULL COMMENT '调用时间',
|
||||
`response_time` int DEFAULT NULL COMMENT '响应耗时(毫秒)',
|
||||
`cost_price` decimal(10, 2) DEFAULT 0.00 COMMENT '本次调用成本(成功时从feature.cost_price获取,失败时为0)',
|
||||
`error_code` varchar(50) DEFAULT NULL COMMENT '错误码(失败时记录)',
|
||||
`error_message` varchar(500) DEFAULT NULL COMMENT '错误信息(失败时记录)',
|
||||
`request_params` text DEFAULT NULL COMMENT '请求参数(JSON格式)',
|
||||
`response_data` text DEFAULT NULL COMMENT '响应数据(JSON格式,仅记录关键信息)',
|
||||
`transaction_id` varchar(100) DEFAULT NULL COMMENT '天远API流水号',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
|
||||
`del_state` tinyint NOT NULL DEFAULT 0 COMMENT '删除状态:0=未删除,1=已删除',
|
||||
`version` bigint NOT NULL DEFAULT 0 COMMENT '版本号(乐观锁)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_feature_id` (`feature_id`),
|
||||
KEY `idx_api_id` (`api_id`),
|
||||
KEY `idx_order_id` (`order_id`),
|
||||
KEY `idx_query_id` (`query_id`),
|
||||
KEY `idx_call_status` (`call_status`),
|
||||
KEY `idx_call_time` (`call_time`),
|
||||
KEY `idx_feature_time` (`feature_id`, `call_time`) COMMENT '复合索引:查询某个功能在某段时间的调用记录'
|
||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '天远API调用记录表';
|
||||
|
||||
-- ============================================
|
||||
-- 说明:
|
||||
-- 1. feature_id: 关联到feature表,记录是哪个接口的调用
|
||||
-- 2. api_id: 天远API的接口标识(如:YYSYBE08)
|
||||
-- 3. order_id/query_id: 关联订单或查询,方便追溯
|
||||
-- 4. call_status: 调用状态,成功=1,失败=0
|
||||
-- 5. cost_price: 成本价,成功时为feature.cost_price,失败时为0
|
||||
-- 6. error_code/error_message: 失败时记录错误信息
|
||||
-- 7. request_params/response_data: 请求和响应数据(可选择性记录)
|
||||
-- 8. transaction_id: 天远API返回的流水号
|
||||
-- 9. 无论成功失败都会记录,方便统计分析
|
||||
-- ============================================
|
||||
183
deploy/sql/优化后的批量修改说明.md
Normal file
183
deploy/sql/优化后的批量修改说明.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# 优化后的批量修改说明 - 使用ctx参数
|
||||
|
||||
## 优化说明
|
||||
|
||||
根据建议,我们通过 `ProcessRequests` 方法传入 `ctx context.Context` 参数,而不是在每个方法内部创建 `context.Background()`。
|
||||
|
||||
这样的好处:
|
||||
1. **符合Go最佳实践**:Context应该从上层传入
|
||||
2. **更好的控制**:可以统一控制请求超时、取消等
|
||||
3. **代码更简洁**:不需要在每个方法中重复创建context
|
||||
4. **更好的追踪**:可以统一传递追踪信息
|
||||
|
||||
## 已完成的修改
|
||||
|
||||
### 1. 修改了 ProcessRequests 方法签名
|
||||
```go
|
||||
func (a *ApiRequestService) ProcessRequests(ctx context.Context, params []byte, productID string) ([]byte, error)
|
||||
```
|
||||
- 移除了内部的 `ctx, cancel = context.WithCancel(context.Background())`
|
||||
- 直接使用外部传入的 `ctx`
|
||||
|
||||
### 2. 定义了 RequestProcessor 类型
|
||||
```go
|
||||
type RequestProcessor func(ctx context.Context, a *ApiRequestService, params []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
### 3. 更新了 requestProcessors 映射
|
||||
所有方法签名的类型都更新为接收 `context.Context` 参数
|
||||
|
||||
### 4. 修改了 PreprocessRequestApi 方法
|
||||
```go
|
||||
func (a *ApiRequestService) PreprocessRequestApi(ctx context.Context, params []byte, apiID string) ([]byte, error) {
|
||||
if processor, exists := requestProcessors[apiID]; exists {
|
||||
return processor(ctx, a, params) // 传递ctx
|
||||
}
|
||||
return nil, errors.New("api请求, 未找到相应的处理程序")
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 修改了示例方法
|
||||
- `ProcessYYSYBE08Request` ✅ - 已添加 `ctx context.Context` 参数
|
||||
- `ProcessFLXG0V4BRequest` ✅ - 已添加 `ctx context.Context` 参数
|
||||
|
||||
## 需要完成的修改
|
||||
|
||||
现在还需要修改剩余30个方法的签名,在每个方法签名的 `params` 参数前添加 `ctx context.Context` 参数。
|
||||
|
||||
### 方法1:使用批量修改脚本(推荐)
|
||||
|
||||
#### Linux/Mac 环境
|
||||
```bash
|
||||
cd ycc-proxy-server
|
||||
chmod +x deploy/sql/批量修改方法签名.sh
|
||||
./deploy/sql/批量修改方法签名.sh
|
||||
```
|
||||
|
||||
这个脚本会:
|
||||
1. 备份 `apirequestService.go` 文件
|
||||
2. 批量修改31个方法的签名
|
||||
3. 显示修改统计
|
||||
|
||||
### 方法2:使用IDE查找替换(Windows环境推荐)
|
||||
|
||||
#### 步骤1:在IDE中打开查找替换
|
||||
打开 `apirequestService.go`,按 `Ctrl+H` 打开查找替换
|
||||
|
||||
#### 步骤2:查找并替换
|
||||
**查找内容:**
|
||||
```text
|
||||
func (a *ApiRequestService) Process(params []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
**替换为:**
|
||||
```text
|
||||
func (a *ApiRequestService) Process(ctx context.Context, params []byte) ([]byte, error)
|
||||
```
|
||||
|
||||
**注意:**
|
||||
- 这个模式会匹配所有 `Process*Request` 方法
|
||||
- 点击"全部替换"即可
|
||||
|
||||
#### 步骤3:验证替换
|
||||
替换后,检查是否所有31个方法都成功修改。如果没有修改成功,可能是因为:
|
||||
1. 某些方法已经修改过了
|
||||
2. 方法签名格式有差异
|
||||
|
||||
### 方法3:逐个手动修改
|
||||
|
||||
如果批量方法不适用,可以逐个修改。需要修改的方法列表:
|
||||
|
||||
#### 已修改 ✅
|
||||
1. ProcessYYSYBE08Request
|
||||
2. ProcessFLXG0V4BRequest
|
||||
|
||||
#### 待修改 ⏳
|
||||
1. ProcessPersonEnterpriseProRequest (第312行)
|
||||
2. ProcessFLXG0687Request (第671行)
|
||||
3. ProcessFLXG3D56Request (第699行)
|
||||
4. ProcessIVYZ5733Request (第754行)
|
||||
5. ProcessIVYZ9A2BRequest (第810行)
|
||||
6. ProcessJRZQ0A03Request (第922行)
|
||||
7. ProcessJRZQ8203Request (第979行)
|
||||
8. ProcessJRZQ4AA8Request (第1036行)
|
||||
9. ProcessQYGL8271Request (第1085行)
|
||||
10. ProcessQYGL6F2DRequest (第1150行)
|
||||
11. ProcessQCXG7A2BRequest (第1191行)
|
||||
12. ProcessYYSY09CDRequest (第1211行)
|
||||
13. ProcessBehaviorRiskScanRequest (第1247行)
|
||||
14. ProcessDWBG8B4DRequest (第1314行)
|
||||
15. ProcessDWBG6A2CRequest (第1339行)
|
||||
16. ProcessJRZQ4B6CRequest (第1363行)
|
||||
17. ProcessJRZQ09J8Request (第1387行)
|
||||
18. ProcessJRZQ5E9FRequest (第1411行)
|
||||
19. ProcessQYGL3F8ERequest (第1433行)
|
||||
20. ProcessIVYZ81NCRequest (第1461行)
|
||||
21. ProcessIVYZ7F3ARequest (第1482行)
|
||||
22. ProcessDWBG7F3ARequest (第1505行)
|
||||
23. ProcessJRZQ8A2DRequest (第1528行)
|
||||
24. ProcessYYSY8B1CRequest (第1550行)
|
||||
25. ProcessYYSY7D3ERequest (第1569行)
|
||||
26. ProcessFLXG7E8FRequest (第1590行)
|
||||
27. ProcessIVYZ8I9JRequest (第1613行)
|
||||
28. ProcessJRZQ7F1ARequest (第1636行)
|
||||
29. ProcessIVYZ3P9MRequest (第1659行)
|
||||
30. ProcessJRZQ6F2ARequest (第1680行)
|
||||
|
||||
每个方法需要做的修改:
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
func (a *ApiRequestService) ProcessMethodName(params []byte) ([]byte, error) {
|
||||
// 方法体
|
||||
}
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
func (a *ApiRequestService) ProcessMethodName(ctx context.Context, params []byte) ([]byte, error) {
|
||||
// 方法体
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **不需要在每个方法中添加 `ctx := context.Background()`**
|
||||
- 因为现在通过参数传入
|
||||
- 使用 `ctx context.Context` 参数即可
|
||||
|
||||
2. **`callTianyuanApiWithLog` 方法已经支持传入 ctx**
|
||||
- 如果第一个参数为空字符串 `""`,会自动从缓存获取featureID
|
||||
- 否则使用传入的featureID
|
||||
|
||||
3. **不需要修改方法内部的 API 调用**
|
||||
- 因为我们已经修改了部分方法使用 `callTianyuanApiWithLog`
|
||||
- 批量替换后,记得将所有 `a.tianyuanapi.CallInterface` 替换为 `a.callTianyuanApiWithLog(ctx, "",`
|
||||
|
||||
## 完成后验证
|
||||
|
||||
1. **编译项目**
|
||||
```bash
|
||||
cd ycc-proxy-server
|
||||
go build ./...
|
||||
```
|
||||
|
||||
2. **检查编译错误**
|
||||
- 主要是方法签名不匹配的错误
|
||||
- 如果有错误,检查哪些方法没有正确修改
|
||||
|
||||
3. **运行测试**
|
||||
- 发起几个API请求
|
||||
- 检查 `tianyuanapi_call_log` 表
|
||||
- 验证日志是否正确记录
|
||||
|
||||
## 优势总结
|
||||
|
||||
使用 `ctx` 参数的方式:
|
||||
|
||||
✅ **代码更简洁** - 不需要重复创建context
|
||||
✅ **更好的控制** - 可以统一管理超时、取消
|
||||
✅ **符合最佳实践** - Context应该从上层传入
|
||||
✅ **便于追踪** - 可以在ctx中传递追踪信息
|
||||
✅ **便于测试** - 测试时可以传入自定义的ctx
|
||||
|
||||
135
deploy/sql/利润统计API成本计入说明.md
Normal file
135
deploy/sql/利润统计API成本计入说明.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# 利润统计API成本计入说明
|
||||
|
||||
## 修改内容
|
||||
|
||||
在后台统计面板的利润统计部分,将API调用成本计入成本计算中。
|
||||
|
||||
## 修改位置
|
||||
|
||||
文件:`ycc-proxy-server/app/main/api/internal/logic/admin_dashboard/admingetdashboardstatisticslogic.go`
|
||||
|
||||
方法:`calculateProfitStatistics`
|
||||
|
||||
## 修改详情
|
||||
|
||||
### 1. 今日利润计算
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
// 今日利润 = 营收 - 佣金 - 返利 - 税务成本 + 提现收税
|
||||
stats.TodayProfit = todayRevenue - todayCommission - todayRebate - todayCompanyTax + todayTaxIncome
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
// 今日API调用成本
|
||||
todayApiCost := 0.0
|
||||
if l.svcCtx.TianyuanapiCallLogService != nil {
|
||||
todayApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{
|
||||
StartDate: todayStart,
|
||||
EndDate: todayEnd,
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("获取今日API调用成本失败: %v", err)
|
||||
} else {
|
||||
todayApiCost = todayApiStats.TotalCost
|
||||
}
|
||||
}
|
||||
// 今日利润 = 营收 - 佣金 - 返利 - 税务成本 - API调用成本 + 提现收税
|
||||
stats.TodayProfit = todayRevenue - todayCommission - todayRebate - todayCompanyTax - todayApiCost + todayTaxIncome
|
||||
```
|
||||
|
||||
### 2. 当月利润计算
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
// 当月利润
|
||||
stats.MonthProfit = monthRevenue - monthCommission - monthRebate - monthCompanyTax + monthTaxIncome
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
// 当月API调用成本
|
||||
monthApiCost := 0.0
|
||||
if l.svcCtx.TianyuanapiCallLogService != nil {
|
||||
monthApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{
|
||||
StartDate: monthStart,
|
||||
EndDate: monthEnd,
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("获取当月API调用成本失败: %v", err)
|
||||
} else {
|
||||
monthApiCost = monthApiStats.TotalCost
|
||||
}
|
||||
}
|
||||
// 当月利润
|
||||
stats.MonthProfit = monthRevenue - monthCommission - monthRebate - monthCompanyTax - monthApiCost + monthTaxIncome
|
||||
```
|
||||
|
||||
### 3. 总利润计算
|
||||
|
||||
**修改前:**
|
||||
```go
|
||||
// 总利润
|
||||
stats.TotalProfit = totalRevenue - totalCommission - totalRebate - totalCompanyTax + totalTaxIncome
|
||||
```
|
||||
|
||||
**修改后:**
|
||||
```go
|
||||
// 总API调用成本
|
||||
totalApiCost := 0.0
|
||||
if l.svcCtx.TianyuanapiCallLogService != nil {
|
||||
totalApiStats, err := l.svcCtx.TianyuanapiCallLogService.GetStatistics(l.ctx, service.StatisticsFilter{})
|
||||
if err != nil {
|
||||
logx.Errorf("获取总API调用成本失败: %v", err)
|
||||
} else {
|
||||
totalApiCost = totalApiStats.TotalCost
|
||||
}
|
||||
}
|
||||
// 总利润
|
||||
stats.TotalProfit = totalRevenue - totalCommission - totalRebate - totalCompanyTax - totalApiCost + totalTaxIncome
|
||||
```
|
||||
|
||||
## 利润计算公式
|
||||
|
||||
修改后的利润计算公式为:
|
||||
|
||||
```
|
||||
利润 = 营收 - 佣金 - 返利 - 税务成本 - API调用成本 + 提现收税
|
||||
```
|
||||
|
||||
其中:
|
||||
- **营收**:订单金额总和(status = 'paid')
|
||||
- **佣金**:代理佣金总和(status != 3)
|
||||
- **返利**:代理返利总和(status != 3)
|
||||
- **税务成本**:订单金额的 6%
|
||||
- **API调用成本**:天元API成功调用的成本总和(从 `tianyuanapi_call_log` 表统计)
|
||||
- **提现收税**:代理提现税总和(tax_status = 2)
|
||||
|
||||
## API调用成本统计说明
|
||||
|
||||
API调用成本通过 `TianyuanapiCallLogService.GetStatistics` 方法获取:
|
||||
|
||||
1. **今日API调用成本**:统计 `call_time >= todayStart AND call_time < todayEnd` 的成功调用成本
|
||||
2. **当月API调用成本**:统计 `call_time >= monthStart AND call_time < monthEnd` 的成功调用成本
|
||||
3. **总API调用成本**:统计所有成功调用的成本
|
||||
|
||||
**注意**:只有成功调用(`call_status = 1`)才会计入成本,失败调用不计成本。
|
||||
|
||||
## 错误处理
|
||||
|
||||
如果获取API调用成本失败,会记录错误日志,但不会影响利润计算(API成本默认为0),确保统计功能的稳定性。
|
||||
|
||||
## 依赖项
|
||||
|
||||
- `TianyuanapiCallLogService`:需要在 `servicecontext.go` 中初始化
|
||||
- `tianyuanapi_call_log` 表:需要已创建并包含调用记录数据
|
||||
|
||||
## 验证
|
||||
|
||||
修改完成后,可以通过以下方式验证:
|
||||
|
||||
1. 查看后台统计面板的利润统计数据
|
||||
2. 检查日志,确认API调用成本是否正确获取
|
||||
3. 对比修改前后的利润数据,确认API成本已正确计入
|
||||
|
||||
149
deploy/sql/利润统计面板改造说明.md
Normal file
149
deploy/sql/利润统计面板改造说明.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# 利润统计面板改造说明
|
||||
|
||||
## 改造内容
|
||||
|
||||
将利润统计从原来的卡片布局改为右侧栏面板,并展示详细的成本和收入明细。
|
||||
|
||||
## 修改文件
|
||||
|
||||
### 1. 后端API定义
|
||||
|
||||
**文件:** `ycc-proxy-server/app/main/api/desc/admin/dashboard.api`
|
||||
|
||||
**修改内容:**
|
||||
- 在 `AdminProfitStatistics` 中添加了三个明细字段:
|
||||
- `TodayDetail AdminProfitDetail` - 今日明细
|
||||
- `MonthDetail AdminProfitDetail` - 当月明细
|
||||
- `TotalDetail AdminProfitDetail` - 总计明细
|
||||
- 新增 `AdminProfitDetail` 类型,包含:
|
||||
- `Revenue` - 营收
|
||||
- `Commission` - 佣金
|
||||
- `Rebate` - 返利
|
||||
- `CompanyTax` - 税务成本
|
||||
- `ApiCost` - API调用成本
|
||||
- `TaxIncome` - 提现收税
|
||||
- `Profit` - 利润
|
||||
- `ProfitRate` - 利润率
|
||||
|
||||
### 2. 后端逻辑
|
||||
|
||||
**文件:** `ycc-proxy-server/app/main/api/internal/logic/admin_dashboard/admingetdashboardstatisticslogic.go`
|
||||
|
||||
**修改内容:**
|
||||
- 在 `calculateProfitStatistics` 方法中,为今日、当月、总计三个时间范围都填充了明细数据
|
||||
- 明细数据包含所有成本和收入的详细金额
|
||||
|
||||
### 3. 前端类型定义
|
||||
|
||||
**文件:** `ycc-proxy-admin/apps/web-antd/src/api/dashboard/dashboard.ts`
|
||||
|
||||
**修改内容:**
|
||||
- 添加了 `ProfitDetail` 接口
|
||||
- 更新了 `ProfitStatistics` 接口,添加三个明细字段
|
||||
|
||||
### 4. 前端主页面
|
||||
|
||||
**文件:** `ycc-proxy-admin/apps/web-antd/src/views/dashboard/analytics/index.vue`
|
||||
|
||||
**修改内容:**
|
||||
- 移除了利润统计卡片(从4列布局改为3列布局)
|
||||
- 改为左右布局:左侧是统计卡片和图表,右侧是利润统计面板
|
||||
- 添加了响应式布局,小屏幕下右侧面板会移到下方
|
||||
|
||||
### 5. 前端利润面板组件(新建)
|
||||
|
||||
**文件:** `ycc-proxy-admin/apps/web-antd/src/views/dashboard/analytics/analytics-profit-panel.vue`
|
||||
|
||||
**功能:**
|
||||
- 展示利润总额和利润率
|
||||
- 通过Tab切换今日/当月/总计
|
||||
- 详细展示收入明细(营收、提现收税)
|
||||
- 详细展示成本明细(代理佣金、代理返利、税务成本、API调用成本)
|
||||
- 分别计算收入合计和成本合计
|
||||
|
||||
## 布局说明
|
||||
|
||||
### 桌面端(>1200px)
|
||||
```
|
||||
┌─────────────────────────────────┬──────────────┐
|
||||
│ │ │
|
||||
│ 统计卡片(3列) │ 利润统计 │
|
||||
│ │ 面板 │
|
||||
│ 趋势图表 │ (固定) │
|
||||
│ │ │
|
||||
└─────────────────────────────────┴──────────────┘
|
||||
```
|
||||
|
||||
### 移动端(≤1200px)
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ 统计卡片(3列) │
|
||||
│ │
|
||||
│ 趋势图表 │
|
||||
│ │
|
||||
│ 利润统计面板 │
|
||||
│ (移到下方) │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 明细数据说明
|
||||
|
||||
### 收入项
|
||||
1. **营收**:订单金额总和(status = 'paid')
|
||||
2. **提现收税**:代理提现税总和(tax_status = 2)
|
||||
|
||||
### 成本项
|
||||
1. **代理佣金**:代理佣金总和(status != 3)
|
||||
2. **代理返利**:代理返利总和(status != 3)
|
||||
3. **税务成本**:订单金额的 6%
|
||||
4. **API调用成本**:天元API成功调用的成本总和
|
||||
|
||||
### 利润计算
|
||||
```
|
||||
利润 = 营收 + 提现收税 - 代理佣金 - 代理返利 - 税务成本 - API调用成本
|
||||
利润率 = (利润 / 营收) × 100%
|
||||
```
|
||||
|
||||
## 使用步骤
|
||||
|
||||
### 1. 生成API类型(后端)
|
||||
|
||||
运行API生成脚本:
|
||||
```bash
|
||||
cd ycc-proxy-server
|
||||
# 运行gen_api脚本生成types
|
||||
```
|
||||
|
||||
### 2. 编译验证
|
||||
|
||||
```bash
|
||||
# 后端编译
|
||||
cd ycc-proxy-server
|
||||
go build
|
||||
|
||||
# 前端编译
|
||||
cd ycc-proxy-admin
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 3. 测试验证
|
||||
|
||||
1. 打开后台统计面板
|
||||
2. 查看右侧利润统计面板
|
||||
3. 切换今日/当月/总计Tab
|
||||
4. 验证各项成本和收入明细是否正确显示
|
||||
5. 验证收入合计和成本合计计算是否正确
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **必须运行gen_api脚本**:修改了API定义后,需要运行gen_api脚本生成新的types.go文件
|
||||
2. **数据准确性**:确保API调用成本数据已正确记录在 `tianyuanapi_call_log` 表中
|
||||
3. **响应式布局**:在小屏幕设备上,右侧面板会自动移到下方,确保良好的用户体验
|
||||
|
||||
## UI特性
|
||||
|
||||
- **固定定位**:右侧面板在桌面端使用sticky定位,滚动时保持可见
|
||||
- **颜色区分**:收入用绿色(+),成本用红色(-),利润根据正负显示不同颜色
|
||||
- **Tab切换**:可以快速切换查看不同时间范围的明细
|
||||
- **合计显示**:分别显示收入合计和成本合计,方便查看
|
||||
|
||||
159
deploy/sql/天元API调用记录修改说明.md
Normal file
159
deploy/sql/天元API调用记录修改说明.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# 天元API调用记录功能 - 代码修改说明
|
||||
|
||||
## 概述
|
||||
本文档说明如何修改 `apirequestService.go`,为每次天元API调用添加记录功能。
|
||||
|
||||
## 已完成的修改
|
||||
|
||||
### 1. 数据库层面
|
||||
- ✅ 创建 `tianyuanapi_cost_migration.sql` 脚本
|
||||
- 在 `feature` 表添加 `cost_price` 字段
|
||||
- 创建 `tianyuanapi_call_log` 表
|
||||
|
||||
### 2. Service层面
|
||||
- ✅ 创建 `tianyuanapiCallLogService.go` 服务
|
||||
- `RecordCall()` - 记录API调用
|
||||
- `GetStatistics()` - 获取统计信息
|
||||
|
||||
### 3. Model层面
|
||||
- ⏳ 需要执行 `generate_tianyuanapi_models.sh` 生成Model代码
|
||||
|
||||
### 4. ApiRequestService修改
|
||||
- ✅ 添加 `tianyuanapiCallLogService` 字段
|
||||
- ✅ 修改构造函数,添加 `tianyuanapiCallLogService` 参数
|
||||
- ✅ 创建 `callTianyuanApiWithLog()` 辅助方法
|
||||
|
||||
## 待完成的修改
|
||||
|
||||
### 1. 执行SQL脚本
|
||||
```bash
|
||||
# 在数据库中执行迁移脚本
|
||||
mysql -u root -p ycc < ycc-proxy-server/deploy/sql/tianyuanapi_cost_migration.sql
|
||||
```
|
||||
|
||||
### 2. 生成Model代码
|
||||
```bash
|
||||
cd ycc-proxy-server/deploy/sql
|
||||
bash generate_tianyuanapi_models.sh
|
||||
```
|
||||
|
||||
### 3. 更新 servicecontext.go
|
||||
在 `svc/servicecontext.go` 中添加:
|
||||
```go
|
||||
// 初始化Model
|
||||
tianyuanapiCallLogModel := model.NewTianyuanapiCallLogModel(db, cacheConf)
|
||||
|
||||
// 初始化Service
|
||||
tianyuanapiCallLogService := service.NewTianyuanapiCallLogService(
|
||||
tianyuanapiCallLogModel,
|
||||
featureModel,
|
||||
)
|
||||
|
||||
// 修改ApiRequestService初始化
|
||||
apiRequestService := service.NewApiRequestService(
|
||||
c,
|
||||
featureModel,
|
||||
productFeatureModel,
|
||||
userFeatureWhitelistModel,
|
||||
tianyuanapi,
|
||||
tianyuanapiCallLogService, // 新增参数
|
||||
)
|
||||
|
||||
// 在ServiceContext结构体中添加字段
|
||||
TianyuanapiCallLogModel model.TianyuanapiCallLogModel
|
||||
TianyuanapiCallLogService *service.TianyuanapiCallLogService
|
||||
|
||||
// 在返回的ServiceContext中添加
|
||||
TianyuanapiCallLogModel: tianyuanapiCallLogModel,
|
||||
TianyuanapiCallLogService: tianyuanapiCallLogService,
|
||||
```
|
||||
|
||||
### 4. 修改API调用方法示例
|
||||
|
||||
#### 原代码:
|
||||
```go
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "QYGLB4C0", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
```
|
||||
|
||||
#### 修改后:
|
||||
```go
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, featureID, "QYGLB4C0", map[string]interface{}{
|
||||
"id_card": idCard.String(),
|
||||
})
|
||||
```
|
||||
|
||||
### 需要修改的方法列表(共32个)
|
||||
|
||||
1. `ProcessPersonEnterpriseProRequest` - 需要修改2处
|
||||
- 第253行:`QYGLB4C0` - 主接口
|
||||
- 第455行:`QYGL8271` - 涉诉信息查询
|
||||
|
||||
2. `ProcessFLXG0V4BRequest` - 第586行:`FLXG0V4B`
|
||||
3. `ProcessFLXG0687Request` - 第608行:`FLXG0687`
|
||||
4. `ProcessFLXG3D56Request` - 第638行:`FLXG3D56`
|
||||
5. `ProcessIVYZ5733Request` - 第692行:`IVYZ5733`
|
||||
6. `ProcessIVYZ9A2BRequest` - 第748行:`IVYZ9A2B`
|
||||
7. `ProcessYYSYBE08Request` - 第819行:`YYSYBE08`
|
||||
8. `ProcessJRZQ0A03Request` - 第861行:`JRZQ0A03`
|
||||
9. `ProcessJRZQ8203Request` - 第918行:`JRZQ8203`
|
||||
10. `ProcessJRZQ4AA8Request` - 第975行:`JRZQ4AA8`
|
||||
11. `ProcessQYGL8271Request` - 第1024行:`QYGL8271`
|
||||
12. `ProcessQYGL6F2DRequest` - 第1082行:`QYGL6F2D`
|
||||
13. `ProcessQCXG7A2BRequest` - 第1123行:`QCXG7A2B`
|
||||
14. `ProcessYYSY09CDRequest` - 第1143行:`YYSY09CD`
|
||||
15. `ProcessDWBG8B4DRequest` - 第1254行:`DWBG8B4D`
|
||||
16. `ProcessDWBG6A2CRequest` - 第1279行:`DWBG6A2C`
|
||||
17. `ProcessJRZQ4B6CRequest` - 第1303行:`JRZQ4B6C`
|
||||
18. `ProcessJRZQ09J8Request` - 第1327行:`JRZQ09J8`
|
||||
19. `ProcessJRZQ5E9FRequest` - 第1351行:`JRZQ5E9F`
|
||||
20. `ProcessQYGL3F8ERequest` - 第1373行:`QYGL3F8E`
|
||||
21. `ProcessIVYZ81NCRequest` - 第1393行:`IVYZ81NC`
|
||||
22. `ProcessIVYZ7F3ARequest` - 第1414行:`IVYZ7F3A`
|
||||
23. `ProcessDWBG7F3ARequest` - 第1437行:`DWBG7F3A`
|
||||
24. `ProcessJRZQ8A2DRequest` - 第1460行:`JRZQ8A2D`
|
||||
25. `ProcessYYSY8B1CRequest` - 第1482行:`YYSY8B1C`
|
||||
26. `ProcessYYSY7D3ERequest` - 第1501行:`YYSY7D3E`
|
||||
27. `ProcessFLXG7E8FRequest` - 第1522行:`FLXG7E8F`
|
||||
28. `ProcessIVYZ8I9JRequest` - 第1545行:`IVYZ8I9J`
|
||||
29. `ProcessJRZQ7F1ARequest` - 第1568行:`JRZQ7F1A`
|
||||
30. `ProcessIVYZ3P9MRequest` - 第1591行:`IVYZ3P9M`
|
||||
31. `ProcessJRZQ6F2ARequest` - 第1612行:`JRZQ6F2A`
|
||||
|
||||
### 注意事项
|
||||
|
||||
1. **featureID获取**:每个方法中已经有了 `feature` 对象,直接使用 `feature.Id` 即可
|
||||
2. **context传递**:需要从方法签名中获取 `ctx context.Context` 参数
|
||||
3. **错误处理**:`callTianyuanApiWithLog` 已经包含了错误处理,无需额外处理
|
||||
4. **批量修改建议**:可以使用查找替换功能批量修改
|
||||
- 查找:`a.callTianyuanApiWithLog(ctx, "", "`
|
||||
- 替换为:`a.callTianyuanApiWithLog(ctx, feature.Id, "`
|
||||
|
||||
## 统计功能使用示例
|
||||
|
||||
```go
|
||||
// 获取某个功能在某个时间段的调用统计
|
||||
filter := StatisticsFilter{
|
||||
FeatureID: "feature-id-123",
|
||||
StartDate: time.Now().AddDate(0, 0, -30), // 30天前
|
||||
EndDate: time.Now(),
|
||||
}
|
||||
stats, err := ctx.TianyuanapiCallLogService.GetStatistics(context.Background(), filter)
|
||||
if err == nil {
|
||||
fmt.Printf("总调用次数: %d\n", stats.TotalCalls)
|
||||
fmt.Printf("成功次数: %d\n", stats.SuccessCalls)
|
||||
fmt.Printf("失败次数: %d\n", stats.FailedCalls)
|
||||
fmt.Printf("总成本: %.2f元\n", stats.TotalCost)
|
||||
}
|
||||
```
|
||||
|
||||
## 验证步骤
|
||||
|
||||
1. 执行SQL脚本,检查表是否创建成功
|
||||
2. 运行Model生成脚本,检查Model文件是否生成
|
||||
3. 编译项目,检查是否有编译错误
|
||||
4. 运行项目,发起一个API请求
|
||||
5. 检查 `tianyuanapi_call_log` 表,验证记录是否正确插入
|
||||
6. 检查成本价是否正确计算(成功调用有成本,失败调用成本为0)
|
||||
|
||||
297
deploy/sql/天元API调用记录功能完成总结.md
Normal file
297
deploy/sql/天元API调用记录功能完成总结.md
Normal file
@@ -0,0 +1,297 @@
|
||||
# 天元API调用记录功能 - 实施总结
|
||||
|
||||
## 功能概述
|
||||
|
||||
本功能实现了天元API调用的成本记录,包括:
|
||||
1. 在 `feature` 表添加 `cost_price` 字段,存储每个接口的成本价
|
||||
2. 创建 `tianyuanapi_call_log` 表,记录每次API调用的详细信息
|
||||
3. 无论成功失败都记录,但只有成功调用才计算成本
|
||||
4. 提供统计功能,可查询时间段内的调用次数和总成本
|
||||
|
||||
## 已完成的工作
|
||||
|
||||
### 1. 数据库层面 ✅
|
||||
|
||||
**文件:** `ycc-proxy-server/deploy/sql/tianyuanapi_cost_migration.sql`
|
||||
|
||||
**修改内容:**
|
||||
- 在 `feature` 表添加 `cost_price` 字段(decimal(10, 2),默认0.00)
|
||||
- 创建 `tianyuanapi_call_log` 表,包含以下字段:
|
||||
- `feature_id`: 关联feature表
|
||||
- `api_id`: 天元API标识(如:YYSYBE08)
|
||||
- `order_id`: 关联订单(可选)
|
||||
- `query_id`: 关联查询(可选)
|
||||
- `call_status`: 调用状态(0=失败,1=成功)
|
||||
- `call_time`: 调用时间
|
||||
- `response_time`: 响应耗时(毫秒)
|
||||
- `cost_price`: 本次调用成本(成功时有值,失败为0)
|
||||
- `error_code`: 错误码(失败时)
|
||||
- `error_message`: 错误信息(失败时)
|
||||
- `request_params`: 请求参数(JSON)
|
||||
- `response_data`: 响应数据(JSON,截取前1000字符)
|
||||
- `transaction_id`: 天元API流水号
|
||||
|
||||
**索引设计:**
|
||||
- `idx_feature_id`: 按feature_id查询
|
||||
- `idx_api_id`: 按api_id查询
|
||||
- `idx_order_id`: 按order_id查询
|
||||
- `idx_query_id`: 按query_id查询
|
||||
- `idx_call_status`: 按调用状态查询
|
||||
- `idx_call_time`: 按调用时间查询
|
||||
- `idx_feature_time`: 复合索引(feature_id + call_time)
|
||||
|
||||
### 2. Service层面 ✅
|
||||
|
||||
**文件:** `ycc-proxy-server/app/main/api/internal/service/tianyuanapiCallLogService.go`
|
||||
|
||||
**新增方法:**
|
||||
1. `RecordCall(ctx context.Context, opts CallLogOptions) error`
|
||||
- 记录API调用
|
||||
- 自动获取feature的成本价
|
||||
- 成功时记录成本,失败时成本为0
|
||||
- 异步记录,不影响主流程
|
||||
|
||||
2. `GetStatistics(ctx context.Context, filter StatisticsFilter) (*Statistics, error)`
|
||||
- 获取统计信息
|
||||
- 支持按feature_id、api_id、时间范围过滤
|
||||
- 返回:总调用次数、成功次数、失败次数、总成本
|
||||
|
||||
### 3. ApiRequestService修改 ✅
|
||||
|
||||
**文件:** `ycc-proxy-server/app/main/api/internal/service/apirequestService.go`
|
||||
|
||||
**新增字段:**
|
||||
- `tianyuanapiCallLogService *TianyuanapiCallLogService`
|
||||
- `apiFeatureMapCache map[string]string` - apiID到featureID的缓存
|
||||
- `apiFeatureMapMutex sync.RWMutex` - 缓存读写锁
|
||||
|
||||
**新增方法:**
|
||||
1. `callTianyuanApiWithLog(ctx context.Context, featureID, apiID string, params map[string]interface{}) (*tianyuanapi.Response, error)`
|
||||
- 调用天元API
|
||||
- 记录调用开始时间
|
||||
- 计算响应耗时
|
||||
- 异步记录调用日志
|
||||
- 返回响应和错误
|
||||
|
||||
2. 在 `ProcessRequests` 方法中构建 `apiID -> featureID` 映射缓存
|
||||
|
||||
**修改的方法(示例):**
|
||||
- `ProcessYYSYBE08Request` - 已修改
|
||||
- `ProcessFLXG0V4BRequest` - 已修改
|
||||
|
||||
**待修改的方法(30个):**
|
||||
剩余30个方法需要将 `a.callTianyuanApiWithLog(ctx, "", "API名称", ...)`
|
||||
替换为 `a.callTianyuanApiWithLog(ctx, "", "API名称", ...)`
|
||||
|
||||
详细列表见:`批量替换API调用说明.md`
|
||||
|
||||
### 4. ServiceContext修改 ✅
|
||||
|
||||
**文件:** `ycc-proxy-server/app/main/api/internal/svc/servicecontext.go`
|
||||
|
||||
**新增模型:**
|
||||
```go
|
||||
TianyuanapiCallLogModel model.TianyuanapiCallLogModel
|
||||
TianyuanapiCallLogService *service.TianyuanapiCallLogService
|
||||
```
|
||||
|
||||
**新增初始化:**
|
||||
```go
|
||||
tianyuanapiCallLogModel := model.NewTianyuanapiCallLogModel(db, cacheConf)
|
||||
tianyuanapiCallLogService := service.NewTianyuanapiCallLogService(tianyuanapiCallLogModel, featureModel)
|
||||
```
|
||||
|
||||
**修改ApiRequestService初始化:**
|
||||
```go
|
||||
apiRequestService := service.NewApiRequestService(
|
||||
c,
|
||||
featureModel,
|
||||
productFeatureModel,
|
||||
userFeatureWhitelistModel,
|
||||
tianyuanapi,
|
||||
tianyuanapiCallLogService, // 新增参数
|
||||
)
|
||||
```
|
||||
|
||||
### 5. Model生成脚本 ✅
|
||||
|
||||
**文件:** `ycc-proxy-server/deploy/sql/generate_tianyuanapi_models.sh`
|
||||
|
||||
**功能:**
|
||||
- 生成 `feature` 表的Model(已更新,包含cost_price字段)
|
||||
- 生成 `tianyuanapi_call_log` 表的Model
|
||||
|
||||
### 6. 文档 ✅
|
||||
|
||||
**已创建的文档:**
|
||||
1. `天元API调用记录修改说明.md` - 详细的修改步骤和示例
|
||||
2. `批量替换API调用说明.md` - 批量修改API调用方法的指南
|
||||
|
||||
## 待完成的工作
|
||||
|
||||
### 1. 执行SQL脚本 ⏳
|
||||
|
||||
```bash
|
||||
# 在数据库中执行迁移脚本
|
||||
mysql -u root -p ycc < ycc-proxy-server/deploy/sql/tianyuanapi_cost_migration.sql
|
||||
```
|
||||
|
||||
### 2. 生成Model代码 ⏳
|
||||
|
||||
```bash
|
||||
cd ycc-proxy-server/deploy/sql
|
||||
bash generate_tianyuanapi_models.sh
|
||||
```
|
||||
|
||||
这将生成以下文件:
|
||||
- `app/main/model/featureModel_gen.go` (已更新,包含cost_price字段)
|
||||
- `app/main/model/featureModel.go` (已更新)
|
||||
- `app/main/model/tianyuanapiCallLogModel_gen.go` (新建)
|
||||
- `app/main/model/tianyuanapiCallLogModel.go` (新建)
|
||||
|
||||
### 3. 批量修改API调用方法 ⏳
|
||||
|
||||
**需要修改30个方法,将:**
|
||||
```go
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "API名称", map[string]interface{}{
|
||||
```
|
||||
|
||||
**替换为:**
|
||||
```go
|
||||
ctx := context.Background()
|
||||
resp, err := a.callTianyuanApiWithLog(ctx, "", "API名称", map[string]interface{}{
|
||||
```
|
||||
|
||||
**参考文档:** `批量替换API调用说明.md`
|
||||
|
||||
**建议使用IDE批量替换功能:**
|
||||
1. 打开 `apirequestService.go`
|
||||
2. 按 `Ctrl+H` 打开查找替换
|
||||
3. 查找:`a.callTianyuanApiWithLog(ctx, "", "`
|
||||
4. 替换:`a.callTianyuanApiWithLog(ctx, "", "`
|
||||
5. 全部替换
|
||||
|
||||
**然后手动在每个方法开头添加:**
|
||||
```go
|
||||
ctx := context.Background()
|
||||
```
|
||||
|
||||
### 4. 编译验证 ⏳
|
||||
|
||||
```bash
|
||||
cd ycc-proxy-server
|
||||
go build ./...
|
||||
```
|
||||
|
||||
检查是否有编译错误。
|
||||
|
||||
### 5. 测试验证 ⏳
|
||||
|
||||
1. 运行项目
|
||||
2. 发起几个API请求(成功和失败各几次)
|
||||
3. 检查 `tianyuanapi_call_log` 表,验证:
|
||||
- 记录是否正确插入
|
||||
- 成功调用有正确的成本价
|
||||
- 失败调用成本为0
|
||||
- 响应耗时是否记录
|
||||
- 错误信息是否正确
|
||||
|
||||
### 6. 后台配置 ⏳
|
||||
|
||||
在后台"功能管理"页面,为每个feature配置成本价:
|
||||
1. 进入"功能管理"
|
||||
2. 编辑某个功能
|
||||
3. 设置"天元API调用成本价"字段
|
||||
4. 保存
|
||||
|
||||
## 统计功能使用示例
|
||||
|
||||
```go
|
||||
// 获取某个功能在某个时间段的调用统计
|
||||
filter := StatisticsFilter{
|
||||
FeatureID: "feature-id-123",
|
||||
StartDate: time.Now().AddDate(0, 0, -30), // 30天前
|
||||
EndDate: time.Now(),
|
||||
}
|
||||
stats, err := ctx.TianyuanapiCallLogService.GetStatistics(context.Background(), filter)
|
||||
if err == nil {
|
||||
fmt.Printf("总调用次数: %d\n", stats.TotalCalls)
|
||||
fmt.Printf("成功次数: %d\n", stats.SuccessCalls)
|
||||
fmt.Printf("失败次数: %d\n", stats.FailedCalls)
|
||||
fmt.Printf("总成本: %.2f元\n", stats.TotalCost)
|
||||
}
|
||||
```
|
||||
|
||||
## SQL查询示例
|
||||
|
||||
### 查询某个接口的调用记录
|
||||
```sql
|
||||
SELECT * FROM tianyuanapi_call_log
|
||||
WHERE api_id = 'YYSYBE08'
|
||||
ORDER BY call_time DESC
|
||||
LIMIT 100;
|
||||
```
|
||||
|
||||
### 统计某天所有接口的调用情况
|
||||
```sql
|
||||
SELECT
|
||||
api_id,
|
||||
COUNT(*) as total_calls,
|
||||
SUM(CASE WHEN call_status = 1 THEN 1 ELSE 0 END) as success_calls,
|
||||
SUM(CASE WHEN call_status = 0 THEN 1 ELSE 0 END) as failed_calls,
|
||||
SUM(cost_price) as total_cost
|
||||
FROM tianyuanapi_call_log
|
||||
WHERE DATE(call_time) = CURDATE()
|
||||
GROUP BY api_id;
|
||||
```
|
||||
|
||||
### 查询成功率最低的接口
|
||||
```sql
|
||||
SELECT
|
||||
api_id,
|
||||
COUNT(*) as total_calls,
|
||||
SUM(CASE WHEN call_status = 1 THEN 1 ELSE 0 END) as success_calls,
|
||||
(SUM(CASE WHEN call_status = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*)) as success_rate
|
||||
FROM tianyuanapi_call_log
|
||||
WHERE call_time >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
||||
GROUP BY api_id
|
||||
ORDER BY success_rate ASC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **成本价配置**:需要在后台为每个feature配置成本价,否则所有调用的成本都是0
|
||||
2. **性能考虑**:调用日志采用异步记录,不影响API响应速度
|
||||
3. **数据量控制**:response_data只记录前1000字符,避免存储过大
|
||||
4. **缓存机制**:apiID到featureID的映射在 `ProcessRequests` 时构建,避免频繁查询数据库
|
||||
5. **失败不收费**:根据需求,调用失败时天元API不收费,所以cost_price为0
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **定时清理**:可以添加定时任务,定期清理超过一定时间的日志数据(如90天)
|
||||
2. **成本预警**:可以添加监控,当某个时间段的总成本超过阈值时发送告警
|
||||
3. **成功率监控**:监控各接口的成功率,低于阈值时告警
|
||||
4. **性能分析**:分析响应时间,找出性能瓶颈
|
||||
5. **数据归档**:将历史日志归档到其他存储,避免主表过大
|
||||
|
||||
## 文件清单
|
||||
|
||||
### 新增文件
|
||||
1. `deploy/sql/tianyuanapi_cost_migration.sql` - 数据库迁移脚本
|
||||
2. `deploy/sql/generate_tianyuanapi_models.sh` - Model生成脚本
|
||||
3. `app/main/api/internal/service/tianyuanapiCallLogService.go` - 调用记录服务
|
||||
4. `deploy/sql/天元API调用记录修改说明.md` - 详细修改说明
|
||||
5. `deploy/sql/批量替换API调用说明.md` - 批量替换指南
|
||||
6. `deploy/sql/天元API调用记录功能完成总结.md` - 本文档
|
||||
|
||||
### 修改文件
|
||||
1. `app/main/api/internal/service/apirequestService.go` - 添加调用记录逻辑
|
||||
2. `app/main/api/internal/svc/servicecontext.go` - 添加新Model和Service初始化
|
||||
|
||||
### 待生成文件(执行脚本后)
|
||||
1. `app/main/model/featureModel_gen.go` - 已更新
|
||||
2. `app/main/model/featureModel.go` - 已更新
|
||||
3. `app/main/model/tianyuanapiCallLogModel_gen.go` - 新建
|
||||
4. `app/main/model/tianyuanapiCallLogModel.go` - 新建
|
||||
|
||||
83
deploy/sql/批量修改方法签名.sh
Normal file
83
deploy/sql/批量修改方法签名.sh
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 批量修改API请求方法签名,添加ctx参数
|
||||
|
||||
FILE="app/main/api/internal/service/apirequestService.go"
|
||||
|
||||
# 需要修改的方法列表(不包括ProcessYYSYBE08Request和ProcessFLXG0V4BRequest,因为已经修改过了)
|
||||
METHODS=(
|
||||
"ProcessPersonEnterpriseProRequest"
|
||||
"ProcessFLXG0687Request"
|
||||
"ProcessFLXG3D56Request"
|
||||
"ProcessIVYZ5733Request"
|
||||
"ProcessIVYZ9A2BRequest"
|
||||
"ProcessJRZQ0A03Request"
|
||||
"ProcessJRZQ8203Request"
|
||||
"ProcessJRZQ4AA8Request"
|
||||
"ProcessQYGL8271Request"
|
||||
"ProcessQYGL6F2DRequest"
|
||||
"ProcessQCXG7A2BRequest"
|
||||
"ProcessYYSY09CDRequest"
|
||||
"ProcessBehaviorRiskScanRequest"
|
||||
"ProcessDWBG8B4DRequest"
|
||||
"ProcessDWBG6A2CRequest"
|
||||
"ProcessJRZQ4B6CRequest"
|
||||
"ProcessJRZQ09J8Request"
|
||||
"ProcessJRZQ5E9FRequest"
|
||||
"ProcessQYGL3F8ERequest"
|
||||
"ProcessIVYZ81NCRequest"
|
||||
"ProcessIVYZ7F3ARequest"
|
||||
"ProcessDWBG7F3ARequest"
|
||||
"ProcessJRZQ8A2DRequest"
|
||||
"ProcessYYSY8B1CRequest"
|
||||
"ProcessYYSY7D3ERequest"
|
||||
"ProcessFLXG7E8FRequest"
|
||||
"ProcessIVYZ8I9JRequest"
|
||||
"ProcessJRZQ7F1ARequest"
|
||||
"ProcessIVYZ3P9MRequest"
|
||||
"ProcessJRZQ6F2ARequest"
|
||||
)
|
||||
|
||||
echo "开始批量修改方法签名..."
|
||||
echo ""
|
||||
|
||||
# 备份文件
|
||||
if [ ! -f "$FILE.backup" ]; then
|
||||
cp "$FILE" "$FILE.backup"
|
||||
echo "✓ 已备份文件到: $FILE.backup"
|
||||
echo ""
|
||||
else
|
||||
echo "⚠ 备份文件已存在,跳过备份"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# 逐个修改方法
|
||||
count=0
|
||||
for method in "${METHODS[@]}"; do
|
||||
# 查找方法定义
|
||||
old_pattern="func (a \*ApiRequestService) $method(params \[\]byte\) \(\[\]byte, error\)"
|
||||
new_pattern="func (a *ApiRequestService) $method(ctx context.Context, params \[\]byte\) \(\[\]byte, error\)"
|
||||
|
||||
# 检查文件中是否包含这个方法签名
|
||||
if grep -q "$method" "$FILE"; then
|
||||
# 使用sed替换
|
||||
sed -i "s/$old_pattern/$new_pattern/g" "$FILE"
|
||||
echo "✓ 已修改: $method"
|
||||
((count++))
|
||||
else
|
||||
echo "✗ 未找到: $method"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo "修改完成!"
|
||||
echo "========================================="
|
||||
echo "共修改了 $count 个方法"
|
||||
echo ""
|
||||
echo "下一步:"
|
||||
echo "1. 检查修改后的文件"
|
||||
echo "2. 编译项目验证是否有错误"
|
||||
echo "3. 运行测试"
|
||||
echo "========================================="
|
||||
|
||||
86
deploy/sql/批量替换API调用方法.ps1
Normal file
86
deploy/sql/批量替换API调用方法.ps1
Normal file
@@ -0,0 +1,86 @@
|
||||
# 批量替换API调用方法的PowerShell脚本
|
||||
|
||||
# 说明:此脚本用于批量修改apirequestService.go中的API调用方法
|
||||
# 使用前请先备份文件!
|
||||
|
||||
$filePath = "app\main\api\internal\service\apirequestService.go"
|
||||
|
||||
# 检查文件是否存在
|
||||
if (-not (Test-Path $filePath)) {
|
||||
Write-Host "错误:文件不存在 - $filePath" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 备份文件
|
||||
$backupPath = "$filePath.backup"
|
||||
Copy-Item $filePath $backupPath
|
||||
Write-Host "已备份文件到: $backupPath" -ForegroundColor Green
|
||||
|
||||
# 读取文件内容
|
||||
$content = Get-Content $filePath -Raw
|
||||
|
||||
# 需要修改的方法列表(已完成的除外)
|
||||
$methodsToSkip = @(
|
||||
"ProcessYYSYBE08Request",
|
||||
"ProcessFLXG0V4BRequest"
|
||||
)
|
||||
|
||||
# 需要添加ctx声明的模式
|
||||
$pattern1 = '(?m)(func \(a \*ApiRequestService\) Process(\w+)Request\(params \[\]byte\) \(\[\]byte, error\) \{)'
|
||||
|
||||
# 替换API调用
|
||||
$pattern2 = 'a\.tianyuanapi\.CallInterface\("'
|
||||
$replacement2 = 'a.callTianyuanApiWithLog(ctx, "", "'
|
||||
|
||||
# 执行替换
|
||||
$count = 0
|
||||
$content -replace $pattern2, $replacement2 | Out-File $filePath -Encoding UTF8
|
||||
|
||||
# 统计替换次数
|
||||
$matches = [regex]::Matches($content, $pattern2)
|
||||
$count = $matches.Count
|
||||
|
||||
Write-Host "已替换 $count 处 a.tianyuanapi.CallInterface 调用" -ForegroundColor Green
|
||||
|
||||
Write-Host "`n现在需要手动为每个方法添加 ctx 声明:" -ForegroundColor Yellow
|
||||
Write-Host "在每个方法的 func 声明后,第一行添加:" -ForegroundColor Yellow
|
||||
Write-Host 'ctx := context.Background()' -ForegroundColor Cyan
|
||||
|
||||
Write-Host "`n需要修改的方法列表(已完成的除外):" -ForegroundColor Yellow
|
||||
Write-Host "ProcessPersonEnterpriseProRequest - 主接口和涉诉查询" -ForegroundColor White
|
||||
Write-Host "ProcessFLXG0687Request" -ForegroundColor White
|
||||
Write-Host "ProcessFLXG3D56Request" -ForegroundColor White
|
||||
Write-Host "ProcessIVYZ5733Request" -ForegroundColor White
|
||||
Write-Host "ProcessIVYZ9A2BRequest" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ0A03Request" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ8203Request" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ4AA8Request" -ForegroundColor White
|
||||
Write-Host "ProcessQYGL8271Request" -ForegroundColor White
|
||||
Write-Host "ProcessQYGL6F2DRequest" -ForegroundColor White
|
||||
Write-Host "ProcessQCXG7A2BRequest" -ForegroundColor White
|
||||
Write-Host "ProcessYYSY09CDRequest" -ForegroundColor White
|
||||
Write-Host "ProcessDWBG8B4DRequest" -ForegroundColor White
|
||||
Write-Host "ProcessDWBG6A2CRequest" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ4B6CRequest" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ09J8Request" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ5E9FRequest" -ForegroundColor White
|
||||
Write-Host "ProcessQYGL3F8ERequest" -ForegroundColor White
|
||||
Write-Host "ProcessIVYZ81NCRequest" -ForegroundColor White
|
||||
Write-Host "ProcessIVYZ7F3ARequest" -ForegroundColor White
|
||||
Write-Host "ProcessDWBG7F3ARequest" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ8A2DRequest" -ForegroundColor White
|
||||
Write-Host "ProcessYYSY8B1CRequest" -ForegroundColor White
|
||||
Write-Host "ProcessYYSY7D3ERequest" -ForegroundColor White
|
||||
Write-Host "ProcessFLXG7E8FRequest" -ForegroundColor White
|
||||
Write-Host "ProcessIVYZ8I9JRequest" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ7F1ARequest" -ForegroundColor White
|
||||
Write-Host "ProcessIVYZ3P9MRequest" -ForegroundColor White
|
||||
Write-Host "ProcessJRZQ6F2ARequest" -ForegroundColor White
|
||||
|
||||
Write-Host "`n总计需要修改 30 个方法" -ForegroundColor Yellow
|
||||
Write-Host "`n提示:在IDE中使用查找替换功能会更方便" -ForegroundColor Cyan
|
||||
Write-Host "查找:a.tianyuanapi.CallInterface(`(" -ForegroundColor Cyan
|
||||
Write-Host "替换:a.callTianyuanApiWithLog(ctx, `", `(" -ForegroundColor Cyan
|
||||
|
||||
Write-Host "`n`n操作完成!请检查文件并手动添加 ctx 声明" -ForegroundColor Green
|
||||
|
||||
97
deploy/sql/批量替换API调用说明.md
Normal file
97
deploy/sql/批量替换API调用说明.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# 批量替换天元API调用方法
|
||||
|
||||
## 目的
|
||||
将所有 `a.tianyuanapi.CallInterface(` 替换为 `a.callTianyuanApiWithLog(ctx, "", `
|
||||
|
||||
## 需要修改的文件
|
||||
`ycc-proxy-server/app/main/api/internal/service/apirequestService.go`
|
||||
|
||||
## 手动修改步骤
|
||||
|
||||
### 步骤1:在方法开头添加 ctx 声明
|
||||
在每个需要修改的方法开头,在 `func` 声明后添加:
|
||||
```go
|
||||
ctx := context.Background()
|
||||
```
|
||||
|
||||
### 步骤2:替换调用
|
||||
查找并替换:
|
||||
```
|
||||
a.callTianyuanApiWithLog(ctx, "", "API名称", map[string]interface{}{
|
||||
```
|
||||
替换为:
|
||||
```
|
||||
a.callTianyuanApiWithLog(ctx, "", "API名称", map[string]interface{}{
|
||||
```
|
||||
|
||||
## 具体需要修改的方法列表(已完成部分)
|
||||
|
||||
### ✅ 已完成
|
||||
1. ✅ ProcessYYSYBE08Request (第886行)
|
||||
2. ✅ ProcessFLXG0V4BRequest (第653行)
|
||||
|
||||
### ⏳ 待修改
|
||||
1. ProcessPersonEnterpriseProRequest (第320行) - 主接口
|
||||
2. ProcessPersonEnterpriseProRequest (第522行) - 涉诉查询
|
||||
3. ProcessFLXG0687Request (第675行)
|
||||
4. ProcessFLXG3D56Request (第705行)
|
||||
5. ProcessIVYZ5733Request (第759行)
|
||||
6. ProcessIVYZ9A2BRequest (第815行)
|
||||
7. ProcessJRZQ0A03Request (第929行)
|
||||
8. ProcessJRZQ8203Request (第986行)
|
||||
9. ProcessJRZQ4AA8Request (第1043行)
|
||||
10. ProcessQYGL8271Request (第1092行)
|
||||
11. ProcessQYGL6F2DRequest (第1150行)
|
||||
12. ProcessQCXG7A2BRequest (第1191行)
|
||||
13. ProcessYYSY09CDRequest (第1211行)
|
||||
14. ProcessDWBG8B4DRequest (第1322行)
|
||||
15. ProcessDWBG6A2CRequest (第1347行)
|
||||
16. ProcessJRZQ4B6CRequest (第1371行)
|
||||
17. ProcessJRZQ09J8Request (第1395行)
|
||||
18. ProcessJRZQ5E9FRequest (第1419行)
|
||||
19. ProcessQYGL3F8ERequest (第1441行)
|
||||
20. ProcessIVYZ81NCRequest (第1461行)
|
||||
21. ProcessIVYZ7F3ARequest (第1482行)
|
||||
22. ProcessDWBG7F3ARequest (第1505行)
|
||||
23. ProcessJRZQ8A2DRequest (第1528行)
|
||||
24. ProcessYYSY8B1CRequest (第1550行)
|
||||
25. ProcessYYSY7D3ERequest (第1569行)
|
||||
26. ProcessFLXG7E8FRequest (第1590行)
|
||||
27. ProcessIVYZ8I9JRequest (第1545行)
|
||||
28. ProcessJRZQ7F1ARequest (第1568行)
|
||||
29. ProcessIVYZ3P9MRequest (第1591行)
|
||||
30. ProcessJRZQ6F2ARequest (第1612行)
|
||||
|
||||
## 使用IDE批量替换功能
|
||||
|
||||
### 方式1:使用VSCode查找替换
|
||||
1. 打开 `apirequestService.go`
|
||||
2. 按 `Ctrl+H` 打开查找替换
|
||||
3. 查找内容:`a.callTianyuanApiWithLog(ctx, "", "`
|
||||
4. 替换内容:`a.callTianyuanApiWithLog(ctx, "", "`
|
||||
5. 点击"全部替换"
|
||||
|
||||
### 方式2:使用正则表达式批量替换
|
||||
查找:`a\.tianyuanapi\.CallInterface\("(.+?)",`
|
||||
替换:`a.callTianyuanApiWithLog(ctx, "", "$1",`
|
||||
|
||||
**注意:** 执行批量替换后,还需要在每个方法开头添加 `ctx := context.Background()` 声明
|
||||
|
||||
## 验证修改
|
||||
|
||||
修改完成后,执行以下步骤验证:
|
||||
|
||||
1. 编译项目
|
||||
```bash
|
||||
cd ycc-proxy-server
|
||||
go build ./...
|
||||
```
|
||||
|
||||
2. 检查是否有编译错误
|
||||
|
||||
3. 运行测试,发起几个API请求
|
||||
|
||||
4. 检查数据库 `tianyuanapi_call_log` 表,验证记录是否正确插入
|
||||
|
||||
5. 检查成本价是否正确计算(成功调用有成本,失败调用成本为0)
|
||||
|
||||
Reference in New Issue
Block a user