-
需求評審
》》》》》》》》》》》》》》》》》》》》》》》》》
-
詳細設計:
-
背景和目標
緊跟熱點事件,通過卡券、周邊等激勵用戶參與答題,根據不同的娛樂熱點,配合影視綜宣發,上線不同的答題主題,將答題作爲一個日常可複用的小程序通用模板
-
排期 (10人日)
1.小程序登錄 端上通過code,請求webpage,webpage通過開放平臺換取openid 和sessionKey,後續通過openid換取uid,進行緩存 高煒煒 0.5
2.活動的配置 ( 活動id 開始時間 結束時間 活動的名字 活動的標題 活動首圖 單題的倒計時 單題的分數 每天的答題次數 每次能答幾道題 成績的結果頁配置 張寧 0.5
3. 題庫的導入,運營同學提供excel文件 ,我收到轉換成csv文件,格式如下:
開發同學通過腳本解析csv文件,判斷格式是否正確,讀入緩存之後,在寫入數據庫 和 redis中 ,數據庫格式看存儲設計 ,redis用於後續題目的分配使用, 以及開發題目的修復腳本,張洪銘1天
4.首頁接口 0.5天 張洪銘
返回活動題目,活動的名字,答題次數(需要判斷分享+1)以及是否登錄的判斷
5.請求題目的接口 1.5天 張洪銘
1. 端上需要傳過來activity_id,後端通過activity_id,去查找這個活動對應的題目,分別從redis中取出兩種類型的題號,進行比例隨機抽取分配,同時生成group_id代表本次的答題組,並把題號通過group_id保存在redis中,用於後續查詢把group_id,activty_id,problem_id,is_next_problem(是否是最後一題)題目的其他信息返回給端上用於展示。group_id和problem_id可以定位下一題的題號
2.去重邏輯,端上答完題會把題號寫入redis的集合中,只需要每次把答過的題號和redis中存入的總題號做diff即可 張洪銘 1.5天
6.判題的得分的接口 1.5天 張洪銘
1.得分是以時間爲基礎算得,爲了用戶的體驗,端上傳遞時間,需要加入簽名進行保證時間不被修改
2. 端上需要傳過來activity_id,group_id,problem_id,消耗的時間,分值,答案,server進行比較判題,把結果進行存儲,同時返回給端上本題的正確答案,和本題是否正確的字段
3.如果本題是錯誤的回答,進行任務的創建,同時分配任務類型和生成任務id。把這些信息一起返回給端上,用於進行復活
4.同時判斷本次得分是不是目前最高的一次,最高的一次需要寫入排行榜的redis中
7. 任務接口,點擊復活調用相應的發文和關注的任務接口,任務成功回執狀態,同時更新數據庫中的任務狀態和本題的分數(以及判斷分數的狀態是否需要寫入排行榜的redis中) 高煒煒 2天
8.單次成績結果接口 0.5天 張洪銘
9.排行榜的接口 0.5天 張洪銘
寫入,修改用戶分數 zadd 鍵 activity_id + rank_list 分數 score 用戶標識 uid
查看用戶分數 zscore 鍵 activity_id + rank_list 用戶標識 uid
查看排行榜的名次 zrevrange 鍵 activity_id + rank_list 0 99 前一百
查看用戶的排名 zrevrank 鍵 activity_id + rank_list 用戶標識uid
10.個人獎品頁:
通過pbcms上傳名單,和所得獎品的文字,圖片(運營提供)和 排行榜進行匹配,生成 0.5天 張洪銘
11.分享回調
端上傳給後端分享是否成功,後端判斷是第幾次,好進行次數的判端 高煒煒 1天
存儲設計Mysql
活動信息的配置
pbcms |
|
|
|
---|---|---|---|
activity_id | int | 活動id | |
activity_start | int | 開始時間 | |
activity_end | int | 結束時間 | |
activity_name | varchar(255) | 活動的名字 | |
activity_title | varchar(255) | 活動的標題 | |
activity_first_image | varchar(255) | //活動首圖 | |
activity_single_countdown | int | 單題的倒計時 | |
activity_single_score | int | 單題的分數 | |
activity_day_answer_num | int | 每天的答題次數 | |
activity_single_answer_num | int | 每次能答幾道題 | |
activity_result_page | varchar(255) | 成績的結果頁配置 | |
activity_ext | varchar(255) | 活動的擴展字端 |
題庫: mysql
mysql
answer_problem_store |
|
|
|
---|---|---|---|
activity_id |
int |
和活動id對應 |
|
problem_id |
自增 int |
問題id 唯一主鍵 |
|
problem_title |
varchar(255) |
問題的題目 |
|
problem_image |
varchar(255) |
圖片 |
|
problem_option |
varchar(255) |
選項 |
{"范冰冰","李冰冰","朱一龍","馮紹峯"} |
problem_answer |
varchar(255) |
答案 |
0 索引 |
problem_type | int | 問題類型 | 1選擇2選字 |
problem_status | int | 題目的狀態 | 生效,失效 |
problem_ext |
varchar(255) |
擴展字端 |
{} |
Table: answer_problem_store
Create Table: CREATE TABLE `answer_problem_store` (
`problem_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '問題ID',
`activity_id` int(11) NOT NULL DEFAULT '0' COMMENT '活動id',
`problem_title` varchar(255) NOT NULL DEFAULT ' ' COMMENT '問題描述',
`problem_image` varchar(255) NOT NULL DEFAULT ' ' COMMENT '問題圖片',
`problem_option` varchar(255) NOT NULL DEFAULT ' ' COMMENT '問題選項',
`problem_answer` varchar(255) NOT NULL DEFAULT ' ' COMMENT '問題答案',
`problem_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '問題類型1選擇2選字',
`problem_ext` varchar(512) NOT NULL DEFAULT ' ' COMMENT '問題的擴展字段',
`problem_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0生效1失效',
PRIMARY KEY (`problem_id`),
KEY `idx_activity_type` (`activity_id`,`problem_type`)
) ENGINE=InnoDB AUTO_INCREMENT=458 DEFAULT CHARSET=utf8 COMMENT='問題的存儲表'
1 row in set (0.00 sec)
每組答題題目記錄 mysql + redis
mysql
answer_group_record |
|
|
|
---|---|---|---|
group_id | int | 自增id | |
activity_id | int | 活動id | |
uid | int | 用戶id | |
allot_problem_group | varchar(255) | 分配的問題 | {8,10,3,90,23} |
total_score | int | 總得分 | 1000 |
group_status | int | 本組狀態 | 1 進行中 2完成 |
group_problemid | int | 回答到哪個問題 | |
is_share | int | 是否分享 | 1,0 |
create_time | int | 創建時間 | |
update_time | int | 更新時間 |
Table: answer_group_record
Create Table: CREATE TABLE `answer_group_record` (
`group_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '問題組id',
`activity_id` int(11) NOT NULL DEFAULT '0' COMMENT '活動id',
`uid` bigint(20) NOT NULL DEFAULT '0' COMMENT '用戶id',
`allot_problem_group` varchar(255) NOT NULL DEFAULT '' COMMENT '分配的問題組',
`total_score` int(11) NOT NULL DEFAULT '0' COMMENT '總分',
`group_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '本組狀態 0是開始 1 進行中 2完成',
`group_problemid` int(11) NOT NULL DEFAULT '0' COMMENT '回答到哪個問題',
`is_share` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否分享 1分享0是沒有',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '創建時間',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '創建時間',
PRIMARY KEY (`group_id`),
KEY `idx_activity_uid_time` (`activity_id`,`uid`,`create_time`)
) ENGINE=InnoDB AUTO_INCREMENT=573 DEFAULT CHARSET=utf8 COMMENT='問題組表'
用戶已答題記錄 mysql + redis
mysql
answer_record |
|
|
|
---|---|---|---|
activity_id | int | 活動id | |
problem_id | int | 問題id | |
group_id | int | 組id | |
uid | bigint(20) | 誰回答的 | |
answer_result | varchar(255) | 填寫的答案 | |
is_correct | tinyint | 回答是否正確 | |
task_type | tinyint | 1是社區發文2是批量關注', | |
is_task_success | tinyint(4) | 1是成功0是沒有 | |
task_ext | varchar(512) | 任務擴展字段 | |
get_ score | int | 本次得分 | |
use_time | int | 耗時s | |
create_time | int | 創建時間 | |
update_time | int | 更新時間 |
Table: answer_record
Create Table: CREATE TABLE `answer_record` (
`answer_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '回答id',
`activity_id` int(11) NOT NULL DEFAULT '0' COMMENT '活動id',
`problem_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '問題id',
`group_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '問題組id',
`uid` bigint(20) NOT NULL DEFAULT '0' COMMENT '用戶id',
`answer_result` varchar(255) NOT NULL DEFAULT '' COMMENT '回答',
`is_correct` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0是沒有答題1是正確2是錯誤',
`task_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1是社區發文2是批量關注',
`is_task_success` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1是成功0是沒有',
`task_ext` varchar(512) NOT NULL DEFAULT '0' COMMENT '任務擴展字段',
`get_score` int(11) NOT NULL DEFAULT '0' COMMENT '本次得分',
`use_time` int(11) NOT NULL DEFAULT '0' COMMENT '耗時',
`create_time` int(11) NOT NULL DEFAULT '0' COMMENT '創建時間',
`update_time` int(11) NOT NULL DEFAULT '0' COMMENT '創建時間',
PRIMARY KEY (`answer_id`),
KEY `idx_activity_uid` (`activity_id`,`uid`),
KEY `idx_group_problem` (`group_id`,`problem_id`)
) ENGINE=InnoDB AUTO_INCREMENT=480 DEFAULT CHARSET=utf8 COMMENT='回答問題記錄'
存儲設計Redis
活動所有選擇問題id的存儲key
數據結構 |
集合 |
|
|
---|---|---|---|
key |
answer_choice_problemid_store."_".$activity_id; |
||
value |
problem_id |
活動所有選字問題id的存儲key
數據結構 |
集合 |
|
|
---|---|---|---|
key |
answer_word_problemid_store."_".$activity_id; |
||
value | problemid |
用戶已經回答問題的key
數據結構 |
集合 |
|
|
---|---|---|---|
key |
answer_already_problemid_store . "_".$activity_id."_".$uid |
||
value | problemid |
用戶組的信息key
數據結構 |
string |
|
|
---|---|---|---|
key |
answer_group_info."_".$group_id |
||
value | 數據組分配問題id信息的json串 |
題目信息的存儲
數據結構 |
string |
|
|
---|---|---|---|
key |
answer_problem_info."_".$problem_id; |
||
value | 題目信息 |
每天已經答題的次數
數據結構 |
lock |
|
|
---|---|---|---|
key |
answer_perday_answertimes."_".$activity_id."_".date("Ymd")."_".$uid; |
||
value | 鎖 |
排行榜記錄
redis
數據結構 |
有序集合 |
|
|
---|---|---|---|
key | answer_ranklist."_".$activity_id; | ||
value | 分數,成員 |
寫入,修改用戶分數 zadd 鍵 activity_id + rank_list 分數 score 用戶標識 uid
查看用戶分數 zscore 鍵 activity_id + rank_list 用戶標識 uid
查看排行榜的名次 zrevrange 鍵 activity_id + rank_list 0 99 前一百
查看用戶的排名 zrevrank 鍵 activity_id + rank_list 用戶標識uid
全景圖
時序圖
接口梳理
- 1.小程序的登錄接口 高煒煒 0.5
- 2.答題入口頁的接口 張洪銘 0.5
- 3.請求題目的接口 張洪銘 1.5
- 4.判題得分接口 張洪銘 1.5
- 5.社區發文任務接口 高煒煒 1
- 6.關注任務接口 高煒煒 1
- 7.單次成績結果接口 張洪銘 0.5
- 8.排行榜接口 張洪銘 0.5
- 9.個人獎品頁 張洪銘 0.5
- 10.分享成功回調接口 高煒煒 1
- 11. 題庫的倒入腳本 張洪銘 0.5
- 12 pbcms的設置 張寧 1
依賴服務整理
關注:
社區發文:
小程序登錄: (appkey的申請)
詳細接口設計
GET公參
字段 |
值 |
備註 |
---|---|---|
activity_id | 2 | 活動id |
smartAppName | answer | 小程序標識,用於小程序相關功能通用處理 |
答題首頁入口
/webpage?type=yuleactivity&action=answerindex&smartAppName=answer&activity_id=2&smartAppName=answer
參數:activity_id=2
返回結構
|
請求題目接口
/webpage?type=yuleactivity&action=answerrequestproblem&smartAppName=answer&activity_id=1&group_id=61
參數
沒有group_id代表創建問題組
有group_id代表從問題組中獲取下一道題
|
判題接口
接口返回
|
成績頁接口
webpage?type=yuleactivity&action=answerresultpage&activity_id=1&group_id=61
|
排行榜接口
webpage?type=yuleactivity&action=answerranklist&activity_id=1
|
獎品頁接口
/webpage?type=yuleactivity&action=answergetaward&activity_id=1
|
復活任務完成接口
Request:
GET:
社區發文:
/webpage?type=yuleactivity&action=answerrevive&activity_id=2&smartAppName=answer&answer_id=123&task_type=1
關注任務:
/webpage?type=yuleactivity&action=answerrevive&activity_id=2&smartAppName=answer&answer_id=123&task_type=2&followtype=superinterest&third_id=1001,1002,10003
參數:
字段 |
值 |
備註 |
---|---|---|
answer_id | int | 答題id |
task_type | 1|2 |
1:社區發文 2:關注 |
follow_type | 關注資源type | superinterest |
third_id | 關注id | 要關注的社區id,支持批量,用英文逗號連接 |
Response:
{
"errno" : 0, //失敗errno非0
"errmsg" : "succ",
"data" : {//關注任務返回data爲空
//發文任務返回示例:
"url" : "http://xiongyang.baidu.com:8910/interest?id=%s&activefrom=%s&yule={\"refreshMetaId\":12345,\"toast\":{\"message\":\"文案\",\"buttonText\":\"返回\",\"type\":1,\"duration\":6}}" // 跳轉url
}
}
復活任務完成後返回答案接口
Request:
GET: /webpage?type=yuleactivity&action=answerrevivedone&activity_id=2&smartAppName=answer&answer_id=123
參數:
字段 |
值 |
備註 |
---|---|---|
answer_id | int | 答題id |
Response:
{
"errno" : 0, //非法調用errno非0
"errmsg" : "succ",
"data" : {
"answer" : "正確答案"
}
}
分享接口彈窗
Request:
GET: /webpage?type=yuleactivity&action=answersharepopup&smartAppName=answer&activity_id=2&group_id=123
參數:
字段 |
值 |
備註 |
---|---|---|
group_id |
Response:
{
"errno" : 0,
"errmsg" : "succ",
"data" : {
"popup" : 0|1 //0:不展示彈窗;1:展示彈窗
}
}
分享中間h5頁
Request:
GET: /webpage?type=yuleactivity&action=answersharepage&smartAppName=answer&activity_id=2
Response:
{
"errno" : 0, //非法調用errno非0
"errmsg" : "succ",
"data" : {
"activityId" : 2 //備用:如果後續不同小程序展示中間頁不一樣的話
}
}
注意的點
1.端上傳過來的時間和回答有可能是空,判斷的時候需要注意
2.server控制時間,端上的時間用於展示,小程序進入後臺,重新進入需要在請求一次接口同步server的時間 is_try
3.答案判斷,採取的是索引判斷,不是文字比較
4.權限相關,需要判斷用戶不能答其他人的題,問題組id,問題id,活動id userid 需要一致
5.答題次數判斷,需要加鎖,但是隻在生成問題組的時候才加,後續的請求問題,不需要判斷鎖
6.請求下一題的時候,還需要判斷是否復活成功,沒有成功是不能請求下一題的,一直到成功爲止
7.請求相同的一道題不應該是返回錯誤,而應該是返回之前的答案
8.排行榜按照時間排序,分數做爲整數 + (活動結束時間-答題時間做爲小數)這個有問題,10.9 和10.448比較就有問題了,應該是448比9更加早開始答題的,但是取數據的時候就有問題了,解決辦法是將時間進行
9.當前的答題分數算百分比,算出當前分數在排行榜中所佔的排名,除以總數
10.答題小程序的名字只能修改5次
11.排行榜的計算中有關時間的計算不應該以活動結束時間來算,一旦更改活動結束時間,就會導致排行榜不是按照時間排序了,因爲後面的有可能時間長比前面的大。