第三流專案:以資料為中心的開發 - 程式碼研究所。
該項目是使用 Flask Microframework 建造的,它可以用作手動秒錶,為多名運動員的游泳和田徑比賽計時。該應用程式的目標是透過減少單獨計時的人數並直接儲存時間(而不是保留書面文件)來提高運動計時的效率。
此應用程式僅供教育用途。此應用程式不可用於商業用途。
可以在此處找到該專案的現場演示。這個應用程式託管在 Heroku 上。時間儲存在 MongoDB 中。
這個計時助手應用程式的想法來自於我童年時接觸游泳的經驗。我注意到需要有很多人參與計時過程,因為池中的觸控板由於各種原因並不總是能產生準確或可讀的時間。此外,教練和運動員直到比賽結束後才能看到最後的時間或分段,除非有多個人在甲板上為每條泳道計時,並將時間寫在剪貼板上。
我看到了這個機會,創建了一個應用程序,可以減少參與計時過程的人員數量,希望提高比賽效率以及對運動員和教練的回饋。該應用程式可以針對任何計時運動進行最佳化,並且該版本適用於游泳和田徑運動。
教練和計時員都可以選擇運動項目、比賽、賽事、預賽和泳道號碼,這些都有助於他們追蹤比賽中發生的情況。它還允許他們在比賽結束後向運動員提供即時回饋,因為時間會在您儲存它們然後點擊「查看時間」後顯示。我還想確保他們能夠看到會議的累積結果,而不是一次只能看到一項活動。
此設計沒有使用主題,之所以選擇現代設計,是因為頁面上有大量計時器和數據,可能會顯得混亂且無組織。我不想要這個,所以雖然我想要在一個頁面上顯示計時器、時間和事件選項,但我認為將頁面垂直分成三部分是實現此目的的最佳方法,在每個三分之一之間產生明顯的差異。
Timing Assistant 是使用 Python 中的 Flask Microframework 建構的,後端有 NoSQL (MongoDB) 資料庫,前端有 HTML、CSS、Javascript 和 jQuery,並且用於秒錶功能,透過 AJAX 連接到後端。
在應用程式的主頁上,使用者輸入他們想要參加的運動、球隊名稱、使用者名稱和比賽名稱。此操作會將他們帶到秒錶頁面,然後他們可以在其中選擇他們想要計時的賽事和熱度。使用者最多可以為三個車道計時,並為所有三個車道進行分段。在所有三個小計時器停止後,使用者必須手動停止主計時器,因為它們是單獨設定的。然而,如果教練想知道比賽持續了多長時間並比較游泳運動員的時間與最終完賽者的時間,這可能特別有用。主定時器的時間不會儲存到資料庫中。
一旦他們點擊“提交”,事件和熱度就會出現。然後,他們可以透過按主秒錶上的「開始」開始最多三個車道的計時。這將啟動所有四個秒錶,但是,只有最後三個會保存在資料庫中。可以選擇使用“SPLIT”按鈕單獨收集每個車道的分割時間。每個計時器都可以單獨停止和啟動,主計時器控制所有碼錶(啟動、停止和重置)。
透過點擊“保存時間”,將使用 Javascript 檔案中的 AJAX 呼叫將時間推送到 Flask 來保存時間,同時 Flask 連接到 MongoDB。儲存時間後,透過點擊“查看時間”,時間將顯示在秒錶下方。
數據也將在沒有指定賽事或預賽的情況下保存(查看時間時這些欄位將為空白)。如果教練想在練習中而不是在比賽中使用秒錶,這可能會很有用。
我希望教練能夠有機會下載 PDF 或其他文件格式的資料。從長遠來看,這將使他們能夠保留所有手動計時記錄,而不必依賴手寫數據或每次想回去查看舊比賽時都依賴該網站。
我還想讓教練根據每場預賽的運動員人數來選擇他們想要查看的秒錶數量。目前,您一次只能為 3 名運動員計時,並且無法選擇為少於 3 名的運動員計時。
我還想實現“練習模式”和“比賽模式”,以便為比賽和練習提供更複雜的計時。比賽模式將對選擇賽事或預賽產生更多限制,並允許教練選擇他們想要參加多少泳道。練習模式將允許教練記錄他們節省的時間(針對特定的訓練等),而不必指定賽事或預賽。
該專案的所有測試都是手動完成的。登陸頁面上的表單在輸入標籤上具有必需的屬性,以防止使用者不填寫表單中的字段,因為這將導致 400 錯誤,因為 Flask 應用程式路由依賴這些輸入。
透過控制台測試 Ajax 功能和「儲存時間」按鈕,並驗證資料在 MongoDB 中的顯示格式是否正確。還測試了從計時器收集的數據和預期的數據結構。
每個通道一個文件單獨節省時間:

在同一文件中顯示泳道的時間(注意:出於測試目的,此處僅保存了兩個泳道,以確保兩個泳道會顯示在同一文檔中。):

正確的資料結構:

秒錶的測試也是手動完成的,以確保主重置按鈕重置秒錶並清除所有計時器的分段,而每個單獨的秒錶僅清除自己的時間和分段。此外,還針對啟動/停止功能進行了測試,因為主秒錶控制所有碼錶,而各個碼錶應僅控制自己的啟動/停止功能。
所有 Flask 路徑也都經過測試,以確保所有連結都有效,並且可以處理輸入中的任何不常見值,並且可以透過 HTML 檔案中的 Jinja 正確顯示輸入。
在測試過程中,我意識到兩個用戶可能具有相同的會議名稱或相同的俱樂部名稱,因此使用戶有可能遇到其他人的資料。因此,要查看模板中的時間,我添加了以下內容,以確保登入頁面上的三個輸入欄位必須匹配才能顯示相應的時間。這需要正確的團隊名稱、使用者名稱和會議名稱進行匹配,以防止交叉保存或交叉查看時間。
{% if time.team == team %}
{% if time.username == username %}
{% if time.meet == meets %}
每個車道的分割最初以以下格式顯示:
split: ["00:02.2300:01.45"]
但是,我希望它們出現在這樣的清單中:
split: ["00:02.23", "00:01.45"]
因此,我必須實現一種列表理解,以每 9 個字元將該字串分成列表中的多個字串(如果對一條通道進行多次分割)。
在 HTML timer_page.html 中,為 AJAX 函數發送資料的表單看起來有一個雜散結束標記,但是,需要包含所有最終時間、分割和車道數據,以便將時間保存到 MongoDB 。由於需要顯示樣式和其他元素,表單看起來確實與其他元素不符。另外,查看 HTML 有空標籤,但是,這是使用 jQuery 將分割時間插入 HTML 的地方。
儲存時間時,如果為每個計時器選擇相同的泳道(例如泳道 1),則查看時間中只會顯示泳道 1 時間之一。但是,您必須選擇一條通道,因為由於資料結構的性質,如果沒有它,您將無法查看已儲存的時間。車道下拉清單預設為保存在車道 1、區域 2 和區域 3,以防使用者未指定車道。我希望實現一個驗證,如果使用者在預賽中為兩個泳道選擇相同的泳道編號,將禁止節省時間。
運行秒錶的 Javascript 函數是根據 Sara 的針對此應用程式的秒錶編碼教學進行修改的。一些 HTML 也是按照她的範例建模的,但進行了修改以適應樣式、多個按鈕、分割和通道。
對於JavaScript,修改了重置按鈕的重置功能,以重置所有秒錶而不是刷新頁面,並且刪除了每個小秒錶的單獨重置按鈕,因為它對於該專案的使用者體驗來說是不必要的功能。還新增了拆分功能。使用 jQuery 修改開始/停止函數以變更按鈕的樣式。為使用者體驗添加了一個主秒錶,因此教練可以看到總時間以及個人時間,類似於游泳記分板。使用 Ajax 新增了用於將值傳遞到 Flask 和 MongoDB 的「儲存」按鈕。
Ajax 函數是根據 Stack Overflow 上的這篇文章建模的,並透過查看其他 Ajax 使用和語法的模式進行了修改以適應該專案。新增了 PreventDefault 以防止在進行 AJAX 呼叫時重新載入頁面。
Jinja 中的遞歸用於迭代 Python 中的巢狀字典,透過確保所有通道都循環並顯示來正確渲染時間和滿足資料。遵循 Stack Overflow 中的這種方法作為指導,並根據我的資料結構的性質進行修改。
嘗試重構秒錶的 javascript 函數,以便使用者可以根據所選車道的數量決定在螢幕上顯示多少個秒錶。
var stopwatches = [ ] ;
var i ;
for ( i = 0 ; i <= 1 ; i ++ ) {
var stopwatch = new timing ( "timerLabel" + i , "start" + i , "splitLabel" + i ) ;
stopwatches . push ( stopwatch ) ;
console . log ( i ) ;
document . getElementById ( "start" + i ) . onclick = function ( ) {
stopwatches [ i ] . start ( ) ;
}
document . getElementById ( "reset" + i ) . onclick = function ( ) {
stopwatches [ i ] . reset ( ) ;
}
document . getElementById ( "split" + i ) . onclick = function ( ) {
stopwatches [ i ] . split ( ) ;
}
console . log ( stopwatches ) ;
}當嘗試在這樣的 for 迴圈中寫入這些內容時,stopwatches[i].start() 不會將i讀取為可以更改的變量,但是,當它被硬編碼時,就沒有問題了:
document . getElementById ( "reset" + i ) . onclick = function ( ) {
stopwatches [ 0 ] . reset ( ) ;
}
document . getElementById ( "split" + i ) . onclick = function ( ) {
stopwatches [ 0 ] . split ( ) ;
}我嘗試以不同的方式處理它,其中涉及 if 語句來顯示相應的秒錶。
嘗試將i作為從上面的 for 循環獲取的參數傳遞給函數,但沒有成功:
function chooseNumberOfStopwatches ( i ) {
if ( i == 1 ) {
stopwatches_one . start ( ) ;
}
else if ( i == 2 ) {
stopwatches_one . start ( ) ;
stopwatches_two . start ( ) ;
} else {
console . log ( 'else' ) ;
}
}如果您有興趣複製此儲存庫,請在終端機中執行以下命令來設定和安裝requirements.txt中的所有內容:
$ sudo pip3 -r install requirements.txt
請注意,我在這個專案中使用了 Cloud9,因此如果您使用不同的編輯器,終端命令可能會有所不同。請參閱您所使用的編輯器的文檔,以取得有關特定於編輯器的終端命令的更多資訊。 MongoDB 的所有金鑰都需要單獨獲取,因為它們是隱藏的並且是特定於我的。