更新后端接口
This commit is contained in:
101
modules/Account/app/Controllers/Admin/Bill.php
Normal file
101
modules/Account/app/Controllers/Admin/Bill.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Modules\Account\Controllers\Admin;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use Modules\Account\Services\AdminBillService;
|
||||
|
||||
class Bill extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 账单列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @param BillService $service
|
||||
* @return void
|
||||
*/
|
||||
public function index(Request $request, AdminBillService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加账单
|
||||
*
|
||||
* @param Request $request
|
||||
* @param BillService $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, AdminBillService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 编辑账单
|
||||
*
|
||||
* @param Request $request
|
||||
* @param BillService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, AdminBillService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除账单
|
||||
*
|
||||
* @param Request $request
|
||||
* @param BillService $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request, AdminBillService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 账单详情
|
||||
*
|
||||
* @param Request $request
|
||||
* @param BillService $service
|
||||
* @return void
|
||||
*/
|
||||
public function detail(Request $request, AdminBillService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->detail($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
152
modules/Account/app/Controllers/Admin/Family.php
Normal file
152
modules/Account/app/Controllers/Admin/Family.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Modules\Account\Controllers\Admin;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use Modules\Account\Services\AdminFamilyService;
|
||||
|
||||
class Family extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 家庭列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminFamilyService $service
|
||||
* @return void
|
||||
*/
|
||||
public function index(Request $request, AdminFamilyService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->getDataList($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加家庭
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminFamilyService $service
|
||||
* @return void
|
||||
*/
|
||||
public function add(Request $request, AdminFamilyService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->create($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 编辑家庭
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminFamilyService $service
|
||||
* @return void
|
||||
*/
|
||||
public function edit(Request $request, AdminFamilyService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->update($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除家庭
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminFamilyService $service
|
||||
* @return void
|
||||
*/
|
||||
public function delete(Request $request, AdminFamilyService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->delete($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 家庭详情
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminFamilyService $service
|
||||
* @return void
|
||||
*/
|
||||
public function detail(Request $request, AdminFamilyService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->detail($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 家庭成员列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminFamilyService $service
|
||||
* @return void
|
||||
*/
|
||||
public function members(Request $request, AdminFamilyService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->getMembers($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加家庭成员
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminFamilyService $service
|
||||
* @return void
|
||||
*/
|
||||
public function addMember(Request $request, AdminFamilyService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->addMember($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 移除家庭成员
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminFamilyService $service
|
||||
* @return void
|
||||
*/
|
||||
public function removeMember(Request $request, AdminFamilyService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->removeMember($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
101
modules/Account/app/Controllers/Admin/Statistics.php
Normal file
101
modules/Account/app/Controllers/Admin/Statistics.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Modules\Account\Controllers\Admin;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use Modules\Account\Services\AdminStatisticsService;
|
||||
|
||||
class Statistics extends BaseController {
|
||||
|
||||
/**
|
||||
* @title 概览统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminStatisticsService $service
|
||||
* @return void
|
||||
*/
|
||||
public function overview(Request $request, AdminStatisticsService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->getOverview($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 趋势统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminStatisticsService $service
|
||||
* @return void
|
||||
*/
|
||||
public function trend(Request $request, AdminStatisticsService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->getTrend($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 分类统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminStatisticsService $service
|
||||
* @return void
|
||||
*/
|
||||
public function category(Request $request, AdminStatisticsService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->getCategoryStatistics($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 用户统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminStatisticsService $service
|
||||
* @return void
|
||||
*/
|
||||
public function user(Request $request, AdminStatisticsService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->getUserStatistics($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 家庭统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @param AdminStatisticsService $service
|
||||
* @return void
|
||||
*/
|
||||
public function family(Request $request, AdminStatisticsService $service) {
|
||||
try {
|
||||
$this->data['data'] = $service->getFamilyStatistics($request);
|
||||
} catch (\Exception $e) {
|
||||
$this->data['code'] = 0;
|
||||
$this->data['message'] = $e->getMessage();
|
||||
}
|
||||
return response()->json($this->data);
|
||||
}
|
||||
}
|
||||
311
modules/Account/app/Services/AdminBillService.php
Normal file
311
modules/Account/app/Services/AdminBillService.php
Normal file
@@ -0,0 +1,311 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Modules\Account\Services;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Account\Models\Bill;
|
||||
|
||||
class AdminBillService {
|
||||
|
||||
/**
|
||||
* @title 获取账单列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request) {
|
||||
$map = [];
|
||||
|
||||
// 用户筛选
|
||||
if ($request->filled('user_id')) {
|
||||
$map[] = ['user_id', '=', $request->input('user_id')];
|
||||
}
|
||||
|
||||
// 家庭筛选
|
||||
if ($request->filled('family_id')) {
|
||||
$map[] = ['family_id', '=', $request->input('family_id')];
|
||||
}
|
||||
|
||||
// 类型筛选
|
||||
if ($request->filled('type') && in_array($request->input('type'), ['income', 'expense'])) {
|
||||
$map[] = ['type', '=', $request->input('type')];
|
||||
}
|
||||
|
||||
// 分类筛选
|
||||
if ($request->filled('category')) {
|
||||
$map[] = ['category', 'like', '%' . $request->input('category') . '%'];
|
||||
}
|
||||
|
||||
// 支付方式筛选
|
||||
if ($request->filled('payment_method')) {
|
||||
$map[] = ['payment_method', '=', $request->input('payment_method')];
|
||||
}
|
||||
|
||||
// 备注搜索
|
||||
if ($request->filled('remark')) {
|
||||
$map[] = ['remark', 'like', '%' . $request->input('remark') . '%'];
|
||||
}
|
||||
|
||||
// 日期范围筛选
|
||||
if ($request->filled('start_date')) {
|
||||
$map[] = ['bill_date', '>=', $request->input('start_date')];
|
||||
}
|
||||
if ($request->filled('end_date')) {
|
||||
$map[] = ['bill_date', '<=', $request->input('end_date')];
|
||||
}
|
||||
|
||||
// 年月筛选
|
||||
if ($request->filled('year') && $request->filled('month')) {
|
||||
$startDate = $request->input('year') . '-' . str_pad($request->input('month'), 2, '0', STR_PAD_LEFT) . '-01';
|
||||
$endDate = $request->input('year') . '-' . str_pad($request->input('month'), 2, '0', STR_PAD_LEFT) . '-31';
|
||||
// 清除之前的日期条件
|
||||
$map = array_filter($map, function($item) {
|
||||
return !isset($item[0]) || !in_array($item[0], ['bill_date']);
|
||||
});
|
||||
$map[] = ['bill_date', '>=', $startDate];
|
||||
$map[] = ['bill_date', '<=', $endDate];
|
||||
}
|
||||
|
||||
$query = Bill::with(['user:uid,nickname,username', 'family:id,name']);
|
||||
|
||||
$query->where($map);
|
||||
|
||||
// 排序
|
||||
$query->orderBy($request->input('order', 'bill_date'), $request->input('sort', 'desc'));
|
||||
|
||||
// 分页
|
||||
if ($request->filled('page')) {
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))
|
||||
->limit($request->input('limit', 10))
|
||||
->get(),
|
||||
];
|
||||
} else {
|
||||
$data = $query->get();
|
||||
}
|
||||
|
||||
// 计算统计数据
|
||||
if ($request->filled('page')) {
|
||||
$statsQuery = Bill::query()->where($map);
|
||||
$totalExpense = (clone $statsQuery)->where('type', 'expense')->sum('amount');
|
||||
$totalIncome = (clone $statsQuery)->where('type', 'income')->sum('amount');
|
||||
$data['statistics'] = [
|
||||
'total_expense' => (float)$totalExpense,
|
||||
'total_income' => (float)$totalIncome,
|
||||
'total_balance' => (float)($totalIncome - $totalExpense),
|
||||
'total_count' => $data['total']
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加账单
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function create($request) {
|
||||
$request->validate([
|
||||
'user_id' => 'required|integer',
|
||||
'type' => 'required|in:income,expense',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'category_id' => 'required|integer',
|
||||
'payment_method' => 'nullable|string|in:微信,支付宝,银行卡,现金,其他',
|
||||
'remark' => 'nullable|string|max:255',
|
||||
'date' => 'required|date',
|
||||
'family_id' => 'nullable|integer|exists:account_families,id'
|
||||
], [
|
||||
'user_id.required' => '请选择用户',
|
||||
'type.required' => '请选择账单类型',
|
||||
'amount.required' => '请输入金额',
|
||||
'category_id.required' => '请选择分类',
|
||||
'date.required' => '请选择日期'
|
||||
]);
|
||||
|
||||
$data = $request->all();
|
||||
|
||||
// 将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'];
|
||||
|
||||
// 移除前端字段
|
||||
unset($data['category_id'], $data['date']);
|
||||
|
||||
return Bill::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 更新账单
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function update($request) {
|
||||
$request->validate([
|
||||
'id' => 'required|integer',
|
||||
'user_id' => 'required|integer',
|
||||
'type' => 'required|in:income,expense',
|
||||
'amount' => 'required|numeric|min:0.01',
|
||||
'category_id' => 'required|integer',
|
||||
'payment_method' => 'nullable|string|in:微信,支付宝,银行卡,现金,其他',
|
||||
'remark' => 'nullable|string|max:255',
|
||||
'date' => 'required|date',
|
||||
'family_id' => 'nullable|integer|exists:account_families,id'
|
||||
], [
|
||||
'id.required' => '请提供账单ID',
|
||||
'user_id.required' => '请选择用户',
|
||||
'type.required' => '请选择账单类型',
|
||||
'amount.required' => '请输入金额',
|
||||
'category_id.required' => '请选择分类',
|
||||
'date.required' => '请选择日期'
|
||||
]);
|
||||
|
||||
$bill = Bill::findOrFail($request->input('id'));
|
||||
$data = $request->all();
|
||||
|
||||
// 将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'];
|
||||
|
||||
// 移除前端字段
|
||||
unset($data['category_id'], $data['date'], $data['id']);
|
||||
|
||||
$bill->update($data);
|
||||
|
||||
return $bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除账单
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function delete($request) {
|
||||
if ($request->filled('id')) {
|
||||
try {
|
||||
$bill = Bill::findOrFail($request->input('id'));
|
||||
$bill->delete();
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("账单不存在!", 1);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->filled('ids')) {
|
||||
try {
|
||||
$bill = Bill::whereIn('id', $request->input('ids'));
|
||||
$bill->delete();
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 账单详情
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function detail($request) {
|
||||
$id = $request->input('id');
|
||||
|
||||
$bill = Bill::with(['user:uid,nickname,username', 'family:id,name,owner_id'])
|
||||
->findOrFail($id);
|
||||
|
||||
return $bill;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取分类映射
|
||||
*
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
private function getCategoryMap($type) {
|
||||
if ($type === 'income') {
|
||||
return [
|
||||
101 => '工资',
|
||||
102 => '奖金',
|
||||
103 => '投资',
|
||||
104 => '兼职',
|
||||
105 => '其他'
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
1 => '餐饮',
|
||||
2 => '交通',
|
||||
3 => '购物',
|
||||
4 => '娱乐',
|
||||
5 => '医疗',
|
||||
6 => '教育',
|
||||
7 => '居住',
|
||||
8 => '其他'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取分类列表
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCategoryList() {
|
||||
return [
|
||||
'expense' => [
|
||||
['id' => 1, 'name' => '餐饮'],
|
||||
['id' => 2, 'name' => '交通'],
|
||||
['id' => 3, 'name' => '购物'],
|
||||
['id' => 4, 'name' => '娱乐'],
|
||||
['id' => 5, 'name' => '医疗'],
|
||||
['id' => 6, 'name' => '教育'],
|
||||
['id' => 7, 'name' => '居住'],
|
||||
['id' => 8, 'name' => '其他']
|
||||
],
|
||||
'income' => [
|
||||
['id' => 101, 'name' => '工资'],
|
||||
['id' => 102, 'name' => '奖金'],
|
||||
['id' => 103, 'name' => '投资'],
|
||||
['id' => 104, 'name' => '兼职'],
|
||||
['id' => 105, 'name' => '其他']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取支付方式列表
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPaymentMethods() {
|
||||
return [
|
||||
['value' => '微信', 'label' => '微信'],
|
||||
['value' => '支付宝', 'label' => '支付宝'],
|
||||
['value' => '银行卡', 'label' => '银行卡'],
|
||||
['value' => '现金', 'label' => '现金'],
|
||||
['value' => '其他', 'label' => '其他']
|
||||
];
|
||||
}
|
||||
}
|
||||
422
modules/Account/app/Services/AdminFamilyService.php
Normal file
422
modules/Account/app/Services/AdminFamilyService.php
Normal file
@@ -0,0 +1,422 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Modules\Account\Services;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Account\Models\Family;
|
||||
use Modules\Account\Models\FamilyMember;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class AdminFamilyService {
|
||||
|
||||
/**
|
||||
* @title 获取家庭列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function getDataList($request) {
|
||||
$map = [];
|
||||
|
||||
// 名称搜索
|
||||
if ($request->filled('name')) {
|
||||
$map[] = ['name', 'like', '%' . $request->input('name') . '%'];
|
||||
}
|
||||
|
||||
// 家主筛选
|
||||
if ($request->filled('owner_id')) {
|
||||
$map[] = ['owner_id', '=', $request->input('owner_id')];
|
||||
}
|
||||
|
||||
// 邀请码筛选
|
||||
if ($request->filled('invite_code')) {
|
||||
$map[] = ['invite_code', '=', $request->input('invite_code')];
|
||||
}
|
||||
|
||||
// 日期范围筛选
|
||||
if ($request->filled('start_date')) {
|
||||
$map[] = ['created_at', '>=', $request->input('start_date')];
|
||||
}
|
||||
if ($request->filled('end_date')) {
|
||||
$map[] = ['created_at', '<=', $request->input('end_date')];
|
||||
}
|
||||
|
||||
$query = Family::with(['owner:uid,nickname,username', 'members:uid,nickname,username']);
|
||||
|
||||
$query->where($map);
|
||||
|
||||
// 排序
|
||||
$query->orderBy($request->input('order', 'created_at'), $request->input('sort', 'desc'));
|
||||
|
||||
// 分页
|
||||
if ($request->filled('page')) {
|
||||
$data = [
|
||||
'total' => $query->count(),
|
||||
'page' => $request->input('page', 1),
|
||||
'data' => $query->offset($request->input('offset', 0))
|
||||
->limit($request->input('limit', 10))
|
||||
->get(),
|
||||
];
|
||||
} else {
|
||||
$data = $query->get();
|
||||
}
|
||||
|
||||
// 添加成员数量统计
|
||||
if ($request->filled('page')) {
|
||||
foreach ($data['data'] as $family) {
|
||||
$family->member_count = $family->members->count();
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 创建家庭
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function create($request) {
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:50',
|
||||
'owner_id' => 'required|integer'
|
||||
], [
|
||||
'name.required' => '请输入家庭名称',
|
||||
'owner_id.required' => '请选择家主'
|
||||
]);
|
||||
|
||||
$data = $request->all();
|
||||
|
||||
// 生成10位邀请码
|
||||
do {
|
||||
$inviteCode = strtoupper(substr(str_shuffle('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 10));
|
||||
} while (Family::where('invite_code', $inviteCode)->exists());
|
||||
|
||||
$data['invite_code'] = $inviteCode;
|
||||
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
$family = Family::create($data);
|
||||
|
||||
// 家主自动加入家庭
|
||||
FamilyMember::create([
|
||||
'family_id' => $family->id,
|
||||
'user_id' => $data['owner_id']
|
||||
]);
|
||||
|
||||
DB::commit();
|
||||
|
||||
return $family;
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 更新家庭
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function update($request) {
|
||||
$request->validate([
|
||||
'id' => 'required|integer',
|
||||
'name' => 'required|string|max:50',
|
||||
'owner_id' => 'required|integer'
|
||||
], [
|
||||
'id.required' => '请提供家庭ID',
|
||||
'name.required' => '请输入家庭名称',
|
||||
'owner_id.required' => '请选择家主'
|
||||
]);
|
||||
|
||||
$family = Family::findOrFail($request->input('id'));
|
||||
$data = $request->all();
|
||||
|
||||
unset($data['id']);
|
||||
|
||||
$family->update($data);
|
||||
|
||||
return $family;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 删除家庭
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function delete($request) {
|
||||
if ($request->filled('id')) {
|
||||
try {
|
||||
$family = Family::findOrFail($request->input('id'));
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
// 删除家庭成员
|
||||
FamilyMember::where('family_id', $family->id)->delete();
|
||||
// 删除家庭
|
||||
$family->delete();
|
||||
DB::commit();
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollBack();
|
||||
throw $th;
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("家庭不存在!", 1);
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->filled('ids')) {
|
||||
try {
|
||||
$families = Family::whereIn('id', $request->input('ids'))->get();
|
||||
DB::beginTransaction();
|
||||
try {
|
||||
foreach ($families as $family) {
|
||||
// 删除家庭成员
|
||||
FamilyMember::where('family_id', $family->id)->delete();
|
||||
}
|
||||
// 删除家庭
|
||||
$families->each->delete();
|
||||
DB::commit();
|
||||
} catch (\Throwable $th) {
|
||||
DB::rollBack();
|
||||
throw $th;
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $family;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 家庭详情
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function detail($request) {
|
||||
$id = $request->input('id');
|
||||
|
||||
$family = Family::with(['owner:uid,nickname,username', 'members:uid,nickname,username,email'])
|
||||
->findOrFail($id);
|
||||
|
||||
// 添加成员数量
|
||||
$family->member_count = $family->members->count();
|
||||
|
||||
// 添加统计信息
|
||||
$billCount = DB::table('account_bills')->where('family_id', $family->id)->count();
|
||||
$totalExpense = DB::table('account_bills')
|
||||
->where('family_id', $family->id)
|
||||
->where('type', 'expense')
|
||||
->sum('amount');
|
||||
$totalIncome = DB::table('account_bills')
|
||||
->where('family_id', $family->id)
|
||||
->where('type', 'income')
|
||||
->sum('amount');
|
||||
|
||||
$family->statistics = [
|
||||
'bill_count' => $billCount,
|
||||
'total_expense' => (float)$totalExpense,
|
||||
'total_income' => (float)$totalIncome,
|
||||
'total_balance' => (float)($totalIncome - $totalExpense)
|
||||
];
|
||||
|
||||
return $family;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取家庭成员列表
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function getMembers($request) {
|
||||
$familyId = $request->input('family_id');
|
||||
|
||||
if (!$familyId) {
|
||||
throw new \Exception('请提供家庭ID');
|
||||
}
|
||||
|
||||
$family = Family::findOrFail($familyId);
|
||||
|
||||
$members = FamilyMember::with('user:uid,nickname,username,email')
|
||||
->where('family_id', $familyId)
|
||||
->get();
|
||||
|
||||
return [
|
||||
'family_id' => $familyId,
|
||||
'family_name' => $family->name,
|
||||
'owner_id' => $family->owner_id,
|
||||
'members' => $members->map(function($member) use ($family) {
|
||||
return [
|
||||
'id' => $member->id,
|
||||
'user_id' => $member->user_id,
|
||||
'name' => $member->user->nickname ?? $member->user->username,
|
||||
'username' => $member->user->username,
|
||||
'email' => $member->user->email,
|
||||
'is_owner' => $family->owner_id == $member->user_id,
|
||||
'joined_at' => $member->created_at
|
||||
];
|
||||
})->toArray(),
|
||||
'total' => $members->count()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 添加家庭成员
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function addMember($request) {
|
||||
$request->validate([
|
||||
'family_id' => 'required|integer',
|
||||
'user_id' => 'required|integer'
|
||||
], [
|
||||
'family_id.required' => '请提供家庭ID',
|
||||
'user_id.required' => '请选择用户'
|
||||
]);
|
||||
|
||||
$familyId = $request->input('family_id');
|
||||
$userId = $request->input('user_id');
|
||||
|
||||
// 检查家庭是否存在
|
||||
$family = Family::findOrFail($familyId);
|
||||
|
||||
// 检查用户是否已在家庭中
|
||||
$existingMember = FamilyMember::where('family_id', $familyId)
|
||||
->where('user_id', $userId)
|
||||
->first();
|
||||
|
||||
if ($existingMember) {
|
||||
throw new \Exception('该用户已在家庭中');
|
||||
}
|
||||
|
||||
// 检查用户是否已在其他家庭中
|
||||
$userInOtherFamily = FamilyMember::where('user_id', $userId)->first();
|
||||
if ($userInOtherFamily) {
|
||||
throw new \Exception('该用户已在其他家庭中');
|
||||
}
|
||||
|
||||
// 添加家庭成员
|
||||
FamilyMember::create([
|
||||
'family_id' => $familyId,
|
||||
'user_id' => $userId
|
||||
]);
|
||||
|
||||
return ['message' => '成员已添加'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 移除家庭成员
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function removeMember($request) {
|
||||
$request->validate([
|
||||
'family_id' => 'required|integer',
|
||||
'user_id' => 'required|integer'
|
||||
], [
|
||||
'family_id.required' => '请提供家庭ID',
|
||||
'user_id.required' => '请提供用户ID'
|
||||
]);
|
||||
|
||||
$familyId = $request->input('family_id');
|
||||
$userId = $request->input('user_id');
|
||||
|
||||
// 检查家庭是否存在
|
||||
$family = Family::findOrFail($familyId);
|
||||
|
||||
// 不能移除家主
|
||||
if ($family->owner_id == $userId) {
|
||||
throw new \Exception('不能移除家主,请先转让家主');
|
||||
}
|
||||
|
||||
// 移除成员
|
||||
$member = FamilyMember::where('family_id', $familyId)
|
||||
->where('user_id', $userId)
|
||||
->first();
|
||||
|
||||
if (!$member) {
|
||||
throw new \Exception('该用户不在家庭中');
|
||||
}
|
||||
|
||||
$member->delete();
|
||||
|
||||
return ['message' => '成员已移除'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 重新生成邀请码
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function regenerateInviteCode($request) {
|
||||
$familyId = $request->input('family_id');
|
||||
|
||||
if (!$familyId) {
|
||||
throw new \Exception('请提供家庭ID');
|
||||
}
|
||||
|
||||
$family = Family::findOrFail($familyId);
|
||||
|
||||
// 生成新邀请码
|
||||
do {
|
||||
$inviteCode = strtoupper(substr(str_shuffle('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 10));
|
||||
} while (Family::where('invite_code', $inviteCode)->exists());
|
||||
|
||||
$family->update(['invite_code' => $inviteCode]);
|
||||
|
||||
return [
|
||||
'invite_code' => $inviteCode,
|
||||
'family_name' => $family->name
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 转让家主
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function transferOwner($request) {
|
||||
$request->validate([
|
||||
'family_id' => 'required|integer',
|
||||
'user_id' => 'required|integer'
|
||||
], [
|
||||
'family_id.required' => '请提供家庭ID',
|
||||
'user_id.required' => '请提供用户ID'
|
||||
]);
|
||||
|
||||
$familyId = $request->input('family_id');
|
||||
$userId = $request->input('user_id');
|
||||
|
||||
$family = Family::findOrFail($familyId);
|
||||
|
||||
// 目标用户必须在家庭中
|
||||
$targetMember = FamilyMember::where('family_id', $familyId)
|
||||
->where('user_id', $userId)
|
||||
->first();
|
||||
|
||||
if (!$targetMember) {
|
||||
throw new \Exception('该用户不在家庭中');
|
||||
}
|
||||
|
||||
// 转让家主
|
||||
$family->update(['owner_id' => $userId]);
|
||||
|
||||
return ['message' => '家主已转让'];
|
||||
}
|
||||
}
|
||||
303
modules/Account/app/Services/AdminStatisticsService.php
Normal file
303
modules/Account/app/Services/AdminStatisticsService.php
Normal file
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2024 http://www.tensent.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Modules\Account\Services;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\Account\Models\Bill;
|
||||
use Modules\Account\Models\Family;
|
||||
use Modules\Account\Models\FamilyMember;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AdminStatisticsService {
|
||||
|
||||
/**
|
||||
* @title 获取概览统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getOverview($request) {
|
||||
$year = $request->input('year', date('Y'));
|
||||
$month = $request->input('month', date('m'));
|
||||
$startDate = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT) . '-01';
|
||||
$endDate = $year . '-' . str_pad($month, 2, '0', STR_PAD_LEFT) . '-31';
|
||||
|
||||
// 总账单数
|
||||
$totalBills = Bill::count();
|
||||
|
||||
// 当月账单数
|
||||
$monthBills = Bill::whereBetween('bill_date', [$startDate, $endDate])->count();
|
||||
|
||||
// 总收入
|
||||
$totalIncome = (float)Bill::where('type', 'income')->sum('amount');
|
||||
|
||||
// 总支出
|
||||
$totalExpense = (float)Bill::where('type', 'expense')->sum('amount');
|
||||
|
||||
// 当月收入
|
||||
$monthIncome = (float)Bill::where('type', 'income')
|
||||
->whereBetween('bill_date', [$startDate, $endDate])
|
||||
->sum('amount');
|
||||
|
||||
// 当月支出
|
||||
$monthExpense = (float)Bill::where('type', 'expense')
|
||||
->whereBetween('bill_date', [$startDate, $endDate])
|
||||
->sum('amount');
|
||||
|
||||
// 总用户数
|
||||
$totalUsers = DB::table('auth_users')->count();
|
||||
|
||||
// 总家庭数
|
||||
$totalFamilies = Family::count();
|
||||
|
||||
// 活跃用户数(本月有记账的用户)
|
||||
$activeUsers = Bill::whereBetween('bill_date', [$startDate, $endDate])
|
||||
->distinct('user_id')
|
||||
->count('user_id');
|
||||
|
||||
// 活跃家庭数(本月有记账的家庭)
|
||||
$activeFamilies = Bill::whereBetween('bill_date', [$startDate, $endDate])
|
||||
->whereNotNull('family_id')
|
||||
->distinct('family_id')
|
||||
->count('family_id');
|
||||
|
||||
return [
|
||||
'total_bills' => $totalBills,
|
||||
'month_bills' => $monthBills,
|
||||
'total_income' => $totalIncome,
|
||||
'total_expense' => $totalExpense,
|
||||
'total_balance' => $totalIncome - $totalExpense,
|
||||
'month_income' => $monthIncome,
|
||||
'month_expense' => $monthExpense,
|
||||
'month_balance' => $monthIncome - $monthExpense,
|
||||
'total_users' => $totalUsers,
|
||||
'total_families' => $totalFamilies,
|
||||
'active_users' => $activeUsers,
|
||||
'active_families' => $activeFamilies
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取趋势统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getTrend($request) {
|
||||
$type = $request->input('type', 'month'); // month 或 year
|
||||
$year = $request->input('year', date('Y'));
|
||||
$months = $request->input('months', 12);
|
||||
$years = $request->input('years', 5);
|
||||
|
||||
if ($type === 'month') {
|
||||
// 月度趋势
|
||||
$data = [];
|
||||
for ($i = $months - 1; $i >= 0; $i--) {
|
||||
$date = date('Y-m', strtotime("-$i months"));
|
||||
$startDate = $date . '-01';
|
||||
$endDate = date('Y-m-t', strtotime($date));
|
||||
|
||||
$income = (float)Bill::where('type', 'income')
|
||||
->whereBetween('bill_date', [$startDate, $endDate])
|
||||
->sum('amount');
|
||||
|
||||
$expense = (float)Bill::where('type', 'expense')
|
||||
->whereBetween('bill_date', [$startDate, $endDate])
|
||||
->sum('amount');
|
||||
|
||||
$count = Bill::whereBetween('bill_date', [$startDate, $endDate])->count();
|
||||
|
||||
$data[] = [
|
||||
'date' => $date,
|
||||
'income' => $income,
|
||||
'expense' => $expense,
|
||||
'balance' => $income - $expense,
|
||||
'count' => $count
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// 年度趋势
|
||||
$data = [];
|
||||
for ($i = $years - 1; $i >= 0; $i--) {
|
||||
$currentYear = date('Y') - $i;
|
||||
|
||||
$income = (float)Bill::where('type', 'income')
|
||||
->whereYear('bill_date', $currentYear)
|
||||
->sum('amount');
|
||||
|
||||
$expense = (float)Bill::where('type', 'expense')
|
||||
->whereYear('bill_date', $currentYear)
|
||||
->sum('amount');
|
||||
|
||||
$count = Bill::whereYear('bill_date', $currentYear)->count();
|
||||
|
||||
$data[] = [
|
||||
'year' => $currentYear,
|
||||
'income' => $income,
|
||||
'expense' => $expense,
|
||||
'balance' => $income - $expense,
|
||||
'count' => $count
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取分类统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getCategoryStatistics($request) {
|
||||
$type = $request->input('type', 'expense'); // income 或 expense
|
||||
$year = $request->input('year', date('Y'));
|
||||
$month = $request->input('month');
|
||||
|
||||
$query = Bill::where('type', $type);
|
||||
|
||||
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';
|
||||
$query->whereBetween('bill_date', [$startDate, $endDate]);
|
||||
} else {
|
||||
$query->whereYear('bill_date', $year);
|
||||
}
|
||||
|
||||
$bills = $query->get();
|
||||
|
||||
// 按分类汇总
|
||||
$data = $bills->groupBy('category')->map(function ($items) {
|
||||
return [
|
||||
'category' => $items->first()->category,
|
||||
'count' => $items->count(),
|
||||
'amount' => (float)$items->sum('amount')
|
||||
];
|
||||
})->sortByDesc('amount')->values();
|
||||
|
||||
// 计算总金额和占比
|
||||
$totalAmount = $data->sum('amount');
|
||||
$data = $data->map(function ($item) use ($totalAmount) {
|
||||
$item['percentage'] = $totalAmount > 0 ? round($item['amount'] / $totalAmount * 100, 2) : 0;
|
||||
return $item;
|
||||
});
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'total_amount' => (float)$totalAmount,
|
||||
'total_count' => $data->sum('count'),
|
||||
'categories' => $data
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取用户统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getUserStatistics($request) {
|
||||
$limit = $request->input('limit', 20);
|
||||
$type = $request->input('type', 'expense'); // income 或 expense
|
||||
$year = $request->input('year', date('Y'));
|
||||
$month = $request->input('month');
|
||||
|
||||
$query = Bill::select('user_id')
|
||||
->selectRaw('COUNT(*) as bill_count')
|
||||
->selectRaw('SUM(CASE WHEN type = "income" THEN amount ELSE 0 END) as total_income')
|
||||
->selectRaw('SUM(CASE WHEN type = "expense" THEN amount ELSE 0 END) as total_expense')
|
||||
->selectRaw('SUM(CASE WHEN type = "income" THEN amount ELSE 0 END) - SUM(CASE WHEN type = "expense" THEN amount ELSE 0 END) as balance')
|
||||
->with('user:uid,nickname,username');
|
||||
|
||||
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';
|
||||
$query->whereBetween('bill_date', [$startDate, $endDate]);
|
||||
} else {
|
||||
$query->whereYear('bill_date', $year);
|
||||
}
|
||||
|
||||
$users = $query->groupBy('user_id')
|
||||
->orderBy($type === 'income' ? 'total_income' : 'total_expense', 'desc')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'users' => $users->map(function ($user) {
|
||||
return [
|
||||
'user_id' => $user->user_id,
|
||||
'name' => $user->user->nickname ?? $user->user->username,
|
||||
'username' => $user->user->username,
|
||||
'bill_count' => $user->bill_count,
|
||||
'total_income' => (float)$user->total_income,
|
||||
'total_expense' => (float)$user->total_expense,
|
||||
'balance' => (float)$user->balance
|
||||
];
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @title 获取家庭统计
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function getFamilyStatistics($request) {
|
||||
$limit = $request->input('limit', 20);
|
||||
$type = $request->input('type', 'expense'); // income 或 expense
|
||||
$year = $request->input('year', date('Y'));
|
||||
$month = $request->input('month');
|
||||
|
||||
$query = Bill::select('family_id')
|
||||
->selectRaw('COUNT(*) as bill_count')
|
||||
->selectRaw('SUM(CASE WHEN type = "income" THEN amount ELSE 0 END) as total_income')
|
||||
->selectRaw('SUM(CASE WHEN type = "expense" THEN amount ELSE 0 END) as total_expense')
|
||||
->selectRaw('SUM(CASE WHEN type = "income" THEN amount ELSE 0 END) - SUM(CASE WHEN type = "expense" THEN amount ELSE 0 END) as balance')
|
||||
->whereNotNull('family_id')
|
||||
->with('family:id,name,owner_id');
|
||||
|
||||
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';
|
||||
$query->whereBetween('bill_date', [$startDate, $endDate]);
|
||||
} else {
|
||||
$query->whereYear('bill_date', $year);
|
||||
}
|
||||
|
||||
$families = $query->groupBy('family_id')
|
||||
->orderBy($type === 'income' ? 'total_income' : 'total_expense', 'desc')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
// 获取成员数量
|
||||
$familyIds = $families->pluck('family_id')->toArray();
|
||||
$memberCounts = FamilyMember::whereIn('family_id', $familyIds)
|
||||
->selectRaw('family_id, COUNT(*) as member_count')
|
||||
->groupBy('family_id')
|
||||
->pluck('member_count', 'family_id');
|
||||
|
||||
return [
|
||||
'type' => $type,
|
||||
'families' => $families->map(function ($family) use ($memberCounts) {
|
||||
return [
|
||||
'family_id' => $family->family_id,
|
||||
'name' => $family->family->name,
|
||||
'member_count' => $memberCounts[$family->family_id] ?? 0,
|
||||
'bill_count' => $family->bill_count,
|
||||
'total_income' => (float)$family->total_income,
|
||||
'total_expense' => (float)$family->total_expense,
|
||||
'balance' => (float)$family->balance
|
||||
];
|
||||
})
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
namespace Modules\Account\Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Services\Auth\MenuService;
|
||||
|
||||
class AccountDatabaseSeeder extends Seeder
|
||||
{
|
||||
@@ -17,6 +18,36 @@ class AccountDatabaseSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// $this->call([]);
|
||||
$this->addAccountMenu();
|
||||
}
|
||||
/**
|
||||
* @title 记账模块菜单导入
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addAccountMenu(){
|
||||
$menuService = app(MenuService::class);
|
||||
|
||||
$menuService->importMenu([
|
||||
['title' => '账单', 'name' => 'account', 'path' => '/account', 'component' => 'account', 'type' => 'menu', 'children' => [
|
||||
['title' => '账单管理', 'name' => 'account.lists', 'path' => '/account/lists', 'component' => 'account/lists', 'type' => 'menu', 'children' => [
|
||||
['title' => '查看账单', 'name' => 'account.bill.view', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
['title' => '添加账单', 'name' => 'account.bill.add', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
['title' => '编辑账单', 'name' => 'account.bill.edit', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
['title' => '删除账单', 'name' => 'account.bill.delete', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
]
|
||||
],
|
||||
['title' => '家庭管理', 'name' => 'account.family', 'path' => '/account/family', 'component' => 'account/family', 'type' => 'menu', 'children' => [
|
||||
['title' => '查看家庭', 'name' => 'account.family.view', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
['title' => '添加家庭', 'name' => 'account.family.add', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
['title' => '编辑家庭', 'name' => 'account.family.edit', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
['title' => '删除家庭', 'name' => 'account.family.delete', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
['title' => '管理成员', 'name' => 'account.family.manage', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
]],
|
||||
['title' => '统计报表', 'name' => 'account.statistics', 'path' => '/account/statistics', 'component' => 'account/statistics', 'type' => 'menu', 'children' => [
|
||||
['title' => '查看统计', 'name' => 'account.statistics.view', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
['title' => '导出报表', 'name' => 'account.statistics.export', 'path' => '', 'component' => '', 'type' => 'button'],
|
||||
]],
|
||||
]]], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,32 @@
|
||||
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Modules\Account\Controllers\AccountController;
|
||||
use Modules\Account\Controllers\Admin\Bill;
|
||||
use Modules\Account\Controllers\Admin\Family;
|
||||
use Modules\Account\Controllers\Admin\Statistics;
|
||||
|
||||
Route::middleware(['auth.check:admin'])->group(function () {
|
||||
Route::apiResource('account', AccountController::class)->names('account');
|
||||
// 账单管理
|
||||
Route::get('account/bill', [Bill::class, 'index'])->name('account.bill.index');
|
||||
Route::post('account/bill', [Bill::class, 'add'])->name('account.bill.add');
|
||||
Route::put('account/bill', [Bill::class, 'edit'])->name('account.bill.edit');
|
||||
Route::delete('account/bill', [Bill::class, 'delete'])->name('account.bill.delete');
|
||||
Route::get('account/bill/detail', [Bill::class, 'detail'])->name('account.bill.detail');
|
||||
|
||||
// 家庭管理
|
||||
Route::get('account/family', [Family::class, 'index'])->name('account.family.index');
|
||||
Route::post('account/family', [Family::class, 'add'])->name('account.family.add');
|
||||
Route::put('account/family', [Family::class, 'edit'])->name('account.family.edit');
|
||||
Route::delete('account/family', [Family::class, 'delete'])->name('account.family.delete');
|
||||
Route::get('account/family/detail', [Family::class, 'detail'])->name('account.family.detail');
|
||||
Route::get('account/family/members', [Family::class, 'members'])->name('account.family.members');
|
||||
Route::post('account/family/member', [Family::class, 'addMember'])->name('account.family.addMember');
|
||||
Route::delete('account/family/member', [Family::class, 'removeMember'])->name('account.family.removeMember');
|
||||
|
||||
// 统计报表
|
||||
Route::get('account/statistics/overview', [Statistics::class, 'overview'])->name('account.statistics.overview');
|
||||
Route::get('account/statistics/trend', [Statistics::class, 'trend'])->name('account.statistics.trend');
|
||||
Route::get('account/statistics/category', [Statistics::class, 'category'])->name('account.statistics.category');
|
||||
Route::get('account/statistics/user', [Statistics::class, 'user'])->name('account.statistics.user');
|
||||
Route::get('account/statistics/family', [Statistics::class, 'family'])->name('account.statistics.family');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user