iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 25
0
Modern Web

從零開始的個人化記帳程式開發系列 第 25

記帳程式 (25):專案開發 Part.5 - 完成月曆串接記帳列表

昨天先引入了 Day.js 後,接下來要繼續完成選取月曆上日期時,要對應到該日記帳清單的增刪改查。

關於這個手刻月曆元件

首先要來重新回憶一下當初這個 component 是怎麼做的,一看不得了,這個 Calendar 原本要傳入選定的日期,以今天的日期 2019-10-11 為例,要這樣傳進去:

{
  year: 2019,
  month: 9,
  day: 11
}

日期是傳物件就算了,但月份的部分竟然還要另外減一。

是我。

於是將原本的元件改造一下,改為將選定的日期傳出來就好,不餵入其他 props,但回傳的日期格式有點偷懶就先沒動了。

串接各個元件

接著要開始將所有元件串接上月曆了,這邊稍微畫個圖,看看整體開發完後,各個元件的關係及資料流會清楚一點:

還是我。

開發完成後一直覺得資料流好像可以再優化,圖畫完後可以更容易看清楚問題在哪,像是 BillingCalendar 這一層有點多餘,並且將一些共用資料放在 store 用 mapState 直接對,會比放在 Billing 資料一定要透過父層傳來傳去更方便。

於是不偷懶的調整成下面這樣:

稍微乾淨一點了,果然開始動手打程式前不思考就直接寫,會很容易寫出爛 code。以下先解釋一下每個角色分別是畫面上哪一個部分:

  • Billing:是整個月記帳本的最外層頁面,其中內容切為三個子元件
    • Calendar:月曆元件。
    • BillingList:記帳紀錄列表。
    • BillingDialog:新增與編輯的表單對話框。
  • Store:這裡指 billing 的 store module,負責儲存資料並且與後端溝通。
  • FireStore:後端 API server 與資料庫。

選定日期顯示對應記帳紀錄

當使用者點擊畫面上的月曆選定日期時,會觸發 Calendar 中的 select 事件往上傳給 Billing

Billing 收到新的日期時,本身的事件處理也會觸發去執行呼叫 action,去重讀當日的記帳紀錄:

handleSelectedDate(date) {
  // 處理 Calendar 回傳的日期格式
  const { year, month, day } = date
  const zMonth = ('0' + (month + 1)).slice(-2)
  const zDay = ('0' + day).slice(-2)
  this.selectedDate = `${year}-${zMonth}-${zDay}`

  // 重拉資料
  this.isLoading = true
  this.$store
    .dispatch('billing/getExpenseData', date)
    .then(() => {
      this.isLoading = false
    })
    .catch(status => console.log(status))
}

當資料回來後會更新 store 的 expenseData,這時候 BillingList 就會收到新的資料而自動更新畫面。

新增紀錄時對應日期的調整

由於原本之前開發時,還沒有加上日期的欄位,所以調整資料結構花了一番功夫。

而新增的部分遇到一個比較算是操作流程的問題,因為按下新增時會跳出一個 dialog,裡面可以選擇要紀錄這一筆帳的日期。

那假如今天我的月曆點在 10/11 的地方按新增,然後新增日期選擇 10/12,依照原本的邏輯,儲存後記帳資料更新會顯現 10/12 的資料,但我的月曆卻仍選在 10/11 上面,而造成兩者不對應的問題。

想到的解法有兩種:

  • 在新增的表單時,仍可以選擇其他日期,儲存後顯示那一日的記帳資料,並且上方月曆也對應換成那一天。
  • 在新增的表單時,不可以選擇其他日期,直接帶入月曆上選定的日期並 disable。要加別天的要在月曆上直接另外選擇。

後來偷懶選擇第二種,變成是根據月曆選定的日期,只做那一天的操作與重載資料,體驗沒那麼好但開發相對單純。

向 Firestore 拉資料選定特定日期

這邊比較值得紀錄的是現在新增、編輯、刪除後,要重新拉回特定日期的資料,那這個要怎麼修改 API 呢?

查了一下語法,Firestore 的讀取有提供一個 where 的寫法,其實就像 SQL 語法中的篩選條件一樣:

db.collection('expense')
  .where('date', '==', date)
  .get()
  .then(querySnapshot => {
    const documents = querySnapshot.docs.map(doc => {
      return {
        ...doc.data(),
        id: doc.id
      }
    })
    commit('SET_EXPENSE_DATA', documents)
    resolve()
  })

在原本讀取集合中的文件資料後,加上 where('date', '==', date),就能夠去直接拉取文件中欄位 date 與我指定的日期一致的資料,非常方便吧!

後記

今天花了一番功夫將月曆選擇對應記帳資訊的功能串起來了,也總算完成一個基本功能了。

雖然只有支出的部分,這部分要完整還有「支出、收入、轉帳共用表單」、「分類管理」的功能還沒做,真覺得當初前面怎麼有勇氣列這麼多開發功能 XD

我們明天見~


上一篇
記帳程式 (24):專案開發 Part.4 - Day.js 安裝及 Vue.js global method 筆記
下一篇
記帳程式 (26):專案開發 Part.6 - 支出分類
系列文
從零開始的個人化記帳程式開發30

1 則留言

0
挖洗菜呱
iT邦新手 5 級 ‧ 2019-10-15 13:36:55

不是都是先寫了再說嘛XD
寫了才知道原來寫這麼爛
還是因為我太菜QQ

Dez iT邦新手 5 級‧ 2019-10-15 14:28:35 檢舉

因為好像常聽別人在教學時說:「別急著寫程式,先思考清楚如何拆解問題及設計資料結構後再下手。」

但算是有時候為了求快的確都是先寫了再說,先求有再求好也是一種開發方式,然後就會容易產出一堆爛 code /images/emoticon/emoticon07.gif

我要留言

立即登入留言