天天看點

[分享] 來,做一個問卷調查(有抽獎!)

前言

“小王,明天公司在***舉辦一個xxx産品釋出會,你今天準備2000份問卷調查。還有,我們這次還做一個抽獎活動,也記得弄一個抽獎箱和一些抽獎球哦。”

……

活動結束了,小王想起早上捧着這2000張問卷和抽獎箱的情景,生平第一次對弘二頭肌起了念想。回過神來看着桌子上回收回來的問卷,整整齊齊的像座小山一樣好看,但上司依然不太滿意,因為隻回收了1000來張。可是1000多張的樣本已經足夠了呀,統計也很花時間的呀。小王本想反駁,但他什麼也沒說,隻是下意識地摸了摸自己的背包,包裡裝着那丢失的900多張問卷。

以上劇情根據真實故事改編,如有雷同,算你倒黴。

數字化大背景

現在還有不少活動是用紙質問卷來做調查的,幾千張紙是小錢,但後期統計這一堆資料可是費神費力的苦力活。以前裝置落後,手機上做問卷體驗太差。但現在是80歲大爺都會玩智能手機的年代,一個二維碼也解決了入口問題,線上調查問卷的體驗也就上來了。再加上現在辦個活動什麼的都是用微信宣傳微信組織,配合一點抽獎活動,觀衆們還是願意去回答的。既然已經具備了線上問卷的大環境,下面就讓小茄帶大家來做一個線上問卷調查吧。

需求

先來分析一下需求。

1、線上問卷調查的使用者都是市場營運的從業人員,他們對程式設計的了解很少,是以背景操作必須簡單明了。

2、輸入為問題資訊,輸出為回答統計資訊,輸出需要使用可視化圖表呈現,必要時也提供中繼資料。

3、最好能帶一點圈粉屬性,掃一掃關注公衆号然後才開始答題。硬生生讓人關注公衆号,許多人可能無動于衷,但增加了一個問卷和抽獎的梗,關注公衆号就顯得非常合理自然。

4、最好能帶一點統計功能,統計一下到底多少人打開了頁面,進而為後續改進提供資料分析支撐。

其中1、2是剛需,3、4是軟需。

後端

簡單分析可以發現,開發這個小應用最主要的工作是在後端開發部分,而且這個主要是以資料處理為主,顯然采用面向資料庫程式設計的方式來開發更為合适。

面向資料庫開發第一步,先來定義資料庫吧。先使用excel做出相應的表格,大概是這樣的:

[分享] 來,做一個問卷調查(有抽獎!)

然後就是分表寫資料庫,将question、options、answer分成3個表,以questionID做索引關聯3個表,另外使用者資訊和獎品資訊也要用一個資料表來儲存。本來這裡想用MySQL for Excel來實作,這樣市場的妹子們也能簡單上手。不過想想還是導出一個sql腳本更好,畢竟這樣就可以手把手教妹子怎麼把問卷資料寫到sql檔案裡面了。(/▽╲)

問卷資料的讀寫都可以用WeX5通用的查詢接口來實作資料的讀寫,這裡不再贅述。

這裡要自己寫的是抽獎算法的實作,要點是保證中獎幾率的均一性。但是,算法也不能太死闆,主要看臉,哦不,主要看獎品大小。

如果有大獎,那麼大獎單獨出來所有人抽一次會比較好,這樣能有效活躍起現場氣氛。這種情況下可以設定一個抽獎期間,背景統計這個期間内的人數,然後在這個人數裡面随機選中一個即可。如果都是些小獎品,那麼肯定就是先答題後抽獎,抽獎結果要馬上呈現。也就是每個觀衆抽獎的時刻是不同的,而且抽獎的人數也是未知的,這種情況下要保證前後抽獎的人都有相同的中獎幾率,而且要把獎品發完的話,好像很難的樣子。但是,既然是小獎品,按照先來先得發不完也沒事的原則,每次都查詢目前獎品池的獎品,如果還有獎品則用随機數判斷是否中獎,否則就不中獎就完事了,簡單粗暴。

是以說,一切以實際出發,把重心放到重要的事上,把吃奶的力用到吃奶上,才是王道。

貼個抽獎算法的簡單實作:

1 public static JSONObject drawPrize(JSONObject params, ActionContext context) throws SQLException, NamingException {
2 // 擷取參數
3 String batch = params.getString("batch");
4 int index = params.getInteger("index");
5 String weixinID = params.getString("weixinID");
6 JSONObject result = new JSONObject();
7 Connection conn = context.getConnection(DATASOURCE);
8 
9 try {
10 conn.setAutoCommit(false);
11 try {
12 // 擷取user
13 Statement stat = conn.createStatement();
14 try {
15 ResultSet rsUser = stat.executeQuery("SELECT * FROM user WHERE fBatch = \'" + batch + "\' AND fWeixinID = \'" + weixinID + "\'");
16 if (!rsUser.next()) {
17 // 未登記
18 result.put("code", -2);
19 } else if (!Utils.isEmptyString(rsUser.getString("fPrize" + index))) {
20 // 已中獎
21 result.put("code", -1);
22 result.put("prize", rsUser.getString("fPrize" + index));
23 } else {
24 // 讀取獎池
25 List<String> prizes = new ArrayList<String>();
26 ResultSet rsPrize = stat.executeQuery("SELECT * FROM prize WHERE (fTotal - COALESCE(fCount, 0)) > 0 AND fBatch = \'" + batch + "\' AND fIndex = " + index);
27 while (rsPrize.next()) {
28 prizes.add(rsPrize.getString("fName"));
29 }
30 if (prizes.size() == 0) {
31 // 獎池空了
32 result.put("code", -3);
33 } else {
34 Random r = new Random();
35 // 看運氣
36 int luck = r.nextInt(10);
37 if (luck > 0) {
38 // 未中獎
39 result.put("code", 0);
40 } else {
41 // 抽獎
42 luck = r.nextInt(prizes.size());
43 String prize = prizes.get(luck);
44 
45 int k = stat.executeUpdate("UPDATE prize SET fCOUNT = COALESCE(fCount, 0) + 1 WHERE (fTotal - COALESCE(fCount, 0)) > 0 AND fBatch = \'" + batch + "\' AND fIndex = "
46 + index + " AND fName = \'" + prize + "\'");
47 if (k == 0) {
48 // 未中獎
49 result.put("code", 0);
50 } else {
51 // 記錄資料
52 stat.executeUpdate("UPDATE user SET fPrize" + index + " = \'" + prize + "\' WHERE fBatch = \'" + batch + "\' AND fWeixinID = \'" + weixinID + "\'");
53 result.put("code", 1);
54 result.put("prize", prize);
55 }
56 }
57 }
58 }
59 } finally {
60 stat.close();
61 }
62 conn.commit();
63 } catch (SQLException e) {
64 conn.rollback();
65 throw e;
66 }
67 } finally {
68 conn.close();
69 }
70 
71 return result;
72 }      

前端

問卷部分:前端當然是一個單頁應用了。因為問題形式差不多,是以可以做一個問題模闆,将從後端擷取到的依次問題資料渲染到頁面。這裡可以用WeX5的資料元件和模闆綁定來實作。另外要考慮到的一個問題是問卷的原子性,就是說要麼不回答,要麼就要回答所有題目。是以問卷的送出是一次性的,不能做成每道題都送出的形式。因為資料量不大,是以可以一次請求把所有question、option都取回來,減少請求數。

抽獎部分:這裡使用了搖一搖的形式來進行抽獎。原理很簡單,就是判斷加速度計在一個時間區間内的變化率大小,當變化率超過一定門檻值時就說明目前手機受力突增,也就是正在“搖一搖”的狀态。具體實作是監聽’devicemotion’事件,代碼如下:

1 // 搖一搖事件
2 if (window.DeviceMotionEvent) {
3 window.addEventListener(\'devicemotion\', deviceMotionHandler, false);
4 } else {
5 alert(\'本裝置不支援搖一搖\');
6 }
7 function deviceMotionHandler(eventData) {
8 var acceleration = eventData.accelerationIncludingGravity;
9 var curTime = new Date().getTime();
10 if ((curTime - last_update) > 100) {
11 var diffTime = curTime - last_update;
12 last_update = curTime;
13 x = acceleration.x;
14 y = acceleration.y;
15 z = acceleration.z;
16 var speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
17 
18 if (speed > SHAKE_THRESHOLD) {
19 self.imgRockClick();
20 }
21 last_x = x;
22 last_y = y;
23 last_z = z;
24 }
25 }      

輸出部分:問卷資料采集完之後,可以使用echart來展現統計資料。具體教程可以看看官方文檔:http://docs.wex5.com/integrate-echarts/ ,但是不贊同使用單檔案的形式,建議采用子產品按需載入的方式。這裡用到的無外乎是柱狀或者餅狀圖,是以隻加載基類和這兩類js檔案即可。

如果妹子要中繼資料怎麼辦?一行代碼搞定:select * from answer into outfile ‘d:/answer.xls’; 建議一定要拉着妹子的手,手把手地把這個好用的技能教給她。

更進一步

通過上面幾步,一個簡單好用的線上問卷就已經實作了。細心的你估計發現了,3、4點需求還沒實作呢。好吧,下面看看這兩點怎麼實作,沒興趣的同學可以直接到文章末尾點贊了,謝謝配合。

首先是增加圈粉屬性。

這個前提就是你要把應用部署在你的公衆号伺服器上。還沒有伺服器?Cloud X5 搞起吧,簡明教程:http://docs.wex5.com/about-cloudx5/

圈粉主要是要把你的應用入口改成微信網頁授權頁面,也就是這個位址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect,記得裡面的大寫字母參數要改成你自己的參數。回調 uri 記得要做URI轉碼。一般來說我們還要擷取使用者資訊的,是以這裡的SCOPE填入snsapi_userinfo。其他參數請參考微信開發者文檔自行補充,這裡就不贅述了:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN。如果對這一部分不太熟悉的話,可以看看小茄上一篇【30分鐘做一個二維碼名片應用】http://www.wex5.com/openway_qrcode/,裡面有詳細介紹如何使用WeX5進行微信公衆号開發。

再來看看統計功能:在2016年7月4号之前,你都隻能在網頁中引用站長工具啦、百度統計啦、谷歌統計來進行資料統計。而現在你也可以使用微信自家的統計功能了,這個是專門統計微信用戶端的通路量的。傳送門:https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&key=1467639271&version=1&lang=zh_CN,直接在背景就能看。由于它統計的是使用了JSSDK的頁面,是以這個頁面也需要配置jssdk_config。既然上面都說要圈粉了,那就增加一個分享接口就好了,後面判斷這個分享接口被調用的次數就能間接得到某個時間段的通路量了。對了,每個接口還按照頁面區分好了,是以你不用擔心其他頁面資料的幹擾。

[分享] 來,做一個問卷調查(有抽獎!)

然後,然後小王終于可以忘了曾一度被問卷調查所支配的恐怖和被囚禁于資料統計中的那份屈辱了。

全文完,點贊不謝!