mirror of
https://github.com/henry4682/finance_app.git
synced 2026-07-16 00:10:00 +00:00
feat: 前端分離+功能api化
1. 新增資產管理CRUD、googleOAuth登入 2. 更改原記帳controller
This commit is contained in:
114
app/Http/Controllers/Api/DashboardController.php
Normal file
114
app/Http/Controllers/Api/DashboardController.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\Expense;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$userId = Auth::id();
|
||||
$now = Carbon::now();
|
||||
|
||||
// 1. 本月基礎統計 (用一個查詢同時撈出「總金額」與「總筆數」)
|
||||
$monthStats = Expense::where('user_id', $userId)
|
||||
->whereYear('date', $now->year)
|
||||
->whereMonth('date', $now->month)
|
||||
->selectRaw('SUM(amount) as total_amount, COUNT(id) as total_count')
|
||||
->first();
|
||||
|
||||
$monthlyTotal = (float) ($monthStats->total_amount ?? 0);
|
||||
$monthlyCount = (int) ($monthStats->total_count ?? 0);
|
||||
|
||||
// 2. 本月分類統計(圓餅圖)- 保持集合操作即可
|
||||
$categoryStats = Expense::with('category')
|
||||
->where('user_id', $userId)
|
||||
->whereYear('date', $now->year)
|
||||
->whereMonth('date', $now->month)
|
||||
->get()
|
||||
->groupBy(fn($e) => $e->category?->name ?? '未分類')
|
||||
->map(fn($group, $name) => [
|
||||
'name' => $name,
|
||||
'total' => (float) $group->sum('amount'),
|
||||
'color' => $group->first()->category?->color ?? '#6B7280',
|
||||
])
|
||||
->values();
|
||||
|
||||
// 3. 近 6 個月趨勢優化:一次性撈出半年內的所有資料,避免 6 次 SQL 查詢
|
||||
$sixMonthsAgo = $now->copy()->subMonths(5)->startOfMonth();
|
||||
$endOfCurrentMonth = $now->copy()->endOfMonth();
|
||||
|
||||
// 建立近 6 個月的初始月份清單(例如 ['2026/01' => 0.0, '2026/02' => 0.0 ... ])
|
||||
$monthlyTrendData = collect(range(5, 0))->mapWithKeys(function ($i) use ($now) {
|
||||
$monthStr = $now->copy()->subMonths($i)->format('Y/m');
|
||||
return [$monthStr => 0.0];
|
||||
})->toArray();
|
||||
|
||||
// ➔ (A) 撈取一般消費 (未開啟分攤)
|
||||
$isPostgres = DB::connection()->getDriverName() === 'pgsql';
|
||||
$dateGroupRaw = $isPostgres ? "to_char(date, 'YYYY/MM')" : "DATE_FORMAT(date, '%Y/%m')";
|
||||
|
||||
$normalExpenses = Expense::where('user_id', $userId)
|
||||
->where('is_amortized', false)
|
||||
->where('date', '>=', $sixMonthsAgo)
|
||||
->selectRaw("{$dateGroupRaw} as month, SUM(amount) as total")
|
||||
->groupBy('month')
|
||||
->get();
|
||||
|
||||
foreach ($normalExpenses as $expense) {
|
||||
if (array_key_exists($expense->month, $monthlyTrendData)) {
|
||||
$monthlyTrendData[$expense->month] += (float) $expense->total;
|
||||
}
|
||||
}
|
||||
|
||||
// ➔ (B) 智慧分攤消費 (處理跨月、跨年、半年繳大魔王 🎯)
|
||||
// 撈出所有歸屬期間有交集到這 6 個月範圍內的分攤費用
|
||||
$amortizedExpenses = Expense::where('user_id', $userId)
|
||||
->where('is_amortized', true)
|
||||
->where(function ($query) use ($sixMonthsAgo, $endOfCurrentMonth) {
|
||||
$query->where('period_start', '<=', $endOfCurrentMonth)
|
||||
->where('period_end', '>=', $sixMonthsAgo);
|
||||
})
|
||||
->get();
|
||||
|
||||
foreach ($amortizedExpenses as $expense) {
|
||||
$start = Carbon::parse($expense->period_start)->startOfMonth();
|
||||
$end = Carbon::parse($expense->period_end)->endOfMonth();
|
||||
|
||||
// 計算這筆費用的總跨月份數 (至少為 1 個月)
|
||||
$totalMonths = max(1, $start->diffInMonths($end) + 1);
|
||||
// 算出每月平均攤提金額
|
||||
$monthlyShare = (float) $expense->amount / $totalMonths;
|
||||
|
||||
// 跑這 6 個月的迴圈,看有沒有落在這筆費用的歸屬區間內
|
||||
foreach ($monthlyTrendData as $monthStr => $currentTotal) {
|
||||
$currentMonthObj = Carbon::createFromFormat('Y/m', $monthStr)->startOfMonth();
|
||||
|
||||
// 如果圖表上的這個月份,剛好在費用的歸屬起訖之內,就把每月平均金額灌進去!
|
||||
if ($currentMonthObj->betweenIncluded($start, $end)) {
|
||||
$monthlyTrendData[$monthStr] += $monthlyShare;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 轉回前端圖表要的格式
|
||||
$monthlyTrend = collect($monthlyTrendData)->map(function ($total, $monthStr) {
|
||||
return [
|
||||
'month' => $monthStr,
|
||||
'total' => round($total, 2), // 四捨五入到小數點兩位
|
||||
];
|
||||
})->values();
|
||||
|
||||
return response()->json([
|
||||
'monthlyTotal' => $monthlyTotal,
|
||||
'monthlyCount' => $monthlyCount,
|
||||
'categoryStats' => $categoryStats,
|
||||
'monthlyTrend' => $monthlyTrend,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user