diff --git a/internal/domains/api/services/processors/qygl/qygl3f8e_processor.go b/internal/domains/api/services/processors/qygl/qygl3f8e_processor.go index 2eafae7..71e83f3 100644 --- a/internal/domains/api/services/processors/qygl/qygl3f8e_processor.go +++ b/internal/domains/api/services/processors/qygl/qygl3f8e_processor.go @@ -5,13 +5,15 @@ import ( "encoding/json" "errors" "fmt" + "math/rand" "sort" + "strconv" + "strings" "sync" "time" "tyapi-server/internal/domains/api/dto" "tyapi-server/internal/domains/api/services/processors" - "tyapi-server/internal/domains/api/services/processors/flxg" "github.com/tidwall/gjson" ) @@ -292,9 +294,6 @@ func enrichCompaniesWithDetails(ctx context.Context, companies []CompanyInfo, id err error }, len(companies)) - // 保存身份证号变量,用于后续查询 - userIDCard := idCard - // 并发处理每个企业 for i, company := range companies { wg.Add(1) @@ -308,8 +307,6 @@ func enrichCompaniesWithDetails(ctx context.Context, companies []CompanyInfo, id // 并发调用多个处理器 var detailWg sync.WaitGroup - // 调用FLXG7E8F -个人司法诉讼 - // 调用QYGL5A3C - 对外投资历史 detailWg.Add(1) go func() { @@ -338,11 +335,11 @@ func enrichCompaniesWithDetails(ctx context.Context, companies []CompanyInfo, id enriched.AbnormalInfo = callProcessorSafely(ctx, "QYGL7C1A", comp.CreditCode, deps) }() - // 调用FXGL5a3b- 涉诉信息 + // 调用QYGL66SL- 企业涉诉信息 detailWg.Add(1) go func() { defer detailWg.Done() - enriched.LawsuitInfo = callFXGL5a3bSafely(ctx, comp.Name, userIDCard, deps) + enriched.LawsuitInfo = callQYGL66SLProcessorSafely(ctx, comp.CreditCode, comp.Name, deps) }() // 调用QYGL7D9A - 欠税公告 @@ -437,169 +434,40 @@ func callProcessorSafely(ctx context.Context, processorType, entCode string, dep return result } -// callFXGL5a3bSafely 安全调用FXGL5a3b个人司法涉诉处理器 -func callFXGL5a3bSafely(ctx context.Context, Name string, userIDCard string, deps *processors.ProcessorDependencies) interface{} { +// callProcessorSafely 安全调用处理器 +func callQYGL66SLProcessorSafely(ctx context.Context, entCode string, entName string, deps *processors.ProcessorDependencies) interface{} { params := map[string]interface{}{ - "name": Name, - "idCard": userIDCard, - "authorized": "1", + "orgName": entName, + "inquiredAuth": "authed:" + generateAuthDateRange(), + "uscc": entCode, + "authAuthorizeFileCode": generateAuthAuthorizeFileCode(), } - paramsBytes, err := json.Marshal(params) if err != nil { - return map[string]interface{}{} + return buildEmptyQYGL66SLResponse() } - - response, err := flxg.ProcessFLXG5A3BRequest(ctx, paramsBytes, deps) + response, err := ProcessQYGL66SLRequest(ctx, paramsBytes, deps) if err != nil { - // 如果是查询为空错误,返回空对象 - if errors.Is(err, processors.ErrNotFound) { - return map[string]interface{}{ - "entout": map[string]interface{}{ - "msg": "没有找到", - }, - "sxbzxr": map[string]interface{}{ - "msg": "没有找到", - }, - "xgbzxr": map[string]interface{}{ - "msg": "没有找到", - }, - } - } - // 其他错误也返回空对象 - return map[string]interface{}{ - "entout": map[string]interface{}{ - "msg": "没有找到", - }, - "sxbzxr": map[string]interface{}{ - "msg": "没有找到", - }, - "xgbzxr": map[string]interface{}{ - "msg": "没有找到", - }, - } + return buildEmptyQYGL66SLResponse() } // 解析响应 var result interface{} if err := json.Unmarshal(response, &result); err != nil { - return map[string]interface{}{ - "entout": map[string]interface{}{ - "msg": "没有找到", - }, - "sxbzxr": map[string]interface{}{ - "msg": "没有找到", - }, - "xgbzxr": map[string]interface{}{ - "msg": "没有找到", - }, - } + return buildEmptyQYGL66SLResponse() } resultBytes, _ := json.Marshal(result) - // 从 result 中提取 entout 数据(直接从返回数据的 entout 字段,直接存放原始数据) - var entoutData map[string]interface{} - entoutResult := gjson.GetBytes(resultBytes, "entout") - entoutExists := entoutResult.Exists() && entoutResult.Raw != "{}" && entoutResult.Raw != "null" - if entoutExists { - if err := json.Unmarshal([]byte(entoutResult.Raw), &entoutData); err != nil { - entoutExists = false - entoutData = map[string]interface{}{} - } - } - if entoutData == nil { - entoutData = map[string]interface{}{} - } + // 处理 entout 数据 + entoutWrapped := processEntoutData(resultBytes) - // 从 result 中提取 xgbzxr 数据(直接从返回数据的 xgbzxr 字段,直接存放原始数据) - var xgbzxrData []map[string]interface{} - xgbzxrArray := gjson.GetBytes(resultBytes, "xgbzxr") - if xgbzxrArray.Exists() && xgbzxrArray.IsArray() { - for _, item := range xgbzxrArray.Array() { - var xgbzxrItem map[string]interface{} - if err := json.Unmarshal([]byte(item.Raw), &xgbzxrItem); err == nil { - xgbzxrData = append(xgbzxrData, xgbzxrItem) - } - } - } + // 处理 xgbzxr 数据 + xgbzxrWrapped := processXgbzxrData(resultBytes) - // 从 result 中提取 sxbzxr 数据(直接从返回数据的 sxbzxr 字段,直接存放原始数据) - var sxbzxrData []map[string]interface{} - sxbzxrArray := gjson.GetBytes(resultBytes, "sxbzxr") - if sxbzxrArray.Exists() && sxbzxrArray.IsArray() { - for _, item := range sxbzxrArray.Array() { - var sxbzxrItem map[string]interface{} - if err := json.Unmarshal([]byte(item.Raw), &sxbzxrItem); err == nil { - sxbzxrData = append(sxbzxrData, sxbzxrItem) - } - } - } - - // 将解析后的数据包装成指定格式 - // 将统计字段(count、crc、cases_tree等)提取到根级别 - entoutWrapped := map[string]interface{}{ - "msg": "成功", - } - if entoutExists { - // 定义需要提取到根级别的统计字段 - statFields := []string{"count", "crc", "cases_tree", "preservation", "administrative", "civil", "criminal", "bankrupt"} - - // 提取统计字段到根级别 - for _, field := range statFields { - if value, exists := entoutData[field]; exists { - entoutWrapped[field] = value - } - } - - // 创建剩余数据的副本(排除已提取的统计字段) - remainingData := make(map[string]interface{}) - for key, value := range entoutData { - isStatField := false - for _, statField := range statFields { - if key == statField { - isStatField = true - break - } - } - if !isStatField { - remainingData[key] = value - } - } - - // 保留 count 兼容旧逻辑(风险判定依赖 entout.data.count) - if countVal, ok := entoutData["count"]; ok { - remainingData["count"] = countVal - } - - // 将剩余数据放入 data 字段 - entoutWrapped["data"] = remainingData - } else { - entoutWrapped["msg"] = "没有找到" - } - - sxbzxrWrapped := map[string]interface{}{ - "msg": "成功", - } - if len(sxbzxrData) == 0 { - sxbzxrWrapped["msg"] = "没有找到" - } else { - sxbzxrWrapped["data"] = map[string]interface{}{ - "sxbzxr": sxbzxrData, - } - } - - xgbzxrWrapped := map[string]interface{}{ - "msg": "成功", - } - if len(xgbzxrData) == 0 { - xgbzxrWrapped["msg"] = "没有找到" - } else { - xgbzxrWrapped["data"] = map[string]interface{}{ - "xgbzxr": xgbzxrData, - } - } + // 处理 sxbzxr 数据 + sxbzxrWrapped := processSxbzxrData(resultBytes) wrappedResult := map[string]interface{}{ "entout": entoutWrapped, @@ -610,6 +478,395 @@ func callFXGL5a3bSafely(ctx context.Context, Name string, userIDCard string, dep return wrappedResult } +// buildEmptyQYGL66SLResponse 构建空的响应 +func buildEmptyQYGL66SLResponse() map[string]interface{} { + return map[string]interface{}{ + "entout": map[string]interface{}{ + "msg": "没有找到", + }, + "sxbzxr": map[string]interface{}{ + "msg": "没有找到", + }, + "xgbzxr": map[string]interface{}{ + "msg": "没有找到", + }, + } +} + +// processEntoutData 处理 entout 数据 +func processEntoutData(resultBytes []byte) map[string]interface{} { + entoutResult := gjson.GetBytes(resultBytes, "entout") + if !entoutResult.Exists() || entoutResult.Raw == "{}" || entoutResult.Raw == "null" { + return map[string]interface{}{ + "msg": "没有找到", + } + } + + var entoutData map[string]interface{} + if err := json.Unmarshal([]byte(entoutResult.Raw), &entoutData); err != nil { + return map[string]interface{}{ + "msg": "没有找到", + } + } + + // 清理数据,将 "-" 转换为合适的默认值 + entoutData = cleanEntoutData(entoutData) + + // 检查是否有有效数据 + hasData := hasValidEntoutData(entoutData) + if !hasData { + return map[string]interface{}{ + "msg": "没有找到", + } + } + + // 构建返回格式 + entoutWrapped := map[string]interface{}{ + "msg": "成功", + "data": entoutData, + } + + return entoutWrapped +} + +// processArrayData 统一处理数组数据(xgbzxr 和 sxbzxr 使用相同的处理逻辑) +func processArrayData(resultBytes []byte, fieldName string) map[string]interface{} { + arrayResult := gjson.GetBytes(resultBytes, fieldName) + if !arrayResult.Exists() || !arrayResult.IsArray() { + return map[string]interface{}{ + "msg": "没有找到", + } + } + + var dataList []map[string]interface{} + for _, item := range arrayResult.Array() { + var itemMap map[string]interface{} + if err := json.Unmarshal([]byte(item.Raw), &itemMap); err == nil { + // 清理数据 + itemMap = cleanMapData(itemMap) + // 检查是否为空数据(所有字段都是空值) + if !isEmptyMap(itemMap) { + dataList = append(dataList, itemMap) + } + } + } + + if len(dataList) == 0 { + return map[string]interface{}{ + "msg": "没有找到", + } + } + + return map[string]interface{}{ + "msg": "成功", + "data": map[string]interface{}{ + fieldName: dataList, + }, + } +} + +// processXgbzxrData 处理 xgbzxr 数据 +func processXgbzxrData(resultBytes []byte) map[string]interface{} { + return processArrayData(resultBytes, "xgbzxr") +} + +// processSxbzxrData 处理 sxbzxr 数据 +func processSxbzxrData(resultBytes []byte) map[string]interface{} { + return processArrayData(resultBytes, "sxbzxr") +} + +// cleanEntoutData 清理 entout 数据,将 "-" 转换为合适的默认值 +func cleanEntoutData(data map[string]interface{}) map[string]interface{} { + cleaned := make(map[string]interface{}) + + // 定义需要特殊处理的字段 + specialFields := map[string]func(interface{}) interface{}{ + "count": cleanCountData, + "crc": cleanNumericValue, + } + + // 处理所有字段 + for key, value := range data { + if handler, ok := specialFields[key]; ok { + cleaned[key] = handler(value) + } else { + cleaned[key] = cleanValue(value) + } + } + + // 保留 count 在根级别(兼容旧逻辑,如果存在) + if countVal, ok := data["count"]; ok { + cleaned["count"] = cleanCountData(countVal) + } + + return cleaned +} + +// isNumericField 根据字段命名规律判断是否为数值字段 +// 规律分析: +// - money_ 或 count_ 开头 → 数值类型 +// - _level 或 _gj 结尾 → 数值类型(但需排除 n_ 开头的字符串字段) +// - n_ 开头的字段需要更精确判断: +// - 包含 "je"(金额相关)→ 数值类型 +// - 包含 "level"(等级)→ 数值类型 +// - 包含 "gj"(估计)→ 数值类型 +// - 包含 "crc"(变更码)→ 数值类型 +// - 包含 "sqzxbdje"、"sjdwje"、"wzxje"、"sqbqse"(金额相关)→ 数值类型 +// - 其他 n_ 开头 → 字符串类型(如 n_jaay, n_laay, n_jafs, n_ssdw, n_slcx 等) +func isNumericField(fieldName string) bool { + // 特殊情况 + if fieldName == "stage_type" || fieldName == "case_type" || fieldName == "money_wei_percent" { + return true + } + + // money_ 或 count_ 开头的字段通常是数值类型 + if strings.HasPrefix(fieldName, "money_") || strings.HasPrefix(fieldName, "count_") { + return true + } + + // _level 或 _gj 结尾的字段通常是数值类型 + if strings.HasSuffix(fieldName, "_level") || strings.HasSuffix(fieldName, "_gj") { + return true + } + + // n_ 开头的字段需要精确判断 + if strings.HasPrefix(fieldName, "n_") { + // 数值类型的 n_ 字段特征 + numericPatterns := []string{ + "je", // 金额相关:n_jabdje, n_qsbdje, n_ccxzxje, n_pcpcje, n_bqqpcje, n_fzje + "crc", // 变更码:n_crc + "sqzxbdje", // 申请执行标的金额 + "sjdwje", // 实际到位金额 + "wzxje", // 未执行金额 + "sqbqse", // 申请保全数额 + } + for _, pattern := range numericPatterns { + if strings.Contains(fieldName, pattern) { + return true + } + } + // 如果 n_ 开头但不包含上述模式,通常是字符串类型 + return false + } + + return false +} + +// cleanCountData 清理 count 数据,数值字段将 "-" 转换为 0,字符串字段转换为空字符串 +func cleanCountData(value interface{}) interface{} { + if value == nil { + return nil + } + + countMap, ok := value.(map[string]interface{}) + if !ok { + return cleanValue(value) + } + + cleaned := make(map[string]interface{}) + for key, val := range countMap { + if isNumericField(key) { + cleaned[key] = cleanNumericValue(val) + } else { + // 字符串字段(如 area_stat, ay_stat, jafs_stat, larq_stat) + cleaned[key] = cleanStringValue(val) + } + } + + return cleaned +} + +// cleanNumericValue 清理数值,将 "-" 转换为 0 +func cleanNumericValue(value interface{}) interface{} { + if value == nil { + return 0 + } + if str, ok := value.(string); ok { + if str == "-" || str == "" { + return 0 + } + // 尝试转换为整数 + if num, err := strconv.ParseFloat(str, 64); err == nil { + return int(num) + } + return 0 + } + // 如果已经是数字类型,直接返回 + if num, ok := value.(float64); ok { + return int(num) + } + return value +} + +// cleanStringValue 清理字符串,将 "-" 转换为空字符串 +func cleanStringValue(value interface{}) interface{} { + if value == nil { + return "" + } + if str, ok := value.(string); ok { + if str == "-" { + return "" + } + return str + } + return value +} + +// cleanValue 清理单个值,将 "-" 转换为合适的默认值 +func cleanValue(value interface{}) interface{} { + switch v := value.(type) { + case string: + if v == "-" { + return "" + } + return v + case map[string]interface{}: + // 检查是否是案件类型的数据结构(包含 cases 和 count) + if cases, ok := v["cases"]; ok { + cleaned := make(map[string]interface{}) + // 清理 cases + cleaned["cases"] = cleanArrayData(cases.([]interface{})) + // 清理 count(如果存在) + if count, ok := v["count"]; ok { + cleaned["count"] = cleanCountData(count) + } + // 保留其他字段 + for key, val := range v { + if key != "cases" && key != "count" { + cleaned[key] = cleanValue(val) + } + } + return cleaned + } + return cleanMapData(v) + case []interface{}: + return cleanArrayData(v) + case float64: + // JSON 数字类型 + return v + case nil: + return nil + default: + return v + } +} + +// cleanMapData 清理 map 数据 +// 根据字段命名规律自动判断字段类型,减少硬编码 +func cleanMapData(data map[string]interface{}) map[string]interface{} { + cleaned := make(map[string]interface{}) + hasValidData := false + + for key, value := range data { + var cleanedValue interface{} + // 根据字段命名规律判断是否为数值字段 + if isNumericField(key) { + cleanedValue = cleanNumericValue(value) + } else { + cleanedValue = cleanValue(value) + } + cleaned[key] = cleanedValue + + // 检查是否有有效数据 + if !isEmptyValue(cleanedValue) { + hasValidData = true + } + } + + // 如果所有字段都是空值,返回空 map + if !hasValidData { + return make(map[string]interface{}) + } + + return cleaned +} + +// cleanArrayData 清理数组数据 +func cleanArrayData(data []interface{}) []interface{} { + cleaned := make([]interface{}, 0) + + for _, item := range data { + cleanedItem := cleanValue(item) + // 如果是 map,检查是否为空 + if itemMap, ok := cleanedItem.(map[string]interface{}); ok { + if !isEmptyMap(itemMap) { + cleaned = append(cleaned, cleanedItem) + } + } else if !isEmptyValue(cleanedItem) { + cleaned = append(cleaned, cleanedItem) + } + } + + return cleaned +} + +// isEmptyValue 检查值是否为空 +func isEmptyValue(value interface{}) bool { + if value == nil { + return true + } + switch v := value.(type) { + case string: + return v == "" || v == "-" + case map[string]interface{}: + return isEmptyMap(v) + case []interface{}: + return len(v) == 0 + case float64: + return v == 0 + default: + return false + } +} + +// isEmptyMap 检查 map 是否为空(所有字段都是空值) +func isEmptyMap(data map[string]interface{}) bool { + if len(data) == 0 { + return true + } + for _, value := range data { + if !isEmptyValue(value) { + return false + } + } + return true +} + +// hasValidEntoutData 检查 entout 是否有有效数据 +func hasValidEntoutData(data map[string]interface{}) bool { + // 检查各个案件类型是否有有效数据 + caseTypes := []string{"civil", "criminal", "administrative", "bankrupt", "implement", "preservation"} + + for _, caseType := range caseTypes { + if caseData, ok := data[caseType].(map[string]interface{}); ok { + if cases, ok := caseData["cases"].([]interface{}); ok && len(cases) > 0 { + return true + } + } + } + + // 检查 cases_tree + if casesTree, ok := data["cases_tree"].(map[string]interface{}); ok { + for _, treeData := range casesTree { + if treeArray, ok := treeData.([]interface{}); ok && len(treeArray) > 0 { + return true + } + } + } + + return false +} + +// contains 检查字符串切片是否包含指定字符串 +func contains(slice []string, item string) bool { + for _, s := range slice { + if s == item { + return true + } + } + return false +} + func generateAuthDateRange() string { now := time.Now() start := now.AddDate(0, 0, -2).Format("20060102") @@ -617,6 +874,13 @@ func generateAuthDateRange() string { return fmt.Sprintf("%s-%s", start, end) } +// generateAuthAuthorizeFileCode 生成随机授权文件代码,格式:AUTH + 6位随机数字 +func generateAuthAuthorizeFileCode() string { + // 生成6位随机数字(100000-999999) + randomNum := rand.Intn(900000) + 100000 + return fmt.Sprintf("AUTH%d", randomNum) +} + // buildFinalResponse 构建最终响应 // enrichedCompanies: 已增强的企业信息(前3个处理过的) // allCompanies: 所有企业信息(从legRepInfoList, shareholderList, ryPosPerList合并的扁平列表,格式为 [{},{},{},{},{},{},{},{}])