Compare commits
46 Commits
fix/crud-v
...
fix/dashbo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5e3fdd915 | ||
|
|
cdd84d02da | ||
|
|
ee1a395c75 | ||
|
|
3bfcaddba4 | ||
|
|
9ea7e96af1 | ||
|
|
e0d11af7d2 | ||
|
|
fefef609ac | ||
|
|
f5790cda94 | ||
|
|
f3db3783f9 | ||
|
|
101e76c0fa | ||
|
|
4cc698a623 | ||
|
|
544ad1db46 | ||
|
|
30ca819aa1 | ||
|
|
b0bab784d1 | ||
|
|
01fda22c89 | ||
|
|
de300c2c32 | ||
|
|
7f8a2e4936 | ||
|
|
38948b6633 | ||
|
|
aa9943ba45 | ||
|
|
9e55ea0dbb | ||
|
|
93f0ac5ef7 | ||
|
|
8bae33519f | ||
|
|
6865e353e6 | ||
|
|
bb4ab5c769 | ||
|
|
e743b82087 | ||
|
|
c3c7b8e3ec | ||
|
|
d49035ce8d | ||
|
|
ffd9d3514c | ||
|
|
675477c734 | ||
|
|
4350c466e3 | ||
|
|
5ab407d672 | ||
|
|
2aaa487746 | ||
|
|
080582f7ab | ||
|
|
91475aeead | ||
|
|
a7afbd69fb | ||
|
|
1ff5587050 | ||
|
|
9c8a1a3f3f | ||
|
|
5c4be7635b | ||
|
|
ba315b1dee | ||
|
|
33b7131c33 | ||
|
|
7a56735099 | ||
|
|
dd331b4a08 | ||
|
|
dcd93d66e2 | ||
|
|
5d50d6d6cc | ||
|
|
39717d184c | ||
|
|
54146c8c08 |
85
README.md
85
README.md
@@ -1,66 +1,37 @@
|
||||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
|
||||
# Usage icon
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||
</p>
|
||||
search or pick icon in <a href="https://icon-sets.iconify.design/mingcute/?keyword=mingcute">here</a>
|
||||
|
||||
## About Laravel
|
||||
# Set up queue for running automatically
|
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||
- Install Supervisor
|
||||
|
||||
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||
```
|
||||
sudo apt update && sudo apt install supervisor -y
|
||||
```
|
||||
|
||||
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||
- Create Supervisor Config
|
||||
|
||||
## Learning Laravel
|
||||
```
|
||||
sudo nano /etc/supervisor/conf.d/laravel-worker.conf
|
||||
|
||||
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
|
||||
[program:laravel-worker]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=php /path-to-your-project/artisan queue:work --tries=3 --timeout=600
|
||||
autostart=true
|
||||
autorestart=true
|
||||
numprocs=1
|
||||
user=www-data
|
||||
redirect_stderr=true
|
||||
stdout_logfile=/var/log/supervisor/laravel-worker.log
|
||||
```
|
||||
|
||||
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
|
||||
- Reload Supervisor
|
||||
|
||||
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||
|
||||
## Laravel Sponsors
|
||||
|
||||
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
|
||||
|
||||
### Premium Partners
|
||||
|
||||
- **[Vehikl](https://vehikl.com/)**
|
||||
- **[Tighten Co.](https://tighten.co)**
|
||||
- **[WebReinvent](https://webreinvent.com/)**
|
||||
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||
- **[64 Robots](https://64robots.com)**
|
||||
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
|
||||
- **[Cyber-Duck](https://cyber-duck.co.uk)**
|
||||
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||
- **[Jump24](https://jump24.co.uk)**
|
||||
- **[Redberry](https://redberry.international/laravel/)**
|
||||
- **[Active Logic](https://activelogic.com)**
|
||||
- **[byte5](https://byte5.de)**
|
||||
- **[OP.GG](https://op.gg)**
|
||||
|
||||
## Contributing
|
||||
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||
|
||||
## Security Vulnerabilities
|
||||
|
||||
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||
|
||||
## License
|
||||
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||
```
|
||||
sudo supervisorctl reread
|
||||
sudo supervisorctl update
|
||||
sudo supervisorctl start laravel-worker
|
||||
sudo supervisorctl restart laravel-worker
|
||||
sudo supervisorctl status
|
||||
```
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Jobs\SyncronizeSIMBG;
|
||||
use App\Services\ServiceSIMBG;
|
||||
use Illuminate\Console\Command;
|
||||
use \Illuminate\Support\Facades\Log;
|
||||
@@ -28,13 +29,12 @@ class ExecuteScraping extends Command
|
||||
|
||||
private $service_simbg;
|
||||
|
||||
public function __construct(ServiceSIMBG $service_simbg){
|
||||
$this->service_simbg = $service_simbg;
|
||||
public function __construct(){
|
||||
parent::__construct();
|
||||
}
|
||||
public function handle()
|
||||
{
|
||||
SyncronizeSIMBG::dispatch();
|
||||
Log::info("running scheduler daily scraping");
|
||||
$this->service_simbg->syncTaskList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ class AdvertisementController extends Controller
|
||||
|
||||
public function downloadExcelAdvertisement()
|
||||
{
|
||||
$filePath = storage_path('app/public/templates/template_reklame.xlsx');
|
||||
$filePath = public_path('templates/template_reklame.xlsx');
|
||||
|
||||
// Cek apakah file ada
|
||||
if (!file_exists($filePath)) {
|
||||
|
||||
234
app/Http/Controllers/Api/BigDataResumeController.php
Normal file
234
app/Http/Controllers/Api/BigDataResumeController.php
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\BigdataResumeResource;
|
||||
use App\Models\BigdataResume;
|
||||
use App\Models\DataSetting;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BigDataResumeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try{
|
||||
$filterDate = $request->get("filterByDate");
|
||||
|
||||
if (!$filterDate || $filterDate === "latest") {
|
||||
$big_data_resume = BigdataResume::where('year', now()->year)->latest()->first();
|
||||
if (!$big_data_resume) {
|
||||
return $this->response_empty_resume();
|
||||
}
|
||||
} else {
|
||||
$big_data_resume = BigdataResume::whereDate('created_at', $filterDate)
|
||||
->orderBy('id', 'desc')
|
||||
->first();
|
||||
|
||||
if (!$big_data_resume) {
|
||||
return $this->response_empty_resume();
|
||||
}
|
||||
}
|
||||
|
||||
$data_settings = DataSetting::all();
|
||||
if($data_settings->isEmpty()){
|
||||
return response()->json(['message' => 'No data setting found']);
|
||||
}
|
||||
|
||||
function cleanNumber($value) {
|
||||
return floatval(str_replace('.', '', $value));
|
||||
}
|
||||
|
||||
$target_pad = floatval(optional($data_settings->where('key', 'TARGET_PAD')->first())->value);
|
||||
$realisasi_terbit_pbg_sum = cleanNumber(optional($data_settings->where('key', 'REALISASI_TERBIT_PBG_SUM')->first())->value);
|
||||
$realisasi_terbit_pbg_count = cleanNumber(optional($data_settings->where('key', 'REALISASI_TERBIT_PBG_COUNT')->first())->value);
|
||||
$menunggu_klik_dpmptsp_sum = cleanNumber(optional($data_settings->where('key', 'MENUNGGU_KLIK_DPMPTSP_SUM')->first())->value);
|
||||
$menunggu_klik_dpmptsp_count = cleanNumber(optional($data_settings->where('key', 'MENUNGGU_KLIK_DPMPTSP_COUNT')->first())->value);
|
||||
$proses_dinas_teknis_sum = cleanNumber(optional($data_settings->where('key', 'PROSES_DINAS_TEKNIS_SUM')->first())->value);
|
||||
$proses_dinas_teknis_count = cleanNumber(optional($data_settings->where('key', 'PROSES_DINAS_TEKNIS_COUNT')->first())->value);
|
||||
|
||||
$tata_ruang = $big_data_resume->spatial_sum;
|
||||
$kekurangan_potensi = $target_pad - $big_data_resume->potention_sum;
|
||||
|
||||
// percentage kekurangan potensi
|
||||
$kekurangan_potensi_percentage = $target_pad > 0 && $target_pad > 0
|
||||
? round(($kekurangan_potensi / $target_pad) * 100, 2) : 0;
|
||||
|
||||
// percentage total potensi
|
||||
$total_potensi_percentage = $big_data_resume->potention_sum > 0 && $target_pad > 0
|
||||
? round(($big_data_resume->potention_sum / $target_pad) * 100, 2) : 0;
|
||||
|
||||
// percentage verified document
|
||||
$verified_percentage = $big_data_resume->verified_sum > 0 && $big_data_resume->potention_sum > 0
|
||||
? round(($big_data_resume->verified_sum / $big_data_resume->potention_sum) * 100, 2) : 0;
|
||||
|
||||
// percentage non-verified document
|
||||
$non_verified_percentage = $big_data_resume->non_verified_sum > 0 && $big_data_resume->potention_sum > 0
|
||||
? round(($big_data_resume->non_verified_sum / $big_data_resume->potention_sum) * 100, 2) : 0;
|
||||
|
||||
// percentage business document
|
||||
$business_percentage = $big_data_resume->business_sum > 0 && $big_data_resume->non_verified_sum > 0
|
||||
? round(($big_data_resume->business_sum / $big_data_resume->non_verified_sum) * 100, 2) : 0;
|
||||
|
||||
// percentage non-business document
|
||||
$non_business_percentage = $big_data_resume->non_business_sum > 0 && $big_data_resume->potention_sum > 0
|
||||
? round(($big_data_resume->non_business_sum / $big_data_resume->potention_sum) * 100, 2) : 0;
|
||||
|
||||
// percentage tata ruang
|
||||
$tata_ruang_percentage = $tata_ruang > 0 && $big_data_resume->potention_sum > 0
|
||||
? round(($tata_ruang / $big_data_resume->potention_sum) * 100, 2) : 0;
|
||||
|
||||
// percentage realisasi terbit pbg
|
||||
$realisasi_terbit_percentage = $big_data_resume->verified_sum > 0 && $realisasi_terbit_pbg_sum > 0
|
||||
? round(($realisasi_terbit_pbg_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
|
||||
|
||||
// percentage menunggu klik dpmptsp
|
||||
$menunggu_klik_dpmptsp_percentage = $big_data_resume->verified_sum > 0 && $menunggu_klik_dpmptsp_sum > 0
|
||||
? round(($menunggu_klik_dpmptsp_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
|
||||
|
||||
// percentage proses_dinas_teknis
|
||||
$proses_dinas_teknis_percentage = $big_data_resume->verified_sum > 0 && $proses_dinas_teknis_sum > 0
|
||||
? round(($proses_dinas_teknis_sum / $big_data_resume->verified_sum) * 100, 2) : 0;
|
||||
|
||||
$result = [
|
||||
'target_pad' => [
|
||||
'sum' => $target_pad,
|
||||
'percentage' => 100,
|
||||
],
|
||||
'tata_ruang' => [
|
||||
'sum' => $big_data_resume->spatial_sum,
|
||||
'count' => $big_data_resume->spatial_count,
|
||||
'percentage' => $tata_ruang_percentage,
|
||||
],
|
||||
'kekurangan_potensi' => [
|
||||
'sum' => $kekurangan_potensi,
|
||||
'percentage' => $kekurangan_potensi_percentage
|
||||
],
|
||||
'total_potensi' => [
|
||||
'sum' => (float) $big_data_resume->potention_sum,
|
||||
'count' => $big_data_resume->potention_count,
|
||||
'percentage' => $total_potensi_percentage
|
||||
],
|
||||
'verified_document' => [
|
||||
'sum' => (float) $big_data_resume->verified_sum,
|
||||
'count' => $big_data_resume->verified_count,
|
||||
'percentage' => $verified_percentage
|
||||
],
|
||||
'non_verified_document' => [
|
||||
'sum' => (float) $big_data_resume->non_verified_sum,
|
||||
'count' => $big_data_resume->non_verified_count,
|
||||
'percentage' => $non_verified_percentage
|
||||
],
|
||||
'business_document' => [
|
||||
'sum' => (float) $big_data_resume->business_sum,
|
||||
'count' => $big_data_resume->business_count,
|
||||
'percentage' => $business_percentage
|
||||
],
|
||||
'non_business_document' => [
|
||||
'sum' => (float) $big_data_resume->non_business_sum,
|
||||
'count' => $big_data_resume->non_business_count,
|
||||
'percentage' => $non_business_percentage
|
||||
],
|
||||
'realisasi_terbit' => [
|
||||
'sum' => $realisasi_terbit_pbg_sum,
|
||||
'count' => $realisasi_terbit_pbg_count,
|
||||
'percentage' => $realisasi_terbit_percentage
|
||||
],
|
||||
'menunggu_klik_dpmptsp' => [
|
||||
'sum' => $menunggu_klik_dpmptsp_sum,
|
||||
'count' => $menunggu_klik_dpmptsp_count,
|
||||
'percentage' => $menunggu_klik_dpmptsp_percentage
|
||||
],
|
||||
'proses_dinas_teknis' => [
|
||||
'sum' => $proses_dinas_teknis_sum,
|
||||
'count' => $proses_dinas_teknis_count,
|
||||
'percentage' => $proses_dinas_teknis_percentage
|
||||
]
|
||||
];
|
||||
return response()->json($result);
|
||||
}catch(\Exception $e){
|
||||
return response()->json(['message' => 'Error when fetching data'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function bigdata_report(Request $request){
|
||||
try{
|
||||
$query = BigdataResume::query()->orderBy('id', 'desc');
|
||||
|
||||
if($request->filled('search')){
|
||||
$query->where('name', 'LIKE', '%'.$request->input('search').'%');
|
||||
}
|
||||
|
||||
$query = $query->paginate(config('app.paginate_per_page', 50));
|
||||
return BigdataResumeResource::collection($query)->response()->getData(true);
|
||||
}catch(\Exception $e){
|
||||
Log::error($e->getMessage());
|
||||
return response()->json(['message' => 'Error when fetching data'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
private function response_empty_resume(){
|
||||
$result = [
|
||||
'target_pad' => [
|
||||
'sum' => 0,
|
||||
'percentage' => 100,
|
||||
],
|
||||
'tata_ruang' => [
|
||||
'sum' => 0,
|
||||
'percentage' => 0,
|
||||
],
|
||||
'kekurangan_potensi' => [
|
||||
'sum' => 0,
|
||||
'percentage' => 0
|
||||
],
|
||||
'total_potensi' => [
|
||||
'sum' => 0,
|
||||
'count' => 0,
|
||||
'percentage' => 0
|
||||
],
|
||||
'verified_document' => [
|
||||
'sum' => 0,
|
||||
'count' => 0,
|
||||
'percentage' => 0
|
||||
],
|
||||
'non_verified_document' => [
|
||||
'sum' => 0,
|
||||
'count' => 0,
|
||||
'percentage' => 0
|
||||
],
|
||||
'business_document' => [
|
||||
'sum' => 0,
|
||||
'count' => 0,
|
||||
'percentage' => 0
|
||||
],
|
||||
'non_business_document' => [
|
||||
'sum' => 0,
|
||||
'count' => 0,
|
||||
'percentage' => 0
|
||||
],
|
||||
'realisasi_terbit' => [
|
||||
'sum' => 0,
|
||||
'count' => 0,
|
||||
'percentage' => 0
|
||||
],
|
||||
'menunggu_klik_dpmptsp' => [
|
||||
'sum' => 0,
|
||||
'count' => 0,
|
||||
'percentage' => 0
|
||||
],
|
||||
'proses_dinas_teknis' => [
|
||||
'sum' => 0,
|
||||
'count' => 0,
|
||||
'percentage' => 0
|
||||
]
|
||||
];
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use App\Models\BusinessOrIndustry;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use \Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Requests\ExcelUploadRequest;
|
||||
class BusinessOrIndustriesController extends Controller
|
||||
{
|
||||
/**
|
||||
@@ -30,7 +31,7 @@ class BusinessOrIndustriesController extends Controller
|
||||
});
|
||||
}
|
||||
|
||||
return response()->json($query->paginate());
|
||||
return response()->json($query->paginate(config('app.paginate_per_page', 50)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,29 +80,15 @@ class BusinessOrIndustriesController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function upload(Request $request){
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
$file = $request->file('file');
|
||||
}
|
||||
|
||||
// Validasi file
|
||||
$validator = Validator::make($request->all(), [
|
||||
'file' => 'required|mimes:xlsx,xls|max:102400', // Max 100MB
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message' => 'File validation failed.',
|
||||
'errors' => $validator->errors()
|
||||
], 400);
|
||||
}
|
||||
|
||||
public function upload(ExcelUploadRequest $request){
|
||||
try {
|
||||
// Ambil file dari request
|
||||
$file = $request->file('file');
|
||||
if(!$request->hasFile('file')){
|
||||
return response()->json([
|
||||
'error' => 'No file provided'
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Menggunakan Laravel Excel untuk mengimpor file
|
||||
$file = $request->file('file');
|
||||
Excel::import(new BusinessIndustriesImport, $file);
|
||||
|
||||
// Jika sukses, kembalikan respons sukses
|
||||
|
||||
84
app/Http/Controllers/Api/ChatbotController.php
Normal file
84
app/Http/Controllers/Api/ChatbotController.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Services\OpenAIService;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ChatbotController extends Controller
|
||||
{
|
||||
protected $openAIService;
|
||||
|
||||
public function __construct(OpenAIService $openAIService)
|
||||
{
|
||||
$this->openAIService = $openAIService;
|
||||
}
|
||||
|
||||
public function generateText(Request $request)
|
||||
{
|
||||
info($request);
|
||||
$request->validate([
|
||||
'tab_active' => 'required|string',
|
||||
'prompt' => 'required|string',
|
||||
]);
|
||||
|
||||
$tab_active = $request->input('tab_active');
|
||||
$main_content = match ($tab_active) {
|
||||
"count-retribusi" => "RETRIBUTION",
|
||||
"document-validation" => "DOCUMENT VALIDATION",
|
||||
"data-information" => "DATA SUMMARY",
|
||||
default => "UNKNOWN",
|
||||
};
|
||||
|
||||
if ($main_content === "UNKNOWN") {
|
||||
return response()->json(['response' => 'Invalid tab_active value.'], 400);
|
||||
}
|
||||
|
||||
info($main_content);
|
||||
|
||||
// Klasifikasi apakah pertanyaan butuh database atau bisa dijawab langsung
|
||||
$classifyResponse = $this->openAIService->generateClassifyMainContent($request->input('prompt'), $main_content);
|
||||
|
||||
if ($classifyResponse === "DATABASE") {
|
||||
$queryResponse = $this->openAIService->generateQueryBasedMainContent($request->input('prompt'), $main_content);
|
||||
if (is_array($queryResponse)) {
|
||||
info('Query Response is an array: ', $queryResponse);
|
||||
} else {
|
||||
info('Query Response is a string: ' . $queryResponse);
|
||||
}
|
||||
|
||||
// Validasi query dua kali sebelum eksekusi
|
||||
if (
|
||||
$this->openAIService->validateSyntaxQuery($queryResponse) === "VALID" &&
|
||||
$this->openAIService->validateSyntaxQuery($queryResponse) === "VALID"
|
||||
) {
|
||||
info($queryResponse);
|
||||
$queryResponse = str_replace(['```sql', '```'], '', $queryResponse);
|
||||
$resultQuery = DB::select($queryResponse);
|
||||
$formattedResultQuery = json_encode($resultQuery, JSON_PRETTY_PRINT);
|
||||
$nlpResult = $this->openAIService->generateNLPFromQuery($request->input('prompt'), $formattedResultQuery);
|
||||
$finalGeneratedText =$this->openAIService->generateFinalText($nlpResult);
|
||||
return response()->json(['response' => $finalGeneratedText]);
|
||||
}
|
||||
|
||||
return response()->json(['response' => ''], 400);
|
||||
}
|
||||
|
||||
if ($classifyResponse === "GENERAL") {
|
||||
$nlpResult = $this->openAIService->generateGeneralText($request->input('prompt'), $main_content);
|
||||
$finalGeneratedText =$this->openAIService->generateFinalText($nlpResult);
|
||||
return response()->json(['response' => $finalGeneratedText]);
|
||||
}
|
||||
|
||||
return response()->json(['response' => ''], 500);
|
||||
}
|
||||
|
||||
|
||||
private function classifyContent(string $prompt) {
|
||||
$classifyResponse = $this->openAIService->generateClassifyContent($prompt);
|
||||
return $classifyResponse;
|
||||
}
|
||||
}
|
||||
130
app/Http/Controllers/Api/CustomersController.php
Normal file
130
app/Http/Controllers/Api/CustomersController.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\CustomersRequest;
|
||||
use App\Http\Requests\ExcelUploadRequest;
|
||||
use App\Http\Resources\CustomersResource;
|
||||
use App\Imports\CustomersImport;
|
||||
use App\Models\Customer;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class CustomersController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Customer::query()->orderBy('id', 'desc');
|
||||
if ($request->has('search') &&!empty($request->get('search'))) {
|
||||
$query = $query->where('nomor_pelanggan', 'LIKE', '%'.$request->get('search').'%')
|
||||
->orWhere('nama', 'LIKE', '%'.$request->get('search').'%')
|
||||
->orWhere('kota_pelayanan', 'LIKE', '%'.$request->get('search').'%');
|
||||
}
|
||||
return CustomersResource::collection($query->paginate(config('app.paginate_per_page', 50)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(CustomersRequest $request)
|
||||
{
|
||||
try{
|
||||
$customer = Customer::create($request->validated());
|
||||
return response()->json(['message' => 'Successfully created', new CustomersResource($customer)]);
|
||||
}catch(\Exception $e){
|
||||
return response()->json([
|
||||
'message' => 'Failed to create customer',
|
||||
'error' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
try{
|
||||
$customer = Customer::find($id);
|
||||
if($customer){
|
||||
return new CustomersResource($customer);
|
||||
} else {
|
||||
return response()->json(['message' => 'Customer not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
return response()->json([
|
||||
'message' => 'Failed to retrieve customer',
|
||||
'error' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(CustomersRequest $request, string $id)
|
||||
{
|
||||
try{
|
||||
$customer = Customer::find($id);
|
||||
if($customer){
|
||||
$customer->update($request->validated());
|
||||
return response()->json(['message' => 'Successfully updated', new CustomersResource($customer)]);
|
||||
} else {
|
||||
return response()->json(['message' => 'Customer not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e) {
|
||||
return response()->json([
|
||||
'message' => 'Failed to update customer',
|
||||
'error' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
try{
|
||||
$customer = Customer::find($id);
|
||||
if($customer){
|
||||
$customer->delete();
|
||||
return response()->json(['message' => 'Successfully deleted']);
|
||||
}else {
|
||||
return response()->json(['message' => 'Customer not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e) {
|
||||
return response()->json([
|
||||
'message' => 'Failed to delete customer',
|
||||
'error' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
public function upload(ExcelUploadRequest $request){
|
||||
try{
|
||||
if(!$request->hasFile('file')){
|
||||
return response()->json([
|
||||
'error' => 'No file provided'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$file = $request->file('file');
|
||||
Excel::import(new CustomersImport, $file);
|
||||
|
||||
return response()->json([
|
||||
'message' => 'File uploaded successfully',
|
||||
]);
|
||||
}catch(\Exception $e){
|
||||
\Log::info($e->getMessage());
|
||||
return response()->json([
|
||||
'error' => 'Failed to upload file',
|
||||
'message' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ class ImportDatasourceController extends Controller
|
||||
$search = $request->get("search");
|
||||
$query->where('status', 'like', "%".$search."%");
|
||||
}
|
||||
return ImportDatasourceResource::collection($query->paginate());
|
||||
return ImportDatasourceResource::collection($query->paginate(config('app.paginate_per_page', 50)));
|
||||
}
|
||||
|
||||
public function checkImportDatasource(){
|
||||
|
||||
34
app/Http/Controllers/Api/LackOfPotentialController.php
Normal file
34
app/Http/Controllers/Api/LackOfPotentialController.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Advertisement;
|
||||
use App\Models\Customer;
|
||||
use App\Models\SpatialPlanning;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\TourismBasedKBLI;
|
||||
|
||||
class LackOfPotentialController extends Controller
|
||||
{
|
||||
|
||||
public function count_lack_of_potential(){
|
||||
try{
|
||||
$total_reklame = Advertisement::count();
|
||||
$total_pdam = Customer::count();
|
||||
$total_tata_ruang = SpatialPlanning::count();
|
||||
$data_report_tourism = TourismBasedKBLI::all();
|
||||
|
||||
return response()->json([
|
||||
'total_reklame' => $total_reklame,
|
||||
'total_pdam' => $total_pdam,
|
||||
'total_tata_ruang' => $total_tata_ruang,
|
||||
'data_report' => $data_report_tourism,
|
||||
], 200);
|
||||
}catch(\Exception $e){
|
||||
return response()->json([
|
||||
'message' => 'Error: '.$e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,11 @@
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\MenuRequest;
|
||||
use App\Http\Resources\MenuResource;
|
||||
use App\Models\Menu;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class MenusController extends Controller
|
||||
{
|
||||
@@ -13,21 +16,27 @@ class MenusController extends Controller
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Menu::query();
|
||||
$query = Menu::query()->orderBy('id', 'desc');
|
||||
|
||||
if($request->has("search") && !empty($request->get("search"))){
|
||||
$query = $query->where("name", "like", "%".$request->get("search")."%");
|
||||
}
|
||||
|
||||
return response()->json($query->paginate());
|
||||
return response()->json($query->paginate(config('app.paginate_per_page', 50)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
public function store(MenuRequest $request)
|
||||
{
|
||||
//
|
||||
try{
|
||||
$menu = Menu::create($request->validated());
|
||||
return response()->json(['message' => 'Menu created successfully', 'data' => new MenuResource($menu)]);
|
||||
}catch(\Exception $e){
|
||||
Log::error($e);
|
||||
return response()->json(['message' => 'Error when creating menu'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,15 +44,37 @@ class MenusController extends Controller
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
try{
|
||||
$menu = Menu::find($id);
|
||||
if($menu){
|
||||
return response()->json(['message' => 'Menu found', 'data' => new MenuResource($menu)]);
|
||||
} else {
|
||||
return response()->json(['message' => 'Menu not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
Log::error($e);
|
||||
Log::error($e->getMessage());
|
||||
return response()->json(['message' => 'Error when finding menu'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
public function update(MenuRequest $request, string $id)
|
||||
{
|
||||
//
|
||||
try{
|
||||
$menu = Menu::findOrFail($id);
|
||||
if($menu){
|
||||
$menu->update($request->validated());
|
||||
return response()->json(['message' => 'Menu updated successfully', 'data' => new MenuResource($menu)]);
|
||||
} else {
|
||||
return response()->json(['message' => 'Menu not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
Log::error($e);
|
||||
return response()->json(['message' => 'Error when updating menu'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,6 +82,28 @@ class MenusController extends Controller
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
try{
|
||||
$menu = Menu::findOrFail($id);
|
||||
if($menu){
|
||||
$this->deleteChildren($menu);
|
||||
$menu->roles()->detach();
|
||||
$menu->delete();
|
||||
return response()->json(['message' => 'Menu deleted successfully']);
|
||||
} else {
|
||||
return response()->json(['message' => 'Menu not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
Log::error($e);
|
||||
return response()->json(['message' => 'Error when deleting menu'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteChildren($menu)
|
||||
{
|
||||
foreach ($menu->children as $child) {
|
||||
$this->deleteChildren($child); // Recursively delete its children
|
||||
$child->roles()->detach(); // Detach roles before deleting
|
||||
$child->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,35 @@ class PbgTaskController extends Controller
|
||||
public function __construct(GoogleSheetService $googleSheetService){
|
||||
$this->googleSheetService = $googleSheetService;
|
||||
}
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
//
|
||||
info($request);
|
||||
|
||||
$isLastUpdated = filter_var($request->query('isLastUpdated', false), FILTER_VALIDATE_BOOLEAN);
|
||||
|
||||
$query = PbgTask::query();
|
||||
|
||||
if ($isLastUpdated) {
|
||||
$query->orderBy('updated_at', 'desc');
|
||||
} else {
|
||||
$query->where('status', 20);
|
||||
}
|
||||
|
||||
// Ambil maksimal 10 data
|
||||
$pbg_task = $query->limit(10)->get();
|
||||
$totalData = $pbg_task->count();
|
||||
|
||||
// Tambahkan nomor urut
|
||||
$data = $pbg_task->map(function ($item, $index) {
|
||||
return array_merge($item->toArray(), ['no' => $index + 1]);
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'data' => $data,
|
||||
'meta' => [
|
||||
'total' => $totalData
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,8 @@ class RequestAssignmentController extends Controller
|
||||
$query = PbgTask::query()->orderBy('id', 'desc');
|
||||
if($request->has('search') && !empty($request->get("search"))){
|
||||
$query->where('name', 'LIKE', '%'.$request->get('search').'%')
|
||||
->orWhere('registration_number', 'LIKE', '%'.$request->get('search').'%');
|
||||
->orWhere('registration_number', 'LIKE', '%'.$request->get('search').'%')
|
||||
->orWhere('document_number', 'LIKE', '%'.$request->get('search').'%');
|
||||
}
|
||||
return RequestAssignmentResouce::collection($query->paginate());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\RoleRequest;
|
||||
use App\Models\Role;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -13,21 +14,26 @@ class RolesController extends Controller
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Role::query();
|
||||
$query = Role::query()->orderBy('id', 'desc');
|
||||
|
||||
if($request->has('search') && !empty($request->get('search'))){
|
||||
$query = $query->where('name', 'like', '%'. $request->get('search') . '%');
|
||||
}
|
||||
|
||||
return response()->json($query->paginate());
|
||||
return response()->json($query->paginate(config('app.paginate_per_page', 50)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
public function store(RoleRequest $request)
|
||||
{
|
||||
//
|
||||
try{
|
||||
$role = Role::create($request->validated());
|
||||
return response()->json(['message' => 'Successfully created', 'data' => $role]);
|
||||
}catch(\Exception $e){
|
||||
return response()->json(['message' => 'Error when creating role', 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,15 +41,34 @@ class RolesController extends Controller
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
try{
|
||||
$role = Role::find($id);
|
||||
if($role){
|
||||
return response()->json(['data' => $role]);
|
||||
} else {
|
||||
return response()->json(['message' => 'Role not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
return response()->json(['message' => 'Error when getting role', 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
public function update(RoleRequest $request, string $id)
|
||||
{
|
||||
//
|
||||
try{
|
||||
$role = Role::find($id);
|
||||
if($role){
|
||||
$role->update($request->validated());
|
||||
return response()->json(['message' => 'Successfully updated', 'data' => $role]);
|
||||
} else {
|
||||
return response()->json(['message' => 'Role not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
return response()->json(['message' => 'Error when updating role', 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,6 +76,16 @@ class RolesController extends Controller
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
try{
|
||||
$role = Role::find($id);
|
||||
if($role){
|
||||
$role->delete();
|
||||
return response()->json(['message' => 'Successfully deleted']);
|
||||
} else {
|
||||
return response()->json(['message' => 'Role not found'], 404);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
return response()->json(['message' => 'Error when deleting role', 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Enums\ImportDatasourceStatus;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Jobs\SyncronizeSIMBG;
|
||||
use App\Models\ImportDatasource;
|
||||
use App\Traits\GlobalApiResponse;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
@@ -23,8 +24,8 @@ class ScrapingController extends Controller
|
||||
}
|
||||
|
||||
// run service artisan command
|
||||
Artisan::call("app:execute-scraping");
|
||||
return $this->resSuccess("Success execute scraping service please wait");
|
||||
SyncronizeSIMBG::dispatch();
|
||||
return $this->resSuccess(["message" => "Success execute scraping service on background, check status for more"]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
146
app/Http/Controllers/Api/SpatialPlanningController.php
Normal file
146
app/Http/Controllers/Api/SpatialPlanningController.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\SpatialPlanning;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\SpatialPlanningRequest;
|
||||
use Illuminate\Http\Response;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\SpatialPlanningResource;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use App\Imports\SpatialPlanningImport;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class SpatialPlanningController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
info($request);
|
||||
$perPage = $request->input('per_page', 15);
|
||||
$search = $request->input('search', '');
|
||||
|
||||
$query = SpatialPlanning::query();
|
||||
if ($search) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%$search%")
|
||||
->orWhere('kbli', 'like', "%$search%")
|
||||
->orWhere('activities', 'like', "%$search%")
|
||||
->orWhere('area', 'like', "%$search%")
|
||||
->orWhere('location', 'like', "%$search%")
|
||||
->orWhere('number', 'like', "%$search%");
|
||||
});
|
||||
}
|
||||
|
||||
$spatialPlannings = $query->paginate($perPage);
|
||||
|
||||
// Menambhakan nomor urut (No)
|
||||
$start = ($spatialPlannings->currentPage()-1) * $perPage + 1;
|
||||
|
||||
// Tambahkan nomor urut ke dalam data
|
||||
$data = $spatialPlannings->map(function ($item, $index) use ($start) {
|
||||
return array_merge($item->toArray(), ['no' => $start + $index]);
|
||||
});
|
||||
|
||||
info($data);
|
||||
|
||||
return response()->json([
|
||||
'data' => $data,
|
||||
'meta' => [
|
||||
'total' => $spatialPlannings->total(),
|
||||
'per_page' => $spatialPlannings->perPage(),
|
||||
'current_page' => $spatialPlannings->currentPage(),
|
||||
'last_page'=>$spatialPlannings->lastPage(),
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(SpatialPlanningRequest $request): SpatialPlanning
|
||||
{
|
||||
$data = $request->validated();
|
||||
return SpatialPlanning::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* import spatial planning from excel
|
||||
*/
|
||||
public function importFromFile(Request $request)
|
||||
{
|
||||
info($request);
|
||||
//validasi file
|
||||
$validator = Validator::make($request->all(), [
|
||||
'file' => 'required|mimes:xlsx, xls|max:10240'
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json([
|
||||
'message'=>'File vaildation failed.',
|
||||
"errors"=>$validator->errors()
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
$file = $request->file('file');
|
||||
Excel::import(new SpatialPlanningImport, $file);
|
||||
return response()->json([
|
||||
'message'=>'File uploaded and imported successfully!'
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'message'=>'Error during file import.',
|
||||
'error'=>$e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(SpatialPlanning $spatialPlanning): SpatialPlanning
|
||||
{
|
||||
return $spatialPlanning;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(SpatialPlanningRequest $request, SpatialPlanning $spatialPlanning): SpatialPlanning
|
||||
{
|
||||
info($request);
|
||||
$data = $request->validated();
|
||||
info($data);
|
||||
|
||||
$spatialPlanning->update($data);
|
||||
|
||||
return $spatialPlanning;
|
||||
}
|
||||
|
||||
public function destroy(SpatialPlanning $spatialPlanning): Response
|
||||
{
|
||||
$spatialPlanning->delete();
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
public function downloadExcelSpatialPlanning()
|
||||
{
|
||||
$filePath = public_path('templates/template_spatial_planning.xlsx');
|
||||
info(sprintf("File Path: %s | Exists: %s", $filePath, file_exists($filePath) ? 'Yes' : 'No'));
|
||||
|
||||
// Cek apakah file ada
|
||||
if (!file_exists($filePath)) {
|
||||
return response()-> json(['message' => 'File tidak ditemukan!'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Return file to download
|
||||
return response()->download($filePath);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,13 @@ class TourismController extends Controller
|
||||
$search = $request->input('search', '');
|
||||
|
||||
$query = Tourism::query();
|
||||
if ($search) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('business_name', 'like', "%$search%")
|
||||
->orWhere('project_name', 'like', "%$search%")
|
||||
->orWhere('business_address', 'like', "%$search%");
|
||||
});
|
||||
}
|
||||
$tourisms = $query->paginate($perPage);
|
||||
|
||||
$tourisms->getCollection()->transform(function ($tourisms) {
|
||||
@@ -36,8 +43,14 @@ class TourismController extends Controller
|
||||
return $tourisms;
|
||||
});
|
||||
|
||||
$start = ($tourisms->currentPage()-1) * $perPage + 1;
|
||||
|
||||
$data = $tourisms->map(function ($item, $index) use ($start) {
|
||||
return array_merge($item->toArray(), ['no' => $start + $index]);
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'data' => TourismResource::collection($tourisms),
|
||||
'data' => $data,
|
||||
'meta' => [
|
||||
'total' => $tourisms->total(),
|
||||
'per_page' => $tourisms->perPage(),
|
||||
@@ -93,6 +106,18 @@ class TourismController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
public function getAllLocation()
|
||||
{
|
||||
$locations = Tourism::whereNotNull('longitude')
|
||||
->whereNotNull('latitude')
|
||||
->select('project_name', 'longitude', 'latitude')
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'data' => $locations
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
@@ -127,4 +152,18 @@ class TourismController extends Controller
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
public function downloadExcelTourism()
|
||||
{
|
||||
$filePath = public_path('templates/template_pariwisata.xlsx');
|
||||
info(sprintf("File Path: %s | Exists: %s", $filePath, file_exists($filePath) ? 'Yes' : 'No'));
|
||||
|
||||
// Cek apakah file ada
|
||||
if (!file_exists($filePath)) {
|
||||
return response()-> json(['message' => 'File tidak ditemukan!'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Return file to download
|
||||
return response()->download($filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,17 @@ class UmkmController extends Controller
|
||||
|
||||
$query = Umkm::query();
|
||||
|
||||
if ($search) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('business_name', 'like', "%$search%")
|
||||
->orWhere('business_address', 'like', "%$search%")
|
||||
->orWhere('business_desc', 'like', "%$search%")
|
||||
->orWhere('business_id_number', 'like', "%$search%")
|
||||
->orWhere('owner_id', 'like', "%$search%")
|
||||
->orWhere('owner_name', 'like', "%$search%");
|
||||
});
|
||||
}
|
||||
|
||||
$umkm = $query->paginate($perPage);
|
||||
|
||||
$umkm->getCollection()->transform(function ($umkm) {
|
||||
@@ -47,8 +58,14 @@ class UmkmController extends Controller
|
||||
return $umkm;
|
||||
});
|
||||
|
||||
$start = ($umkm->currentPage()-1) * $perPage + 1;
|
||||
|
||||
$data = $umkm->map(function ($item, $index) use ($start) {
|
||||
return array_merge($item->toArray(), ['no' => $start + $index]);
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'data' => UmkmResource::collection($umkm),
|
||||
'data' => $data,
|
||||
'meta' => [
|
||||
'total' => $umkm->total(),
|
||||
'per_page' => $umkm->perPage(),
|
||||
@@ -176,7 +193,7 @@ class UmkmController extends Controller
|
||||
|
||||
public function downloadExcelUmkm()
|
||||
{
|
||||
$filePath = storage_path('app/public/templates/template_umkm.xlsx');
|
||||
$filePath = public_path('templates/template_umkm.xlsx');
|
||||
|
||||
// Cek apakah file ada
|
||||
if (!file_exists($filePath)) {
|
||||
|
||||
@@ -31,7 +31,7 @@ class UsersController extends Controller
|
||||
if($request->has('search') && !empty($request->get("search"))){
|
||||
$query->where('name', 'LIKE', '%'.$request->get('search').'%');
|
||||
}
|
||||
return UserResource::collection($query->paginate());
|
||||
return UserResource::collection($query->paginate(config('app.paginate_per_page', 50)));
|
||||
}
|
||||
public function logout(Request $request){
|
||||
$request->user()->tokens()->delete();
|
||||
|
||||
48
app/Http/Controllers/BigdataResumesController.php
Normal file
48
app/Http/Controllers/BigdataResumesController.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BigdataResumesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('bigdata-resumes.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
17
app/Http/Controllers/Chatbot/ChatbotController.php
Normal file
17
app/Http/Controllers/Chatbot/ChatbotController.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Chatbot;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ChatbotController extends Controller
|
||||
{
|
||||
/**
|
||||
* Displya a listing of the resource
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('chatbot.index');
|
||||
}
|
||||
}
|
||||
26
app/Http/Controllers/CustomersController.php
Normal file
26
app/Http/Controllers/CustomersController.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Customer;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CustomersController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('customers.index');
|
||||
}
|
||||
public function create()
|
||||
{
|
||||
return view('customers.create');
|
||||
}
|
||||
public function edit(string $id)
|
||||
{
|
||||
$data = Customer::findOrFail($id);
|
||||
return view('customers.edit', compact('data'));
|
||||
}
|
||||
public function upload(){
|
||||
return view('customers.upload');
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,8 @@ class BigDataController extends Controller
|
||||
return view('dashboards.bigdata', compact('latest_created'));
|
||||
}
|
||||
|
||||
public function pbg(){
|
||||
return view('index');
|
||||
public function pbg()
|
||||
{
|
||||
return view('dashboards.pbg');
|
||||
}
|
||||
}
|
||||
|
||||
125
app/Http/Controllers/Data/SpatialPlanningController.php
Normal file
125
app/Http/Controllers/Data/SpatialPlanningController.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Data;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\SpatialPlanning;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SpatialPlanningController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('data.spatialPlannings.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* show the form for creating a new resource.
|
||||
*/
|
||||
public function bulkCreate()
|
||||
{
|
||||
return view('data.spatialPlannings.form-upload');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$title = 'Rencana Tata Ruang';
|
||||
$subtitle = "Create Data";
|
||||
|
||||
// Mengambil data untuk dropdown
|
||||
$dropdownOptions = [];
|
||||
|
||||
$fields = $this->getFields();
|
||||
$fieldTypes = $this->getFieldTypes();
|
||||
|
||||
$apiUrl = url('/api/spatial-plannings');
|
||||
return view('data.spatialPlannings.form', compact('title', 'subtitle', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
$title = 'Rencana Tata Ruang';
|
||||
$subtitle = 'Update Data';
|
||||
|
||||
$modelInstance = SpatialPlanning::find($id);
|
||||
// Pastikan model ditemukan
|
||||
if (!$modelInstance) {
|
||||
return redirect()->route('spatialPlanning.index') ->with('error', 'Rencana tata ruang tidak ditemukan');
|
||||
}
|
||||
|
||||
$dropdownOptions = [];
|
||||
|
||||
$fields = $this->getFields();
|
||||
$fieldTypes = $this->getFieldTypes();
|
||||
|
||||
$apiUrl = url('/api/spatial-plannings');
|
||||
return view('data.spatialPlannings.form', compact('title', 'subtitle', 'modelInstance', 'fields', 'fieldTypes', 'apiUrl', 'dropdownOptions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
private function getFields()
|
||||
{
|
||||
return [
|
||||
"name"=> "Nama",
|
||||
"kbli"=> "KBLI",
|
||||
"activities"=> "Kegiatan",
|
||||
"area"=> "Luas (m2)",
|
||||
"location"=> "Lokasi",
|
||||
"number"=> "Nomor",
|
||||
"date"=> "Tanggal",
|
||||
];
|
||||
}
|
||||
|
||||
private function getFieldTypes()
|
||||
{
|
||||
return [
|
||||
"name"=> "text",
|
||||
"kbli"=> "text",
|
||||
"activities"=> "text",
|
||||
"area"=> "text",
|
||||
"location"=> "text",
|
||||
"number"=> "text",
|
||||
"date"=> "date",
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class TourismController extends Controller
|
||||
public function edit($id)
|
||||
{
|
||||
$title = 'Pariwisata';
|
||||
$subtitle = 'Create Data';
|
||||
$subtitle = 'Update Data';
|
||||
|
||||
$modelInstance = Tourism::find($id);
|
||||
// Pastikan model ditemukan
|
||||
|
||||
12
app/Http/Controllers/GoogleApisController.php
Normal file
12
app/Http/Controllers/GoogleApisController.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GoogleApisController extends Controller
|
||||
{
|
||||
public function index(){
|
||||
return view('maps.google-api');
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,12 @@ class SyncronizeController extends Controller
|
||||
}
|
||||
|
||||
public function syncPbgTask(){
|
||||
$res = $this->service_simbg->syncTaskList();
|
||||
$res = $this->service_simbg->syncTaskPBG();
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function syncronizeTask(Request $request){
|
||||
$res = $this->service_simbg->syncTaskList();
|
||||
$res = $this->service_simbg->syncTaskPBG();
|
||||
return redirect()->back()->with('success', 'Processing completed successfully');
|
||||
}
|
||||
|
||||
|
||||
@@ -40,4 +40,40 @@ class AdvertisementRequest extends FormRequest
|
||||
'contact' => 'required|string',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* pesan error validasi
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'no.required' => 'Nomor harus diisi.',
|
||||
'business_name.required' => 'Nama usaha harus diisi.',
|
||||
'business_name.string' => 'Nama usaha harus berupa teks.',
|
||||
'npwpd.required' => 'NPWPD harus diisi.',
|
||||
'npwpd.string' => 'NPWPD harus berupa teks.',
|
||||
'advertisement_type.required' => 'Jenis reklame harus diisi.',
|
||||
'advertisement_type.string' => 'Jenis reklame harus berupa teks.',
|
||||
'advertisement_content.required' => 'Isi reklame harus diisi.',
|
||||
'advertisement_content.string' => 'Isi reklame harus berupa teks.',
|
||||
'business_address.required' => 'Alamat usaha harus diisi.',
|
||||
'business_address.string' => 'Alamat usaha harus berupa teks.',
|
||||
'advertisement_location.required' => 'Lokasi reklame harus diisi.',
|
||||
'advertisement_location.string' => 'Lokasi reklame harus berupa teks.',
|
||||
'village_name.required' => 'Nama desa harus diisi.',
|
||||
'district_name.required' => 'Nama kecamatan harus diisi.',
|
||||
'length.required' => 'Panjang harus diisi.',
|
||||
'width.required' => 'Lebar harus diisi.',
|
||||
'viewing_angle.required' => 'Sudut pandang harus diisi.',
|
||||
'viewing_angle.string' => 'Sudut pandang harus berupa teks.',
|
||||
'face.required' => 'Jumlah sisi harus diisi.',
|
||||
'face.string' => 'Jumlah sisi harus berupa teks.',
|
||||
'area.required' => 'Luas harus diisi.',
|
||||
'area.string' => 'Luas harus berupa teks.',
|
||||
'angle.required' => 'Sudut harus diisi.',
|
||||
'angle.string' => 'Sudut harus berupa teks.',
|
||||
'contact.required' => 'Kontak harus diisi.',
|
||||
'contact.string' => 'Kontak harus berupa teks.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
33
app/Http/Requests/CustomersRequest.php
Normal file
33
app/Http/Requests/CustomersRequest.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class CustomersRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'nomor_pelanggan' => ['required', 'string'],
|
||||
'kota_pelayanan' => ['required', 'string'],
|
||||
'nama' => ['required', 'string'],
|
||||
'alamat' => ['required', 'string'],
|
||||
'latitude' => ['required', 'numeric', 'between:-90,90'],
|
||||
'longitude' => ['required', 'numeric', 'between:-180,180'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class DataSettingRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$id = $this->route('data_setting');
|
||||
$id = $this->route('data_setting_id');
|
||||
return [
|
||||
"key" => "required|unique:data_settings,key," . $id,
|
||||
"value" => "required",
|
||||
|
||||
28
app/Http/Requests/ExcelUploadRequest.php
Normal file
28
app/Http/Requests/ExcelUploadRequest.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ExcelUploadRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
"file" => "required|file|mimes:xlsx,xls|max:102400"
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class MenuRequest extends FormRequest
|
||||
{
|
||||
@@ -21,12 +22,14 @@ class MenuRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$menuId = $this->route('menu_id'); // Get the menu ID if updating
|
||||
|
||||
return [
|
||||
'name' => ['required','string','max:255'],
|
||||
'url' => ['nullable','string','max:255'],
|
||||
'icon' => ['nullable','string','max:255'],
|
||||
'parent_id' => ['nullable','exists:menus,id'],
|
||||
'sort_order' => ['required','integer'],
|
||||
'name' => ['required', 'string', 'max:255', Rule::unique('menus', 'name')->ignore($menuId)],
|
||||
'url' => ['nullable', 'string', 'max:255'],
|
||||
'icon' => ['nullable', 'string', 'max:255'],
|
||||
'parent_id' => ['nullable', 'exists:menus,id'],
|
||||
'sort_order' => ['required', 'integer'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class RoleRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$roleId = $this->route('role');
|
||||
$roleId = $this->route('role_id');
|
||||
return [
|
||||
'name' => 'required|string|max:255|unique:roles,name,' . ($roleId ?? 'NULL') . ',id',
|
||||
'description' => 'nullable|string',
|
||||
|
||||
52
app/Http/Requests/SpatialPlanningRequest.php
Normal file
52
app/Http/Requests/SpatialPlanningRequest.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class SpatialPlanningRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'string',
|
||||
'kbli' => 'string',
|
||||
'activities' => 'string',
|
||||
'area' => 'string',
|
||||
'location' => 'string',
|
||||
'number' => 'string',
|
||||
'date' => 'date_format:Y-m-d',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation messages for the defined validation rules.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'name.string' => 'Kolom Nama harus berupa teks.',
|
||||
'kbli.string' => 'Kolom KBLI harus berupa teks.',
|
||||
'activities.string' => 'Kolom Kegiatan harus berupa teks.',
|
||||
'area.string' => 'Kolom Area harus berupa teks.',
|
||||
'location.string' => 'Kolom Lokasi harus berupa teks.',
|
||||
'number.string' => 'Kolom Nomor harus berupa teks.',
|
||||
'date.date_format' => 'Format tanggal tidak valid, gunakan format Y-m-d H:i:s.',
|
||||
];
|
||||
}
|
||||
}
|
||||
35
app/Http/Requests/SpatialPlanningsRequest.php
Normal file
35
app/Http/Requests/SpatialPlanningsRequest.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class SpatialPlanningsRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => ['required','string','max:255'],
|
||||
'kbli' => ['required','string','max:255'],
|
||||
'kegiatan' => ['required','string'],
|
||||
'luas' => ['required','numeric','regex:/^\d{1,16}(\.\d{1,2})?$/'],
|
||||
'lokasi' => ['required','string'],
|
||||
'nomor' => ['required','string','max:255',Rule::unique('spatial_plannings')->ignore($this->id)],
|
||||
'sp_date' => ['required','date'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -49,4 +49,85 @@ class TourismRequest extends FormRequest
|
||||
'tki' => 'required|string',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation messages for the defined validation rules.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'project_id.required' => 'ID proyek harus diisi.',
|
||||
'project_id.string' => 'ID proyek harus berupa teks.',
|
||||
|
||||
'project_type_id.required' => 'ID tipe proyek harus diisi.',
|
||||
'project_type_id.string' => 'ID tipe proyek harus berupa teks.',
|
||||
|
||||
'nib.required' => 'NIB harus diisi.',
|
||||
'nib.string' => 'NIB harus berupa teks.',
|
||||
|
||||
'business_name.required' => 'Nama usaha harus diisi.',
|
||||
'business_name.string' => 'Nama usaha harus berupa teks.',
|
||||
|
||||
'oss_publication_date.required' => 'Tanggal publikasi OSS harus diisi.',
|
||||
|
||||
'investment_status_description.required' => 'Deskripsi status investasi harus diisi.',
|
||||
'investment_status_description.string' => 'Deskripsi status investasi harus berupa teks.',
|
||||
|
||||
'business_form.required' => 'Bentuk usaha harus diisi.',
|
||||
'business_form.string' => 'Bentuk usaha harus berupa teks.',
|
||||
|
||||
'project_risk.required' => 'Risiko proyek harus diisi.',
|
||||
'project_risk.string' => 'Risiko proyek harus berupa teks.',
|
||||
|
||||
'project_name.required' => 'Nama proyek harus diisi.',
|
||||
'project_name.string' => 'Nama proyek harus berupa teks.',
|
||||
|
||||
'business_scale.required' => 'Skala usaha harus diisi.',
|
||||
'business_scale.string' => 'Skala usaha harus berupa teks.',
|
||||
|
||||
'business_address.required' => 'Alamat usaha harus diisi.',
|
||||
'business_address.string' => 'Alamat usaha harus berupa teks.',
|
||||
|
||||
'district_name.required' => 'Nama kecamatan harus diisi.',
|
||||
|
||||
'village_name.required' => 'Nama desa harus diisi.',
|
||||
|
||||
'longitude.required' => 'Garis bujur harus diisi.',
|
||||
'longitude.string' => 'Garis bujur harus berupa teks.',
|
||||
|
||||
'latitude.required' => 'Garis lintang harus diisi.',
|
||||
'latitude.string' => 'Garis lintang harus berupa teks.',
|
||||
|
||||
'project_submission_date.required' => 'Tanggal pengajuan proyek harus diisi.',
|
||||
|
||||
'kbli.required' => 'Kode KBLI harus diisi.',
|
||||
'kbli.string' => 'Kode KBLI harus berupa teks.',
|
||||
|
||||
'kbli_title.required' => 'Judul KBLI harus diisi.',
|
||||
'kbli_title.string' => 'Judul KBLI harus berupa teks.',
|
||||
|
||||
'supervisory_sector.required' => 'Sektor pengawasan harus diisi.',
|
||||
'supervisory_sector.string' => 'Sektor pengawasan harus berupa teks.',
|
||||
|
||||
'user_name.required' => 'Nama pengguna harus diisi.',
|
||||
'user_name.string' => 'Nama pengguna harus berupa teks.',
|
||||
|
||||
'email.required' => 'Email harus diisi.',
|
||||
'email.string' => 'Email harus berupa teks.',
|
||||
|
||||
'contact.required' => 'Kontak harus diisi.',
|
||||
'contact.string' => 'Kontak harus berupa teks.',
|
||||
|
||||
'land_area_in_m2.required' => 'Luas lahan dalam m² harus diisi.',
|
||||
'land_area_in_m2.string' => 'Luas lahan dalam m² harus berupa teks.',
|
||||
|
||||
'investment_amount.required' => 'Jumlah investasi harus diisi.',
|
||||
'investment_amount.string' => 'Jumlah investasi harus berupa teks.',
|
||||
|
||||
'tki.required' => 'Jumlah tenaga kerja Indonesia harus diisi.',
|
||||
'tki.string' => 'Jumlah tenaga kerja Indonesia harus berupa teks.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
51
app/Http/Resources/BigdataResumeResource.php
Normal file
51
app/Http/Resources/BigdataResumeResource.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BigdataResumeResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'import_datasource_id' => $this->import_datasource_id,
|
||||
'potention_count' => (int) $this->potention_count,
|
||||
'potention_sum' => number_format((float) $this->potention_sum, 2, ',', '.'),
|
||||
|
||||
'non_verified_count' => (int) $this->non_verified_count,
|
||||
'non_verified_sum' => number_format((float) $this->non_verified_sum, 2, ',', '.'),
|
||||
|
||||
'verified_count' => (int) $this->verified_count,
|
||||
'verified_sum' => number_format((float) $this->verified_sum, 2, ',', '.'),
|
||||
|
||||
'business_count' => (int) $this->business_count,
|
||||
'business_sum' => number_format((float) $this->business_sum, 2, ',', '.'),
|
||||
|
||||
'non_business_count' => (int) $this->non_business_count,
|
||||
'non_business_sum' => number_format((float) $this->non_business_sum, 2, ',', '.'),
|
||||
|
||||
'spatial_count' => (int) $this->spatial_count,
|
||||
'spatial_sum' => number_format((float) $this->spatial_sum, 2, ',', '.'),
|
||||
|
||||
'issuance_realization_pbg_count' => (int) $this->issuance_realization_pbg_count,
|
||||
'issuance_realization_pbg_sum' => number_format((float) $this->issuance_realization_pbg_sum, 2, ',', '.'),
|
||||
|
||||
'waiting_click_dpmptsp_count' => (int) $this->waiting_click_dpmptsp_count,
|
||||
'waiting_click_dpmptsp_sum' => number_format((float) $this->waiting_click_dpmptsp_sum, 2, ',', '.'),
|
||||
|
||||
'process_in_technical_office_count' => (int) $this->process_in_technical_office_count,
|
||||
'process_in_technical_office_sum' => number_format((float) $this->process_in_technical_office_sum, 2, ',', '.'),
|
||||
|
||||
'year' => $this->year,
|
||||
'created_at' => $this->created_at->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
19
app/Http/Resources/CustomersResource.php
Normal file
19
app/Http/Resources/CustomersResource.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class CustomersResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
19
app/Http/Resources/MenuResource.php
Normal file
19
app/Http/Resources/MenuResource.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class MenuResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
19
app/Http/Resources/SpatialPlanningResource.php
Normal file
19
app/Http/Resources/SpatialPlanningResource.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class SpatialPlanningResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
19
app/Http/Resources/SpatialPlanningsResource.php
Normal file
19
app/Http/Resources/SpatialPlanningsResource.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class SpatialPlanningsResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return parent::toArray($request);
|
||||
}
|
||||
}
|
||||
@@ -3,37 +3,105 @@
|
||||
namespace App\Imports;
|
||||
|
||||
use App\Models\BusinessOrIndustry;
|
||||
use Maatwebsite\Excel\Concerns\ToModel;
|
||||
use Maatwebsite\Excel\Concerns\ToCollection;
|
||||
use Illuminate\Support\Collection;
|
||||
use Maatwebsite\Excel\Concerns\ToCollection;
|
||||
use Maatwebsite\Excel\Concerns\WithChunkReading;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
||||
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Maatwebsite\Excel\Concerns\WithBatchInserts;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BusinessIndustriesImport implements ToCollection
|
||||
class BusinessIndustriesImport implements ToCollection, WithMultipleSheets, WithChunkReading, WithBatchInserts, ShouldQueue, WithHeadingRow
|
||||
{
|
||||
/**
|
||||
* @param array $row
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Model|null
|
||||
*/
|
||||
public function collection(Collection $rows)
|
||||
* @param Collection $collection
|
||||
*/
|
||||
public function collection(Collection $collection)
|
||||
{
|
||||
foreach ($rows->skip(1) as $row){
|
||||
$clean_nop = preg_replace('/[^A-Za-z0-9]/', '', $row[2]);
|
||||
if (!BusinessOrIndustry::where('nop', $clean_nop)->exists()) {
|
||||
BusinessOrIndustry::create([
|
||||
'nama_kecamatan' => $row[0],
|
||||
'nama_kelurahan' => $row[1],
|
||||
'nop' => $clean_nop, // Store cleaned 'nop'
|
||||
'nama_wajib_pajak' => $row[3],
|
||||
'alamat_wajib_pajak' => $row[4],
|
||||
'alamat_objek_pajak' => $row[5],
|
||||
'luas_bumi' => $row[6],
|
||||
'luas_bangunan' => $row[7],
|
||||
'njop_bumi' => $row[8],
|
||||
'njop_bangunan' => $row[9],
|
||||
'ketetapan' => $row[10],
|
||||
'tahun_pajak' => $row[11],
|
||||
try{
|
||||
$batchData = [];
|
||||
$batchSize = 1000;
|
||||
|
||||
foreach ($collection as $row){
|
||||
if(!isset($row['nop']) || empty($row['nop'])){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$clean_nop = preg_replace('/[^A-Za-z0-9]/', '', $row['nop']);
|
||||
|
||||
$batchData[] = [
|
||||
'nama_kecamatan' => $row['nama_kecamatan'],
|
||||
'nama_kelurahan' => $row['nama_kelurahan'],
|
||||
'nop' => $clean_nop,
|
||||
'nama_wajib_pajak' => $row['nama_wajib_pajak'],
|
||||
'alamat_wajib_pajak' => $row['alamat_wajib_pajak'],
|
||||
'alamat_objek_pajak' => $row['alamat_objek_pajak'],
|
||||
'luas_bumi' => $row['luas_bumi'],
|
||||
'luas_bangunan' => $row['luas_bangunan'],
|
||||
'njop_bumi' => $row['njop_bumi'],
|
||||
'njop_bangunan' => $row['njop_bangunan'],
|
||||
'ketetapan' => $row['ketetapan'],
|
||||
'tahun_pajak' => $row['tahun_pajak'],
|
||||
];
|
||||
|
||||
if(count($batchData) >= $batchSize){
|
||||
BusinessOrIndustry::upsert($batchData, ['nop'], [
|
||||
'nama_kecamatan',
|
||||
'nama_kelurahan',
|
||||
'nama_wajib_pajak',
|
||||
'alamat_wajib_pajak',
|
||||
'alamat_objek_pajak',
|
||||
'luas_bumi',
|
||||
'luas_bangunan',
|
||||
'njop_bumi',
|
||||
'njop_bangunan',
|
||||
'ketetapan',
|
||||
'tahun_pajak',
|
||||
]);
|
||||
$batchData = [];
|
||||
}
|
||||
}
|
||||
if(!empty($batchData)){
|
||||
BusinessOrIndustry::upsert($batchData, ['nop'], [
|
||||
'nama_kecamatan',
|
||||
'nama_kelurahan',
|
||||
'nama_wajib_pajak',
|
||||
'alamat_wajib_pajak',
|
||||
'alamat_objek_pajak',
|
||||
'luas_bumi',
|
||||
'luas_bangunan',
|
||||
'njop_bumi',
|
||||
'njop_bangunan',
|
||||
'ketetapan',
|
||||
'tahun_pajak',
|
||||
]);
|
||||
}
|
||||
}catch(\Exception $exception){
|
||||
Log::error('Error while importing Business Industries data:', ['error' => $exception->getMessage()]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public function sheets(): array {
|
||||
return [
|
||||
0 => $this
|
||||
];
|
||||
}
|
||||
|
||||
public function headingRow(): int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function chunkSize(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
|
||||
public function batchSize(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
92
app/Imports/CustomersImport.php
Normal file
92
app/Imports/CustomersImport.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Imports;
|
||||
|
||||
use App\Models\Customer;
|
||||
use Illuminate\Support\Collection;
|
||||
use Maatwebsite\Excel\Concerns\ToCollection;
|
||||
use Maatwebsite\Excel\Concerns\WithLimit;
|
||||
use Maatwebsite\Excel\Concerns\WithChunkReading;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
||||
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Maatwebsite\Excel\Concerns\WithBatchInserts;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CustomersImport implements ToCollection, WithMultipleSheets, WithChunkReading, WithBatchInserts, ShouldQueue, WithHeadingRow
|
||||
{
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*/
|
||||
public function collection(Collection $collection)
|
||||
{
|
||||
$batchData = [];
|
||||
$batchSize = 1000;
|
||||
|
||||
foreach ($collection as $row) {
|
||||
if (!isset($row['nomor_pelanggan']) || empty($row['nomor_pelanggan'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$latitude = '0';
|
||||
$longitude = '0';
|
||||
|
||||
if (isset($row['latkor']) && !empty(trim($row['latkor']))) {
|
||||
$latitude = str_replace(',', '.', trim($row['latkor']));
|
||||
if (is_numeric($latitude)) {
|
||||
$latitude = bcadd($latitude, '0', 18);
|
||||
} else {
|
||||
$latitude = '0';
|
||||
}
|
||||
} else {
|
||||
$latitude = '0';
|
||||
}
|
||||
|
||||
if (isset($row['lonkor']) && !empty(trim($row['lonkor']))) {
|
||||
$longitude = str_replace(',', '.', trim($row['lonkor']));
|
||||
if (is_numeric($longitude)) {
|
||||
$longitude = bcadd($longitude, '0', 18);
|
||||
} else {
|
||||
$longitude = '0';
|
||||
}
|
||||
} else {
|
||||
$longitude = '0';
|
||||
}
|
||||
|
||||
$batchData[] = [
|
||||
'nomor_pelanggan' => $row['nomor_pelanggan'] ?? '',
|
||||
'kota_pelayanan' => $row['kota_pelayanan'] ?? '',
|
||||
'nama' => $row['nama'] ?? '',
|
||||
'alamat' => $row['alamat'] ?? '',
|
||||
'latitude' => $latitude,
|
||||
'longitude' => $longitude,
|
||||
];
|
||||
|
||||
if (count($batchData) >= $batchSize) {
|
||||
Customer::upsert($batchData, ['nomor_pelanggan'], ['kota_pelayanan', 'nama', 'alamat', 'latitude', 'longitude']);
|
||||
$batchData = [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($batchData)) {
|
||||
Customer::upsert($batchData, ['nomor_pelanggan'], ['kota_pelayanan', 'nama', 'alamat', 'latitude', 'longitude']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function sheets(): array {
|
||||
return [
|
||||
0 => $this
|
||||
];
|
||||
}
|
||||
|
||||
public function chunkSize(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
|
||||
public function batchSize(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
63
app/Imports/SpatialPlanningImport.php
Normal file
63
app/Imports/SpatialPlanningImport.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Imports;
|
||||
|
||||
use App\Models\SpatialPlanning;
|
||||
use Illuminate\Support\Collection;
|
||||
use Maatwebsite\Excel\Concerns\ToCollection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use DateTime;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class SpatialPlanningImport implements ToCollection
|
||||
{
|
||||
protected static $processed = false;
|
||||
|
||||
/**
|
||||
* Process each row in the file
|
||||
*/
|
||||
public function collection(Collection $rows)
|
||||
{
|
||||
if (self::$processed) {
|
||||
return;
|
||||
}
|
||||
self::$processed = true;
|
||||
|
||||
if ($rows->isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//cari header secara otomatis
|
||||
$header = $rows->first();
|
||||
$headerIndex = collect($header)->search(fn($value) => !empty($value));
|
||||
|
||||
// Pastikan header ditemukan
|
||||
if ($headerIndex === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($rows->skip(1) as $row) {
|
||||
$dateValue = trim($row[7]);
|
||||
info($dateValue);
|
||||
$parsedDate = Carbon::createFromFormat('Y-m-d', $dateValue)->format('Y-m-d');
|
||||
info($parsedDate);
|
||||
|
||||
$dataToInsert[] = [
|
||||
'name'=>$row[1],
|
||||
'kbli'=>$row[2],
|
||||
'activities'=>$row[3],
|
||||
'area'=>$row[4],
|
||||
'location'=>$row[5],
|
||||
'number'=>$row[6],
|
||||
'date'=>$parsedDate,
|
||||
];
|
||||
}
|
||||
|
||||
if(!empty($dataToInsert)) {
|
||||
SpatialPlanning::insert($dataToInsert);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,13 +65,6 @@ class TourismImport implements ToCollection
|
||||
// ambill village code yang village_name sama dengan $villageName
|
||||
$villageCode = $listTrueVillage[$villageName]['village_code'] ?? '000000';
|
||||
|
||||
|
||||
// if (empty($row[16])) {
|
||||
// info("Data kosong");
|
||||
// } else {
|
||||
// info("Baris ke- | Nilai: " . $row[16]);
|
||||
// }
|
||||
|
||||
$excelSerialDate = $row[16];
|
||||
if (is_numeric($excelSerialDate)) {
|
||||
$projectSubmissionDate = Carbon::createFromFormat('Y-m-d', '1899-12-30')
|
||||
@@ -82,8 +75,6 @@ class TourismImport implements ToCollection
|
||||
->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
info("Tanggal dikonversi: " . $projectSubmissionDate);
|
||||
|
||||
$dataToInsert[] = [
|
||||
'project_id' => $row[1],
|
||||
'project_type_id' => $row[2],
|
||||
|
||||
27
app/Jobs/SyncronizeSIMBG.php
Normal file
27
app/Jobs/SyncronizeSIMBG.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Services\GoogleSheetService;
|
||||
use App\Services\ServiceSIMBG;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class SyncronizeSIMBG implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$serviceSIMBG = app(ServiceSIMBG::class);
|
||||
$serviceSIMBG->syncTaskPBG();
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,15 @@ class BigdataResume extends Model
|
||||
'business_sum',
|
||||
'non_business_count',
|
||||
'non_business_sum',
|
||||
'spatial_count',
|
||||
'spatial_sum',
|
||||
'year',
|
||||
'waiting_click_dpmptsp_count',
|
||||
'waiting_click_dpmptsp_sum',
|
||||
'issuance_realization_pbg_count',
|
||||
'issuance_realization_pbg_sum',
|
||||
'process_in_technical_office_count',
|
||||
'process_in_technical_office_sum',
|
||||
];
|
||||
|
||||
public function importDatasource()
|
||||
@@ -28,88 +37,84 @@ class BigdataResume extends Model
|
||||
return $this->belongsTo(ImportDatasource::class, 'import_datasource_id');
|
||||
}
|
||||
|
||||
public static function generateResumeData($import_datasource_id){
|
||||
$query_verified = once( function () {
|
||||
return DB::table('pbg_task AS pt')
|
||||
->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi')
|
||||
->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid')
|
||||
->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) = ?', [strtolower(trim('Selesai Verifikasi'))])
|
||||
->selectRaw('COUNT(pt.id) AS total_data,
|
||||
SUM(ptr.nilai_retribusi_bangunan) AS total_retribution')
|
||||
->first();
|
||||
});
|
||||
|
||||
$verified_count = $query_verified->total_data ?? 0;
|
||||
$verified_total = $query_verified->total_retribution ?? 0;
|
||||
|
||||
$query_business = once(function () {
|
||||
return DB::table('pbg_task AS pt')
|
||||
->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi')
|
||||
->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid')
|
||||
->where(function ($query) {
|
||||
$query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))])
|
||||
->orWhereNull('ptgs.status_verifikasi');
|
||||
})
|
||||
->where(function ($query) {
|
||||
$query->whereRaw('LOWER(TRIM(pt.function_type)) = ?', [strtolower(trim('Sebagai Tempat Usaha'))]);
|
||||
})
|
||||
->selectRaw('COUNT(pt.id) AS total_data,
|
||||
SUM(ptr.nilai_retribusi_bangunan) AS total_retribution')
|
||||
->first();
|
||||
});
|
||||
|
||||
$business_count = $query_business->total_data ?? 0;
|
||||
$business_total = $query_business->total_retribution ?? 0;
|
||||
|
||||
$query_non_business = once( function () {
|
||||
return DB::table('pbg_task AS pt')
|
||||
->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi')
|
||||
->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid') // Join ke pbg_task_retributions
|
||||
->where(function ($query) {
|
||||
$query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))])
|
||||
->orWhereNull('ptgs.status_verifikasi'); // Include NULL values
|
||||
public static function generateResumeData($import_datasource_id, $year, $data_setting){
|
||||
$stats = PbgTask::with(['googleSheet', 'pbg_task_retributions'])
|
||||
->leftJoin('pbg_task_retributions as ptr', 'pbg_task.uuid', '=', 'ptr.pbg_task_uid')
|
||||
->leftJoin('pbg_task_google_sheet as ptgs', 'pbg_task.registration_number', '=', 'ptgs.no_registrasi')
|
||||
->when($year !== 'all', function ($query) use ($year) {
|
||||
$query->whereYear('pbg_task.task_created_at', (int) $year);
|
||||
})
|
||||
->where(function ($query) {
|
||||
$query->whereRaw('LOWER(TRIM(pt.function_type)) != ?', [strtolower(trim('Sebagai Tempat Usaha'))])
|
||||
->orWhereNull('pt.function_type'); // Include NULL values
|
||||
})
|
||||
->selectRaw('COUNT(pt.id) AS total_data,
|
||||
SUM(ptr.nilai_retribusi_bangunan) AS total_retribution') // Menambahkan SUM dari pbg_task_retributions
|
||||
->first();
|
||||
});
|
||||
$non_business_count = $query_non_business->total_data ?? 0;
|
||||
$non_business_total = $query_non_business->total_retribution ?? 0;
|
||||
->selectRaw("
|
||||
COUNT(CASE WHEN LOWER(TRIM(ptgs.status_verifikasi)) = 'selesai verifikasi' THEN 1 END) AS verified_count,
|
||||
SUM(CASE WHEN LOWER(TRIM(ptgs.status_verifikasi)) = 'selesai verifikasi' THEN ptr.nilai_retribusi_bangunan ELSE 0 END) AS verified_total,
|
||||
|
||||
COUNT(CASE WHEN LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL THEN 1 END) AS non_verified_count,
|
||||
SUM(CASE WHEN LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL THEN ptr.nilai_retribusi_bangunan ELSE 0 END) AS non_verified_total,
|
||||
|
||||
COUNT(CASE WHEN (LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL)
|
||||
AND LOWER(TRIM(pbg_task.function_type)) = 'sebagai tempat usaha' THEN 1 END) AS business_count,
|
||||
SUM(CASE WHEN (LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL)
|
||||
AND LOWER(TRIM(pbg_task.function_type)) = 'sebagai tempat usaha' THEN ptr.nilai_retribusi_bangunan ELSE 0 END) AS business_total,
|
||||
|
||||
$query_non_verified = once(function () {
|
||||
return DB::table('pbg_task AS pt')
|
||||
->leftJoin('pbg_task_google_sheet AS ptgs', 'pt.registration_number', '=', 'ptgs.no_registrasi')
|
||||
->leftJoin('pbg_task_retributions AS ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid') // Join tabel pbg_task_retributions
|
||||
->where(function ($query) {
|
||||
$query->whereRaw('LOWER(TRIM(ptgs.status_verifikasi)) != ?', [strtolower(trim('Selesai Verifikasi'))])
|
||||
->orWhereNull('ptgs.status_verifikasi'); // Include NULL values
|
||||
})
|
||||
->selectRaw('COUNT(pt.id) AS total_data,
|
||||
SUM(ptr.nilai_retribusi_bangunan) AS total_retribution') // Menambahkan SUM dari pbg_task_retributions
|
||||
COUNT(CASE WHEN (LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL)
|
||||
AND (LOWER(TRIM(pbg_task.function_type)) != 'sebagai tempat usaha' OR pbg_task.function_type IS NULL) THEN 1 END) AS non_business_count,
|
||||
SUM(CASE WHEN (LOWER(TRIM(ptgs.status_verifikasi)) != 'selesai verifikasi' OR ptgs.status_verifikasi IS NULL)
|
||||
AND (LOWER(TRIM(pbg_task.function_type)) != 'sebagai tempat usaha' OR pbg_task.function_type IS NULL) THEN ptr.nilai_retribusi_bangunan ELSE 0 END) AS non_business_total
|
||||
")
|
||||
->first();
|
||||
|
||||
// Assign Results
|
||||
$verified_count = $stats->verified_count ?? 0;
|
||||
$verified_total = $stats->verified_total ?? 0;
|
||||
$non_verified_count = $stats->non_verified_count ?? 0;
|
||||
$non_verified_total = $stats->non_verified_total ?? 0;
|
||||
$business_count = $stats->business_count ?? 0;
|
||||
$business_total = $stats->business_total ?? 0;
|
||||
$non_business_count = $stats->non_business_count ?? 0;
|
||||
$non_business_total = $stats->non_business_total ?? 0;
|
||||
|
||||
$query_potention = once(function () use ($year) {
|
||||
$query = PbgTask::leftJoin('pbg_task_retributions as ptr', 'pbg_task.uuid', '=', 'ptr.pbg_task_uid')
|
||||
->selectRaw('COUNT(DISTINCT pbg_task.id) as task_count, SUM(ptr.nilai_retribusi_bangunan) as total_retribution');
|
||||
|
||||
if ($year !== 'all') {
|
||||
$query->whereYear('pbg_task.task_created_at', (int) $year);
|
||||
}
|
||||
|
||||
return $query->first();
|
||||
});
|
||||
|
||||
$non_verified_count = $query_non_verified->total_data ?? 0;
|
||||
$non_verified_total = $query_non_verified->total_retribution ?? 0;
|
||||
|
||||
$query_potention = once( function () {
|
||||
return DB::table('pbg_task as pt')
|
||||
->leftJoin('pbg_task_retributions as ptr', 'pt.uuid', '=', 'ptr.pbg_task_uid')
|
||||
->select(
|
||||
DB::raw('COUNT(DISTINCT pt.id) as task_count'),
|
||||
DB::raw('SUM(ptr.nilai_retribusi_bangunan) as total_retribution')
|
||||
)
|
||||
->first();
|
||||
});
|
||||
$potention_count = $query_potention->task_count ?? 0;
|
||||
$potention_total = $query_potention->total_retribution ?? 0;
|
||||
|
||||
$query_spatial_plannings = once(function () use ($year) {
|
||||
$query = PbgTask::leftJoin('spatial_plannings as sp', 'pbg_task.document_number', '=', 'sp.number')
|
||||
->leftJoin('pbg_task_retributions as ptr', 'ptr.pbg_task_uid', '=', 'pbg_task.uuid')
|
||||
->selectRaw('
|
||||
CASE
|
||||
WHEN COUNT(DISTINCT sp.id) > 0 THEN COUNT(DISTINCT sp.id)
|
||||
ELSE (SELECT COUNT(*) FROM spatial_plannings)
|
||||
END as task_count,
|
||||
SUM(CASE WHEN sp.id IS NOT NULL AND ptr.id IS NOT NULL THEN ptr.nilai_retribusi_bangunan ELSE 0 END) as total_retribution
|
||||
');
|
||||
|
||||
if ($year !== 'all') {
|
||||
$query->whereYear('pbg_task.task_created_at', (int) $year);
|
||||
}
|
||||
|
||||
return $query->first();
|
||||
});
|
||||
|
||||
$spatial_planning_count = $query_spatial_plannings->task_count ?? 0;
|
||||
$spatial_planning_total = $query_spatial_plannings->total_retribution;
|
||||
|
||||
$potention_count -= $spatial_planning_count;
|
||||
$potention_total -= $spatial_planning_total;
|
||||
|
||||
return self::create([
|
||||
'import_datasource_id' => $import_datasource_id,
|
||||
'spatial_count' => $spatial_planning_count,
|
||||
'spatial_sum' => $spatial_planning_total ?? 0.00,
|
||||
'potention_count' => $potention_count ?? 0,
|
||||
'potention_sum' => $potention_total ?? 0.00,
|
||||
'non_verified_count' => $non_verified_count ?? 0,
|
||||
@@ -120,6 +125,13 @@ class BigdataResume extends Model
|
||||
'business_sum' => $business_total ?? 0.00,
|
||||
'non_business_count' => $non_business_count ?? 0,
|
||||
'non_business_sum' => $non_business_total ?? 0.00,
|
||||
'year' => $year,
|
||||
'waiting_click_dpmptsp_count' => $data_setting['MENUNGGU_KLIK_DPMPTSP_COUNT'] ?? 0,
|
||||
'waiting_click_dpmptsp_sum' => $data_setting['MENUNGGU_KLIK_DPMPTSP_SUM'] ?? 0.00,
|
||||
'issuance_realization_pbg_count' => $data_setting['REALISASI_TERBIT_PBG_COUNT'] ?? 0,
|
||||
'issuance_realization_pbg_sum' => $data_setting['REALISASI_TERBIT_PBG_SUM'] ?? 0.00,
|
||||
'process_in_technical_office_count' => $data_setting['PROSES_DINAS_TEKNIS_COUNT'] ?? 0,
|
||||
'process_in_technical_office_sum' => $data_setting['PROSES_DINAS_TEKNIS_SUM'] ??0.00,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
20
app/Models/Customer.php
Normal file
20
app/Models/Customer.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Customer extends Model
|
||||
{
|
||||
protected $table = 'customers';
|
||||
protected $fillable = [
|
||||
'nomor_pelanggan',
|
||||
'kota_pelayanan',
|
||||
'nama',
|
||||
'alamat',
|
||||
'latitude',
|
||||
'longitude',
|
||||
];
|
||||
|
||||
|
||||
}
|
||||
@@ -37,4 +37,8 @@ class PbgTask extends Model
|
||||
public function pbg_task_index_integrations(){
|
||||
return $this->hasOne(PbgTaskIndexIntegrations::class, 'pbg_task_uid', 'uuid');
|
||||
}
|
||||
|
||||
public function googleSheet(){
|
||||
return $this->hasOne(PbgTaskGoogleSheet::class, 'no_registrasi', 'registration_number');
|
||||
}
|
||||
}
|
||||
|
||||
37
app/Models/SpatialPlanning.php
Normal file
37
app/Models/SpatialPlanning.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Class SpatialPlanning
|
||||
*
|
||||
* @property $id
|
||||
* @property $created_at
|
||||
* @property $updated_at
|
||||
* @property $name
|
||||
* @property $kbli
|
||||
* @property $activities
|
||||
* @property $area
|
||||
* @property $location
|
||||
* @property $number
|
||||
* @property $date
|
||||
*
|
||||
* @package App
|
||||
* @mixin \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
class SpatialPlanning extends Model
|
||||
{
|
||||
|
||||
protected $perPage = 20;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = ['name', 'kbli', 'activities', 'area', 'location', 'number', 'date'];
|
||||
|
||||
|
||||
}
|
||||
@@ -9,6 +9,8 @@ use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Carbon\Carbon;
|
||||
use App\Services\ServiceSIMBG;
|
||||
use App\Services\GoogleSheetService;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -17,7 +19,9 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
$this->app->singleton(ServiceSIMBG::class, function ($app) {
|
||||
return new ServiceSIMBG($app->make(GoogleSheetService::class));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,7 @@ class GoogleSheetService
|
||||
protected $client;
|
||||
protected $service;
|
||||
protected $spreadsheetID;
|
||||
protected $service_sheets;
|
||||
public function __construct()
|
||||
{
|
||||
$this->client = new Google_Client();
|
||||
|
||||
157
app/Services/OpenAIService.php
Normal file
157
app/Services/OpenAIService.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use OpenAI;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class OpenAIService
|
||||
{
|
||||
protected $client;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->client = OpenAI::client(env('OPENAI_API_KEY'));
|
||||
}
|
||||
|
||||
public function generateGeneralText($prompt, $mainContent)
|
||||
{
|
||||
$response = $this->client->chat()->create([
|
||||
'model' => 'gpt-4o-mini',
|
||||
'messages' => [
|
||||
[
|
||||
'role' => 'system',
|
||||
'content' => "You are an expert assistant. Your task is to generate a concise response based on the provided prompt and main content.
|
||||
|
||||
Guidelines:
|
||||
- Summarize the key points in exactly 5 bullet points.
|
||||
- Ensure the response is clear and relevant to the prompt.
|
||||
- Use simple and professional language."
|
||||
],
|
||||
['role' => 'user', 'content' => "Prompt: $prompt \nMain Content: $mainContent"],
|
||||
],
|
||||
]);
|
||||
|
||||
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||
}
|
||||
|
||||
public function generateClassifyMainContent($prompt, $mainContent)
|
||||
{
|
||||
$response = $this->client->chat()->create([
|
||||
'model' => 'gpt-4o-mini',
|
||||
'messages' => [
|
||||
[
|
||||
'role' => 'system',
|
||||
'content' => "You are an expert assistant in classifying questions based on whether their answers must be retrieved from a database or can be explained generally.
|
||||
Your task is to return one of the following two labels:
|
||||
- \"DATABASE\" → If the question requires specific data that can only be obtained from a database.
|
||||
- \"GENERAL\" → If the question can be answered without accessing a database.
|
||||
|
||||
Consider the following context: \"$mainContent\"
|
||||
|
||||
Respond with only one of the labels: \"DATABASE\" or \"GENERAL\"."
|
||||
],
|
||||
['role' => 'user', 'content' => $prompt],
|
||||
],
|
||||
]);
|
||||
|
||||
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||
}
|
||||
|
||||
public function generateQueryBasedMainContent($prompt, $mainContent)
|
||||
{
|
||||
// Load file JSON
|
||||
$jsonPath = public_path('templates/contentTemplatePrompt.json'); // Sesuaikan path
|
||||
$jsonData = json_decode(file_get_contents($jsonPath), true);
|
||||
|
||||
// Periksa apakah kategori ada dalam JSON
|
||||
if (!isset($jsonData[$mainContent])) {
|
||||
return "Template prompt tidak ditemukan.";
|
||||
}
|
||||
|
||||
// Ambil template berdasarkan kategori
|
||||
$promptTemplate = $jsonData[$mainContent]['prompt'];
|
||||
|
||||
$response = $this->client->chat()->create([
|
||||
'model' => 'gpt-4o-mini',
|
||||
'messages' => [
|
||||
['role' => 'system', 'content' => $promptTemplate],
|
||||
['role' => 'user', 'content' => $prompt],
|
||||
],
|
||||
]);
|
||||
|
||||
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||
}
|
||||
|
||||
|
||||
public function validateSyntaxQuery($queryResponse)
|
||||
{
|
||||
$response = $this->client->chat()->create([
|
||||
'model' => 'gpt-4o-mini',
|
||||
'messages' => [
|
||||
[
|
||||
'role' => 'system',
|
||||
'content' => "You are a MariaDB SQL expert. Your task is to validate the syntax of an SQL query to ensure it follows proper MariaDB syntax rules.
|
||||
|
||||
Guidelines:
|
||||
- Check for any syntax errors, missing keywords, or incorrect clause usage.
|
||||
- Ensure the query is well-structured and adheres to best practices.
|
||||
- Verify that all SQL keywords are used correctly and in the right order.
|
||||
- If the query is valid, respond with: \"VALID\".
|
||||
- If the query has issues, respond with: \"INVALID\".
|
||||
|
||||
Always respond with either \"VALID\" or \"INVALID\"."
|
||||
],
|
||||
['role' => 'user', 'content' => $queryResponse],
|
||||
],
|
||||
]);
|
||||
|
||||
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||
}
|
||||
|
||||
public function generateNLPFromQuery($inputUser, $resultQuery) {
|
||||
$response = $this->client->chat()->create([
|
||||
'model' => 'gpt-4o-mini',
|
||||
'messages' => [
|
||||
[
|
||||
'role' => 'system',
|
||||
'content' => "You are an expert assistant. Your task is to analyze the database query results and transform them into a human-readable answer based on the user's question.
|
||||
|
||||
Guidelines:
|
||||
- Understand the user's question and extract the key intent.
|
||||
- Summarize or format the query results to directly answer the user's question.
|
||||
- Ensure the response is clear, concise, and relevant.
|
||||
- If the query result is empty or does not match the question, provide a polite response indicating that no data is available.
|
||||
|
||||
Always provide a well-structured response that makes sense based on the input question."
|
||||
],
|
||||
['role' => 'user', 'content' => "User's question: $inputUser \nDatabase result: $resultQuery"],
|
||||
],
|
||||
]);
|
||||
|
||||
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||
}
|
||||
|
||||
public function generateFinalText($nlpResult) {
|
||||
$response = $this->client->chat()->create([
|
||||
'model' => 'gpt-4o-mini',
|
||||
'messages' => [
|
||||
[
|
||||
'role' => 'system',
|
||||
'content' => "You are an expert text formatter. Your task is to take the given NLP result and format it into a structured, human-readable text suitable for rendering inside an HTML <div>.
|
||||
|
||||
Guidelines:
|
||||
- Preserve the meaning and clarity of the content.
|
||||
- Use proper line breaks for readability.
|
||||
- If the text contains lists, convert them into bullet points.
|
||||
- Emphasize important keywords using <strong> tags if necessary.
|
||||
- Ensure the response remains clean and concise without extra explanations."
|
||||
],
|
||||
['role' => 'user', 'content' => "Here is the NLP result that needs formatting:\n\n$nlpResult"],
|
||||
],
|
||||
]);
|
||||
|
||||
return trim($response['choices'][0]['message']['content'] ?? 'No response');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,9 @@ use App\Traits\GlobalApiResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Carbon\Carbon;
|
||||
use App\Services\ServiceClient;
|
||||
use App\Services\GoogleSheetService;
|
||||
use App\Models\DataSetting;
|
||||
use App\Models\PbgTaskGoogleSheet;
|
||||
|
||||
class ServiceSIMBG
|
||||
{
|
||||
@@ -24,10 +27,11 @@ class ServiceSIMBG
|
||||
private $simbg_host;
|
||||
private $fetch_per_page;
|
||||
private $service_client;
|
||||
private $googleSheetService;
|
||||
/**
|
||||
* Create a new class instance.
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(GoogleSheetService $googleSheetService)
|
||||
{
|
||||
$settings = GlobalSetting::whereIn('key', [
|
||||
'SIMBG_EMAIL', 'SIMBG_PASSWORD', 'SIMBG_HOST', 'FETCH_PER_PAGE'
|
||||
@@ -39,6 +43,7 @@ class ServiceSIMBG
|
||||
$this->fetch_per_page = trim((string) ($settings['FETCH_PER_PAGE'] ?? ""));
|
||||
|
||||
$this->service_client = new ServiceClient($this->simbg_host);
|
||||
$this->googleSheetService = $googleSheetService;
|
||||
}
|
||||
|
||||
public function getToken(){
|
||||
@@ -61,32 +66,37 @@ class ServiceSIMBG
|
||||
}
|
||||
}
|
||||
|
||||
public function syncIndexIntegration($uuid, $token)
|
||||
public function syncIndexIntegration($uuids, $token)
|
||||
{
|
||||
try{
|
||||
$url = "/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/";
|
||||
|
||||
$headers = [
|
||||
'Authorization' => "Bearer " . $token,
|
||||
];
|
||||
|
||||
$res = $this->service_client->get($url, $headers);
|
||||
|
||||
if (empty($res->original['success']) || !$res->original['success']) {
|
||||
// Log error
|
||||
Log::error("API response indicates failure", ['url' => $url, 'uuid' => $uuid]);
|
||||
if(empty($uuids)){
|
||||
return false;
|
||||
}
|
||||
|
||||
$integrations = [];
|
||||
foreach($uuids as $uuid){
|
||||
$url = "/api/pbg/v1/detail/" . $uuid . "/retribution/indeks-terintegrasi/";
|
||||
|
||||
$data = $res->original['data']['data'] ?? null;
|
||||
if (!$data) {
|
||||
Log::error("No valid data returned from API", ['url' => $url, 'uuid' => $uuid]);
|
||||
return false;
|
||||
}
|
||||
|
||||
$resultData = PbgTaskIndexIntegrations::updateOrCreate(
|
||||
['pbg_task_uid' => $uuid],
|
||||
[
|
||||
$headers = [
|
||||
'Authorization' => "Bearer " . $token,
|
||||
];
|
||||
|
||||
$res = $this->service_client->get($url, $headers);
|
||||
|
||||
if (empty($res->original['success']) || !$res->original['success']) {
|
||||
// Log error
|
||||
Log::error("API response indicates failure", ['url' => $url, 'uuid' => $uuid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$data = $res->original['data']['data'] ?? null;
|
||||
if (!$data) {
|
||||
Log::error("No valid data returned from API", ['url' => $url, 'uuid' => $uuid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$integrations[] = [
|
||||
'pbg_task_uid' => $uuid,
|
||||
'indeks_fungsi_bangunan' => $data['indeks_fungsi_bangunan'] ?? null,
|
||||
'indeks_parameter_kompleksitas' => $data['indeks_parameter_kompleksitas'] ?? null,
|
||||
'indeks_parameter_permanensi' => $data['indeks_parameter_permanensi'] ?? null,
|
||||
@@ -94,8 +104,11 @@ class ServiceSIMBG
|
||||
'faktor_kepemilikan' => $data['faktor_kepemilikan'] ?? null,
|
||||
'indeks_terintegrasi' => $data['indeks_terintegrasi'] ?? null,
|
||||
'total' => $data['total'] ?? null,
|
||||
]
|
||||
);
|
||||
];
|
||||
}
|
||||
|
||||
PbgTaskIndexIntegrations::upsert($integrations, ['pbg_task_uid'], ['indeks_fungsi_bangunan',
|
||||
'indeks_parameter_kompleksitas', 'indeks_parameter_permanensi', 'indeks_parameter_ketinggian', 'faktor_kepemilikan', 'indeks_terintegrasi', 'total']);
|
||||
|
||||
return true;
|
||||
}catch (Exception $e){
|
||||
@@ -104,132 +117,298 @@ class ServiceSIMBG
|
||||
}
|
||||
}
|
||||
|
||||
public function syncTaskList()
|
||||
public function syncTaskPBG()
|
||||
{
|
||||
$initResToken = $this->getToken();
|
||||
|
||||
$importDatasource = ImportDatasource::create([
|
||||
'status' => ImportDatasourceStatus::Processing->value,
|
||||
]);
|
||||
|
||||
if (empty($initResToken->original['data']['token']['access'])) {
|
||||
$importDatasource->update([
|
||||
'status' => ImportDatasourceStatus::Failed->value,
|
||||
'message' => 'Failed to retrieve token'
|
||||
try {
|
||||
$importDatasource = ImportDatasource::create([
|
||||
'status' => ImportDatasourceStatus::Processing->value,
|
||||
]);
|
||||
return $this->resError("Failed to retrieve token");
|
||||
}
|
||||
|
||||
$apiToken = $initResToken->original['data']['token']['access'];
|
||||
$headers = ['Authorization' => "Bearer " . $apiToken];
|
||||
// sync google sheet first
|
||||
$totalRowCount = $this->googleSheetService->getLastRowByColumn("C");
|
||||
$sheetData = $this->googleSheetService->getSheetDataCollection($totalRowCount);
|
||||
$sheet_big_data = $this->googleSheetService->get_data_by_sheet();
|
||||
$data_setting_result = []; // Initialize result storage
|
||||
|
||||
$found_section = null; // Track which section is found
|
||||
|
||||
foreach ($sheet_big_data as $row) {
|
||||
// Check for section headers
|
||||
if (in_array("•PROSES PENERBITAN:", $row)) {
|
||||
$found_section = "MENUNGGU_KLIK_DPMPTSP";
|
||||
} elseif (in_array("•BERKAS AKTUAL TERVERIFIKASI DINAS TEKNIS 2024:", $row)) {
|
||||
$found_section = "REALISASI_TERBIT_PBG";
|
||||
} elseif (in_array("•TERPROSES DI DPUTR: belum selesai rekomtek'", $row)) {
|
||||
$found_section = "PROSES_DINAS_TEKNIS";
|
||||
}
|
||||
|
||||
// If a section is found and we reach "Grand Total", save the corresponding values
|
||||
if ($found_section && isset($row[0]) && trim($row[0]) === "Grand Total") {
|
||||
if ($found_section === "MENUNGGU_KLIK_DPMPTSP") {
|
||||
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_COUNT"] = $row[2] ?? null;
|
||||
$data_setting_result["MENUNGGU_KLIK_DPMPTSP_SUM"] = $row[3] ?? null;
|
||||
} elseif ($found_section === "REALISASI_TERBIT_PBG") {
|
||||
$data_setting_result["REALISASI_TERBIT_PBG_COUNT"] = $row[2] ?? null;
|
||||
$data_setting_result["REALISASI_TERBIT_PBG_SUM"] = $row[4] ?? null;
|
||||
} elseif ($found_section === "PROSES_DINAS_TEKNIS") {
|
||||
$data_setting_result["PROSES_DINAS_TEKNIS_COUNT"] = $row[2] ?? null;
|
||||
$data_setting_result["PROSES_DINAS_TEKNIS_SUM"] = $row[3] ?? null;
|
||||
}
|
||||
|
||||
// Reset section tracking after capturing "Grand Total"
|
||||
$found_section = null;
|
||||
}
|
||||
}
|
||||
|
||||
$url = "/api/pbg/v1/list/?page=1&size={$this->fetch_per_page}&sort=ASC";
|
||||
$initialResponse = $this->service_client->get($url, $headers);
|
||||
foreach ($data_setting_result as $key => $value) {
|
||||
DataSetting::updateOrInsert(
|
||||
["key" => $key], // Find by key
|
||||
["value" => $value] // Update or insert value
|
||||
);
|
||||
}
|
||||
$mapToUpsert = [];
|
||||
$count = 0;
|
||||
|
||||
$totalPage = $initialResponse->original['data']['total_page'] ?? 0;
|
||||
if ($totalPage == 0) {
|
||||
$importDatasource->update([
|
||||
'status' => ImportDatasourceStatus::Failed->value,
|
||||
'message' => 'Invalid response: no total_page'
|
||||
]);
|
||||
return $this->resError("Invalid response from API");
|
||||
}
|
||||
foreach($sheetData as $data){
|
||||
$mapToUpsert[] =
|
||||
[
|
||||
'no_registrasi' => $data['no__registrasi'] ?? null,
|
||||
'jenis_konsultasi' => $data['jenis_konsultasi'] ?? null,
|
||||
'fungsi_bg' => $data['fungsi_bg'] ?? null,
|
||||
'tgl_permohonan' => $this->convertToDate($data['tgl_permohonan']),
|
||||
'status_verifikasi' => $data['status_verifikasi'] ?? null,
|
||||
'status_permohonan' => $this->convertToDate($data['status_permohonan']),
|
||||
'alamat_pemilik' => $data['alamat_pemilik'] ?? null,
|
||||
'no_hp' => $data['no__hp'] ?? null,
|
||||
'email' => $data['e_mail'] ?? null,
|
||||
'tanggal_catatan' => $this->convertToDate($data['tanggal_catatan']),
|
||||
'catatan_kekurangan_dokumen' => $data['catatan_kekurangan_dokumen'] ?? null,
|
||||
'gambar' => $data['gambar'] ?? null,
|
||||
'krk_kkpr' => $data['krk_kkpr'] ?? null,
|
||||
'no_krk' => $data['no__krk'] ?? null,
|
||||
'lh' => $data['lh'] ?? null,
|
||||
'ska' => $data['ska'] ?? null,
|
||||
'keterangan' => $data['keterangan'] ?? null,
|
||||
'helpdesk' => $data['helpdesk'] ?? null,
|
||||
'pj' => $data['pj'] ?? null,
|
||||
'kepemilikan' => $data['kepemilikan'] ?? null,
|
||||
'potensi_taru' => $data['potensi_taru'] ?? null,
|
||||
'validasi_dinas' => $data['validasi_dinas'] ?? null,
|
||||
'kategori_retribusi' => $data['kategori_retribusi'] ?? null,
|
||||
'no_urut_ba_tpt' => $data['no__urut_ba_tpt__2024_0001_'] ?? null,
|
||||
'tanggal_ba_tpt' => $this->convertToDate($data['tanggal_ba_tpt']),
|
||||
'no_urut_ba_tpa' => $data['no__urut_ba_tpa'] ?? null,
|
||||
'tanggal_ba_tpa' => $this->convertToDate($data['tanggal_ba_tpa']),
|
||||
'no_urut_skrd' => $data['no__urut_skrd__2024_0001_'] ?? null,
|
||||
'tanggal_skrd' => $this->convertToDate($data['tanggal_skrd']),
|
||||
'ptsp' => $data['ptsp'] ?? null,
|
||||
'selesai_terbit' => $data['selesai_terbit'] ?? null,
|
||||
'tanggal_pembayaran' => $this->convertToDate($data['tanggal_pembayaran__yyyy_mm_dd_']),
|
||||
'format_sts' => $data['format_sts'] ?? null,
|
||||
'tahun_terbit' => (int) $data['tahun_terbit'] ?? null,
|
||||
'tahun_berjalan' => (int) $data['tahun_berjalan'] ?? null,
|
||||
'kelurahan' => $data['kelurahan'] ?? null,
|
||||
'kecamatan' => $data['kecamatan'] ?? null,
|
||||
'lb' => $this->convertToDecimal($data['lb']) ?? null,
|
||||
'tb' => $this->convertToDecimal($data['tb']) ?? null,
|
||||
'jlb' => (int) $data['jlb'] ?? null,
|
||||
'unit' => (int) $data['unit'] ?? null,
|
||||
'usulan_retribusi' => (int) $data['usulan_retribusi'] ?? null,
|
||||
'nilai_retribusi_keseluruhan_simbg' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__simbg_']) ?? null,
|
||||
'nilai_retribusi_keseluruhan_pad' => $this->convertToDecimal($data['nilai_retribusi_keseluruhan__pad_']) ?? null,
|
||||
'denda' => $this->convertToDecimal($data['denda']) ?? null,
|
||||
'latitude' => $data['latitude'] ?? null,
|
||||
'longitude' => $data['longitude'] ?? null,
|
||||
'nik_nib' => $data['nik_nib'] ?? null,
|
||||
'dok_tanah' => $data['dok__tanah'] ?? null,
|
||||
'temuan' => $data['temuan'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
$savedCount = $failedCount = 0;
|
||||
$batchSize = 1000;
|
||||
$chunks = array_chunk($mapToUpsert, $batchSize);
|
||||
|
||||
for ($currentPage = 1; $currentPage <= $totalPage; $currentPage++) {
|
||||
$pageUrl = "/api/pbg/v1/list/?page={$currentPage}&size={$this->fetch_per_page}&sort=ASC";
|
||||
$getToken = $this->getToken();
|
||||
Log::info("response index integration", ['currentPage' => $currentPage]);
|
||||
if (empty($getToken->original['data']['token']['access'])) {
|
||||
foreach($chunks as $chunk){
|
||||
PbgTaskGoogleSheet::upsert($chunk, ["no_registrasi"],[
|
||||
'jenis_konsultasi',
|
||||
'nama_pemilik',
|
||||
'lokasi_bg',
|
||||
'fungsi_bg',
|
||||
'nama_bangunan',
|
||||
'tgl_permohonan',
|
||||
'status_verifikasi',
|
||||
'status_permohonan',
|
||||
'alamat_pemilik',
|
||||
'no_hp',
|
||||
'email',
|
||||
'tanggal_catatan',
|
||||
'catatan_kekurangan_dokumen',
|
||||
'gambar',
|
||||
'krk_kkpr',
|
||||
'no_krk',
|
||||
'lh',
|
||||
'ska',
|
||||
'keterangan',
|
||||
'helpdesk',
|
||||
'pj',
|
||||
'kepemilikan',
|
||||
'potensi_taru',
|
||||
'validasi_dinas',
|
||||
'kategori_retribusi',
|
||||
'no_urut_ba_tpt',
|
||||
'tanggal_ba_tpt',
|
||||
'no_urut_ba_tpa',
|
||||
'tanggal_ba_tpa',
|
||||
'no_urut_skrd',
|
||||
'tanggal_skrd',
|
||||
'ptsp',
|
||||
'selesai_terbit',
|
||||
'tanggal_pembayaran',
|
||||
'format_sts',
|
||||
'tahun_terbit',
|
||||
'tahun_berjalan',
|
||||
'kelurahan',
|
||||
'kecamatan',
|
||||
'lb',
|
||||
'tb',
|
||||
'jlb',
|
||||
'unit',
|
||||
'usulan_retribusi',
|
||||
'nilai_retribusi_keseluruhan_simbg',
|
||||
'nilai_retribusi_keseluruhan_pad',
|
||||
'denda',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'nik_nib',
|
||||
'dok_tanah',
|
||||
'temuan',
|
||||
]);
|
||||
}
|
||||
|
||||
$initResToken = $this->getToken();
|
||||
if (empty($initResToken->original['data']['token']['access'])) {
|
||||
$importDatasource->update([
|
||||
'status' => ImportDatasourceStatus::Failed->value,
|
||||
'message' => 'Failed to retrieve token'
|
||||
]);
|
||||
break;
|
||||
return $this->resError("Failed to retrieve token");
|
||||
}
|
||||
$token = $getToken->original['data']['token']['access'];
|
||||
$headers = ['Authorization' => "Bearer " . $token];
|
||||
$response = $this->service_client->get($pageUrl, $headers);
|
||||
$tasks = $response->original['data']['data'] ?? [];
|
||||
$apiToken = $initResToken->original['data']['token']['access'];
|
||||
$headers = ['Authorization' => "Bearer " . $apiToken];
|
||||
|
||||
if (empty($tasks)) {
|
||||
$url = "/api/pbg/v1/list/?page=1&size={$this->fetch_per_page}&sort=ASC";
|
||||
$initialResponse = $this->service_client->get($url, $headers);
|
||||
|
||||
$totalPage = $initialResponse->original['data']['total_page'] ?? 0;
|
||||
if ($totalPage == 0) {
|
||||
$importDatasource->update([
|
||||
'status' => ImportDatasourceStatus::Failed->value,
|
||||
'message' => 'No data found on page'
|
||||
'message' => 'Invalid response: no total_page'
|
||||
]);
|
||||
Log::warning("No data found on page", ['page' => $currentPage]);
|
||||
break;
|
||||
return $this->resError("Invalid response from API");
|
||||
}
|
||||
|
||||
Log::info("executed page", ['page' => $currentPage, 'total' => $totalPage]);
|
||||
$savedCount = $failedCount = 0;
|
||||
|
||||
$tasksCollective = [];
|
||||
foreach ($tasks as $item) {
|
||||
for ($currentPage = 1; $currentPage <= $totalPage; $currentPage++) {
|
||||
try {
|
||||
$tasksCollective[] = [
|
||||
'uuid' => $item['uid'],
|
||||
'name' => $item['name'],
|
||||
'owner_name' => $item['owner_name'],
|
||||
'application_type' => $item['application_type'],
|
||||
'application_type_name' => $item['application_type_name'],
|
||||
'condition' => $item['condition'],
|
||||
'registration_number' => $item['registration_number'],
|
||||
'document_number' => $item['document_number'],
|
||||
'address' => $item['address'],
|
||||
'status' => $item['status'],
|
||||
'status_name' => $item['status_name'],
|
||||
'slf_status' => $item['slf_status'] ?? null,
|
||||
'slf_status_name' => $item['slf_status_name'] ?? null,
|
||||
'function_type' => $item['function_type'],
|
||||
'consultation_type' => $item['consultation_type'],
|
||||
'due_date' => $item['due_date'],
|
||||
'land_certificate_phase' => $item['land_certificate_phase'],
|
||||
'task_created_at' => isset($item['created_at']) ? Carbon::parse($item['created_at'])->format('Y-m-d H:i:s') : null,
|
||||
'updated_at' => now(),
|
||||
'created_at' => now(),
|
||||
];
|
||||
$pageUrl = "/api/pbg/v1/list/?page={$currentPage}&size={$this->fetch_per_page}&sort=ASC";
|
||||
|
||||
$this->syncIndexIntegration($item['uid'], $token);
|
||||
Log::info("Fetching tasks", ['currentPage' => $currentPage]);
|
||||
|
||||
$this->syncTaskDetailSubmit($item['uid'], $token);
|
||||
|
||||
$savedCount++;
|
||||
$response = $this->service_client->get($pageUrl, $headers);
|
||||
$tasks = $response->original['data']['data'] ?? [];
|
||||
|
||||
if (empty($tasks)) {
|
||||
Log::warning("No data found on page", ['page' => $currentPage]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$tasksCollective = [];
|
||||
foreach ($tasks as $item) {
|
||||
try {
|
||||
$tasksCollective[] = [
|
||||
'uuid' => $item['uid'],
|
||||
'name' => $item['name'],
|
||||
'owner_name' => $item['owner_name'],
|
||||
'application_type' => $item['application_type'],
|
||||
'application_type_name' => $item['application_type_name'],
|
||||
'condition' => $item['condition'],
|
||||
'registration_number' => $item['registration_number'],
|
||||
'document_number' => $item['document_number'],
|
||||
'address' => $item['address'],
|
||||
'status' => $item['status'],
|
||||
'status_name' => $item['status_name'],
|
||||
'slf_status' => $item['slf_status'] ?? null,
|
||||
'slf_status_name' => $item['slf_status_name'] ?? null,
|
||||
'function_type' => $item['function_type'],
|
||||
'consultation_type' => $item['consultation_type'],
|
||||
'due_date' => $item['due_date'],
|
||||
'land_certificate_phase' => $item['land_certificate_phase'],
|
||||
'task_created_at' => isset($item['created_at']) ? Carbon::parse($item['created_at'])->format('Y-m-d H:i:s') : null,
|
||||
'updated_at' => now(),
|
||||
'created_at' => now(),
|
||||
];
|
||||
|
||||
$this->syncTaskDetailSubmit($item['uid'], $apiToken);
|
||||
$savedCount++;
|
||||
} catch (Exception $e) {
|
||||
$failedCount++;
|
||||
Log::error("Failed to process task", [
|
||||
'error' => $e->getMessage(),
|
||||
'task' => $item,
|
||||
]);
|
||||
continue; // Skip failed task, continue processing the rest
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($tasksCollective)) {
|
||||
PbgTask::upsert($tasksCollective, ['uuid'], [
|
||||
'name', 'owner_name', 'application_type', 'application_type_name', 'condition',
|
||||
'registration_number', 'document_number', 'address', 'status', 'status_name',
|
||||
'slf_status', 'slf_status_name', 'function_type', 'consultation_type', 'due_date',
|
||||
'land_certificate_phase', 'task_created_at', 'updated_at'
|
||||
]);
|
||||
|
||||
$uuids = array_column($tasksCollective, 'uuid');
|
||||
$this->syncIndexIntegration($uuids, $apiToken);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$failedCount++;
|
||||
$importDatasource->update([
|
||||
'status' => ImportDatasourceStatus::Failed->value,
|
||||
'message' => "Successfully processed: $savedCount, Failed: $failedCount"
|
||||
]);
|
||||
Log::error("Failed to process task", [
|
||||
Log::error("Failed to process page", [
|
||||
'error' => $e->getMessage(),
|
||||
'task' => $item,
|
||||
'page' => $currentPage,
|
||||
]);
|
||||
break;
|
||||
continue; // Skip the failed page and move to the next
|
||||
}
|
||||
}
|
||||
|
||||
PbgTask::upsert($tasksCollective, ['uuid'], [
|
||||
'name', 'owner_name', 'application_type', 'application_type_name', 'condition',
|
||||
'registration_number', 'document_number', 'address', 'status', 'status_name',
|
||||
'slf_status', 'slf_status_name', 'function_type', 'consultation_type', 'due_date',
|
||||
'land_certificate_phase', 'task_created_at', 'updated_at'
|
||||
BigdataResume::generateResumeData($importDatasource->id, "all", $data_setting_result);
|
||||
BigdataResume::generateResumeData($importDatasource->id, now()->year, $data_setting_result);
|
||||
|
||||
// Final update after processing all pages
|
||||
$importDatasource->update([
|
||||
'status' => ImportDatasourceStatus::Success->value,
|
||||
'message' => "Successfully processed: $savedCount, Failed: $failedCount"
|
||||
]);
|
||||
|
||||
Log::info("syncTaskList completed", ['savedCount' => $savedCount, 'failedCount' => $failedCount]);
|
||||
|
||||
return $this->resSuccess(['savedCount' => $savedCount, 'failedCount' => $failedCount]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error("syncTaskList failed", ['error' => $e->getMessage()]);
|
||||
if (isset($importDatasource)) {
|
||||
$importDatasource->update([
|
||||
'status' => ImportDatasourceStatus::Failed->value,
|
||||
'message' => 'Critical failure: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
return $this->resError("Critical failure occurred: " . $e->getMessage());
|
||||
}
|
||||
|
||||
$importDatasource->update([
|
||||
'status' => ImportDatasourceStatus::Success->value,
|
||||
'message' => "Successfully processed: $savedCount, Failed: $failedCount"
|
||||
]);
|
||||
|
||||
BigdataResume::generateResumeData($importDatasource->id);
|
||||
|
||||
Log::info("syncTaskList completed", ['savedCount' => $savedCount, 'failedCount' => $failedCount]);
|
||||
|
||||
return $this->resSuccess(['savedCount' => $savedCount, 'failedCount' => $failedCount]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function syncTaskDetailSubmit($uuid, $token)
|
||||
{
|
||||
try{
|
||||
@@ -310,6 +489,59 @@ class ServiceSIMBG
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
protected function convertToDecimal(?string $value): ?float
|
||||
{
|
||||
if (empty($value)) {
|
||||
return null; // Return null if the input is empty
|
||||
}
|
||||
|
||||
}
|
||||
// Remove all non-numeric characters except comma and dot
|
||||
$value = preg_replace('/[^0-9,\.]/', '', $value);
|
||||
|
||||
// If the number contains both dot (.) and comma (,)
|
||||
if (strpos($value, '.') !== false && strpos($value, ',') !== false) {
|
||||
$value = str_replace('.', '', $value); // Remove thousands separator
|
||||
$value = str_replace(',', '.', $value); // Convert decimal separator to dot
|
||||
}
|
||||
// If only a dot is present (assumed as thousands separator)
|
||||
elseif (strpos($value, '.') !== false) {
|
||||
$value = str_replace('.', '', $value); // Remove all dots (treat as thousands separators)
|
||||
}
|
||||
// If only a comma is present (assumed as decimal separator)
|
||||
elseif (strpos($value, ',') !== false) {
|
||||
$value = str_replace(',', '.', $value); // Convert comma to dot (decimal separator)
|
||||
}
|
||||
|
||||
// Ensure the value is numeric before returning
|
||||
return is_numeric($value) ? (float) number_format((float) $value, 2, '.', '') : null;
|
||||
}
|
||||
|
||||
protected function convertToInteger($value) {
|
||||
// Check if the value is an empty string, and return null if true
|
||||
if (trim($value) === "") {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Otherwise, cast to integer
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
protected function convertToDate($dateString)
|
||||
{
|
||||
try {
|
||||
// Check if the string is empty
|
||||
if (empty($dateString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to parse the date string
|
||||
$date = Carbon::parse($dateString);
|
||||
|
||||
// Return the Carbon instance
|
||||
return $date->format('Y-m-d');
|
||||
} catch (Exception $e) {
|
||||
// Return null if an error occurs during parsing
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,11 @@
|
||||
"laravel/framework": "^11.31",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^2.9",
|
||||
"maatwebsite/excel": "^3.1"
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"openai-php/client": "^0.10.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.23",
|
||||
"ibex/crud-generator": "^2.1",
|
||||
"laravel/pail": "^1.1",
|
||||
"laravel/pint": "^1.13",
|
||||
"laravel/sail": "^1.26",
|
||||
|
||||
300
composer.lock
generated
300
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "52617d098d62b15c6ce8538cc8aea775",
|
||||
"content-hash": "41bb51871a746904ab745e4095db8b46",
|
||||
"packages": [
|
||||
{
|
||||
"name": "brick/math",
|
||||
@@ -3296,6 +3296,97 @@
|
||||
],
|
||||
"time": "2024-11-21T10:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "openai-php/client",
|
||||
"version": "v0.10.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openai-php/client.git",
|
||||
"reference": "4a565d145e0fb3ea1baba8fffe39d86c56b6dc2c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/openai-php/client/zipball/4a565d145e0fb3ea1baba8fffe39d86c56b6dc2c",
|
||||
"reference": "4a565d145e0fb3ea1baba8fffe39d86c56b6dc2c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1.0",
|
||||
"php-http/discovery": "^1.20.0",
|
||||
"php-http/multipart-stream-builder": "^1.4.2",
|
||||
"psr/http-client": "^1.0.3",
|
||||
"psr/http-client-implementation": "^1.0.1",
|
||||
"psr/http-factory-implementation": "*",
|
||||
"psr/http-message": "^1.1.0|^2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/guzzle": "^7.9.2",
|
||||
"guzzlehttp/psr7": "^2.7.0",
|
||||
"laravel/pint": "^1.18.1",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"nunomaduro/collision": "^7.11.0|^8.5.0",
|
||||
"pestphp/pest": "^2.36.0|^3.5.0",
|
||||
"pestphp/pest-plugin-arch": "^2.7|^3.0",
|
||||
"pestphp/pest-plugin-type-coverage": "^2.8.7|^3.1.0",
|
||||
"phpstan/phpstan": "^1.12.7",
|
||||
"symfony/var-dumper": "^6.4.11|^7.1.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/OpenAI.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"OpenAI\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nuno Maduro",
|
||||
"email": "enunomaduro@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sandro Gehri"
|
||||
}
|
||||
],
|
||||
"description": "OpenAI PHP is a supercharged PHP API client that allows you to interact with the Open AI API",
|
||||
"keywords": [
|
||||
"GPT-3",
|
||||
"api",
|
||||
"client",
|
||||
"codex",
|
||||
"dall-e",
|
||||
"language",
|
||||
"natural",
|
||||
"openai",
|
||||
"php",
|
||||
"processing",
|
||||
"sdk"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/openai-php/client/issues",
|
||||
"source": "https://github.com/openai-php/client/tree/v0.10.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.paypal.com/paypalme/enunomaduro",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/gehrisandro",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nunomaduro",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-12T20:51:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v3.0.0",
|
||||
@@ -3413,6 +3504,141 @@
|
||||
},
|
||||
"time": "2020-10-15T08:29:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/discovery",
|
||||
"version": "1.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/discovery.git",
|
||||
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/discovery/zipball/82fe4c73ef3363caed49ff8dd1539ba06044910d",
|
||||
"reference": "82fe4c73ef3363caed49ff8dd1539ba06044910d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer-plugin-api": "^1.0|^2.0",
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"nyholm/psr7": "<1.0",
|
||||
"zendframework/zend-diactoros": "*"
|
||||
},
|
||||
"provide": {
|
||||
"php-http/async-client-implementation": "*",
|
||||
"php-http/client-implementation": "*",
|
||||
"psr/http-client-implementation": "*",
|
||||
"psr/http-factory-implementation": "*",
|
||||
"psr/http-message-implementation": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/composer": "^1.0.2|^2.0",
|
||||
"graham-campbell/phpspec-skip-example-extension": "^5.0",
|
||||
"php-http/httplug": "^1.0 || ^2.0",
|
||||
"php-http/message-factory": "^1.0",
|
||||
"phpspec/phpspec": "^5.1 || ^6.1 || ^7.3",
|
||||
"sebastian/comparator": "^3.0.5 || ^4.0.8",
|
||||
"symfony/phpunit-bridge": "^6.4.4 || ^7.0.1"
|
||||
},
|
||||
"type": "composer-plugin",
|
||||
"extra": {
|
||||
"class": "Http\\Discovery\\Composer\\Plugin",
|
||||
"plugin-optional": true
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Discovery\\": "src/"
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"src/Composer/Plugin.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Finds and installs PSR-7, PSR-17, PSR-18 and HTTPlug implementations",
|
||||
"homepage": "http://php-http.org",
|
||||
"keywords": [
|
||||
"adapter",
|
||||
"client",
|
||||
"discovery",
|
||||
"factory",
|
||||
"http",
|
||||
"message",
|
||||
"psr17",
|
||||
"psr7"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/discovery/issues",
|
||||
"source": "https://github.com/php-http/discovery/tree/1.20.0"
|
||||
},
|
||||
"time": "2024-10-02T11:20:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-http/multipart-stream-builder",
|
||||
"version": "1.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-http/multipart-stream-builder.git",
|
||||
"reference": "10086e6de6f53489cca5ecc45b6f468604d3460e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-http/multipart-stream-builder/zipball/10086e6de6f53489cca5ecc45b6f468604d3460e",
|
||||
"reference": "10086e6de6f53489cca5ecc45b6f468604d3460e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1 || ^8.0",
|
||||
"php-http/discovery": "^1.15",
|
||||
"psr/http-factory-implementation": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"nyholm/psr7": "^1.0",
|
||||
"php-http/message": "^1.5",
|
||||
"php-http/message-factory": "^1.0.2",
|
||||
"phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Http\\Message\\MultipartStream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A builder class that help you create a multipart stream",
|
||||
"homepage": "http://php-http.org",
|
||||
"keywords": [
|
||||
"factory",
|
||||
"http",
|
||||
"message",
|
||||
"multipart stream",
|
||||
"stream"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-http/multipart-stream-builder/issues",
|
||||
"source": "https://github.com/php-http/multipart-stream-builder/tree/1.4.2"
|
||||
},
|
||||
"time": "2024-09-04T13:22:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpoffice/phpspreadsheet",
|
||||
"version": "1.29.10",
|
||||
@@ -7155,74 +7381,6 @@
|
||||
},
|
||||
"time": "2020-07-09T08:09:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ibex/crud-generator",
|
||||
"version": "v2.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/awais-vteams/laravel-crud-generator.git",
|
||||
"reference": "3906f4a702c91bbe3a84d940c3021d1511834320"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/awais-vteams/laravel-crud-generator/zipball/3906f4a702c91bbe3a84d940c3021d1511834320",
|
||||
"reference": "3906f4a702c91bbe3a84d940c3021d1511834320",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"laravel/framework": "^10.30|^11.0",
|
||||
"php": "^8.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Ibex\\CrudGenerator\\CrudServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ibex\\CrudGenerator\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "M Awais",
|
||||
"email": "asargodha@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Laravel CRUD Generator",
|
||||
"keywords": [
|
||||
"alpine js",
|
||||
"bootstrap css",
|
||||
"crud",
|
||||
"crud generator",
|
||||
"laravel",
|
||||
"laravel crud generator",
|
||||
"laravel package",
|
||||
"tailwind css"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/awais-vteams/laravel-crud-generator/issues",
|
||||
"source": "https://github.com/awais-vteams/laravel-crud-generator/tree/v2.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/awais-vteams",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://ko-fi.com/mawais",
|
||||
"type": "ko_fi"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-09T06:01:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/pail",
|
||||
"version": "v1.2.2",
|
||||
@@ -9316,12 +9474,12 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^8.2"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
@@ -123,5 +123,6 @@ return [
|
||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||
],
|
||||
|
||||
'api_url' => env('API_URL', 'http://localhost:8000')
|
||||
'api_url' => env('API_URL', 'http://localhost:8000'),
|
||||
'paginate_per_page' => 50
|
||||
];
|
||||
|
||||
@@ -109,4 +109,10 @@ return [
|
||||
'table' => 'failed_jobs',
|
||||
],
|
||||
|
||||
// set timeout queue
|
||||
|
||||
'worker' => [
|
||||
'timeout' => 300
|
||||
]
|
||||
|
||||
];
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('spatial_planning', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
|
||||
$table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
|
||||
$table->string('name')->nullable();
|
||||
$table->string('kbli')->nullable();
|
||||
$table->string('activities')->nullable();
|
||||
$table->string('area')->nullable();
|
||||
$table->string('location')->nullable();
|
||||
$table->string('number')->nullable();
|
||||
$table->dateTime('date')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('spatial_planning');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::rename('spatial_planning', 'spatial_plannings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::rename('spatial_plannings', 'spatial_planning');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('customers', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nomor_pelanggan')->unique();
|
||||
$table->string('kota_pelayanan');
|
||||
$table->string('nama');
|
||||
$table->text('alamat');
|
||||
$table->decimal('latitude', 22,18);
|
||||
$table->decimal('longitude', 22,18);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('customers');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('bigdata_resumes', function (Blueprint $table) {
|
||||
$table->integer('spatial_count')->default(0);
|
||||
$table->decimal('spatial_sum', 20,2)->default(0);
|
||||
$table->string('year');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('bigdata_resumes', function (Blueprint $table) {
|
||||
$table->dropColumn('spatial_count');
|
||||
$table->dropColumn('spatial_sum');
|
||||
$table->dropColumn('year');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('pbg_task_google_sheet', function (Blueprint $table) {
|
||||
$table->string('formatted_registration_number')->nullable()->after('no_registrasi');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('pbg_task_google_sheet', function (Blueprint $table) {
|
||||
$table->dropColumn('formatted_registration_number');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('bigdata_resumes', function (Blueprint $table) {
|
||||
$table->integer('waiting_click_dpmptsp_count')->default(0);
|
||||
$table->decimal('waiting_click_dpmptsp_sum', 20,2)->default(0);
|
||||
$table->integer('issuance_realization_pbg_count')->default(0);
|
||||
$table->decimal('issuance_realization_pbg_sum', 20,2)->default(0);
|
||||
$table->integer('process_in_technical_office_count')->default(0);
|
||||
$table->decimal('process_in_technical_office_sum', 20,2)->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('bigdata_resumes', function (Blueprint $table) {
|
||||
$table->dropColumn('waiting_click_dpmptsp_count');
|
||||
$table->dropColumn('waiting_click_dpmptsp_sum');
|
||||
$table->dropColumn('issuance_realization_pbg_count');
|
||||
$table->dropColumn('issuance_realization_pbg_sum');
|
||||
$table->dropColumn('process_in_technical_office_count');
|
||||
$table->dropColumn('process_in_technical_office_sum');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -71,7 +71,7 @@ class UsersRoleMenuSeeder extends Seeder
|
||||
[
|
||||
"name" => "Laporan",
|
||||
"url" => "/laporan",
|
||||
"icon" => "mingcute:task-line",
|
||||
"icon" => "mingcute:report-line",
|
||||
"parent_id" => null,
|
||||
"sort_order" => 6,
|
||||
]
|
||||
@@ -116,6 +116,13 @@ class UsersRoleMenuSeeder extends Seeder
|
||||
"parent_id" => $dashboard->id,
|
||||
"sort_order" => 3,
|
||||
],
|
||||
[
|
||||
"name" => "PETA",
|
||||
"url" => "dashboard.maps",
|
||||
"icon" => null,
|
||||
"parent_id" => $dashboard->id,
|
||||
"sort_order" => 4,
|
||||
],
|
||||
[
|
||||
"name" => "Users",
|
||||
"url" => "users.index",
|
||||
@@ -186,6 +193,20 @@ class UsersRoleMenuSeeder extends Seeder
|
||||
"parent_id" => $data->id,
|
||||
"sort_order" => 5,
|
||||
],
|
||||
[
|
||||
"name" => "Tata Ruang",
|
||||
"url" => "spatial-plannings.index",
|
||||
"icon" => null,
|
||||
"parent_id" => $data->id,
|
||||
"sort_order" => 6,
|
||||
],
|
||||
[
|
||||
"name" => "PDAM",
|
||||
"url" => "customers",
|
||||
"icon" => null,
|
||||
"parent_id" => $data->id,
|
||||
"sort_order" => 7,
|
||||
],
|
||||
[
|
||||
"name" => "Lap Pariwisata",
|
||||
"url" => "tourisms.index",
|
||||
@@ -193,6 +214,13 @@ class UsersRoleMenuSeeder extends Seeder
|
||||
"parent_id" => $laporan->id,
|
||||
"sort_order" => 1,
|
||||
],
|
||||
[
|
||||
"name" => "Lap Pimpinan",
|
||||
"url" => "bigdata-resumes",
|
||||
"icon" => null,
|
||||
"parent_id" => $laporan->id,
|
||||
"sort_order" => 2,
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($children_menus as $child_menu) {
|
||||
@@ -213,6 +241,10 @@ class UsersRoleMenuSeeder extends Seeder
|
||||
$laporan_pariwisata = Menu::where('name', 'Lap Pariwisata')->first();
|
||||
$umkm = Menu::where('name', 'UMKM')->first();
|
||||
$lack_of_potentials = Menu::where('name', 'Dashboard Potensi')->first();
|
||||
$spatial_plannings = Menu::where('name', 'Tata Ruang')->first();
|
||||
$pdam = Menu::where('name', 'PDAM')->first();
|
||||
$peta = Menu::where('name', 'PETA')->first();
|
||||
$bigdata_resume = Menu::where('name', 'Lap Pimpinan')->first();
|
||||
|
||||
// Superadmin gets all menus
|
||||
$superadmin->menus()->sync([
|
||||
@@ -238,6 +270,10 @@ class UsersRoleMenuSeeder extends Seeder
|
||||
$laporan_pariwisata->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
$umkm->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
$lack_of_potentials->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
$spatial_plannings->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
$pdam->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
$peta->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
$bigdata_resume->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
]);
|
||||
|
||||
// Admin gets limited menus
|
||||
@@ -252,6 +288,7 @@ class UsersRoleMenuSeeder extends Seeder
|
||||
$dashboard->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
$data->id => ["allow_show" => true, "allow_create" => true, "allow_update" => true, "allow_destroy" => true],
|
||||
]);
|
||||
|
||||
// Attach User to role super admin
|
||||
User::findOrFail(1)->roles()->sync([$superadmin->id]);
|
||||
}
|
||||
|
||||
38
deploy.sh
Normal file
38
deploy.sh
Normal file
@@ -0,0 +1,38 @@
|
||||
GIT_BRANCH="dev"
|
||||
PHP_VERSION="php8.3"
|
||||
|
||||
echo "🚀 Starting deployment..."
|
||||
php artisan down
|
||||
|
||||
echo "📥 Pulling latest changes from Git..."
|
||||
git fetch origin $GIT_BRANCH
|
||||
git reset --hard origin/$GIT_BRANCH
|
||||
git pull origin $GIT_BRANCH
|
||||
|
||||
echo "⚡ Installing NPM dependencies and building assets..."
|
||||
npm ci --no-audit --no-fund
|
||||
npm run build
|
||||
|
||||
echo "📦 Installing composer dependencies..."
|
||||
composer install --no-interaction --optimize-autoloader
|
||||
|
||||
echo "🗄️ Running migrations..."
|
||||
php artisan migrate --force
|
||||
|
||||
echo "⚡ Optimizing application..."
|
||||
php artisan cache:clear
|
||||
php artisan config:clear
|
||||
php artisan config:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
|
||||
echo "🔄 Restarting PHP service..."
|
||||
systemctl restart $PHP_VERSION-fpm
|
||||
|
||||
echo "🔁 Restarting Supervisor queue workers..."
|
||||
supervisorctl stop all
|
||||
supervisorctl reload
|
||||
supervisorctl start all
|
||||
|
||||
php artisan up
|
||||
echo "🚀 Deployment completed successfully!"
|
||||
5851
package-lock.json
generated
5851
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
69
package.json
69
package.json
@@ -1,36 +1,37 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"dev": "vite"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.20",
|
||||
"axios": "^1.7.4",
|
||||
"concurrently": "^9.0.1",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"postcss": "^8.4.47",
|
||||
"sass": "^1.81.1",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"vite": "^5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"apexcharts": "^3.44.2",
|
||||
"big.js": "^6.2.2",
|
||||
"bootstrap": "^5.3.3",
|
||||
"countup.js": "^2.3.2",
|
||||
"dropzone": "^5.9.0",
|
||||
"flatpickr": "^4.6.13",
|
||||
"gmaps": "^0.4.25",
|
||||
"gridjs": "^5.1.0",
|
||||
"iconify-icon": "^2.1.0",
|
||||
"jsvectormap": "^1.5.1",
|
||||
"moment": "^2.29.4",
|
||||
"node-waves": "^0.7.6",
|
||||
"quill": "^1.3.7",
|
||||
"simplebar": "^5.3.9",
|
||||
"sweetalert2": "^11.16.0",
|
||||
"wnumb": "^1.2.0"
|
||||
}
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"dev": "vite"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.20",
|
||||
"axios": "^1.7.4",
|
||||
"concurrently": "^9.0.1",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"postcss": "^8.4.47",
|
||||
"sass": "^1.81.1",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"vite": "^5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"apexcharts": "^3.44.2",
|
||||
"big.js": "^6.2.2",
|
||||
"bootstrap": "^5.3.3",
|
||||
"countup.js": "^2.3.2",
|
||||
"dropzone": "^5.9.0",
|
||||
"flatpickr": "^4.6.13",
|
||||
"gmaps": "^0.4.25",
|
||||
"gridjs": "^5.1.0",
|
||||
"iconify-icon": "^2.1.0",
|
||||
"jsvectormap": "^1.5.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"moment": "^2.29.4",
|
||||
"node-waves": "^0.7.6",
|
||||
"quill": "^1.3.7",
|
||||
"simplebar": "^5.3.9",
|
||||
"sweetalert2": "^11.16.0",
|
||||
"wnumb": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
BIN
public/images/iconchatbot.jpeg
Normal file
BIN
public/images/iconchatbot.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 177 KiB |
@@ -5,6 +5,7 @@ use Illuminate\Http\Request;
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
ini_set('max_execution_time',14400);
|
||||
ini_set('memory_limit', '2G');
|
||||
|
||||
// Determine if the application is in maintenance mode...
|
||||
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
|
||||
|
||||
11
public/templates/contentTemplatePrompt.json
Normal file
11
public/templates/contentTemplatePrompt.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"RETRIBUTION": {
|
||||
"prompt": "You are a MariaDB SQL expert. Your task is to generate an efficient and optimized SQL query based on user input.\n\n The query should retrieve data from the view table `v_pbg_task_with_retributions`, specifically selecting the following columns:\n\n - nilai_retribusi_bangunan\n - land_certificate_phase\n - due_date\n - consultation_type\n - function_type\n - slf_status_name\n - slf_status\n - status_name\n - status\n - address\n - document_number\n - registration_number\n - application_type_name\n - application_type\n - owner_name\n - name\n\n Ensure the query is well-structured, uses best indexing practices, and avoids performance bottlenecks.\n\n Consider the following context: \"$mainContent\".\n\n Always return only the SQL query without any additional explanation."
|
||||
},
|
||||
"DOCUMENT VALIDATION": {
|
||||
"prompt": "You are a MariaDB SQL expert. Your task is to generate an efficient and optimized SQL query based on user input.\n\n The query should retrieve data from the view table `pbg_task`, specifically selecting the following columns:\n\n - name\n - owner_name\n - application_type\n - application_type_name\n - registration_number\n - document_number\n - address\n - status_name\n - slf_status\n - slf_status_name\n - function_type\n - consultation_type\n - function_type\n - consultation_type\n - due_date\n - land_certificate_phase\n\n Ensure the query is well-structured, uses best indexing practices, and avoids performance bottlenecks.\n\n Consider the following context: \"$mainContent\".\n\n Always return only the SQL query without any additional explanation."
|
||||
},
|
||||
"DATA SUMMARY": {
|
||||
"prompt": "You are a MariaDB SQL expert. Your task is to generate an efficient and optimized SQL query based on user input.\n\n The query should retrieve data from the view table `bigdata_resumes`, specifically selecting the following columns:\n\n - potention_count\n - potention_sum\n - non_verified_count\n - non_verified_sum\n - verified_sum\n - verified_count\n - business_count\n - business_sum\n - non_business_count\n - non_business_sum\n - spatial_count\n - spatial_sum\n - updated_at\n\n Ensure the query is well-structured, uses best indexing practices, and avoids performance bottlenecks.\n\n Consider the following context: \"$mainContent\".\n\n Always return only the SQL query without any additional explanation."
|
||||
}
|
||||
}
|
||||
BIN
public/templates/template_pariwisata.xlsx
Normal file
BIN
public/templates/template_pariwisata.xlsx
Normal file
Binary file not shown.
BIN
public/templates/template_spatial_planning.xlsx
Normal file
BIN
public/templates/template_spatial_planning.xlsx
Normal file
Binary file not shown.
@@ -2,6 +2,30 @@ import bootstrap from "bootstrap/dist/js/bootstrap";
|
||||
window.bootstrap = bootstrap;
|
||||
import "iconify-icon";
|
||||
import "simplebar/dist/simplebar";
|
||||
// import flatpickr from "flatpickr";
|
||||
// import "flatpickr/dist/flatpickr.min.css";
|
||||
|
||||
// class InitDatePicker {
|
||||
// constructor(selector = ".datepicker") {
|
||||
// this.selector = selector;
|
||||
// }
|
||||
// init() {
|
||||
// const elements = document.querySelectorAll(this.selector);
|
||||
// if (elements.length === 0) return; // Skip if no elements found
|
||||
|
||||
// const today = new Date();
|
||||
// const minYear = today.getFullYear() - 5;
|
||||
|
||||
// elements.forEach((element) => {
|
||||
// flatpickr(element, {
|
||||
// enableTime: false,
|
||||
// dateFormat: "Y-m-d",
|
||||
// minDate: `${minYear}-01-01`,
|
||||
// maxDate: today,
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
class Components {
|
||||
initBootstrapComponents() {
|
||||
@@ -107,6 +131,7 @@ class FormValidation {
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new Components().init(), new FormValidation().init();
|
||||
// new InitDatePicker().init();
|
||||
});
|
||||
class ThemeLayout {
|
||||
constructor() {
|
||||
|
||||
170
resources/js/bigdata-resumes/index.js
Normal file
170
resources/js/bigdata-resumes/index.js
Normal file
@@ -0,0 +1,170 @@
|
||||
import { Grid } from "gridjs/dist/gridjs.umd.js";
|
||||
import gridjs from "gridjs/dist/gridjs.umd.js";
|
||||
import "gridjs/dist/gridjs.umd.js";
|
||||
import GlobalConfig, { addThousandSeparators } from "../global-config.js";
|
||||
import Swal from "sweetalert2";
|
||||
import moment from "moment";
|
||||
|
||||
class BigdataResume {
|
||||
constructor() {
|
||||
this.toastMessage = document.getElementById("toast-message");
|
||||
this.toastElement = document.getElementById("toastNotification");
|
||||
this.toast = new bootstrap.Toast(this.toastElement);
|
||||
this.table = null;
|
||||
|
||||
// Initialize functions
|
||||
this.initTableDataSettings();
|
||||
// this.initEvents();
|
||||
}
|
||||
initEvents() {
|
||||
document.body.addEventListener("click", async (event) => {
|
||||
const deleteButton = event.target.closest(
|
||||
".btn-delete-data-settings"
|
||||
);
|
||||
if (deleteButton) {
|
||||
event.preventDefault();
|
||||
await this.handleDelete(deleteButton);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
initTableDataSettings() {
|
||||
let tableContainer = document.getElementById("table-bigdata-resumes");
|
||||
this.table = new Grid({
|
||||
columns: [
|
||||
{ name: "ID" },
|
||||
{ name: "Jumlah Potensi" },
|
||||
{ name: "Total Potensi" },
|
||||
{ name: "Jumlah Berkas Belum Terverifikasi" },
|
||||
{ name: "Total Berkas Belum Terverifikasi" },
|
||||
{ name: "Jumlah Berkas Terverifikasi" },
|
||||
{ name: "Total Berkas Terverifikasi" },
|
||||
{ name: "Jumlah Usaha" },
|
||||
{ name: "Total Usaha" },
|
||||
{ name: "Jumlah Non Usaha" },
|
||||
{ name: "Total Non Usaha" },
|
||||
{ name: "Jumlah Tata Ruang" },
|
||||
{ name: "Total Tata Ruang" },
|
||||
{ name: "Jumlah Menunggu Klik DPMPTSP" },
|
||||
{ name: "Total Menunggu Klik DPMPTSP" },
|
||||
{ name: "Jumlah Realisasi Terbit PBG" },
|
||||
{ name: "Total Realisasi Terbit PBG" },
|
||||
{ name: "Jumlah Proses Dinas Teknis" },
|
||||
{ name: "Total Proses Dinas Teknis" },
|
||||
{
|
||||
name: "Created",
|
||||
attributes: { style: "width: 200px; white-space: nowrap;" }, // Set width dynamically
|
||||
},
|
||||
],
|
||||
pagination: {
|
||||
limit: 50,
|
||||
server: {
|
||||
url: (prev, page) =>
|
||||
`${prev}${prev.includes("?") ? "&" : "?"}page=${
|
||||
page + 1
|
||||
}`,
|
||||
},
|
||||
},
|
||||
sort: true,
|
||||
search: {
|
||||
server: {
|
||||
url: (prev, keyword) => `${prev}?search=${keyword}`,
|
||||
},
|
||||
},
|
||||
server: {
|
||||
url: `${GlobalConfig.apiHost}/api/bigdata-report`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
then: (data) => {
|
||||
return data.data.map((item) => [
|
||||
item.id,
|
||||
item.potention_count,
|
||||
addThousandSeparators(item.potention_sum),
|
||||
item.non_verified_count,
|
||||
addThousandSeparators(item.non_verified_sum),
|
||||
item.verified_count,
|
||||
addThousandSeparators(item.verified_sum),
|
||||
item.business_count,
|
||||
addThousandSeparators(item.business_sum),
|
||||
item.non_business_count,
|
||||
addThousandSeparators(item.non_business_sum),
|
||||
item.spatial_count,
|
||||
addThousandSeparators(item.spatial_sum),
|
||||
item.waiting_click_dpmptsp_count,
|
||||
addThousandSeparators(item.waiting_click_dpmptsp_sum),
|
||||
item.issuance_realization_pbg_count,
|
||||
addThousandSeparators(
|
||||
item.issuance_realization_pbg_sum
|
||||
),
|
||||
item.process_in_technical_office_count,
|
||||
addThousandSeparators(
|
||||
item.process_in_technical_office_sum
|
||||
),
|
||||
moment(item.created_at).format("YYYY-MM-DD H:mm:ss"),
|
||||
]);
|
||||
},
|
||||
total: (data) => data.total,
|
||||
},
|
||||
}).render(tableContainer);
|
||||
}
|
||||
async handleDelete(deleteButton) {
|
||||
const id = deleteButton.getAttribute("data-id");
|
||||
|
||||
const result = await Swal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "You won't be able to revert this!",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete it!",
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
let response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/data-settings/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
this.toastMessage.innerText =
|
||||
result.message || "Deleted successfully!";
|
||||
this.toast.show();
|
||||
|
||||
// Refresh Grid.js table
|
||||
if (typeof this.table !== "undefined") {
|
||||
this.table.updateConfig({}).forceRender();
|
||||
}
|
||||
} else {
|
||||
let error = await response.json();
|
||||
console.error("Delete failed:", error);
|
||||
this.toastMessage.innerText =
|
||||
error.message || "Delete failed!";
|
||||
this.toast.show();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting item:", error);
|
||||
this.toastMessage.innerText = "An error occurred!";
|
||||
this.toast.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new BigdataResume();
|
||||
});
|
||||
@@ -5,9 +5,9 @@ Dropzone.autoDiscover = false;
|
||||
var previewTemplate,
|
||||
dropzone,
|
||||
dropzonePreviewNode = document.querySelector("#dropzone-preview-list");
|
||||
console.log(previewTemplate);
|
||||
console.log(dropzone);
|
||||
console.log(dropzonePreviewNode);
|
||||
|
||||
const uploadButton = document.getElementById("btnUploadBusinessIndustry");
|
||||
const spinner = document.getElementById("spinner");
|
||||
|
||||
const toastNotification = document.getElementById("toastNotification");
|
||||
const toast = new bootstrap.Toast(toastNotification);
|
||||
@@ -29,97 +29,50 @@ const toast = new bootstrap.Toast(toastNotification);
|
||||
.getAttribute("content")}`,
|
||||
},
|
||||
init: function () {
|
||||
// Listen for the success event
|
||||
this.on("success", function (file, response) {
|
||||
console.log("File successfully uploaded:", file);
|
||||
console.log("API Response:", response);
|
||||
|
||||
// Show success toast
|
||||
document.getElementById("toast-message").innerText =
|
||||
response.message;
|
||||
toast.show();
|
||||
document.getElementById("submit-upload").innerHTML =
|
||||
"Upload Files";
|
||||
// Tunggu sebentar lalu reload halaman
|
||||
setTimeout(() => {
|
||||
window.location.href = "/data/business-industries";
|
||||
}, 2000);
|
||||
});
|
||||
// Listen for the error event
|
||||
this.on("error", function (file, errorMessage) {
|
||||
console.error("Error uploading file:", file);
|
||||
console.error("Error message:", errorMessage);
|
||||
// Handle the error response
|
||||
|
||||
// Show error toast
|
||||
document.getElementById("toast-message").innerText =
|
||||
errorMessage.message;
|
||||
toast.show();
|
||||
document.getElementById("submit-upload").innerHTML =
|
||||
"Upload Files";
|
||||
uploadButton.disabled = false;
|
||||
spinner.classList.add("d-none");
|
||||
});
|
||||
},
|
||||
})));
|
||||
|
||||
// Add event listener to control the submission manually
|
||||
document.querySelector("#submit-upload").addEventListener("click", function () {
|
||||
console.log("Ini adalah value dropzone", dropzone.files[0]);
|
||||
const formData = new FormData();
|
||||
console.log("Dropzonefiles", dropzone.files);
|
||||
document
|
||||
.querySelector("#btnUploadBusinessIndustry")
|
||||
.addEventListener("click", function () {
|
||||
console.log("Ini adalah value dropzone", dropzone.files[0]);
|
||||
const formData = new FormData();
|
||||
|
||||
this.innerHTML =
|
||||
'<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>Loading...';
|
||||
if (dropzone.files.length > 0) {
|
||||
formData.append("file", dropzone.files[0]);
|
||||
dropzone.processQueue(); // Ini akan manual memicu upload
|
||||
uploadButton.disabled = true;
|
||||
spinner.classList.remove("d-none");
|
||||
} else {
|
||||
document.getElementById("toast-message").innerText =
|
||||
"Please add a file first.";
|
||||
toast.show();
|
||||
uploadButton.disabled = false;
|
||||
spinner.classList.add("d-none");
|
||||
}
|
||||
});
|
||||
|
||||
// Pastikan ada file dalam queue sebelum memprosesnya
|
||||
if (dropzone.files.length > 0) {
|
||||
formData.append("file", dropzone.files[0]);
|
||||
console.log("ini adalah form data on submit", ...formData);
|
||||
dropzone.processQueue(); // Ini akan manual memicu upload
|
||||
} else {
|
||||
// Show error toast when no file is selected
|
||||
document.getElementById("toast-message").innerText =
|
||||
"Please add a file first.";
|
||||
toast.show();
|
||||
|
||||
document.getElementById("submit-upload").innerHTML = "Upload Files";
|
||||
}
|
||||
});
|
||||
|
||||
// Optional: Listen for the 'addedfile' event to log or control file add behavior
|
||||
dropzone.on("addedfile", function (file) {
|
||||
console.log("File ditambahkan:", file);
|
||||
console.log("Nama File:", file.name);
|
||||
console.log("Tipe File:", file.type);
|
||||
console.log("Ukuran File:", (file.size / 1024).toFixed(2) + " KB");
|
||||
});
|
||||
dropzone.on("addedfile", function (file) {});
|
||||
|
||||
dropzone.on("complete", function (file) {
|
||||
dropzone.removeFile(file);
|
||||
});
|
||||
|
||||
// Function to show toast
|
||||
// function showToast(iconClass, iconColor, message) {
|
||||
// const toastElement = document.getElementById("toastUploadAdvertisement");
|
||||
// const toastBody = toastElement.querySelector(".toast-body");
|
||||
// const toastHeader = toastElement.querySelector(".toast-header");
|
||||
|
||||
// // Remove existing icon (if any) before adding the new one
|
||||
// const existingIcon = toastHeader.querySelector(".bx");
|
||||
// if (existingIcon) {
|
||||
// toastHeader.querySelector(".auth-logo").removeChild(existingIcon); // Remove the existing icon
|
||||
// }
|
||||
|
||||
// // Add the new icon to the toast header
|
||||
// const icon = document.createElement("i");
|
||||
// icon.classList.add("bx", iconClass);
|
||||
// icon.style.fontSize = "25px";
|
||||
// icon.style.color = iconColor;
|
||||
// toastHeader.querySelector(".auth-logo").appendChild(icon);
|
||||
|
||||
// // Set the toast message
|
||||
// toastBody.textContent = message;
|
||||
|
||||
// // Show the toast
|
||||
// const toast = new bootstrap.Toast(toastElement); // Inisialisasi Bootstrap Toast
|
||||
// toast.show();
|
||||
// }
|
||||
|
||||
@@ -2,58 +2,36 @@ import { Grid } from "gridjs/dist/gridjs.umd.js";
|
||||
import gridjs from "gridjs/dist/gridjs.umd.js";
|
||||
import "gridjs/dist/gridjs.umd.js";
|
||||
import GlobalConfig from "../global-config.js";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
class BusinessIndustries {
|
||||
constructor() {
|
||||
this.table = null; // Store Grid.js instance
|
||||
this.toastMessage = document.getElementById("toast-message");
|
||||
this.toastElement = document.getElementById("toastNotification");
|
||||
this.toast = new bootstrap.Toast(this.toastElement);
|
||||
this.table = null;
|
||||
|
||||
// Initialize functions
|
||||
this.initTableBusinessIndustries();
|
||||
this.initEvents();
|
||||
}
|
||||
init() {
|
||||
this.getFetchApiData();
|
||||
initEvents() {
|
||||
document.body.addEventListener("click", async (event) => {
|
||||
const deleteButton = event.target.closest(
|
||||
".btn-delete-business-industry"
|
||||
);
|
||||
if (deleteButton) {
|
||||
event.preventDefault();
|
||||
await this.handleDelete(deleteButton);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getFetchApiData() {
|
||||
initTableBusinessIndustries() {
|
||||
let tableContainer = document.getElementById(
|
||||
"table-business-industries"
|
||||
);
|
||||
|
||||
if (this.table) {
|
||||
// If table exists, update its data instead of recreating
|
||||
this.table
|
||||
.updateConfig({
|
||||
server: {
|
||||
url: `${GlobalConfig.apiHost}/api/api-business-industries`,
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
then: (data) =>
|
||||
data.data.map((item) => [
|
||||
item.id,
|
||||
item.nama_kecamatan,
|
||||
item.nama_kelurahan,
|
||||
item.nop,
|
||||
item.nama_wajib_pajak,
|
||||
item.alamat_wajib_pajak,
|
||||
item.alamat_objek_pajak,
|
||||
item.luas_bumi,
|
||||
item.luas_bangunan,
|
||||
item.njop_bumi,
|
||||
item.njop_bangunan,
|
||||
item.ketetapan,
|
||||
item.tahun_pajak,
|
||||
item.created_at,
|
||||
item.id,
|
||||
]),
|
||||
total: (data) => data.total,
|
||||
},
|
||||
})
|
||||
.forceRender();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new Grid.js instance only if it doesn't exist
|
||||
this.table = new Grid({
|
||||
columns: [
|
||||
{ name: "ID", width: "80px", hidden: false },
|
||||
@@ -71,29 +49,22 @@ class BusinessIndustries {
|
||||
{ name: "Tahun Pajak", width: "120px" },
|
||||
{ name: "Created", width: "180px" },
|
||||
{
|
||||
name: "Actions",
|
||||
width: "120px",
|
||||
formatter: function (cell) {
|
||||
return gridjs.html(`
|
||||
<div class="d-flex justify-content-center gap-2">
|
||||
<a href="/data/business-industries/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
|
||||
<i class='bx bx-edit'></i>
|
||||
</a>
|
||||
<button class="btn btn-sm btn-red d-inline-flex align-items-center justify-content-center btn-delete-business-industries" data-id="${cell}">
|
||||
<i class='bx bxs-trash'></i>
|
||||
</button>
|
||||
</div>
|
||||
`);
|
||||
},
|
||||
name: "Action",
|
||||
formatter: (cell) =>
|
||||
gridjs.html(`
|
||||
<div class="d-flex justify-content-center gap-2">
|
||||
<a href="/data/business-industries/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
|
||||
<i class='bx bx-edit'></i>
|
||||
</a>
|
||||
<button data-id="${cell}" class="btn btn-sm btn-red btn-delete-business-industry d-inline-flex align-items-center justify-content-center">
|
||||
<i class='bx bxs-trash' ></i>
|
||||
</button>
|
||||
</div>
|
||||
`),
|
||||
},
|
||||
],
|
||||
search: {
|
||||
server: {
|
||||
url: (prev, keyword) => `${prev}?search=${keyword}`,
|
||||
},
|
||||
},
|
||||
pagination: {
|
||||
limit: 15,
|
||||
limit: 50,
|
||||
server: {
|
||||
url: (prev, page) =>
|
||||
`${prev}${prev.includes("?") ? "&" : "?"}page=${
|
||||
@@ -102,6 +73,11 @@ class BusinessIndustries {
|
||||
},
|
||||
},
|
||||
sort: true,
|
||||
search: {
|
||||
server: {
|
||||
url: (prev, keyword) => `${prev}?search=${keyword}`,
|
||||
},
|
||||
},
|
||||
server: {
|
||||
url: `${GlobalConfig.apiHost}/api/api-business-industries`,
|
||||
headers: {
|
||||
@@ -131,98 +107,26 @@ class BusinessIndustries {
|
||||
total: (data) => data.total,
|
||||
},
|
||||
}).render(tableContainer);
|
||||
|
||||
document.addEventListener("click", this.handleDelete.bind(this));
|
||||
}
|
||||
handleDelete(event) {
|
||||
if (event.target.classList.contains("btn-delete-business-industries")) {
|
||||
event.preventDefault();
|
||||
const id = event.target.getAttribute("data-id");
|
||||
let modalElement = document.getElementById("modalConfirmation");
|
||||
let toastMessage = document.getElementById("toast-message");
|
||||
async handleDelete(deleteButton) {
|
||||
const id = deleteButton.getAttribute("data-id");
|
||||
|
||||
if (!modalElement) {
|
||||
console.error("Modal element not found!");
|
||||
return;
|
||||
}
|
||||
const result = await Swal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "You won't be able to revert this!",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete it!",
|
||||
});
|
||||
|
||||
let modal = new bootstrap.Modal(modalElement);
|
||||
let btnSaveConfirmation = document.getElementById(
|
||||
"btnSaveConfirmation"
|
||||
);
|
||||
let toastElement = document.getElementById("toastNotification");
|
||||
let toast = new bootstrap.Toast(toastElement);
|
||||
|
||||
// Remove previous event listeners to avoid multiple bindings
|
||||
btnSaveConfirmation.replaceWith(
|
||||
btnSaveConfirmation.cloneNode(true)
|
||||
);
|
||||
btnSaveConfirmation = document.getElementById(
|
||||
"btnSaveConfirmation"
|
||||
);
|
||||
|
||||
// Set the role ID on the confirm button inside the modal
|
||||
btnSaveConfirmation.setAttribute("data-business-industries-id", id);
|
||||
|
||||
// Show the modal
|
||||
modal.show();
|
||||
|
||||
btnSaveConfirmation.addEventListener("click", async () => {
|
||||
let deletedId = btnSaveConfirmation.getAttribute(
|
||||
"data-business-industries-id"
|
||||
);
|
||||
|
||||
try {
|
||||
let response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/api-business-industries/${deletedId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"X-CSRF-TOKEN": document
|
||||
.querySelector('meta[name="csrf-token"]')
|
||||
.getAttribute("content"),
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
toastMessage.innerText =
|
||||
result.message || "Deleted successfully!";
|
||||
toast.show();
|
||||
|
||||
// Hide modal
|
||||
modal.hide();
|
||||
|
||||
// Refresh Grid.js table
|
||||
this.refreshDataSettings();
|
||||
} else {
|
||||
let error = await response.json();
|
||||
console.error("Delete failed:", error);
|
||||
toastMessage.innerText =
|
||||
error.message || "Delete failed!";
|
||||
toast.show();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting item:", error);
|
||||
toastMessage.innerText = "An error occurred!";
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
refreshDataSettings() {
|
||||
if (this.table) {
|
||||
this.table
|
||||
.updateConfig({
|
||||
server: {
|
||||
url: `${GlobalConfig.apiHost}/api/api-business-industries`,
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
let response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/api-business-industries/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
@@ -230,31 +134,34 @@ class BusinessIndustries {
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
then: (data) =>
|
||||
data.data.map((item) => [
|
||||
item.id,
|
||||
item.nama_kecamatan,
|
||||
item.nama_kelurahan,
|
||||
item.nop,
|
||||
item.nama_wajib_pajak,
|
||||
item.alamat_wajib_pajak,
|
||||
item.alamat_objek_pajak,
|
||||
item.luas_bumi,
|
||||
item.luas_bangunan,
|
||||
item.njop_bumi,
|
||||
item.njop_bangunan,
|
||||
item.ketetapan,
|
||||
item.tahun_pajak,
|
||||
item.created_at,
|
||||
item.id, // ID for Actions column
|
||||
]),
|
||||
total: (data) => data.total,
|
||||
},
|
||||
})
|
||||
.forceRender();
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
this.toastMessage.innerText =
|
||||
result.message || "Deleted successfully!";
|
||||
this.toast.show();
|
||||
|
||||
// Refresh Grid.js table
|
||||
if (typeof this.table !== "undefined") {
|
||||
this.table.updateConfig({}).forceRender();
|
||||
}
|
||||
} else {
|
||||
let error = await response.json();
|
||||
console.error("Delete failed:", error);
|
||||
this.toastMessage.innerText =
|
||||
error.message || "Delete failed!";
|
||||
this.toast.show();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting item:", error);
|
||||
this.toastMessage.innerText = "An error occurred!";
|
||||
this.toast.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new BusinessIndustries().init();
|
||||
new BusinessIndustries();
|
||||
});
|
||||
|
||||
176
resources/js/chatbot/index.js
Normal file
176
resources/js/chatbot/index.js
Normal file
@@ -0,0 +1,176 @@
|
||||
import GlobalConfig from "../global-config.js";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.querySelectorAll(".nav-link").forEach(tab => {
|
||||
tab.addEventListener("click", function () {
|
||||
setTimeout(() => {
|
||||
const tab_active = getActiveTabId();
|
||||
console.log("Active Tab ID:", tab_active);
|
||||
}, 100); // Timeout untuk memastikan class `active` sudah diperbarui
|
||||
});
|
||||
});
|
||||
|
||||
const textarea = document.getElementById("user-message");
|
||||
const sendButton = document.getElementById("send");
|
||||
const conversationArea = document.querySelector(".row.flex-grow");
|
||||
|
||||
// Fungsi untuk mengirim pesan
|
||||
async function sendMessage() {
|
||||
const userText = textarea.value.trim();
|
||||
if (userText !== "") {
|
||||
// Kosongkan textarea setelah mengirim
|
||||
textarea.value = "";
|
||||
|
||||
// Ambil tab aktif saat ini
|
||||
const currentTab = getActiveTabId();
|
||||
|
||||
// Tambahkan pesan user ke UI
|
||||
addMessage(userText, "user");
|
||||
|
||||
// Tambahkan pesan bot sementara dengan "Loading..."
|
||||
const botMessageElement = addMessage('<div class="loader w-auto"></div>', "bot");
|
||||
|
||||
// Panggil API untuk mendapatkan response dari bot
|
||||
const botResponse = await getBotResponse(currentTab, userText);
|
||||
|
||||
// Perbarui pesan bot dengan respons yang sebenarnya
|
||||
botMessageElement.innerHTML = botResponse;;
|
||||
}
|
||||
}
|
||||
|
||||
// Event listener untuk klik tombol
|
||||
sendButton.addEventListener("click", sendMessage);
|
||||
|
||||
// Event listener untuk menekan Enter di textarea
|
||||
textarea.addEventListener("keydown", function (event) {
|
||||
if (event.key === "Enter" && !event.shiftKey) {
|
||||
event.preventDefault(); // Mencegah newline di textarea
|
||||
sendMessage(); // Panggil fungsi kirim pesan
|
||||
}
|
||||
});
|
||||
|
||||
function addMessage(text, sender) {
|
||||
const messageRow = document.createElement("div");
|
||||
messageRow.classList.add("row", "flex-grow", "overflow-auto");
|
||||
|
||||
const messageCol = document.createElement("div");
|
||||
messageCol.classList.add("w-auto", "d-inline-block"); // Menyesuaikan lebar konten
|
||||
|
||||
if (sender === "user") {
|
||||
messageCol.classList.add("ms-auto", "max-w-50"); // Rata kanan, max 50% (setara col-6)
|
||||
} else {
|
||||
messageCol.classList.add("max-w-75"); // Max 75% (setara col-9)
|
||||
|
||||
// Tambahkan avatar hanya untuk bot
|
||||
const avatarSpan = document.createElement("span");
|
||||
avatarSpan.classList.add("d-flex", "align-items-center", "mb-1");
|
||||
|
||||
const avatarImg = document.createElement("img");
|
||||
avatarImg.classList.add("rounded-circle");
|
||||
avatarImg.width = 32;
|
||||
avatarImg.src = "/images/iconchatbot.jpeg";
|
||||
avatarImg.alt = "bot-avatar";
|
||||
|
||||
avatarSpan.appendChild(avatarImg);
|
||||
messageCol.appendChild(avatarSpan);
|
||||
}
|
||||
|
||||
const messageDiv = document.createElement("div");
|
||||
messageDiv.classList.add("p-2", "rounded", "mb-2");
|
||||
|
||||
if (sender === "user") {
|
||||
messageDiv.classList.add("user-response", "bg-primary", "text-white");
|
||||
} else {
|
||||
messageDiv.classList.add("bot-response", "bg-light");
|
||||
}
|
||||
|
||||
// Menyisipkan konten HTML langsung (bisa berupa teks atau loader)
|
||||
messageDiv.innerHTML = text;
|
||||
messageCol.appendChild(messageDiv);
|
||||
messageRow.appendChild(messageCol);
|
||||
|
||||
// Tambahkan ke area percakapan
|
||||
conversationArea.appendChild(messageRow);
|
||||
|
||||
// Scroll otomatis ke bawah
|
||||
conversationArea.scrollTop = conversationArea.scrollHeight;
|
||||
|
||||
return messageDiv; // Mengembalikan elemen agar bisa diperbarui nanti
|
||||
}
|
||||
|
||||
|
||||
// function addMessage(text, sender) {
|
||||
// const messageRow = document.createElement("div");
|
||||
// messageRow.classList.add("row", "flex-grow", "overflow-auto");
|
||||
|
||||
// const messageCol = document.createElement("div");
|
||||
// messageCol.classList.add("col-9", "w-auto");
|
||||
|
||||
// if (sender === "user") {
|
||||
// messageCol.classList.add("ms-auto"); // Geser ke kanan untuk user
|
||||
// }
|
||||
|
||||
// const messageDiv = document.createElement("div");
|
||||
// messageDiv.classList.add("p-2", "rounded", "mb-2");
|
||||
|
||||
// if (sender === "user") {
|
||||
// messageDiv.classList.add("user-response", "bg-primary", "text-white");
|
||||
// } else {
|
||||
// messageDiv.classList.add("bot-response", "bg-light");
|
||||
|
||||
// // Tambahkan avatar hanya untuk bot
|
||||
// const avatarSpan = document.createElement("span");
|
||||
// avatarSpan.classList.add("d-flex", "align-items-center", "mb-1");
|
||||
|
||||
// const avatarImg = document.createElement("img");
|
||||
// avatarImg.classList.add("rounded-circle");
|
||||
// avatarImg.width = 32;
|
||||
// avatarImg.src = "/images/iconchatbot.jpeg";
|
||||
// avatarImg.alt = "bot-avatar";
|
||||
|
||||
// avatarSpan.appendChild(avatarImg);
|
||||
// messageCol.appendChild(avatarSpan);
|
||||
// }
|
||||
|
||||
// // Menyisipkan konten HTML langsung (bisa berupa teks atau loader)
|
||||
// messageDiv.innerHTML = text;
|
||||
// messageCol.appendChild(messageDiv);
|
||||
// messageRow.appendChild(messageCol);
|
||||
|
||||
// // Tambahkan ke area percakapan
|
||||
// conversationArea.appendChild(messageRow);
|
||||
|
||||
// // Scroll otomatis ke bawah
|
||||
// conversationArea.scrollTop = conversationArea.scrollHeight;
|
||||
|
||||
// return messageDiv; // Mengembalikan elemen agar bisa diperbarui nanti
|
||||
// }
|
||||
|
||||
// Fungsi untuk memanggil API
|
||||
async function getBotResponse(tab_active, userText) {
|
||||
try {
|
||||
const url = `${GlobalConfig.apiHost}/api/generate-text`;
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({tab_active:tab_active, prompt: userText }),
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
return data.response || "Maaf, saya tidak mengerti.";
|
||||
} catch (error) {
|
||||
console.error("Error fetching bot response:", error);
|
||||
return "Terjadi kesalahan, coba lagi nanti.";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function getActiveTabId() {
|
||||
const activeTab = document.querySelector(".nav-link.active");
|
||||
return activeTab ? activeTab.id : null;
|
||||
}
|
||||
65
resources/js/customers/create.js
Normal file
65
resources/js/customers/create.js
Normal file
@@ -0,0 +1,65 @@
|
||||
class CreateCustomer {
|
||||
constructor() {
|
||||
this.initCreateCustomer();
|
||||
}
|
||||
|
||||
initCreateCustomer() {
|
||||
const toastNotification = document.getElementById("toastNotification");
|
||||
const toast = new bootstrap.Toast(toastNotification);
|
||||
document
|
||||
.getElementById("btnCreateCustomer")
|
||||
.addEventListener("click", async function () {
|
||||
let submitButton = this;
|
||||
let spinner = document.getElementById("spinner");
|
||||
let form = document.getElementById("formCreateCustomer");
|
||||
|
||||
if (!form) {
|
||||
console.error("Form element not found!");
|
||||
return;
|
||||
}
|
||||
// Get form data
|
||||
let formData = new FormData(form);
|
||||
|
||||
// Disable button and show spinner
|
||||
submitButton.disabled = true;
|
||||
spinner.classList.remove("d-none");
|
||||
|
||||
try {
|
||||
let response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
document.getElementById("toast-message").innerText =
|
||||
result.message;
|
||||
toast.show();
|
||||
setTimeout(() => {
|
||||
window.location.href = "/data/customers";
|
||||
}, 2000);
|
||||
} else {
|
||||
let error = await response.json();
|
||||
document.getElementById("toast-message").innerText =
|
||||
error.message;
|
||||
toast.show();
|
||||
console.error("Error:", error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Request failed:", error);
|
||||
document.getElementById("toast-message").innerText =
|
||||
error.message;
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new CreateCustomer();
|
||||
});
|
||||
65
resources/js/customers/edit.js
Normal file
65
resources/js/customers/edit.js
Normal file
@@ -0,0 +1,65 @@
|
||||
class UpdateCustomer {
|
||||
constructor() {
|
||||
this.initUpdateCustomer();
|
||||
}
|
||||
|
||||
initUpdateCustomer() {
|
||||
const toastNotification = document.getElementById("toastNotification");
|
||||
const toast = new bootstrap.Toast(toastNotification);
|
||||
document
|
||||
.getElementById("btnUpdateCustomer")
|
||||
.addEventListener("click", async function () {
|
||||
let submitButton = this;
|
||||
let spinner = document.getElementById("spinner");
|
||||
let form = document.getElementById("formUpdateCustomer");
|
||||
|
||||
if (!form) {
|
||||
console.error("Form element not found!");
|
||||
return;
|
||||
}
|
||||
// Get form data
|
||||
let formData = new FormData(form);
|
||||
|
||||
// Disable button and show spinner
|
||||
submitButton.disabled = true;
|
||||
spinner.classList.remove("d-none");
|
||||
|
||||
try {
|
||||
let response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
document.getElementById("toast-message").innerText =
|
||||
result.message;
|
||||
toast.show();
|
||||
setTimeout(() => {
|
||||
window.location.href = "/data/customers";
|
||||
}, 2000);
|
||||
} else {
|
||||
let error = await response.json();
|
||||
document.getElementById("toast-message").innerText =
|
||||
error.message;
|
||||
toast.show();
|
||||
console.error("Error:", error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Request failed:", error);
|
||||
document.getElementById("toast-message").innerText =
|
||||
error.message;
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new UpdateCustomer();
|
||||
});
|
||||
151
resources/js/customers/index.js
Normal file
151
resources/js/customers/index.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import { Grid } from "gridjs/dist/gridjs.umd.js";
|
||||
import gridjs from "gridjs/dist/gridjs.umd.js";
|
||||
import "gridjs/dist/gridjs.umd.js";
|
||||
import GlobalConfig from "../global-config";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
class Customers {
|
||||
constructor() {
|
||||
this.toastMessage = document.getElementById("toast-message");
|
||||
this.toastElement = document.getElementById("toastNotification");
|
||||
this.toast = new bootstrap.Toast(this.toastElement);
|
||||
this.table = null;
|
||||
|
||||
// Initialize functions
|
||||
this.initTableCustomers();
|
||||
this.initEvents();
|
||||
}
|
||||
initEvents() {
|
||||
document.body.addEventListener("click", async (event) => {
|
||||
const deleteButton = event.target.closest(".btn-delete-customers");
|
||||
if (deleteButton) {
|
||||
event.preventDefault();
|
||||
await this.handleDelete(deleteButton);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
initTableCustomers() {
|
||||
let tableContainer = document.getElementById("table-customers");
|
||||
// Create a new Grid.js instance only if it doesn't exist
|
||||
this.table = new Grid({
|
||||
columns: [
|
||||
"ID",
|
||||
"Nomor Pelanggan",
|
||||
"Nama",
|
||||
"Kota Pelayanan",
|
||||
"Alamat",
|
||||
"Latitude",
|
||||
"Longitude",
|
||||
{
|
||||
name: "Action",
|
||||
formatter: (cell) =>
|
||||
gridjs.html(`
|
||||
<div class="d-flex justify-content-center gap-2">
|
||||
<a href="/data/customers/${cell}/edit" class="btn btn-yellow btn-sm d-inline-flex align-items-center justify-content-center">
|
||||
<i class='bx bx-edit'></i>
|
||||
</a>
|
||||
<button data-id="${cell}" class="btn btn-sm btn-red btn-delete-customers d-inline-flex align-items-center justify-content-center">
|
||||
<i class='bx bxs-trash' ></i>
|
||||
</button>
|
||||
</div>
|
||||
`),
|
||||
},
|
||||
],
|
||||
pagination: {
|
||||
limit: 50,
|
||||
server: {
|
||||
url: (prev, page) =>
|
||||
`${prev}${prev.includes("?") ? "&" : "?"}page=${
|
||||
page + 1
|
||||
}`,
|
||||
},
|
||||
},
|
||||
sort: true,
|
||||
search: {
|
||||
server: {
|
||||
url: (prev, keyword) => `${prev}?search=${keyword}`,
|
||||
},
|
||||
},
|
||||
server: {
|
||||
url: `${GlobalConfig.apiHost}/api/customers`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
then: (data) =>
|
||||
data.data.map((item) => [
|
||||
item.id,
|
||||
item.nomor_pelanggan,
|
||||
item.nama,
|
||||
item.kota_pelayanan,
|
||||
item.alamat,
|
||||
item.latitude,
|
||||
item.longitude,
|
||||
item.id,
|
||||
]),
|
||||
total: (data) => data.meta.total,
|
||||
},
|
||||
}).render(tableContainer);
|
||||
}
|
||||
|
||||
async handleDelete(deleteButton) {
|
||||
const id = deleteButton.getAttribute("data-id");
|
||||
|
||||
const result = await Swal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "You won't be able to revert this!",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete it!",
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
let response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/customers/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
this.toastMessage.innerText =
|
||||
result.message || "Deleted successfully!";
|
||||
this.toast.show();
|
||||
|
||||
// Refresh Grid.js table
|
||||
if (typeof this.table !== "undefined") {
|
||||
this.table.updateConfig({}).forceRender();
|
||||
}
|
||||
} else {
|
||||
let error = await response.json();
|
||||
console.error("Delete failed:", error);
|
||||
this.toastMessage.innerText =
|
||||
error.message || "Delete failed!";
|
||||
this.toast.show();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting item:", error);
|
||||
this.toastMessage.innerText = "An error occurred!";
|
||||
this.toast.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new Customers();
|
||||
});
|
||||
78
resources/js/customers/upload.js
Normal file
78
resources/js/customers/upload.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Dropzone } from "dropzone";
|
||||
Dropzone.autoDiscover = false;
|
||||
|
||||
class UploadCustomers {
|
||||
constructor() {
|
||||
this.spatialDropzone = null;
|
||||
this.formElement = document.getElementById("formUploadCustomers");
|
||||
this.uploadButton = document.getElementById("submit-upload");
|
||||
this.spinner = document.getElementById("spinner");
|
||||
if (!this.formElement) {
|
||||
console.error("Element formUploadCustomers tidak ditemukan!");
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
this.initDropzone();
|
||||
this.setupUploadButton();
|
||||
}
|
||||
|
||||
initDropzone() {
|
||||
const toastNotification = document.getElementById("toastNotification");
|
||||
const toast = new bootstrap.Toast(toastNotification);
|
||||
var previewTemplate,
|
||||
dropzonePreviewNode = document.querySelector(
|
||||
"#dropzone-preview-list"
|
||||
);
|
||||
(dropzonePreviewNode.id = ""),
|
||||
dropzonePreviewNode &&
|
||||
((previewTemplate = dropzonePreviewNode.parentNode.innerHTML),
|
||||
dropzonePreviewNode.parentNode.removeChild(dropzonePreviewNode),
|
||||
(this.spatialDropzone = new Dropzone(".dropzone", {
|
||||
url: this.formElement.action,
|
||||
method: "post",
|
||||
acceptedFiles: ".xls,.xlsx",
|
||||
previewTemplate: previewTemplate,
|
||||
previewsContainer: "#dropzone-preview",
|
||||
autoProcessQueue: false,
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
},
|
||||
init: function () {
|
||||
this.on("success", function (file, response) {
|
||||
document.getElementById("toast-message").innerText =
|
||||
response.message;
|
||||
toast.show();
|
||||
setTimeout(() => {
|
||||
window.location.href = "/data/customers";
|
||||
}, 2000);
|
||||
});
|
||||
this.on("error", function (file, errorMessage) {
|
||||
document.getElementById("toast-message").innerText =
|
||||
errorMessage.message;
|
||||
toast.show();
|
||||
this.uploadButton.disabled = false;
|
||||
this.spinner.classList.add("d-none");
|
||||
});
|
||||
},
|
||||
})));
|
||||
}
|
||||
|
||||
setupUploadButton() {
|
||||
this.uploadButton.addEventListener("click", (e) => {
|
||||
if (this.spatialDropzone.files.length > 0) {
|
||||
this.spatialDropzone.processQueue();
|
||||
this.uploadButton.disabled = true;
|
||||
this.spinner.classList.remove("d-none");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new UploadCustomers().init();
|
||||
});
|
||||
@@ -1,167 +1,31 @@
|
||||
import Big from "big.js";
|
||||
import GlobalConfig, { addThousandSeparators } from "../global-config.js";
|
||||
import flatpickr from "flatpickr";
|
||||
import "flatpickr/dist/flatpickr.min.css";
|
||||
import InitDatePicker from "../utils/InitDatePicker.js";
|
||||
|
||||
class BigData {
|
||||
async init() {
|
||||
try {
|
||||
this.filterYear = new Date().getFullYear(); // Set initial year
|
||||
|
||||
let yearSelect = document.querySelector("#yearPicker");
|
||||
let filterButton = document.querySelector("#btnFilterYear");
|
||||
|
||||
if (!yearSelect || !filterButton) {
|
||||
console.error(
|
||||
"Element #yearPicker or #btnFilterYear not found."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set default value for input
|
||||
yearSelect.value = this.filterYear;
|
||||
|
||||
yearSelect.addEventListener("change", () => {
|
||||
this.updateYear(yearSelect.value);
|
||||
});
|
||||
|
||||
// Handle button click
|
||||
filterButton.addEventListener("click", () => {
|
||||
this.updateYear(yearSelect.value);
|
||||
});
|
||||
|
||||
console.log("init filter this year", this.filterYear);
|
||||
new InitDatePicker(
|
||||
"#datepicker-dashboard-bigdata",
|
||||
this.handleChangeDate.bind(this)
|
||||
).init();
|
||||
|
||||
// Load initial data
|
||||
await this.updateData(this.filterYear);
|
||||
this.updateData("latest");
|
||||
} catch (error) {
|
||||
console.error("Error initializing data:", error);
|
||||
}
|
||||
}
|
||||
updateYear(value) {
|
||||
let inputYear = parseInt(value, 10);
|
||||
if (!isNaN(inputYear)) {
|
||||
this.filterYear = inputYear;
|
||||
this.updateData(this.filterYear);
|
||||
} else {
|
||||
console.error("Invalid year input");
|
||||
}
|
||||
|
||||
handleChangeDate(filterDate) {
|
||||
if (!filterDate) return;
|
||||
this.updateData(filterDate);
|
||||
}
|
||||
async updateData(year) {
|
||||
async updateData(filterDate) {
|
||||
try {
|
||||
this.totalTargetPAD = await this.getDataSettings("TARGET_PAD");
|
||||
this.resultDataTotal = await this.getDataTotalPotensi(year);
|
||||
this.dataVerification = await this.getDataVerfication(year);
|
||||
this.dataNonVerification = await this.getDataNonVerfication(year);
|
||||
this.dataBusiness = await this.getDataBusiness(year);
|
||||
this.dataNonBusiness = await this.getDataNonBusiness(year);
|
||||
this.dataTataRuang = await this.getDataSettings("TATA_RUANG");
|
||||
this.dataSumRealisasiTerbit = await this.getDataSettings(
|
||||
"REALISASI_TERBIT_PBG_SUM"
|
||||
);
|
||||
this.dataCountRealisasiTerbit = await this.getDataSettings(
|
||||
"REALISASI_TERBIT_PBG_COUNT"
|
||||
);
|
||||
this.dataSumMenungguKlikDPMPTSP = await this.getDataSettings(
|
||||
"MENUNGGU_KLIK_DPMPTSP_SUM"
|
||||
);
|
||||
this.dataCountMenungguKlikDPMPTSP = await this.getDataSettings(
|
||||
"MENUNGGU_KLIK_DPMPTSP_COUNT"
|
||||
);
|
||||
this.dataSumProsesDinasTeknis = await this.getDataSettings(
|
||||
"PROSES_DINAS_TEKNIS_SUM"
|
||||
);
|
||||
this.dataCountProsesDinasTeknis = await this.getDataSettings(
|
||||
"PROSES_DINAS_TEKNIS_COUNT"
|
||||
);
|
||||
this.resumeBigData = await this.getBigDataResume(filterDate);
|
||||
|
||||
// total potensi
|
||||
this.bigTargetPAD = new Big(this.totalTargetPAD ?? 0);
|
||||
this.bigTotalPotensi = new Big(this.resultDataTotal.totalData ?? 0);
|
||||
|
||||
this.resultPercentage = 0;
|
||||
if (this.bigTotalPotensi > 0 && this.bigTargetPAD > 0) {
|
||||
this.resultPercentage = this.bigTotalPotensi
|
||||
.div(this.bigTargetPAD)
|
||||
.times(100)
|
||||
.toFixed(2);
|
||||
if (this.resultPercentage > 100) {
|
||||
this.resultPercentage = 100;
|
||||
}
|
||||
}
|
||||
|
||||
// tata ruang
|
||||
this.bigTotalTataRuang = new Big(this.dataTataRuang);
|
||||
this.percentageResultTataRuang =
|
||||
this.bigTotalTataRuang <= 0 || this.bigTotalPotensi <= 0
|
||||
? 0
|
||||
: this.bigTotalTataRuang
|
||||
.div(this.bigTotalPotensi)
|
||||
.times(100)
|
||||
.toFixed(2);
|
||||
|
||||
// kekurangan potensi
|
||||
this.totalKekuranganPotensi = new Big(
|
||||
this.bigTargetPAD - this.bigTotalPotensi
|
||||
);
|
||||
|
||||
this.percentageKekuranganPotensi =
|
||||
this.totalKekuranganPotensi <= 0 || this.bigTargetPAD <= 0
|
||||
? 0
|
||||
: this.totalKekuranganPotensi
|
||||
.div(this.bigTargetPAD)
|
||||
.times(100)
|
||||
.toFixed(2);
|
||||
|
||||
// non-verification documents
|
||||
this.bigTotalNonVerification = new Big(
|
||||
this.dataNonVerification.total
|
||||
);
|
||||
this.percentageResultNonVerification =
|
||||
this.bigTotalNonVerification <= 0 || this.bigTotalPotensi <= 0
|
||||
? 0
|
||||
: this.bigTotalNonVerification
|
||||
.div(this.bigTotalPotensi)
|
||||
.times(100)
|
||||
.toFixed(2);
|
||||
|
||||
// verification documents
|
||||
this.bigTotalVerification = new Big(this.dataVerification.total);
|
||||
this.percetageResultVerification =
|
||||
this.bigTotalVerification <= 0 || this.bigTotalPotensi <= 0
|
||||
? 0
|
||||
: this.bigTotalVerification
|
||||
.div(this.bigTargetPAD)
|
||||
.times(100)
|
||||
.toFixed(2);
|
||||
|
||||
// business documents
|
||||
this.bigTotalBusiness = new Big(this.dataBusiness.total);
|
||||
this.percentageResultBusiness =
|
||||
this.bigTotalNonVerification <= 0 || this.bigTotalBusiness <= 0
|
||||
? 0
|
||||
: this.bigTotalBusiness
|
||||
.div(this.bigTotalNonVerification)
|
||||
.times(100)
|
||||
.toFixed(2);
|
||||
|
||||
// non-business documents
|
||||
this.bigTotalNonBusiness = new Big(this.dataNonBusiness.total);
|
||||
this.percentageResultNonBusiness =
|
||||
this.bigTotalNonBusiness <= 0 ||
|
||||
this.bigTotalNonVerification <= 0
|
||||
? 0
|
||||
: this.bigTotalNonBusiness
|
||||
.div(this.bigTotalNonVerification)
|
||||
.times(100)
|
||||
.toFixed(2);
|
||||
|
||||
if (!this.bigTargetPAD) {
|
||||
console.error("Failed to load chart data");
|
||||
return;
|
||||
}
|
||||
|
||||
this.initChartTargetPAD();
|
||||
this.initChartTargetPAD(filterDate);
|
||||
this.initChartUsaha();
|
||||
this.initChartNonUsaha();
|
||||
this.initChartTotalPotensi();
|
||||
@@ -177,10 +41,10 @@ class BigData {
|
||||
}
|
||||
}
|
||||
|
||||
async getDataTotalPotensi(year) {
|
||||
async getBigDataResume(filterByDate) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/all-task-documents?year=${year}`,
|
||||
`${GlobalConfig.apiHost}/api/bigdata-resume?filterByDate=${filterByDate}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
@@ -198,169 +62,23 @@ class BigData {
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
countData: data.data.count,
|
||||
totalData: data.data.total,
|
||||
};
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async getDataVerfication(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/verification-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']")
|
||||
.content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
count: data.data.count,
|
||||
total: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getDataNonVerfication(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/non-verification-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']")
|
||||
.content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
count: data.data.count,
|
||||
total: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getDataBusiness(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/business-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']")
|
||||
.content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
count: data.data.count,
|
||||
total: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getDataNonBusiness(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/non-business-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']")
|
||||
.content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
count: data.data.count,
|
||||
total: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getDataSettings(string_key) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/api-data-settings?search=${string_key}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']")
|
||||
.content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.data[0].value;
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
initChartTargetPAD() {
|
||||
initChartTargetPAD(filterDate) {
|
||||
const year =
|
||||
filterDate === "latest"
|
||||
? new Date().getFullYear()
|
||||
: new Date(filterDate).getFullYear();
|
||||
document
|
||||
.querySelectorAll(".document-title.chart-target-pad")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Target PAD ${year}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-target-pad")
|
||||
.forEach((element) => {
|
||||
@@ -370,53 +88,59 @@ class BigData {
|
||||
.querySelectorAll(".document-total.chart-target-pad")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.bigTargetPAD.toString()
|
||||
this.resumeBigData.target_pad.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-target-pad")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${100}%`;
|
||||
element.innerText = `${this.resumeBigData.target_pad.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartTotalPotensi() {
|
||||
const countAll = this.resultDataTotal.countData ?? 0;
|
||||
// const countAll = this.resultDataTotal.countData ?? 0;
|
||||
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-total-potensi")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${countAll}`;
|
||||
// element.innerText = `${countAll}`;
|
||||
element.innerText = `${this.resumeBigData.total_potensi.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-total.chart-total-potensi")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.bigTotalPotensi.toString()
|
||||
// this.bigTotalPotensi.toString()
|
||||
this.resumeBigData.total_potensi.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-total-potensi")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.resultPercentage}%`;
|
||||
// element.innerText = `${this.resultPercentage}%`;
|
||||
element.innerText = `${this.resumeBigData.total_potensi.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartVerificationDocuments() {
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-berkas-terverifikasi")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.dataVerification.count}`;
|
||||
// element.innerText = `${this.dataVerification.count}`;
|
||||
element.innerText = `${this.resumeBigData.verified_document.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-total.chart-berkas-terverifikasi")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.bigTotalVerification.toString()
|
||||
// this.bigTotalVerification.toString()
|
||||
this.resumeBigData.verified_document.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-berkas-terverifikasi")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.percetageResultVerification}%`;
|
||||
// element.innerText = `${this.percetageResultVerification}%`;
|
||||
element.innerText = `${this.resumeBigData.verified_document.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartNonVerificationDocuments() {
|
||||
@@ -425,7 +149,8 @@ class BigData {
|
||||
".document-count.chart-berkas-belum-terverifikasi"
|
||||
)
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.dataNonVerification.count}`;
|
||||
// element.innerText = `${this.dataNonVerification.count}`;
|
||||
element.innerText = `${this.resumeBigData.non_verified_document.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(
|
||||
@@ -433,7 +158,8 @@ class BigData {
|
||||
)
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.bigTotalNonVerification.toString()
|
||||
// this.bigTotalNonVerification.toString()
|
||||
this.resumeBigData.non_verified_document.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
@@ -441,45 +167,52 @@ class BigData {
|
||||
".small-percentage.chart-berkas-belum-terverifikasi"
|
||||
)
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.percentageResultNonVerification}%`;
|
||||
// element.innerText = `${this.percentageResultNonVerification}%`;
|
||||
element.innerText = `${this.resumeBigData.non_verified_document.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartUsaha() {
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-business")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.dataBusiness.count}`;
|
||||
// element.innerText = `${this.dataBusiness.count}`;
|
||||
element.innerText = `${this.resumeBigData.business_document.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-total.chart-business")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.bigTotalBusiness.toString()
|
||||
// this.bigTotalBusiness.toString()
|
||||
this.resumeBigData.business_document.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-business")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.percentageResultBusiness}%`;
|
||||
// element.innerText = `${this.percentageResultBusiness}%`;
|
||||
element.innerText = `${this.resumeBigData.business_document.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartNonUsaha() {
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-non-business")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.dataNonBusiness.count}`;
|
||||
// element.innerText = `${this.dataNonBusiness.count}`;
|
||||
element.innerText = `${this.resumeBigData.non_business_document.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-total.chart-non-business")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.bigTotalNonBusiness.toString()
|
||||
// this.bigTotalNonBusiness.toString()
|
||||
this.resumeBigData.non_business_document.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-non-business")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.percentageResultNonBusiness}%`;
|
||||
// element.innerText = `${this.percentageResultNonBusiness}%`;
|
||||
element.innerText = `${this.resumeBigData.non_business_document.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartKekuranganPotensi() {
|
||||
@@ -492,89 +225,97 @@ class BigData {
|
||||
.querySelectorAll(".document-total.chart-kekurangan-potensi")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.totalKekuranganPotensi.toString()
|
||||
// this.totalKekuranganPotensi.toString()
|
||||
this.resumeBigData.kekurangan_potensi.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-kekurangan-potensi")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.percentageKekuranganPotensi}%`;
|
||||
// element.innerText = `${this.percentageKekuranganPotensi}%`;
|
||||
element.innerText = `${this.resumeBigData.kekurangan_potensi.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartRealisasiTerbitPBG() {
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-realisasi-tebit-pbg")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.dataCountRealisasiTerbit}`;
|
||||
// element.innerText = `${this.dataCountRealisasiTerbit}`;
|
||||
element.innerText = `${this.resumeBigData.realisasi_terbit.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-total.chart-realisasi-tebit-pbg")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.dataSumRealisasiTerbit
|
||||
// this.dataSumRealisasiTerbit
|
||||
this.resumeBigData.realisasi_terbit.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-realisasi-tebit-pbg")
|
||||
.forEach((element) => {
|
||||
element.innerText = `0.00%`;
|
||||
element.innerText = `${this.resumeBigData.realisasi_terbit.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartMenungguKlikDPMPTSP() {
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-menunggu-klik-dpmptsp")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.dataCountMenungguKlikDPMPTSP}`;
|
||||
// element.innerText = `${this.dataCountMenungguKlikDPMPTSP}`;
|
||||
element.innerText = `${this.resumeBigData.menunggu_klik_dpmptsp.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-total.chart-menunggu-klik-dpmptsp")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.dataSumMenungguKlikDPMPTSP
|
||||
// this.dataSumMenungguKlikDPMPTSP
|
||||
this.resumeBigData.menunggu_klik_dpmptsp.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-menunggu-klik-dpmptsp")
|
||||
.forEach((element) => {
|
||||
element.innerText = `0.00%`;
|
||||
element.innerText = `${this.resumeBigData.menunggu_klik_dpmptsp.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartProsesDinasTeknis() {
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-proses-dinas-teknis")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.dataCountProsesDinasTeknis}`;
|
||||
// element.innerText = `${this.dataCountProsesDinasTeknis}`;
|
||||
element.innerText = `${this.resumeBigData.proses_dinas_teknis.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-total.chart-proses-dinas-teknis")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.dataSumProsesDinasTeknis
|
||||
// this.dataSumProsesDinasTeknis
|
||||
this.resumeBigData.proses_dinas_teknis.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-proses-dinas-teknis")
|
||||
.forEach((element) => {
|
||||
element.innerText = `0.00%`;
|
||||
element.innerText = `${this.resumeBigData.proses_dinas_teknis.percentage}%`;
|
||||
});
|
||||
}
|
||||
initChartPotensiTataRuang() {
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-potensi-tata-ruang")
|
||||
.forEach((element) => {
|
||||
element.innerText = "";
|
||||
element.innerText = `${this.resumeBigData.tata_ruang.count}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".document-total.chart-potensi-tata-ruang")
|
||||
.forEach((element) => {
|
||||
element.innerText = `Rp.${addThousandSeparators(
|
||||
this.bigTotalTataRuang.toString()
|
||||
this.resumeBigData.tata_ruang.sum.toString()
|
||||
)}`;
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".small-percentage.chart-potensi-tata-ruang")
|
||||
.forEach((element) => {
|
||||
element.innerText = `${this.percentageResultTataRuang}%`;
|
||||
element.innerText = `${this.resumeBigData.tata_ruang.percentage}%`;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,55 @@
|
||||
import Big from "big.js";
|
||||
import GlobalConfig, { addThousandSeparators } from "../global-config.js";
|
||||
import InitDatePicker from "../utils/InitDatePicker.js";
|
||||
|
||||
class LackOfPotential {
|
||||
async init() {
|
||||
new InitDatePicker(
|
||||
"#datepicker-lack-of-potential",
|
||||
this.handleChangedDate.bind(this)
|
||||
).init();
|
||||
this.bigTotalLackPotential = 0;
|
||||
this.totalPotensi = await this.getDataTotalPotensi(2025);
|
||||
this.totalPotensi = await this.getDataTotalPotensi("latest");
|
||||
this.totalTargetPAD = await this.getDataSettings("TARGET_PAD");
|
||||
this.allCountData = await this.getValueDashboard();
|
||||
this.reklameCount = this.allCountData.total_reklame ?? 0;
|
||||
this.pdamCount = this.allCountData.total_pdam ?? 0;
|
||||
this.tataRuangCount = this.allCountData.total_tata_ruang ?? 0;
|
||||
|
||||
let dataReportTourism = this.allCountData.data_report;
|
||||
|
||||
this.totalVilla = dataReportTourism
|
||||
.filter((item) => item.kbli_title.toLowerCase() === "vila")
|
||||
.reduce((sum, item) => sum + item.total_records, 0);
|
||||
this.totalRestoran = dataReportTourism
|
||||
.filter((item) => item.kbli_title.toLowerCase() === "restoran")
|
||||
.reduce((sum, item) => sum + item.total_records, 0);
|
||||
this.totalPariwisata = dataReportTourism.reduce(
|
||||
(sum, item) => sum + item.total_records,
|
||||
0
|
||||
);
|
||||
|
||||
this.bigTargetPAD = new Big(this.totalTargetPAD ?? 0);
|
||||
this.bigTotalPotensi = new Big(this.totalPotensi.totalData ?? 0);
|
||||
this.bigTotalLackPotential = this.bigTargetPAD - this.bigTotalPotensi;
|
||||
this.bigTotalPotensi = new Big(this.totalPotensi.total ?? 0);
|
||||
this.bigTotalLackPotential = this.bigTargetPAD.minus(
|
||||
this.bigTotalPotensi
|
||||
);
|
||||
this.initChartKekuranganPotensi();
|
||||
this.initDataValueDashboard();
|
||||
}
|
||||
async handleChangedDate(filterDate) {
|
||||
const totalPotensi = await this.getDataTotalPotensi(filterDate);
|
||||
this.bigTotalPotensi = new Big(totalPotensi.total ?? 0);
|
||||
this.bigTotalLackPotential = this.bigTargetPAD.minus(
|
||||
this.bigTotalPotensi
|
||||
);
|
||||
|
||||
this.initChartKekuranganPotensi();
|
||||
}
|
||||
async getDataTotalPotensi(year) {
|
||||
async getDataTotalPotensi(filterDate) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/all-task-documents?year=${year}`,
|
||||
`${GlobalConfig.apiHost}/api/bigdata-resume?filterByDate=${filterDate}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
@@ -34,8 +68,7 @@ class LackOfPotential {
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
countData: data.data.count,
|
||||
totalData: data.data.total,
|
||||
total: data.total_potensi.sum,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
@@ -45,7 +78,7 @@ class LackOfPotential {
|
||||
async getDataSettings(string_key) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/api-data-settings?search=${string_key}`,
|
||||
`${GlobalConfig.apiHost}/api/data-settings?search=${string_key}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
@@ -69,6 +102,33 @@ class LackOfPotential {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
async getValueDashboard() {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/dashboard-potential-count`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']")
|
||||
.content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
initChartKekuranganPotensi() {
|
||||
document
|
||||
.querySelectorAll(".document-count.chart-lack-of-potential")
|
||||
@@ -88,6 +148,21 @@ class LackOfPotential {
|
||||
element.innerText = ``;
|
||||
});
|
||||
}
|
||||
initDataValueDashboard() {
|
||||
document.getElementById("reklame-count").innerText = this.reklameCount;
|
||||
document.getElementById("pdam-count").innerText = this.pdamCount;
|
||||
document.getElementById("pbb-bangunan-count").innerText =
|
||||
this.tataRuangCount;
|
||||
document.getElementById("tata-ruang-count").innerText =
|
||||
this.tataRuangCount;
|
||||
document.getElementById("tata-ruang-usaha-count").innerText =
|
||||
this.tataRuangCount;
|
||||
document.getElementById("restoran-count").innerText =
|
||||
this.totalRestoran;
|
||||
document.getElementById("villa-count").innerText = this.totalVilla;
|
||||
document.getElementById("pariwisata-count").innerText =
|
||||
this.totalPariwisata;
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", async function (e) {
|
||||
await new LackOfPotential().init();
|
||||
|
||||
543
resources/js/dashboards/pbg.js
Normal file
543
resources/js/dashboards/pbg.js
Normal file
@@ -0,0 +1,543 @@
|
||||
import Big from "big.js";
|
||||
import GlobalConfig, { addThousandSeparators } from "../global-config.js";
|
||||
import ApexCharts from "apexcharts";
|
||||
import "gridjs/dist/gridjs.umd.js";
|
||||
import GeneralTable from "../table-generator.js";
|
||||
|
||||
var chart;
|
||||
document.addEventListener("DOMContentLoaded", async function () {
|
||||
await initChart();
|
||||
const yearPicker = document.getElementById("yearPicker");
|
||||
|
||||
async function updateDataByYear(selectedYear) {
|
||||
// Target PAD Element
|
||||
const targetPadElement = document.getElementById("target-pad");
|
||||
if (!targetPadElement) return;
|
||||
const targetPadValue = await getDataSettings("TARGET_PAD");
|
||||
targetPadElement.textContent = formatCurrency(targetPadValue);
|
||||
|
||||
// Total Potensi Berkas
|
||||
const totalPotensiBerkas = document.getElementById(
|
||||
"total-potensi-berkas"
|
||||
);
|
||||
if (!totalPotensiBerkas) return;
|
||||
const totalPotensiBerkasValue = await getDataTotalPotensi(selectedYear);
|
||||
totalPotensiBerkas.textContent = formatCurrency(
|
||||
totalPotensiBerkasValue.totalData
|
||||
);
|
||||
|
||||
// Total Berkas Terverifikasi
|
||||
const totalBerkasTerverifikasi = document.getElementById(
|
||||
"total-berkas-terverifikasi"
|
||||
);
|
||||
if (!totalBerkasTerverifikasi) return;
|
||||
const totalBerkasTerverifikasiValue = await getDataVerification(
|
||||
selectedYear
|
||||
);
|
||||
totalBerkasTerverifikasi.textContent = formatCurrency(
|
||||
totalBerkasTerverifikasiValue.totalData
|
||||
);
|
||||
|
||||
// Total Kekurangan potensi
|
||||
const totalKekuranganPotensi = document.getElementById(
|
||||
"total-kekurangan-potensi"
|
||||
);
|
||||
if (!totalKekuranganPotensi) return;
|
||||
const totalKekuranganPotensiValue =
|
||||
new Big(targetPadValue) -
|
||||
new Big(totalPotensiBerkasValue.totalData);
|
||||
totalKekuranganPotensi.textContent = formatCurrency(
|
||||
totalKekuranganPotensiValue
|
||||
);
|
||||
|
||||
// Total Potensi PBG dari tata ruang
|
||||
const totalPotensiPBGTataRuang = document.getElementById(
|
||||
"total-potensi-pbd-tata-ruang"
|
||||
);
|
||||
if (!totalPotensiPBGTataRuang) return;
|
||||
const totalPotensiPBGTataRuangValue = await getDataSettings(
|
||||
"TATA_RUANG"
|
||||
);
|
||||
totalPotensiPBGTataRuang.textContent = formatCurrency(
|
||||
totalPotensiPBGTataRuangValue
|
||||
);
|
||||
|
||||
// Total Berkas Belum terverifikasi
|
||||
const totalBerkasBelumTerverifikasi = document.getElementById(
|
||||
"total-berkas-belum-terverifikasi"
|
||||
);
|
||||
if (!totalBerkasBelumTerverifikasi) return;
|
||||
const totalBerkasBelumTerverifikasiValue = await getDataNonVerification(
|
||||
selectedYear
|
||||
);
|
||||
const totalBerkasBelumTerverifikasiCount =
|
||||
totalBerkasBelumTerverifikasiValue.countData;
|
||||
totalBerkasBelumTerverifikasi.textContent = formatCurrency(
|
||||
totalBerkasBelumTerverifikasiValue.totalData
|
||||
);
|
||||
|
||||
// Total Berkas Usaha
|
||||
const totalBerkasUsahaValue = await getDataBusiness(selectedYear);
|
||||
const totalBerkasUsahaCount = totalBerkasUsahaValue.countData;
|
||||
const totalBerkasUsahaTotalData = totalBerkasUsahaValue.totalData;
|
||||
|
||||
// Total Berkas Non Usaha
|
||||
const totalBerkasNonUsahaValue = await getDataNonBusiness(selectedYear);
|
||||
const totalBerkasNonUsahaCount = totalBerkasNonUsahaValue.countData;
|
||||
const totalBerkasNonUsahaTotalData = totalBerkasNonUsahaValue.totalData;
|
||||
|
||||
// Pie Chart Section
|
||||
let persenUsaha =
|
||||
totalBerkasBelumTerverifikasiCount > 0
|
||||
? (
|
||||
(totalBerkasUsahaCount /
|
||||
totalBerkasBelumTerverifikasiCount) *
|
||||
100
|
||||
).toFixed(2)
|
||||
: "0";
|
||||
|
||||
let persenNonUsaha =
|
||||
totalBerkasBelumTerverifikasiCount > 0
|
||||
? (
|
||||
(totalBerkasNonUsahaCount /
|
||||
totalBerkasBelumTerverifikasiCount) *
|
||||
100
|
||||
).toFixed(2)
|
||||
: "0";
|
||||
|
||||
const dataSeriesPieChart = [
|
||||
Number(persenUsaha),
|
||||
Number(persenNonUsaha),
|
||||
];
|
||||
const labelsPieChart = ["Berkas Usaha", "Berkas Non Usaha"];
|
||||
document.querySelector("td[data-category='non-usaha']").textContent =
|
||||
formatCurrency(totalBerkasNonUsahaTotalData).toLocaleString();
|
||||
document.querySelector(
|
||||
"td[data-category='non-usaha-percentage']"
|
||||
).textContent = persenNonUsaha + "%";
|
||||
|
||||
document.querySelector("td[data-category='usaha']").textContent =
|
||||
formatCurrency(totalBerkasUsahaTotalData).toLocaleString();
|
||||
document.querySelector(
|
||||
"td[data-category='usaha-percentage']"
|
||||
).textContent = persenUsaha + "%";
|
||||
|
||||
updatePieChart(dataSeriesPieChart, labelsPieChart);
|
||||
|
||||
// Load all Tourism location
|
||||
const allLocation = await getAllLocation();
|
||||
console.log(allLocation);
|
||||
|
||||
// Filter hanya data yang memiliki angka valid
|
||||
let validLocations = allLocation.dataLocation.filter((loc) => {
|
||||
return (
|
||||
!isNaN(parseFloat(loc.longitude)) &&
|
||||
!isNaN(parseFloat(loc.latitude))
|
||||
);
|
||||
});
|
||||
|
||||
// Ubah string ke float
|
||||
validLocations = validLocations.map((loc) => ({
|
||||
name: loc.project_name,
|
||||
longitude: parseFloat(loc.longitude),
|
||||
latitude: parseFloat(loc.latitude),
|
||||
}));
|
||||
|
||||
console.log(validLocations.name);
|
||||
|
||||
// Inisialisasi peta
|
||||
var map = L.map("map").setView([-7.023, 107.5275], 10);
|
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||
attribution: "© OpenStreetMap contributors",
|
||||
}).addTo(map);
|
||||
|
||||
// Tambahkan marker ke peta
|
||||
validLocations.forEach(function (loc) {
|
||||
L.marker([loc.latitude, loc.longitude])
|
||||
.addTo(map)
|
||||
.bindPopup(`<b>${loc.name}</b>`) // Popup saat diklik
|
||||
.bindTooltip(loc.name, { permanent: false, direction: "top" }); // Tooltip saat di-hover
|
||||
});
|
||||
|
||||
// Realisasi terbit PBG
|
||||
const totalRealisasiTerbitPBG = document.getElementById(
|
||||
"realisasi-terbit-pbg"
|
||||
);
|
||||
if (!totalRealisasiTerbitPBG) return;
|
||||
const totalRealisasiTerbitPBGValue = await getDataSettings(
|
||||
"REALISASI_TERBIT_PBG_SUM"
|
||||
);
|
||||
totalRealisasiTerbitPBG.textContent = formatCurrency(
|
||||
totalRealisasiTerbitPBGValue
|
||||
);
|
||||
|
||||
// Menunggu Klik DPMPTSP
|
||||
const totalMenungguKlikDpmptsp = document.getElementById(
|
||||
"waiting-click-dpmptsp"
|
||||
);
|
||||
if (!totalMenungguKlikDpmptsp) return;
|
||||
const totalMenungguKlikDpmptspValue = await getDataSettings(
|
||||
"MENUNGGU_KLIK_DPMPTSP_SUM"
|
||||
);
|
||||
totalMenungguKlikDpmptsp.textContent = formatCurrency(
|
||||
totalMenungguKlikDpmptspValue
|
||||
);
|
||||
|
||||
// Proses Dinas Teknis
|
||||
const totalProsesDinasTeknis = document.getElementById(
|
||||
"processing-technical-services"
|
||||
);
|
||||
if (!totalProsesDinasTeknis) return;
|
||||
const totalProsesDinasTeknisValue = await getDataSettings(
|
||||
"PROSES_DINAS_TEKNIS_SUM"
|
||||
);
|
||||
totalProsesDinasTeknis.textContent = formatCurrency(
|
||||
totalProsesDinasTeknisValue
|
||||
);
|
||||
|
||||
// Load Tabel Baru di Update
|
||||
const tableLastUpdated = new GeneralTable(
|
||||
"pbg-filter-by-updated-at",
|
||||
`${GlobalConfig.apiHost}/api/api-pbg-task?isLastUpdated=true`,
|
||||
`${GlobalConfig.apiHost}`,
|
||||
pbgTaskColumns
|
||||
);
|
||||
|
||||
tableLastUpdated.processData = function (data) {
|
||||
console.log("Response Data:", data);
|
||||
return data.data.map((item) => {
|
||||
return [
|
||||
item.no,
|
||||
item.name,
|
||||
item.registration_number,
|
||||
item.document_number,
|
||||
item.address,
|
||||
];
|
||||
});
|
||||
};
|
||||
|
||||
tableLastUpdated.init();
|
||||
|
||||
// Load Tabel Status SK Terbit
|
||||
const tableSKPBGTerbit = new GeneralTable(
|
||||
"pbg-filter-by-status",
|
||||
`${GlobalConfig.apiHost}/api/api-pbg-task?isLastUpdated=false`,
|
||||
`${GlobalConfig.apiHost}`,
|
||||
pbgTaskColumns
|
||||
);
|
||||
|
||||
tableSKPBGTerbit.processData = function (data) {
|
||||
console.log("Response Data:", data);
|
||||
return data.data.map((item) => {
|
||||
return [
|
||||
item.no,
|
||||
item.name,
|
||||
item.registration_number,
|
||||
item.document_number,
|
||||
item.address,
|
||||
];
|
||||
});
|
||||
};
|
||||
|
||||
tableSKPBGTerbit.init();
|
||||
|
||||
document.querySelector(
|
||||
"#pbg-filter-by-updated-at .gridjs-search"
|
||||
).hidden = true;
|
||||
document.querySelector(
|
||||
"#pbg-filter-by-updated-at .gridjs-footer"
|
||||
).hidden = true;
|
||||
document.querySelector(
|
||||
"#pbg-filter-by-status .gridjs-search"
|
||||
).hidden = true;
|
||||
document.querySelector(
|
||||
"#pbg-filter-by-status .gridjs-footer"
|
||||
).hidden = true;
|
||||
}
|
||||
|
||||
await updateDataByYear(yearPicker.value);
|
||||
|
||||
yearPicker.addEventListener("change", async function () {
|
||||
console.log("event change dropdown");
|
||||
await updateDataByYear(yearPicker.value);
|
||||
});
|
||||
});
|
||||
|
||||
async function getDataSettings(string_key) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/data-settings?search=${string_key}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']").content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.data?.[0]?.value ?? 0; // Pastikan tidak error jika data kosong
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function getDataTotalPotensi(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/all-task-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']").content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
totalData: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function getDataVerification(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/verification-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']").content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
totalData: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function getDataNonVerification(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/non-verification-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']").content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
countData: data.data.count,
|
||||
totalData: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function getDataBusiness(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/business-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']").content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return {
|
||||
countData: data.data.count,
|
||||
totalData: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function getDataNonBusiness(year) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/non-business-documents?year=${year}`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']").content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
const data = await response.json();
|
||||
return {
|
||||
countData: data.data.count,
|
||||
totalData: data.data.total,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function getAllLocation() {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/get-all-location`,
|
||||
{
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${
|
||||
document.querySelector("meta[name='api-token']").content
|
||||
}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
console.error("Network response was not ok", response);
|
||||
}
|
||||
const data = await response.json();
|
||||
return {
|
||||
dataLocation: data.data,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching chart data:", error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function initChart() {
|
||||
var options = {
|
||||
chart: {
|
||||
height: 180,
|
||||
type: "donut",
|
||||
},
|
||||
series: [0, 0], // Inisialisasi dengan nilai awal
|
||||
labels: ["Berkas Usaha", "Berkas Non Usaha"],
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
stroke: {
|
||||
width: 0,
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
donut: {
|
||||
size: "60%",
|
||||
},
|
||||
},
|
||||
},
|
||||
colors: ["#7e67fe", "#17c553"],
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: {
|
||||
width: 200,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
fill: {
|
||||
type: "gradient",
|
||||
},
|
||||
};
|
||||
|
||||
chart = new ApexCharts(document.querySelector("#conversions"), options);
|
||||
chart.render();
|
||||
}
|
||||
|
||||
async function updatePieChart(dataSeries, labels) {
|
||||
if (!Array.isArray(dataSeries) || dataSeries.length === 0) {
|
||||
console.error("Data series tidak valid:", dataSeries);
|
||||
return;
|
||||
}
|
||||
|
||||
// Perbarui data series chart
|
||||
chart.updateSeries(dataSeries);
|
||||
|
||||
// Perbarui label jika diperlukan
|
||||
if (Array.isArray(labels) && labels.length === dataSeries.length) {
|
||||
chart.updateOptions({
|
||||
labels: labels,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fungsi untuk format angka ke Rupiah
|
||||
function formatCurrency(number) {
|
||||
return new Intl.NumberFormat("id-ID", {
|
||||
style: "currency",
|
||||
currency: "IDR",
|
||||
minimumFractionDigits: 0,
|
||||
}).format(number);
|
||||
}
|
||||
|
||||
const pbgTaskColumns = [
|
||||
"No",
|
||||
"Name",
|
||||
"Nomor Registrasi",
|
||||
"Nomor Dokumen",
|
||||
"Alamat",
|
||||
];
|
||||
@@ -24,10 +24,9 @@ document.addEventListener("DOMContentLoaded", function (e) {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"X-CSRF-TOKEN": document
|
||||
.querySelector('meta[name="csrf-token"]')
|
||||
.getAttribute("content"),
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
@@ -35,7 +34,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
document.getElementById("toast-message").innerText =
|
||||
result.message;
|
||||
result.data.message;
|
||||
toast.show();
|
||||
setTimeout(() => {
|
||||
window.location.href = "/data-settings";
|
||||
@@ -46,6 +45,8 @@ document.addEventListener("DOMContentLoaded", function (e) {
|
||||
error.message;
|
||||
toast.show();
|
||||
console.error("Error:", error);
|
||||
submitButton.disabled = false;
|
||||
spinner.classList.add("d-none");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Request failed:", error);
|
||||
|
||||
@@ -2,46 +2,34 @@ import { Grid } from "gridjs/dist/gridjs.umd.js";
|
||||
import gridjs from "gridjs/dist/gridjs.umd.js";
|
||||
import "gridjs/dist/gridjs.umd.js";
|
||||
import GlobalConfig from "../global-config.js";
|
||||
import Swal from "sweetalert2";
|
||||
|
||||
class DataSettings {
|
||||
constructor() {
|
||||
this.table = null; // Store Grid.js instance
|
||||
this.toastMessage = document.getElementById("toast-message");
|
||||
this.toastElement = document.getElementById("toastNotification");
|
||||
this.toast = new bootstrap.Toast(this.toastElement);
|
||||
this.table = null;
|
||||
|
||||
// Initialize functions
|
||||
this.initTableDataSettings();
|
||||
this.initEvents();
|
||||
}
|
||||
init() {
|
||||
this.getFetchApiData();
|
||||
initEvents() {
|
||||
document.body.addEventListener("click", async (event) => {
|
||||
const deleteButton = event.target.closest(
|
||||
".btn-delete-data-settings"
|
||||
);
|
||||
if (deleteButton) {
|
||||
event.preventDefault();
|
||||
await this.handleDelete(deleteButton);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getFetchApiData() {
|
||||
initTableDataSettings() {
|
||||
let tableContainer = document.getElementById("table-data-settings");
|
||||
|
||||
if (this.table) {
|
||||
// If table exists, update its data instead of recreating
|
||||
this.table
|
||||
.updateConfig({
|
||||
server: {
|
||||
url: `${GlobalConfig.apiHost}/api/api-data-settings`,
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
then: (data) =>
|
||||
data.data.map((item) => [
|
||||
item.id,
|
||||
item.key,
|
||||
item.value,
|
||||
item.created_at,
|
||||
item.id,
|
||||
]),
|
||||
total: (data) => data.meta.total,
|
||||
},
|
||||
})
|
||||
.forceRender();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new Grid.js instance only if it doesn't exist
|
||||
this.table = new Grid({
|
||||
columns: [
|
||||
"ID",
|
||||
@@ -65,11 +53,6 @@ class DataSettings {
|
||||
},
|
||||
},
|
||||
],
|
||||
search: {
|
||||
server: {
|
||||
url: (prev, keyword) => `${prev}?search=${keyword}`,
|
||||
},
|
||||
},
|
||||
pagination: {
|
||||
limit: 15,
|
||||
server: {
|
||||
@@ -80,8 +63,13 @@ class DataSettings {
|
||||
},
|
||||
},
|
||||
sort: true,
|
||||
search: {
|
||||
server: {
|
||||
url: (prev, keyword) => `${prev}?search=${keyword}`,
|
||||
},
|
||||
},
|
||||
server: {
|
||||
url: `${GlobalConfig.apiHost}/api/api-data-settings`,
|
||||
url: `${GlobalConfig.apiHost}/api/data-settings`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
@@ -99,94 +87,26 @@ class DataSettings {
|
||||
total: (data) => data.meta.total,
|
||||
},
|
||||
}).render(tableContainer);
|
||||
|
||||
document.addEventListener("click", this.handleDelete.bind(this));
|
||||
}
|
||||
handleDelete(event) {
|
||||
if (event.target.classList.contains("btn-delete-data-settings")) {
|
||||
event.preventDefault();
|
||||
const id = event.target.getAttribute("data-id");
|
||||
let modalElement = document.getElementById("modalConfirmation");
|
||||
let toastMessage = document.getElementById("toast-message");
|
||||
async handleDelete(deleteButton) {
|
||||
const id = deleteButton.getAttribute("data-id");
|
||||
|
||||
if (!modalElement) {
|
||||
console.error("Modal element not found!");
|
||||
return;
|
||||
}
|
||||
const result = await Swal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "You won't be able to revert this!",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#3085d6",
|
||||
cancelButtonColor: "#d33",
|
||||
confirmButtonText: "Yes, delete it!",
|
||||
});
|
||||
|
||||
let modal = new bootstrap.Modal(modalElement);
|
||||
let btnSaveConfirmation = document.getElementById(
|
||||
"btnSaveConfirmation"
|
||||
);
|
||||
let toastElement = document.getElementById("toastNotification");
|
||||
let toast = new bootstrap.Toast(toastElement);
|
||||
|
||||
// Remove previous event listeners to avoid multiple bindings
|
||||
btnSaveConfirmation.replaceWith(
|
||||
btnSaveConfirmation.cloneNode(true)
|
||||
);
|
||||
btnSaveConfirmation = document.getElementById(
|
||||
"btnSaveConfirmation"
|
||||
);
|
||||
|
||||
// Set the role ID on the confirm button inside the modal
|
||||
btnSaveConfirmation.setAttribute("data-settings-id", id);
|
||||
|
||||
// Show the modal
|
||||
modal.show();
|
||||
|
||||
btnSaveConfirmation.addEventListener("click", async () => {
|
||||
let dataSettingId =
|
||||
btnSaveConfirmation.getAttribute("data-settings-id");
|
||||
|
||||
try {
|
||||
let response = await fetch(
|
||||
`/data-settings/${dataSettingId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"X-CSRF-TOKEN": document
|
||||
.querySelector('meta[name="csrf-token"]')
|
||||
.getAttribute("content"),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
toastMessage.innerText =
|
||||
result.message || "Deleted successfully!";
|
||||
toast.show();
|
||||
|
||||
// Hide modal
|
||||
modal.hide();
|
||||
|
||||
// Refresh Grid.js table
|
||||
this.refreshDataSettings();
|
||||
} else {
|
||||
let error = await response.json();
|
||||
console.error("Delete failed:", error);
|
||||
toastMessage.innerText =
|
||||
error.message || "Delete failed!";
|
||||
toast.show();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting item:", error);
|
||||
toastMessage.innerText = "An error occurred!";
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
refreshDataSettings() {
|
||||
if (this.table) {
|
||||
this.table
|
||||
.updateConfig({
|
||||
server: {
|
||||
url: `${GlobalConfig.apiHost}/api/api-data-settings`,
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
let response = await fetch(
|
||||
`${GlobalConfig.apiHost}/api/data-settings/${id}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
@@ -194,21 +114,34 @@ class DataSettings {
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
then: (data) =>
|
||||
data.data.map((item) => [
|
||||
item.id,
|
||||
item.key,
|
||||
item.value,
|
||||
item.created_at,
|
||||
item.id,
|
||||
]),
|
||||
total: (data) => data.meta.total,
|
||||
},
|
||||
})
|
||||
.forceRender();
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
this.toastMessage.innerText =
|
||||
result.message || "Deleted successfully!";
|
||||
this.toast.show();
|
||||
|
||||
// Refresh Grid.js table
|
||||
if (typeof this.table !== "undefined") {
|
||||
this.table.updateConfig({}).forceRender();
|
||||
}
|
||||
} else {
|
||||
let error = await response.json();
|
||||
console.error("Delete failed:", error);
|
||||
this.toastMessage.innerText =
|
||||
error.message || "Delete failed!";
|
||||
this.toast.show();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error deleting item:", error);
|
||||
this.toastMessage.innerText = "An error occurred!";
|
||||
this.toast.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new DataSettings().init();
|
||||
new DataSettings();
|
||||
});
|
||||
|
||||
@@ -24,16 +24,16 @@ document.addEventListener("DOMContentLoaded", function (e) {
|
||||
let response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-CSRF-TOKEN": document
|
||||
.querySelector('meta[name="csrf-token"]')
|
||||
.getAttribute("content"),
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
toastMessage.innerText = result.message;
|
||||
toastMessage.innerText = result.data.message;
|
||||
toast.show();
|
||||
setTimeout(() => {
|
||||
window.location.href = "/data-settings";
|
||||
@@ -43,6 +43,8 @@ document.addEventListener("DOMContentLoaded", function (e) {
|
||||
toastMessage.innerText = error.message;
|
||||
toast.show();
|
||||
console.error("Error:", error);
|
||||
submitButton.disabled = false;
|
||||
spinner.classList.add("d-none");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Request failed:", error);
|
||||
|
||||
@@ -28,12 +28,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
data[key] = value;
|
||||
});
|
||||
|
||||
// Log semua data dalam FormData
|
||||
for (let pair of formData.entries()) {
|
||||
console.log(pair[0] + ": " + pair[1]);
|
||||
}
|
||||
const url = form.getAttribute("action");
|
||||
console.log("Ini adalah url dari form action", url);
|
||||
|
||||
const method = isEdit ? "PUT" : "POST";
|
||||
|
||||
@@ -49,7 +44,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log("Response data:", data);
|
||||
if (!data.errors) {
|
||||
// Remove existing icon (if any) before adding the new one
|
||||
if (authLogo) {
|
||||
@@ -74,11 +68,11 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
toast.classList.add('show'); // Show the toast
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show'); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
}, 2000);
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = '/data/advertisements';
|
||||
}, 3000);
|
||||
}, 1000);
|
||||
} else {
|
||||
if (authLogo) {
|
||||
// Hapus ikon yang sudah ada jika ada
|
||||
@@ -96,21 +90,21 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
// Tambahkan ikon ke dalam auth-logo
|
||||
authLogo.appendChild(icon);
|
||||
}
|
||||
// Set error message for the toast
|
||||
toastBody.textContent = "Error: " + (responseData.message || "Something went wrong");
|
||||
toast.classList.add('show'); // Show the toast
|
||||
|
||||
// Enable button and reset its text on error
|
||||
modalButton.disabled = false;
|
||||
modalButton.innerHTML = isEdit ? "Update" : "Create";
|
||||
|
||||
// Set error message for the toast
|
||||
toastBody.textContent = "Failed: " + (data.message || "Something went wrong");
|
||||
toast.classList.add('show'); // Show the toast
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show'); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error:", error);
|
||||
.catch(errors => {
|
||||
if (authLogo) {
|
||||
// Hapus ikon yang sudah ada jika ada
|
||||
const existingIcon = authLogo.querySelector('.bx');
|
||||
@@ -127,14 +121,14 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
// Tambahkan ikon ke dalam auth-logo
|
||||
authLogo.appendChild(icon);
|
||||
}
|
||||
// Enable button and reset its text on error
|
||||
modalButton.disabled = false;
|
||||
modalButton.innerHTML = isEdit ? "Update" : "Create";
|
||||
|
||||
// Set error message for the toast
|
||||
toastBody.textContent = "An error occurred while processing your request.";
|
||||
toast.classList.add('show'); // Show the toast
|
||||
|
||||
// Enable button and reset its text on error
|
||||
modalButton.disabled = false;
|
||||
modalButton.innerHTML = isEdit ? "Update" : "Create";
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show'); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
@@ -144,7 +138,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
// Fungsi fetchOptions untuk autocomplete server-side
|
||||
window.fetchOptions = function (field) {
|
||||
let inputValue = document.getElementById(field).value;
|
||||
console.log("Query Value:", inputValue); // Debugging log
|
||||
if (inputValue.length < 2) return;
|
||||
let districtValue = document.getElementById("district_name").value; // Ambil kecamatan terpilih
|
||||
|
||||
|
||||
63
resources/js/data/spatialPlannings/data-spatialPlannings.js
Normal file
63
resources/js/data/spatialPlannings/data-spatialPlannings.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Grid } from "gridjs/dist/gridjs.umd.js";
|
||||
import gridjs from "gridjs/dist/gridjs.umd.js";
|
||||
import "gridjs/dist/gridjs.umd.js";
|
||||
import GlobalConfig from "../../global-config.js";
|
||||
import GeneralTable from "../../table-generator.js";
|
||||
|
||||
const dataSpatialPlanningColumns = [
|
||||
"No",
|
||||
"Nama",
|
||||
"KBLI",
|
||||
"Kegiatan",
|
||||
"Luas",
|
||||
"Lokasi",
|
||||
"Nomor",
|
||||
"Tanggal",
|
||||
{
|
||||
name: "Actions",
|
||||
widht: "120px",
|
||||
formatter: function (cell, row) {
|
||||
const id = row.cells[8].data;
|
||||
const model = "data/spatial-plannings";
|
||||
return gridjs.html(`
|
||||
<div class="d-flex justify-items-end gap-10">
|
||||
<button class="btn btn-warning me-2 btn-edit"
|
||||
data-id="${id}"
|
||||
data-model="${model}">
|
||||
<i class='bx bx-edit'></i></button>
|
||||
|
||||
<button class="btn btn-red btn-delete"
|
||||
data-id="${id}">
|
||||
<i class='bx bxs-trash'></i></button>
|
||||
</div>
|
||||
`);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const table = new GeneralTable(
|
||||
"spatial-planning-data-table",
|
||||
`${GlobalConfig.apiHost}/api/spatial-plannings`,
|
||||
`${GlobalConfig.apiHost}`,
|
||||
dataSpatialPlanningColumns
|
||||
);
|
||||
|
||||
table.processData = function (data) {
|
||||
return data.data.map((item) => {
|
||||
return [
|
||||
item.no,
|
||||
item.name,
|
||||
item.kbli,
|
||||
item.activities,
|
||||
item.area,
|
||||
item.location,
|
||||
item.number,
|
||||
item.date,
|
||||
item.id,
|
||||
];
|
||||
});
|
||||
};
|
||||
|
||||
table.init();
|
||||
});
|
||||
185
resources/js/data/spatialPlannings/form-create-update.js
Normal file
185
resources/js/data/spatialPlannings/form-create-update.js
Normal file
@@ -0,0 +1,185 @@
|
||||
import GlobalConfig from "../../global-config";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const saveButton = document.querySelector(".modal-footer .btn-primary");
|
||||
const modalButton = document.querySelector(".btn-modal");
|
||||
const form = document.querySelector("form#create-update-form");
|
||||
var authLogo = document.querySelector(".auth-logo");
|
||||
|
||||
if (!saveButton || !form) return;
|
||||
|
||||
saveButton.addEventListener("click", function () {
|
||||
// Disable tombol dan tampilkan spinner
|
||||
modalButton.disabled = true;
|
||||
modalButton.innerHTML = `
|
||||
<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>
|
||||
Loading...
|
||||
`;
|
||||
const isEdit = saveButton.classList.contains("btn-edit");
|
||||
const formData = new FormData(form);
|
||||
const toast = document.getElementById("toastEditUpdate");
|
||||
const toastBody = toast.querySelector(".toast-body");
|
||||
const toastHeader = toast.querySelector(".toast-header small");
|
||||
|
||||
const data = {};
|
||||
|
||||
// Mengonversi FormData ke dalam JSON
|
||||
formData.forEach((value, key) => {
|
||||
data[key] = value;
|
||||
});
|
||||
|
||||
const url = form.getAttribute("action");
|
||||
|
||||
const method = isEdit ? "PUT" : "POST";
|
||||
|
||||
fetch(url, {
|
||||
method: method,
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (!data.errors) {
|
||||
// Remove existing icon (if any) before adding the new one
|
||||
if (authLogo) {
|
||||
// Hapus ikon yang sudah ada jika ada
|
||||
const existingIcon = authLogo.querySelector(".bx");
|
||||
if (existingIcon) {
|
||||
authLogo.removeChild(existingIcon);
|
||||
}
|
||||
|
||||
// Buat ikon baru
|
||||
const icon = document.createElement("i");
|
||||
icon.classList.add("bx", "bxs-check-square");
|
||||
icon.style.fontSize = "25px";
|
||||
icon.style.color = "green"; // Pastikan 'green' dalam bentuk string
|
||||
|
||||
// Tambahkan ikon ke dalam auth-logo
|
||||
authLogo.appendChild(icon);
|
||||
}
|
||||
|
||||
// Set success message for the toast
|
||||
toastBody.textContent = isEdit
|
||||
? "Data updated successfully!"
|
||||
: "Data created successfully!";
|
||||
toast.classList.add("show"); // Show the toast
|
||||
setTimeout(() => {
|
||||
toast.classList.remove("show"); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = "/data/spatial-plannings";
|
||||
}, 3000);
|
||||
} else {
|
||||
if (authLogo) {
|
||||
// Hapus ikon yang sudah ada jika ada
|
||||
const existingIcon = authLogo.querySelector(".bx");
|
||||
if (existingIcon) {
|
||||
authLogo.removeChild(existingIcon);
|
||||
}
|
||||
|
||||
// Buat ikon baru
|
||||
const icon = document.createElement("i");
|
||||
icon.classList.add("bx", "bxs-error-alt");
|
||||
icon.style.fontSize = "25px";
|
||||
icon.style.color = "red"; // Pastikan 'green' dalam bentuk string
|
||||
|
||||
// Tambahkan ikon ke dalam auth-logo
|
||||
authLogo.appendChild(icon);
|
||||
}
|
||||
// Set error message for the toast
|
||||
toastBody.textContent =
|
||||
"Error: " + (data.message || "Something went wrong");
|
||||
toast.classList.add("show"); // Show the toast
|
||||
|
||||
// Enable button and reset its text on error
|
||||
modalButton.disabled = false;
|
||||
modalButton.innerHTML = isEdit ? "Update" : "Create";
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove("show"); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (authLogo) {
|
||||
// Hapus ikon yang sudah ada jika ada
|
||||
const existingIcon = authLogo.querySelector(".bx");
|
||||
if (existingIcon) {
|
||||
authLogo.removeChild(existingIcon);
|
||||
}
|
||||
|
||||
// Buat ikon baru
|
||||
const icon = document.createElement("i");
|
||||
icon.classList.add("bx", "bxs-error-alt");
|
||||
icon.style.fontSize = "25px";
|
||||
icon.style.color = "red"; // Pastikan 'green' dalam bentuk string
|
||||
|
||||
// Tambahkan ikon ke dalam auth-logo
|
||||
authLogo.appendChild(icon);
|
||||
}
|
||||
// Set error message for the toast
|
||||
toastBody.textContent =
|
||||
"An error occurred while processing your request.";
|
||||
toast.classList.add("show"); // Show the toast
|
||||
|
||||
// Enable button and reset its text on error
|
||||
modalButton.disabled = false;
|
||||
modalButton.innerHTML = isEdit ? "Update" : "Create";
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove("show"); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
|
||||
// Fungsi fetchOptions untuk autocomplete server-side
|
||||
window.fetchOptions = function (field) {
|
||||
let inputValue = document.getElementById(field).value;
|
||||
if (inputValue.length < 2) return;
|
||||
let districtValue = document.getElementById("district_name").value; // Ambil kecamatan terpilih
|
||||
|
||||
let url = `${
|
||||
GlobalConfig.apiHost
|
||||
}/api/combobox/search-options?query=${encodeURIComponent(
|
||||
inputValue
|
||||
)}&field=${field}`;
|
||||
|
||||
// Jika field desa, tambahkan kecamatan sebagai filter
|
||||
if (field === "village_name") {
|
||||
url += `&district=${encodeURIComponent(districtValue)}`;
|
||||
}
|
||||
|
||||
fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
let dataList = document.getElementById(field + "Options");
|
||||
dataList.innerHTML = "";
|
||||
|
||||
data.forEach((item) => {
|
||||
let option = document.createElement("option");
|
||||
option.value = item.name;
|
||||
option.dataset.code = item.code;
|
||||
dataList.appendChild(option);
|
||||
});
|
||||
})
|
||||
.catch((error) => console.error("Error fetching options:", error));
|
||||
};
|
||||
|
||||
document.querySelector(".btn-back").addEventListener("click", function () {
|
||||
window.history.back();
|
||||
});
|
||||
});
|
||||
150
resources/js/data/spatialPlannings/form-upload.js
Normal file
150
resources/js/data/spatialPlannings/form-upload.js
Normal file
@@ -0,0 +1,150 @@
|
||||
import { Dropzone } from "dropzone";
|
||||
import GlobalConfig from "../../global-config.js";
|
||||
|
||||
Dropzone.autoDiscover = false;
|
||||
|
||||
var previewTemplate,
|
||||
dropzone,
|
||||
dropzonePreviewNode = document.querySelector("#dropzone-preview-list");
|
||||
console.log(previewTemplate);
|
||||
console.log(dropzone);
|
||||
console.log(dropzonePreviewNode);
|
||||
|
||||
(dropzonePreviewNode.id = ""),
|
||||
dropzonePreviewNode &&
|
||||
((previewTemplate = dropzonePreviewNode.parentNode.innerHTML),
|
||||
dropzonePreviewNode.parentNode.removeChild(dropzonePreviewNode),
|
||||
(dropzone = new Dropzone(".dropzone", {
|
||||
url: `${GlobalConfig.apiHost}/api/spatial-plannings/import`,
|
||||
// url: "https://httpbin.org/post",
|
||||
method: "post",
|
||||
acceptedFiles: ".xls,.xlsx", // Use acceptedFiles for better validation
|
||||
previewTemplate: previewTemplate,
|
||||
previewsContainer: "#dropzone-preview",
|
||||
autoProcessQueue: false, // Disable auto post
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`
|
||||
},
|
||||
init: function() {
|
||||
// Listen for the success event
|
||||
this.on("success", function(file, response) {
|
||||
console.log("File successfully uploaded:", file);
|
||||
console.log("API Response:", response);
|
||||
|
||||
// Show success toast
|
||||
showToast('bxs-check-square', 'green', response.message);
|
||||
document.getElementById("submit-upload").innerHTML = "Upload Files";
|
||||
// Tunggu sebentar lalu reload halaman
|
||||
setTimeout(() => {
|
||||
window.location.href = "/data/spatial-plannings";
|
||||
}, 2000);
|
||||
});
|
||||
// Listen for the error event
|
||||
this.on("error", function(file, errorMessage) {
|
||||
console.error("Error uploading file:", file);
|
||||
console.error("Error message:", errorMessage);
|
||||
// Handle the error response
|
||||
|
||||
// Show error toast
|
||||
showToast('bxs-error-alt', 'red', errorMessage.message);
|
||||
document.getElementById("submit-upload").innerHTML = "Upload Files";
|
||||
});
|
||||
}
|
||||
})));
|
||||
|
||||
// Add event listener to control the submission manually
|
||||
document.querySelector("#submit-upload").addEventListener("click", function() {
|
||||
console.log("Ini adalah value dropzone", dropzone.files[0]);
|
||||
const formData = new FormData()
|
||||
console.log("Dropzonefiles",dropzone.files);
|
||||
|
||||
this.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>Loading...';
|
||||
|
||||
// Pastikan ada file dalam queue sebelum memprosesnya
|
||||
if (dropzone.files.length > 0) {
|
||||
formData.append('file', dropzone.files[0])
|
||||
console.log("ini adalah form data on submit", ...formData);
|
||||
dropzone.processQueue(); // Ini akan manual memicu upload
|
||||
} else {
|
||||
// Show error toast when no file is selected
|
||||
showToast('bxs-error-alt', 'red', "Please add a file first.");
|
||||
document.getElementById("submit-upload").innerHTML = "Upload Files";
|
||||
}
|
||||
});
|
||||
|
||||
// Optional: Listen for the 'addedfile' event to log or control file add behavior
|
||||
dropzone.on("addedfile", function (file) {
|
||||
console.log("File ditambahkan:", file);
|
||||
console.log("Nama File:", file.name);
|
||||
console.log("Tipe File:", file.type);
|
||||
console.log("Ukuran File:", (file.size / 1024).toFixed(2) + " KB");
|
||||
});
|
||||
|
||||
dropzone.on("complete", function(file) {
|
||||
dropzone.removeFile(file);
|
||||
});
|
||||
|
||||
// Add event listener to download file template
|
||||
document.getElementById('downloadtempspatialPlannings').addEventListener('click', function() {
|
||||
var url = `${GlobalConfig.apiHost}/api/download-template-spatialPlannings`;
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.blob(); // Jika respons OK, konversi menjadi blob
|
||||
} else {
|
||||
return response.json(); // Jika respons gagal, konversi menjadi JSON untuk menangani pesan error
|
||||
}
|
||||
})
|
||||
.then((blob) => {
|
||||
console.log(blob);
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.href = url;
|
||||
a.download = 'template_rencana_tata_ruang.xlsx';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Gagal mendownload file:", error);
|
||||
showToast('bxs-error-alt', 'red', "Template file is not already exist.");
|
||||
})
|
||||
})
|
||||
|
||||
// Function to show toast
|
||||
function showToast(iconClass, iconColor, message) {
|
||||
const toastElement = document.getElementById('toastUploadSpatialPlannings');
|
||||
const toastBody = toastElement.querySelector('.toast-body');
|
||||
const toastHeader = toastElement.querySelector('.toast-header');
|
||||
|
||||
// Remove existing icon (if any) before adding the new one
|
||||
const existingIcon = toastHeader.querySelector('.bx');
|
||||
if (existingIcon) {
|
||||
toastHeader.querySelector('.auth-logo').removeChild(existingIcon); // Remove the existing icon
|
||||
}
|
||||
|
||||
// Add the new icon to the toast header
|
||||
const icon = document.createElement('i');
|
||||
icon.classList.add('bx', iconClass);
|
||||
icon.style.fontSize = '25px';
|
||||
icon.style.color = iconColor;
|
||||
toastHeader.querySelector('.auth-logo').appendChild(icon);
|
||||
|
||||
// Set the toast message
|
||||
toastBody.textContent = message;
|
||||
|
||||
// Show the toast
|
||||
const toast = new bootstrap.Toast(toastElement); // Inisialisasi Bootstrap Toast
|
||||
toast.show();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import GlobalConfig from "../../global-config.js";
|
||||
import GeneralTable from "../../table-generator.js";
|
||||
|
||||
const dataTourismsColumns = [
|
||||
"No",
|
||||
"Nama Perusahaan",
|
||||
"Nama Proyek",
|
||||
"Alamat Usaha",
|
||||
@@ -19,9 +20,9 @@ const dataTourismsColumns = [
|
||||
name: "Actions",
|
||||
widht: "120px",
|
||||
formatter: function (cell, row) {
|
||||
const id = row.cells[10].data;
|
||||
const long = row.cells[8].data;
|
||||
const lat = row.cells[9].data;
|
||||
const id = row.cells[11].data;
|
||||
const long = row.cells[9].data;
|
||||
const lat = row.cells[10].data;
|
||||
const model = "data/tourisms";
|
||||
return gridjs.html(`
|
||||
<div class="d-flex justify-items-end gap-10">
|
||||
@@ -54,6 +55,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
table.processData = function (data) {
|
||||
return data.data.map((item) => {
|
||||
return [
|
||||
item.no,
|
||||
item.business_name,
|
||||
item.project_name,
|
||||
item.business_address,
|
||||
|
||||
@@ -28,12 +28,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
data[key] = value;
|
||||
});
|
||||
|
||||
// Log semua data dalam FormData
|
||||
for (let pair of formData.entries()) {
|
||||
console.log(pair[0] + ": " + pair[1]);
|
||||
}
|
||||
const url = form.getAttribute("action");
|
||||
console.log("Ini adalah url dari form action", url);
|
||||
|
||||
const method = isEdit ? "PUT" : "POST";
|
||||
|
||||
@@ -49,7 +44,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
console.log("Response data:", data);
|
||||
if (!data.errors) {
|
||||
// Remove existing icon (if any) before adding the new one
|
||||
if (authLogo) {
|
||||
@@ -113,7 +107,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error);
|
||||
if (authLogo) {
|
||||
// Hapus ikon yang sudah ada jika ada
|
||||
const existingIcon = authLogo.querySelector(".bx");
|
||||
@@ -148,7 +141,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
// Fungsi fetchOptions untuk autocomplete server-side
|
||||
window.fetchOptions = function (field) {
|
||||
let inputValue = document.getElementById(field).value;
|
||||
console.log("Query Value:", inputValue); // Debugging log
|
||||
if (inputValue.length < 2) return;
|
||||
let districtValue = document.getElementById("district_name").value; // Ambil kecamatan terpilih
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ dropzone.on("complete", function(file) {
|
||||
|
||||
// Add event listener to download file template
|
||||
document.getElementById('downloadtemptourisms').addEventListener('click', function() {
|
||||
var url = `${GlobalConfig.apiHost}/api/download-template-umkm`;
|
||||
var url = `${GlobalConfig.apiHost}/api/download-template-tourism`;
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
@@ -105,11 +105,12 @@ document.getElementById('downloadtemptourisms').addEventListener('click', functi
|
||||
}
|
||||
})
|
||||
.then((blob) => {
|
||||
console.log(blob);
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.href = url;
|
||||
a.download = 'template_tourisms.xlsx';
|
||||
a.download = 'template_pariwisata.xlsx';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
@@ -122,7 +123,7 @@ document.getElementById('downloadtemptourisms').addEventListener('click', functi
|
||||
|
||||
// Function to show toast
|
||||
function showToast(iconClass, iconColor, message) {
|
||||
const toastElement = document.getElementById('toastUploadUmkm');
|
||||
const toastElement = document.getElementById('toastUploadTourisms');
|
||||
const toastBody = toastElement.querySelector('.toast-body');
|
||||
const toastHeader = toastElement.querySelector('.toast-header');
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import GlobalConfig from "../../global-config.js";
|
||||
import GeneralTable from "../../table-generator.js";
|
||||
|
||||
const dataUMKMColumns = [
|
||||
"No",
|
||||
"Nama Usaha",
|
||||
"Alamat Usaha",
|
||||
"Deskripsi Usaha",
|
||||
@@ -26,7 +27,7 @@ const dataUMKMColumns = [
|
||||
name: "Actions",
|
||||
widht: "120px",
|
||||
formatter: function(cell, row) {
|
||||
const id = row.cells[18].data;
|
||||
const id = row.cells[19].data;
|
||||
const model = "data/umkm";
|
||||
return gridjs.html(`
|
||||
<div class="d-flex justify-items-end gap-10">
|
||||
@@ -54,6 +55,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
table.processData = function (data) {
|
||||
return data.data.map((item) => {
|
||||
return [
|
||||
item.no,
|
||||
item.business_name,
|
||||
item.business_address,
|
||||
item.business_desc,
|
||||
|
||||
@@ -28,12 +28,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
data[key] = value;
|
||||
});
|
||||
|
||||
// Log semua data dalam FormData
|
||||
for (let pair of formData.entries()) {
|
||||
console.log(pair[0] + ": " + pair[1]);
|
||||
}
|
||||
const url = form.getAttribute("action");
|
||||
console.log("Ini adalah url dari form action", url);
|
||||
|
||||
const method = isEdit ? "PUT" : "POST";
|
||||
|
||||
@@ -74,11 +69,11 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
toast.classList.add('show'); // Show the toast
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show'); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
}, 2000);
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.href = '/data/umkm';
|
||||
}, 3000);
|
||||
}, 1000);
|
||||
} else {
|
||||
if (authLogo) {
|
||||
// Hapus ikon yang sudah ada jika ada
|
||||
@@ -96,14 +91,16 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
// Tambahkan ikon ke dalam auth-logo
|
||||
authLogo.appendChild(icon);
|
||||
}
|
||||
// Set error message for the toast
|
||||
toastBody.textContent = "Error: " + (data.message || "Something went wrong");
|
||||
toast.classList.add('show'); // Show the toast
|
||||
|
||||
// Enable button and reset its text on error
|
||||
modalButton.disabled = false;
|
||||
modalButton.innerHTML = isEdit ? "Update" : "Create";
|
||||
|
||||
|
||||
// Set error message for the toast
|
||||
toastBody.textContent = "Error: " + (data.message || "Something went wrong");
|
||||
toast.classList.add('show'); // Show the toast
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show'); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
@@ -127,14 +124,15 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
// Tambahkan ikon ke dalam auth-logo
|
||||
authLogo.appendChild(icon);
|
||||
}
|
||||
// Set error message for the toast
|
||||
toastBody.textContent = "An error occurred while processing your request.";
|
||||
toast.classList.add('show'); // Show the toast
|
||||
|
||||
// Enable button and reset its text on error
|
||||
modalButton.disabled = false;
|
||||
modalButton.innerHTML = isEdit ? "Update" : "Create";
|
||||
|
||||
// Set error message for the toast
|
||||
toastBody.textContent = "An error occurred while processing your request.";
|
||||
toast.classList.add('show'); // Show the toast
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show'); // Hide the toast after 3 seconds
|
||||
}, 3000);
|
||||
@@ -144,7 +142,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
// Fungsi fetchOptions untuk autocomplete server-side
|
||||
window.fetchOptions = function (field) {
|
||||
let inputValue = document.getElementById(field).value;
|
||||
console.log("Query Value:", inputValue); // Debugging log
|
||||
if (inputValue.length < 2) return;
|
||||
let districtValue = document.getElementById("district_name").value; // Ambil kecamatan terpilih
|
||||
|
||||
|
||||
79
resources/js/maps/maps-kml.js
Normal file
79
resources/js/maps/maps-kml.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import L from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
var map = L.map("map").setView([-6.9175, 107.6191], 10); // Bandung
|
||||
|
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||
attribution: "© OpenStreetMap contributors",
|
||||
}).addTo(map);
|
||||
|
||||
// Dapatkan elemen loading
|
||||
const loadingDiv = document.getElementById("loading");
|
||||
loadingDiv.style.display = "flex"; // Tampilkan loading
|
||||
|
||||
fetch("/storage/maps/rencana-polaruang.geojson")
|
||||
.then((res) => res.json())
|
||||
.then((geojson) => {
|
||||
let colorMapping = {
|
||||
BJ: "rgb(235, 30, 30)",
|
||||
BA: "rgb(151, 219, 242)",
|
||||
CA: "rgb(70, 70, 165)",
|
||||
"P-2": "rgb(230, 255, 75)",
|
||||
HL: "rgb(50, 95, 40)",
|
||||
HPT: "rgb(75, 155, 55)",
|
||||
HP: "rgb(125, 180, 55)",
|
||||
W: "rgb(255, 165, 255)",
|
||||
PTL: "rgb(0, 255, 205)",
|
||||
"IK-2": "rgb(130, 185, 210)",
|
||||
"P-3": "rgb(175, 175, 55)",
|
||||
PS: "rgb(5, 215, 215)",
|
||||
PD: "rgb(235, 155, 60)",
|
||||
PK: "rgb(245, 155, 30)",
|
||||
HK: "rgb(155, 0, 255)",
|
||||
KPI: "rgb(105, 0, 0)",
|
||||
MBT: "rgb(95, 115, 145)",
|
||||
"P-4": "rgb(185, 235, 185)",
|
||||
TB: "rgb(70, 150, 255)",
|
||||
"P-1": "rgb(200, 245, 70)",
|
||||
TR: "rgb(215, 55, 0)",
|
||||
THR: "rgb(185, 165, 255)",
|
||||
TWA: "rgb(210, 190, 255)",
|
||||
};
|
||||
var geoLayer = L.geoJSON(geojson, {
|
||||
style: function (feature) {
|
||||
let htmlString = feature.properties.description.toString();
|
||||
|
||||
let match = htmlString.match(
|
||||
/<td>Kode Kawasan<\/td>\s*<td>(.*?)<\/td>/
|
||||
);
|
||||
|
||||
console.log("Kode Kawasan ", match[1]);
|
||||
|
||||
let color_code = match[1];
|
||||
|
||||
return {
|
||||
color: colorMapping[color_code],
|
||||
fillColor: colorMapping[color_code] || "#cccccc",
|
||||
fillOpacity: 0.6,
|
||||
weight: 1.5,
|
||||
};
|
||||
},
|
||||
onEachFeature: function (feature, layer) {
|
||||
if (feature.properties && feature.properties.name) {
|
||||
layer.bindPopup(feature.properties.name);
|
||||
}
|
||||
},
|
||||
}).addTo(map);
|
||||
|
||||
map.fitBounds(geoLayer.getBounds());
|
||||
|
||||
// Sembunyikan loading setelah selesai render
|
||||
loadingDiv.style.display = "none";
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error loading GeoJSON:", error);
|
||||
loadingDiv.innerHTML =
|
||||
"<div class='loading-text' style='background: red;'>Failed to load data!</div>";
|
||||
});
|
||||
});
|
||||
@@ -31,7 +31,7 @@ class UsersTable {
|
||||
},
|
||||
],
|
||||
pagination: {
|
||||
limit: 15,
|
||||
limit: 50,
|
||||
server: {
|
||||
url: (prev, page) =>
|
||||
`${prev}${prev.includes("?") ? "&" : "?"}page=${
|
||||
|
||||
@@ -1,55 +1,67 @@
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
const toastNotification = document.getElementById("toastNotification");
|
||||
const toast = new bootstrap.Toast(toastNotification);
|
||||
document
|
||||
.getElementById("btnCreateMenus")
|
||||
.addEventListener("click", async function () {
|
||||
let submitButton = this;
|
||||
let spinner = document.getElementById("spinner");
|
||||
let form = document.getElementById("formCreateMenus");
|
||||
class CreateMenu {
|
||||
constructor() {
|
||||
this.initCreateMenu();
|
||||
}
|
||||
|
||||
if (!form) {
|
||||
console.error("Form element not found!");
|
||||
return;
|
||||
}
|
||||
// Get form data
|
||||
let formData = new FormData(form);
|
||||
initCreateMenu() {
|
||||
const toastNotification = document.getElementById("toastNotification");
|
||||
const toast = new bootstrap.Toast(toastNotification);
|
||||
document
|
||||
.getElementById("btnCreateMenus")
|
||||
.addEventListener("click", async function () {
|
||||
let submitButton = this;
|
||||
let spinner = document.getElementById("spinner");
|
||||
let form = document.getElementById("formCreateMenus");
|
||||
|
||||
// Disable button and show spinner
|
||||
submitButton.disabled = true;
|
||||
spinner.classList.remove("d-none");
|
||||
if (!form) {
|
||||
console.error("Form element not found!");
|
||||
return;
|
||||
}
|
||||
// Get form data
|
||||
let formData = new FormData(form);
|
||||
|
||||
try {
|
||||
let response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-CSRF-TOKEN": document
|
||||
.querySelector('meta[name="csrf-token"]')
|
||||
.getAttribute("content"),
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
// Disable button and show spinner
|
||||
submitButton.disabled = true;
|
||||
spinner.classList.remove("d-none");
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
document.getElementById("toast-message").innerText =
|
||||
result.message;
|
||||
toast.show();
|
||||
setTimeout(() => {
|
||||
window.location.href = "/menus";
|
||||
}, 2000);
|
||||
} else {
|
||||
let error = await response.json();
|
||||
try {
|
||||
let response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${document
|
||||
.querySelector('meta[name="api-token"]')
|
||||
.getAttribute("content")}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
let result = await response.json();
|
||||
document.getElementById("toast-message").innerText =
|
||||
result.message;
|
||||
toast.show();
|
||||
setTimeout(() => {
|
||||
window.location.href = "/menus";
|
||||
}, 2000);
|
||||
} else {
|
||||
let error = await response.json();
|
||||
document.getElementById("toast-message").innerText =
|
||||
error.message;
|
||||
toast.show();
|
||||
console.error("Error:", error);
|
||||
submitButton.disabled = false;
|
||||
spinner.classList.add("d-none");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Request failed:", error);
|
||||
document.getElementById("toast-message").innerText =
|
||||
error.message;
|
||||
toast.show();
|
||||
console.error("Error:", error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Request failed:", error);
|
||||
document.getElementById("toast-message").innerText =
|
||||
error.message;
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
new CreateMenu();
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user