347 lines
10 KiB
PHP
347 lines
10 KiB
PHP
<?php
|
||
|
||
namespace Modules\Account\Services;
|
||
|
||
use Illuminate\Http\Request;
|
||
use Modules\Account\Models\Bill;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
class BillService
|
||
{
|
||
/**
|
||
* 获取账单列表
|
||
*/
|
||
public function getList(Request $request)
|
||
{
|
||
$userId = auth('api')->user()['uid'];
|
||
$page = $request->input('page', 1);
|
||
$limit = $request->input('limit', 20);
|
||
$type = $request->input('type');
|
||
$year = $request->input('year');
|
||
$month = $request->input('month');
|
||
$startDate = $request->input('start_date');
|
||
$endDate = $request->input('end_date');
|
||
$dataType = $request->input('data_type', 'family'); // 默认为家庭数据
|
||
|
||
// 获取用户所在的家庭ID
|
||
$userFamilyId = $this->getUserFamilyId($userId);
|
||
|
||
$query = Bill::with(['user:uid,nickname,username', 'family:id,name']);
|
||
|
||
// 根据data_type参数判断数据类型
|
||
if ($dataType === 'personal') {
|
||
// 个人数据:只显示当前用户的账单
|
||
$query->where('user_id', $userId);
|
||
} elseif ($dataType === 'family' && $userFamilyId) {
|
||
// 家庭数据:显示用户所在家庭的账单
|
||
$query->where('family_id', $userFamilyId);
|
||
} else {
|
||
// 默认显示个人数据
|
||
$query->where('user_id', $userId);
|
||
}
|
||
|
||
// 年月筛选
|
||
if ($year && $month) {
|
||
$startDate = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT) . '-01';
|
||
$endDate = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT) . '-31';
|
||
}
|
||
|
||
// 日期范围筛选
|
||
if ($startDate) {
|
||
$query->where('bill_date', '>=', $startDate);
|
||
}
|
||
if ($endDate) {
|
||
$query->where('bill_date', '<=', $endDate);
|
||
}
|
||
|
||
// 类型筛选
|
||
if ($type && in_array($type, ['income', 'expense'])) {
|
||
$query->where('type', $type);
|
||
}
|
||
|
||
$bills = $query->orderBy('bill_date', 'desc')
|
||
->orderBy('created_at', 'desc')
|
||
->paginate($limit, ['*'], 'page', $page);
|
||
|
||
// 计算本月收支
|
||
$monthExpense = Bill::query();
|
||
$monthIncome = Bill::query();
|
||
|
||
// 同样的数据类型查询逻辑
|
||
if ($dataType === 'personal') {
|
||
$monthExpense->where('user_id', $userId);
|
||
$monthIncome->where('user_id', $userId);
|
||
} elseif ($dataType === 'family' && $userFamilyId) {
|
||
$monthExpense->where('family_id', $userFamilyId);
|
||
$monthIncome->where('family_id', $userFamilyId);
|
||
} else {
|
||
$monthExpense->where('user_id', $userId);
|
||
$monthIncome->where('user_id', $userId);
|
||
}
|
||
|
||
if ($startDate) {
|
||
$monthExpense->where('bill_date', '>=', $startDate);
|
||
$monthIncome->where('bill_date', '>=', $startDate);
|
||
}
|
||
if ($endDate) {
|
||
$monthExpense->where('bill_date', '<=', $endDate);
|
||
$monthIncome->where('bill_date', '<=', $endDate);
|
||
}
|
||
|
||
$monthExpense->where('type', 'expense');
|
||
$monthIncome->where('type', 'income');
|
||
|
||
// 转换数据格式以匹配前端
|
||
$list = collect($bills->items())->map(function($bill) {
|
||
return [
|
||
'id' => $bill->id,
|
||
'type' => $bill->type,
|
||
'amount' => (float)$bill->amount,
|
||
'category' => $bill->category,
|
||
'category_id' => $this->getCategoryId($bill->category, $bill->type),
|
||
'remark' => $bill->remark,
|
||
'date' => $bill->bill_date,
|
||
'bill_date' => $bill->bill_date,
|
||
'created_at' => $bill->created_at->format('Y-m-d H:i:s'),
|
||
'user' => $bill->user,
|
||
'family' => $bill->family
|
||
];
|
||
})->toArray();
|
||
|
||
return [
|
||
'list' => $list,
|
||
'month_expense' => (float)$monthExpense->sum('amount'),
|
||
'month_income' => (float)$monthIncome->sum('amount'),
|
||
'pagination' => [
|
||
'current_page' => $bills->currentPage(),
|
||
'total' => $bills->total(),
|
||
'per_page' => $bills->perPage(),
|
||
'last_page' => $bills->lastPage()
|
||
]
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 根据分类名称获取分类ID(前端使用)
|
||
*/
|
||
private function getCategoryId($categoryName, $type)
|
||
{
|
||
// 支出分类映射
|
||
$expenseMap = [
|
||
'餐饮' => 1,
|
||
'交通' => 2,
|
||
'购物' => 3,
|
||
'娱乐' => 4,
|
||
'医疗' => 5,
|
||
'教育' => 6,
|
||
'居住' => 7,
|
||
'其他' => 8
|
||
];
|
||
|
||
// 收入分类映射
|
||
$incomeMap = [
|
||
'工资' => 101,
|
||
'奖金' => 102,
|
||
'投资' => 103,
|
||
'兼职' => 104,
|
||
'其他' => 105
|
||
];
|
||
|
||
$map = $type === 'income' ? $incomeMap : $expenseMap;
|
||
return $map[$categoryName] ?? ($type === 'income' ? 105 : 8);
|
||
}
|
||
|
||
/**
|
||
* 添加账单
|
||
*/
|
||
public function add(Request $request)
|
||
{
|
||
$userId = auth('api')->user()['uid'];
|
||
|
||
$data = $request->validate([
|
||
'type' => 'required|in:income,expense',
|
||
'amount' => 'required|numeric|min:0.01',
|
||
'category_id' => 'required|integer',
|
||
'remark' => 'nullable|string|max:255',
|
||
'date' => 'required|date',
|
||
'family_id' => 'nullable|integer|exists:account_families,id'
|
||
]);
|
||
|
||
// 将category_id转换为category字符串
|
||
$categoryMap = $this->getCategoryMap($data['type']);
|
||
if (!isset($categoryMap[$data['category_id']])) {
|
||
throw new \Exception('分类不存在');
|
||
}
|
||
|
||
$data['category'] = $categoryMap[$data['category_id']];
|
||
$data['bill_date'] = $data['date'];
|
||
|
||
// 如果前端没有指定family_id,自动获取用户所在的家庭
|
||
if (empty($data['family_id'])) {
|
||
$userFamilyId = $this->getUserFamilyId($userId);
|
||
if ($userFamilyId) {
|
||
$data['family_id'] = $userFamilyId;
|
||
}
|
||
} else {
|
||
// 检查家庭权限
|
||
$this->checkFamilyAccess($userId, $data['family_id']);
|
||
}
|
||
|
||
$data['user_id'] = $userId;
|
||
|
||
// 移除前端字段
|
||
unset($data['category_id'], $data['date']);
|
||
|
||
return Bill::create($data);
|
||
}
|
||
|
||
/**
|
||
* 获取分类映射
|
||
*/
|
||
private function getCategoryMap($type)
|
||
{
|
||
if ($type === 'income') {
|
||
return [
|
||
101 => '工资',
|
||
102 => '奖金',
|
||
103 => '投资',
|
||
104 => '兼职',
|
||
105 => '其他'
|
||
];
|
||
} else {
|
||
return [
|
||
1 => '餐饮',
|
||
2 => '交通',
|
||
3 => '购物',
|
||
4 => '娱乐',
|
||
5 => '医疗',
|
||
6 => '教育',
|
||
7 => '居住',
|
||
8 => '其他'
|
||
];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 编辑账单
|
||
*/
|
||
public function edit(Request $request)
|
||
{
|
||
$userId = auth('api')->user()['uid'];
|
||
$id = $request->input('id');
|
||
|
||
$bill = Bill::findOrFail($id);
|
||
|
||
// 验证权限
|
||
if ($bill->user_id != $userId) {
|
||
throw new \Exception('无权操作此账单');
|
||
}
|
||
|
||
$data = $request->validate([
|
||
'type' => 'required|in:income,expense',
|
||
'amount' => 'required|numeric|min:0.01',
|
||
'category_id' => 'required|integer',
|
||
'remark' => 'nullable|string|max:255',
|
||
'date' => 'required|date',
|
||
'family_id' => 'nullable|integer|exists:account_families,id'
|
||
]);
|
||
|
||
// 将category_id转换为category字符串
|
||
$categoryMap = $this->getCategoryMap($data['type']);
|
||
if (!isset($categoryMap[$data['category_id']])) {
|
||
throw new \Exception('分类不存在');
|
||
}
|
||
|
||
$data['category'] = $categoryMap[$data['category_id']];
|
||
$data['bill_date'] = $data['date'];
|
||
|
||
// 检查家庭权限
|
||
if (!empty($data['family_id'])) {
|
||
$this->checkFamilyAccess($userId, $data['family_id']);
|
||
}
|
||
|
||
// 移除前端字段
|
||
unset($data['category_id'], $data['date']);
|
||
|
||
$bill->update($data);
|
||
|
||
return $bill;
|
||
}
|
||
|
||
/**
|
||
* 删除账单
|
||
*/
|
||
public function delete(Request $request)
|
||
{
|
||
$userId = auth('api')->user()['uid'];
|
||
$id = $request->input('id');
|
||
|
||
$bill = Bill::findOrFail($id);
|
||
|
||
// 验证权限
|
||
if ($bill->user_id != $userId) {
|
||
throw new \Exception('无权删除此账单');
|
||
}
|
||
|
||
return $bill->delete();
|
||
}
|
||
|
||
/**
|
||
* 获取账单详情
|
||
*/
|
||
public function detail(Request $request)
|
||
{
|
||
$userId = auth('api')->user()['uid'];
|
||
$id = $request->input('id');
|
||
|
||
$bill = Bill::with(['user:uid,nickname,username', 'family:id,name,owner_id'])
|
||
->findOrFail($id);
|
||
|
||
// 验证权限:只有账单创建者才能查看和编辑
|
||
if ($bill->user_id != $userId) {
|
||
throw new \Exception('无权查看此账单');
|
||
}
|
||
|
||
// 转换数据格式以匹配前端
|
||
return [
|
||
'id' => $bill->id,
|
||
'type' => $bill->type,
|
||
'amount' => (float)$bill->amount,
|
||
'category' => $bill->category,
|
||
'category_id' => $this->getCategoryId($bill->category, $bill->type),
|
||
'remark' => $bill->remark,
|
||
'date' => $bill->bill_date,
|
||
'bill_date' => $bill->bill_date,
|
||
'created_at' => $bill->created_at->format('Y-m-d H:i:s'),
|
||
'user' => $bill->user,
|
||
'family' => $bill->family
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 检查家庭访问权限
|
||
*/
|
||
private function checkFamilyAccess($userId, $familyId)
|
||
{
|
||
$isMember = DB::table('account_family_members')
|
||
->where('family_id', $familyId)
|
||
->where('user_id', $userId)
|
||
->exists();
|
||
|
||
if (!$isMember) {
|
||
throw new \Exception('您不是该家庭成员');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取用户所在的家庭ID
|
||
*/
|
||
private function getUserFamilyId($userId)
|
||
{
|
||
$familyMember = DB::table('account_family_members')
|
||
->where('user_id', $userId)
|
||
->first();
|
||
return $familyMember ? $familyMember->family_id : null;
|
||
}
|
||
}
|