create page growth report

This commit is contained in:
arifal
2025-05-15 17:02:02 +07:00
parent 9aa3d32b6e
commit a103b38265
9 changed files with 237 additions and 5 deletions

View File

@@ -0,0 +1,85 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\BigdataResume;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class GrowthReportAPIController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(Request $request)
{
// Get current date
$today = Carbon::today();
// Define default range: 1 month back from today
$defaultStart = $today->copy()->subMonth();
$defaultEnd = $today;
// Use request values if provided, else use defaults
$startDate = $request->input('start_date', $defaultStart->toDateString());
$endDate = $request->input('end_date', $defaultEnd->toDateString());
// Optional year filter (used if specified)
$year = $request->input('year', now()->year);
$query = BigdataResume::selectRaw("
DATE(created_at) as date,
SUM(potention_sum) as potention_sum,
SUM(verified_sum) as verified_sum,
SUM(non_verified_sum) as non_verified_sum
")
->whereBetween('created_at', [$startDate, $endDate]);
$query->whereNotNull('year')
->where('year', '!=', 'all');
$data = $query->groupBy(DB::raw('DATE(created_at)'))
->orderBy(DB::raw('DATE(created_at)'))
->get()
->map(function ($item) {
$item->date = Carbon::parse($item->date)->format('d M Y');
return $item;
});
return response()->json($data);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*/
public function show(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function destroy(string $id)
{
//
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace App\Http\Controllers\Report;
use App\Http\Controllers\Controller;
use App\Models\Menu;
use Illuminate\Http\Request;
class GrowthReportsController extends Controller
{
public function index(){
return view('report.growth-report.index');
}
}

View File

@@ -208,23 +208,29 @@ class MenuSeeder extends Seeder
"icon" => null,
"sort_order" => 2,
],
[
"name" => "Lap Pertumbuhan",
"url" => "growths",
"icon" => null,
"sort_order" => 3,
],
[
"name" => "Rekap Pembayaran",
"url" => "payment-recaps",
"icon" => null,
"sort_order" => 3,
"sort_order" => 4,
],
[
"name" => "Lap Rekap Data Pembayaran",
"url" => "report-payment-recaps",
"icon" => null,
"sort_order" => 4,
"sort_order" => 5,
],
[
"name" => "Lap PBG (PTSP)",
"url" => "report-pbg-ptsp",
"icon" => null,
"sort_order" => 5,
"sort_order" => 6,
],
]
],

View File

@@ -25,7 +25,7 @@ class UsersRoleMenuSeeder extends Seeder
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'PETA',
'Lap Pimpinan', 'Dalam Sistem', 'Luar Sistem', 'Google Sheets', 'TPA TPT',
'Approval Pejabat', 'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)'
'Approval Pejabat', 'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)', 'Lap Pertumbuhan'
])->get()->keyBy('name');
// Define access levels for each role
@@ -36,7 +36,7 @@ class UsersRoleMenuSeeder extends Seeder
'Menu', 'Role', 'Setting Dashboard', 'PBG', 'Reklame', 'Usaha atau Industri', 'Pariwisata',
'Lap Pariwisata', 'UMKM', 'Dashboard Potensi', 'Tata Ruang', 'PDAM', 'Dalam Sistem',
'Luar Sistem', 'Lap Pimpinan', 'Google Sheets', 'TPA TPT', 'Approval Pejabat',
'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)'
'Undangan', 'Rekap Pembayaran', 'Lap Rekap Data Pembayaran', 'Lap PBG (PTSP)', 'Lap Pertumbuhan'
],
'user' => ['Dashboard', 'Data', 'Laporan', 'Neng Bedas',
'Approval', 'Tools', 'Dashboard Pimpinan', 'Dashboard PBG', 'Users', 'Syncronize',

View File

@@ -0,0 +1,94 @@
import ApexCharts from "apexcharts";
class GrowthReport {
init() {
this.loadChart();
}
async loadChart() {
try {
const chartElement = document.getElementById("chart-growth-report");
const apiUrl = chartElement.dataset.url;
const token = document
.querySelector('meta[name="api-token"]')
.getAttribute("content");
const response = await fetch(apiUrl, {
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json",
},
});
const data = await response.json();
console.log("data", data);
const categories = data.map((item) => item.date);
const potentionSeries = {
name: "Potensi Berkas",
data: data.map((item) => item.potention_sum),
};
const verifiedSeries = {
name: "Terverifikasi",
data: data.map((item) => item.verified_sum),
};
const nonVerifiedSeries = {
name: "Belum Terverifikasi",
data: data.map((item) => item.non_verified_sum),
};
const options = {
chart: {
type: "bar",
height: 350,
},
title: {
text: "Grafik Pertumbuhan",
},
dataLabels: {
enabled: false,
},
legend: {
show: true,
},
xaxis: {
categories: categories,
},
yaxis: {
title: {
text: "Total SUM Per Date",
},
labels: {
formatter: function (value) {
return "Rp. " + value.toLocaleString("id-ID");
},
},
},
noData: {
text: "Data tidak tersedia",
align: "center",
verticalAlign: "middle",
style: {
color: "#999",
fontSize: "16px",
},
},
series: [potentionSeries, verifiedSeries, nonVerifiedSeries],
};
const chart = new ApexCharts(chartElement, options);
chart.render();
} catch (error) {
console.error("Failed to load growth report data:", error);
}
}
}
document.addEventListener("DOMContentLoaded", function () {
new GrowthReport().init();
});

View File

@@ -0,0 +1,21 @@
@extends('layouts.vertical', ['subtitle' => 'Laporan Pertumbuhan'])
@section('css')
@endsection
@section('content')
@include('layouts.partials/page-title', ['title' => 'Laporan', 'subtitle' => 'Laporan Pertumbuhan'])
<div class="card">
<div class="card-body">
<div class="row">
<div id="chart-growth-report" data-url="{{ route('api.growth') }}"></div>
</div>
</div>
</div>
@endsection
@section('scripts')
@vite(['resources/js/report/growth-report/index.js'])
@endsection

View File

@@ -7,6 +7,7 @@ use App\Http\Controllers\Api\DashboardController;
use App\Http\Controllers\Api\DataSettingController;
use App\Http\Controllers\Api\GlobalSettingsController;
use App\Http\Controllers\Api\GoogleSheetController;
use App\Http\Controllers\Api\GrowthReportAPIController;
use App\Http\Controllers\Api\ImportDatasourceController;
use App\Http\Controllers\Api\LackOfPotentialController;
use App\Http\Controllers\Api\MenusController;
@@ -187,4 +188,8 @@ Route::group(['middleware' => 'auth:sanctum'], function (){
Route::post('/pbg-task-attachment/{pbg_task_id}', 'store')->name('api.pbg-task.upload');
Route::get('/pbg-task-attachment/{attachment_id}/download', 'download')->name('api.pbg-task.download');
});
Route::controller(GrowthReportAPIController::class)->group(function(){
Route::get('/growth','index')->name('api.growth');
});
});

View File

@@ -16,6 +16,7 @@ use App\Http\Controllers\MenusController;
use App\Http\Controllers\PaymentRecapsController;
use App\Http\Controllers\PbgTaskAttachmentsController;
use App\Http\Controllers\QuickSearchController;
use App\Http\Controllers\Report\GrowthReportsController;
use App\Http\Controllers\ReportPaymentRecapsController;
use App\Http\Controllers\ReportPbgPTSPController;
use App\Http\Controllers\RequestAssignment\PbgTaskController;
@@ -163,6 +164,10 @@ Route::group(['middleware' => 'auth'], function(){
Route::controller(ReportPbgPTSPController::class)->group(function (){
Route::get('/report-pbg-ptsp', 'index')->name('report-pbg-ptsp');
});
Route::controller(GrowthReportsController::class)->group(function (){
Route::get('/growths','index')->name('growths');
});
});
// approval

View File

@@ -116,6 +116,8 @@ export default defineConfig({
"resources/js/quick-search/index.js",
"resources/js/quick-search/result.js",
"resources/js/quick-search/detail.js",
// growth-report
"resources/js/report/growth-report/index.js",
// dummy
"resources/js/approval/index.js",
"resources/js/invitations/index.js",