一、項目基本情況
概述
本項目以清華大學為預期用戶,作為校內信息化統計平臺進行服務,建立網頁端和移動端校內信息化統計平臺,基于Project_1的需求實現。
本項目能夠滿足校內學生團體的幾類統計需求,如活動報名、實驗室招募、多規則投票;對于收集到的數據可以進行一定的統計、分析,并且將分析結果進行可視化的展示,為提升校園工作的效率和數據的安全性供幫助。同時也為公司和校外團隊提供服務。
開發環境
本項目在前端及javascript部分使用了Bootstrap 3.3.5及jQuery2.1.4等框架,在后端則使用了Python 2.7.10 + Django 1.8.4的框架,并使用了Django框架中自帶的SQLite數據庫。
運行說明
為了運行本項目,首先需要確保運行的環境已經安裝好Python2.7以及Django1.8.4。
若需要在本地運行本項目,進入所在目錄的src文件夾,執行如下命令:
$ python manage.py runserver 0.0.0.0 8080
并在瀏覽器中訪問 http://127.0.0.1:8080/ 便可看到登陸界面
二、需求分析
概述
本項目的需求分析基于項目開始前需求方提供的文檔《PRJ1-校園信息化統計平臺》進行。在對這份進行分析后,我們將所有的需求分為三大塊:
問卷系統設計
該部分為本項目最主要的功能,具體表現為活動的發起方可以在線編輯問卷并發布,活動的參與方可以根據發起方發布的有平臺生成的信息訪問該問卷并進行填寫,填寫的信息需記錄在平臺的后臺備用。問卷的設計發布功能需滿足多種要求。
問卷數據的處理
該部分為本項目的重要功能之一,對問卷平臺的活動發布者開放,根據問卷系統中所收集備用的信息處理,并向用戶開放數據導出、分析與統計的端口,包括各種可視化實現。
用戶系統管理
設置管理員權限用戶,使用內置賬戶登錄,可以管理其它普通用戶和普通用戶發布的問卷,同時需要實現普通用戶的個人用戶界面。
值得注意的是,由于需求中包括普通要求,提高要求,終極要求等多個等級,而部分提高要求在開始是不在實現計劃的范圍內,在最后也并未實現,下述的詳細需求分析中刪去了這部分提高要求的內容,并在本組與需求方討論后添加了用于優化用戶體驗的內容。
問卷系統設計
圖1: 問卷系統泳道圖
其中設置的三種文件模板分別對應需求中提及的報名/信息統計表、實驗室對象招募設計以及多規則投票平臺。題目的類型特征對應題目類型,包括多選題的選項數,填空題的內容類型(數字,電話號碼,郵箱等),若使用投票平臺等模板,則此處的問卷問題變為投票的項目。問卷的發布方式為導出鏈接與二維碼,問卷的傳播由發布者利用社交工具進行。
問卷數據的處理
圖2: 問卷數據處理泳道圖
其中可視化表格包括柱狀圖、餅狀圖、折線圖等,內容包括平均值、方差等簡單的計算與簡單的數據總量統計。需收集的答卷情況除了答卷本身外,還包括填寫者的IP等信息,導出的excel/csv格式數據中包括以上內容。
用戶系統管理
圖3: 用戶系統管理泳道圖
該部分要求主要來自與需求方的溝通,管理員由內置賬號實現,而清華學生用戶由清華賬號登陸。管理員主要功能為查看與刪除問卷,查看用戶信息與發布公告。
三、模塊及接口設計
概述
本項目的實現主要分為四個模塊,由于本項目由Python2.7.10加上Django1.8.4實現,這四個模塊體現為四個app,分別為dance、interface、api以及database。
interface、database以及api三個模塊分別負責前端用戶界面,數據庫,以及連接前端用戶界面與數據庫,將在本章的其余部分做詳細說明。
圖4: 模塊拓撲關系圖
頂層模塊dance為Django項目創建時自帶的app,主要負責記錄Django框架的基本設置,以及保存其余三個模塊所通用的URL模板。由于本項目Django設置主要為將其余三個模塊app加入頂層模塊,設置語言,時區、設置SMTP服務器等,在這一章中不做更多的說明,其具體的設置見技術細節部分。
用戶界面interface
interface模塊的接口主要在interface文件夾下的views.py中實現,該模塊直接與用戶進行交互,主要實現的接口功能為響應URL請求并對模板進行渲染后返回,下表以普通用戶的權限可以訪問的URL接口為例展示接口功能,管理員與游客身份問卷發布者的接口與之類似:
接口名 | 接口功能 |
legalUser | 用戶登錄時調用,返回用戶主界面 |
legalUser_dashboard | 用戶主界面中右邊展示的信息部件 |
legalUser_show_app_list | 查看所有自己發布的問卷時調用,返回一個可排序表格部件 |
legaUser_design | 用戶進入編輯問卷界面時調用,返回一個問卷模板 |
legalUser_design_question | 用戶添加或編輯題目后調用,即時顯示題目信息 |
show_model | 在多種場合調用,彈出一個阻塞式窗口,以編輯或選擇 |
user_information | 用戶查看用戶信息時調用,返回用戶信息頁面 |
user_information_change | 用戶修改用戶信息時調用,返回修改信息頁面 |
show_statistics_choose | ;用戶點擊數據統計頁面時調用,返回該頁面有部的各種部件,如統計圖表,用以選擇需要查看統計信息的問卷與問卷中題目的下拉菜單,填寫者信息表格等內容 |
show_statsitics | ;用戶點擊數據統計頁面時調用,返回該頁面有部的各種部件,如統計圖表,用以選擇需要查看統計信息的問卷與問卷中題目的下拉菜單,填寫者信息表格等內容 |
show_charts | ;用戶點擊數據統計頁面時調用,返回該頁面有部的各種部件,如統計圖表,用以選擇需要查看統計信息的問卷與問卷中題目的下拉菜單,填寫者信息表格等內容 |
statistics_question | ;用戶點擊數據統計頁面時調用,返回該頁面有部的各種部件,如統計圖表,用以選擇需要查看統計信息的問卷與問卷中題目的下拉菜單,填寫者信息表格等內容 |
statistics_question_list | ;用戶點擊數據統計頁面時調用,返回該頁面有部的各種部件,如統計圖表,用以選擇需要查看統計信息的問卷與問卷中題目的下拉菜單,填寫者信息表格等內容 |
questionnaire_publish | 用戶發布問卷確認后調用,展示問卷連接與二維碼 |
log_off | 用戶注銷接口,返回登陸頁面 |
表1:interface模塊中普通用戶頁面的接口名稱與功能表
除此之外還定義了一些問卷參與者填寫問卷時調用的接口,以及模塊內部互相調用的一些函數,如render_ajax與render_sortable,封裝了返回一個部件或可排序表格的過程,以及check_indentity和get_username等檢查session中信息以實現權限控制的內容。
前后端接口api
api模塊位于前端與數據庫之間,負責將前端的數據傳給數據庫,并將數據庫的處理結果返回給前端。考慮到實現效率和用戶體驗問題,發送郵件,請求登錄等耗時操作也在此模塊中進行,并在這個過程中調用database的接口,api中具體的接口名稱與功能如下表,這些接口主要位于api文件夾下的views.py文件中,其中刪去了一些內部調用的函數:
接口名 | 接口功能 |
modify_name | 修改問卷名稱,并將修改后內容存入數據庫 |
create_new_act | 創建新問卷,并返回數據庫提供的問卷id |
operation_qst | 修改問卷題目順序,并返回數據庫提供的修改結果 |
modify_qst | 修改問卷題目內容,并返回數據庫提供的修改結果 |
remove_act | 將問卷狀態設置為已刪除,并返回數據庫提供的修改結果 |
save_act | 保存問卷,并返回數據庫提供的修改結果 |
publish_act | 發布問卷,并返回數據庫提供的修改結果 |
email_act | 發送郵件,并返回郵件發送結果 |
info_change_act | 提交用戶信息修改,并返回數據庫提供的修改結果 |
login_act | 提交用戶登陸請求,調用清華賬號api并返回登陸結果 |
get_user_information_act | 返回用戶信息 |
get_all_user | 返回所有用戶與其信息的列表 |
get_all_questionnaire | 返回所有問卷與其信息的列表 |
get_questionnaire_byID | 根據問卷ID或者問卷狀態,獲取符合條件的問卷 |
get_questionnaire_byST | 根據問卷ID或者問卷狀態,獲取符合條件的問卷 |
get_participants | 獲取問卷參與者列表 |
get_result_of_question | 獲取問卷結果與問卷結果的統計信息 |
get_statistics_of_question | 獲取問卷結果與問卷結果的統計信息 |
notic_act\get_notice | 管理員修改系統公告\獲取系統公告內容 |
questionnaire_submit | 問卷提交,將提交內容存入數據庫,并返回處理信息 |
stop_act\resume_act | 停止問卷收集與重新開始問卷收集的接口,返回處理結果 |
get_chart_json | 從數據庫中獲取問卷統計信息并制作各種圖表返回 |
表2:api模塊的接口名稱與接口功能表
后端數據庫database
database模塊即我們的數據庫,其接口為api所調用,主要返回數據庫中所存放的信息,這些接口與api接口即功能表中提到的需要訪問數據庫的接口基本對應,這些接口主要位于database文件夾下的api.py文件中,具體如下。
接口名 | 接口功能 |
createUser | 創建一個新的用戶 |
userInfoChange | 修改數據庫中保存的用戶信息,返回修改結果 |
接口名 | 接口功能 |
getUserInfo | 在數據庫中查找用戶信息并返回 |
getAllUser | 查找數據庫,并返回所有用戶及其信息的列表 |
getAllQuestionnaireInfo | 查找數據庫,并返回所有問卷及其信息的列表 |
getQuestionarieByStatus | 查找數據庫,根據問卷狀態或者信息,返回一個問卷或多個問卷所組成的列表 |
getQuestionarieByID | 查找數據庫,根據問卷狀態或者信息,返回一個問卷或多個問卷所組成的列表 |
createNewQuestionnaire | 創建新問卷,返回問卷ID |
saveQuestionnaireInfo | 保存問卷信息,返回處理結果 |
createNewQuestion | 創建新問題,返回問題ID |
operateQuestion | 調整問題的順序,返回處理結果 |
deleteQuestionnaire | 刪除問卷,返回處理結果 |
saveQuestionnaire | 保存問卷,返回處理結果 |
publishQuestionnaire | 發布問卷,返回處理結果 |
stop\wakeQuestionnaire | 停止或重新開始問卷收集,返回處理結果 |
modifyQuestion | 調整問題內容并保存,返回處理結果 |
fillQuestionnaire | 保存填寫問卷信息,返回處理結果 |
getFillers | 在數據庫中查找問卷填寫者信息并返回 |
getQuestionFill | 在數據庫中查找所有填寫過的問卷并返回 |
getStatisticsOfQuestion | 在數據庫中查找問卷填寫情況信息并返回 |
表3:database模塊的接口名與功能表
該表中刪去了部分database模塊內部調用的接口,這些接口主要負責將數據庫中取出的信息制成dict類型,并且將多個這種dict制成一個list。還有部分接口負責進行測試,這些接口也沒有在這張接口功能表中被提及。
在api模塊與database模塊的功能表中多次提到“返回數據庫提供的處理結果”以及“返回處理結果”等表述,這里返回的處理結果為一個變量,表示處理流程是否成功完成,用以避免數據庫出錯或者從interface傳入api模塊的數據出錯所導致的問題。
四、技術細節
概述
本項目的實現主要包括三種類型的代碼,分別是作為網站框架的Django+Python代碼,前端網頁的HTML文件與CSS樣式表,以及前端的JavaScript腳本語言。本章將對這三種類型的代碼分別展開,介紹本項目的一些重要的技術細節。
本項目所實現的網站的拓撲結構如下圖所示,每個模塊基本由HTML+CSS加上JavaScript實現,模塊間的跳轉與準入權限控制等由Django+Python實現,模塊間的和模塊與后臺的數據溝通由JavaScript和Django+Python實現。
圖5:清華大學信息化統計平臺網站拓撲結構圖
Django部分
Django渲染函數
interface文件夾中的views.py文件包含了網站所有頁面對應的Django渲染函數,具體的接口名稱和功能請見模塊與接口設計一章的用戶界面interface一節,此處不再贅述,這一節里將重點介紹在前面沒有提及的封裝的兩個渲染函數render_ajax與render_sortable,分別進行Ajax請求的處理以及可排序表格的渲染。
在概述一節中提出的網頁拓撲結構圖中的鏈接跳轉絕大部分是由Ajax請求完成的,通過Ajax請求載入頁面時,在載入網頁時不需要刷新整個頁面,只需要返回一個部件即可,而當用戶進行刷新等操作,或者直接通過URL訪問網頁時,需要刷新整個頁面。render_ajax函數可以解決此類矛盾,通過判斷請求是否為Ajax請求,若是,則通過JavaScript實現僅渲染一個部件,若不是,則渲染整個網頁,因此對于每個頁面存在兩種模板文件。
render_ajax函數的調用方法類似render函數,其接口如下:
render_ajax(request,url,params,item_id = ‘ ’)
參數名 | 功能 |
request | Django的Request對象 |
url | 要渲染的HTML模板文件路徑 |
params | 模板中的各種參數 |
item_id | 頁面對應的左邊欄項目ID |
表4:render_ajax函數的參數表
可排序表格為本項目中一個經常使用的特殊部件,例如用戶查看所有自己發布的文件時會需要渲染可排序表格,關于該表格的具體技術細節見HTML與CSS部分。本項目封裝了用于渲染可排序表格的函數render_sortable,其接口如下:
render_sortable(request, items, url, params)
參數名 | 功能 |
request | Django的Request對象 |
item | 要渲染的表格中的項目列表 |
params | 模板中的各種參數 |
url | 要渲染的HTML文件路徑 |
表5:render_sortable函數的參數表
可排序表格支持排序順序的自定義,包括升序和降序,排序內容的篩選,以及關鍵詞搜索。這些參數將會以GET請求從網頁中事實獲得,并對表格進行刷新。可排序表格中每一個分頁的分頁信息,即參數調用同一文件內的get_pagination函數獲得,其接口如下:
get_pagination(item_total, item_per_page, cur)
參數名 | 功能 |
item_total | 表格內容的總項目數 |
item_per_page | 表格每頁顯示的項目數 |
cur | 當前頁碼 |
表6: get_pagination函數的參數表
該函數根據這些信息打包為一個list,作為params傳入render_sortable函數中
Django網頁模板
本項目通過Django模板的繼承避免了大量的代碼重復,下面介紹主要使用到的模板,以及這些模板對應的網頁的結構與作用,模板的具體實現將在HTML與CSS部分介紹。
這些模板文件均位于interface模塊下的templates文件夾中。publish_base.html與base.html為最主要的兩個模板,分別對應問卷填寫者,以及問卷發布者,包括清華學生用戶,游客,管理員的主界面模板。前者由后者刪除user-menu模塊與left-column模塊后得到,其余部分與base.html基本一致,因此這里僅詳細介紹base.html。
base.html模板為大部分其它模板所繼承,共包含8個block,如下表所示:
名稱 | 描述 |
title | 頁面的標題 |
css | 自定義的css樣式表 |
script | 自定義的script |
subtitle | 導航欄上的副標題 |
user-menu | 導航欄右側用戶名標簽的下拉菜單 |
main-frame | 左側邊欄+主頁面的整個框架,通常不修改 |
left-column | 左側邊欄 |
main-page | 主頁面 |
表7: base.html模板的block說明表
由于base.html文件為問卷發布者用戶界面的模板,服務于普通清華賬號用戶,管理員以及游客,本項目對于者三種身份的用戶在base.html模板的基礎上定制了獨特的用戶界面。這些定制的用戶界面模板均命名為index.html,存放于templates文件夾下的legalUser、manager以及guest等子文件夾中。
又由于其中管理員以及游客界面所使用的用戶界面是在普通用戶的界面中刪去某些部分,或是稍作修改而成,這里首先以普通用戶的legalUser文件夾下的模板文件為例介紹用戶界面的結構。
legalUser文件夾根目錄的情況如下表所示:
路徑 | 描述 |
dashboard.html | 用戶首頁模板,包括各種概覽信息頁面 |
dashboard.ajax.html | 用戶首頁Ajax請求加載時的模板 |
applications | 文件夾,用以存放可排序表格的渲染文件 |
design | 文件夾,存放各種阻塞式窗口、問卷問題的模板;以及用戶問卷頁面的模板與ajax模板 |
information | 文件夾,存放用戶信息查看與修改界面的模板與ajax模板 |
login | 文件夾,存放登陸信息界面 |
statistic | 文件夾,存放數據統計界面的各種模板,如圖表等 |
表8:legalUser文件夾內容表
其中可排序表格的渲染模板文件如下表所示:
文件名 | 功能 |
applications.ajax.html | 可排序表格頁面Ajax請求加載時的模板 |
applications.html | 可排序表格頁面模板 |
applications_content.html | 可排序表格表格體模板 |
applications_list.html | 可排序表格表頭內容模板 |
表9:可排序表格渲染模板文件表
阻塞式窗口是為了讓用戶優先響應某些事件而設立的,如修改題目時的設置表,簡單的確認框等,將會在HTML與CSS部分詳細介紹,其模板類型如下表所示:
文件名 | 功能 |
email_modal.html | 填寫反饋郵箱彈窗模板 |
fillin_modal.html | 填空題設置彈窗模板 |
information_modal.html | 用戶信息查看彈窗模板 |
mark_modal.html | 實驗室招募題設置彈窗模板 |
mutl_modal.html | 多選題設置彈窗模板 |
publish_modal.html | 問卷發布成功信息展示彈窗模板 |
qst_name_modal.html | 問卷名稱設置彈窗模板 |
single_modal.html | 單選題設置彈窗模板 |
vote_modal.html | 投票提設置彈窗模板 |
表10:阻塞式窗口渲染模板文件表
問卷問題模板用于在用戶編輯時即時顯示問題的樣式,也用戶在問卷填寫者填寫問卷時顯示問題的樣式,其模板類型如下表所示:
文件名 | 功能 |
fillinl.html | 填空題顯示模板 |
mark_modal.html | 實驗室招募題顯示模板 |
mutl_modal.html | 多選題顯示模板 |
single_modal.html | 單選題顯示模板 |
vote_modal.html | 投票題顯示模板 |
表11:問卷問題模板文件表
除了已經提到的dashboard與application兩個欄目以外,用戶界面還設置有其它數個欄目,這些欄目的模板均由一個html文件和一個ajax.html文件組成,應對不同請求:
欄目名 | 功能 |
dashboard | 用戶主頁 |
application | 顯示可排序表格 |
user_information | 查看用戶信息 |
user_information_change | 修改用戶信息 |
design | 編輯與發布問卷 |
statistics | 數據統計查看 |
notice | 管理員界面專有,發布公告 |
表12:用戶頁面界面種類表
除了用戶界面外,還有繼承了publish_base.html模板的填寫問卷界面模板,這些模板文件位于templates目錄下的questionnaire文件夾中,該文件夾目錄如下表:
路徑 | 描述 |
publish_qst | 文件夾,存有填寫問卷時題目顯示模板文件 |
err_visit.html | 用戶訪問的問卷不存在時的錯誤頁面 |
index.html | 繼承自publish_base.html的頁面 |
questionnaire.html | 繼承自index.html的問卷背景頁面 |
questionnaire_list.html | 問卷上顯示的問題列表部件 |
questionnaire_success.html | 問卷提交成功的提示頁面 |
表13:questionnaire文件夾目錄表
其中publish_qst中的模板與上面提到的顯示模板基本一致,但取消了問題操作菜單。
Django 數據模型
使用了Django ORM進行數據庫的構建與管理。以下列出所使用的數據模型。
Admin
每條記錄表示一名管理員。
域名 | 描述 | 類型與限制 |
username | 用戶名。 | 字符串,最大長度20 |
description | 附加說明,通常填寫真實姓名。 | 字符串,最大長度100 |
password | 密碼。 | 字符串,最大長度32 |
| 電子郵箱。 | 字符串,最大長度254 |
User
每條記錄代表一名用戶。
域名 | 描述 | 類型與限制 |
student_id | 學生號碼。 | 字符串,最大長度20 |
username | 用戶名。 | 字符串,最大長度20 |
real_name | 真實姓名。 | 字符串,最大長度20 |
identity | 身份,大部分用戶為legaluser。 | 字符串,最大長度20 |
password | 密碼,鑒于已使用清華賬號登錄暫時棄之不用。 | 字符串,最大長度32 |
age | 年齡,用戶自行填寫。 | 字符串,最大長度18 |
gender | 性別。 | 字符串,最大長度10 |
status | 狀態,類似簽名的記錄。 | 字符串,最大長度400 |
address | 地址,用戶自行填寫。 | 字符串,最大長度400 |
tel | 電話,用戶自行填寫。 | 字符串,最大長度20 |
| 電子郵箱,用戶自行填寫。 | 字符串,最大長度254 |
Questionaire
每條記錄代表一張問卷。
域名 | 描述 | 類型與限制 |
questionaire_user | 問卷所屬用戶。 | User外鍵 |
questionaire_title | 問卷標題。 | 字符串,最大長度30 |
questionaire_introduction | 問卷介紹。 | 文本 |
questionaire_status | 問卷狀態,詳情見下。 | 字符串 |
questionaire_type | 問卷類型,詳情見下。 | 字符串 |
questionaire_time | 問卷創建時間。 | 字符串,最大長度50 |
questionaire_ip | 問卷創建者ip。 | ip |
questionaire_numOfQues | 問題數量。 | 整數 |
questionaire_numOfFilled | 已填寫次數。 | 整數 |
questionaire_haveMaxTime | 是否擁有最大填寫次數。 | 布爾 |
questionaire_maxTime | 最大填寫次數。 | 整數 |
questionaire_md5 | 問卷唯一標識,用創建時間+創建者id hash得到。 | 字符串,最大長度32 |
questionaire_status域可能的取值與含義如下:
值 | 描述 |
IN | 新建問卷 |
SA | 已保存問卷 |
LA | 已發布問卷 |
PA | 已暫停問卷 |
questionaire_type域可能的取值與含義如下:
值 | 描述 |
VO | 投票 |
LW | 實驗室招募 |
SU | 報名 |
Question
每條記錄代表一個問題。
域名 | 描述 | 類型與限制 |
questionaire_id | 問題所屬問卷,名字為歷史遺留問題 | Questionaire外鍵 |
question_text | 問題文本內容 | 文本 |
question_type | 問題類型,詳情見下 | 字符串 |
question_order | 問題在問卷中的序號 | 整數 |
question_choices | 選項數,對選擇題有意義 | 整數 |
question_time | 問題創建時間 | 字符串,最大長度20 |
question_fillinrow | 可以填寫的行數,對填空題有意義 | 整數 |
question_fillinhint | 提示文字,對填空題有意義 | 字符串,最大長度200 |
question_fillincheck | 填寫內容的檢查,對填空題有意義 | 字符串,最大長度200 |
question_mustfill | 是否必須填寫 | 布爾 |
question_minfill | 最少選擇的項數,對選擇題有意義 | 整數 |
question_maxfill | 最少選擇的項數,對選擇題有意義 | 整數 |
question_displayVotes | 是否顯示投票結果,對投票題有意義 | 布爾 |
question_ipTimes | 每ip的填寫上限,null則為無上限 | 整數 |
question_dayTimes | 每天的填寫上限,null則為無上限 | 整數 |
question_type域可能的取值與含義如下:
值 | 描述 |
SI | 單選題 |
MU | 多選題 |
FI | 填空題 |
VO | 投票題 |
MA | 打分題 |
SO | 排序題 |
Choice
每條記錄代表一個選項。
域名 | 描述 | 類型與限制 |
question | 選項所屬問題 | Question外鍵 |
choice_text | 選項文本內容 | 字符串,最大長度200 |
choice_order | 選項在問題中的序號 | 整數 |
choice_limit | 最大選擇次數,null則為無上限 | 整數 |
choice_hasPicture | 是否包含圖片 | 布爾 |
votes | 已選擇次數 | 整數 |
Filler
每條記錄代表一次填寫。
域名 | 描述 | 類型與限制 |
filler_ip | 填寫者ip | 字符串,最大長度30 |
filler_time | 填寫時間,與ip共同確定一個填寫 | 字符串,最大長度30 |
filler_address | 填寫者地址 | 字符串,最大長度50 |
filler_questionaire | 填寫所屬問卷 | Questionaire外鍵 |
Answer
每條記錄代表一個回答。
域名 | 描述 | 類型與限制 |
answer_filler | 回答所屬填寫 | Filler外鍵 |
answer_question | 回答所屬問題 | Question外鍵 |
answer_content | 回答內容 | 文本 |
answer_choice | 回答的選項,僅選擇題有意義 | Choice外鍵 |
HTML與CSS部分
概況
在前端設計部分,本項目使用了開源框架,經過發布者允許后利用了其中的部分html文件模板,經過優化和細節方面的修改,應用于本項目。如上節中提到的base.html文件,這些html文件模板主要用于用戶界面。并復用了該項目中使用的多種運行庫。同時本項目借鑒了上述開源項目的部分JS代碼,并根據自身需求加以修改和優化,這一部分將在下一節JavaScript代碼部分重點強調。
本項目用戶界面以外的部分由小組成員設計并實現,與使用了該框架的用戶界面部分風格有所不用,但是配色等整體印象大體一致,例如登陸界面以及問卷提交成功界面,這些界面基本上由靜態HTML文件實現,并沒有使用Bootstrap等框架。
主頁面情況
本項目的主頁面如下圖:
圖6:清華大學信息化統計平臺主頁面
頁面最頂端為導航欄,左側為側邊欄,右側為主頁面,對應上一節提到的base.html的block,在legalUser/index.html中具體實現。主頁面中每一個方框在html標簽中為一個div容器,通過Bootstrap中的col-md標簽來控制寬度并自適應高度。
單擊左邊欄中的按鈕會發送Ajax請求,動態的加載對應的主頁面部件,如下圖所示:
圖7:清華大學信息化統計平臺問卷設計界面
其它用戶界面的風格與實現與之類似,而上文提到的用戶登陸界面等其它一些界面的風格與之有所不同,下面以該界面為例,其html與css代碼位于login_page.html文件:
圖8:清華大學信息化統計平臺用戶登陸界面
該頁面中使用了表單form,圖像img和容器div,表單項目input等html標簽,css部分主要設置了部件顏色,間距,位置,大小等信息,并根據不同寬度屏幕設置了自適應寬度。
本項目中多次,多處使用了html的form表單標簽,后端對表單的處理方式為通過URL請求調用interface模塊中的接口,這些接口的具體定義見第三章內容,網頁端同時使用JS對表單的提交進行處理,詳見本章的JavaScript一節。
阻塞式窗口
阻塞式窗口的設置可以讓用戶優先響應某些事件,本項目中的阻塞式窗口有兩種類型,一種是包含復雜的HTML窗口,具體種類如表11所示,如圖9,另一種是簡單的確認框。
圖9:復雜HTML阻塞式窗口
圖10:簡單的確認框
移動端優化
本項目對移動端進行了部分優化,這些優化繼承于概述中提到的開源項目,并且針對用戶體驗進行了大幅度的優化,使得手機端的操作更加人性化,加載更加迅速。
圖11:移動端訪問本網站的效果
移動端優化如隱藏側邊欄為左側的滑動窗口,一些長度過長的表格進行分頁等。移動端的布局基于Bootstrap響應式布局,當頁面寬度低于一個固定值768px時會自動切換。
可排序表格
可排序表格為本項目的一個特點,繼承于概述中提到的開源項目,并針對本項目的特點進行了優化和重新設計,并且修復了一些運行中的錯誤,具體效果如下圖所示:
圖12:可排序表格
整個表格外部被一個div所容納,搜索框與表示表內項目數的氣泡均基于Bootstrap框架實現。表格內部被分為表頭和表體兩部分,分別由兩個HTML文件作為模板,詳情見上一節可排序表格的內容,表格的顯示與HTML標簽原生的表格與Bootstrap框架類似,但通過表格體item的篩選實現可排序功能。表格體內容的篩選通過調用后端interface模塊的接口進行,表格體內容的實時加載在后面JavaScript部分會提及。
JavaScript部分
概況
JavaScript部分解決了絕大多數頁面邏輯以及交互效果的實現,是本項目中代碼量最多的部分。本項目使用了兩個核心JS框架,分別為jQuery.js和History.js。
前者是當下最流行的JS庫之一,目前能看到的大多數網站都是基于jQuery開發的。它對ECMAScript原生操作進行了很好地包裝,提供了操作DOM元素的便捷方法,使前端開發更為方便和快捷。
后者則可以借助HTML5的函數修改瀏覽器的地址欄與前進/后退歷史。由于本項目使用了Ajax技術實現頁面切換,在進行跳轉的時候只載入了部分頁面,避免了實際的鏈接跳轉。因此瀏覽器不會修改地址欄與前進/后退歷史,如此地址欄的URL會一直保持第一個頁面的URL,如果用戶刷新頁面或者點擊前進/后退,就會跳轉到錯誤的頁面,與預期相應不符。History.js則解決了這個問題,使利用Ajax請求完成頁面切換的同時,也能正確響應刷新、前進、后退的操作。
除了兩個核心JS框架之外,在實現一些細節功能時本項目還用到了其他JavaScript開源庫,比如FusionCharts圖表套件、Validator表單驗證、TableExport導出文件、icheck美化選框等。再次向各位庫作者表示感謝。
另外,關于下文將要提到的JS文件,有一點需要說明的是,在各目錄中可能存在一些同名,但是以.min.js結尾的文件。這些文件是對應JS文件壓縮之后得到的小體積JS文件,內容上沒有任何區別。在實際部署使用時,應當使用這些JS文件。
文件列表
路徑 | 描述 |
base/js/charts.js | 渲染FusionCharts圖表。詳見“可視化圖表”部分。 |
base/js/scripts.js | 核心部分。詳見下文“核心部分介紹”。 |
bootstrap/js/* | Bootstrap相關的文件。 |
fusioncharts/* | FusionCharts圖表相關文件。 |
ie/* | 兼容IE的相關文件。包括舊版本的jQuery等。 |
jquery/jquery.js | jQuery的核心文件 |
jquery/jquery.fixer.js | 基于jQuery的簡易布局插件,用于確定左邊欄位置。 |
jquery/jquery.history.js | History.js框架核心文件。 |
jquery/jquery.scrollto.js | 基于jQuery的滾動插件。用于將頁面滾動到指定位置。 |
md5/md5.js | MD5加密。用于密碼和問序號等加密。 |
validator/validator.js | 表單驗證插件。 |
TableExport/* | 表格導出成文件插件。用于導出Excel表格。 |
icheck-1.x/icheck.js | 基于jQuery的選框美化插件。 |
FileSaver/* | 供TableExport使用的文件保存插件。 |
表14:JavaScript文件列表
核心部分介紹
interface模塊static/base/js文件夾中的scripts.js是本項目的核心JS文件,里面包括了一些常用的函數以及各頁面通用的一些操作,比如Ajax載入、表單提交、繪制圖表等。其中也包含了一些自定義的工具函數,方便各個地方調用。下面具體說明幾個核心函數的功能和屬性:
Ajax載入響應函數
loadContent(url, params, item_selector, load_params, callback)
通過Ajax請求加載指定url的頁面內容到#main-page上。
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
* url | string | 需要載入的目標URL。 |
params | JSON | Ajax請求附加的信息,根據具體頁面而變化。 |
item_selector | string | 對應左邊欄項目的id。 |
load_params | JSON | 載入時的選項。 |
callback | function() | 函數執行完后調用的回調函數。 |
load_params參數列表 | load_params參數列表 | load_params參數列表 |
replace | boolean | 是否是對頁面的更新,而非載入新的頁面。 |
anim | boolean | 是否使用淡入淡出的動畫效果。 |
表15:loadContent函數參數列表
loadContentOn(container, url, params, load_params, callback)
通過Ajax請求加載指定url的頁面內容到指定DOM對象container上。
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
* container | string | 待載入內容的DOM對象選擇器。 |
* url | string | 需要載入的目標URL。 |
params | JSON | Ajax請求附加的信息,根據具體頁面而變化。 |
load_params | JSON | 載入時的選項。 |
callback | function() | 函數執行完后調用的回調函數。 |
load_params參數列表 | load_params參數列表 | load_params參數列表 |
anim | boolean | 是否使用淡入淡出的動畫效果。 |
表16:loadContentOn函數參數列表
loadContentOfItem(item, load_params, callback)
通過Ajax請求加載左邊欄項目對應的主頁面。
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
* item | string | 待載入的左邊欄選擇器。 |
load_params | JSON | 載入時的選項。 |
callback | function() | 函數執行完后調用的回調函數。 |
load_params參數列表 | load_params參數列表 | load_params參數列表 |
replace | boolean | 是否是對頁面的更新,而非載入新的頁面。 |
anim | boolean | 是否使用淡入淡出的動畫效果。 |
表17:loadContentOfItem函數參數列表
displayContent(data, params, container, callback)
將Ajax請求得到的頁面內容data載入到指定DOM元素container中。
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
* data | string/object | 載入的頁面內容。可以使HTML字符串或DOM。 |
params | JSON | 載入時的選項。 |
container | string | 待載入內容的DOM對象選擇器,默認為主界面。 |
callback | function() | 函數執行完后調用的回調函數。 |
load_params參數列表 | load_params參數列表 | load_params參數列表 |
scroll | boolean | 是否將頁面滾動到帶載入對象的頂部。 |
anim | boolean | 是否使用淡入淡出的動畫效果。 |
表18:displayContent函數參數列表
表單提交處理函數
handleFormPost(form_selector, post_url, params)
通過Ajax請求加載指定url的頁面內容到#main-page上。
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
* form_selector | string | 需要處理的表單選擇器。 |
* post_url | string | 表單提交發送POST請求的目標URL。 |
params | JSON | 表單處理的選項。 |
params參數列表 | params參數列表 | params參數列表 |
success_callback | function(data) | 表單提交成功時調用的回調函數。 |
error_callback | function(data) | 表單提交失敗時調用的回調函數。 |
success_message | function(data) | 表單提交成功時顯示的提示信息。 |
before_submit | function(data) | 提交表單之前調用的回調函數。 |
表19:handleFormPost函數參數列表
彈出窗口函數
showConfirmModal(title, message, one_button, callback)
彈出Bootstrap風格的對話框。可以彈出只含有一個按鈕的提示對話框,也可以彈出包含兩個按鈕的的確認對話框。后者在點擊“確認”按鈕時會調用指定的回調函數。
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
* title | string | 對話框標題。 |
* message | string | 對話框內容。 |
one_button | boolean | 是否彈出只包含一個按鈕的對話框,默認false。 |
callback | function(event) | 點擊“確認”按鈕時調用的回調函數。 |
表20:showConfirmModal函數參數列表
showModal(url, id)
彈出指定的URL中的對話框。
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
* url | string | 對話框的URL。 |
* id | string | 該對話框DOM對象的ID。 |
表21:showModal函數參數列表
頁面更新及處理函數
initAjaxPage(container)
為指定DOM對象container中需要使用Ajax請求完成跳轉的鏈接(.ajax-link)進行點擊事件的綁定,通常在刷新頁面之后對刷新的DOM對象調用。
loadComplete()
刷新頁面內所有的數字氣泡(.badge),通常在刷新頁面之后調用。
resizeComponents()
頁面寬度發生變化時的處理函數,會調整頁面的最小高度,并觸發左邊欄的滾動事件,以更新其坐標。另外,函數還會調整對話框(阻塞式窗口)的暗色背景高度,因此在彈出對話框的函數中也會用到此函數。
圖表繪制函數
drawCharts(selected_charts)
對于指定的包含圖表的DOM對象,載入其中的FusionCharts圖表。詳見“可視化圖表”部分。
初始化函數
initLeftColumn()
處理左邊欄的相關事件,具體包括:
- 綁定移動端界面的彈出左側邊欄按鈕的點擊事件;
- 處理頂部標題中箭頭的方向切換;
- 綁定左側邊欄內部的滾動事件;
- 為側邊欄中非選中項目綁定點擊事件;
- 使用jQuery.fixer完成左側邊欄的頁面內位置處理。
自定義功能函數
stop_act(act_id, url, item)
停止收集問卷,向后臺發送消息并刷新當前頁面。
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
* act_id | string | 要停止的問卷ID。 |
* url | string | 通知后臺時要GET的目標URL。 |
* item | string | 當前所在頁面對應左邊欄的項目,用于刷新。 |
表21:stop_act函數參數列表
resume_act(act_id, url, item)
繼續收集問卷,向后臺發送消息并刷新當前頁面,參數同上。
remove_act(act_id, url, item)
刪除問卷,向后臺發送消息并刷新當前頁面,參數同上。
publish_act(act_id, url, modal_url)
發布問卷,彈出提示框,不要求用戶輸入郵箱,modal_url為對話框URL。
email_act(act_id, modal_url)
彈出發布問卷的對話框,需要用戶輸入聯系郵箱并將問卷和后臺鏈接發送至郵箱。
callRepeated(callback, cycles, time)
每隔一段時間反復調用指定的函數若干次。
animate(item, animation)
對指定DOM對象施加單次的Animate.css動畫(默認情況下動畫會循環播放)。
removePx(str)
從字符串中刪除末尾的“px“,并轉換成數字返回。用于處理CSS的height一類屬性。
可視化圖表
圖表繪制主要使用了FusionCharts開源庫(http://www.fusioncharts.com/dev/chart-attributes.html),項目中與其相關的JavaScript文件共有9個:
路徑 | 描述 |
base/js/charts.js | 渲染FusionCharts圖表。 |
fusioncharts/startrender.js | 指示開始渲染的文件。詳見下文。 |
fusioncharts/fusioncharts(共3個); ? fusioncharts/themes/(共4個) | Fusionchart圖表主題等相關文件。 |
表22:FusionCharts相關文件列表
其中charts.js中只有一個函數:
renderChart(container, type, data, params, callback)
用于在指定的DOM對象中繪制FusiongCharts圖表。具體參數含義基本類似其官方示例,可以參照官網的說明文檔。
由于FusionCharts的JS文件體積龐大,加載需要相當長的時間,因此需要使用非阻塞的載入方式。在繪制時先載入所有JS文件,最后載入startrender.js,其中包含開始繪制的指令。
fusioncharts文件夾下的其他文件則是圖表主題等配置文件,為開源庫自帶。
項目中用到圖表的頁面只有一個,為對單個題目進行分析的頁面,其中圖表頁面被單獨分離出來作為一個單獨的HTML(legalUser/statistics/charts/charts.html)。這個頁面中包含一些調用圖表繪制的JavaScript代碼,主要作用是初始化頁面內的圖表組件,并載入其他幾個JS文件。圖表的信息則是在Django模板渲染時就得到的,以JSON格式存入頁面之中。具體來說,該信息轉換為字符串存入待繪制的DOM對象的data-json屬性中。圖表的類型則存在data-type屬性中。drawCharts函數會讀取DOM對象的這兩個屬性,并調用renderChart函數完成繪制。
導出表格和美化選框
導出表格使用的是github上TableExport插件,使用非常簡單,只需要對需要導出的表格調用tableExport函數即可,具體參數如下:
參數列表 | 參數列表 | 參數列表 |
參數 | 類型 | 描述 |
headings | boolean | 是否顯示table headings。 |
footers | boolean | 是否顯示table footers。 |
formats | string[] | 導出的文件類型集合。 |
fileName | string | 導出文件的文件名。 |
bootstrap | boolean | 是否采用Bootstrap風格的按鈕。 |
position | string | 取值為top或bottom,決定按鈕位置。 |
表23:tableExport函數參數列表
本項目中需要導出的是填寫問卷的情況。導出的這個表格包含信息較多,頁面上沒有哪個顯示的表格同時包含這么多的信息,所以單獨設置了一個隱藏的表格專門用來導出,在頁面上不顯示(legalUser/statistics/print_table.html)。其中包含一段JavaScript調用tableExport函數來支持表格導出。使用時只要在需要導出表格的地方使用”{% include ... %}”語法包含該HTML頁面即可實現導出。
選框上由于Bootstrap自帶的單選和復選框不甚美觀,所以使用了iCheck插件來美化選框。在所有使用到選框的頁面中加入iCheck的配置語句,即可把選框的樣式重新設置為指定的風格。同時該插件還可以自定義增加選框的點擊范圍,使點擊在較小的屏幕上也變得更加容易。插件也支持各種回調函數,用于處理選中和取消選中的事件。
五、總結
這次參與本項目是本小組所有成員第一次接觸這種系統的,可以被稱作軟件工程的軟件開發。在本項目開始之前的幾年中,我們在大作業中也完成了各種各樣的“軟件”,例如大一時候完成的中英文字典,FlowFree小游戲,在線五子棋,大二小學期完成的安卓APP等。在完成了本項目之后我們深刻體會到了即使是簡化后的軟件開發流程也比原先所接觸的這些大作業要復雜的多,對軟件品質的要求也要高得多。
從十月初理想到十一月末正式完成,這兩個月時間的經歷中,我們覺得以下幾點是給我們感觸最大的部分,也是我們在這門課中除了完成課程以外最大的收獲。
作為計算機行業的從業人員,學習能力非常重要
本項目開發的過程中,主要使用了Django+Python,HTML與CSS,javaScript三種語言,除了Django+Python的架構一年多之前曾經短暫接觸過,并且留下的印象并不深外,其余的語言可以說從來沒有接觸過。在本次開發的最初階段,小組成員的主要工作便是學習數門新的語言,并且在沒有完全掌握的情況下便投入到了開發中。
為此一度出現了多人工作進度處于停滯狀態的現象,以及開始開發時想要獲得一個能夠被接受的版本非常難。小組某位成員剛開始接觸HTML加上CSS,便接手任務繪制用戶登陸界面,在最終完成之前被否決了三個版本。在后期開發熟練后情況有了很大好轉。
在以后的工作中,作為計算機行業的從業人員,一定也會遇到許多這種情況,會去接觸一些新的工具并嘗試去使用它,不能有吃老本的思想,一定要貫徹終身學習的方針。
團隊工作中,一定要進行充分的溝通
本小組的成員均來自一個班,其中三人更是來自同一個宿舍,按照常理來講溝通渠道暢通無比,然而在實際開發的過程中還是或多或少出現了溝通方面的問題。這方面的問題主要出現在開發工作的初期,由于所有人對于本項目開發的構想均還沒有一個明確的目標,再加上適逢國慶假期,溝通略有不便,因此造成了本項目啟動階段非常緩慢的問題。
在這里要感謝小組長王晨陽個人的努力,他依靠自身的能力率先確立了一個大致的方案,并完成了初步的實現,其余小組成員落實這個方案的實現,最終使我們的開發走上了正軌。但是凡事不能總依靠個人的力量,在實際的開發過程中一定要注意充分的溝通。