此文档用于描述 FunQuiz 的设计细节,包括功能设计、接口定义和数据存储设计等内容。
- question_file 规定了何处读取问题CSV文件
- rules.total_questions=10 规定每套测验包含的题目数量
- rules.streak_for_success=3 规定 streak 达到多少题即判定挑战成功
- rules.max_skips=2 规定每套测验可使用的跳过次数上限
- rules.result_effective_minutes=3 规定结算结果有效期(分钟)
- stats.question_effective_count=10 不低于这个值时才在答题后显示题目的正确率
- stats.recent_minutes=1440 规定近期统计的时间窗口(分钟)
- external 列表用于配置外部资源展示项(名称 + 二维码图片路径或链接 URL)
- ip_start_concurrency=20
- ip_start_cooldown=60
- user_start_concurrency=2
- user_start_cooldown=60
每次用户请求开始时,算作一次并发,当开始了 cooldown 秒后,算作移除占用。
- 用户进入 /start 页面并点击开始后,请求开始测验 API,判断是否触发并发限制,若有则弹出提示,若无则进入 /quiz?id=some_rid 页面。
- 测验页面每次展示一道题目,用户提交后可进入下一题;若达到连续答对成功条件或题目答完,则跳 /complete?id=some_rid 页面,该页面立即请求结束测验 API。
- 外部资源列表在两处展示:开始页开始卡片下方、结算页结算卡片下方。
用户点击选项后,选项变色、末尾位置移入显示“确认”及其图标,点击后视为提交答案。提交后,有关选项的末尾位置移入显示“正确”或“错误”及其图标,题目下方显示击败了百分之多少的选手(如果满足正确率的计算条件)和答后附言(如有)。用户也可点击“跳过”,跳过会消耗次数但不会中断连续答对。
用户完成测验后,在完成页面,如果已达成连续答对成功条件,显示较大的“对勾”图标,否则显示与“继续努力”相关的图标。
动效风格借鉴的是《明日方舟:终末地》游戏的平面设计风格。
关键反馈动效:采用双闪动效来增强用户点击选项后的反馈感受。双闪动效指的是元素在极短时间内快速闪烁两次(没有渐入渐出效果),总持续时间是 100ms。
页面加载动画:开始时,页面最左侧有一个较窄的纯色方形进度条,从上往下延伸。进度条的当前进度的右侧以刻度的感觉显示百分比进度文本。页面其余部分是默认背景在加载完成时,进度条会向屏幕右侧拉伸,直至填充整个屏幕宽度,然后渐入切到页面内容。加载至少需要消耗 1000ms吗,所有动画需要采用缓动函数。
有一个题目创建工具脚本,用于从 CSV 文件中读取题目并写入数据库。
CSV 无表头,各个列是:题干文本,附件图片 URL?,答后附言?,正确选项文本,错误选项文本 1/2/3,错误选项文本 4/5?。其中 ? 是可选字段。
题目都是单项选择题。抽取题目时若错误选项大于 3 个,则随机选取 3 个。
POST:
- /api/quiz/start:创建一个测验记录(每次题目和选项的排列是随机的)。
- /api/quiz/get:返回测验的题目、选项和进度(最前面的一个没有提交答案的题目)。
- /api/quiz/submit:用户确认回答一个问题(
answer=-1表示跳过),立即修改测验记录、问题和选项的各类计数值,返回该问题的回答结果、剩余跳过次数以及历史正确率(若满足正确率的计算条件)。 - /api/quiz/complete:用户确认结束测验,返回得分、最大 streak 和挑战是否成功。
GET:
- /api/stats/recent:返回近期总参与人次和总成功人次。
- /api/image/{iid}:返回图片二进制数据,iid 是图片的 uuid。
- 200:成功
- 401:未授权,用户 cookie 中没有 uid,或者 uid 不属于这个测验。
- 409:冲突,用户提交了已经提交过答案的问题,或者用户提交了已经结束的测验。
- 429:过多请求,用户超过了开始测验的并发限制。
- uid 用户的 uuid ,也会被放到用户 cookie 里,非空。
- created_at 创建时间戳,非空。
- uid 非空。
- rid 测验的 uuid,非空。
- start_time 开始时间戳,非空。
- submit_time 结束时间戳,可空。
- details JSON 对象,非空,包含:
- questions 字段,非空,包含:
- qid 问题编号,非空。
- options 数组表示选项排列,0 表示选择了正确选项,正整数分别是对应的错误选项,非空。
- answer 回答了哪个选项,可空;特殊值 -1 表示该题被跳过。
- answer_time 何时回答的这个问题,可空。
- questions 字段,非空,包含:
- score 提交得分,非负整数表示答对数量,可空。
- qid 题目的数字 id,非空。
- text 题干文本,非空。
- attachment 非空,附件图片 URL。
- appendix 非空,问题回答后显示的文本。
- options 数组存储选项编号,第一个值对应正确选项,其余值是错误选项,非空。
- correct_count 累计答对数量,非空。
- wrong_count 累计答错数量,非空。
- oid 选项的数字 id,非空。
- text 非空。
- qid 非空,外键。
- select_count 累计被选择次数,非空。
- iid 图片缓存 uuid,非空。
- src_url 图片来源 URL,非空。
- cached_time 缓存时间戳,非空。
- data 图片二进制数据,可空。
由于部分图片来源网站存在跨域限制,提供题目时,提供的图片 URL 需要使用我们的获取图片的 API URL 进行拼接。若该图片的源 URL 对应的数据项没有存在数据表里面,则插入到数据表(此时先不下载图片数据)。当获取图片的 API 收到请求时,此时的服务器再去检查对应的 iid(假设存在,不存在就返回 404)的二进制数据是否空,如果空就下载并缓存和返回。