mirror of
https://github.com/henry4682/finance_app.git
synced 2026-07-16 00:10:00 +00:00
fix: add md & fix dateformat & add note
All checks were successful
Laravel-Oracle-Deploy / redeploy (push) Successful in 1m10s
All checks were successful
Laravel-Oracle-Deploy / redeploy (push) Successful in 1m10s
This commit is contained in:
@@ -15,21 +15,42 @@ class DashboardController extends Controller
|
|||||||
$userId = Auth::id();
|
$userId = Auth::id();
|
||||||
$now = Carbon::now();
|
$now = Carbon::now();
|
||||||
|
|
||||||
|
$latestMonth = $now->copy();
|
||||||
|
$latestYear = $latestMonth->year;
|
||||||
|
|
||||||
// 1. 本月基礎統計 (用一個查詢同時撈出「總金額」與「總筆數」)
|
// 1. 本月基礎統計 (用一個查詢同時撈出「總金額」與「總筆數」)
|
||||||
$monthStats = Expense::where('user_id', $userId)
|
$monthStats = Expense::where('user_id', $userId)
|
||||||
->whereYear('date', $now->year)
|
->whereYear('date', $latestYear)
|
||||||
->whereMonth('date', $now->month)
|
->whereMonth('date', $latestMonth)
|
||||||
->selectRaw('SUM(amount) as total_amount, COUNT(id) as total_count')
|
->selectRaw('SUM(amount) as total_amount, COUNT(id) as total_count')
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
|
if (!$monthStats || $monthStats->total_amount == 0) {
|
||||||
|
// 改用 first() 確保能抓到單筆資料
|
||||||
|
$latestExpense = Expense::where('user_id', $userId)->latest('date')->first();
|
||||||
|
|
||||||
|
if ($latestExpense) {
|
||||||
|
$targetDate = Carbon::parse($latestExpense->date);
|
||||||
|
$latestYear = $targetDate->year;
|
||||||
|
$latestMonth = $targetDate->month;
|
||||||
|
|
||||||
|
// 重新撈取該月份的統計資料
|
||||||
|
$monthStats = Expense::where('user_id', $userId)
|
||||||
|
->whereYear('date', $latestYear)
|
||||||
|
->whereMonth('date', $latestMonth)
|
||||||
|
->selectRaw('SUM(amount) as total_amount, COUNT(id) as total_count')
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$monthlyTotal = (float) ($monthStats->total_amount ?? 0);
|
$monthlyTotal = (float) ($monthStats->total_amount ?? 0);
|
||||||
$monthlyCount = (int) ($monthStats->total_count ?? 0);
|
$monthlyCount = (int) ($monthStats->total_count ?? 0);
|
||||||
|
|
||||||
// 2. 本月分類統計(圓餅圖)- 保持集合操作即可
|
// 2. 本月分類統計(圓餅圖)- 保持集合操作即可
|
||||||
$categoryStats = Expense::with('category')
|
$categoryStats = Expense::with('category')
|
||||||
->where('user_id', $userId)
|
->where('user_id', $userId)
|
||||||
->whereYear('date', $now->year)
|
->whereYear('date', $latestYear)
|
||||||
->whereMonth('date', $now->month)
|
->whereMonth('date', $latestMonth)
|
||||||
->get()
|
->get()
|
||||||
->groupBy(fn($e) => $e->category?->name ?? '未分類')
|
->groupBy(fn($e) => $e->category?->name ?? '未分類')
|
||||||
->map(fn($group, $name) => [
|
->map(fn($group, $name) => [
|
||||||
@@ -86,12 +107,12 @@ class DashboardController extends Controller
|
|||||||
$monthlyShare = (float) $expense->amount / $totalMonths;
|
$monthlyShare = (float) $expense->amount / $totalMonths;
|
||||||
|
|
||||||
// 跑這 6 個月的迴圈,看有沒有落在這筆費用的歸屬區間內
|
// 跑這 6 個月的迴圈,看有沒有落在這筆費用的歸屬區間內
|
||||||
foreach ($monthlyTrendData as $monthStr => $currentTotal) {
|
foreach ($monthlyTrendData as $monthStr => &$currentTotal) {
|
||||||
$currentMonthObj = Carbon::createFromFormat('Y/m', $monthStr)->startOfMonth();
|
$currentMonthObj = Carbon::createFromFormat('Y/m', $monthStr)->startOfMonth();
|
||||||
|
|
||||||
// 如果圖表上的這個月份,剛好在費用的歸屬起訖之內,就把每月平均金額灌進去!
|
// 如果圖表上的這個月份,剛好在費用的歸屬起訖之內,就把每月平均金額灌進去!
|
||||||
if ($currentMonthObj->betweenIncluded($start, $end)) {
|
if ($currentMonthObj->betweenIncluded($start, $end)) {
|
||||||
$monthlyTrendData[$monthStr] += $monthlyShare;
|
$currentTotal += $monthlyShare;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ class UpdateAssetPriceJob implements ShouldQueue
|
|||||||
$latestPrice = floatval($info['z'] ?? $info['o'] ?? 0);
|
$latestPrice = floatval($info['z'] ?? $info['o'] ?? 0);
|
||||||
$latestPriceDate = isset($info['d']) ? Carbon::parse($info['d'])->format('Y-m-d') : now()->format('Y-m-d');
|
$latestPriceDate = isset($info['d']) ? Carbon::parse($info['d'])->format('Y-m-d') : now()->format('Y-m-d');
|
||||||
$name = $info['n'] ?? $this->defaultName;
|
$name = $info['n'] ?? $this->defaultName;
|
||||||
|
// 忘了備份時用的
|
||||||
|
// $latestPriceDate = isset($info['d']) ? Carbon::parse($info['d'], 'Asia/Taipei')->subDay()->format('Y-m-d') : now()->subDay()->format('Y-m-d');
|
||||||
if (isset($info['y']) && $latestPrice > 0) {
|
if (isset($info['y']) && $latestPrice > 0) {
|
||||||
$changeAmount = floatval($latestPrice - $info['y']);
|
$changeAmount = floatval($latestPrice - $info['y']);
|
||||||
$changeRate = ($changeAmount / $info['y']) * 100;
|
$changeRate = ($changeAmount / $info['y']) * 100;
|
||||||
@@ -88,7 +89,9 @@ class UpdateAssetPriceJob implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($headerInfo) {
|
if ($headerInfo) {
|
||||||
$latestPriceDate = isset($headerInfo['navDate']) ? substr($headerInfo['navDate'], 0, 10) : now()->format('Y-m-d');
|
$latestPriceDate = isset($headerInfo['navDate']) ? Carbon::parse($headerInfo['navDate'], 'Asia/Taipei')->format('Y-m-d') : now()->format('Y-m-d');
|
||||||
|
// 忘了備份時用的
|
||||||
|
// $latestPriceDate = isset($headerInfo['navDate']) ? Carbon::parse($headerInfo['navDate'], 'Asia/Taipei')->subDay()->format('Y-m-d') : now()->subDay()->format('Y-m-d');
|
||||||
$latestPrice = floatval($headerInfo['nav'] ?? 0);
|
$latestPrice = floatval($headerInfo['nav'] ?? 0);
|
||||||
|
|
||||||
if ($latestPriceDate !== now()->format('Y-m-d')) {
|
if ($latestPriceDate !== now()->format('Y-m-d')) {
|
||||||
|
|||||||
35
develop.md
Normal file
35
develop.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Fin-Buddy 專案開發進度與規劃
|
||||||
|
|
||||||
|
## ✅ 已完成階段
|
||||||
|
- [x] **容器架構部署**:Laravel 與 PostgreSQL 成功運行於 `1panel-network`。
|
||||||
|
- [x] **資料庫遷移**:順利整合至 1Panel 內建資料庫容器。
|
||||||
|
- [x] **環境對齊**:修正 Port 對應 (8081:9000) 及路由快取問題,系統穩定運行。
|
||||||
|
- [x] **端到端測試**:核心 API 流程驗證通過。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⏳ 待辦與優化清單
|
||||||
|
|
||||||
|
### 1. 系統清理與維運
|
||||||
|
- [ ] 移除舊容器與無用映像檔 (釋放空間)。
|
||||||
|
- [ ] 將 `web.php` 內危險的同步腳本遷移至 Laravel Artisan Command。
|
||||||
|
- [ ] 檢查 `.env` 安全性設定 (關閉 `APP_DEBUG`)。
|
||||||
|
- [ ] 配置 1Panel 資料庫自動備份任務。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 未來 Roadmap
|
||||||
|
|
||||||
|
| 階段 | 項目 | 目標 |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **I** | **APP 化 (PWA)** | 將前端轉換為 PWA,實現手機桌面安裝與離線訪問。 |
|
||||||
|
| **I** | **記帳 Widget** | 實作快速記帳入口,點擊即錄入,簡化操作動線。 |
|
||||||
|
| **II** | **內容細化與排程** | 擴充 DB Schema,納入「信用卡結帳日」、「發票排程」邏輯。 |
|
||||||
|
| **II** | **銀行與信用卡聯動** | 實作數據同步機制 (Open Banking / 自動抓取)。 |
|
||||||
|
| **III** | **後台與權限管理** | 導入 Filament 與 Spatie,建立 API 測試後台與系統監控。 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 優先級建議
|
||||||
|
1. **建議先做:** 將 `sync-all-history` 正式化為 Command,減少系統安全風險。
|
||||||
|
2. **開發策略:** 建議優先採用 **Filament** 進行後台開發,這能省去 80% 開發後台介面的時間,讓你直接專注於監控系統與 API 測試。
|
||||||
Reference in New Issue
Block a user