This commit is contained in:
2026-04-07 13:55:50 +08:00
parent 35a2eb03d8
commit d3554e8b44
3 changed files with 863 additions and 27 deletions

View File

@@ -17,9 +17,9 @@ import (
"tyapi-server/internal/domains/api/services/processors"
)
// ProcessQYGLJ1U9Request 企业全景报告处理器:并发调用企业全量(QYGLUY3S)、股权全景(QYGLJ0Q1)、司法涉诉(QYGL5S1I)
// 以及企业年报(QYGLDJ12)、税收违法(QYGL8848)、欠税公告(QYGL7D9A)
// 前三者走 buildReport / map*;后三者在 buildReport 中转为 annualReports、taxViolations、ownTaxNotices 供页面展示
// ProcessQYGLJ1U9Request 企业全景报告处理器:并发调用企业全量(QYGLUY3S)、股权全景(QYGLJ0Q1)、司法涉诉(QYGL5S1I)
// 企业年报(QYGLDJ12)、税收违法(QYGL8848)、欠税公告(QYGL7D9A)
// 单路失败、查无、解析失败时该路按空数据处理并继续合并;仅当合并后的报告仍无任何可展示的企业要素时返回查询为空
func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors.ProcessorDependencies) ([]byte, error) {
// 复用 QYGLUY3S 的入参结构:企业名称/注册号/统一社会信用代码
var p dto.QYGLJ1U9Req
@@ -30,7 +30,7 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 并发调用三个已有处理器
// 并发调用六个子处理器;单路失败或无数据时降级为空结果,仅当合并后仍无任何企业要素时返回查询为空
type apiResult struct {
key string
data map[string]interface{}
@@ -108,12 +108,15 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
wg.Wait()
close(resultsCh)
var jiguang, judicial, equity map[string]interface{}
var annualReport, taxViolation, taxArrears map[string]interface{}
jiguang := map[string]interface{}{}
judicial := map[string]interface{}{}
equity := map[string]interface{}{}
annualReport := map[string]interface{}{}
taxViolation := map[string]interface{}{}
taxArrears := map[string]interface{}{}
for r := range resultsCh {
if r.err != nil {
// 任一关键数据源异常,则返回系统错误(也可以根据需求做降级)
return nil, errors.Join(processors.ErrSystem, fmt.Errorf("%s 调用失败: %w", r.key, r.err))
if r.err != nil || r.data == nil {
continue
}
switch r.key {
case "jiguangFull":
@@ -130,27 +133,12 @@ func ProcessQYGLJ1U9Request(ctx context.Context, params []byte, deps *processors
taxArrears = r.data
}
}
if jiguang == nil {
jiguang = map[string]interface{}{}
}
if judicial == nil {
judicial = map[string]interface{}{}
}
if equity == nil {
equity = map[string]interface{}{}
}
if annualReport == nil {
annualReport = map[string]interface{}{}
}
if taxViolation == nil {
taxViolation = map[string]interface{}{}
}
if taxArrears == nil {
taxArrears = map[string]interface{}{}
}
// 复用构建逻辑生成企业报告结构(含年报 / 税收违法 / 欠税公告的转化结果)
report := buildReport(jiguang, judicial, equity, annualReport, taxViolation, taxArrears)
if !qyglJ1U9ReportHasSubstantiveData(report) {
return nil, errors.Join(processors.ErrNotFound, errors.New("未查询到可用于生成报告的企业数据"))
}
// 为报告生成唯一编号并缓存,供后续通过编号查看
reportID := saveQYGLReport(report)

View File

@@ -58,9 +58,654 @@ func buildReport(jiguang, judicial, equity, annualRaw, taxViolationRaw, taxArrea
report["annualReports"] = annualReports
report["taxViolations"] = mapTaxViolations(taxViolationRaw)
report["ownTaxNotices"] = mapOwnTaxNotices(taxArrearsRaw)
applyQYGLJ1U9ReportFieldDefaults(report)
return report
}
// applyQYGLJ1U9ReportFieldDefaults 在子数据源缺失时仍保证报告字段齐全:字符串 ""、数值 0、数组 []、对象按约定填空结构(不向客户暴露「缺键」)。
func applyQYGLJ1U9ReportFieldDefaults(report map[string]interface{}) {
if report == nil {
return
}
// 顶层字符串
report["entName"] = str(report["entName"])
report["creditCode"] = str(report["creditCode"])
report["reportTime"] = str(report["reportTime"])
report["basic"] = mergeBasicDefaults(report["basic"])
b, _ := report["basic"].(map[string]interface{})
if str(report["entName"]) == "" {
report["entName"] = str(b["entName"])
}
if str(report["creditCode"]) == "" {
report["creditCode"] = str(b["creditCode"])
}
report["branches"] = ensureSlice(report["branches"])
report["guarantees"] = ensureSlice(report["guarantees"])
report["inspections"] = ensureSlice(report["inspections"])
report["timeline"] = ensureSlice(report["timeline"])
report["beneficiaries"] = ensureSlice(report["beneficiaries"])
report["annualReports"] = ensureSlice(report["annualReports"])
if _, ok := report["basicList"]; !ok {
report["basicList"] = []interface{}{}
} else {
report["basicList"] = ensureSlice(report["basicList"])
}
report["shareholding"] = mergeShareholdingDefaults(report["shareholding"])
report["controller"] = mergeControllerDefaults(report["controller"])
report["investments"] = mergeInvestmentsDefaults(report["investments"])
report["management"] = mergeManagementDefaults(report["management"])
report["assets"] = mergeAssetsDefaults(report["assets"])
report["licenses"] = mergeLicensesDefaults(report["licenses"])
report["activities"] = mergeActivitiesDefaults(report["activities"])
report["risks"] = mergeRisksDefaults(report["risks"])
report["listed"] = mergeListedDefaults(report["listed"])
report["taxViolations"] = mergeTaxViolationsDefaults(report["taxViolations"])
report["ownTaxNotices"] = mergeOwnTaxNoticesDefaults(report["ownTaxNotices"])
if ro, ok := report["riskOverview"].(map[string]interface{}); ok {
report["riskOverview"] = mergeRiskOverviewDefaults(ro)
} else {
report["riskOverview"] = mergeRiskOverviewDefaults(nil)
}
}
func mergeBasicDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
skel := map[string]interface{}{
"entName": "",
"creditCode": "",
"regNo": "",
"orgCode": "",
"entType": "",
"entTypeCode": "",
"entityTypeCode": "",
"establishDate": "",
"registeredCapital": float64(0),
"regCapCurrency": "",
"regCapCurrencyCode": "",
"regOrg": "",
"regOrgCode": "",
"regProvince": "",
"provinceCode": "",
"regCity": "",
"regCityCode": "",
"regDistrict": "",
"districtCode": "",
"address": "",
"postalCode": "",
"legalRepresentative": "",
"compositionForm": "",
"approvedBusinessItem": "",
"status": "",
"statusCode": "",
"operationPeriodFrom": "",
"operationPeriodTo": "",
"approveDate": "",
"cancelDate": "",
"revokeDate": "",
"cancelReason": "",
"revokeReason": "",
"businessScope": "",
"lastAnnuReportYear": "",
"oldNames": []interface{}{},
}
for k, def := range skel {
if _, ok := out[k]; !ok {
out[k] = def
}
}
if out["oldNames"] == nil {
out["oldNames"] = []interface{}{}
}
return out
}
func ensureSlice(v interface{}) []interface{} {
if v == nil {
return []interface{}{}
}
arr, ok := v.([]interface{})
if !ok {
return []interface{}{}
}
return arr
}
func mergeShareholdingDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
skel := map[string]interface{}{
"shareholders": []interface{}{},
"equityChanges": []interface{}{},
"equityPledges": []interface{}{},
"paidInDetails": []interface{}{},
"subscribedCapitalDetails": []interface{}{},
"hasEquityPledges": false,
"shareholderCount": 0,
"registeredCapital": float64(0),
"currency": "",
"topHolderName": "",
"topHolderPercent": float64(0),
"top5TotalPercent": float64(0),
}
for k, def := range skel {
if _, ok := out[k]; !ok {
out[k] = def
}
}
for _, k := range []string{"shareholders", "equityChanges", "equityPledges", "paidInDetails", "subscribedCapitalDetails"} {
out[k] = ensureSlice(out[k])
}
if out["registeredCapital"] == nil {
out["registeredCapital"] = float64(0)
}
if _, ok := out["hasEquityPledges"].(bool); !ok {
out["hasEquityPledges"] = false
}
return out
}
func mergeControllerDefaults(v interface{}) map[string]interface{} {
if m, ok := v.(map[string]interface{}); ok && m != nil {
if m["path"] == nil {
m["path"] = map[string]interface{}{
"nodes": []interface{}{},
"links": []interface{}{},
}
}
if p, ok := m["path"].(map[string]interface{}); ok {
if _, ok := p["nodes"]; !ok {
p["nodes"] = []interface{}{}
}
if _, ok := p["links"]; !ok {
p["links"] = []interface{}{}
}
}
ensureStrKeys(m, []string{"id", "name", "type", "reason", "source"})
if m["percent"] == nil {
m["percent"] = float64(0)
} else if _, ok := m["percent"].(float64); !ok {
m["percent"] = num(m["percent"])
}
return m
}
return map[string]interface{}{
"id": "",
"name": "",
"type": "",
"percent": float64(0),
"path": map[string]interface{}{
"nodes": []interface{}{},
"links": []interface{}{},
},
"reason": "",
"source": "",
}
}
func mergeInvestmentsDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
if _, ok := out["totalCount"]; !ok {
out["totalCount"] = 0
}
if _, ok := out["totalAmount"]; !ok {
out["totalAmount"] = float64(0)
}
if out["totalAmount"] == nil {
out["totalAmount"] = float64(0)
}
out["list"] = ensureSlice(out["list"])
out["legalRepresentativeInvestments"] = ensureSlice(out["legalRepresentativeInvestments"])
return out
}
func mergeManagementDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
if _, ok := out["executives"]; !ok {
out["executives"] = []interface{}{}
} else {
out["executives"] = ensureSlice(out["executives"])
}
if _, ok := out["legalRepresentativeOtherPositions"]; !ok {
out["legalRepresentativeOtherPositions"] = []interface{}{}
} else {
out["legalRepresentativeOtherPositions"] = ensureSlice(out["legalRepresentativeOtherPositions"])
}
if _, ok := out["employeeCount"]; !ok || out["employeeCount"] == nil {
out["employeeCount"] = float64(0)
}
if _, ok := out["femaleEmployeeCount"]; !ok || out["femaleEmployeeCount"] == nil {
out["femaleEmployeeCount"] = float64(0)
}
if out["socialSecurity"] == nil {
out["socialSecurity"] = map[string]interface{}{}
}
return out
}
func mergeAssetsDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
if _, ok := out["years"]; !ok {
out["years"] = []interface{}{}
} else {
out["years"] = ensureSlice(out["years"])
}
return out
}
func mergeLicensesDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
for _, k := range []string{"permits", "permitChanges", "ipPledges", "otherLicenses"} {
if _, ok := out[k]; !ok {
out[k] = []interface{}{}
} else {
out[k] = ensureSlice(out[k])
}
}
return out
}
func mergeActivitiesDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
if _, ok := out["bids"]; !ok {
out["bids"] = []interface{}{}
} else {
out["bids"] = ensureSlice(out["bids"])
}
if _, ok := out["websites"]; !ok {
out["websites"] = []interface{}{}
} else {
out["websites"] = ensureSlice(out["websites"])
}
return out
}
func litigationTypeKeys() []string {
return []string{
"administrative", "implement", "preservation", "civil", "criminal",
"bankrupt", "jurisdict", "compensate",
}
}
func defaultLitigationShell() map[string]interface{} {
out := map[string]interface{}{"totalCases": 0}
for _, k := range litigationTypeKeys() {
out[k] = map[string]interface{}{
"count": 0,
"cases": []interface{}{},
}
}
return out
}
func mergeLitigationShape(v interface{}) map[string]interface{} {
out := defaultLitigationShell()
if v == nil {
return out
}
m, ok := v.(map[string]interface{})
if !ok {
return out
}
known := map[string]struct{}{}
for _, k := range litigationTypeKeys() {
known[k] = struct{}{}
}
for k, val := range m {
if k == "totalCases" {
out["totalCases"] = intFromAny(val)
continue
}
if _, isCat := known[k]; isCat {
sm, ok := val.(map[string]interface{})
if !ok {
continue
}
out[k] = map[string]interface{}{
"count": intFromAny(sm["count"]),
"cases": ensureSlice(sm["cases"]),
}
continue
}
out[k] = val
}
return out
}
func defaultQuickCancelShell() map[string]interface{} {
return map[string]interface{}{
"entName": "",
"creditCode": "",
"regNo": "",
"regOrg": "",
"noticeFromDate": "",
"noticeToDate": "",
"cancelResult": "",
"dissents": []interface{}{},
}
}
func defaultLiquidationShell() map[string]interface{} {
return map[string]interface{}{
"principal": "",
"members": []interface{}{},
}
}
func mergeRisksDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
boolKeys := []string{
"hasCourtJudgments", "hasJudicialAssists", "hasDishonestDebtors", "hasLimitHighDebtors",
"hasAdminPenalty", "hasException", "hasSeriousIllegal", "hasTaxOwing", "hasSeriousTaxIllegal",
"hasMortgage", "hasEquityPledges", "hasQuickCancel",
}
for _, k := range boolKeys {
if _, ok := out[k]; !ok {
out[k] = false
}
}
if _, ok := out["riskLevel"]; !ok {
out["riskLevel"] = "低"
}
if _, ok := out["riskScore"]; !ok {
out["riskScore"] = 80
}
for _, k := range []string{"dishonestDebtorCount", "limitHighDebtorCount"} {
if _, ok := out[k]; !ok {
out[k] = 0
}
}
for _, k := range []string{
"courtJudgments", "judicialAssists", "dishonestDebtors", "limitHighDebtors",
"adminPenalties", "adminPenaltyUpdates", "exceptions", "seriousIllegals", "mortgages",
} {
if _, ok := out[k]; !ok {
out[k] = []interface{}{}
} else {
out[k] = ensureSlice(out[k])
}
}
out["litigation"] = mergeLitigationShape(out["litigation"])
if out["quickCancel"] == nil {
out["quickCancel"] = defaultQuickCancelShell()
} else if qm, ok := out["quickCancel"].(map[string]interface{}); ok {
dc := defaultQuickCancelShell()
for k, def := range dc {
if _, ok := qm[k]; !ok {
qm[k] = def
}
}
if qm["dissents"] == nil {
qm["dissents"] = []interface{}{}
} else {
qm["dissents"] = ensureSlice(qm["dissents"])
}
out["quickCancel"] = qm
}
if out["liquidation"] == nil {
out["liquidation"] = defaultLiquidationShell()
} else if lm, ok := out["liquidation"].(map[string]interface{}); ok {
dc := defaultLiquidationShell()
for k, def := range dc {
if _, ok := lm[k]; !ok {
lm[k] = def
}
}
if lm["members"] == nil {
lm["members"] = []interface{}{}
} else {
lm["members"] = ensureSlice(lm["members"])
}
out["liquidation"] = lm
}
tr, _ := out["taxRecords"].(map[string]interface{})
if tr == nil {
tr = map[string]interface{}{}
}
for _, k := range []string{"taxLevelAYears", "seriousTaxIllegal", "taxOwings"} {
if _, ok := tr[k]; !ok {
tr[k] = []interface{}{}
} else {
tr[k] = ensureSlice(tr[k])
}
}
out["taxRecords"] = tr
return out
}
// normalizeListedStock 无股票结构时用 JSON null避免前端把 {} 当成有值而 JSON.stringify 出 "{}"。
func normalizeListedStock(v interface{}) interface{} {
if v == nil {
return nil
}
m, ok := v.(map[string]interface{})
if !ok {
return v
}
if len(m) == 0 {
return nil
}
return v
}
func mergeListedDefaults(v interface{}) map[string]interface{} {
if m, ok := v.(map[string]interface{}); ok && m != nil {
if _, ok := m["isListed"].(bool); !ok {
m["isListed"] = false
}
co, _ := m["company"].(map[string]interface{})
if co == nil {
co = map[string]interface{}{}
}
for k, def := range map[string]interface{}{
"bizScope": "", "creditCode": "", "regAddr": "", "regCapital": "",
"orgCode": "", "cur": "", "curName": "",
} {
if _, ok := co[k]; !ok {
co[k] = def
}
}
m["company"] = co
m["stock"] = normalizeListedStock(m["stock"])
if _, ok := m["topShareholders"]; !ok {
m["topShareholders"] = []interface{}{}
} else {
m["topShareholders"] = ensureSlice(m["topShareholders"])
}
if _, ok := m["listedManagers"]; !ok {
m["listedManagers"] = []interface{}{}
} else {
m["listedManagers"] = ensureSlice(m["listedManagers"])
}
return m
}
return map[string]interface{}{
"isListed": false,
"company": map[string]interface{}{
"bizScope": "", "creditCode": "", "regAddr": "", "regCapital": "",
"orgCode": "", "cur": "", "curName": "",
},
"stock": nil,
"topShareholders": []interface{}{},
"listedManagers": []interface{}{},
}
}
func mergeTaxViolationsDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
if _, ok := out["total"]; !ok {
out["total"] = 0
}
if _, ok := out["items"]; !ok {
out["items"] = []interface{}{}
} else {
out["items"] = ensureSlice(out["items"])
}
return out
}
func mergeOwnTaxNoticesDefaults(v interface{}) map[string]interface{} {
return mergeTaxViolationsDefaults(v)
}
func mergeRiskOverviewDefaults(v interface{}) map[string]interface{} {
out, _ := v.(map[string]interface{})
if out == nil {
out = map[string]interface{}{}
}
if _, ok := out["riskLevel"]; !ok {
out["riskLevel"] = "低"
}
if _, ok := out["riskScore"]; !ok {
out["riskScore"] = 100
}
if _, ok := out["tags"]; !ok {
out["tags"] = []interface{}{}
} else {
out["tags"] = ensureSlice(out["tags"])
}
if _, ok := out["items"]; !ok {
out["items"] = []interface{}{}
} else {
out["items"] = ensureSlice(out["items"])
}
return out
}
func ensureStrKeys(m map[string]interface{}, keys []string) {
if m == nil {
return
}
for _, k := range keys {
if _, ok := m[k]; !ok {
m[k] = ""
} else if m[k] == nil {
m[k] = ""
}
}
}
// qyglJ1U9ReportHasSubstantiveData 判断合并后的报告是否至少含一项可展示的企业要素。
// 当所有子数据源均失败或等价于无数据时返回 false用于 QYGLJ1U9 整体返回「查询为空」。
func qyglJ1U9ReportHasSubstantiveData(report map[string]interface{}) bool {
if report == nil {
return false
}
trim := func(v interface{}) string { return strings.TrimSpace(str(v)) }
basic, _ := report["basic"].(map[string]interface{})
if basic != nil {
if trim(basic["entName"]) != "" || trim(basic["creditCode"]) != "" {
return true
}
}
if trim(report["entName"]) != "" || trim(report["creditCode"]) != "" {
return true
}
if ar, ok := report["annualReports"].([]interface{}); ok && len(ar) > 0 {
return true
}
if tv, ok := report["taxViolations"].(map[string]interface{}); ok {
if intFromAny(tv["total"]) > 0 {
return true
}
if items, ok := tv["items"].([]interface{}); ok && len(items) > 0 {
return true
}
}
if ot, ok := report["ownTaxNotices"].(map[string]interface{}); ok {
if intFromAny(ot["total"]) > 0 {
return true
}
if items, ok := ot["items"].([]interface{}); ok && len(items) > 0 {
return true
}
}
if br, ok := report["branches"].([]interface{}); ok && len(br) > 0 {
return true
}
if bl, ok := report["basicList"].([]interface{}); ok && len(bl) > 0 {
return true
}
if sh, ok := report["shareholding"].(map[string]interface{}); ok {
if arr, ok := sh["shareholders"].([]interface{}); ok && len(arr) > 0 {
return true
}
if intFromAny(sh["shareholderCount"]) > 0 {
return true
}
}
if inv, ok := report["investments"].(map[string]interface{}); ok {
if arr, ok := inv["list"].([]interface{}); ok && len(arr) > 0 {
return true
}
if intFromAny(inv["totalCount"]) > 0 {
return true
}
}
if ben, ok := report["beneficiaries"].([]interface{}); ok && len(ben) > 0 {
return true
}
if tl, ok := report["timeline"].([]interface{}); ok && len(tl) > 0 {
return true
}
if ctl, _ := report["controller"].(map[string]interface{}); ctl != nil && trim(ctl["name"]) != "" {
return true
}
if risks, ok := report["risks"].(map[string]interface{}); ok {
for _, key := range []string{
"dishonestDebtors", "limitHighDebtors", "adminPenalties", "exceptions",
"seriousIllegals", "mortgages", "courtJudgments", "judicialAssists",
} {
if arr, ok := risks[key].([]interface{}); ok && len(arr) > 0 {
return true
}
}
if lit, ok := risks["litigation"].(map[string]interface{}); ok {
for _, v := range lit {
sub, ok := v.(map[string]interface{})
if !ok {
continue
}
if arr, ok := sub["cases"].([]interface{}); ok && len(arr) > 0 {
return true
}
}
}
}
return false
}
// jiguangWithoutYearReportTables 浅拷贝全量 map并去掉企业全量 V2 中与「公示年报」对应的 YEARREPORT* 键。
// 在已接入 QYGLDJ12 且年报列表非空时使用,避免 build 与 HTML 中与「十六、企业年报」重复展示。
func jiguangWithoutYearReportTables(jiguang map[string]interface{}) map[string]interface{} {

View File

@@ -0,0 +1,203 @@
# QYGLJ1U9 企业全景报告字段说明
## 一、返回对象总览
| 字段 | 类型 | 说明 |
| --------------- | ------------- | -------------------------------------------------- |
| `reportId` | string | 报告编号,可用于后续按编号访问报告页面或下载 PDF。 |
| `reportUrl` | string | 报告访问链接。 |
| `reportTime` | string | 报告生成时间,格式示例:`2026-03-21 19:30:45`。 |
| `entName` | string | 企业名称。 |
| `creditCode` | string | 统一社会信用代码。 |
| `basic` | object | 企业主体基础信息。 |
| `branches` | array | 分支机构列表。 |
| `shareholding` | object | 股权结构与股东信息。 |
| `controller` | object / null | 实际控制人信息。 |
| `beneficiaries` | array | 最终受益人列表。 |
| `investments` | object | 对外投资信息。 |
| `guarantees` | array | 对外担保信息。 |
| `management` | object | 高管、人员和社保相关信息。 |
| `assets` | object | 资产经营类年度信息。 |
| `licenses` | object | 行政许可、许可变更、知识产权出质等。 |
| `activities` | object | 招投标、网站网店等经营活动信息。 |
| `inspections` | array | 抽查检查信息。 |
| `risks` | object | 风险与合规信息。 |
| `timeline` | array | 工商变更时间线。 |
| `listed` | object / null | 上市相关信息。 |
| `riskOverview` | object | 风险总览(等级、分值、标签)。 |
| `annualReports` | array | 企业年报列表。 |
| `taxViolations` | object | 税收违法信息,结构为 `{ total, items }`。 |
| `ownTaxNotices` | object | 欠税公告信息,结构为 `{ total, items }`。 |
---
## 二、核心字段说明
### 1) `basic` 企业主体基础信息
常见字段如下:
| 字段 | 说明 |
| ------------------------------------------- | ---------------- |
| `entName` | 企业名称 |
| `creditCode` | 统一社会信用代码 |
| `regNo` | 注册号 |
| `orgCode` | 组织机构代码 |
| `entType` | 企业类型 |
| `establishDate` | 成立日期 |
| `registeredCapital` | 注册资本 |
| `regCapCurrency` | 注册资本币种 |
| `legalRepresentative` | 法定代表人 |
| `status` | 经营状态 |
| `operationPeriodFrom` / `operationPeriodTo` | 营业期限起止 |
| `regOrg` | 登记机关 |
| `address` | 企业地址 |
| `businessScope` | 经营范围 |
| `oldNames` | 曾用名列表 |
### 2) `shareholding` 股权结构
| 字段 | 说明 |
| -------------------------- | ---------------------- |
| `shareholders` | 股东列表 |
| `shareholderCount` | 股东人数 |
| `topHolderName` | 第一大股东名称 |
| `topHolderPercent` | 第一大股东持股比例 |
| `top5TotalPercent` | 前五大股东持股比例合计 |
| `equityChanges` | 股权变更记录 |
| `equityPledges` | 股权出质记录 |
| `paidInDetails` | 实缴出资明细 |
| `subscribedCapitalDetails` | 认缴出资明细 |
`shareholders` 常见子字段:
`name``type``ownershipPercent``subscribedAmount``paidAmount``subscribedDate``paidDate`
### 3) `controller` 实际控制人
常见字段:`id``name``type``percent``path``reason`
### 4) `beneficiaries` 最终受益人
每条常见字段:`id``name``type``percent``path``reason`
### 5) `investments` 对外投资
| 字段 | 说明 |
| -------------------------------- | ------------------------ |
| `totalCount` | 对外投资企业数量 |
| `totalAmount` | 对外投资金额汇总(如有) |
| `list` | 对外投资企业列表 |
| `legalRepresentativeInvestments` | 法定代表人对外投资列表 |
`list` 常见子字段:`entName``creditCode``entStatus``regCap``investAmount``investPercent`
### 6) `management` 管理层与人员信息
| 字段 | 说明 |
| ----------------------------------- | ---------------------- |
| `executives` | 高管列表(姓名、职务) |
| `legalRepresentativeOtherPositions` | 法人对外任职信息 |
| `employeeCount` | 员工人数 |
| `femaleEmployeeCount` | 女性员工人数 |
| `socialSecurity` | 社保相关字段集合 |
### 7) `assets` 资产经营信息
`assets.years` 为按年度的经营数据,常见字段:
`year``assetTotal``revenueTotal``mainBusinessRevenue``taxTotal``equityTotal``profitTotal``netProfit``liabilityTotal`
### 8) `licenses` 许可与资质信息
| 字段 | 说明 |
| --------------- | ---------------- |
| `permits` | 行政许可列表 |
| `permitChanges` | 行政许可变更列表 |
| `ipPledges` | 知识产权出质列表 |
| `otherLicenses` | 其他许可信息 |
### 9) `activities` 经营活动信息
| 字段 | 说明 |
| ---------- | -------------- |
| `bids` | 招投标信息 |
| `websites` | 网站或网店信息 |
### 10) `inspections` 抽查检查
每条常见字段:`dataType``regOrg``inspectDate``result`
---
## 三、风险相关字段
### 1) `riskOverview` 风险总览(建议用于首页展示)
| 字段 | 类型 | 说明 |
| ----------- | ------ | ---------------------------------------------------- |
| `riskLevel` | string | 风险等级:`低` / `中` / `高`。 |
| `riskScore` | number | 风险分值0-100。 |
| `tags` | array | 风险标签列表。 |
| `items` | array | 各类风险项命中情况,元素结构通常为 `{ name, hit }`。 |
### 2) `risks` 风险详情
常见布尔字段:
`hasCourtJudgments``hasJudicialAssists``hasDishonestDebtors``hasLimitHighDebtors``hasAdminPenalty``hasException``hasSeriousIllegal``hasTaxOwing``hasSeriousTaxIllegal``hasMortgage``hasEquityPledges``hasQuickCancel`
常见明细字段:
`dishonestDebtors``limitHighDebtors``litigation``adminPenalties``adminPenaltyUpdates``exceptions``seriousIllegals``mortgages``taxRecords``courtJudgments``judicialAssists``quickCancel``liquidation`
---
## 四、年报与税务字段
### 1) `annualReports` 企业年报列表
每个元素代表一个年度年报,字段较多,常见包括:
- 基础信息(如年度、企业基本经营情况)
- 股东与出资信息
- 对外投资信息
- 网站网店信息
- 社保信息
- 对外担保信息
- 股权变更信息
- 年报变更信息
### 2) `taxViolations` 税收违法信息
结构示例:
```json
{
"total": 2,
"items": [
{
"entityName": "示例企业",
"taxpayerCode": "xxxx",
"illegalFact": "......",
"publishDepartment": "......",
"illegalTime": "2025-06-12"
}
]
}
```
### 3) `ownTaxNotices` 欠税公告信息
结构示例:
```json
{
"total": 1,
"items": [
{
"taxpayerName": "示例企业",
"taxIdNumber": "xxxx",
"taxCategory": "增值税",
"ownTaxBalance": "100000",
"publishDate": "2025-12-01"
}
]
}
```