Files
MAcode/tcs-iptv/internal/service/regulatory.go
T
selfrelease 8db9d33694 feat(phase3): 备案对接/全国统计/号段管理/BFF安全化/链合约源码
- A.1 备案对接: BindFiling/QueryFiling 关联网标号+备案号
- A.2 监管上报: DailyRegulatoryReport 日报
- B.1 号段管理: ListSegments + /admin/segments
- C.1/C.2 全国统计按省聚合 + 跨省协同(单一可信源天然联动)
- F.2 全国监管大屏: NationalStats(按省/类目/状态)
- B(遗留) 监管大屏BFF: internal/bff + cmd/console-bff, 密钥仅存后端浏览器只用会话令牌
- G 真实链合约源码: contracts/tcs_registry/registry.go (ChainMaker Go)
- 新增9个API+BFF服务; 5项新测试; 端到端BFF验证
- D/E(压测/等保/HSM)/F.1(标准)/真实链部署 标注需外部环境
2026-06-14 17:53:12 +08:00

116 lines
3.2 KiB
Go

package service
import (
"time"
"github.com/tcs-iptv/tcs/internal/macode"
"github.com/tcs-iptv/tcs/internal/model"
)
// 三期:备案对接、全国统计、号段管理、监管上报。
// 机构节点 → 省份映射(与发码机构号段分配一致;示例覆盖部分省)。
var orgNodeProvince = map[string]string{
"6101": "陕西", "4401": "广东", "3301": "浙江", "3201": "江苏",
"1101": "北京", "3101": "上海", "5101": "四川", "4201": "湖北",
}
// BindFiling 关联备案号/网标号至 MA 码(三期 A.1,对接广电总局备案系统)。
func (s *Service) BindFiling(maCode, licenseNo, filingNo string) (model.FilingRecord, error) {
if _, err := s.chain.QueryContent(maCode); err != nil {
return model.FilingRecord{}, err
}
rec := model.FilingRecord{
MACode: maCode, LicenseNo: licenseNo, FilingNo: filingNo,
BoundAt: time.Now().Format(time.RFC3339),
}
s.mu.Lock()
s.filings[maCode] = rec
s.mu.Unlock()
s.prov.Record(model.ProvenanceEvent{
MACode: maCode, Node: model.NodeIssue, Operator: "广电总局备案系统",
Detail: "关联网标号 " + licenseNo + " / 备案号 " + filingNo,
})
return rec, nil
}
// QueryFiling 查询备案关联。
func (s *Service) QueryFiling(maCode string) (model.FilingRecord, bool) {
s.mu.Lock()
defer s.mu.Unlock()
r, ok := s.filings[maCode]
return r, ok
}
// NationalStats 全国监管统计(三期 A.2/F.2)。
func (s *Service) NationalStats() (model.NationalStats, error) {
all, err := s.chain.ListContents("")
if err != nil {
return model.NationalStats{}, err
}
st := model.NationalStats{
ByStatus: map[string]int{},
ByCategory: map[string]int{},
ByProvince: map[string]model.ProvinceStat{},
}
st.TotalContents = len(all)
for _, c := range all {
st.ByStatus[c.Status]++
p, perr := macode.Parse(c.MACode)
if perr == nil {
st.ByCategory[p.Category]++
prov := orgNodeProvince[p.OrgNode]
if prov == "" {
prov = "其他(" + p.OrgNode + ")"
}
ps := st.ByProvince[prov]
ps.Province = prov
ps.OrgNode = p.OrgNode
ps.Total++
switch c.Status {
case model.StatusPublished:
ps.Published++
case model.StatusRevoked:
ps.Revoked++
}
st.ByProvince[prov] = ps
}
}
return st, nil
}
// ListSegments 列出已登记号段及使用情况(三期 B.1)。
func (s *Service) ListSegments() []macode.SegmentInfo {
return s.gen.Segments()
}
// RegisterSegment 登记新号段(三期 B.1,与发码机构对接后配置)。
func (s *Service) RegisterSegment(seg macode.Segment) error {
return s.gen.RegisterSegment(seg)
}
// DailyRegulatoryReport 生成监管数据上报日报(三期 A.2)。
func (s *Service) DailyRegulatoryReport(date string) (model.RegulatoryReport, error) {
all, err := s.chain.ListContents("")
if err != nil {
return model.RegulatoryReport{}, err
}
rep := model.RegulatoryReport{
ReportType: "daily_summary", Date: date,
LevelDist: map[string]int{},
}
for _, c := range all {
rep.TotalNew++
if p, perr := macode.Parse(c.MACode); perr == nil {
rep.LevelDist[p.Category]++
}
if c.Status == model.StatusRevoked {
rep.RevokedCnt++
}
}
s.mu.Lock()
rep.BlacklistCnt = len(s.black)
s.mu.Unlock()
return rep, nil
}