feat(qualification): 资质库和资质匹配(查标第 4 步,规则集 2026.11-r4)
Some checks failed
ci / server (push) Has been cancelled
ci / web (push) Has been cancelled
ci / contract (push) Has been cancelled

- 资质库(FR-M6-08):增删改、证书扫描件(PDF/JPG/PNG,企业级密钥加密、签名下载)、
  late_for 按进行中项目的投标截止日提醒、审计;前端资质库页和对话框,侧栏入口
- 资质匹配(FR-M3-05):证书类别词表(16 类,产品证书、人员证书不进匹配),
  QUAL.EXPIRED / LEVEL_LOW / NOT_COVERED;投标文字层按清单项定级,只有资质库记录的降一级,
  出处显示「依据:资质库记录」(查标页、报告模板 v2);一类证书一个问题;评分项不逐条找响应的也查
- 响应错位规则不再把资质表的证书名称格当成照抄的要求
- 评测:qual_defects.py 派生资质情况表,D12 3/3、D18 2/2、规矩的资质表 0 误报;开发集不退化
- 决策 QL1–QL7;方案和落地记录 docs/architecture/qualification-plan.md,评测 check-eval.md §13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
YANG JIANKUAN
2026-11-04 23:22:50 +08:00
parent e7fb797925
commit 08e3fe7eff
43 changed files with 2643 additions and 49 deletions

View File

@@ -624,7 +624,7 @@ paths:
filename: { type: string, maxLength: 255 }
size_bytes: { type: integer, minimum: 1 }
sha256: { type: string, pattern: '^[0-9a-f]{64}$', description: 选填;提供时完成上传时校验 }
purpose: { type: string, enum: [project_document, qualification_file] }
purpose: { type: string, enum: [project_document, qualification_file], description: '资质附件只收 PDF、JPG、PNG,单个不超过 20MB' }
responses:
'201':
description: OK
@@ -1593,10 +1593,15 @@ paths:
tags: [qualifications]
operationId: listQualifications
summary: 资质库
description: 按「有效期至」从近到远排,长期有效的在最后。
parameters:
- name: kind
in: query
schema: { $ref: '#/components/schemas/QualificationKind' }
- name: q
in: query
description: 按名称、证书编号、发证机构搜索
schema: { type: string, maxLength: 100 }
responses:
'200':
description: OK
@@ -1944,7 +1949,7 @@ components:
ProjectStatus: { type: string, enum: [tracking, drafting, checked, submitted, archived] }
LegalRegime: { type: string, enum: [gov_procurement, tendering, unknown] }
DocumentRole: { type: string, enum: [tender, addendum, clarification, bid_volume] }
DetectedFormat: { type: string, enum: [pdf, docx, doc, wps, ofd, encrypted_bid, unknown] }
DetectedFormat: { type: string, enum: [pdf, docx, doc, wps, ofd, encrypted_bid, jpeg, png, unknown], description: jpeg、png 只出现在资质附件(purpose = qualification_file)上 }
JobStatus: { type: string, enum: [queued, running, succeeded, failed, cancelled] }
Category: { type: string, enum: [qualification, invalidity, scoring, schedule, tech_param, format_doc, price] }
Importance:
@@ -2866,12 +2871,13 @@ components:
items: { $ref: '#/components/schemas/Category' }
rule:
type: [object, 'null']
description: 规则问题的规则编号和说明(detector = rule 时有);资质匹配的问题同时挂清单项
properties:
code: { type: string, examples: [PRICE.CAPITAL_MISMATCH] }
description: { type: string }
detail:
type: object
description: 按类型的补充信息:参数的要求值和响应值、资质预警种类(expired / insufficient_level / not_covered)、从投标文件读到的金额
description: 按类型的补充信息:参数的要求值和响应值、从投标文件读到的金额;资质问题(type = qualification)有 kind(expired / level_low / not_covered)、source(bid_text / library)、deadline,issues[] 里 source = library 的带 library(资质库记录的快照:id、name、kind、level、cert_no、valid_to),界面显示为「依据:资质库记录」
tender_citations:
type: array
items: { $ref: '#/components/schemas/Citation' }
@@ -3016,16 +3022,16 @@ components:
properties:
name: { type: string, minLength: 1, maxLength: 200 }
kind: { $ref: '#/components/schemas/QualificationKind' }
level: { type: [string, 'null'] }
cert_no: { type: [string, 'null'] }
issuer: { type: [string, 'null'] }
level: { type: [string, 'null'], maxLength: 40 }
cert_no: { type: [string, 'null'], maxLength: 80, description: 界面上必填(查标时用它核对附件),接口可空,以后批量导入时不一定读得全 }
issuer: { type: [string, 'null'], maxLength: 120 }
valid_from: { type: [string, 'null'], format: date }
valid_to: { type: [string, 'null'], format: date, description: 空表示长期有效 }
valid_to: { type: [string, 'null'], format: date, description: 空表示长期有效;要晚于 valid_from }
Qualification:
allOf:
- $ref: '#/components/schemas/QualificationInput'
- type: object
required: [id, files, created_at, updated_at]
required: [id, files, late_for, created_at, updated_at]
properties:
id: { $ref: '#/components/schemas/Id' }
files:
@@ -3037,6 +3043,16 @@ components:
id: { $ref: '#/components/schemas/Id' }
filename: { type: string }
size_bytes: { type: integer }
late_for:
type: array
description: 进行中的项目(跟进中、编制中、已检查,截止日不早于今天)里,投标截止日晚于「有效期至」的项目。到期按每个项目的截止日判断,不按今天
items:
type: object
required: [project_id, name, deadline]
properties:
project_id: { $ref: '#/components/schemas/Id' }
name: { type: string }
deadline: { type: string, format: date }
created_at: { $ref: '#/components/schemas/Timestamp' }
updated_at: { $ref: '#/components/schemas/Timestamp' }