This commit is contained in:
Mrx
2026-05-29 12:28:08 +08:00
parent 43acbeb8f4
commit 0973bb099c
21 changed files with 2964 additions and 156 deletions

View File

@@ -0,0 +1,59 @@
package flxg
import (
"context"
"encoding/json"
"errors"
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/zhicha"
)
// ProcessFLXG5A3BCOPYRequest FLXG5A3B COPY API处理方法 - 个人司法涉诉
func ProcessFLXG5A3BCOPYRequest(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
var paramsDto dto.FLXG5A3BReq
if err := json.Unmarshal(params, &paramsDto); err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if err := deps.Validator.ValidateStruct(paramsDto); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" || paramsDto.IDCard == "370982199012037272" || paramsDto.IDCard == "431027198810290730" || paramsDto.IDCard == "362502199510298017" || paramsDto.IDCard == "340826199008250378" || paramsDto.IDCard == "321027198304072129" || paramsDto.IDCard == "420116198907031413" || paramsDto.IDCard == "13032319930128263X" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI006", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return respBytes, nil
}

View File

@@ -7,7 +7,7 @@ import (
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/zhicha"
"tyapi-server/internal/infrastructure/external/nuoer"
)
// ProcessFLXG5A3BRequest FLXG5A3B API处理方法 - 个人司法涉诉
@@ -24,33 +24,33 @@ func ProcessFLXG5A3BRequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
body := map[string]string{
"name": paramsDto.Name,
"idCard": paramsDto.IDCard,
}
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
nuoerDoCheckAPIKey := "personalLawsuit_cv1"
ApiPath := "/v1/doCheck"
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI006", reqData)
resp, err := deps.NuoerService.CallAPI(ctx, nuoerDoCheckAPIKey, ApiPath, body)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
if errors.Is(err, nuoer.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
if errors.Is(err, nuoer.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
rawData, ok := resp.Data.(map[string]interface{})
if !ok {
return nil, errors.Join(processors.ErrSystem, errors.New("响应格式错误"))
}
result := mapNuoerPersonalLawsuitToResponse(rawData)
respBytes, err := json.Marshal(result)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}

View File

@@ -0,0 +1,177 @@
package flxg
// mapNuoerPersonalLawsuitToResponse 将 nuoer 响应转为对外结构2.md
// lawsuitStat -> entout, breachCaseList -> sxbzxr, consumptionRestrictionList -> xgbzxr
func mapNuoerPersonalLawsuitToResponse(data map[string]interface{}) map[string]interface{} {
if data == nil {
return defaultFLXG5A3BResponse()
}
if _, hasEntout := data["entout"]; hasEntout {
return data
}
flat := unwrapNuoerPersonalLawsuitData(data)
return map[string]interface{}{
"sxbzxr": asSlice(flat["breachCaseList"]),
"xgbzxr": asSlice(flat["consumptionRestrictionList"]),
"entout": pickEntout(flat["lawsuitStat"]),
}
}
func defaultFLXG5A3BResponse() map[string]interface{} {
return map[string]interface{}{
"sxbzxr": []interface{}{},
"entout": map[string]interface{}{},
"xgbzxr": []interface{}{},
}
}
func pickEntout(v interface{}) interface{} {
if v == nil {
return map[string]interface{}{}
}
return v
}
// unwrapNuoerPersonalLawsuitData 解包 nuoer 嵌套结构 data.result.detail[],提取 1.md 平铺字段。
func unwrapNuoerPersonalLawsuitData(data map[string]interface{}) map[string]interface{} {
if _, ok := data["lawsuitStat"]; ok {
return data
}
if result, ok := data["result"].(map[string]interface{}); ok {
for _, item := range asSlice(result["detail"]) {
if flat := extractFromNuoerDetailItem(asMap(item)); len(flat) > 0 {
return flat
}
}
}
return data
}
func extractFromNuoerDetailItem(item map[string]interface{}) map[string]interface{} {
if len(item) == 0 {
return nil
}
lawsuitStat := extractLawsuitStatFromDetailItem(item)
if !isLawsuitStatPayload(asMap(lawsuitStat)) {
return nil
}
return map[string]interface{}{
"lawsuitStat": lawsuitStat,
"breachCaseList": extractBreachCaseRecords(item),
"consumptionRestrictionList": extractConsumptionRestrictionRecords(item),
}
}
func extractLawsuitStatFromDetailItem(item map[string]interface{}) interface{} {
// nuoer 真实涉诉数据通常在 breachCaseList/consumptionRestrictionList 的包装对象内
for _, v := range asSlice(item["breachCaseList"]) {
if m := asMap(v); m != nil {
if ls := asMap(m["lawsuitStat"]); isLawsuitStatPayload(ls) {
return ls
}
}
}
for _, v := range asSlice(item["consumptionRestrictionList"]) {
if m := asMap(v); m != nil {
if ls := asMap(m["lawsuitStat"]); isLawsuitStatPayload(ls) {
return ls
}
}
}
if lsWrap := asMap(item["lawsuitStat"]); lsWrap != nil {
if ls := extractLawsuitStatFromWrapper(lsWrap); ls != nil {
return ls
}
}
return map[string]interface{}{}
}
func extractLawsuitStatFromWrapper(wrap map[string]interface{}) map[string]interface{} {
if isLawsuitStatPayload(wrap) {
return wrap
}
for _, v := range asSlice(wrap["detail"]) {
if m := asMap(v); m != nil {
if ls := asMap(m["lawsuitStat"]); isLawsuitStatPayload(ls) {
return ls
}
if isLawsuitStatPayload(m) {
return m
}
}
}
return nil
}
func isLawsuitStatPayload(m map[string]interface{}) bool {
if len(m) == 0 {
return false
}
for _, k := range []string{"criminal", "civil", "administrative", "cases_tree", "count", "crc", "implement", "preservation", "bankrupt"} {
if _, ok := m[k]; ok {
return true
}
}
return false
}
func extractBreachCaseRecords(item map[string]interface{}) []interface{} {
out := make([]interface{}, 0)
collectBreachCaseRecords(asSlice(item["breachCaseList"]), &out)
if lsWrap := asMap(item["lawsuitStat"]); lsWrap != nil {
for _, v := range asSlice(lsWrap["detail"]) {
collectBreachCaseRecords(asSlice(asMap(v)["breachCaseList"]), &out)
}
}
return out
}
func collectBreachCaseRecords(list []interface{}, out *[]interface{}) {
for _, v := range list {
m := asMap(v)
if len(m) == 0 {
continue
}
if _, isWrapper := m["lawsuitStat"]; isWrapper {
if inner := asSlice(m["breachCaseList"]); len(inner) > 0 {
collectBreachCaseRecords(inner, out)
}
continue
}
if _, hasAh := m["ah"]; hasAh {
*out = append(*out, m)
}
}
}
func extractConsumptionRestrictionRecords(item map[string]interface{}) []interface{} {
out := make([]interface{}, 0)
collectConsumptionRestrictionRecords(asSlice(item["consumptionRestrictionList"]), &out)
if lsWrap := asMap(item["lawsuitStat"]); lsWrap != nil {
for _, v := range asSlice(lsWrap["detail"]) {
collectConsumptionRestrictionRecords(asSlice(asMap(v)["consumptionRestrictionList"]), &out)
}
}
return out
}
func collectConsumptionRestrictionRecords(list []interface{}, out *[]interface{}) {
for _, v := range list {
m := asMap(v)
if len(m) == 0 {
continue
}
if _, isWrapper := m["lawsuitStat"]; isWrapper {
if inner := asSlice(m["consumptionRestrictionList"]); len(inner) > 0 {
collectConsumptionRestrictionRecords(inner, out)
}
continue
}
if _, hasAh := m["ah"]; hasAh {
*out = append(*out, m)
}
}
}

View File

@@ -7,7 +7,7 @@ import (
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/zhicha"
"tyapi-server/internal/infrastructure/external/nuoer"
)
// ProcessFLXGDEA9Request FLXGDEA9 API处理方法
@@ -21,34 +21,36 @@ func ProcessFLXGDEA9Request(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err)
}
encryptedName, err := deps.ZhichaService.Encrypt(paramsDto.Name)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
if paramsDto.IDCard == "350681198611130611" || paramsDto.IDCard == "622301200006250550" || paramsDto.IDCard == "320682198910134998" || paramsDto.IDCard == "640102198708020925" || paramsDto.IDCard == "420624197310234034" || paramsDto.IDCard == "350104198501184416" || paramsDto.IDCard == "410521198606018056" || paramsDto.IDCard == "410482198504029333" || paramsDto.IDCard == "370982199012037272" || paramsDto.IDCard == "431027198810290730" || paramsDto.IDCard == "362502199510298017" || paramsDto.IDCard == "340826199008250378" || paramsDto.IDCard == "321027198304072129" || paramsDto.IDCard == "420116198907031413" || paramsDto.IDCard == "13032319930128263X" {
return nil, errors.Join(processors.ErrNotFound, errors.New("查询为空"))
}
encryptedIDCard, err := deps.ZhichaService.Encrypt(paramsDto.IDCard)
body := map[string]string{
"name": paramsDto.Name,
"idCard": paramsDto.IDCard,
}
nuoerDoCheckAPIKey := "idRiskTagV106"
ApiPath := "/v1/doCheck"
resp, err := deps.NuoerService.CallAPI(ctx, nuoerDoCheckAPIKey, ApiPath, body)
if err != nil {
if errors.Is(err, nuoer.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
}
if errors.Is(err, nuoer.ErrNotFound) {
return nil, errors.Join(processors.ErrNotFound, err)
}
return nil, errors.Join(processors.ErrSystem, err)
}
reqData := map[string]interface{}{
"name": encryptedName,
"idCard": encryptedIDCard,
"authorized": paramsDto.Authorized,
rawData, ok := resp.Data.(map[string]interface{})
if !ok {
return nil, errors.Join(processors.ErrSystem, errors.New("响应格式错误"))
}
respData, err := deps.ZhichaService.CallAPI(ctx, "ZCI005", reqData)
if err != nil {
if errors.Is(err, zhicha.ErrDatasource) {
return nil, errors.Join(processors.ErrDatasource, err)
} else {
return nil, errors.Join(processors.ErrSystem, err)
}
}
result := mapNuoerIdRiskToResponse(rawData)
// 将响应数据转换为JSON字节
respBytes, err := json.Marshal(respData)
respBytes, err := json.Marshal(result)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}

View File

@@ -0,0 +1,154 @@
package flxg
import (
"fmt"
"strconv"
"strings"
)
// riskCode 位序(从左至右 1-25到 level 代码映射,见 2.md / 1.md。
var riskCodeBitLevelMappings = map[int]string{
1: "A",
2: "B2",
3: "B",
4: "B",
5: "B4",
6: "B3",
7: "B3",
8: "B3",
9: "B3",
10: "B3",
11: "A",
12: "B",
13: "J",
14: "C3",
15: "C3",
16: "A",
17: "D",
18: "D4",
19: "D2",
20: "D",
21: "E",
22: "E",
23: "E",
24: "E",
}
// mapNuoerIdRiskToResponse 将 nuoer 响应2json.md转为对外结构1json.md
// 解包 result将 riskCode 转为 level。
func mapNuoerIdRiskToResponse(data map[string]interface{}) map[string]interface{} {
if data == nil {
return map[string]interface{}{"level": "0"}
}
if level, ok := data["level"]; ok && level != nil {
if s := strings.TrimSpace(stringifyRiskCodeVal(level)); s != "" {
return map[string]interface{}{"level": s}
}
}
payload := unwrapNuoerIdRiskData(data)
riskCode := strings.TrimSpace(stringifyRiskCodeVal(payload["riskCode"]))
return map[string]interface{}{
"level": mapRiskCodeToLevel(riskCode),
}
}
func unwrapNuoerIdRiskData(data map[string]interface{}) map[string]interface{} {
if _, ok := data["riskCode"]; ok {
return data
}
if result, ok := data["result"].(map[string]interface{}); ok {
return result
}
return data
}
func mapRiskCodeToLevel(riskCode string) string {
if riskCode == "" {
return "0"
}
codes := make([]string, 0, 8)
for i, ch := range riskCode {
if ch != '1' {
continue
}
pos := i + 1
if pos == 25 {
continue
}
if code, ok := riskCodeBitLevelMappings[pos]; ok && code != "" {
codes = append(codes, code)
}
}
codes = dedupeLevelCodes(codes)
codes = collapseParentLevelCodes(codes)
if len(codes) == 0 {
return "0"
}
return strings.Join(codes, ",")
}
func dedupeLevelCodes(codes []string) []string {
if len(codes) == 0 {
return codes
}
seen := make(map[string]struct{}, len(codes))
out := make([]string, 0, len(codes))
for _, code := range codes {
if _, ok := seen[code]; ok {
continue
}
seen[code] = struct{}{}
out = append(out, code)
}
return out
}
func collapseParentLevelCodes(codes []string) []string {
if len(codes) == 0 {
return codes
}
hasChild := func(parent string) bool {
for _, code := range codes {
if code != parent && strings.HasPrefix(code, parent) {
return true
}
}
return false
}
out := make([]string, 0, len(codes))
for _, code := range codes {
switch code {
case "A", "B", "C", "D":
if hasChild(code) {
continue
}
}
out = append(out, code)
}
return out
}
func stringifyRiskCodeVal(v interface{}) string {
if v == nil {
return ""
}
switch val := v.(type) {
case string:
return val
case float64:
if val == float64(int64(val)) {
return strconv.FormatInt(int64(val), 10)
}
return strconv.FormatFloat(val, 'f', -1, 64)
case int:
return strconv.Itoa(val)
case int64:
return strconv.FormatInt(val, 10)
default:
return fmt.Sprint(val)
}
}