1843 lines
54 KiB
Go
1843 lines
54 KiB
Go
package pdf
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"fmt"
|
||
"sort"
|
||
"strings"
|
||
|
||
"github.com/jung-kurt/gofpdf/v2"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// GenerateQYGLReportPDF 使用 gofpdf 根据 QYGLJ1U9 聚合结果生成企业全景报告 PDF,
|
||
// 尽量复刻 qiye.html 中的板块顺序和展示逻辑。
|
||
// report 参数通常是从 JSON 反序列化得到的 map[string]interface{}。
|
||
func GenerateQYGLReportPDF(_ context.Context, logger *zap.Logger, report map[string]interface{}) ([]byte, error) {
|
||
if logger == nil {
|
||
logger = zap.NewNop()
|
||
}
|
||
|
||
pdf := gofpdf.New("P", "mm", "A4", "")
|
||
// 整体页边距和自动分页底部预留稍微加大,整体更「松」一点
|
||
pdf.SetMargins(15, 25, 15)
|
||
pdf.SetAutoPageBreak(true, 22)
|
||
|
||
// 加载中文字体
|
||
fontManager := NewFontManager(logger)
|
||
chineseFontLoaded := fontManager.LoadChineseFont(pdf)
|
||
fontName := "ChineseFont"
|
||
if !chineseFontLoaded {
|
||
// 回退:使用内置核心字体(英文),中文可能会显示为方块
|
||
fontName = "Arial"
|
||
}
|
||
// 整体默认正文字体稍微放大
|
||
pdf.SetFont(fontName, "", 14)
|
||
|
||
// 头部信息,对齐 qiye.html
|
||
entName := getString(report, "entName")
|
||
if entName == "" {
|
||
entName = "未知企业"
|
||
}
|
||
creditCode := getString(report, "creditCode")
|
||
if creditCode == "" {
|
||
creditCode = getStringFromMap(report, "basic", "creditCode")
|
||
}
|
||
basic := getMap(report, "basic")
|
||
entStatus := getString(basic, "status")
|
||
if entStatus == "" {
|
||
entStatus = getString(basic, "entStatus")
|
||
}
|
||
entType := getString(basic, "entType")
|
||
reportTime := getString(report, "reportTime")
|
||
|
||
riskOverview := getMap(report, "riskOverview")
|
||
riskScore := getString(riskOverview, "riskScore")
|
||
riskLevel := getString(riskOverview, "riskLevel")
|
||
|
||
// 首页头部
|
||
pdf.AddPage()
|
||
// 预留更多顶部空白,让标题整体再下移一些
|
||
pdf.Ln(20)
|
||
// 顶部大标题:居中、加粗、蓝色,更大字号
|
||
pdf.SetFont(fontName, "B", 34)
|
||
pdf.SetTextColor(37, 99, 235)
|
||
pdf.CellFormat(0, 18, "企业全景报告", "", 1, "C", false, 0, "")
|
||
pdf.Ln(10)
|
||
// 恢复正文颜色
|
||
pdf.SetTextColor(0, 0, 0)
|
||
|
||
pdf.SetFont(fontName, "", 18)
|
||
pdf.MultiCell(0, 9, fmt.Sprintf("企业名称:%s", entName), "", "L", false)
|
||
|
||
pdf.SetFont(fontName, "", 14)
|
||
pdf.MultiCell(0, 7, fmt.Sprintf("统一社会信用代码:%s", safePlaceholder(creditCode)), "", "L", false)
|
||
pdf.MultiCell(0, 7, fmt.Sprintf("经营状态:%s", safePlaceholder(entStatus)), "", "L", false)
|
||
pdf.MultiCell(0, 7, fmt.Sprintf("企业类型:%s", safePlaceholder(entType)), "", "L", false)
|
||
if reportTime != "" {
|
||
pdf.MultiCell(0, 7, fmt.Sprintf("报告生成时间:%s", reportTime), "", "L", false)
|
||
}
|
||
|
||
// 综合风险评分(使用 riskOverview)
|
||
pdf.Ln(6)
|
||
pdfSubTitle(pdf, fontName, "综合风险评分")
|
||
pdf.SetFont(fontName, "", 13)
|
||
if riskScore != "" {
|
||
pdf.MultiCell(0, 7, fmt.Sprintf("风险得分:%s", riskScore), "", "L", false)
|
||
}
|
||
if riskLevel != "" {
|
||
pdf.MultiCell(0, 7, fmt.Sprintf("风险等级:%s", riskLevel), "", "L", false)
|
||
}
|
||
// 头部风险标签
|
||
if tags, ok := riskOverview["tags"].([]interface{}); ok && len(tags) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "", 11)
|
||
pdf.MultiCell(0, 5, "风险标签:", "", "L", false)
|
||
for _, t := range tags {
|
||
pdf.MultiCell(0, 5, fmt.Sprintf("· %v", t), "", "L", false)
|
||
}
|
||
}
|
||
|
||
// 对齐 qiye.html 的板块顺序
|
||
sections := []struct {
|
||
key string
|
||
title string
|
||
}{
|
||
{"riskOverview", "风险情况(综合分析)"},
|
||
{"basic", "一、主体概览(企业基础信息)"},
|
||
{"branches", "二、分支机构"},
|
||
{"shareholding", "三、股权与控制(持股结构;认缴与实缴公示见第十六节)"},
|
||
{"controller", "四、实际控制人"},
|
||
{"beneficiaries", "五、最终受益人"},
|
||
{"investments", "六、对外投资"},
|
||
{"guarantees", "七、对外担保(全量年报披露摘要;公示年报详版见第十六节)"},
|
||
{"management", "八、人员与组织(高管与任职;年报从业与社保见第十六节)"},
|
||
{"assets", "九、资产与经营(全量年报财务摘要;公示年报详版见第十六节)"},
|
||
{"licenses", "十、行政许可与资质"},
|
||
{"activities", "十一、经营活动(招投标;网站或网店公示见第十六节)"},
|
||
{"inspections", "十二、抽查检查"},
|
||
{"risks", "十三、风险与合规"},
|
||
{"timeline", "十四、发展时间线"},
|
||
{"listed", "十五、上市信息"},
|
||
}
|
||
|
||
for _, s := range sections {
|
||
switch s.key {
|
||
case "riskOverview":
|
||
renderPDFRiskOverview(pdf, fontName, s.title, riskOverview)
|
||
case "basic":
|
||
renderPDFBasic(pdf, fontName, s.title, basic, entName, creditCode)
|
||
case "branches":
|
||
renderPDFBranches(pdf, fontName, s.title, getSlice(report, "branches"))
|
||
case "shareholding":
|
||
renderPDFShareholding(pdf, fontName, s.title, getMap(report, "shareholding"))
|
||
case "controller":
|
||
renderPDFController(pdf, fontName, s.title, getMap(report, "controller"))
|
||
case "beneficiaries":
|
||
renderPDFBeneficiaries(pdf, fontName, s.title, getSlice(report, "beneficiaries"))
|
||
case "investments":
|
||
renderPDFInvestments(pdf, fontName, s.title, getMap(report, "investments"))
|
||
case "guarantees":
|
||
renderPDFGuarantees(pdf, fontName, s.title, getSlice(report, "guarantees"))
|
||
case "management":
|
||
renderPDFManagement(pdf, fontName, s.title, getMap(report, "management"))
|
||
case "assets":
|
||
renderPDFAssets(pdf, fontName, s.title, getMap(report, "assets"))
|
||
case "licenses":
|
||
renderPDFLicenses(pdf, fontName, s.title, getMap(report, "licenses"))
|
||
case "activities":
|
||
renderPDFActivities(pdf, fontName, s.title, getMap(report, "activities"))
|
||
case "inspections":
|
||
renderPDFInspections(pdf, fontName, s.title, getSlice(report, "inspections"))
|
||
case "risks":
|
||
renderPDFRisks(pdf, fontName, s.title, getMap(report, "risks"))
|
||
case "timeline":
|
||
renderPDFTimeline(pdf, fontName, s.title, getSlice(report, "timeline"))
|
||
case "listed":
|
||
renderPDFListed(pdf, fontName, s.title, getMap(report, "listed"))
|
||
}
|
||
}
|
||
|
||
// 输出为字节
|
||
var buf bytes.Buffer
|
||
if err := pdf.Output(&buf); err != nil {
|
||
return nil, fmt.Errorf("输出企业全景报告 PDF 失败: %w", err)
|
||
}
|
||
return buf.Bytes(), nil
|
||
}
|
||
|
||
// 辅助方法
|
||
|
||
func getString(m map[string]interface{}, key string) string {
|
||
if m == nil {
|
||
return ""
|
||
}
|
||
if v, ok := m[key]; ok && v != nil {
|
||
if s, ok := v.(string); ok {
|
||
return s
|
||
}
|
||
return fmt.Sprint(v)
|
||
}
|
||
return ""
|
||
}
|
||
|
||
func getStringFromMap(root map[string]interface{}, field string, key string) string {
|
||
child := getMap(root, field)
|
||
return getString(child, key)
|
||
}
|
||
|
||
func getMap(m map[string]interface{}, key string) map[string]interface{} {
|
||
if m == nil {
|
||
return map[string]interface{}{}
|
||
}
|
||
if v, ok := m[key]; ok && v != nil {
|
||
if mm, ok := v.(map[string]interface{}); ok {
|
||
return mm
|
||
}
|
||
}
|
||
return map[string]interface{}{}
|
||
}
|
||
|
||
func getSlice(m map[string]interface{}, key string) []interface{} {
|
||
if m == nil {
|
||
return nil
|
||
}
|
||
if v, ok := m[key]; ok && v != nil {
|
||
if arr, ok := v.([]interface{}); ok {
|
||
return arr
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func writeKeyValue(pdf *gofpdf.Fpdf, fontName, label, value string) {
|
||
if value == "" {
|
||
return
|
||
}
|
||
// 计算表格布局:左侧标签列 + 右侧内容列(模块内数据统一用表格框展示)
|
||
pageW, pageH := pdf.GetPageSize()
|
||
lMargin, _, rMargin, bMargin := pdf.GetMargins()
|
||
labelW := 40.0
|
||
valueW := pageW - lMargin - rMargin - labelW
|
||
// 行高整体拉宽一点
|
||
lineH := 10.0
|
||
|
||
// 当前起始坐标(统一从左边距起,栅格化对齐)
|
||
x := lMargin
|
||
y := pdf.GetY()
|
||
|
||
// 预计算内容高度:使用 SplitLines 获取行数,避免长内容导致单元格高度不够
|
||
lines := pdf.SplitLines([]byte(value), valueW)
|
||
rowH := float64(len(lines)) * lineH
|
||
if rowH < lineH {
|
||
rowH = lineH
|
||
}
|
||
// 轻微增加上下留白,避免文字贴边
|
||
rowH += 2
|
||
|
||
// 如剩余空间不足,先换到新页再画整行,避免表格跨页导致内容重叠
|
||
if y+rowH > pageH-bMargin {
|
||
pdf.AddPage()
|
||
y = pdf.GetY()
|
||
pdf.SetXY(lMargin, y)
|
||
}
|
||
|
||
// 画出整行的两个单元格边框
|
||
// 使用黑色描边,左侧标签单元格填充标题蓝色背景
|
||
pdf.SetDrawColor(0, 0, 0)
|
||
pdf.SetFillColor(91, 155, 213)
|
||
pdf.Rect(x, y, labelW, rowH, "FD") // 标签:填充+描边
|
||
pdf.Rect(x+labelW, y, valueW, rowH, "D") // 值:仅描边
|
||
|
||
// 写入标签单元格
|
||
pdf.SetXY(x, y)
|
||
pdf.SetFont(fontName, "B", 13)
|
||
pdf.SetTextColor(255, 255, 255)
|
||
pdf.CellFormat(labelW, rowH, fmt.Sprintf("%s:", label), "", 0, "L", false, 0, "")
|
||
|
||
// 写入值单元格(自动换行)
|
||
pdf.SetXY(x+labelW, y)
|
||
pdf.SetFont(fontName, "", 13)
|
||
pdf.SetTextColor(0, 0, 0)
|
||
pdf.MultiCell(valueW, lineH, value, "", "L", false)
|
||
|
||
// 将光标移动到下一行开头,恢复默认颜色
|
||
pdf.SetDrawColor(0, 0, 0)
|
||
pdf.SetFillColor(255, 255, 255)
|
||
pdf.SetXY(lMargin, y+rowH)
|
||
}
|
||
|
||
func safePlaceholder(s string) string {
|
||
if s == "" {
|
||
return "-"
|
||
}
|
||
return s
|
||
}
|
||
|
||
// -------------------------
|
||
// 各板块渲染(与 qiye.html 对齐)
|
||
// -------------------------
|
||
|
||
// 风险综合分析(只做风险点一览,与 qiye.html 中 renderRiskOverview 对齐的精简版)
|
||
func renderPDFRiskOverview(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
|
||
pdf.SetFont(fontName, "", 11)
|
||
itemsRaw, ok := v["items"].([]interface{})
|
||
if !ok || len(itemsRaw) == 0 {
|
||
pdf.MultiCell(0, 6, "暂无风险分析数据", "", "L", false)
|
||
return
|
||
}
|
||
|
||
for _, it := range itemsRaw {
|
||
m, ok := it.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "name")
|
||
if name == "" {
|
||
continue
|
||
}
|
||
hit := false
|
||
if hv, ok := m["hit"]; ok {
|
||
if b, ok := hv.(bool); ok {
|
||
hit = b
|
||
} else {
|
||
hit = fmt.Sprint(hv) == "true"
|
||
}
|
||
}
|
||
status := "未命中"
|
||
if hit {
|
||
status = "命中"
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("· %s:%s", name, status), "", "L", false)
|
||
}
|
||
}
|
||
|
||
// 主体概览,对照 qiye.html renderBasic 中的字段顺序,做精简单列展示
|
||
func renderPDFBasic(pdf *gofpdf.Fpdf, fontName, title string, basic map[string]interface{}, entName, creditCode string) {
|
||
if len(basic) == 0 && entName == "" && creditCode == "" {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 13)
|
||
|
||
// 基本信息采用条目式行展示,隔行背景色,不使用表格框
|
||
rowIndex := 0
|
||
writeBasicRow := func(label, val string) {
|
||
if val == "" {
|
||
return
|
||
}
|
||
alt := rowIndex%2 == 0
|
||
pdfWriteBasicRow(pdf, fontName, label, val, alt)
|
||
rowIndex++
|
||
}
|
||
|
||
writeBasicRow("企业名称", entName)
|
||
writeBasicRow("统一社会信用代码", safePlaceholder(creditCode))
|
||
|
||
keys := []string{
|
||
"regNo", "orgCode", "entType", "entTypeCode", "entityTypeCode",
|
||
"establishDate", "registeredCapital", "regCap", "regCapCurrency",
|
||
"regCapCurrencyCode", "regOrg", "regOrgCode", "regProvince", "provinceCode",
|
||
"regCity", "regCityCode", "regDistrict", "districtCode", "address",
|
||
"postalCode", "legalRepresentative", "compositionForm", "approvedBusinessItem",
|
||
"status", "statusCode", "operationPeriodFrom", "operationPeriodTo", "approveDate",
|
||
"cancelDate", "revokeDate", "cancelReason", "revokeReason",
|
||
"oldNames", "businessScope", "lastAnnuReportYear",
|
||
}
|
||
|
||
for _, k := range keys {
|
||
val := getString(basic, k)
|
||
if k == "oldNames" && val == "" {
|
||
continue
|
||
}
|
||
if val == "" {
|
||
continue
|
||
}
|
||
writeBasicRow(mapBasicLabel(k), val)
|
||
}
|
||
}
|
||
|
||
func mapBasicLabel(k string) string {
|
||
switch k {
|
||
case "regNo":
|
||
return "注册号"
|
||
case "orgCode":
|
||
return "组织机构代码"
|
||
case "entType":
|
||
return "企业类型"
|
||
case "entTypeCode":
|
||
return "企业类型编码"
|
||
case "entityTypeCode":
|
||
return "实体类型编码"
|
||
case "establishDate":
|
||
return "成立日期"
|
||
case "registeredCapital", "regCap":
|
||
return "注册资本"
|
||
case "regCapCurrency":
|
||
return "注册资本币种"
|
||
case "regCapCurrencyCode":
|
||
return "注册资本币种代码"
|
||
case "regOrg":
|
||
return "登记机关"
|
||
case "regOrgCode":
|
||
return "注册地址行政编号"
|
||
case "regProvince":
|
||
return "所在省份"
|
||
case "provinceCode":
|
||
return "所在省份编码"
|
||
case "regCity":
|
||
return "所在城市"
|
||
case "regCityCode":
|
||
return "所在城市编码"
|
||
case "regDistrict":
|
||
return "所在区/县"
|
||
case "districtCode":
|
||
return "所在区/县编码"
|
||
case "address":
|
||
return "住址"
|
||
case "postalCode":
|
||
return "邮编"
|
||
case "legalRepresentative":
|
||
return "法定代表人"
|
||
case "compositionForm":
|
||
return "组成形式"
|
||
case "approvedBusinessItem":
|
||
return "许可经营项目"
|
||
case "status":
|
||
return "经营状态"
|
||
case "statusCode":
|
||
return "经营状态编码"
|
||
case "operationPeriodFrom":
|
||
return "经营期限自"
|
||
case "operationPeriodTo":
|
||
return "经营期限至"
|
||
case "approveDate":
|
||
return "核准日期"
|
||
case "cancelDate":
|
||
return "注销日期"
|
||
case "revokeDate":
|
||
return "吊销日期"
|
||
case "cancelReason":
|
||
return "注销原因"
|
||
case "revokeReason":
|
||
return "吊销原因"
|
||
case "oldNames":
|
||
return "曾用名"
|
||
case "businessScope":
|
||
return "经营业务范围"
|
||
case "lastAnnuReportYear":
|
||
return "最后年检年度"
|
||
default:
|
||
return k
|
||
}
|
||
}
|
||
|
||
func renderPDFBranches(pdf *gofpdf.Fpdf, fontName, title string, branches []interface{}) {
|
||
if len(branches) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
for i, b := range branches {
|
||
m, ok := b.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "name")
|
||
if name == "" {
|
||
name = getString(m, "entName")
|
||
}
|
||
if name == "" {
|
||
continue
|
||
}
|
||
regNo := getString(m, "regNo")
|
||
credit := getString(m, "creditCode")
|
||
regOrg := getString(m, "regOrg")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, name), "", "L", false)
|
||
meta := fmt.Sprintf(" 注册号:%s;信用代码:%s;登记机关:%s",
|
||
safePlaceholder(regNo),
|
||
safePlaceholder(credit),
|
||
safePlaceholder(regOrg),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
func renderPDFShareholding(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
if len(v) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
// 汇总(对齐前端 renderShareholding 的 summary 部分)
|
||
shareholderCount := getString(v, "shareholderCount")
|
||
registeredCapital := getString(v, "registeredCapital")
|
||
currency := getString(v, "currency")
|
||
topHolderName := getString(v, "topHolderName")
|
||
topHolderPercent := getString(v, "topHolderPercent")
|
||
top5TotalPercent := getString(v, "top5TotalPercent")
|
||
hasEquityPledges := boolToCN(getString(v, "hasEquityPledges"))
|
||
|
||
if shareholderCount != "" || registeredCapital != "" || currency != "" ||
|
||
topHolderName != "" || topHolderPercent != "" || top5TotalPercent != "" || hasEquityPledges != "" {
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "股权汇总", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
if shareholderCount != "" {
|
||
writeKeyValue(pdf, fontName, "股东总数", shareholderCount)
|
||
}
|
||
if registeredCapital != "" {
|
||
writeKeyValue(pdf, fontName, "注册资本", registeredCapital+" 元")
|
||
}
|
||
if currency != "" {
|
||
writeKeyValue(pdf, fontName, "币种", currency)
|
||
}
|
||
if topHolderName != "" {
|
||
writeKeyValue(pdf, fontName, "第一大股东", topHolderName)
|
||
}
|
||
if topHolderPercent != "" {
|
||
writeKeyValue(pdf, fontName, "第一大股东持股", topHolderPercent)
|
||
}
|
||
if top5TotalPercent != "" {
|
||
writeKeyValue(pdf, fontName, "前五大合计", top5TotalPercent)
|
||
}
|
||
if hasEquityPledges != "" {
|
||
writeKeyValue(pdf, fontName, "存在股权出质", hasEquityPledges)
|
||
}
|
||
}
|
||
|
||
// 股东明细(股东全量字段的精简版)
|
||
if shRaw, ok := v["shareholders"].([]interface{}); ok && len(shRaw) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "股东明细", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
for i, sh := range shRaw {
|
||
m, ok := sh.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "name")
|
||
if name == "" {
|
||
continue
|
||
}
|
||
pct := getString(m, "ownershipPercent")
|
||
if pct == "" {
|
||
pct = getString(m, "sharePercent")
|
||
}
|
||
titleLine := fmt.Sprintf("%d. %s", i+1, name)
|
||
if pct != "" {
|
||
titleLine = fmt.Sprintf("%s(持股:%s)", titleLine, pct)
|
||
}
|
||
pdf.MultiCell(0, 6, titleLine, "", "L", false)
|
||
// 认缴 / 实缴等关键信息
|
||
subscribedAmount := getString(m, "subscribedAmount")
|
||
subscribedCurrency := getString(m, "subscribedCurrency")
|
||
subscribedCurrencyCode := getString(m, "subscribedCurrencyCode")
|
||
subscribedDate := getString(m, "subscribedDate")
|
||
subscribedMethod := getString(m, "subscribedMethod")
|
||
subscribedMethodCode := getString(m, "subscribedMethodCode")
|
||
paidAmount := getString(m, "paidAmount")
|
||
paidDate := getString(m, "paidDate")
|
||
paidMethod := getString(m, "paidMethod")
|
||
creditCode := getString(m, "creditCode")
|
||
regNo := getString(m, "regNo")
|
||
isHistory := boolToCN(getString(m, "isHistory"))
|
||
|
||
metaParts := []string{}
|
||
if subscribedAmount != "" {
|
||
sub := "认缴:" + subscribedAmount
|
||
if subscribedCurrency != "" || subscribedCurrencyCode != "" {
|
||
sub += " " + subscribedCurrency
|
||
if subscribedCurrencyCode != "" {
|
||
sub += "(" + subscribedCurrencyCode + ")"
|
||
}
|
||
}
|
||
metaParts = append(metaParts, sub)
|
||
}
|
||
if subscribedDate != "" {
|
||
metaParts = append(metaParts, "认缴日:"+subscribedDate)
|
||
}
|
||
if subscribedMethod != "" || subscribedMethodCode != "" {
|
||
subm := "认缴方式:" + subscribedMethod
|
||
if subscribedMethodCode != "" {
|
||
subm += "(" + subscribedMethodCode + ")"
|
||
}
|
||
metaParts = append(metaParts, subm)
|
||
}
|
||
if paidAmount != "" {
|
||
metaParts = append(metaParts, "实缴:"+paidAmount)
|
||
}
|
||
if paidDate != "" {
|
||
metaParts = append(metaParts, "实缴日:"+paidDate)
|
||
}
|
||
if paidMethod != "" {
|
||
metaParts = append(metaParts, "实缴方式:"+paidMethod)
|
||
}
|
||
if creditCode != "" {
|
||
metaParts = append(metaParts, "股东信用代码:"+creditCode)
|
||
}
|
||
if regNo != "" {
|
||
metaParts = append(metaParts, "股东注册号:"+regNo)
|
||
}
|
||
if isHistory != "" {
|
||
metaParts = append(metaParts, "是否历史:"+isHistory)
|
||
}
|
||
if len(metaParts) > 0 {
|
||
pdf.MultiCell(0, 5, " "+joinWithChineseSemicolon(metaParts), "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 股权变更记录
|
||
if changes, ok := v["equityChanges"].([]interface{}); ok && len(changes) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "股权变更记录", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, e := range changes {
|
||
m, ok := e.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
changeDate := getString(m, "changeDate")
|
||
shareholderName := getString(m, "shareholderName")
|
||
titleLine := fmt.Sprintf("%d. %s %s", i+1, safePlaceholder(changeDate), shareholderName)
|
||
pdf.MultiCell(0, 6, titleLine, "", "L", false)
|
||
before := getString(m, "percentBefore")
|
||
after := getString(m, "percentAfter")
|
||
if before != "" || after != "" {
|
||
pdf.MultiCell(0, 5, fmt.Sprintf(" 变更前:%s → 变更后:%s", safePlaceholder(before), safePlaceholder(after)), "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 股权出质
|
||
if pledges, ok := v["equityPledges"].([]interface{}); ok && len(pledges) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "股权出质", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, e := range pledges {
|
||
m, ok := e.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
regNo := getString(m, "regNo")
|
||
pledgor := getString(m, "pledgor")
|
||
pledgee := getString(m, "pledgee")
|
||
titleLine := fmt.Sprintf("%d. %s %s → %s", i+1, safePlaceholder(regNo), safePlaceholder(pledgor), safePlaceholder(pledgee))
|
||
pdf.MultiCell(0, 6, titleLine, "", "L", false)
|
||
amount := getString(m, "pledgedAmount")
|
||
regDate := getString(m, "regDate")
|
||
status := getString(m, "status")
|
||
meta := fmt.Sprintf(" 出质数额:%s 元;登记日:%s;状态:%s",
|
||
safePlaceholder(amount),
|
||
safePlaceholder(regDate),
|
||
safePlaceholder(status),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 实缴出资明细
|
||
if paidDetails, ok := v["paidInDetails"].([]interface{}); ok && len(paidDetails) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "实缴出资明细", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, e := range paidDetails {
|
||
m, ok := e.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
investor := getString(m, "investor")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(investor)), "", "L", false)
|
||
paidDate := getString(m, "paidDate")
|
||
paidMethod := getString(m, "paidMethod")
|
||
accumulatedPaid := getString(m, "accumulatedPaid")
|
||
meta := fmt.Sprintf(" 日期:%s;方式:%s;累计实缴:%s 万元",
|
||
safePlaceholder(paidDate),
|
||
safePlaceholder(paidMethod),
|
||
safePlaceholder(accumulatedPaid),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 认缴出资明细
|
||
if subDetails, ok := v["subscribedCapitalDetails"].([]interface{}); ok && len(subDetails) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "认缴出资明细", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, e := range subDetails {
|
||
m, ok := e.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
investor := getString(m, "investor")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(investor)), "", "L", false)
|
||
subscribedDate := getString(m, "subscribedDate")
|
||
subscribedMethod := getString(m, "subscribedMethod")
|
||
accSubscribed := getString(m, "accumulatedSubscribed")
|
||
meta := fmt.Sprintf(" 认缴日:%s;方式:%s;累计认缴:%s 元",
|
||
safePlaceholder(subscribedDate),
|
||
safePlaceholder(subscribedMethod),
|
||
safePlaceholder(accSubscribed),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
}
|
||
|
||
func renderPDFController(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
if len(v) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
writeKeyValue(pdf, fontName, "标识", getString(v, "id"))
|
||
writeKeyValue(pdf, fontName, "姓名/名称", getString(v, "name"))
|
||
writeKeyValue(pdf, fontName, "类型", getString(v, "type"))
|
||
writeKeyValue(pdf, fontName, "持股比例", getString(v, "percent"))
|
||
writeKeyValue(pdf, fontName, "判定依据", getString(v, "reason"))
|
||
writeKeyValue(pdf, fontName, "来源", getString(v, "source"))
|
||
}
|
||
|
||
func renderPDFBeneficiaries(pdf *gofpdf.Fpdf, fontName, title string, arr []interface{}) {
|
||
if len(arr) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
for i, b := range arr {
|
||
m, ok := b.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "name")
|
||
if name == "" {
|
||
continue
|
||
}
|
||
pct := getString(m, "percent")
|
||
line := fmt.Sprintf("%d. %s", i+1, name)
|
||
if pct != "" {
|
||
line = fmt.Sprintf("%s(持股:%s)", line, pct)
|
||
}
|
||
pdf.MultiCell(0, 6, line, "", "L", false)
|
||
reason := getString(m, "reason")
|
||
if reason != "" {
|
||
pdf.MultiCell(0, 5, fmt.Sprintf(" 原因:%s", reason), "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
func renderPDFInvestments(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
if len(v) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
// 汇总
|
||
totalCount := getString(v, "totalCount")
|
||
totalAmount := getString(v, "totalAmount")
|
||
if totalCount != "" || totalAmount != "" {
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "汇总", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
if totalCount != "" {
|
||
writeKeyValue(pdf, fontName, "对外投资数量", totalCount)
|
||
}
|
||
if totalAmount != "" {
|
||
writeKeyValue(pdf, fontName, "投资总额(万)", totalAmount)
|
||
}
|
||
}
|
||
|
||
// 对外投资列表
|
||
list := []interface{}{}
|
||
if arr, ok := v["list"].([]interface{}); ok {
|
||
list = arr
|
||
} else if arr, ok := v["entities"].([]interface{}); ok {
|
||
list = arr
|
||
}
|
||
if len(list) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "对外投资列表", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
for i, inv := range list {
|
||
m, ok := inv.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "entName")
|
||
if name == "" {
|
||
name = getString(m, "name")
|
||
}
|
||
if name == "" {
|
||
continue
|
||
}
|
||
pct := getString(m, "investPercent")
|
||
titleLine := fmt.Sprintf("%d. %s", i+1, name)
|
||
if pct != "" {
|
||
titleLine = fmt.Sprintf("%s(持股:%s)", titleLine, pct)
|
||
}
|
||
pdf.MultiCell(0, 6, titleLine, "", "L", false)
|
||
}
|
||
}
|
||
}
|
||
|
||
func renderPDFGuarantees(pdf *gofpdf.Fpdf, fontName, title string, arr []interface{}) {
|
||
if len(arr) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
for i, it := range arr {
|
||
m, ok := it.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
mortgagor := getString(m, "mortgagor")
|
||
creditor := getString(m, "creditor")
|
||
if mortgagor == "" && creditor == "" {
|
||
continue
|
||
}
|
||
titleLine := fmt.Sprintf("%d. %s → %s", i+1, safePlaceholder(mortgagor), safePlaceholder(creditor))
|
||
pdf.MultiCell(0, 6, titleLine, "", "L", false)
|
||
amount := getString(m, "principalAmount")
|
||
kind := getString(m, "principalKind")
|
||
guaranteeType := getString(m, "guaranteeType")
|
||
periodFrom := getString(m, "periodFrom")
|
||
periodTo := getString(m, "periodTo")
|
||
meta := fmt.Sprintf(" 主债权数额:%s;种类:%s;保证方式:%s;期限:%s 至 %s",
|
||
safePlaceholder(amount),
|
||
safePlaceholder(kind),
|
||
safePlaceholder(guaranteeType),
|
||
safePlaceholder(periodFrom),
|
||
safePlaceholder(periodTo),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
func renderPDFManagement(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
if len(v) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
// 高管列表
|
||
if execs, ok := v["executives"].([]interface{}); ok && len(execs) > 0 {
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "高管列表", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, e := range execs {
|
||
m, ok := e.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "name")
|
||
if name == "" {
|
||
continue
|
||
}
|
||
position := getString(m, "position")
|
||
line := fmt.Sprintf("%d. %s", i+1, name)
|
||
if position != "" {
|
||
line = fmt.Sprintf("%s(%s)", line, position)
|
||
}
|
||
pdf.MultiCell(0, 6, line, "", "L", false)
|
||
}
|
||
}
|
||
|
||
// 从业与社保
|
||
employeeCount := getString(v, "employeeCount")
|
||
femaleEmployeeCount := getString(v, "femaleEmployeeCount")
|
||
ssMap, _ := v["socialSecurity"].(map[string]interface{})
|
||
hasSS := len(ssMap) > 0
|
||
if employeeCount != "" || femaleEmployeeCount != "" || hasSS {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "从业与社保", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
if employeeCount != "" {
|
||
writeKeyValue(pdf, fontName, "从业人数", employeeCount)
|
||
}
|
||
if femaleEmployeeCount != "" {
|
||
writeKeyValue(pdf, fontName, "女性从业人数", femaleEmployeeCount)
|
||
}
|
||
if hasSS {
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "B", 11)
|
||
pdf.MultiCell(0, 5, "社会保险参保人数", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
socialLabels := map[string]string{
|
||
"endowmentInsuranceEmployeeCnt": "城镇职工基本养老保险参保人数",
|
||
"unemploymentInsuranceEmployeeCnt": "失业保险参保人数",
|
||
"medicalInsuranceEmployeeCnt": "职工基本医疗保险参保人数",
|
||
"injuryInsuranceEmployeeCnt": "工伤保险参保人数",
|
||
"maternityInsuranceEmployeeCnt": "生育保险参保人数",
|
||
}
|
||
keys := make([]string, 0, len(ssMap))
|
||
for k := range ssMap {
|
||
keys = append(keys, k)
|
||
}
|
||
sort.Strings(keys)
|
||
for _, k := range keys {
|
||
val := ssMap[k]
|
||
if val == nil {
|
||
continue
|
||
}
|
||
lbl := socialLabels[k]
|
||
if lbl == "" {
|
||
lbl = k
|
||
}
|
||
writeKeyValue(pdf, fontName, lbl, fmt.Sprint(val))
|
||
}
|
||
}
|
||
}
|
||
|
||
// 法定代表人其他任职
|
||
var others []interface{}
|
||
if arr, ok := v["legalRepresentativeOtherPositions"].([]interface{}); ok {
|
||
others = arr
|
||
} else if arr, ok := v["legalPersonOtherPositions"].([]interface{}); ok {
|
||
others = arr
|
||
}
|
||
if len(others) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "法定代表人其他任职", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, f := range others {
|
||
m, ok := f.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
entName := getString(m, "entName")
|
||
if entName == "" {
|
||
continue
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, entName), "", "L", false)
|
||
parts := []string{}
|
||
if pos := getString(m, "position"); pos != "" {
|
||
parts = append(parts, "职务:"+pos)
|
||
}
|
||
if name := getString(m, "name"); name != "" {
|
||
parts = append(parts, "姓名:"+name)
|
||
}
|
||
if st := getString(m, "entStatus"); st != "" {
|
||
parts = append(parts, "企业状态:"+st)
|
||
}
|
||
if cc := getString(m, "creditCode"); cc != "" {
|
||
parts = append(parts, "信用代码:"+cc)
|
||
}
|
||
if rn := getString(m, "regNo"); rn != "" {
|
||
parts = append(parts, "注册号:"+rn)
|
||
}
|
||
if len(parts) > 0 {
|
||
pdf.MultiCell(0, 5, " "+joinWithChineseSemicolon(parts), "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
}
|
||
|
||
func renderPDFAssets(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
yearsRaw, ok := v["years"].([]interface{})
|
||
if !ok || len(yearsRaw) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
for _, y := range yearsRaw {
|
||
m, ok := y.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
year := getString(m, "year")
|
||
reportDate := getString(m, "reportDate")
|
||
titleLine := year
|
||
if reportDate != "" {
|
||
titleLine = fmt.Sprintf("%s(%s)", year, reportDate)
|
||
}
|
||
pdf.MultiCell(0, 6, titleLine, "", "L", false)
|
||
meta := fmt.Sprintf(" 资产总额:%s;营收:%s;净利润:%s;负债:%s",
|
||
safePlaceholder(getString(m, "assetTotal")),
|
||
safePlaceholder(getString(m, "revenueTotal")),
|
||
safePlaceholder(getString(m, "netProfit")),
|
||
safePlaceholder(getString(m, "liabilityTotal")),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
func renderPDFLicenses(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
if len(v) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
// 行政许可列表
|
||
if permits, ok := v["permits"].([]interface{}); ok && len(permits) > 0 {
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "行政许可列表", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, p := range permits {
|
||
m, ok := p.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "name")
|
||
if name == "" {
|
||
continue
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, name), "", "L", false)
|
||
meta := fmt.Sprintf(" 有效期:%s ~ %s;许可机关:%s;%s",
|
||
safePlaceholder(getString(m, "valFrom")),
|
||
safePlaceholder(getString(m, "valTo")),
|
||
safePlaceholder(getString(m, "licAnth")),
|
||
safePlaceholder(getString(m, "licItem")),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 许可变更记录
|
||
if changes, ok := v["permitChanges"].([]interface{}); ok && len(changes) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "许可变更记录", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, p := range changes {
|
||
m, ok := p.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
changeDate := getString(m, "changeDate")
|
||
changeType := getString(m, "changeType")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s %s", i+1, safePlaceholder(changeDate), safePlaceholder(changeType)), "", "L", false)
|
||
before := getString(m, "detailBefore")
|
||
after := getString(m, "detailAfter")
|
||
if before != "" || after != "" {
|
||
pdf.MultiCell(0, 5, " 变更前:"+before, "", "L", false)
|
||
pdf.MultiCell(0, 5, " 变更后:"+after, "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 知识产权出质(如有则原样列出)
|
||
if ipPledges, ok := v["ipPledges"].([]interface{}); ok && len(ipPledges) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "知识产权出质", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, it := range ipPledges {
|
||
pdf.MultiCell(0, 5, fmt.Sprintf("%d. %v", i+1, it), "", "L", false)
|
||
}
|
||
}
|
||
}
|
||
|
||
func renderPDFActivities(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
if len(v) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
// 招投标
|
||
if bids, ok := v["bids"].([]interface{}); ok && len(bids) > 0 {
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "招投标", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, b := range bids {
|
||
m, ok := b.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
titleText := getString(m, "announcetitle")
|
||
if titleText == "" {
|
||
titleText = getString(m, "ANNOUNCETITLE")
|
||
}
|
||
if titleText == "" {
|
||
titleText = getString(m, "title")
|
||
}
|
||
if titleText == "" {
|
||
continue
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, titleText), "", "L", false)
|
||
}
|
||
}
|
||
|
||
// 网站 / 网店
|
||
if websites, ok := v["websites"].([]interface{}); ok && len(websites) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "网站 / 网店", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, w := range websites {
|
||
m, ok := w.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "websitname")
|
||
if name == "" {
|
||
name = getString(m, "WEBSITNAME")
|
||
}
|
||
if name == "" {
|
||
name = getString(m, "name")
|
||
}
|
||
if name == "" {
|
||
continue
|
||
}
|
||
webType := getString(m, "webtype")
|
||
if webType == "" {
|
||
webType = getString(m, "WEBTYPE")
|
||
}
|
||
domain := getString(m, "domain")
|
||
if domain == "" {
|
||
domain = getString(m, "DOMAIN")
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, name), "", "L", false)
|
||
meta := fmt.Sprintf(" 类型:%s;域名:%s", safePlaceholder(webType), safePlaceholder(domain))
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
}
|
||
|
||
func renderPDFInspections(pdf *gofpdf.Fpdf, fontName, title string, arr []interface{}) {
|
||
if len(arr) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
for i, it := range arr {
|
||
m, ok := it.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
date := getString(m, "inspectDate")
|
||
result := getString(m, "result")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s %s", i+1, safePlaceholder(date), safePlaceholder(result)), "", "L", false)
|
||
}
|
||
}
|
||
|
||
func renderPDFRisks(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
if len(v) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
// has* 风险项一览(有 / 无)
|
||
type item struct {
|
||
Key string
|
||
Label string
|
||
}
|
||
items := []item{
|
||
{"hasCourtJudgments", "裁判文书"},
|
||
{"hasJudicialAssists", "司法协助"},
|
||
{"hasDishonestDebtors", "失信被执行人"},
|
||
{"hasLimitHighDebtors", "限高被执行人"},
|
||
{"hasAdminPenalty", "行政处罚"},
|
||
{"hasException", "经营异常"},
|
||
{"hasSeriousIllegal", "严重违法"},
|
||
{"hasTaxOwing", "欠税"},
|
||
{"hasSeriousTaxIllegal", "重大税收违法"},
|
||
{"hasMortgage", "动产抵押"},
|
||
{"hasEquityPledges", "股权出质"},
|
||
{"hasQuickCancel", "简易注销"},
|
||
}
|
||
|
||
for _, it := range items {
|
||
val := getString(v, it.Key)
|
||
status := "未发现"
|
||
if val == "true" || val == "1" {
|
||
status = "存在"
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("· %s:%s", it.Label, status), "", "L", false)
|
||
}
|
||
|
||
// 裁判文书
|
||
if arr, ok := v["courtJudgments"].([]interface{}); !ok || len(arr) == 0 {
|
||
// 兼容 judicialCases 字段
|
||
if alt, ok2 := v["judicialCases"].([]interface{}); ok2 {
|
||
arr = alt
|
||
ok = len(arr) > 0
|
||
}
|
||
}
|
||
if arr, ok := v["courtJudgments"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "裁判文书", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, c := range arr {
|
||
m, ok := c.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
caseNo := getString(m, "caseNumber")
|
||
if caseNo == "" {
|
||
caseNo = getString(m, "CASENUMBER")
|
||
}
|
||
if caseNo == "" {
|
||
caseNo = getString(m, "judicialDocumentId")
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. 案号:%s", i+1, safePlaceholder(caseNo)), "", "L", false)
|
||
}
|
||
}
|
||
|
||
// 司法协助
|
||
if arr, ok := v["judicialAssists"].([]interface{}); !ok || len(arr) == 0 {
|
||
if alt, ok2 := v["judicialAids"].([]interface{}); ok2 {
|
||
arr = alt
|
||
ok = len(arr) > 0
|
||
}
|
||
if ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "司法协助", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, a := range arr {
|
||
m, ok := a.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "iname")
|
||
if name == "" {
|
||
name = getString(m, "INAME")
|
||
}
|
||
if name == "" {
|
||
name = getString(m, "marketName")
|
||
}
|
||
court := getString(m, "courtName")
|
||
if court == "" {
|
||
court = getString(m, "COURTNAME")
|
||
}
|
||
share := getString(m, "shaream")
|
||
if share == "" {
|
||
share = getString(m, "SHAREAM")
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(name)), "", "L", false)
|
||
meta := fmt.Sprintf(" 法院:%s;股权数额:%s 元", safePlaceholder(court), safePlaceholder(share))
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 失信被执行人
|
||
if arr, ok := v["dishonestDebtors"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "失信被执行人", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, d := range arr {
|
||
m, ok := d.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
caseNo := getString(m, "caseNo")
|
||
execCourt := getString(m, "execCourt")
|
||
performance := getString(m, "performanceStatus")
|
||
publishDate := getString(m, "publishDate")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. 案号 %s", i+1, safePlaceholder(caseNo)), "", "L", false)
|
||
meta := fmt.Sprintf(" 执行法院:%s;履行情况:%s;发布时间:%s",
|
||
safePlaceholder(execCourt),
|
||
safePlaceholder(performance),
|
||
safePlaceholder(publishDate),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 限高被执行人
|
||
if arr, ok := v["limitHighDebtors"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "限高被执行人", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, x := range arr {
|
||
m, ok := x.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
ah := getString(m, "ah")
|
||
if ah == "" {
|
||
ah = getString(m, "caseNo")
|
||
}
|
||
zxfy := getString(m, "zxfy")
|
||
if zxfy == "" {
|
||
zxfy = getString(m, "execCourt")
|
||
}
|
||
fbrq := getString(m, "fbrq")
|
||
if fbrq == "" {
|
||
fbrq = getString(m, "publishDate")
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(ah)), "", "L", false)
|
||
meta := fmt.Sprintf(" 执行法院:%s;发布日期:%s", safePlaceholder(zxfy), safePlaceholder(fbrq))
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 行政处罚
|
||
if arr, ok := v["adminPenalties"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "行政处罚", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, p := range arr {
|
||
m, ok := p.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
pendecno := getString(m, "pendecno")
|
||
if pendecno == "" {
|
||
pendecno = getString(m, "PENDECNO")
|
||
}
|
||
illeg := getString(m, "illegacttype")
|
||
if illeg == "" {
|
||
illeg = getString(m, "ILLEGACTTYPE")
|
||
}
|
||
auth := getString(m, "penauth")
|
||
if auth == "" {
|
||
auth = getString(m, "PENAUTH")
|
||
}
|
||
date := getString(m, "pendecissdate")
|
||
if date == "" {
|
||
date = getString(m, "PENDECISSDATE")
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(pendecno)), "", "L", false)
|
||
meta := fmt.Sprintf(" 违法类型:%s;机关:%s;日期:%s", safePlaceholder(illeg), safePlaceholder(auth), safePlaceholder(date))
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 行政处罚变更
|
||
if arr, ok := v["adminPenaltyUpdates"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "行政处罚变更记录", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, p := range arr {
|
||
m, ok := p.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
date := getString(m, "updateDate")
|
||
content := getString(m, "updateContent")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(date)), "", "L", false)
|
||
if content != "" {
|
||
pdf.MultiCell(0, 5, " "+content, "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 经营异常
|
||
if arr, ok := v["exceptions"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "经营异常", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, e := range arr {
|
||
m, ok := e.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
indate := getString(m, "indate")
|
||
if indate == "" {
|
||
indate = getString(m, "INDATE")
|
||
}
|
||
inreason := getString(m, "inreason")
|
||
if inreason == "" {
|
||
inreason = getString(m, "INREASON")
|
||
}
|
||
outdate := getString(m, "outdate")
|
||
if outdate == "" {
|
||
outdate = getString(m, "OUTDATE")
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(indate)), "", "L", false)
|
||
meta := fmt.Sprintf(" 原因:%s;移出:%s", safePlaceholder(inreason), safePlaceholder(outdate))
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 动产抵押
|
||
if arr, ok := v["mortgages"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "动产抵押", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, m := range arr {
|
||
mm, ok := m.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
regNo := getString(mm, "regNo")
|
||
amount := getString(mm, "guaranteedAmount")
|
||
regDate := getString(mm, "regDate")
|
||
regOrg := getString(mm, "regOrg")
|
||
status := getString(mm, "status")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s %s", i+1, safePlaceholder(regNo), safePlaceholder(amount)), "", "L", false)
|
||
meta := fmt.Sprintf(" 登记日:%s;机关:%s;状态:%s", safePlaceholder(regDate), safePlaceholder(regOrg), safePlaceholder(status))
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 简易注销
|
||
if qc, ok := v["quickCancel"].(map[string]interface{}); ok && len(qc) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "简易注销", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
writeKeyValue(pdf, fontName, "企业名称", getString(qc, "entName"))
|
||
writeKeyValue(pdf, fontName, "统一社会信用代码", getString(qc, "creditCode"))
|
||
writeKeyValue(pdf, fontName, "注册号", getString(qc, "regNo"))
|
||
writeKeyValue(pdf, fontName, "登记机关", getString(qc, "regOrg"))
|
||
writeKeyValue(pdf, fontName, "公告起始日期", getString(qc, "noticeFromDate"))
|
||
writeKeyValue(pdf, fontName, "公告结束日期", getString(qc, "noticeToDate"))
|
||
writeKeyValue(pdf, fontName, "注销结果", getString(qc, "cancelResult"))
|
||
}
|
||
|
||
// 清算信息
|
||
if liq, ok := v["liquidation"].(map[string]interface{}); ok && len(liq) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "清算信息", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
writeKeyValue(pdf, fontName, "负责人", getString(liq, "principal"))
|
||
writeKeyValue(pdf, fontName, "成员", getString(liq, "members"))
|
||
}
|
||
|
||
// 纳税与欠税(taxRecords)
|
||
if tax, ok := v["taxRecords"].(map[string]interface{}); ok && len(tax) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "纳税与欠税", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
ayears := getSlice(tax, "taxLevelAYears")
|
||
owings := getSlice(tax, "taxOwings")
|
||
hint := fmt.Sprintf("纳税A级年度:%s;欠税:%s",
|
||
formatCountHint(len(ayears)),
|
||
formatCountHint(len(owings)),
|
||
)
|
||
pdf.MultiCell(0, 5, hint, "", "L", false)
|
||
|
||
if len(owings) > 0 {
|
||
pdf.Ln(1)
|
||
for i, t := range owings {
|
||
m, ok := t.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
taxType := getString(m, "taxOwedType")
|
||
if taxType == "" {
|
||
taxType = getString(m, "taxowedtype")
|
||
}
|
||
total := getString(m, "totalOwedAmount")
|
||
if total == "" {
|
||
total = getString(m, "totalowedamount")
|
||
}
|
||
pub := getString(m, "publishDate")
|
||
if pub == "" {
|
||
pub = getString(m, "publishdate")
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(taxType)), "", "L", false)
|
||
meta := fmt.Sprintf(" 合计:%s;公示日:%s", safePlaceholder(total), safePlaceholder(pub))
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
} else {
|
||
// 完全无 taxRecords 时,与 HTML 行为一致给一个“无”的提示
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "纳税与欠税", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
pdf.MultiCell(0, 5, "无", "", "L", false)
|
||
}
|
||
|
||
// 涉诉案件(litigation)—— 按案件类型分类
|
||
if lit, ok := v["litigation"].(map[string]interface{}); ok && len(lit) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "涉诉案件汇总", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
typeLabels := map[string]string{
|
||
"administrative": "行政案件",
|
||
"implement": "执行案件",
|
||
"preservation": "非诉保全审查",
|
||
"civil": "民事案件",
|
||
"criminal": "刑事案件",
|
||
"bankrupt": "强制清算与破产案件",
|
||
"jurisdict": "管辖案件",
|
||
"compensate": "赔偿案件",
|
||
}
|
||
|
||
// 汇总表
|
||
for key, label := range typeLabels {
|
||
if sec, ok := lit[key].(map[string]interface{}); ok {
|
||
count := getString(sec, "count")
|
||
if count != "" && count != "0" {
|
||
pdf.MultiCell(0, 5, fmt.Sprintf("· %s:%s 件", label, count), "", "L", false)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 各类案件明细
|
||
for key, label := range typeLabels {
|
||
sec, ok := lit[key].(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
cases, ok := sec["cases"].([]interface{})
|
||
if !ok || len(cases) == 0 {
|
||
continue
|
||
}
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, label, "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, c := range cases {
|
||
m, ok := c.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
caseNo := getString(m, "caseNo")
|
||
court := getString(m, "court")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s(%s)", i+1, safePlaceholder(caseNo), safePlaceholder(court)), "", "L", false)
|
||
region := getString(m, "region")
|
||
trialLevel := getString(m, "trialLevel")
|
||
caseType := getString(m, "caseType")
|
||
cause := getString(m, "cause")
|
||
amount := getString(m, "amount")
|
||
filing := getString(m, "filingDate")
|
||
judgment := getString(m, "judgmentDate")
|
||
victory := getString(m, "victoryResult")
|
||
meta := fmt.Sprintf(" 地区:%s;审级:%s;案件类型:%s;案由:%s;标的金额:%s;立案日期:%s;裁判日期:%s;胜败结果:%s",
|
||
safePlaceholder(region),
|
||
safePlaceholder(trialLevel),
|
||
safePlaceholder(caseType),
|
||
safePlaceholder(cause),
|
||
safePlaceholder(amount),
|
||
safePlaceholder(filing),
|
||
safePlaceholder(judgment),
|
||
safePlaceholder(victory),
|
||
)
|
||
pdf.MultiCell(0, 5, meta, "", "L", false)
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func renderPDFTimeline(pdf *gofpdf.Fpdf, fontName, title string, arr []interface{}) {
|
||
if len(arr) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
for i, it := range arr {
|
||
m, ok := it.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
date := getString(m, "date")
|
||
tp := getString(m, "type")
|
||
desc := getString(m, "title")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s %s", i+1, safePlaceholder(date), safePlaceholder(tp)), "", "L", false)
|
||
if desc != "" {
|
||
pdf.MultiCell(0, 5, " "+desc, "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
func renderPDFListed(pdf *gofpdf.Fpdf, fontName, title string, v map[string]interface{}) {
|
||
if len(v) == 0 {
|
||
return
|
||
}
|
||
pdf.AddPage()
|
||
pdfSectionTitle(pdf, fontName, title)
|
||
pdf.Ln(1)
|
||
pdf.SetFont(fontName, "", 11)
|
||
|
||
isListed := boolToCN(getString(v, "isListed"))
|
||
if isListed != "" {
|
||
writeKeyValue(pdf, fontName, "是否上市", isListed)
|
||
}
|
||
|
||
// 上市公司信息
|
||
if company, ok := v["company"].(map[string]interface{}); ok && len(company) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "上市公司信息", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
writeKeyValue(pdf, fontName, "经营范围", getString(company, "bizScope"))
|
||
writeKeyValue(pdf, fontName, "信用代码", getString(company, "creditCode"))
|
||
writeKeyValue(pdf, fontName, "注册地址", getString(company, "regAddr"))
|
||
writeKeyValue(pdf, fontName, "注册资本", getString(company, "regCapital"))
|
||
writeKeyValue(pdf, fontName, "组织机构代码", getString(company, "orgCode"))
|
||
writeKeyValue(pdf, fontName, "币种", getString(company, "cur"))
|
||
writeKeyValue(pdf, fontName, "币种名称", getString(company, "curName"))
|
||
}
|
||
|
||
// 股票信息
|
||
if stock, ok := v["stock"]; ok && stock != nil {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "股票信息", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
switch s := stock.(type) {
|
||
case string:
|
||
if s != "" {
|
||
pdf.MultiCell(0, 5, s, "", "L", false)
|
||
}
|
||
case map[string]interface{}:
|
||
// 简单将几个常见字段以表格形式展示
|
||
code := getString(s, "code")
|
||
name := getString(s, "name")
|
||
market := getString(s, "market")
|
||
if code != "" {
|
||
writeKeyValue(pdf, fontName, "代码", code)
|
||
}
|
||
if name != "" {
|
||
writeKeyValue(pdf, fontName, "名称", name)
|
||
}
|
||
if market != "" {
|
||
writeKeyValue(pdf, fontName, "市场", market)
|
||
}
|
||
default:
|
||
// 其他类型非空时,用字符串方式输出
|
||
txt := fmt.Sprint(stock)
|
||
if txt != "" && txt != "<nil>" {
|
||
pdf.MultiCell(0, 5, txt, "", "L", false)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 十大股东
|
||
if arr, ok := v["topShareholders"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "十大股东", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, s := range arr {
|
||
m, ok := s.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "name")
|
||
if name == "" {
|
||
name = getString(m, "shaname")
|
||
}
|
||
pct := getString(m, "percent")
|
||
if pct == "" {
|
||
pct = getString(m, "fundedratio")
|
||
}
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(name)), "", "L", false)
|
||
if pct != "" {
|
||
pdf.MultiCell(0, 5, " 持股比例:"+pct, "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
|
||
// 上市高管
|
||
if arr, ok := v["listedManagers"].([]interface{}); ok && len(arr) > 0 {
|
||
pdf.Ln(2)
|
||
pdf.SetFont(fontName, "B", 12)
|
||
pdf.MultiCell(0, 6, "上市高管", "", "L", false)
|
||
pdf.SetFont(fontName, "", 11)
|
||
for i, mng := range arr {
|
||
m, ok := mng.(map[string]interface{})
|
||
if !ok {
|
||
continue
|
||
}
|
||
name := getString(m, "name")
|
||
if name == "" {
|
||
name = getString(m, "perName")
|
||
}
|
||
position := getString(m, "position")
|
||
pdf.MultiCell(0, 6, fmt.Sprintf("%d. %s", i+1, safePlaceholder(name)), "", "L", false)
|
||
if position != "" {
|
||
pdf.MultiCell(0, 5, " 职务:"+position, "", "L", false)
|
||
}
|
||
pdf.Ln(1)
|
||
}
|
||
}
|
||
}
|
||
|
||
// joinWithChineseSemicolon 使用中文分号连接字符串
|
||
func joinWithChineseSemicolon(parts []string) string {
|
||
if len(parts) == 0 {
|
||
return ""
|
||
}
|
||
res := parts[0]
|
||
for i := 1; i < len(parts); i++ {
|
||
res += ";" + parts[i]
|
||
}
|
||
return res
|
||
}
|
||
|
||
// pdfSectionTitle 渲染模块主标题(对应 HTML h2)
|
||
func pdfSectionTitle(pdf *gofpdf.Fpdf, fontName, title string) {
|
||
pdf.SetFont(fontName, "B", 17)
|
||
// 模块标题前加蓝色点缀方块
|
||
pdf.SetTextColor(37, 99, 235)
|
||
pdf.CellFormat(0, 10, "■ "+title, "", 1, "L", false, 0, "")
|
||
pdf.SetTextColor(0, 0, 0)
|
||
}
|
||
|
||
// pdfSubTitle 渲染模块内小节标题(对应 HTML h3)
|
||
func pdfSubTitle(pdf *gofpdf.Fpdf, fontName, title string) {
|
||
pdf.SetFont(fontName, "B", 14)
|
||
// 小节标题用圆点前缀,略微缩进
|
||
pdf.SetTextColor(37, 99, 235)
|
||
pdf.CellFormat(0, 8, "● "+title, "", 1, "L", false, 0, "")
|
||
pdf.SetTextColor(0, 0, 0)
|
||
}
|
||
|
||
// pdfWriteBasicRow 渲染基础信息的一行,使用隔行背景色而不加表格框
|
||
func pdfWriteBasicRow(pdf *gofpdf.Fpdf, fontName, label, value string, alt bool) {
|
||
if value == "" {
|
||
return
|
||
}
|
||
pageW, pageH := pdf.GetPageSize()
|
||
lMargin, _, rMargin, bMargin := pdf.GetMargins()
|
||
x := lMargin
|
||
y := pdf.GetY()
|
||
w := pageW - lMargin - rMargin
|
||
labelW := 40.0
|
||
valueW := w - labelW
|
||
// 行高整体拉宽一点
|
||
lineH := 10.0
|
||
|
||
// 预先根据内容拆行,计算本行整体高度(用于背景块)
|
||
lines := pdf.SplitLines([]byte(value), valueW)
|
||
rowH := float64(len(lines)) * lineH
|
||
if rowH < lineH {
|
||
rowH = lineH
|
||
}
|
||
rowH += 2
|
||
|
||
// 如当前页剩余空间不足,先分页再画整行,避免内容与下一页重叠
|
||
if y+rowH > pageH-bMargin {
|
||
pdf.AddPage()
|
||
y = pdf.GetY()
|
||
pdf.SetXY(lMargin, y)
|
||
}
|
||
|
||
// 隔行底色
|
||
if alt {
|
||
pdf.SetFillColor(242, 242, 242)
|
||
} else {
|
||
pdf.SetFillColor(255, 255, 255)
|
||
}
|
||
pdf.Rect(x, y, w, rowH, "F")
|
||
|
||
// 标签列
|
||
pdf.SetXY(x, y)
|
||
pdf.SetFont(fontName, "B", 14)
|
||
pdf.CellFormat(labelW, rowH, fmt.Sprintf("%s:", label), "", 0, "L", false, 0, "")
|
||
|
||
// 值列自动换行
|
||
pdf.SetXY(x+labelW, y)
|
||
pdf.SetFont(fontName, "", 14)
|
||
pdf.MultiCell(valueW, lineH, value, "", "L", false)
|
||
|
||
// 移到下一行起始位置
|
||
pdf.SetXY(lMargin, y+rowH)
|
||
}
|
||
|
||
// formatCountHint 将条数格式化为“X 条”或“无”
|
||
func formatCountHint(n int) string {
|
||
if n <= 0 {
|
||
return "无"
|
||
}
|
||
return fmt.Sprintf("%d 条", n)
|
||
}
|
||
|
||
// boolToCN 将 true/false/1/0/yes/no 映射成 “是/否”
|
||
func boolToCN(s string) string {
|
||
if s == "" {
|
||
return s
|
||
}
|
||
low := strings.ToLower(strings.TrimSpace(s))
|
||
switch low {
|
||
case "true", "1", "yes", "y":
|
||
return "是"
|
||
case "false", "0", "no", "n":
|
||
return "否"
|
||
default:
|
||
return s
|
||
}
|
||
}
|