招投标评分表自查
把招标文件里的评标办法/评分表变成一张表,然后核对抄录过程中的算术与齐备错误。
它回答的问题是:我把评分表从招标文件抄进工作底稿时,有没有抄错。 它不回答的问题是:分设得合不合理、会不会废标、能不能中标。
什么时候用它
- 投标前,把招标文件评分办法整理成底稿,想知道有没有漏项、分值加不加得起来。
- 评标时,已经打好分,想知道单项分有没有超过分值上限、合计对不对。
- 任何时候,想确认一张评分表自身是不是自洽。
不适合:判断分值设置是否恰当、判断评标是否公平、判断是否应当否决投标、预测中标结果。 这些是评标委员会依法独立作出的判断,本工具不做,也不该做。
输入
两条路,任选其一。
A. 直接给 .docx(推荐)
node scripts/docx-text.mjs 招标文件.docx
输出是纯文本:段落一行一段,表格一行一表(| a | b |)。合并单元格会输出 ↔,
意思是"这一格与左边合并了,是占位符不是数据"——不要把它当成缺失值去补。
只认
.docx。.doc(97-2003 二进制格式)和.wps需要先另存为.docx。 PDF 不支持:扫描件要 OCR,文字版 PDF 的表格结构也留不住,硬抽出来错得比不抽更多。
B. 用户直接粘贴评分表文本
粘进来的表格、或者从 PDF 里复制出来的文字都可以。这时候跳过上面的脚本,直接看下面的表结构。
表结构
输出一份 JSON(YAML 也行),形状固定:
{
"project": "项目名称",
"tenderNo": "招标编号",
"method": "综合评分法",
"rows": [
{ "序号": "1", "评审因素": "投标报价", "评审类别": "价格", "分值": "30", "评分依据": "评标基准价法,×30" }
]
}
| 字段 | 必填 | 说明 |
|---|---|---|
| 序号 | 建议 | 评分表的行号,用于定位 |
| 评审因素 | 必填 | 这一行评的是什么。⚠️ 引擎不逐行校验:缺了不报错,会静默算作合格 |
| 评审类别 | 建议 | 价格/技术/商务 等,原文怎么写就怎么填 |
| 分值 | 必填 | 这一项的满分上限(见下面的取值规则)。⚠️ 同上,缺这一列的行会被静默忽略 |
| 投标人A 投标人B 投标人C | 选填 | 实际得分。只在评标打分场景才有;投标人自查通常没有,没有就整列不填 |
| 评分依据 | 建议 | 原文的评分标准/评分细则。这是核对"有没有抄全"的依据 |
| 备注 | 选填 | |
完整别名表见 assets/schema.json(评审因素 也可以写 评分因素,分值 也可以写 满分)。
五条硬规则(做错了整个结果就没意义;其中一条会静默失败)
1. 子项必须拆成多行,不能压成一行
真实评分表大量出现一个单元格里塞几个子项:
| 技术分 | 60 | 技术方案 20 分;项目实施方案 20 分;售后服务方案 20 分 |
必须拆成三行,每行 分值 是子项的 20,而不是写一行 技术分 = 60。
压成一行会让所有核对全部通过——总分对得上、没有重复、没有漏填——而实际上一个子项都没查。 这是本工具最危险的一处静默失败——但不是唯一一处,见文末「已知限制」。
2. 分值 取"这一项最高能得几分"
真实文件很少给单一数字,常见三种写法,统一按上限处理:
| 原文写法 | 分值 填 |
|---|---|
| 3-5 分、3~5 分 | 5 |
| 基准分 10 分,每缺一项扣 0.5 分 | 10 |
| 优 5 分 / 良 3 分 / 一般 1 分 | 5 |
区间下限、档位中间值都不填。核对的是"上限对不对得上",取下限会让合计永远差一截。
3. 一份评分办法常常拆成好几张表,要合成一张台账
真实招标文件的评分办法经常是三到五张独立的表,每张表前面各有一行"评审因素 / 分值 / 评分标准"表头:
| 评审因素 | 分值 | 评分标准 | ← 表一:价格分 + 技术分
| 评审因素 | 分值 | 评分标准 | ← 表二:扣分制项目
| 评审因素 | 分值 | 评分标准 | ← 表三:商务分
必须合并成一张台账,只写一套表头,行按出现顺序连续编号。
这一条不做的后果很具体:只抽表一会得到"合计 45,与总分 100 相差 55"——这是你抽漏了,不是文档错了。 工具会如实报这个差异,用户却会以为自己的表有问题。
4. 整行合并且没有分值的是分节标题,不是评分项
评分表里常见这样的行:
| 服务部分 | ↔ | ↔ |
一整行合并、没有分值、文字是"服务部分""商务部分""技术部分"这类——它是分节标题,
用来把下面的行分组。不要把它当成一行评分项写进台账——写了不会拉低合计(空分值那行会被静默忽略),
但会在报告里留一条无意义的 TM-005,并掩盖你真正缺的行。
如果它自带合计(如"技术部分(31分)"),把合计记进心里用于交叉核对,但不要作为一行。
5. 抄不到就留空,不要补
原文没写分值、或者那一格是图片、或者写着"详见附件",就把 分值 留空,不要估算、不要填 0。
注意:留空的项不会被单独指出来。 它的 分值 不参与合计,报告也不会有一条「这一行缺分值」——
你不会知道它被漏掉了。它的 评分依据 若为空或有占位符,仍会被 TM-005 / TM-007 抓到,
但那两条说的是别的问题,不是「你忘了填分值」。所以宁可先删掉整行,也不要留一个空分值。
同理:评分依据 抄原文,不要改写、不要概括成"按方案优劣打分"。
跑之前先数一遍
抽完表、跑核对之前,做这个检查——它比后面所有核对都重要:
- 文档里出现了几个"评审因素 / 分值 / 评分标准"表头?→ 记为 N
- 你的台账里有没有 N 张表的所有行?
- 文档里有几句"合计 100 分""技术部分 31 分"?把它们加起来对不对?
如果 合计不符 这一条命中,先回头找有没有漏掉的表,再考虑是不是数字抄错。
真实文件里"漏一张表"比"抄错一个数字"常见得多,而报出来的症状一模一样。
怎么跑
# 1. 如果给的是 .docx,先把正文取出来
node scripts/docx-text.mjs 招标文件.docx > 正文.txt
# 2. 照着上面的表结构写出 score-table.json
# 3. 核对。--total 传招标文件写明的总分
node scripts/check.mjs score-table.json --total 100
--total 强烈建议传。 招标文件里通常有一句"评标总分为 100 分"。
不传,最有用的一条(分值合计是否等于总分)会被跳过,报告变成"什么也没查到"。
分制不是 100 的(120 分制、分项加权)就按实际数字传。
其他用法:
node scripts/check.mjs score-table.json --total 100 --json # 原始报告
node scripts/check.mjs --schema # 打印字段别名表
cat score-table.json | node scripts/check.mjs - --total 100 # 从标准输入读
退出码:0 没发现问题,1 有问题,2 表结构被拒(字段名不对/不是合法 JSON)。
没有 npm 依赖,不需要 npm install。 只需要 Node ≥ 18。
报告怎么读
七种检查,按命中时的措辞看:
| 规则 | 查什么 | 命中说明 |
|---|---|---|
| TM-001 | 有没有写项目名与评标办法 | 表头缺栏 |
| TM-002 | 单项得分有没有超过分值上限 | 只在填了 投标人A 时执行 |
| TM-003 | 分值合计等于总分吗 | 需要 --total |
| TM-004 | 得分合计等于汇总栏吗 | ⚠️ 当前版本永不执行:它需要配置该投标人的合计目标,而工具没有提供这个入口 |
| TM-005 | 评分依据有没有漏填 | 该行没抄评分标准 |
| TM-006 | 序号有没有重复 | 抄重了一行 |
| TM-007 | 有没有残留 【】、XXX、待填、TBD、示例 等占位符 | 模板没改完。⚠️ 裸的 XX 分 识别不到 |
"注:"开头的段落、以及 Word 文本框里的字会被读出来——里面常常写着"以下分值以评标办法为准"这类改变读法的说明。 ⚠️ 脚注(footnotes)当前不抽取:脚本只读正文。分值和评分标准若写在脚注里,你会漏项。
报告末尾的**"未执行的检查"**不是错误,是在告诉你哪几条规则因为材料不足没跑。 要把这一节原样转述给用户——它决定了这个结论能用到什么程度。
每条命中都带条款依据(《招标投标法》的对应条款原文)和"建议核对"。
转述结果时的措辞
- 说"第 4 行缺评分依据",不说"你这条不合格"。
- 说"分值合计 95,与总分 100 相差 5",不说"你的表错了"。
- 说"TM-002 未执行,因为没填投标人得分",不说"全部检查通过"。
- 不要说"这样就不会废标"。本工具连"是否应当否决投标"都不判断。
- 不要替用户改数字。指出差异,改不改、怎么改由用户按招标文件决定。
报告自带的免责声明要一起给出,不要删。
示例
assets/example/ 下有一套完整样例:
tender-sample.docx— 一份带合并单元格、嵌套子表、修订痕迹的评分办法score-table.json— 按上表结构抽出来的结果,子项已拆行,抄录正确score-table-typo.json— 同一份文件的抄录件,含三种真实的手误:漏抄一个子项(20 写成 15)、把序号 3 抄成 2、有一行评分依据没填report.md— 上面那份抄录件的核对报告tender-multi-table.docx— 评分办法拆成三张表、带分节标题行、带文本框注释的那一版score-table-multi-table.json— 上面这份的三张表合并成一张台账后的样子(5 行)
先用它验证环境(第一条抽文档,第二条核对干净件,第三条核对抄错件):
node scripts/docx-text.mjs assets/example/tender-sample.docx
node scripts/check.mjs assets/example/score-table.json --total 100 # 0 条,退出码 0
node scripts/check.mjs assets/example/score-table-typo.json --total 100 # 3 条,退出码 1
# 三表合并那一份:看它怎么把 3 张表、1 个分节标题行合成 5 行台账
node scripts/docx-text.mjs assets/example/tender-multi-table.docx
node scripts/check.mjs assets/example/score-table-multi-table.json --total 100
已知限制(实测确认,发布前逐条验过)
这些不是"以后会修",是当前版本的确定行为。报结果时若碰到下面任何一种,要主动向用户说明。
| # | 限制 | 后果 |
|---|---|---|
| 1 | 评审因素 / 分值 号称必填,引擎不逐行校验 | 一张没有评分项、没有分值的表会得到「0 条,退出码 0」 |
| 2 | 分值 留空的行不参与合计,也没有规则指出「缺分值」 | 你以为查了这一行;只有它的评分依据为空/有占位符时才会被 TM-005/TM-007 间接抓到 |
| 3 | TM-004 永不执行(缺合计目标入口) | 评标场景的"得分合计对不对"无法核对 |
| 4 | TM-006 的定位显示的是你声明的序号,不是物理行号 | 会看到"第 2 行与第 2 行重复"这种自相矛盾的话;实际是第 3 行和第 2 行 |
| 5 | TM-007 不识别裸的 XX | 模板里的 XX 分 会被当成正常内容 |
| 6 | 脚注不抽取(只读正文 word/document.xml) | 写在脚注里的分值/标准会漏 |
| 7 | YAML 只支持块式,且顶层不能用 flow 式 | 顶层的 {...} 或 --- 文档标记会失败;rows: [{...}] 这种内层 flow 式可以 |
| 8 | 分值 直接写区间 "3-5" 会被取成 3 | 必须自己填上限 5,工具不会帮你判断 |
| 9 | 报告标题和字段名是内部名(dsh-tender-matrix、basis、maxScore、seq) | 转述给用户时要换成中文说法 |
第 1、2、5、6 条都属于静默失败:工具说"0 条",但它其实没查。 所以不要用「0 条差异」当成"没问题"的同义词——先看「未执行的检查」,再对照这张表。
微信扫一扫