From aab9da4f3109a4b50a512ac29b12b071d60c051b Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 12 Jun 2026 02:11:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E6=96=B0=E6=97=B6?= =?UTF-8?q?=E7=A9=BA=E6=95=B0=E6=8D=AE=E5=BA=94=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.example | 9 + .gitignore | 13 + Dockerfile | 16 + README.md | 102 +++ app/__init__.py | 1 + app/data.py | 841 ++++++++++++++++++++ app/main.py | 608 ++++++++++++++ app/static/accounts.html | 60 ++ app/static/accounts.js | 116 +++ app/static/app.js | 458 +++++++++++ app/static/index.html | 115 +++ app/static/styles.css | 695 ++++++++++++++++ docker-compose.yml | 18 + launchd/com.xsk.records.sync.plist.template | 26 + requirements.txt | 2 + scripts/deploy_to_vps.py | 148 ++++ scripts/install_launch_agent.py | 60 ++ scripts/sync_to_vps.py | 204 +++++ 18 files changed, 3492 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 app/__init__.py create mode 100644 app/data.py create mode 100644 app/main.py create mode 100644 app/static/accounts.html create mode 100644 app/static/accounts.js create mode 100644 app/static/app.js create mode 100644 app/static/index.html create mode 100644 app/static/styles.css create mode 100644 docker-compose.yml create mode 100644 launchd/com.xsk.records.sync.plist.template create mode 100644 requirements.txt create mode 100755 scripts/deploy_to_vps.py create mode 100755 scripts/install_launch_agent.py create mode 100755 scripts/sync_to_vps.py diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..27b6947 --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +APP_PORT=18080 +TZ=Asia/Shanghai +PYTHON_IMAGE=python:3.12-slim + +BASIC_AUTH_USERNAME=wolfydw +BASIC_AUTH_PASSWORD=change-me + +CLASSNOTES_PATH=/data/classnotes.txt +ACCOUNTS_PATH=/data/学生课时账户.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6d9b43a --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.env +.env.* +!.env.example +*.log +__pycache__/ +*.py[cod] +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.venv/ +venv/ +data/ +.DS_Store diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c64e1a1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +ARG PYTHON_IMAGE=python:3.12-slim +FROM ${PYTHON_IMAGE} + +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY app ./app + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..4242013 --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +# 新时空课程记录查询网页 + +这是一个只读查询工具,用于把本机正式业务源中的 `classnotes.txt` 和 `学生课时账户.md` 同步到 VPS,并通过网页查询上课记录和课时账户。 + +## 目录 + +- `app/`:FastAPI 后端和内置前端页面。 +- `scripts/deploy_to_vps.py`:部署网页服务到 VPS。 +- `scripts/sync_to_vps.py`:同步正式数据文件到 VPS。 +- `scripts/install_launch_agent.py`:安装 Mac 开机常驻同步任务。 +- `launchd/com.xsk.records.sync.plist.template`:LaunchAgent 模板。 + +## 首次部署 + +推荐先配置 SSH key。若临时使用密码,可通过环境变量传入,不要写入仓库文件。 + +```bash +cd /Users/yangdawei/Desktop/新时空业务源数据/tools/xsk-records-web +XSK_USE_SSHPASS=1 \ +XSK_SSH_PASSWORD='填写SSH密码' \ +XSK_WEB_PASSWORD='填写网页访问密码' \ +python3 scripts/deploy_to_vps.py --use-sshpass +``` + +默认访问地址: + +```text +http://121.199.172.246:18080/ +``` + +默认网页用户名为 `wolfydw`。网页密码只写入 VPS 的 `/root/新时空数据/app/.env`,不会提交进 Git。 + +如果 VPS 无法访问 Docker Hub,部署脚本会默认使用 `swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/python:3.12-slim` 作为基础镜像。需要更换时设置: + +```bash +XSK_PYTHON_IMAGE='python:3.12-slim' +``` + +## 手动同步数据 + +```bash +XSK_USE_SSHPASS=1 \ +XSK_SSH_PASSWORD='填写SSH密码' \ +python3 scripts/sync_to_vps.py --once --use-sshpass +``` + +同步文件: + +- `/Users/yangdawei/Desktop/新时空业务源数据/新时空课程记录与课时账户/classnotes.txt` +- `/Users/yangdawei/Desktop/新时空业务源数据/新时空课程记录与课时账户/学生课时账户.md` + +远端数据目录: + +```text +/root/新时空数据/data/ +``` + +## 安装自动同步 + +```bash +XSK_USE_SSHPASS=1 \ +XSK_SSH_PASSWORD='填写SSH密码' \ +python3 scripts/install_launch_agent.py --use-sshpass +``` + +日志位置: + +```text +~/Library/Logs/xsk-records-web/sync.log +~/Library/Logs/xsk-records-web/sync.err.log +``` + +查看任务: + +```bash +launchctl list | grep com.xsk.records.sync +``` + +卸载任务: + +```bash +launchctl unload ~/Library/LaunchAgents/com.xsk.records.sync.plist +rm ~/Library/LaunchAgents/com.xsk.records.sync.plist +``` + +## 更换网页访问密码 + +登录 VPS 后修改 `/root/新时空数据/app/.env` 中的 `BASIC_AUTH_PASSWORD`,然后重启: + +```bash +cd /root/新时空数据/app +docker compose up -d +``` + +## API + +- `GET /api/health`:数据状态。 +- `GET /api/records?q=王鑫鹏5月数学课`:自然语言查询上课记录。 +- `GET /api/accounts`:课时账户列表。 +- `GET /api/accounts?q=王鑫鹏`:按学生筛选账户。 +- `GET /api/accounts?status=欠费`:按账户状态筛选。 +- `GET /api/accounts/王鑫鹏`:单个学生账户。 diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1 @@ + diff --git a/app/data.py b/app/data.py new file mode 100644 index 0000000..636650e --- /dev/null +++ b/app/data.py @@ -0,0 +1,841 @@ +from __future__ import annotations + +from collections import defaultdict +from dataclasses import dataclass, replace +from datetime import date, datetime, timedelta +import os +import re +from pathlib import Path +import tempfile +from typing import Iterable + + +SUBJECTS = ["数学", "语文", "英语", "物理", "化学", "生物", "历史", "地理", "政治", "道法"] +SUBJECT_ALIASES = { + "数": "数学", + "语": "语文", + "英": "英语", + "物": "物理", + "化": "化学", + "生": "生物", + "史": "历史", + "地": "地理", + "政": "政治", +} +FALLBACK_ALIASES = { + "施亿涵": "施忆涵", + "施凯其": "施凯萁", + "宇浩": "黄宇澔", + "肖恒罄": "肖恒馨", +} +CLASSNOTE_RE = re.compile( + r"^(?P\d{4}\.\d{2}\.\d{2})-" + r"(?P星期[一二三四五六日])-" + r"(?P