作業所屬課程 | 班級的連結 |
---|---|
作業要求 | 2024秋軟體工程現場程式設計作業 - 作業 - 軟體工程2024 - 班級部落格 - 部落格園 |
作業目標 | 現場極限程式設計,製作一個個人記賬本程式。 |
團隊名稱 | iman |
團隊成員 | 102202146 - 藍敏龍, 102201225 - 陳碧煌, 102202105 - 王梓銘, 102202124 - 阿依娜孜, 102202135 - 施宇翔, 102202134 - 承宇豪, 102202117 - 楊邑豪, 102202122 - 張誠坤, 102201506 - 劉宇傑, 102201137 - 郭劍敏 |
一、職責分工
PM-產品經理
102202146 - 藍敏龍 | 進行任務拆分,統籌組員分工。整體功能設計。 |
---|
前端設計小組
102201225 - 陳碧煌 | 負責總體介面規劃,賬單收支統計功能設計 |
---|---|
102202105 - 王梓銘 | 負責前端介面繪製和美工設計 |
102202124 - 阿依娜孜 | 負責基礎記賬功能設計 |
102201506 - 劉宇傑 | 負責使用者個人介面設計 |
102201137 - 郭劍敏 | 負責除錯測試前端功能 |
後端開發與測試小組
102202135 - 施宇翔 | 負責前後端介面呼叫與資料處理,賬單收支統計與GitHub倉庫建立與管理 |
---|---|
102202134 - 承宇豪 | 編寫賬單新增和記錄模組和除錯賬單新增模組 |
102202117 - 楊邑豪 | 編寫賬單查詢模組,除錯賬單查詢功能 |
102202122 - 張誠坤 | 除錯記賬整體功能,測試功能完備性 |
二、程式執行環境
前端:VUE2
後端:Python3.9 Django3.1.5
三、執行截圖與影片
四、關鍵程式碼展示
讀取和儲存每條賬單記錄
# 初始化 JSON 檔案
def initialize_json_file():
if not os.path.exists(JSON_FILE_PATH):
with open(JSON_FILE_PATH, mode='w', encoding='utf-8') as file:
json.dump([], file) # 建立一個空的 JSON 陣列
# 讀取所有記錄
def read_records():
initialize_json_file() # 確保檔案存在
with open(JSON_FILE_PATH, mode='r', encoding='utf-8') as file:
records = json.load(file) # 從 JSON 檔案載入記錄
return records
# 儲存新記錄
def save_record(year, month, day, amount, category, remark):
initialize_json_file() # 確保檔案存在
records = read_records() # 讀取現有記錄以獲取最新的 ID
record_id = len(records) # 新記錄的 ID 為現有記錄的數量
new_record = {
"id": record_id,
"year": year,
"month": month,
"day": day,
"amount": amount,
"category": category,
"remark": remark
}
records.append(new_record) # 將新記錄新增到現有記錄中
# 將更新後的記錄寫回 JSON 檔案
with open(JSON_FILE_PATH, mode='w', encoding='utf-8') as file:
json.dump(records, file, ensure_ascii=False, indent=4) # 寫入所有記錄
# 寫入所有記錄(用於更新)
def write_all_records(records):
with open(JSON_FILE_PATH, mode='w', encoding='utf-8') as file:
json.dump(records, file, ensure_ascii=False, indent=4) # 寫入所有記錄
賬單展示介面:
使用 v-for
迴圈遍歷 dataList
,動態生成每一條記錄的展示。
<view class="item" v-for="(item, index) in dataList" :key="index">
<view class="count">
<view class="sa-flex-x">
<view>日期: {{item.create_time}}</view>
<view class="week">({{item.create_time | weekFormat}})</view>
</view>
</view>
<view class="sa-flex-x space content">
<view class="sa-flex-x center cover" :class="item.type==1 ? 'income':'expend'">
<image :src="'../../static/icon/'+item.icon+'.png'" mode="aspectFill"></image>
</view>
<view class="info">
<view class="name">{{item.content}}</view>
<view class="desc" v-if="item.remarks">{{item.remarks}}</view>
</view>
<view class="sa-flex-x money" :class="item.type==1 ? 'income':'expend'">
<text class="symbol">{{item.type==1 ? '+':'-'}}</text>
<text>{{item.money}}</text>
</view>
</view>
</view>
weekFormat
過濾器用於格式化日期以顯示星期幾。
filters: {
weekFormat(val) {
return format.getWeekDay(val);
}
},
getData()
從本地儲存中獲取記錄並解析。total()
方法計算總支出、總收入、筆數和結餘,並更新狀態。
getData() {
uni.getStorage({
key: 'sa_storage_bill',
success: res => {
const data = JSON.parse(res.data);
this.dataList = JSON.parse(res.data);
this.total();
}
})
},
total() {
const data = this.dataList;
const group = format.arrayGroup(data, 'type');
if(Object.keys(group).length > 0) {
const expendMoney = group[0].reduce((sum, item) => sum + Number(item.money), 0);
this.totalExpend = expendMoney.toFixed(2);
this.sumExpend = group[0].length;
}
if(Object.keys(group).length > 1) {
const incomeMoney = group[1].reduce((sum, item) => sum + Number(item.money), 0);
this.totalIncome = incomeMoney.toFixed(2);
this.sumIncome = group[1].length;
}
this.sumCount = data.length;
this.totalbalance = (this.totalIncome - this.totalExpend).toFixed(2);
}
五、亮點功能
用圖表展示賬單收支統計
將按天聚合的金額按日期排序,使用 Matplotlib 繪製折線圖,設定圖表的大小、標題、X 軸和 Y 軸標籤,並新增網格。構造影像的絕對 URL,並將其作為響應返回給客戶端。
@api_view(['POST'])
def get_records_image(request):
records = read_records()
# 獲取查詢引數
year = request.data.get('year')
month = request.data.get('month')
category = request.data.get('category')
# 根據查詢條件過濾記錄
if year is not None:
records = [record for record in records if record['year'] == int(year)]
if month is not None:
records = [record for record in records if record['month'] == int(month)]
if category is not None:
records = [record for record in records if record['category'] == category]
# 如果沒有記錄,返回錯誤資訊
if not records:
return Response({"error": "No records found"}, status=404)
# 準備資料用於聚合
daily_totals = defaultdict(int)
for record in records:
day = record['day']
amount = record['amount']
daily_totals[day] += amount
# 將聚合後的資料分開為天和對應的總金額
days = sorted(daily_totals.keys())
amounts = [daily_totals[day] for day in days]
# 繪製折線圖
plt.figure(figsize=(10, 5))
plt.plot(days, amounts, marker='o')
plt.title(f'Records for {year}-{month}')
plt.xlabel('Days')
plt.ylabel('Total Amount')
plt.grid()
# 儲存影像到本地
image_path = os.path.join(settings.MEDIA_ROOT, 'charts', f'records_{year}_{month}_{category}.png')
plt.savefig(image_path)
plt.close()
# 返回影像的 URL
image_url = f"{request.build_absolute_uri(settings.MEDIA_URL)}charts/records_{year}_{month}_{category}.png"
return Response({"image_url": image_url})
六、在編碼、爭論、複審等活動中花費時間較長,給你們較大收穫的事件:
-
學習GitHub的協作程式設計
在專案的初期階段,我們對GitHub的協作操作還不夠熟悉,出現了一些操作失誤。一次因為版本合併問題,不得不重建倉庫,已經上傳的程式碼需要重新提交。雖然這個過程有些繁瑣,但我們對GitHub協作有了更深的理解,認識到它在版本管理和團隊協作中的巨大優勢。(棟:不要使用QQ傳檔案!)
-
前後端介面的聯調測試
在開發過程中,前後端介面聯調耗費了大量時間。尤其是在資料格式和介面呼叫方面,前後端經常出現對不上的情況。這裡非常感謝我們的後端小夥伴,他們的“可以接可以接”讓人心裡暖暖嘟。
-
功能需求與技術實現的取捨
因為三小時時間非常有限,而團隊大家想法非常多想實現的功能也不少,但是考慮到整體框架的實現,我們還是做了很多取捨,最重要的是實現整體快速迭代的開發。
-
使用Matplotlib展示資料
在設計賬單收支統計的圖表功能時,我們第一次嘗試用Matplotlib來展示資料。這個地方我們碰了非常多壁,大家一起學習,最後搞定了圖表展示這一問題。
七、團隊成員感悟:
-
藍敏龍 (產品經理)
作為產品經理,我的任務是統籌全域性,確保每個成員都能在各自的崗位上發揮最大效能。在任務拆分的過程中,我意識到良好的溝通是成功的關鍵。這個極限程式設計對我們一個小團隊來說非常具有挑戰性,但是最後還是成功的做出了一個相對成熟的man記賬!
-
陳碧煌 (前端設計)
這次程式設計給我最大的挑戰其實是協作程式設計,一開始我覺得記賬本很簡單,還樂呵呵的跟隊友說man記賬可以用到我們的man遊中,但是協作程式設計卻給我帶來了很大的挑戰。在最開始pull和merge產生了一些失誤,幸虧有隊友的幫助,我也能在完成自己的工作部分的同時,也協作到團隊的整體工作中,整體來說是收穫滿滿的一次體驗。
-
王梓銘 (前端設計)
在這次團隊程式設計中我學到了很多新東西,雖然寫的程式碼量不多,但是我透過與隊友的討論以及實際程式設計學到了很多前端的注意事項,在和團隊的討論中深刻地體會到了和大家討論的時候效率確實會變高,希望以後還有更多的機會參加團隊程式設計。
-
阿依娜孜 (前端設計)
負責基礎記賬功能設計的過程中,我深入學習了資料結構和邏輯實現。實現一個高效的記賬功能不僅需要考慮使用者的輸入體驗,還要考慮資料的準確性和儲存效率。透過這個專案,我對前端技術有了更深入的認識,特別是在VUE框架下如何實現資料繫結和事件處理,讓我的程式設計能力得到了提升。
-
施宇翔 (後端開發)
作為後端開發人員,我主要負責前後端介面的呼叫與資料處理。在這個專案中,我學會了如何設計高效的API,確保前端能夠順利獲取資料。遇到的挑戰讓我對Django框架有了更深入的理解,也讓我認識到良好文件的重要性。透過與前端團隊的不斷溝通,我體會到協作程式設計的樂趣與意義。
-
承宇豪 (後端開發)
在這次專案中,我負責編寫賬單新增和記錄模組的工作。在實現賬單新增功能時,我遇到了一些挑戰,透過查閱文件和進行多次除錯,我學會了使用Django中的序列化器來驗證和處理資料。這不僅提高了我的程式設計技能,也讓我更加重視程式碼的規範性和可維護性。與前端團隊的合作讓我認識到,良好的介面設計是保證資料順利流動的關鍵,未來我會繼續在這方面努力。
-
楊邑豪 (後端開發)
在編寫賬單查詢模組的過程中,我負責實現查詢功能並進行除錯。這個階段的工作讓我意識到後端系統的複雜性,以及如何根據不同的條件快速過濾和返回資料。為了實現高效的查詢功能,我深入學習了Django ORM的使用,並嘗試最佳化查詢邏輯。在測試階段,我和前端團隊密切合作,確保介面能夠準確地響應請求。
-
劉宇傑 (前端設計)
在使用者個人介面設計中,我提升了使用者體驗的思維,學會了如何更好地展現資訊。
-
郭劍敏 (前端設計)
除錯前端功能的過程讓我認識到測試的重要性,發現問題並解決是提升專案質量的關鍵。
-
張誠坤 (後端開發)
除錯整體功能讓我意識到團隊協作的重要性,溝通能有效提高工作效率和專案質量。
八、PSP:
PSP | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 5 | 5 |
Development | 開發 | 150 | 250 |
Analysis | 需求分析 | 10 | 20 |
Design | 具體設計 | 15 | 30 |
Coding | 具體編碼 | 120 | 180 |
Test | 測試 | 20 | 20 |
合計 | 180 | 255 |
九、GitHub 倉庫地址和 commit 記錄:
倉庫地址:man記賬
十、組員貢獻評分
組員 | 分數 | 組員 | 分數 |
---|---|---|---|
102202146 - 藍敏龍 | 95 | 102202134 - 承宇豪 | 95 |
102201225 - 陳碧煌 | 96 | 102202117 - 楊邑豪 | 95 |
102202105 - 王梓銘 | 94 | 102202122 - 張誠坤 | 83 |
102202124 - 阿依娜孜 | 97 | 102201506 - 劉宇傑 | 89 |
102202135 - 施宇翔 | 98 | 102201137 - 郭劍敏 | 86 |