Logo 晴发文

也无风雨也无晴 · 智能分级 · 一键发文

🏆 排行榜

加载中...

📊 难度分布

未加载

点击"发文"按钮获取文段

选择书籍和难度后,点击发文即可

📜 发文历史(最近30条)

暂无发文记录

🏆 赛文管理

赛文列表

加载中...

今日赛文

加载中...

历史文章

请先选择赛文

📡 API接口地址

服务器地址:http://your-server:8000

🔑 1. 获取公钥

客户端首先需要获取服务器的RSA公钥用于加密:

GET /api/race/public_key

返回:
{
    "public_key": "-----BEGIN RSA PUBLIC KEY-----\\n...\\n-----END RSA PUBLIC KEY-----"
}

📋 2. 获取赛文列表

获取所有启用的赛文(返回数据已加密):

GET /api/race/list

返回(加密):
{
    "encrypted_data": "base64加密字符串"
}

解密后:
{
    "success": true,
    "races": [
        {
            "id": 1,
            "name": "每日赛文",
            "difficulty_group": 3,
            "allow_resubmit": false
        }
    ]
}

📝 3. 初始化赛文挑战

GET /api/race/init?raceId={raceId}
Authorization: Bearer {token}

参数:
- raceId: 赛文ID(必填)

返回:
{
    "version": "1",
    "algorithm": "RSA-OAEP-256+A256GCM",
    "issuedAt": 1710000000000,
    "contentType": "application/json",
    "encryptedKey": "Base64(RSA-OAEP(AESKey))",
    "iv": "Base64(GCM IV)",
    "encryptedData": "Base64(AES-GCM(JSON payload))"
}

解密后的 payload:
{
    "raceId": 1,
    "articleId": 12,
    "content": "今日赛文正文",
    "sessionNonce": "一次性challenge",
    "issuedAt": 1710000000000,
    "expireAt": 1710000600000,
    "serverPublicKey": "Base64服务器公钥",
    "keyId": "当前服务器密钥标识"
}

说明:
- /api/race/init 的 HTTP 响应不再直接暴露 content
- 客户端先调用 init 获取加密 envelope,再使用本地赛文私钥解密出文章、challenge 和服务器公钥
- sessionNonce 仅可使用一次,过期或用过后需要重新初始化

📤 4. 提交成绩

POST /api/race/submit
Authorization: Bearer {token}

请求体:
{
    "raceId": 1,
    "userId": 1,
    "encryptedData": "Base64(RSA-OAEP(payload))",
    "signature": "Base64(客户端RSA签名)",
    "clientTs": 1710000000000,
    "keyId": "当前服务器密钥标识"
}

其中 payload 明文为:
{
    "raceId": 1,
    "articleId": 12,
    "speed": 120.5,
    "accuracy": 98.6,
    "sessionNonce": "init 返回的一次性 challenge",
    "clientTs": 1710000000000
}

说明:
- userId 为兼容字段,可不传;如果传了必须与当前登录用户一致
- 服务端会解密 encryptedData、校验 sessionNonce/clientTs/articleId/raceId,并使用注册时保存的客户端公钥验签
- challenge 只允许成功消费一次

📜 5. 获取历史文章列表

GET /api/race/articles?race_id={race_id}&page={page}&page_size={page_size}

参数:
- race_id: 赛文ID(必填)
- page: 页码,从1开始(可选,默认1)
- page_size: 每页数量(可选,默认30,最大100)

返回:
{
    "success": true,
    "msg": "获取成功",
    "articles": [
        {
            "id": 1,
            "date": "2024-01-01",
            "difficulty": 2.8,
            "difficulty_level": "难",
            "book_name": "红楼梦",
            "char_count": 500,
            "created_at": "2024-01-01 00:00:00"
        }
    ],
    "total": 100,  // 总文章数
    "page": 1,     // 当前页
    "page_size": 30,
    "total_pages": 4  // 总页数
}

⚠️ 注意:此接口仅限本机或内网访问

🏆 6. 获取排行榜

GET /api/race/leaderboard?race_id={race_id}&date_str={date}&limit={limit}

参数:
- race_id: 赛文ID(必填)
- date_str: 日期(可选,格式YYYY-MM-DD,不传则为今天)
- limit: 返回记录数(可选,默认100)

返回(加密):
{
    "encrypted_data": "base64加密字符串"
}

解密后:
{
    "success": true,
    "msg": "获取成功",
    "date": "2024-01-01",
    "leaderboard": [
        {
            "username": "用户名",
            "speed": 120.5,
            "time_cost": 248500,
            "char_count": 500,
            "keystroke": 150.0,
            "code_length": 2.5,
            "backspace_count": 10,
            "key_count": 1250,
            "key_accuracy": 95.5,
            "word_rate": 60.0,
            "input_method": "搜狗拼音",
            "submit_time": "2024-01-01 12:00:00"
        }
    ]
}

说明:
- 排行榜按速度(speed)降序排列
- 如果速度相同,则按键准(key_accuracy)降序排列
- 每个用户只显示当天的最佳成绩

📊 7. 获取用户历史成绩

GET /api/race/history?userId={optionalCurrentUserId}
Authorization: Bearer {token}

参数:
- userId: 可选;不传时默认当前登录用户,传了也必须与当前登录用户一致

返回:
- 当前登录用户最近 100 条赛文成绩记录

🔒 协议说明

  • 统一使用 JWT 登录态识别当前用户
  • 客户端先通过 /api/race/init 获取加密 envelope,并在本地解密出正文与一次性 challenge
  • 响应正文使用 AES-GCM 加密,AES key 再使用客户端公钥做 RSA-OAEP 加密
  • 同一份 payload 还需要使用客户端私钥做 RSA-SHA256 签名
  • 服务端会校验 keyId、sessionNonce、clientTs 和注册时保存的客户端公钥

完整文档请查看项目中的 赛文API文档.md

📚 书籍管理

在这里管理书籍数据库、配置难度分级和处理书籍。

📏 文段默认字数
处理书籍时每段的默认字数
⚙️ 发文规则模式
控制发文时是否叠加系统规则(默认叠加)
🧰 规则编辑工作台
在预览卡片点“+添加”可快速插入模板到高级文本。
🔍 生效规则预览(系统 + 玩家)
下面展示的是当前会生效的规则集合,带来源标记(系统 / 玩家)。
加载中...
🧾 高级文本模式
使用分隔符批量编辑规则:按行分隔,字段用 |,替换规则用 =>
🔄 处理书籍(三阶段)
固定顺序:先准备(生成提示词)→ 再分类(写入分类)→ 最后入库分段。
三步是分开执行,不会自动串行。

👥 用户管理

⚙️ 账户设置

🔑 修改密码