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:
122
app/Http/Controllers/Api/AccountController.php
Normal file
122
app/Http/Controllers/Api/AccountController.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Account;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
// 🟢 1. 預先載入 holdings、transactions 還有全新開荒好的 security 字典表!
|
||||
$accounts = $request->user()->accounts()
|
||||
->with(['holdings.transactions', 'holdings.security']) // 👈 確保能直接拿到最新價格
|
||||
->get()
|
||||
->map(function ($account) {
|
||||
|
||||
$data = $account->toArray();
|
||||
|
||||
// 🟢 2. 處理股票與基金的成本與估計現值計算
|
||||
if (in_array($account->type, ['stock', 'fund'])) {
|
||||
|
||||
$totalCost = 0;
|
||||
$totalValue = 0;
|
||||
|
||||
foreach ($account->holdings as $holding) {
|
||||
|
||||
// 🟢 修正 1:直接拿資料庫存好的庫存股數,不用再去 transactions 加減計算
|
||||
$remainingShares = floatval($holding->shares);
|
||||
|
||||
if ($remainingShares > 0) {
|
||||
|
||||
// 🟢 修正 2:拿到最新價格 (如果沒抓到就先給一個暫時的預設值,例如 10,方便你 debug 畫面)
|
||||
$currentPrice = floatval($holding->security?->latest_price ?? 0);
|
||||
|
||||
if ($currentPrice == 0) {
|
||||
// 💡 Debug 觀測:如果還是 0,我們先用 avg_cost 頂替,或者去手動確認 securities 表有沒有真的更新到價格
|
||||
$currentPrice = floatval($holding->avg_cost ?? 0);
|
||||
}
|
||||
|
||||
// 總現值 = 剩餘單位 * 最新價格
|
||||
$totalValue += ($remainingShares * $currentPrice);
|
||||
|
||||
// 總成本:直接拿你畫面上已經有的 avg_cost * shares 算最快最準!
|
||||
$avgCost = floatval($holding->avg_cost ?? 0);
|
||||
$totalCost += ($remainingShares * $avgCost);
|
||||
}
|
||||
}
|
||||
|
||||
// 🟢 捨入並塞入回傳陣列
|
||||
$data['total_cost'] = round($totalCost); // 持倉成本
|
||||
$data['total_value'] = round($totalValue); // 目前市值
|
||||
|
||||
// 💡 關鍵補強:計算總損益與總報酬率並塞回陣列,消滅前端的 NaN%!
|
||||
$totalProfit = $totalValue - $totalCost;
|
||||
$totalRate = $totalCost > 0 ? ($totalProfit / $totalCost) * 100 : 0;
|
||||
|
||||
// 🚨 請確認這裡的 Key 名稱(例如 total_profit 或是 unrealized_profit),
|
||||
// 要跟你在 Vue 前端 account.xxx 綁定的欄位名稱一模一樣喔!
|
||||
$data['total_profit'] = round($totalProfit);
|
||||
$data['total_rate'] = round($totalRate, 2);
|
||||
}
|
||||
|
||||
// 處理信用卡
|
||||
if ($account->type === 'credit_card') {
|
||||
$data['unpaid_amount'] = $account->unpaidAmount();
|
||||
}
|
||||
|
||||
return $data;
|
||||
});
|
||||
|
||||
return response()->json($accounts);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'type' => 'required|in:cash,bank,stock,fund,wallet,credit_card',
|
||||
'currency' => 'nullable|string|max:10',
|
||||
'balance' => 'nullable|numeric',
|
||||
'note' => 'nullable|string',
|
||||
'billing_day' => 'nullable|integer|min:1|max:31',
|
||||
'payment_day' => 'nullable|integer|min:1|max:31',
|
||||
]);
|
||||
|
||||
$account = $request->user()->accounts()->create($validated);
|
||||
return response()->json($account, 201);
|
||||
}
|
||||
|
||||
public function show(Request $request, string $id)
|
||||
{
|
||||
$account = $request->user()->accounts()->findOrFail($id);
|
||||
return response()->json($account);
|
||||
}
|
||||
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
$account = $request->user()->accounts()->findOrFail($id);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'sometimes|string|max:255',
|
||||
'type' => 'sometimes|in:cash,bank,stock,fund,wallet,credit_card',
|
||||
'currency' => 'nullable|string|max:10',
|
||||
'balance' => 'nullable|numeric',
|
||||
'note' => 'nullable|string',
|
||||
'billing_day' => 'nullable|integer|min:1|max:31',
|
||||
'payment_day' => 'nullable|integer|min:1|max:31',
|
||||
]);
|
||||
|
||||
$account->update($validated);
|
||||
return response()->json($account);
|
||||
}
|
||||
|
||||
public function destroy(Request $request, string $id)
|
||||
{
|
||||
$account = $request->user()->accounts()->findOrFail($id);
|
||||
$account->delete();
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user