[导出] 佣金收入/销售统计/门店统计

main
Jing Li 2024-05-14 20:47:55 +08:00
parent 8b0d5061a8
commit c3a7597482
5 changed files with 241 additions and 25 deletions

View File

@ -5,8 +5,8 @@ namespace App\Admin\Controllers\Finance;
use App\Admin\Controllers\AdminController;
use App\Admin\Filters\LedgerFilter;
use App\Models\Ledger;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Slowlyo\OwlAdmin\Admin;
/**
* @property mixed $name
@ -17,16 +17,21 @@ class CommissionIncomeController extends AdminController
{
if ($this->actionOfGetData()) {
return $this->response()->success([
'items' => [$this->getCommissionIncomeStatistics(request())],
'items' => [$this->getCommissionIncomeStatistics()],
]);
}
if ($this->actionOfExport()) {
return $this->export();
}
return $this->response()->success(
$this->baseList(
$this->baseCRUD()
->headerToolbar([
amis('filter-toggler')->align('right'),
])
->headerToolbar(
collect($this->baseHeaderToolBar())
->when(Admin::user()->can('admin.finance.commission_incomes.export'), fn ($collection) => $collection->push($this->exportAction(true)))
)
->footerToolbar([])
->bulkActions([])
->filter($this->baseFilter()->body([
@ -57,7 +62,7 @@ class CommissionIncomeController extends AdminController
);
}
protected function getCommissionIncomeStatistics(Request $request): array
protected function getCommissionIncomeStatistics(): array
{
$aggregate = Ledger::select([
DB::raw('SUM(expenditure) as expenditure'),
@ -66,7 +71,7 @@ class CommissionIncomeController extends AdminController
DB::raw('SUM(expected_income) as expected_income'),
DB::raw('SUM(actual_income) as actual_income'),
])
->filter($request->input(), LedgerFilter::class)
->filter(request()->input(), LedgerFilter::class)
->first();
$expectedCommission = $aggregate->expected_commission ?? '0';
@ -83,4 +88,69 @@ class CommissionIncomeController extends AdminController
'diff_income' => trim_zeros(bcsub($actualIncome, $expectedIncome, 2)),
];
}
/**
* 导出按钮
*
* @param bool $disableSelectedItem
*
* @return \Slowlyo\OwlAdmin\Renderers\Service
*/
protected function exportAction($disableSelectedItem = false)
{
// 下载路径
$downloadPath = admin_url('_download_export', true);
// 导出接口地址
$exportPath = $this->getExportPath();
// 按钮点击事件
$event = fn($script) => ['click' => ['actions' => [['actionType' => 'custom', 'script' => $script]]]];
// 导出处理动作
$doAction = "doAction([{actionType:'setValue',componentId:'export-action',args:{value:{showExportLoading:true}}},{actionType:'ajax',args:{api:{url:url.toString(),method:'get'}}},{actionType:'setValue',componentId:'export-action',args:{value:{showExportLoading:false}}},{actionType:'custom',expression:'\${event.data.responseResult.responseStatus===0}',script:'window.open(\'{$downloadPath}?path=\'+event.data.responseResult.responseData.path)'}])";
// 按钮
$button = amis()->Button()
->label(__('admin.export.title'))
->icon('fa-solid fa-download')
->onEvent(
$event("let data=event.data;let params=Object.keys(data).filter(key=>key!=='page' && key!=='__super').reduce((obj,key)=>{obj[key]=data[key];return obj;},{});let url=new URL('{$exportPath}',window.location.origin);Object.keys(params).forEach(key=>url.searchParams.append(key,params[key]));{$doAction}")
);
return amis()->Service()
->id('export-action')
->set('align', 'right')
->set('data', ['showExportLoading' => false])
->body(
amis()->Spinner()->set('showOn', '${showExportLoading}')->overlay()->body($button)
);
}
/**
* 导出
*
* @return JsonResponse|JsonResource
*/
protected function export()
{
admin_abort_if(!class_exists('\Rap2hpoutre\FastExcel\FastExcel'), __('admin.export.please_install_laravel_excel'));
// 默认在 storage/app/ 下
$path = sprintf('佣金收入-%s.xlsx', date('YmdHis'));
$data = [$this->getCommissionIncomeStatistics()];
try {
fastexcel($data)->export(storage_path('app/' . $path), fn($row) => [
'预期佣金' => $row['expected_commission'],
'实际佣金' => $row['actual_commission'],
'佣金差异' => $row['diff_commission'],
'预期收益' => $row['expected_income'],
'实际收益' => $row['actual_income'],
'收益差异' => $row['diff_income'],
]);
} catch (\Throwable $e) {
report($e);
admin_abort(__('admin.action_failed'));
}
return $this->response()->success(compact('path'));
}
}

View File

@ -6,8 +6,8 @@ use App\Admin\Controllers\AdminController;
use App\Admin\Filters\LedgerItemFilter;
use App\Models\Keyword;
use App\Models\LedgerItem;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Slowlyo\OwlAdmin\Admin;
/**
* @property mixed $name
@ -18,16 +18,21 @@ class SalesStatisticController extends AdminController
{
if ($this->actionOfGetData()) {
return $this->response()->success([
'items' => $this->getLotteryTypeStatistics(request()),
'items' => $this->getLotteryTypeStatistics(),
]);
}
if ($this->actionOfExport()) {
return $this->export();
}
return $this->response()->success(
$this->baseList(
$this->baseCRUD()
->headerToolbar([
amis('filter-toggler')->align('right'),
])
->headerToolbar(
collect($this->baseHeaderToolBar())
->when(Admin::user()->can('admin.finance.sales_statistics.export'), fn ($collection) => $collection->push($this->exportAction(true)))
)
->footerToolbar([])
->bulkActions([])
->filter($this->baseFilter()->body([
@ -60,7 +65,7 @@ class SalesStatisticController extends AdminController
);
}
protected function getLotteryTypeStatistics(Request $request): array
protected function getLotteryTypeStatistics(): array
{
/** @var \Illuminate\Database\Eloquent\Collection */
$lotteryTypes = Keyword::where('parent_key', 'lottery_type')->get();
@ -71,7 +76,7 @@ class SalesStatisticController extends AdminController
DB::raw('SUM(sales) as sales'),
DB::raw('SUM(expenditure) as expenditure'),
])
->filter($request->input(), LedgerItemFilter::class)
->filter(request()->input(), LedgerItemFilter::class)
->whereIn('ledger_item_type_id', $lotteryTypes->pluck('key'))
->groupBy('ledger_item_type_id')
->get()
@ -97,4 +102,65 @@ class SalesStatisticController extends AdminController
];
})->all();
}
/**
* 导出按钮
*
* @param bool $disableSelectedItem
*
* @return \Slowlyo\OwlAdmin\Renderers\Service
*/
protected function exportAction($disableSelectedItem = false)
{
// 下载路径
$downloadPath = admin_url('_download_export', true);
// 导出接口地址
$exportPath = $this->getExportPath();
// 按钮点击事件
$event = fn($script) => ['click' => ['actions' => [['actionType' => 'custom', 'script' => $script]]]];
// 导出处理动作
$doAction = "doAction([{actionType:'setValue',componentId:'export-action',args:{value:{showExportLoading:true}}},{actionType:'ajax',args:{api:{url:url.toString(),method:'get'}}},{actionType:'setValue',componentId:'export-action',args:{value:{showExportLoading:false}}},{actionType:'custom',expression:'\${event.data.responseResult.responseStatus===0}',script:'window.open(\'{$downloadPath}?path=\'+event.data.responseResult.responseData.path)'}])";
// 按钮
$button = amis()->Button()
->label(__('admin.export.title'))
->icon('fa-solid fa-download')
->onEvent(
$event("let data=event.data;let params=Object.keys(data).filter(key=>key!=='page' && key!=='__super').reduce((obj,key)=>{obj[key]=data[key];return obj;},{});let url=new URL('{$exportPath}',window.location.origin);Object.keys(params).forEach(key=>url.searchParams.append(key,params[key]));{$doAction}")
);
return amis()->Service()
->id('export-action')
->set('align', 'right')
->set('data', ['showExportLoading' => false])
->body(
amis()->Spinner()->set('showOn', '${showExportLoading}')->overlay()->body($button)
);
}
/**
* 导出
*
* @return JsonResponse|JsonResource
*/
protected function export()
{
admin_abort_if(!class_exists('\Rap2hpoutre\FastExcel\FastExcel'), __('admin.export.please_install_laravel_excel'));
// 默认在 storage/app/ 下
$path = sprintf('销售统计-%s.xlsx', date('YmdHis'));
$data = $this->getLotteryTypeStatistics();
try {
fastexcel($data)->export(storage_path('app/' . $path), fn($row) => [
'彩种' => $row['name'],
'销量' => $row['sales'],
'兑奖' => $row['expenditure'],
]);
} catch (\Throwable $e) {
admin_abort(__('admin.action_failed'));
}
return $this->response()->success(compact('path'));
}
}

View File

@ -5,30 +5,29 @@ namespace App\Admin\Controllers\Finance;
use App\Admin\Controllers\AdminController;
use App\Services\StatisticService;
use Illuminate\Support\Arr;
use Slowlyo\OwlAdmin\Admin;
class StoreStatisticController extends AdminController
{
public function index()
{
if ($this->actionOfGetData()) {
$input = Arr::except(request()->input(), ['orderBy', 'orderDir']);
$orderBy = request()->input('orderBy') ?: 'sales';
$orderDir = request()->input('orderDir') ?: 'desc';
$input['sort'] = ($orderDir === 'desc' ? '-' : '').$orderBy;
return $this->response()->success([
'items' => (new StatisticService())->storeRanking($input),
'items' => $this->getStoreRanking(),
]);
}
if ($this->actionOfExport()) {
return $this->export();
}
return $this->response()->success(
$this->baseList(
$this->baseCRUD()
->headerToolbar([
amis('filter-toggler')->align('right'),
])
->headerToolbar(
collect($this->baseHeaderToolBar())
->when(Admin::user()->can('admin.finance.store_statistics.export'), fn ($collection) => $collection->push($this->exportAction(true)))
)
->footerToolbar([])
->bulkActions([])
->filter($this->baseFilter()->body([
@ -55,4 +54,81 @@ class StoreStatisticController extends AdminController
)
);
}
protected function getStoreRanking(): array
{
$input = Arr::except(request()->input(), ['orderBy', 'orderDir']);
$orderBy = request()->input('orderBy') ?: 'sales';
$orderDir = request()->input('orderDir') ?: 'desc';
$input['sort'] = ($orderDir === 'desc' ? '-' : '').$orderBy;
return (new StatisticService())->storeRanking($input);
}
/**
* 导出按钮
*
* @param bool $disableSelectedItem
*
* @return \Slowlyo\OwlAdmin\Renderers\Service
*/
protected function exportAction($disableSelectedItem = false)
{
// 下载路径
$downloadPath = admin_url('_download_export', true);
// 导出接口地址
$exportPath = $this->getExportPath();
// 按钮点击事件
$event = fn($script) => ['click' => ['actions' => [['actionType' => 'custom', 'script' => $script]]]];
// 导出处理动作
$doAction = "doAction([{actionType:'setValue',componentId:'export-action',args:{value:{showExportLoading:true}}},{actionType:'ajax',args:{api:{url:url.toString(),method:'get'}}},{actionType:'setValue',componentId:'export-action',args:{value:{showExportLoading:false}}},{actionType:'custom',expression:'\${event.data.responseResult.responseStatus===0}',script:'window.open(\'{$downloadPath}?path=\'+event.data.responseResult.responseData.path)'}])";
// 按钮
$button = amis()->Button()
->label(__('admin.export.title'))
->icon('fa-solid fa-download')
->onEvent(
$event("let data=event.data;let params=Object.keys(data).filter(key=>key!=='page' && key!=='__super').reduce((obj,key)=>{obj[key]=data[key];return obj;},{});let url=new URL('{$exportPath}',window.location.origin);Object.keys(params).forEach(key=>url.searchParams.append(key,params[key]));{$doAction}")
);
return amis()->Service()
->id('export-action')
->set('align', 'right')
->set('data', ['showExportLoading' => false])
->body(
amis()->Spinner()->set('showOn', '${showExportLoading}')->overlay()->body($button)
);
}
/**
* 导出
*
* @return JsonResponse|JsonResource
*/
protected function export()
{
admin_abort_if(!class_exists('\Rap2hpoutre\FastExcel\FastExcel'), __('admin.export.please_install_laravel_excel'));
// 默认在 storage/app/ 下
$path = sprintf('门店统计-%s.xlsx', date('YmdHis'));
$data = $this->getStoreRanking();
try {
fastexcel($data)->export(storage_path('app/' . $path), function($row) {
return [
'排序' => $row['ranking'],
'门店' => Arr::get($row, 'store.title'),
'收入' => $row['sales'],
'支出' => $row['expenditure'],
];
});
} catch (\Throwable $e) {
report($e);
admin_abort(__('admin.action_failed'));
}
return $this->response()->success(compact('path'));
}
}

View File

@ -192,6 +192,7 @@ class StatisticService
->groupBy('store_id');
$stores = Store::filter($input, StoreFilter::class)
->selectRaw('stores.*,IFNULL(store_ledgers.sales, 0) as sales,IFNULL(store_ledgers.expenditure, 0) as expenditure')
->leftJoinSub($storeLedgers, 'store_ledgers', fn ($join) => $join->on('stores.id', '=', 'store_ledgers.store_id'))
->when($input['sort'] ?? '', function ($query, $sort) {
foreach (explode(',', $sort) as $sort) {

View File

@ -278,6 +278,7 @@ class AdminPermissionSeeder extends Seeder
'resource' => false,
'children' => [
'index' => '佣金收入',
'export' => '导出',
],
],
'reimbursements' => [
@ -296,6 +297,7 @@ class AdminPermissionSeeder extends Seeder
'resource' => false,
'children' => [
'index' => '销售统计',
'export' => '导出',
],
],
'store_statistics' => [
@ -305,6 +307,7 @@ class AdminPermissionSeeder extends Seeder
'resource' => false,
'children' => [
'index' => '门店统计',
'export' => '导出',
],
],
'store_master_commissions' => [