Просмотр исходного кода

docs: comprehensive README for server and client

nonvioce 3 месяцев назад
Родитель
Сommit
5b00ec25cf
2 измененных файлов с 344 добавлено и 11 удалено
  1. 159 11
      tiku-client/README.md
  2. 185 0
      tiku-server/README.md

+ 159 - 11
tiku-client/README.md

@@ -1,17 +1,165 @@
-# tiku_client
+# 题库PLUS 客户端
 
-A new Flutter project.
+C/S 架构数学题库管理系统 — Flutter 跨平台客户端(Android + Web)。
 
-## Getting Started
+## 构建
 
-This project is a starting point for a Flutter application.
+### 环境要求
 
-A few resources to get you started if this is your first Flutter project:
+- Flutter SDK ≥ 3.44
+- Android SDK 36+(compileSdk 36)
+- JDK 17
 
-- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
-- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
-- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
+### 调试构建
 
-For help getting started with Flutter development, view the
-[online documentation](https://docs.flutter.dev/), which offers tutorials,
-samples, guidance on mobile development, and a full API reference.
+```bash
+cd tiku-client
+flutter pub get
+flutter build apk --debug          # 调试版 APK(签名用 debug.keystore)
+flutter install -d <device_id>      # 安装到设备
+```
+
+### 发布构建(签名)
+
+```bash
+# 1. 准备签名文件
+cp key.jks android/app/key.jks
+cp keystore.properties android/app/keystore.properties
+
+# keystore.properties 格式:
+# storeFile=key.jks
+# storePassword=xxxxx
+# keyAlias=xxxxx
+# keyPassword=xxxxx
+
+# 2. 构建
+flutter build apk --release
+
+# 输出:build/app/outputs/flutter-apk/app-release.apk
+```
+
+> **注意**:`key.jks` 和 `keystore.properties` 已加入 `.gitignore`。
+
+### Web 构建(可选)
+
+```bash
+flutter build web --release
+# 产物在 build/web/,复制到服务端 tiku-server/web/ 目录
+```
+
+## 目录结构
+
+```
+lib/
+├── main.dart                    # 入口,ProviderScope 包裹
+├── app.dart                     # MaterialApp + 底部导航 Shell
+├── models/                      # 数据模型
+│   ├── problem.dart             # 题目(Problem, SearchResult)
+│   ├── knowledge.dart           # 知识点树节点
+│   ├── cart.dart                # 试题篮
+│   └── stats.dart               # 统计数据
+├── services/
+│   └── api_service.dart         # Dio HTTP 客户端 + HMAC 签名拦截器
+├── providers/
+│   └── app_provider.dart        # Riverpod Provider(连接状态、激活篮子)
+├── pages/
+│   ├── home/                    # 题库首页
+│   │   └── home_page.dart       # 三栏布局:知识树 | 题目列表 | 预览
+│   ├── search/                  # 搜索页
+│   │   └── search_page.dart     # FTS5 全文搜索
+│   ├── problem_detail/          # 题目详情
+│   │   └── problem_detail_page.dart  # 渲染预览 + 标注对话框
+│   ├── carts/                   # 试题篮
+│   │   ├── cart_list_page.dart  # 多篮管理 + 激活切换
+│   │   └── cart_detail_page.dart # 篮子详情 + 逐题移除
+│   ├── export/                  # 导出
+│   │   └── export_page.dart     # 生成学生版/教师版 docx
+│   ├── import_/                 # 导入
+│   │   └── import_page.dart     # 系统文件选择器 + 上传进度
+│   └── settings/                # 设置
+│       └── settings_page.dart   # 服务器地址 + Token 配置
+└── widgets/                     # 可复用组件
+    ├── knowledge_tree.dart      # 5层可折叠知识点树
+    ├── problem_card.dart        # 题目列表卡片(加入/移除篮按钮)
+    └── webview_render.dart      # WebView(Android)/ IFrame(Web)题目渲染
+```
+
+## 首次使用
+
+1. 打开应用 → 进入设置页
+2. 输入服务器地址(如 `http://数学.top:8765`)和 API Token
+3. 点击"连接"
+4. 连接成功后自动跳转到题库首页
+
+### 模拟器连接
+
+Android 模拟器访问宿主机使用 `http://10.0.2.2:8765`。
+
+## 功能导航
+
+| 标签 | 功能 |
+|------|------|
+| **题库** | 知识点树浏览 → 点击章节筛选题目 → 点击题目查看预览(公式+图片) → + 按钮加入试题篮 |
+| **搜索** | 输入关键词 → FTS5 全文搜索 → 点击结果查看详情 |
+| **试题篮** | 激活一个篮子(⚪→✓) → 查看/导出/删除篮子 |
+| **设置** | 服务器地址配置、断开连接 |
+
+## 试题篮激活机制
+
+1. 进入"试题篮"标签页
+2. 点击篮子右侧的 ⚪ 按钮激活(变为 ✓)
+3. 返回"题库"页,所有 + 按钮加入题目都进这个篮子
+4. 已加入的题目显示红色移除按钮
+5. 切换激活后所有按钮状态自动刷新
+
+## 导入题目
+
+1. 题库页右上角 + → 进入导入页
+2. 选择入库类型(精选题/经典题/高考题)
+3. 点击上传区域 → 系统文件选择器 → 选择 `.docx` 文件
+4. 点击"开始导入" → 实时查看进度条
+5. 导入完成后显示新增/跳过/错误统计
+
+## 题目渲染
+
+题目通过 WebView 加载服务端渲染的完整 HTML 页面(含 MathJax),支持:
+- 行内公式(`\(...\)` LaTeX 语法)
+- 行间公式
+- Base64 内嵌图片
+- 宋体中文排版
+- 答案/解析隐藏/显示切换
+
+## API 认证
+
+客户端通过 Dio 拦截器自动给每个请求添加签名头:
+
+```
+X-Timestamp: <unix_timestamp>
+X-Signature: HMAC-SHA256(token, METHOD+PATH+timestamp) → hex
+```
+
+签名在 Dio 拦截器中透明计算,业务代码无需关心。
+
+## 依赖
+
+| 包 | 用途 |
+|------|------|
+| `flutter_riverpod` | 状态管理 |
+| `dio` | HTTP 客户端 |
+| `webview_flutter` | WebView 题目渲染 |
+| `shared_preferences` | 服务器配置本地持久化 |
+| `crypto` | HMAC-SHA256 签名 |
+| `intl` | 国际化 |
+
+## Android 权限
+
+```xml
+<uses-permission android:name="android.permission.INTERNET"/>
+<application android:usesCleartextTraffic="true" ...>
+```
+
+网络访问 + 明文 HTTP(内网使用)。
+
+## 图标
+
+应用图标为蓝底白 Σ(求和符号),通过 Python PIL 生成各密度 PNG,含自适应图标前景层。

+ 185 - 0
tiku-server/README.md

@@ -0,0 +1,185 @@
+# 题库PLUS 服务端
+
+C/S 架构数学题库管理系统 — 服务端。Python + FastAPI + SQLite,以 docx 原生格式存储题目。
+
+## 快速部署
+
+```bash
+git clone ssh://git@xn--48s96u.top:10022/nonvioce/tiku.git /opt/tiku-server
+cd /opt/tiku-server/tiku-server
+bash install.sh          # 安装依赖、构建知识点
+nohup bash run.sh > tiku.log 2>&1 &   # 后台启动(崩溃/更新自动重启)
+```
+
+部署后打开 `http://<服务器IP>:8765`,使用 `./tiku-server token` 查看 API Token。
+
+## 目录结构
+
+```
+tiku-server/
+├── app/
+│   ├── config.py           # YAML 配置加载(路径、端口、Token)
+│   ├── database.py         # SQLite 连接、建表、CRUD、FTS5
+│   ├── models.py           # Pydantic 请求/响应模型
+│   ├── main.py             # FastAPI 入口 + CLI 入口
+│   ├── routers/            # API 路由层(仅参数校验和 HTTP 返回)
+│   │   ├── auth.py         # Token + HMAC 签名认证
+│   │   ├── problems.py     # 题目 CRUD、搜索、渲染、标注
+│   │   ├── import_.py      # 整卷 docx 上传拆分导入
+│   │   ├── export_.py      # 按章节/试题篮导出 docx
+│   │   ├── knowledge.py    # 知识点树浏览和搜索
+│   │   ├── carts.py        # 试题篮 CRUD
+│   │   └── admin.py        # 备份、索引重建、知识点构建、Git 更新
+│   └── services/           # 业务逻辑层
+│       ├── knowledge.py    # 5层知识点树解析(Markdown → 编码映射)
+│       ├── docx_parser.py  # 整卷 docx 拆分 + 单题 docx 生成
+│       ├── docx_builder.py # 多题 docx 合并导出
+│       ├── indexer.py      # 增量索引(mtime+checksum 检测变更)
+│       ├── renderer.py     # pandoc docx→HTML+MathJax 渲染管线
+│       ├── backup.py       # 本地备份 + WebDAV 远程推送
+│       └── search.py       # FTS5 全文搜索封装
+├── data/                   # 运行时数据(不提交 Git)
+│   ├── problems/           # 单题 docx(<sha256-8>.docx)
+│   ├── bank.db             # SQLite 数据库
+│   ├── papers/             # 导出试卷
+│   ├── backups/            # 自动备份(保留 30 个)
+│   └── uploads/            # 上传临时文件
+├── src/
+│   ├── 知识点树.md          # 5层 Markdown 知识树(1811 叶)
+│   └── knowledge_map.json  # 编码→路径映射(knowledge build 生成)
+├── web/                    # Flutter Web 构建产物(可选)
+├── config.yaml             # 配置文件
+├── install.sh              # 安装脚本
+├── run.sh                  # 启动+自动重启脚本
+├── tiku-server             # CLI 入口
+└── requirements.txt        # Python 依赖
+```
+
+## CLI 命令
+
+| 命令 | 说明 |
+|------|------|
+| `./tiku-server serve` | 启动 FastAPI 服务 |
+| `./tiku-server knowledge build` | 解析 `src/知识点树.md` 生成编码映射 |
+| `./tiku-server rebuild-index` | 手动增量扫描 problems/ 目录 |
+| `./tiku-server stats` | 终端显示题库统计 |
+| `./tiku-server backup` | 创建本地备份快照 |
+| `./tiku-server backup --remote` | 备份并推送到 WebDAV |
+| `./tiku-server token` | 显示 API Token |
+| `./tiku-server token regenerate` | 重新生成 Token |
+
+## API 参考
+
+### 认证
+
+所有需要认证的端点必须携带:
+- `Authorization: Bearer <token>`
+- `X-Timestamp: <unix_timestamp>`(5 分钟内有效)
+- `X-Signature: HMAC-SHA256(token, METHOD+PATH+timestamp)`(hex 编码)
+
+| 方法 | 路径 | 认证 | 说明 |
+|------|------|------|------|
+| GET | `/api/health` | 否 | 健康检查 |
+| POST | `/api/auth/verify` | 否 | 验证 Token |
+
+### 题库查询
+
+| 方法 | 路径 | 参数 | 说明 |
+|------|------|------|------|
+| GET | `/api/stats` | — | 仪表盘统计(总数、按题型/类型/章节分布) |
+| GET | `/api/problems` | `page`, `page_size`, `chapter`, `question_type`, `import_type`, `annotated` | 题目列表(分页+筛选) |
+| GET | `/api/problems/{id}` | — | 题目详情(含渲染 HTML) |
+| GET | `/api/problems/{id}/render` | `include_answer` | 题目 HTML 渲染片段(JSON) |
+| GET | `/api/problems/{id}/view` | `token`, `include_answer` | 题目完整 HTML 页面(IFrame 用,Token 在 URL 中) |
+| GET | `/api/problems/next-unannotated` | `current_id`, `direction` | 连续标注导航 |
+| GET | `/api/search` | `q`, `page`, `page_size` | 全文搜索(FTS5 trigram) |
+
+### 元数据编辑
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| PUT | `/api/problems/{id}/metadata` | 更新元数据(难度、题型、类型、评语) |
+| PUT | `/api/problems/{id}/knowledge` | 更新知识点编码 |
+
+### 导入导出
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| POST | `/api/import` | 上传整卷 docx(multipart: `file` + `import_type`) |
+| GET | `/api/import/{task_id}/status` | 轮询导入进度 |
+| POST | `/api/export/chapter` | 按章节+类型导出(JSON body: `chapter`, `import_type`, `title`) |
+| POST | `/api/export/cart/{id}` | 按试题篮导出 |
+| GET | `/api/exports/{filename}` | 下载导出 docx 文件 |
+
+### 知识点
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/knowledge/tree` | 完整知识树(5层嵌套 JSON) |
+| GET | `/api/knowledge/search` | 搜索知识点(`q` 参数) |
+
+### 试题篮
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/carts` | 篮子列表(含题目数量) |
+| POST | `/api/carts` | 创建篮子(JSON: `name`) |
+| DELETE | `/api/carts/{id}` | 删除篮子 |
+| GET | `/api/carts/{id}` | 篮子详情(含题目列表) |
+| POST | `/api/carts/{id}/items` | 添加题目(JSON: `problem_id`) |
+| DELETE | `/api/carts/{id}/items/{pid}` | 移除题目 |
+
+### 管理
+
+| 方法 | 路径 | 说明 |
+|------|------|------|
+| GET | `/api/admin/backup-config` | 查看 WebDAV 配置 |
+| PUT | `/api/admin/backup-config` | 设置 WebDAV(JSON: `url`, `username`, `password`) |
+| POST | `/api/admin/backup/trigger` | 手动触发备份 |
+| GET | `/api/admin/backup/history` | 备份历史 |
+| POST | `/api/admin/rebuild-index` | 增量重建索引 |
+| POST | `/api/admin/knowledge-build` | 重建知识点编码 |
+| POST | `/api/admin/git-update` | `git pull` + 自动重启 |
+
+## 单题 docx 格式
+
+```
+[题目正文段落(含 OMML 公式、图片、选项)]
+【答案】X                         ← 分割线
+【分析】解题思路...                (可选)
+【详解】详细步骤...                (可选)
+【点睛】...                       (可选)
+```
+
+自定义属性(`custom.xml`,Word 不可见):
+- `question_type`:单选题 / 多选题 / 填空题 / 解答题
+- `difficulty`:0~1 浮点数,越大越容易
+- `knowledge_codes`:JSON 数组,如 `["01.01.03.02.01"]`
+- `import_type`:精选题 / 经典题 / 高考题
+- `comment`:评语
+- `source`:来源文件名
+
+## 数据库结构
+
+```sql
+problems (id, file_path, mtime, checksum, chapters, difficulty,
+          question_type, import_type, knowledge_codes, comment, source, ...)
+
+problems_fts (problem_id, body) — FTS5 trigram 全文索引
+
+knowledge_points (code, path, leaf_name, chapter_code, chapter_name)
+
+carts (id, name, created_at)
+
+cart_items (cart_id, problem_id, added_at) — 联合主键
+
+import_tasks (id, status, total, completed, message, result)
+```
+
+## 域名转换
+
+中文域名 `数学.top` 的 punycode 编码为 `xn--48s96u.top`,在 Git remote 等处使用:
+
+```
+ssh://git@xn--48s96u.top:10022/nonvioce/tiku.git
+```