基于 MongoDB 的在线问卷系统。当前代码已经从 phase1 的“问卷中心”演进到 phase2 的“题目中心”实现,支持题目资产、版本、题库、问卷引用题目版本、跨问卷单题统计。
phase1 主要完成了问卷创建、题目编辑、跳转、填写和整卷统计;phase2 在保留这些主链能力的基础上,引入了题目资产、题目版本、题库和跨问卷单题统计,使系统从“问卷内部管理题目”演化为“题目资产驱动问卷编排”。
- 后端:Python + FastAPI + PyMongo
- 数据库:MongoDB
- 前端:Jinja2 服务端渲染 + 原生 JavaScript + Pico CSS
- 测试:pytest + FastAPI TestClient
前提:Python 3.10+,本地 MongoDB 运行在 mongodb://localhost:27017
pip install -r requirements.txt
uvicorn app.main:app --reload启动后访问:
- 首页:
http://localhost:8000 - Swagger:
http://localhost:8000/docs
可选环境变量:
| 变量 | 默认值 | 说明 |
|---|---|---|
MONGODB_URI |
mongodb://localhost:27017 |
MongoDB 连接字符串 |
DB_NAME |
survey_db |
主数据库名 |
SECRET_KEY |
dev-secret-key-... |
Session 签名密钥 |
pytest -q测试使用独立的 survey_test 数据库,当前回归结果为 93 passed。
测试覆盖包括:
- phase1 主链:问卷创建、发布、填写、整卷统计
- 跳转与校验:跳转路径、题型校验、排序后跳转重写
- phase2 主链:题目资产、版本恢复、题库、共享、跨问卷单题统计
project1/
├── app/
│ ├── main.py
│ ├── config.py
│ ├── database.py
│ ├── models/
│ │ ├── question.py
│ │ ├── response.py
│ │ ├── survey.py
│ │ └── user.py
│ ├── routes/
│ │ ├── auth.py
│ │ ├── pages.py
│ │ ├── question_banks.py
│ │ ├── questions.py
│ │ └── surveys.py
│ └── services/
│ ├── auth_service.py
│ ├── jump_service.py
│ ├── phase2_migration_service.py
│ ├── question_bank_service.py
│ ├── question_service.py
│ ├── response_service.py
│ ├── stats_service.py
│ ├── survey_service.py
│ └── validation_service.py
├── static/
│ ├── css/
│ └── js/
├── templates/
├── tests/
├── docs/
└── scripts/
关键目录职责:
app/models/:Pydantic 数据模型,包含 survey、response、question 等对象app/routes/:API 路由与页面路由app/services/:核心业务逻辑,包括题目资产、题库、答卷、统计、跳转和校验templates/:SSR 页面模板static/:前端脚本与样式docs/:系统说明、数据库设计、API、逻辑说明、测试文档scripts/:迁移与辅助脚本
- phase1 主链仍可用:问卷创建、题目配置、发布、填写、整卷统计
- 用户注册、登录、Session 认证
- 问卷创建、发布、关闭、填写、整卷统计
- 单选、多选、文本、数字四类题目
- 前端与后端一致的跳转与校验逻辑
- 独立题目资产与版本历史
- 题目共享与只读权限视图
- 题库管理与从题库选题
- 问卷引用题目版本、切换版本、排序、配置跳转
- 跨问卷单题统计
当前前端已经从 phase1 的“在问卷里直接写题”演化为 phase2 的“先有题目资产,再由问卷引用题目版本进行编排”。
flowchart TD
A["登录"] --> B["题目资产页 /questions"]
B --> B1["创建题目资产"]
B --> B2["搜索/筛选题目"]
B --> B3["加入题库"]
B1 --> C["题目详情页 /questions/root_id"]
B2 --> C
B3 --> D["题库页 /question-banks"]
C --> C1["创建新版本"]
C --> C2["恢复旧版本"]
C --> C3["修改共享设置"]
C --> C4["查看使用情况"]
C --> C5["查看跨问卷单题统计"]
D --> D1["创建题库"]
D --> D2["管理题库成员"]
D --> E["问卷编辑页 /surveys/survey_id/edit"]
B --> E
C --> E
E --> E1["从题目资产选题"]
E --> E2["从题库选题"]
E --> E3["快速创建题目资产并加入问卷"]
E --> E4["排序"]
E --> E5["配置跳转"]
E --> E6["切换当前问卷使用的版本"]
E --> F["发布问卷"]
F --> G["填写页 /survey/share_code"]
G --> H["统计页 /surveys/survey_id/stats"]
可以这样理解页面职责:
- 题目页负责题目内容、版本、共享和单题统计
- 题库页负责组织题目资产
- 问卷页只负责编排:选题、排序、跳转、切换版本
几个容易混淆的点:
- 问卷页虽然支持“快速创建题目资产并加入问卷”,但底层语义仍然是先创建题目资产,再把该版本加入问卷
- 能共享的是题目资产,不是问卷里的题目实例
- 已发布问卷不会随着题目后续新版本自动变化
- 引用题目的题干、选项、校验规则应在题目详情页修改,而不是在问卷页直接改题目本体