diff --git a/src/api/admin.js b/src/api/admin.js
index a2dec3d..2b5ce83 100644
--- a/src/api/admin.js
+++ b/src/api/admin.js
@@ -322,6 +322,42 @@ export function publicityExportUrl(group) {
return `/api/admin/export-publicity/${group}`
}
+/**
+ * 成绩排名表导出前的统计预检(R220,⛔ 不下载文件,只回统计)
+ *
+ * 排名表是「一行 = 一个参赛小组」的速览表,前端在下载前需要知道三件事:
+ * ① 有没有人未归属小组(会各自单独占一行);② 本组是否根本没有可导出的数据;
+ * ③ 整行底色是否生成失败(后端会自动降级为无色版,文件名带「-无底色」)。
+ * ③ 必须提示,否则管理员会以为「导出错了」而不是「降级了」。
+ *
+ * silent: true —— 属「预检」而非用户动作,失败由调用方按业务语境提示。
+ * @param {string} group - 组别标识(仅 zhongzhi / gaozhi 有效)
+ * @returns {Promise<{fileName:string,rowCount:number,colored:boolean,degradeReason:string,
+ * stats:Object,topN:number,totalContestants:number,noTeamCount:number}>}
+ */
+export function getScoreRankMeta(group) {
+ return request.get(`/admin/export-score-rank/${group}`, {
+ params: { meta: 1 },
+ silent: true,
+ })
+}
+
+/**
+ * 下载成绩排名表(R220)
+ *
+ * 与另外两个导出产物的分工(⛔ 不可互相替代):
+ * · export-excel —— 内部核查表,全字段明细(含身份证号 / 手机号);
+ * · export-publicity —— 对外公示表,主办方模板、获奖等级列留空;
+ * · export-score-rank—— 排名速览表,一小组一行 + 区间底色 + 区间统计,无任何敏感字段。
+ *
+ * 下载动作由 `utils/download.js#safeDownload` 发起(三重校验),故只导出 URL。
+ * @param {string} group
+ * @returns {string} 下载 URL
+ */
+export function scoreRankExportUrl(group) {
+ return `/api/admin/export-score-rank/${group}`
+}
+
/**
* 读取赛项信息(赛项名称 / 赛项编号)
*
diff --git a/src/views/Admin.vue b/src/views/Admin.vue
index e26a0c1..35d7619 100644
--- a/src/views/Admin.vue
+++ b/src/views/Admin.vue
@@ -1015,6 +1015,23 @@
导出Excel
+
+ 导出排名表