chore: 清理测试脚本并更新插件文档

- 删除过时的测试脚本,包括测试配置、路由、API、积分、签到等文件
- 更新 PLUGINS.md 文档,重新组织插件结构,提供更清晰的功能说明和权限要求
- 改进文档格式,增加表格和详细说明,便于用户理解各插件功能
This commit is contained in:
2026-04-10 21:13:46 +08:00
parent b86cc009e9
commit 17dd19330e
8 changed files with 127 additions and 599 deletions

View File

@@ -2,174 +2,145 @@
## 项目概述
蛋定助手是一个基于NoneBot2框架开发的QQ机器人提供多种功能插件包括AI聊天、管理API、自动撤回消息等。该机器人主要面向特定用户群体提供游戏辅助和社群管理功能
蛋定助手是一个基于 NoneBot2 框架开发的 QQ 机器人,提供多种功能插件,包括 AI 聊天、游戏辅助、积分系统、社群管理
## 插件总览
| 插件名称 | 描述 | 权限要求 |
|---------|------|---------|
| chatai | AI聊天功能,对接DeepSeek | 所有用户 |
| auto_recall | 消息自动撤回 | 系统自动执行 |
| damo_balance | 大漠账户余额查询 | 特定用户 |
| danding_api | 蛋定助手管理API | 超级用户 |
| danding_help | 帮助信息 | 特定群用户 |
| command_list | 命令列表管理 | 系统使用 |
| 插件名称 | 描述 | 触发方式 | 权限要求 |
|---------|------|---------|---------|
| [chatai](#1-chatai---ai-聊天) | AI 聊天DeepSeek),支持图文回复 | `*` 开头消息 | 所有用户 |
| [auto_recall](#2-auto_recall---自动撤回) | 自动撤回机器人发送的消息 | 自动执行 | 系统自动 |
| [auto_friend_accept](#3-auto_friend_accept---自动接受好友) | 自动同意好友请求并发送欢迎语 | 自动执行 | 系统自动 |
| [welcome_plugin](#4-welcome_plugin---入群欢迎) | 新成员入群欢迎并发送帮助菜单 | 自动执行 | 特定群 (621016172) |
| [danding_qqpush](#5-danding_qqpush---消息推送) | 通过 HTTP API 向指定群推送图文通知 | HTTP POST | 接口 Token 验证 |
| [danding_points](#6-danding_points---积分系统核心) | 积分系统数据库与 API 核心 | API 调用 | 系统内部 |
| [danding_points_query](#7-danding_points_query---积分查询) | 查询余额、排行及交易记录 | 命令触发 | 所有用户 |
| [group_horse_racing](#8-group_horse_racing---群赛马游戏) | 多人赛马游戏,支持下注与积分奖惩 | 命令触发 | 允许的群聊 |
| [onmyoji_gacha](#9-onmyoji_gacha---阴阳师抽卡模拟) | 阴阳师主题抽卡,包含成就与卡密奖励 | 命令触发 | 允许的群聊/用户 |
| [damo_balance](#10-damo_balance---大漠账户查询) | 查询大漠平台账户余额 | 命令触发 | 特定用户 |
| [danding_api](#11-danding_api---管理-api) | 管理员操作:卡密管理、加时、在线查询 | 命令触发 | 超级用户 |
| [danding_help](#12-danding_help---帮助菜单) | 提供教程、下载及功能指引 | 命令触发 | 特定群 (621016172) |
| [command_list](#13-command_list---指令列表) | 获取系统支持的所有指令列表 | 命令触发 | 所有用户 |
---
## 详细插件文档
### 1. chatai - AI聊天插件
### 1. chatai - AI 聊天
#### 功能描述
基于DeepSeek AI的聊天功能支持将AI回复转换为图片形式并在一定时间后自动撤回。
基于 DeepSeek AI 的聊天功能,支持将回复转换为图片形式,并在一定时间后自动撤回。
#### 使用方法
- 发送以 `*` 开头的消息触发AI回复
- AI回复会自动转为图片显示
- 回复会在120秒后自动撤回
- **使用方法**: 发送以 `*` 开头的消息。
- **配置项**: `DEEPSEEK_TOKEN` (必填)。
- **特性**: AI 回复会自动转为图片显示,默认 120 秒后撤回。
#### 配置项
```env
DEEPSEEK_TOKEN=你的DeepSeek API密钥
```
### 2. auto_recall - 自动撤回
#### 技术实现
- 使用OpenAI客户端连接DeepSeek API
- 使用Pyppeteer将Markdown转为图片
- 内置Chrome浏览器实例管理
监控机器人发出的消息,并在指定时间后自动撤回,保持聊天环境整洁。
#### 示例
用户: *你好,请介绍一下自己
AI: [图片形式回复] 👋 你好呀我是蛋定助手一个活泼可爱的AI助手😊 很高兴认识你!有什么我能帮到你的吗?✨
- **配置项**:
- `RECALL_DELAY`: 普通消息撤回延迟(默认 110s
- `QQPUSH_RECALL_DELAY`: 推送消息撤回延迟(默认 3600s
### 3. auto_friend_accept - 自动接受好友
自动处理好友请求,提升用户接入效率。
- **配置项**:
- `auto_accept_enabled`: 是否开启自动接受。
- `auto_reply_message`: 接受后的欢迎语。
### 4. welcome_plugin - 入群欢迎
针对特定群聊的新成员欢迎功能。
- **触发场景**: 新成员加入群 `621016172`
- **功能**: 随机发送欢迎语,并附带帮助菜单图片。
### 5. danding_qqpush - 消息推送
提供外部系统向 QQ 推送通知的 HTTP 接口。
- **接口**: `POST /danding/qqpush/{token}`
- **功能**: 自动将长文本转换为图片,支持 `@用户` 和换行符 `#`
- **配置**: `DANDING_QQPUSH_TOKEN`
### 6. danding_points - 积分系统核心
为其他插件提供积分存储与结算的基础设施。
- **功能**: 数据库管理SQLite、余额增减、排行榜计算、交易日志记录。
- **数据库路径**: `data/danding_points/points.db`
### 7. danding_points_query - 积分查询
用户通过命令与积分系统交互。
- **主要命令**:
- `我的积分`: 查看个人余额。
- `积分查询 @用户`: 查看他人余额。
- `积分排行`: 查看前 10 名。
- `积分历史查询`: 查看最近 5 条变动记录。
- `积分帮助`: 获取指令指引。
### 8. group_horse_racing - 群赛马游戏
集成积分系统的多人互动游戏。
- **主要命令**:
- `/赛马报名 [马名]`: 参加比赛。
- `/赛马下注 <序号> <金额>`: 对马匹下注。
- `/赛马开赛`: 开始比赛(至少 2 人)。
- **积分逻辑**: 参赛奖励 50 分,冠军奖励 200 分,支持下注赔率结算。
### 9. onmyoji_gacha - 阴阳师抽卡模拟
高度还原的抽卡模拟,包含成就系统。
- **主要命令**:
- `抽卡`: 执行单抽。
- `三连抽`: 执行三连抽。
- `我的抽卡`: 查看个人统计。
- `查询成就`: 查看已解锁成就及进度(非酋、勤勤恳恳系列)。
- `抽卡介绍`: 查看详细机制与奖励说明。
- **特性**: 抽中 SSR/SP 可获得“蛋定助手”卡密奖励(需联系管理员领取)。包含每日抽卡签到积分奖励。
### 10. damo_balance - 大漠账户查询
查询大漠平台账户余额。
- **命令**: `大漠余额``余额查询`
- **限制**: 仅特定用户可用,需输入验证码。
### 11. danding_api - 管理 API
供超级用户使用的后台管理功能。
- **主要命令**:
- `在线人数`: 查询当前活跃用户。
- `生成卡密 <类型>`: 生成天/周/月卡。
- `用户加时 <用户名> <类型>`: 直接为特定用户增加时长。
### 12. danding_help - 帮助菜单
系统的官方指引手册。
- **主要命令**: `帮助``下载``正式版如何运行` 等。
- **限制**: 仅在特定群 `621016172` 可用。
### 13. command_list - 指令列表
快速查阅所有可用指令。
- **命令**: `指令列表`
---
### 2. auto_recall - 自动撤回插件
## 常见问题 (FAQ)
#### 功能描述
监控所有发出的消息,并在指定时间后自动撤回,保持聊天环境整洁。
#### 使用方法
- 无需手动调用,插件会自动监控并撤回消息
#### 配置项
```env
RECALL_DELAY=110 # 撤回延迟时间,单位为秒
```
#### 技术实现
- 使用NoneBot的API拦截功能
- 异步定时任务管理
- 错误处理与日志记录
---
### 3. damo_balance - 大漠账户余额查询
#### 功能描述
查询大漠平台账户余额,需要验证码验证。
#### 使用方法
- 命令:`大漠余额``余额查询`
- 需要验证码验证
#### 权限要求
- 仅特定用户(ID:1424473282)可使用
---
### 4. danding_api - 蛋定助手管理API
#### 功能描述
提供管理员操作接口,包括在线人数查询、卡密管理和用户时长管理功能。
#### 使用方法
主要命令:
- `在线人数`:查询当前在线用户数
- `添加卡密 [类型] [卡密]`:添加指定类型的卡密
- `生成卡密 [类型]`:生成新卡密
- `用户加时 [用户名] [类型]`:为指定用户增加使用时长
#### 卡密类型
- 天卡/day/Day/DAY/天
- 周卡/week/Week/WEEK/周
- 月卡/month/Month/MONTH/月
#### 权限要求
- 仅超级用户可使用
#### 配置项
```env
SUPERUSERS=["1424473282"] # 超级用户ID列表
```
#### 示例
```
在线人数
> 当前在线用户数: 42
添加卡密 天卡 ABCD1234
> 添加卡密成功:天卡 ABCD1234
生成卡密 周卡
> 生成卡密成功:周卡 XYZ789ABC
用户加时 test_user 月卡
> 用户加时成功test_user 增加了30天
```
---
### 5. danding_help - 帮助信息
#### 功能描述
提供各种帮助信息和指南,支持图片形式的教程和指引。
#### 使用方法
主要命令:
- `帮助`:显示帮助菜单
- `下载`:显示下载信息
- `公益版`/`正式版`:显示版本信息
- `正式版御魂双开`:显示双开教程
- `正式版如何运行`:显示运行教程
- `正式版内测计划`:显示内测信息
#### 权限要求
- 仅在特定群(621016172)可用
#### 技术实现
- 使用图片回复提供直观的教程
- 文本与图片混合响应
---
### 6. command_list - 命令列表管理
#### 功能描述
管理系统命令列表,提供命令过滤和权限控制。
#### 使用方法
- 系统内部使用,不直接暴露给用户
## 常见问题
### Q1: 如何启动蛋定助手?
A1: 使用`nb run`命令启动,确保已安装所有依赖。
### Q2: 机器人回复后自动撤回的时间可以修改吗?
A2: 可以,在`.env`文件中修改`RECALL_DELAY`的值(单位为秒)。
### Q3: 如何成为超级用户?
A3: 在`.env`文件的`SUPERUSERS`列表中添加您的QQ号。
### Q4: AI聊天功能如何配置
A4: 需要在`.env`文件中设置`DEEPSEEK_TOKEN`填入您的DeepSeek API密钥。
### Q5: 为什么帮助命令在某些群不可用?
A5: 帮助命令仅在特定群(621016172)内可用,这是一种权限控制机制。
## 技术支持
如有问题,可以:
1. 在群内@机器人并提问
2. 访问帮助文档https://www.danding.icu
3. 联系超级用户获取支持
- **Q: 为什么某些命令没反应?**
A: 部分插件(如 `danding_help`)限制了特定群聊使用;管理指令需要配置 `SUPERUSERS`
- **Q: 积分有什么用?**
A: 目前主要用于赛马下注及展示排名。
- **Q: 抽卡奖励如何领取?**
A: 抽中 SSR/SP 或解锁特定成就后,请截屏联系管理员。

View File

@@ -1,73 +0,0 @@
#!/usr/bin/env python3
"""
测试 onmyoji_gacha Web API
"""
import requests
import json
# API 配置
BASE_URL = "http://localhost:8080"
API_BASE = f"{BASE_URL}/onmyoji_gacha/api"
ADMIN_TOKEN = "onmyoji_admin_token_2024"
# 请求头
headers = {
"Authorization": f"Bearer {ADMIN_TOKEN}",
"Content-Type": "application/json"
}
def test_api():
print("🧪 测试 onmyoji_gacha Web API")
print("=" * 50)
# 测试每日统计
print("\n📊 测试每日统计 API...")
try:
response = requests.get(f"{API_BASE}/stats/daily", headers=headers)
print(f"状态码: {response.status_code}")
if response.status_code == 200:
data = response.json()
print(f"响应: {json.dumps(data, indent=2, ensure_ascii=False)}")
else:
print(f"错误: {response.text}")
except Exception as e:
print(f"请求失败: {e}")
# 测试排行榜
print("\n🏆 测试排行榜 API...")
try:
response = requests.get(f"{API_BASE}/stats/rank", headers=headers)
print(f"状态码: {response.status_code}")
if response.status_code == 200:
data = response.json()
print(f"响应: {json.dumps(data, indent=2, ensure_ascii=False)}")
else:
print(f"错误: {response.text}")
except Exception as e:
print(f"请求失败: {e}")
# 测试用户统计使用示例用户ID
print("\n👤 测试用户统计 API...")
try:
test_user_id = "123456789" # 示例用户ID
response = requests.get(f"{API_BASE}/stats/user/{test_user_id}", headers=headers)
print(f"状态码: {response.status_code}")
if response.status_code == 200:
data = response.json()
print(f"响应: {json.dumps(data, indent=2, ensure_ascii=False)}")
else:
print(f"错误: {response.text}")
except Exception as e:
print(f"请求失败: {e}")
# 测试无令牌访问
print("\n🔒 测试无令牌访问...")
try:
response = requests.get(f"{API_BASE}/stats/daily")
print(f"状态码: {response.status_code}")
print(f"响应: {response.text}")
except Exception as e:
print(f"请求失败: {e}")
if __name__ == "__main__":
test_api()

View File

@@ -1,25 +0,0 @@
#!/usr/bin/env python3
import os
import sys
# Print environment variables
print("=== Environment Variables ===")
for key in os.environ:
if "GROUP_HORSE_RACING" in key:
print(f"{key}={os.environ[key]}")
print("\n=== Loading Config ===")
from danding_bot.plugins.group_horse_racing.config import Config
config = Config()
print(f"TEST_MODE: {config.TEST_MODE} (type: {type(config.TEST_MODE).__name__})")
print(f"TESTERS: {config.TESTERS} (type: {type(config.TESTERS).__name__})")
print(f"TEST_GROUPS: {config.TEST_GROUPS} (type: {type(config.TEST_GROUPS).__name__})")
print(f"ALLOWED_GROUPS: {config.ALLOWED_GROUPS} (type: {type(config.ALLOWED_GROUPS).__name__})")
print("\n=== Testing Permission Check ===")
test_user_id = 1424473282
print(f"Test user_id: {test_user_id}")
print(f"Is in TESTERS: {test_user_id in config.TESTERS}")
print(f"TEST_MODE enabled: {config.TEST_MODE}")
print(f"Should have access: {config.TEST_MODE and test_user_id in config.TESTERS}")

View File

@@ -1,71 +0,0 @@
#!/usr/bin/env python3
"""Manual test script for danding_points plugin."""
import asyncio
import sys
from pathlib import Path
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from danding_bot.plugins.danding_points import points_api
async def test_basic_operations():
"""Test basic points operations."""
print("Testing basic operations...")
# Test 1: Get balance for non-existent user
balance = await points_api.get_balance("test_user_1")
assert balance == 0, f"Expected 0, got {balance}"
print("✓ Non-existent user returns 0 balance")
# Test 2: Add points (auto-create user)
success, new_balance = await points_api.add_points(
"test_user_1", 100, "test_source", "test reason"
)
assert success and new_balance == 100, f"Add failed: {success}, {new_balance}"
print("✓ Add points works and auto-creates user")
# Test 3: Get balance after add
balance = await points_api.get_balance("test_user_1")
assert balance == 100, f"Expected 100, got {balance}"
print("✓ Balance updated correctly")
# Test 4: Spend points
success, new_balance = await points_api.spend_points(
"test_user_1", 30, "test_source", "spend reason"
)
assert success and new_balance == 70, f"Spend failed: {success}, {new_balance}"
print("✓ Spend points works")
# Test 5: Spend more than balance (should fail)
success, new_balance = await points_api.spend_points(
"test_user_1", 100, "test_source", "should fail"
)
assert not success, "Should fail when spending more than balance"
print("✓ Spend fails when insufficient balance")
# Test 6: Set points
success, new_balance = await points_api.set_points(
"test_user_1", 50, "test_source", "set reason"
)
assert success and new_balance == 50, f"Set failed: {success}, {new_balance}"
print("✓ Set points works")
# Test 7: Get transactions
transactions = await points_api.get_transactions("test_user_1", limit=10)
assert len(transactions) > 0, "Should have transactions"
print(f"✓ Get transactions works ({len(transactions)} transactions)")
# Test 8: Get ranking
ranking = await points_api.get_ranking(limit=10)
assert len(ranking) > 0, "Should have ranking entries"
assert "rank" in ranking[0], "Ranking should have rank field"
print(f"✓ Get ranking works ({len(ranking)} entries)")
print("\n✅ All tests passed!")
if __name__ == "__main__":
asyncio.run(test_basic_operations())

View File

@@ -1,95 +0,0 @@
import tempfile
import unittest
import importlib.util
import sys
import types
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent
def ensure_package(package_name: str, package_path: Path) -> None:
if package_name in sys.modules:
return
package = types.ModuleType(package_name)
package.__path__ = [str(package_path)]
sys.modules[package_name] = package
def load_module(module_name: str, relative_path: str):
module_path = PROJECT_ROOT / relative_path
spec = importlib.util.spec_from_file_location(module_name, module_path)
module = importlib.util.module_from_spec(spec)
assert spec and spec.loader
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module
ensure_package("danding_bot", PROJECT_ROOT / "danding_bot")
ensure_package("danding_bot.plugins", PROJECT_ROOT / "danding_bot/plugins")
ensure_package(
"danding_bot.plugins.onmyoji_gacha",
PROJECT_ROOT / "danding_bot/plugins/onmyoji_gacha",
)
load_module(
"danding_bot.plugins.onmyoji_gacha.config",
"danding_bot/plugins/onmyoji_gacha/config.py",
)
data_manager_module = load_module(
"danding_bot.plugins.onmyoji_gacha.data_manager",
"danding_bot/plugins/onmyoji_gacha/data_manager.py",
)
utils = load_module(
"danding_bot.plugins.onmyoji_gacha.utils",
"danding_bot/plugins/onmyoji_gacha/utils.py",
)
class DataManagerSignInTests(unittest.TestCase):
def setUp(self) -> None:
self.temp_dir = tempfile.TemporaryDirectory()
base_path = Path(self.temp_dir.name)
self.original_db_file = data_manager_module.config.DB_FILE
self.original_img_dir = data_manager_module.config.SHIKIGAMI_IMG_DIR
data_manager_module.config.DB_FILE = str(base_path / "gacha.db")
data_manager_module.config.SHIKIGAMI_IMG_DIR = str(base_path / "images")
Path(data_manager_module.config.SHIKIGAMI_IMG_DIR).mkdir(parents=True, exist_ok=True)
self.manager = data_manager_module.DataManager()
def tearDown(self) -> None:
data_manager_module.config.DB_FILE = self.original_db_file
data_manager_module.config.SHIKIGAMI_IMG_DIR = self.original_img_dir
self.temp_dir.cleanup()
def test_record_sign_in_is_idempotent_for_same_day(self) -> None:
user_id = "10001"
self.assertFalse(self.manager.has_signed_in_today(user_id))
self.assertTrue(self.manager.record_sign_in(user_id, 88))
self.assertTrue(self.manager.has_signed_in_today(user_id))
self.assertFalse(self.manager.record_sign_in(user_id, 99))
class UtilsSignInTests(unittest.TestCase):
def test_get_luck_description_uses_document_ranges(self) -> None:
self.assertEqual(utils.get_luck_description(1), ("非酋", "😭"))
self.assertEqual(utils.get_luck_description(11), ("一般", "😐"))
self.assertEqual(utils.get_luck_description(31), ("小欧", "😊"))
self.assertEqual(utils.get_luck_description(61), ("大欧", "🎉"))
self.assertEqual(utils.get_luck_description(91), ("欧皇", "👑"))
def test_format_sign_in_message_matches_required_format(self) -> None:
message = utils.format_sign_in_message("10001", "小夏", 87, 1247)
expected = (
"@小夏 📅 每日签到成功!\n"
"🎁 获得积分87\n"
"🎉 今日运气:大欧\n"
"💰 当前积分1247"
)
self.assertEqual(message, expected)
if __name__ == "__main__":
unittest.main()

View File

@@ -1,49 +0,0 @@
"""Danding_QqPush 插件测试脚本"""
import requests
import json
def test_qqpush_api():
"""测试 QQ 推送 API"""
# 配置
base_url = "http://localhost:8080" # NoneBot 默认端口
token = "danding-8HkL9xQ2" # 默认 Token
# 构造请求数据
data = {
"group_id": 574727392, # 替换为实际群号
"qq": 1424473282, # 替换为实际 QQ 号
"text": "系统告警#数据库连接失败#请立即处理#测试消息"
}
# 发送请求
url = f"{base_url}/danding/qqpush/{token}"
print(f"正在测试 API: {url}")
print(f"请求数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
try:
response = requests.post(
url,
json=data,
headers={"Content-Type": "application/json"},
timeout=10
)
print(f"\n响应状态码: {response.status_code}")
print(f"响应内容: {json.dumps(response.json(), ensure_ascii=False, indent=2)}")
if response.status_code == 200:
print("\n✅ 测试成功!")
else:
print(f"\n❌ 测试失败,状态码: {response.status_code}")
except requests.exceptions.ConnectionError:
print("\n❌ 连接失败,请确认 NoneBot 是否已启动")
except Exception as e:
print(f"\n❌ 测试异常: {str(e)}")
if __name__ == "__main__":
test_qqpush_api()

View File

@@ -1,47 +0,0 @@
#!/usr/bin/env python3
"""
测试 onmyoji_gacha Web API 路由是否正确注册
"""
import sys
import os
# 添加项目路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'danding_bot'))
# 设置环境变量
os.environ.setdefault("ENVIRONMENT", "dev")
try:
# 模拟 NoneBot 环境
from nonebot import get_driver
from nonebot import init
# 初始化 NoneBot
init()
# 尝试获取驱动
driver = get_driver()
print(f"✅ 成功获取驱动: {type(driver)}")
# 检查是否有 server_app 属性
if hasattr(driver, 'server_app'):
print(f"✅ 找到 server_app: {type(driver.server_app)}")
# 检查路由是否已注册
app = driver.server_app
routes = app.routes
print(f"✅ 当前注册的路由数量: {len(routes)}")
# 查找我们的路由
onmyoji_routes = [route for route in routes if hasattr(route, 'path') and '/onmyoji_gacha' in str(route.path)]
print(f"✅ 找到 onmyoji_gacha 路由: {len(onmyoji_routes)}")
for route in onmyoji_routes:
print(f" - {route.path} ({route.methods if hasattr(route, 'methods') else 'N/A'})")
else:
print("❌ 驱动没有 server_app 属性")
except Exception as e:
print(f"❌ 测试失败: {e}")
import traceback
traceback.print_exc()

View File

@@ -1,83 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>令牌测试页面</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h4>管理员令牌测试</h4>
</div>
<div class="card-body">
<div class="mb-3">
<label for="tokenInput" class="form-label">管理员令牌</label>
<input type="text" class="form-control" id="tokenInput" placeholder="请输入管理员令牌">
<small class="text-muted">正确的令牌应该是: onmyoji_admin_token_2024</small>
</div>
<button class="btn btn-primary" onclick="testToken()">测试令牌</button>
<div id="result" class="mt-3"></div>
</div>
</div>
</div>
</div>
</div>
<script>
async function testToken() {
const token = document.getElementById('tokenInput').value.trim();
const resultDiv = document.getElementById('result');
if (!token) {
resultDiv.innerHTML = '<div class="alert alert-warning">请输入令牌</div>';
return;
}
resultDiv.innerHTML = '<div class="alert alert-info">正在测试...</div>';
try {
const response = await fetch('/onmyoji_gacha/api/stats/daily', {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
console.log('响应状态:', response.status);
console.log('响应头:', response.headers);
if (response.ok) {
const data = await response.json();
resultDiv.innerHTML = `
<div class="alert alert-success">
<h5>✅ 令牌验证成功!</h5>
<pre>${JSON.stringify(data, null, 2)}</pre>
</div>
`;
} else {
const errorText = await response.text();
resultDiv.innerHTML = `
<div class="alert alert-danger">
<h5>❌ 令牌验证失败</h5>
<p>状态码: ${response.status}</p>
<p>错误信息: ${errorText}</p>
</div>
`;
}
} catch (error) {
resultDiv.innerHTML = `
<div class="alert alert-danger">
<h5>❌ 请求失败</h5>
<p>${error.message}</p>
</div>
`;
}
}
</script>
</body>
</html>