Skip to content

开发指南 ​

编码与文件写入规范 ​

本仓库源码、YAML 配置和 Markdown 文档统一使用 UTF-8 保存。修改含中文、站点定义或长文档的文件时,优先使用 apply_patch 做局部补丁,避免用会整文件重写的脚本。

硬性要求:所有含中文的 Markdown、YAML 站点定义、JSON dump、配置示例和脚本注释都必须按 UTF-8 保存;任何 PR、补丁、脚本生成物都不能引入乱码。提交前若看到 �、问号替代中文、中文字段变成转义残片,先停止继续改动并恢复正确编码后再提交。

仓库根目录 .editorconfig 已设置 charset = utf-8,编辑器应启用 EditorConfig 支持,避免新建或保存文件时落成系统默认编码。

在 Windows PowerShell 中不要直接用未指定编码的 Set-Content、Add-Content、Out-File、重定向 > 批量重写 UTF-8 文件;确需使用时必须显式指定 UTF-8,并在修改后运行 go run ./tools/verify definitions 等校验。站点定义文件尤其要避免整文件读写过滤注释,防止隐藏换行或中文内容被转码成乱码。

必须由脚本写文件时,按下面方式显式写 UTF-8:

powershell
# PowerShell 7+
Set-Content -LiteralPath $path -Value $text -Encoding utf8NoBOM

# Windows PowerShell 5.1
[System.IO.File]::WriteAllText($path, $text, [System.Text.UTF8Encoding]::new($false))

提交前建议做一次乱码扫描,发现命中后人工确认:

powershell
rg -n "�|Ã|Â|锛|绋|涓|乱码" README backend frontend mobile

读取中文文件排查时可先设置终端编码:

powershell
chcp 65001
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
Get-Content -Encoding utf8 README\07-开发指南.md

项目结构 ​

D:\PTPatronus\
├── backend/              Go 后端(19 包 ~7500 行)
│   ├── cmd/ptpatronus/   入口(main.go)
│   ├── internal/         全部业务代码
│   ├── definitions/      站点定义 YAML(20 个)
│   └── configs/          config.example.yaml
├── frontend/             Vue3 Web UI(8 视图)
├── mobile/               Flutter 客户端
├── README/               本文档
├── Dockerfile            多阶段(前端→embed→后端→运行时)
├── docker-compose.yml
├── Makefile
└── .github/workflows/    CI(ci/docker/flutter-release)

常用命令 ​

bash
# 后端
cd backend && go run ./cmd/ptpatronus     # 启动
cd backend && go test ./...                # 全量测试
cd backend && go vet ./...                 # 静态检查

# 前端
cd frontend && npm run dev                 # 开发(:5173 代理 /api)
cd frontend && npm run build               # 构建

# Flutter
cd mobile && flutter analyze               # 零警告
cd mobile && flutter test                  # 测试
cd mobile && flutter run -d windows        # 运行

# Docker
make up                                    # 构建并启动
make image                                 # 仅构建镜像

# 一键
make test                                  # 全部测试(后端+前端+Flutter)
make embed-preview                         # 前端构建→拷入 embed 目录→本地验证

新增功能的原则(可维护性) ​

1. 优先复用现有模式 ​

要做什么用什么
新站点适配写 YAML 定义(definitions/),不改代码
新游戏实现 entertainment.LotteryGame 接口,注册到 app.go
新下载器类型实现 downloader.Downloader 接口,加到 manager.BuildClient
新通知通道实现 notification.Channel 接口,注册到 Manager
新定时任务scheduler.AddFunc,或加到 automation.Service
新 API 路由handler 放 api/v1/,路由挂到 api/router.go
新 Chain继承 chain.Base,通过 RunModule 调度

2. 文件组织 ​

  • 每个文件单一职责
  • 超过 ~400 行主动拆分(参考 qb/ 拆为 client.go + methods.go + convert.go)
  • 该规范已由门禁强制:scripts/check_file_length.sh 在 CI 与本地 pre-push 钩子运行; 现存超标文件冻结在 scripts/file_length_baseline.txt(棘轮:只许缩不许涨,新增超标即失败)。 新增/改动使文件超 400 行会被拦,拆分后重跑 bash scripts/check_file_length.sh init 刷新 baseline。
  • 通用工具集中(helpers.go / defaults.go / convert.go),不散落
  • 站点 YAML 极简(5 行),选择器自动填充

3. 测试 ​

  • 每个新包至少有一个 _test.go
  • HTTP 交互用 httptest(参考 qb/client_test.go, schemas/nexusphp_test.go)
  • DB 交互用内存 SQLite + t.Cleanup 关连接(Windows 文件锁)
  • 集成测试参考 api/integration_test.go(全栈 httptest)

4. 好学校准参考源 ​

  • 站点源码:F:\www.hxpt.org(NexusPHP 完整 PHP 源码)
  • 站点定义:backend/definitions/hxpt.yaml(VIP=APP专属VIP,头衔非类名)
  • 校准测试:internal/site/hxpt_calib_test.go(钉死选择器正确性)
  • 好学游戏:internal/entertainment/hxpt.go(jgg/magic_scratch/medal)
  • 好学签到:internal/site/schemas/checkin.go(attendance.php)

5. 财神参考源 ​

  • 站点源码:F:\cspt\cspt-web(Laravel PT,API + 插件层)
  • 信封:{ret:200|401, msg, data}(ret==200 为成功)
  • 财神游戏:internal/entertainment/cspt.go

环境要求 ​

工具版本
Go1.23+(本机 1.26.4)
Node18+(本机 24)
Flutter3.41+
Docker任意现代版本

Go 在 C:\Program Files\Go\bin(winget 安装)。bash 中需 export PATH="/c/Program Files/Go/bin:$PATH"。

添加新站点的完整流程 ​

  1. 写 5 行 YAML(definitions/xxx.yaml)
  2. 重启后端
  3. Web UI 添加站点(选定义 → 输入 cookie)
  4. 连接测试验证登录态
  5. 如果选择器不对 → /sites/inspect 在线试错 → 覆盖 YAML 中对应字段

好学 VIP 准入流程 ​

  1. 配置 AUTH_SITE_ENABLED=true
  2. 添加好学站点(cookie)
  3. POST /auth/verify-vip {cookie:"..."} → 后端抓好学用户页 → 判定等级文本是否含「APP专属VIP」
  4. auth.Guard 中间件:未通过 VIP 校验 → 限制访问