add sync to leader dashboard new from google spreadsheet
This commit is contained in:
76
.env.local.backup
Normal file
76
.env.local.backup
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
APP_NAME=SIBEDAS-PBG
|
||||||
|
APP_ENV=local
|
||||||
|
APP_KEY=base64:xqCpwixWKqgu1Ca22gFizoOt44p7h+cgTOKuhS/P0Jw=
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_TIMEZONE=Asia/Jakarta
|
||||||
|
APP_URL=http://localhost:8000
|
||||||
|
|
||||||
|
API_URL=http://localhost:8000
|
||||||
|
|
||||||
|
APP_LOCALE=en
|
||||||
|
APP_FALLBACK_LOCALE=en
|
||||||
|
APP_FAKER_LOCALE=en_US
|
||||||
|
|
||||||
|
APP_MAINTENANCE_DRIVER=file
|
||||||
|
# APP_MAINTENANCE_STORE=database
|
||||||
|
|
||||||
|
PHP_CLI_SERVER_WORKERS=4
|
||||||
|
|
||||||
|
BCRYPT_ROUNDS=12
|
||||||
|
|
||||||
|
LOG_CHANNEL=stack
|
||||||
|
LOG_STACK=single
|
||||||
|
LOG_DEPRECATIONS_CHANNEL=null
|
||||||
|
LOG_LEVEL=debug
|
||||||
|
|
||||||
|
DB_CONNECTION=mariadb
|
||||||
|
DB_HOST=db
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=sibedas_db
|
||||||
|
DB_USERNAME=root
|
||||||
|
DB_PASSWORD=root
|
||||||
|
|
||||||
|
SESSION_DRIVER=database
|
||||||
|
SESSION_LIFETIME=120
|
||||||
|
SESSION_ENCRYPT=false
|
||||||
|
SESSION_PATH=/
|
||||||
|
SESSION_DOMAIN=null
|
||||||
|
|
||||||
|
BROADCAST_CONNECTION=log
|
||||||
|
FILESYSTEM_DISK=local
|
||||||
|
QUEUE_CONNECTION=database
|
||||||
|
|
||||||
|
CACHE_STORE=database
|
||||||
|
CACHE_PREFIX=
|
||||||
|
|
||||||
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
|
REDIS_CLIENT=phpredis
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PASSWORD=null
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
MAIL_MAILER=log
|
||||||
|
MAIL_HOST=127.0.0.1
|
||||||
|
MAIL_PORT=2525
|
||||||
|
MAIL_USERNAME=null
|
||||||
|
MAIL_PASSWORD=null
|
||||||
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_ADDRESS="hello@example.com"
|
||||||
|
MAIL_FROM_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
AWS_ACCESS_KEY_ID=
|
||||||
|
AWS_SECRET_ACCESS_KEY=
|
||||||
|
AWS_DEFAULT_REGION=us-east-1
|
||||||
|
AWS_BUCKET=
|
||||||
|
AWS_USE_PATH_STYLE_ENDPOINT=false
|
||||||
|
|
||||||
|
VITE_APP_NAME="${APP_NAME}"
|
||||||
|
|
||||||
|
SIMBG_HOST="https://simbg.pu.go.id/"
|
||||||
|
SIMBG_EMAIL="dputr@bandungkab.go.id"
|
||||||
|
SIMBG_PASSWORD="Simbg123"
|
||||||
|
|
||||||
|
API_KEY_GOOGLE="AIzaSyBxfEShFkKmykkc7RJR3lVzkQ_xGHK3qr0"
|
||||||
|
SPREAD_SHEET_ID="1QoXzuLdEX3MK70Yrfigz0Qj5rAt4T819jX85vubBNdY"
|
||||||
|
OPENAI_API_KEY="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"
|
||||||
180
BUILD_GUIDE.md
180
BUILD_GUIDE.md
@@ -1,180 +0,0 @@
|
|||||||
# 🚀 Panduan Build untuk Production
|
|
||||||
|
|
||||||
## 📋 Masalah yang Diselesaikan
|
|
||||||
|
|
||||||
Aplikasi ini memiliki **banyak file JS dan CSS** yang harus dibangun semuanya karena:
|
|
||||||
- Setiap halaman memerlukan file JS/CSS yang spesifik
|
|
||||||
- Jika ada file yang hilang, halaman akan error (404 Not Found)
|
|
||||||
- Server dengan RAM terbatas sering mengalami "killed" saat build
|
|
||||||
|
|
||||||
## 🎯 Solusi yang Tersedia
|
|
||||||
|
|
||||||
### 1. **Build di Local (RECOMMENDED) 🏆**
|
|
||||||
```bash
|
|
||||||
# Build di local computer Anda
|
|
||||||
npm run build:local
|
|
||||||
|
|
||||||
# Upload ke server
|
|
||||||
./deploy.sh username server.com /path/to/project
|
|
||||||
```
|
|
||||||
|
|
||||||
**Kelebihan:**
|
|
||||||
- ✅ Tidak ada batasan memory
|
|
||||||
- ✅ Build lebih cepat
|
|
||||||
- ✅ Semua file terjamin ter-build
|
|
||||||
|
|
||||||
### 2. **Build di Server dengan Optimasi**
|
|
||||||
```bash
|
|
||||||
# Option A: Build dengan memory optimization
|
|
||||||
npm run build:prod
|
|
||||||
|
|
||||||
# Option B: Build dengan retry mechanism
|
|
||||||
npm run build:chunked
|
|
||||||
|
|
||||||
# Option C: Build manual dengan script
|
|
||||||
./build-production.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. **Setup Server untuk Build**
|
|
||||||
```bash
|
|
||||||
# Setup swap memory dan optimasi (run dengan sudo)
|
|
||||||
sudo ./server-setup.sh
|
|
||||||
|
|
||||||
# Kemudian build
|
|
||||||
npm run build:prod
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📁 File yang Akan Dibangun
|
|
||||||
|
|
||||||
Semua file ini **WAJIB** ada karena dibutuhkan oleh halaman-halaman aplikasi:
|
|
||||||
|
|
||||||
### CSS Files:
|
|
||||||
- `resources/scss/style.scss` - Main stylesheet
|
|
||||||
- `resources/scss/icons.scss` - Icons
|
|
||||||
- `resources/scss/components/_*.scss` - Components
|
|
||||||
- `resources/scss/dashboards/_*.scss` - Dashboard styles
|
|
||||||
- `resources/scss/pages/quick-search/*.scss` - Quick search pages
|
|
||||||
- Third-party CSS (Quill, Flatpickr, GridJS, dll)
|
|
||||||
|
|
||||||
### JS Files:
|
|
||||||
- **Core:** `app.js`, `config.js`, `dashboard.js`
|
|
||||||
- **Pages:** `chart.js`, `form-*.js`, `table-*.js`, `maps-*.js`
|
|
||||||
- **Data:** `data-advertisements.js`, `data-umkm.js`, `data-tourisms.js`
|
|
||||||
- **Settings:** `syncronize.js`, `general-settings.js`
|
|
||||||
- **Dashboards:** `bigdata.js`, `pbg.js`, `potentials/*.js`
|
|
||||||
- **Users & Roles:** `users/*.js`, `roles/*.js`, `menus/*.js`
|
|
||||||
- **Reports:** `growth-report.js`, `tourisms/index.js`
|
|
||||||
- **Dan semua file lainnya sesuai kebutuhan halaman**
|
|
||||||
|
|
||||||
## ⚙️ Konfigurasi Build
|
|
||||||
|
|
||||||
### Memory Optimization
|
|
||||||
```javascript
|
|
||||||
// vite.config.production.js
|
|
||||||
export default defineConfig({
|
|
||||||
build: {
|
|
||||||
rollupOptions: {
|
|
||||||
output: {
|
|
||||||
manualChunks: {
|
|
||||||
vendor: ['bootstrap', 'moment', 'axios'],
|
|
||||||
charts: ['apexcharts'],
|
|
||||||
maps: ['leaflet', 'jsvectormap', 'gmaps'],
|
|
||||||
ui: ['sweetalert2', 'flatpickr', 'quill']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
maxParallelFileOps: 1 // Untuk server dengan RAM terbatas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
### Memory Limits
|
|
||||||
```bash
|
|
||||||
# Untuk server dengan RAM 2GB+
|
|
||||||
NODE_OPTIONS="--max-old-space-size=2048"
|
|
||||||
|
|
||||||
# Untuk server dengan RAM 1GB
|
|
||||||
NODE_OPTIONS="--max-old-space-size=1024"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 Troubleshooting
|
|
||||||
|
|
||||||
### Build Terkill (Killed)
|
|
||||||
```bash
|
|
||||||
# Solusi 1: Build di local
|
|
||||||
npm run build:local
|
|
||||||
./deploy.sh
|
|
||||||
|
|
||||||
# Solusi 2: Tambah swap memory
|
|
||||||
sudo ./server-setup.sh
|
|
||||||
|
|
||||||
# Solusi 3: Gunakan build chunked
|
|
||||||
npm run build:chunked
|
|
||||||
```
|
|
||||||
|
|
||||||
### File JS/CSS Tidak Ditemukan
|
|
||||||
```bash
|
|
||||||
# Pastikan semua file ada di vite.config.production.js
|
|
||||||
# Jangan hapus file apapun dari daftar input!
|
|
||||||
|
|
||||||
# Verifikasi build
|
|
||||||
find public/build -name "*.js" | wc -l
|
|
||||||
find public/build -name "*.css" | wc -l
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server Kehabisan Memory
|
|
||||||
```bash
|
|
||||||
# Check memory usage
|
|
||||||
free -h
|
|
||||||
|
|
||||||
# Add swap file
|
|
||||||
sudo fallocate -l 2G /swapfile
|
|
||||||
sudo chmod 600 /swapfile
|
|
||||||
sudo mkswap /swapfile
|
|
||||||
sudo swapon /swapfile
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📦 Deployment Flow
|
|
||||||
|
|
||||||
### Local Build → Server Deploy
|
|
||||||
```bash
|
|
||||||
# 1. Di local
|
|
||||||
npm ci
|
|
||||||
npm run build:local
|
|
||||||
|
|
||||||
# 2. Edit deploy.sh dengan info server
|
|
||||||
# 3. Deploy
|
|
||||||
./deploy.sh username server.com /path/to/project
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server Build
|
|
||||||
```bash
|
|
||||||
# 1. Setup server
|
|
||||||
sudo ./server-setup.sh
|
|
||||||
|
|
||||||
# 2. Install dependencies
|
|
||||||
npm ci --production=false
|
|
||||||
|
|
||||||
# 3. Build
|
|
||||||
npm run build:chunked
|
|
||||||
|
|
||||||
# 4. Optimize Laravel
|
|
||||||
php artisan config:cache
|
|
||||||
php artisan route:cache
|
|
||||||
php artisan view:cache
|
|
||||||
```
|
|
||||||
|
|
||||||
## ⚠️ Catatan Penting
|
|
||||||
|
|
||||||
1. **JANGAN HAPUS FILE APAPUN** dari `vite.config.production.js`
|
|
||||||
2. **SEMUA FILE WAJIB ADA** karena dibutuhkan oleh halaman-halaman aplikasi
|
|
||||||
3. **BUILD DI LOCAL** adalah solusi terbaik untuk server dengan RAM terbatas
|
|
||||||
4. **BACKUP** selalu sebelum deploy ke production
|
|
||||||
|
|
||||||
## 🎉 Success Indicators
|
|
||||||
|
|
||||||
Build berhasil jika:
|
|
||||||
- ✅ File `public/build/manifest.json` ada
|
|
||||||
- ✅ Folder `public/build/assets/` berisi banyak file JS/CSS
|
|
||||||
- ✅ Tidak ada error 404 saat mengakses halaman
|
|
||||||
- ✅ Semua halaman dapat memuat JS/CSS yang dibutuhkan
|
|
||||||
33
app/Console/Commands/ScrapingLeaderData.php
Normal file
33
app/Console/Commands/ScrapingLeaderData.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Services\ServiceGoogleSheet;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class ScrapingLeaderData extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'app:scraping-leader-data';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Scraping leader data from google spreadsheet and save to database';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$service_google_sheet = app(ServiceGoogleSheet::class);
|
||||||
|
$service_google_sheet->sync_leader_data();
|
||||||
|
$this->info('Leader data synced successfully');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,4 +21,13 @@ class BigDataController extends Controller
|
|||||||
{
|
{
|
||||||
return view('dashboards.pbg');
|
return view('dashboards.pbg');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function leader()
|
||||||
|
{
|
||||||
|
$latest_import_datasource = ImportDatasource::latest()->first();
|
||||||
|
$latest_created = $latest_import_datasource ?
|
||||||
|
$latest_import_datasource->created_at->format("j F Y H:i:s") : null;
|
||||||
|
$menus = Menu::all();
|
||||||
|
return view('dashboards.leader', compact('latest_created', 'menus'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\BigdataResume;
|
||||||
use App\Models\DataSetting;
|
use App\Models\DataSetting;
|
||||||
use App\Models\ImportDatasource;
|
use App\Models\ImportDatasource;
|
||||||
use App\Models\PbgTaskGoogleSheet;
|
use App\Models\PbgTaskGoogleSheet;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Google_Client;
|
use Google\Client as Google_Client;
|
||||||
use Google_Service_Sheets;
|
use Google\Service\Sheets as Google_Service_Sheets;
|
||||||
use Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
class ServiceGoogleSheet
|
class ServiceGoogleSheet
|
||||||
{
|
{
|
||||||
protected $client;
|
protected $client;
|
||||||
@@ -210,6 +212,78 @@ class ServiceGoogleSheet
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sync_leader_data(){
|
||||||
|
$import_datasource = ImportDatasource::create([
|
||||||
|
'message' => 'Processing leader data',
|
||||||
|
'status' => 'processing',
|
||||||
|
'start_time' => now(),
|
||||||
|
'failed_uuid' => null
|
||||||
|
]);
|
||||||
|
try {
|
||||||
|
$sections = [
|
||||||
|
'TARGET_PAD' => "TARGET PAD 2024",
|
||||||
|
'KEKURANGAN_POTENSI' => "DEVIASI TARGET DENGAN POTENSI TOTAL BERKAS",
|
||||||
|
'TOTAL_POTENSI_BERKAS' => "•TOTAL BERKAS 2025",
|
||||||
|
'BELUM_TERVERIFIKASI' => "•BERKAS AKTUAL BELUM TERVERIFIKASI (POTENSI):",
|
||||||
|
'TERVERIFIKASI' => "•BERKAS AKTUAL TERVERIFIKASI DINAS TEKNIS 2025:",
|
||||||
|
'NON_USAHA' => "•NON USAHA: HUNIAN, SOSBUD, KEAGAMAAN",
|
||||||
|
'USAHA' => "•USAHA: USAHA, CAMPURAN, KOLEKTIF, PRASARANA"
|
||||||
|
];
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($sections as $key => $identifier) {
|
||||||
|
$values = $this->get_values_from_section(2, $identifier, [10, 11]);
|
||||||
|
|
||||||
|
if (!empty($values)) {
|
||||||
|
$result[$key] = [
|
||||||
|
'identifier' => $identifier,
|
||||||
|
'total' => $values[0] ?? null, // index 0 untuk total/jumlah
|
||||||
|
'nominal' => $values[1] ?? null // index 1 untuk nominal
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info("Leader data synced", ['result' => $result]);
|
||||||
|
|
||||||
|
BigdataResume::create([
|
||||||
|
'import_datasource_id' => $import_datasource->id,
|
||||||
|
'year' => now()->year,
|
||||||
|
// USAHA
|
||||||
|
'business_count' => $this->convertToInteger($result['USAHA']['total'] ?? null) ?? 0,
|
||||||
|
'business_sum' => $this->convertToDecimal($result['USAHA']['nominal'] ?? null) ?? 0,
|
||||||
|
// NON USAHA
|
||||||
|
'non_business_count' => $this->convertToInteger($result['NON_USAHA']['total'] ?? null) ?? 0,
|
||||||
|
'non_business_sum' => $this->convertToDecimal($result['NON_USAHA']['nominal'] ?? null) ?? 0,
|
||||||
|
// TERVERIFIKASI
|
||||||
|
'verified_count' => $this->convertToInteger($result['TERVERIFIKASI']['total'] ?? null) ?? 0,
|
||||||
|
'verified_sum' => $this->convertToDecimal($result['TERVERIFIKASI']['nominal'] ?? null) ?? 0,
|
||||||
|
// BELUM TERVERIFIKASI
|
||||||
|
'non_verified_count' => $this->convertToInteger($result['BELUM_TERVERIFIKASI']['total'] ?? null) ?? 0,
|
||||||
|
'non_verified_sum' => $this->convertToDecimal($result['BELUM_TERVERIFIKASI']['nominal'] ?? null) ?? 0,
|
||||||
|
// TOTAL POTENSI BERKAS
|
||||||
|
'potention_count' => $this->convertToInteger($result['TOTAL_POTENSI_BERKAS']['total'] ?? null) ?? 0,
|
||||||
|
'potention_sum' => $this->convertToDecimal($result['TOTAL_POTENSI_BERKAS']['nominal'] ?? null) ?? 0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$import_datasource->update([
|
||||||
|
'status' => 'success',
|
||||||
|
'response_body' => json_encode($result),
|
||||||
|
'message' => 'Leader data synced',
|
||||||
|
'finish_time' => now()
|
||||||
|
]);
|
||||||
|
return $result;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Error syncing leader data", ['error' => $e->getMessage()]);
|
||||||
|
$import_datasource->update([
|
||||||
|
'status' => 'failed',
|
||||||
|
'message' => 'Leader data sync failed',
|
||||||
|
'finish_time' => now()
|
||||||
|
]);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function get_big_resume_data(){
|
public function get_big_resume_data(){
|
||||||
try {
|
try {
|
||||||
$sheet_big_data = $this->get_data_by_sheet();
|
$sheet_big_data = $this->get_data_by_sheet();
|
||||||
@@ -261,9 +335,71 @@ class ServiceGoogleSheet
|
|||||||
return!empty($values)? $values : [];
|
return!empty($values)? $values : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get specific values from a row that contains a specific text/section identifier
|
||||||
|
* @param int $no_sheet Sheet number (0-based)
|
||||||
|
* @param string $section_identifier Text to search for in the row
|
||||||
|
* @param array $column_indices Array of column indices to extract values from
|
||||||
|
* @return array Array of values from specified columns, or empty array if section not found
|
||||||
|
*/
|
||||||
|
private function get_values_from_section($no_sheet = 1, $section_identifier, $column_indices = []) {
|
||||||
|
try {
|
||||||
|
$sheet_data = $this->get_data_by_sheet($no_sheet);
|
||||||
|
|
||||||
|
if (empty($sheet_data)) {
|
||||||
|
Log::warning("No data found in sheet", ['sheet' => $no_sheet]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for the row containing the section identifier
|
||||||
|
$target_row = null;
|
||||||
|
foreach ($sheet_data as $row_index => $row) {
|
||||||
|
if (is_array($row)) {
|
||||||
|
foreach ($row as $cell) {
|
||||||
|
if (is_string($cell) && strpos($cell, $section_identifier) !== false) {
|
||||||
|
$target_row = $row;
|
||||||
|
break 2; // Break out of both loops
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($target_row === null) {
|
||||||
|
Log::warning("Section not found", ['section_identifier' => $section_identifier]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract values from specified column indices
|
||||||
|
$extracted_values = [];
|
||||||
|
foreach ($column_indices as $col_index) {
|
||||||
|
if (isset($target_row[$col_index])) {
|
||||||
|
$value = trim($target_row[$col_index]);
|
||||||
|
$extracted_values[] = $value !== '' ? $value : null;
|
||||||
|
} else {
|
||||||
|
$extracted_values[] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info("Values extracted from section", [
|
||||||
|
'section_identifier' => $section_identifier,
|
||||||
|
'column_indices' => $column_indices,
|
||||||
|
'extracted_values' => $extracted_values
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $extracted_values;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error("Error getting values from section", [
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'section_identifier' => $section_identifier,
|
||||||
|
'sheet' => $no_sheet
|
||||||
|
]);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function convertToInteger($value) {
|
private function convertToInteger($value) {
|
||||||
// Check if the value is an empty string, and return null if true
|
// Check if the value is null or empty string, and return null if true
|
||||||
if (trim($value) === "") {
|
if ($value === null || trim($value) === "") {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Build script bertahap untuk menghindari memory overload
|
|
||||||
# Tetap membangun SEMUA file yang diperlukan tapi secara bertahap
|
|
||||||
|
|
||||||
echo "🔨 Starting chunked production build..."
|
|
||||||
|
|
||||||
# Set memory limit
|
|
||||||
export NODE_OPTIONS="--max-old-space-size=1536"
|
|
||||||
export NODE_ENV=production
|
|
||||||
|
|
||||||
# Clean previous build
|
|
||||||
echo "🧹 Cleaning previous build..."
|
|
||||||
rm -rf public/build/*
|
|
||||||
|
|
||||||
# Fungsi untuk build dengan retry
|
|
||||||
build_with_retry() {
|
|
||||||
local config_file=$1
|
|
||||||
local attempt=1
|
|
||||||
local max_attempts=3
|
|
||||||
|
|
||||||
while [ $attempt -le $max_attempts ]; do
|
|
||||||
echo "🔄 Build attempt $attempt of $max_attempts..."
|
|
||||||
|
|
||||||
if vite build --config $config_file; then
|
|
||||||
echo "✅ Build successful on attempt $attempt"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
echo "❌ Build failed on attempt $attempt"
|
|
||||||
if [ $attempt -lt $max_attempts ]; then
|
|
||||||
echo "⏳ Waiting 5 seconds before retry..."
|
|
||||||
sleep 5
|
|
||||||
# Clear memory caches
|
|
||||||
sync && echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
attempt=$((attempt + 1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "📦 Building all assets with memory optimization..."
|
|
||||||
|
|
||||||
# Try building with production config first
|
|
||||||
if build_with_retry "vite.config.production.js"; then
|
|
||||||
echo "🎉 Build completed successfully!"
|
|
||||||
echo "📊 Build summary:"
|
|
||||||
du -sh public/build/* 2>/dev/null || echo "Build files created"
|
|
||||||
|
|
||||||
# Count generated files
|
|
||||||
echo "📁 Generated files:"
|
|
||||||
find public/build -type f | wc -l | xargs echo "Total files:"
|
|
||||||
|
|
||||||
else
|
|
||||||
echo "❌ Build failed after all attempts!"
|
|
||||||
echo ""
|
|
||||||
echo "💡 Alternative solutions:"
|
|
||||||
echo " 1. ✨ Build locally: npm run build:local"
|
|
||||||
echo " 2. 🔧 Increase server memory/swap"
|
|
||||||
echo " 3. ☁️ Use GitHub Actions CI/CD"
|
|
||||||
echo " 4. 🚀 Use deployment services (Vercel, Netlify)"
|
|
||||||
echo ""
|
|
||||||
echo "🏠 For local build and deploy:"
|
|
||||||
echo " npm run build:local"
|
|
||||||
echo " ./deploy.sh your-username your-server.com /path/to/project"
|
|
||||||
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🔍 Verifying all essential files are built..."
|
|
||||||
|
|
||||||
# Check for essential files
|
|
||||||
essential_files=(
|
|
||||||
"public/build/manifest.json"
|
|
||||||
"public/build/assets"
|
|
||||||
)
|
|
||||||
|
|
||||||
missing_files=()
|
|
||||||
for file in "${essential_files[@]}"; do
|
|
||||||
if [ ! -e "$file" ]; then
|
|
||||||
missing_files+=("$file")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ${#missing_files[@]} -eq 0 ]; then
|
|
||||||
echo "✅ All essential files are present!"
|
|
||||||
else
|
|
||||||
echo "⚠️ Missing files:"
|
|
||||||
printf ' %s\n' "${missing_files[@]}"
|
|
||||||
fi
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Production build script dengan optimasi memory
|
|
||||||
# Untuk server dengan resource terbatas
|
|
||||||
|
|
||||||
echo "🔨 Starting production build with memory optimization..."
|
|
||||||
|
|
||||||
# Set Node.js memory limit (adjust sesuai RAM server)
|
|
||||||
# Untuk server dengan banyak file, gunakan memory yang lebih besar
|
|
||||||
export NODE_OPTIONS="--max-old-space-size=2048 --max-semi-space-size=1024"
|
|
||||||
|
|
||||||
# Use production vite config
|
|
||||||
export NODE_ENV=production
|
|
||||||
|
|
||||||
# Clean previous build
|
|
||||||
echo "🧹 Cleaning previous build..."
|
|
||||||
rm -rf public/build/*
|
|
||||||
|
|
||||||
# Build with limited resources
|
|
||||||
echo "📦 Building assets with memory optimization..."
|
|
||||||
|
|
||||||
# Option 1: Build with custom config
|
|
||||||
vite build --config vite.config.production.js
|
|
||||||
|
|
||||||
# Option 2: Alternative - build in chunks (uncomment if needed)
|
|
||||||
# echo "Building CSS files first..."
|
|
||||||
# vite build --config vite.config.production.js --mode css-only
|
|
||||||
#
|
|
||||||
# echo "Building JS files..."
|
|
||||||
# vite build --config vite.config.production.js --mode js-only
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo "✅ Build completed successfully!"
|
|
||||||
echo "📊 Build summary:"
|
|
||||||
du -sh public/build/*
|
|
||||||
else
|
|
||||||
echo "❌ Build failed!"
|
|
||||||
echo "💡 Try these solutions:"
|
|
||||||
echo " 1. Increase server memory"
|
|
||||||
echo " 2. Build locally and upload files"
|
|
||||||
echo " 3. Use swap memory (temporary solution)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -30,7 +30,7 @@ class MenuSeeder extends Seeder
|
|||||||
"sort_order" => 2,
|
"sort_order" => 2,
|
||||||
"children" => [
|
"children" => [
|
||||||
[
|
[
|
||||||
"name" => "Dashboard Pimpinan",
|
"name" => "Dashboard Pimpinan SIMBG",
|
||||||
"url" => "dashboard.home",
|
"url" => "dashboard.home",
|
||||||
"icon" => null,
|
"icon" => null,
|
||||||
"sort_order" => 1,
|
"sort_order" => 1,
|
||||||
@@ -67,6 +67,12 @@ class MenuSeeder extends Seeder
|
|||||||
"icon" => null,
|
"icon" => null,
|
||||||
"sort_order" => 4,
|
"sort_order" => 4,
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"name" => "Dashboard Pimpinan",
|
||||||
|
"url" => "dashboard.leader",
|
||||||
|
"icon" => null,
|
||||||
|
"sort_order" => 5,
|
||||||
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Debug script untuk diagnosa permission issues
|
|
||||||
# Jalankan di server untuk check masalah permission
|
|
||||||
|
|
||||||
PROJECT_PATH=${1:-"/var/www/pupr"}
|
|
||||||
|
|
||||||
echo "🔍 Debugging permissions for: $PROJECT_PATH"
|
|
||||||
echo "================================================="
|
|
||||||
|
|
||||||
# Check if path exists
|
|
||||||
if [ ! -d "$PROJECT_PATH" ]; then
|
|
||||||
echo "❌ Project path not found: $PROJECT_PATH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$PROJECT_PATH"
|
|
||||||
|
|
||||||
echo "📊 Current User & Groups:"
|
|
||||||
echo "Current user: $(whoami)"
|
|
||||||
echo "Web server user: $(ps aux | grep -E 'apache|nginx|httpd' | grep -v grep | head -1 | awk '{print $1}')"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "📁 Directory Ownership & Permissions:"
|
|
||||||
echo "Project root:"
|
|
||||||
ls -la . | head -5
|
|
||||||
echo ""
|
|
||||||
echo "Storage directory:"
|
|
||||||
ls -la storage/
|
|
||||||
echo ""
|
|
||||||
echo "Storage/framework:"
|
|
||||||
ls -la storage/framework/ 2>/dev/null || echo "storage/framework/ not found"
|
|
||||||
echo ""
|
|
||||||
echo "Bootstrap/cache:"
|
|
||||||
ls -la bootstrap/cache/ 2>/dev/null || echo "bootstrap/cache/ not found"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "🔐 Permission Analysis:"
|
|
||||||
# Check critical directories
|
|
||||||
directories=("storage" "storage/framework" "storage/framework/views" "storage/framework/cache" "storage/logs" "bootstrap/cache")
|
|
||||||
|
|
||||||
for dir in "${directories[@]}"; do
|
|
||||||
if [ -d "$dir" ]; then
|
|
||||||
perm=$(stat -c "%a" "$dir")
|
|
||||||
owner=$(stat -c "%U:%G" "$dir")
|
|
||||||
echo "✅ $dir: $perm ($owner)"
|
|
||||||
else
|
|
||||||
echo "❌ $dir: NOT FOUND"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "🧪 Write Test:"
|
|
||||||
# Test write permissions
|
|
||||||
if [ -w "storage/framework/" ]; then
|
|
||||||
echo "✅ storage/framework/ is writable"
|
|
||||||
# Try creating a test file
|
|
||||||
if touch storage/framework/test_write_$(date +%s).tmp 2>/dev/null; then
|
|
||||||
echo "✅ Can create files in storage/framework/"
|
|
||||||
rm -f storage/framework/test_write_*.tmp
|
|
||||||
else
|
|
||||||
echo "❌ Cannot create files in storage/framework/"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "❌ storage/framework/ is NOT writable"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "⚙️ SELinux Status (if applicable):"
|
|
||||||
if command -v getenforce &> /dev/null; then
|
|
||||||
echo "SELinux: $(getenforce)"
|
|
||||||
if [ "$(getenforce)" = "Enforcing" ]; then
|
|
||||||
echo "⚠️ SELinux is enforcing - may need additional configuration"
|
|
||||||
echo "Try: sudo setsebool -P httpd_unified on"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "SELinux not installed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "📋 Recommended Actions:"
|
|
||||||
echo "1. Fix ownership: sudo chown -R www-data:www-data $PROJECT_PATH"
|
|
||||||
echo "2. Fix permissions: sudo chmod -R 775 $PROJECT_PATH/storage/"
|
|
||||||
echo "3. Clear cache: php artisan view:clear"
|
|
||||||
echo "4. If SELinux: sudo setsebool -P httpd_unified on"
|
|
||||||
59
deploy.sh
59
deploy.sh
@@ -1,59 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Deploy script untuk build di local dan upload ke server
|
|
||||||
# Usage: ./deploy.sh [server-user] [server-host] [server-path]
|
|
||||||
|
|
||||||
# Default values (ganti sesuai server Anda)
|
|
||||||
SERVER_USER=${1:-"root"}
|
|
||||||
SERVER_HOST=${2:-"157.245.48.15"}
|
|
||||||
SERVER_PATH=${3:-"/var/www/pupr"}
|
|
||||||
|
|
||||||
echo "🚀 Starting deployment process..."
|
|
||||||
|
|
||||||
# 1. Clean previous build
|
|
||||||
echo "🧹 Cleaning previous build..."
|
|
||||||
rm -rf public/build/*
|
|
||||||
|
|
||||||
# 2. Install dependencies (jika belum)
|
|
||||||
echo "📦 Installing dependencies..."
|
|
||||||
npm ci --production=false
|
|
||||||
|
|
||||||
# 3. Build project
|
|
||||||
echo "🔨 Building project..."
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Check if build was successful
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "❌ Build failed!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✅ Build completed successfully!"
|
|
||||||
|
|
||||||
# 4. Upload build files to server
|
|
||||||
echo "📤 Uploading build files to server..."
|
|
||||||
rsync -avz --progress --delete public/build/ $SERVER_USER@$SERVER_HOST:$SERVER_PATH/public/build/
|
|
||||||
|
|
||||||
# 5. Upload other necessary files (optional)
|
|
||||||
echo "📤 Uploading other files..."
|
|
||||||
rsync -avz --progress \
|
|
||||||
--exclude='node_modules' \
|
|
||||||
--exclude='.git' \
|
|
||||||
--exclude='public/build' \
|
|
||||||
--exclude='storage/logs/*' \
|
|
||||||
--exclude='bootstrap/cache/*' \
|
|
||||||
./ $SERVER_USER@$SERVER_HOST:$SERVER_PATH/
|
|
||||||
|
|
||||||
echo "🔧 Fixing permissions on server..."
|
|
||||||
ssh $SERVER_USER@$SERVER_HOST "cd $SERVER_PATH && chmod +x fix-permissions.sh && sudo ./fix-permissions.sh $SERVER_PATH"
|
|
||||||
|
|
||||||
echo "📦 Installing composer dependencies on server..."
|
|
||||||
ssh $SERVER_USER@$SERVER_HOST "cd $SERVER_PATH && composer install --no-dev --optimize-autoloader"
|
|
||||||
|
|
||||||
echo "🎉 Deployment completed successfully!"
|
|
||||||
echo ""
|
|
||||||
echo "✅ Permissions have been automatically fixed!"
|
|
||||||
echo "✅ Composer dependencies installed!"
|
|
||||||
echo "✅ Laravel caches optimized!"
|
|
||||||
echo ""
|
|
||||||
echo "🌐 Your application should now be accessible without permission errors!"
|
|
||||||
41
docker/supervisor/laravel-production.conf
Normal file
41
docker/supervisor/laravel-production.conf
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
logfile=/var/log/supervisor/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
|
||||||
|
[program:laravel-queue-worker]
|
||||||
|
process_name=%(program_name)s_%(process_num)02d
|
||||||
|
command=php /var/www/pupr/artisan queue:work --queue=default --timeout=82800 --tries=3 --memory=512 --sleep=3
|
||||||
|
directory=/var/www/pupr
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
numprocs=2
|
||||||
|
redirect_stderr=true
|
||||||
|
stdout_logfile=/var/www/pupr/storage/logs/queue-worker.log
|
||||||
|
stdout_logfile_maxbytes=10MB
|
||||||
|
stdout_logfile_backups=5
|
||||||
|
stopasgroup=true
|
||||||
|
killasgroup=true
|
||||||
|
user=www-data
|
||||||
|
priority=10
|
||||||
|
|
||||||
|
[program:laravel-scheduler]
|
||||||
|
process_name=%(program_name)s_%(process_num)02d
|
||||||
|
command=php /var/www/pupr/artisan schedule:work
|
||||||
|
directory=/var/www/pupr
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
numprocs=1
|
||||||
|
redirect_stderr=true
|
||||||
|
stdout_logfile=/var/www/pupr/storage/logs/scheduler.log
|
||||||
|
stdout_logfile_maxbytes=10MB
|
||||||
|
stdout_logfile_backups=5
|
||||||
|
stopasgroup=true
|
||||||
|
killasgroup=true
|
||||||
|
user=www-data
|
||||||
|
priority=20
|
||||||
|
|
||||||
|
[group:laravel]
|
||||||
|
programs=laravel-queue-worker,laravel-scheduler
|
||||||
|
priority=999
|
||||||
@@ -15,4 +15,17 @@ stdout_logfile=/var/www/storage/logs/worker.log
|
|||||||
stopasgroup=true
|
stopasgroup=true
|
||||||
killasgroup=true
|
killasgroup=true
|
||||||
user=www-data
|
user=www-data
|
||||||
priority=10
|
priority=10
|
||||||
|
|
||||||
|
[program:laravel-scheduler]
|
||||||
|
process_name=%(program_name)s_%(process_num)02d
|
||||||
|
command=php /var/www/artisan schedule:work
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
numprocs=1
|
||||||
|
redirect_stderr=true
|
||||||
|
stdout_logfile=/var/www/storage/logs/scheduler.log
|
||||||
|
stopasgroup=true
|
||||||
|
killasgroup=true
|
||||||
|
user=www-data
|
||||||
|
priority=20
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script untuk fix permissions Laravel setelah deployment
|
|
||||||
# Jalankan di server production
|
|
||||||
|
|
||||||
PROJECT_PATH=${1:-"/var/www/pupr"}
|
|
||||||
|
|
||||||
echo "🔧 Fixing Laravel permissions for: $PROJECT_PATH"
|
|
||||||
|
|
||||||
# Check if path exists
|
|
||||||
if [ ! -d "$PROJECT_PATH" ]; then
|
|
||||||
echo "❌ Project path not found: $PROJECT_PATH"
|
|
||||||
echo "Usage: ./fix-permissions.sh /path/to/your/project"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$PROJECT_PATH"
|
|
||||||
|
|
||||||
echo "📁 Setting correct ownership..."
|
|
||||||
# Set ownership to web server user
|
|
||||||
sudo chown -R www-data:www-data .
|
|
||||||
|
|
||||||
echo "📂 Setting directory permissions..."
|
|
||||||
# Set directory permissions
|
|
||||||
sudo find . -type d -exec chmod 755 {} \;
|
|
||||||
|
|
||||||
echo "📄 Setting file permissions..."
|
|
||||||
# Set file permissions
|
|
||||||
sudo find . -type f -exec chmod 644 {} \;
|
|
||||||
|
|
||||||
echo "🔐 Setting special permissions for Laravel..."
|
|
||||||
# Storage and cache directories need write permissions
|
|
||||||
sudo chmod -R 775 storage/
|
|
||||||
sudo chmod -R 775 bootstrap/cache/
|
|
||||||
|
|
||||||
# Make sure these directories exist
|
|
||||||
sudo mkdir -p storage/framework/views
|
|
||||||
sudo mkdir -p storage/framework/cache
|
|
||||||
sudo mkdir -p storage/framework/sessions
|
|
||||||
sudo mkdir -p storage/logs
|
|
||||||
sudo mkdir -p storage/app/public
|
|
||||||
|
|
||||||
# Set ownership for storage and bootstrap/cache
|
|
||||||
sudo chown -R www-data:www-data storage/
|
|
||||||
sudo chown -R www-data:www-data bootstrap/cache/
|
|
||||||
|
|
||||||
echo "🔑 Setting executable permissions for Artisan..."
|
|
||||||
sudo chmod +x artisan
|
|
||||||
|
|
||||||
echo "🧹 Clearing Laravel caches..."
|
|
||||||
# Clear all caches
|
|
||||||
php artisan config:clear
|
|
||||||
php artisan route:clear
|
|
||||||
php artisan view:clear
|
|
||||||
php artisan cache:clear
|
|
||||||
|
|
||||||
# Recreate caches with correct permissions
|
|
||||||
php artisan config:cache
|
|
||||||
php artisan route:cache
|
|
||||||
php artisan view:cache
|
|
||||||
|
|
||||||
echo "📋 Checking permissions..."
|
|
||||||
echo "Storage permissions:"
|
|
||||||
ls -la storage/
|
|
||||||
echo ""
|
|
||||||
echo "Framework permissions:"
|
|
||||||
ls -la storage/framework/
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "✅ Permissions fixed successfully!"
|
|
||||||
echo "💡 If you still get permission errors, also run:"
|
|
||||||
echo " sudo setsebool -P httpd_can_network_connect on"
|
|
||||||
echo " sudo setsebool -P httpd_unified on"
|
|
||||||
378
resources/js/dashboards/leader.js
Normal file
378
resources/js/dashboards/leader.js
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
import Big from "big.js";
|
||||||
|
import GlobalConfig, { addThousandSeparators } from "../global-config.js";
|
||||||
|
import InitDatePicker from "../utils/InitDatePicker.js";
|
||||||
|
|
||||||
|
class BigData {
|
||||||
|
async init() {
|
||||||
|
try {
|
||||||
|
new InitDatePicker(
|
||||||
|
"#datepicker-dashboard-bigdata",
|
||||||
|
this.handleChangeDate.bind(this)
|
||||||
|
).init();
|
||||||
|
|
||||||
|
// Load initial data
|
||||||
|
this.updateData("latest");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error initializing data:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChangeDate(filterDate) {
|
||||||
|
if (!filterDate) return;
|
||||||
|
this.updateData(filterDate);
|
||||||
|
}
|
||||||
|
async updateData(filterDate) {
|
||||||
|
try {
|
||||||
|
this.resumeBigData = await this.getBigDataResume(filterDate);
|
||||||
|
|
||||||
|
this.initChartTargetPAD(filterDate);
|
||||||
|
this.initChartUsaha();
|
||||||
|
this.initChartNonUsaha();
|
||||||
|
this.initChartTotalPotensi();
|
||||||
|
this.initChartVerificationDocuments();
|
||||||
|
this.initChartNonVerificationDocuments();
|
||||||
|
this.initChartKekuranganPotensi();
|
||||||
|
this.initChartRealisasiTerbitPBG();
|
||||||
|
this.initChartMenungguKlikDPMPTSP();
|
||||||
|
this.initChartProsesDinasTeknis();
|
||||||
|
this.initChartPotensiTataRuang();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBigDataResume(filterByDate) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`${GlobalConfig.apiHost}/api/bigdata-resume?filterByDate=${filterByDate}`,
|
||||||
|
{
|
||||||
|
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 null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
element.innerText = ``;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-total.chart-target-pad")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
this.resumeBigData.target_pad.sum.toString()
|
||||||
|
)}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".small-percentage.chart-target-pad")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `${this.resumeBigData.target_pad.percentage}%`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
initChartTotalPotensi() {
|
||||||
|
// const countAll = this.resultDataTotal.countData ?? 0;
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-count.chart-total-potensi")
|
||||||
|
.forEach((element) => {
|
||||||
|
// 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.resumeBigData.total_potensi.sum.toString()
|
||||||
|
)}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".small-percentage.chart-total-potensi")
|
||||||
|
.forEach((element) => {
|
||||||
|
// 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.resumeBigData.verified_document.count}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-total.chart-berkas-terverifikasi")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
// 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.resumeBigData.verified_document.percentage}%`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
initChartNonVerificationDocuments() {
|
||||||
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
".document-count.chart-berkas-belum-terverifikasi"
|
||||||
|
)
|
||||||
|
.forEach((element) => {
|
||||||
|
// element.innerText = `${this.dataNonVerification.count}`;
|
||||||
|
element.innerText = `${this.resumeBigData.non_verified_document.count}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
".document-total.chart-berkas-belum-terverifikasi"
|
||||||
|
)
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
// this.bigTotalNonVerification.toString()
|
||||||
|
this.resumeBigData.non_verified_document.sum.toString()
|
||||||
|
)}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
".small-percentage.chart-berkas-belum-terverifikasi"
|
||||||
|
)
|
||||||
|
.forEach((element) => {
|
||||||
|
// 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.resumeBigData.business_document.count}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-total.chart-business")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
// this.bigTotalBusiness.toString()
|
||||||
|
this.resumeBigData.business_document.sum.toString()
|
||||||
|
)}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".small-percentage.chart-business")
|
||||||
|
.forEach((element) => {
|
||||||
|
// 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.resumeBigData.non_business_document.count}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-total.chart-non-business")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
// 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.resumeBigData.non_business_document.percentage}%`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
initChartKekuranganPotensi() {
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-count.chart-kekurangan-potensi")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = ``;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-total.chart-kekurangan-potensi")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
// 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.resumeBigData.kekurangan_potensi.percentage}%`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
initChartRealisasiTerbitPBG() {
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-count.chart-realisasi-tebit-pbg")
|
||||||
|
.forEach((element) => {
|
||||||
|
// 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.resumeBigData.realisasi_terbit.sum.toString()
|
||||||
|
)}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".small-percentage.chart-realisasi-tebit-pbg")
|
||||||
|
.forEach((element) => {
|
||||||
|
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.resumeBigData.menunggu_klik_dpmptsp.count}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-total.chart-menunggu-klik-dpmptsp")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
// this.dataSumMenungguKlikDPMPTSP
|
||||||
|
this.resumeBigData.menunggu_klik_dpmptsp.sum.toString()
|
||||||
|
)}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".small-percentage.chart-menunggu-klik-dpmptsp")
|
||||||
|
.forEach((element) => {
|
||||||
|
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.resumeBigData.proses_dinas_teknis.count}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-total.chart-proses-dinas-teknis")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
// this.dataSumProsesDinasTeknis
|
||||||
|
this.resumeBigData.proses_dinas_teknis.sum.toString()
|
||||||
|
)}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".small-percentage.chart-proses-dinas-teknis")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `${this.resumeBigData.proses_dinas_teknis.percentage}%`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
initChartPotensiTataRuang() {
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-count.chart-potensi-tata-ruang")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `${this.resumeBigData.tata_ruang.count}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".document-total.chart-potensi-tata-ruang")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `Rp.${addThousandSeparators(
|
||||||
|
this.resumeBigData.tata_ruang.sum.toString()
|
||||||
|
)}`;
|
||||||
|
});
|
||||||
|
document
|
||||||
|
.querySelectorAll(".small-percentage.chart-potensi-tata-ruang")
|
||||||
|
.forEach((element) => {
|
||||||
|
element.innerText = `${this.resumeBigData.tata_ruang.percentage}%`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", async function (e) {
|
||||||
|
await new BigData().init();
|
||||||
|
});
|
||||||
|
|
||||||
|
// function resizeDashboard() {
|
||||||
|
// //Target Width
|
||||||
|
// let targetElement = document.getElementById("dashboard-fixed-wrapper");
|
||||||
|
// let targetWidth = targetElement.offsetWidth;
|
||||||
|
// //console.log("TARGET ",targetWidth);
|
||||||
|
|
||||||
|
// //Real Object Width
|
||||||
|
// let dashboardElement = document.getElementById("dashboard-fixed-container");
|
||||||
|
// let dashboardWidth = 1110; //dashboardElement.offsetWidth;
|
||||||
|
// //console.log("CURRENT ",dashboardWidth);
|
||||||
|
|
||||||
|
// if (targetWidth > dashboardWidth) {
|
||||||
|
// targetWidth = dashboardWidth;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// dashboardElement.style.transformOrigin = "left top";
|
||||||
|
// dashboardElement.style.transition = "transform 0.2s ease-in-out";
|
||||||
|
// dashboardElement.style.transform =
|
||||||
|
// "scale(" + (targetWidth / dashboardWidth).toFixed(2) + ")";
|
||||||
|
// //console.log("SCALE ", (targetWidth/dashboardWidth).toFixed(2));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// window.addEventListener("load", function () {
|
||||||
|
// resizeDashboard();
|
||||||
|
// });
|
||||||
|
|
||||||
|
// window.addEventListener("resize", function () {
|
||||||
|
// resizeDashboard();
|
||||||
|
// });
|
||||||
|
|
||||||
|
function resizeDashboard() {
|
||||||
|
let targetElement = document.getElementById("dashboard-fixed-wrapper");
|
||||||
|
let dashboardElement = document.getElementById("dashboard-fixed-container");
|
||||||
|
|
||||||
|
let targetWidth = targetElement.offsetWidth;
|
||||||
|
let dashboardWidth = 1110;
|
||||||
|
|
||||||
|
let scaleFactor = (targetWidth / dashboardWidth).toFixed(2);
|
||||||
|
|
||||||
|
// Prevent scaling beyond 1 (100%) to avoid overflow
|
||||||
|
scaleFactor = Math.min(scaleFactor, 1);
|
||||||
|
|
||||||
|
dashboardElement.style.transformOrigin = "left top";
|
||||||
|
dashboardElement.style.transition = "transform 0.2s ease-in-out";
|
||||||
|
dashboardElement.style.transform = `scale(${scaleFactor})`;
|
||||||
|
|
||||||
|
// Ensure horizontal scrolling is allowed if necessary
|
||||||
|
document.body.style.overflowX = "auto";
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", resizeDashboard);
|
||||||
|
window.addEventListener("resize", resizeDashboard);
|
||||||
@@ -71,7 +71,6 @@ class SyncronizeTask {
|
|||||||
data.data.map((item) => [
|
data.data.map((item) => [
|
||||||
item.id,
|
item.id,
|
||||||
item.message,
|
item.message,
|
||||||
item.response_body,
|
|
||||||
item.status,
|
item.status,
|
||||||
item.start_time,
|
item.start_time,
|
||||||
item.duration,
|
item.duration,
|
||||||
|
|||||||
187
resources/views/dashboards/leader.blade.php
Normal file
187
resources/views/dashboards/leader.blade.php
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
@extends('layouts.vertical', ['subtitle' => 'Dashboards'])
|
||||||
|
|
||||||
|
@section('css')
|
||||||
|
@vite(['resources/scss/dashboards/_bigdata.scss'])
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
@include('layouts.partials/page-title', ['title' => 'Dashboards', 'subtitle' => 'Dashboard Pimpinan'])
|
||||||
|
|
||||||
|
<div id="dashboard-fixed-wrapper" class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mt-3 ms-2">
|
||||||
|
<h2 class="text-danger m-0">
|
||||||
|
ANALISA BIG DATA PROSES PBG <br>
|
||||||
|
MELALUI APLIKASI SIBEDAS PBG
|
||||||
|
</h2>
|
||||||
|
<div class="text-black text-end d-flex flex-column align-items-end me-3">
|
||||||
|
<span class="fs-5">Terakhir di update - {{$latest_created}}</span>
|
||||||
|
<input type="text" class="form-control mt-2" style="max-width: 125px;" id="datepicker-dashboard-bigdata" placeholder="Filter Date" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="dashboard-fixed-container" class="row" style="width:1110px;height:770px;position:relative;margin:auto;">
|
||||||
|
@component('components.circle', [
|
||||||
|
'document_title' => 'Kekurangan Potensi',
|
||||||
|
'document_color' => '#ff5757',
|
||||||
|
'document_type' => '',
|
||||||
|
'document_id' => 'chart-kekurangan-potensi',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'top:150px;'
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('components.circle', [
|
||||||
|
'document_title' => 'Target PAD',
|
||||||
|
'document_color' => '#204f6b',
|
||||||
|
'document_type' => '',
|
||||||
|
'document_id' => 'chart-target-pad',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'left:200px;',
|
||||||
|
'document_url' => route('data-settings.index', ['menu_id' => $menus->where('url','data-settings.index')->first()->id])
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<div class="square dia-top-left-bottom-right" style="top:150px;left:350px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="square dia-top-right-bottom-left" style="top:150px;left:150px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@component('components.circle', [
|
||||||
|
'document_title' => 'Total Potensi Berkas',
|
||||||
|
'document_color' => '#0097b3',
|
||||||
|
'document_type' => 'Pemohon',
|
||||||
|
'document_id' => 'chart-total-potensi',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'left:400px;top:150px;',
|
||||||
|
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'all'])
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<div class="square dia-top-right-bottom-left" style="top:300px;left:350px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="square dia-top-left-bottom-right" style="top:300px;left:550px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@component('components.circle', [
|
||||||
|
'document_title' => 'Perkiraan Potensi PBG Dari Tata Ruang',
|
||||||
|
'document_color' => '#ed9d2e',
|
||||||
|
'document_type' => '',
|
||||||
|
'document_id' => 'chart-potensi-tata-ruang',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'left:600px;',
|
||||||
|
'document_url' => route('web-spatial-plannings.index', ['menu_id' => $menus->where('url','web-spatial-plannings.index')->first()->id])
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<div class="square dia-top-right-bottom-left" style="top:150px;left:550px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@component('components.circle', [
|
||||||
|
'document_title' => 'Non Usaha',
|
||||||
|
'document_color' => '#399787',
|
||||||
|
'document_type' => 'Berkas',
|
||||||
|
'document_id' => 'chart-non-business',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'left:900px;top:150px;',
|
||||||
|
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'non-business'])
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('components.circle', [
|
||||||
|
'document_title' => 'Usaha',
|
||||||
|
'document_color' => '#5e7c89',
|
||||||
|
'document_type' => 'Berkas',
|
||||||
|
'document_id' => 'chart-business',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'left:900px;top:400px;',
|
||||||
|
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'business'])
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('components.circle', [
|
||||||
|
'document_title' => 'Berkas Terverifikasi',
|
||||||
|
'document_color' => '#5170ff',
|
||||||
|
'document_type' => 'Berkas',
|
||||||
|
'document_id' => 'chart-berkas-terverifikasi',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'top:300px;left:200px;',
|
||||||
|
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'verified'])
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<div class="square dia-top-right-bottom-left" style="top:500px;left:200px;width:50px">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="square dia-top-left-bottom-right" style="top:450px;left:350px;width:500px;height:200px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@component('components.circle', [
|
||||||
|
'document_title' => 'Berkas Belum Terverifikasi',
|
||||||
|
'document_color' => '#5170ff',
|
||||||
|
'document_type' => 'Berkas',
|
||||||
|
'document_id' => 'chart-berkas-belum-terverifikasi',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'top:300px;left:600px;',
|
||||||
|
'document_url' => route('pbg-task.index', ['menu_id' => $menus->where('url','pbg-task.index')->first()->id, 'filter' => 'non-verified'])
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<div class="square dia-top-right-bottom-left" style="top:200px;left:750px;width:250px;height:150px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="square dia-top-left-bottom-right" style="top:400px;left:750px;width:250px;height:150px;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@component('components.circle',[
|
||||||
|
'document_title' => 'Realisasi Terbit PBG',
|
||||||
|
'document_color' => '#8cc540',
|
||||||
|
'document_type' => 'Berkas',
|
||||||
|
'document_id' => 'chart-realisasi-tebit-pbg',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'top:550px;left:100px;',
|
||||||
|
'document_url' => 'https://docs.google.com/spreadsheets/d/1QoXzuLdEX3MK70Yrfigz0Qj5rAt4T819jX85vubBNdY/edit?gid=1514195399#gid=1514195399'
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<div class="square" style="top:650px;left:200px;width:250px;height:2px;background-color:black;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@component('components.circle',[
|
||||||
|
'document_title' => 'Menunggu Klik DPMPTSP',
|
||||||
|
'document_color' => '#00bf61',
|
||||||
|
'document_type' => 'Berkas',
|
||||||
|
'document_id' => 'chart-menunggu-klik-dpmptsp',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'top:550px;left:400px',
|
||||||
|
'document_url' => 'https://docs.google.com/spreadsheets/d/1QoXzuLdEX3MK70Yrfigz0Qj5rAt4T819jX85vubBNdY/edit?gid=1514195399#gid=1514195399'
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<div class="square" style="top:650px;left:600px;width:250px;height:2px;background-color:black;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@component('components.circle',[
|
||||||
|
'document_title' => 'Berproses Di Dinas Teknis',
|
||||||
|
'document_color' => '#737373',
|
||||||
|
'document_type' => 'Berkas',
|
||||||
|
'document_id' => 'chart-proses-dinas-teknis',
|
||||||
|
'visible_small_circle' => true,
|
||||||
|
'style' => 'top:550px;left:700px',
|
||||||
|
'document_url' => 'https://docs.google.com/spreadsheets/d/1QoXzuLdEX3MK70Yrfigz0Qj5rAt4T819jX85vubBNdY/edit?gid=1514195399#gid=1514195399'
|
||||||
|
])
|
||||||
|
@endcomponent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('scripts')
|
||||||
|
@vite(['resources/js/dashboards/bigdata.js'])
|
||||||
|
@endsection
|
||||||
@@ -8,4 +8,5 @@ Artisan::command('inspire', function () {
|
|||||||
$this->comment(Inspiring::quote());
|
$this->comment(Inspiring::quote());
|
||||||
})->purpose('Display an inspiring quote')->hourly();
|
})->purpose('Display an inspiring quote')->hourly();
|
||||||
|
|
||||||
Schedule::command("app:scraping-data")->dailyAt("00:00");
|
Schedule::command("app:scraping-leader-data")->dailyAt("00:00");
|
||||||
|
Schedule::command("app:scraping-data")->dailyAt("00:30");
|
||||||
@@ -51,6 +51,7 @@ Route::group(['middleware' => 'auth'], function(){
|
|||||||
//dashboards
|
//dashboards
|
||||||
Route::group(['prefix' => '/dashboards'], function(){
|
Route::group(['prefix' => '/dashboards'], function(){
|
||||||
Route::get('/bigdata', [BigDataController::class, 'index'])->name('dashboard.home');
|
Route::get('/bigdata', [BigDataController::class, 'index'])->name('dashboard.home');
|
||||||
|
Route::get('/leader', [BigDataController::class, 'leader'])->name('dashboard.leader');
|
||||||
Route::get('/dashboard-pbg', [BigDataController::class, 'pbg'])->name('dashboard.pbg');
|
Route::get('/dashboard-pbg', [BigDataController::class, 'pbg'])->name('dashboard.pbg');
|
||||||
Route::get('/lack-of-potential', [LackOfPotentialController::class, 'lack_of_potential'])->name('dashboard.lack_of_potential');
|
Route::get('/lack-of-potential', [LackOfPotentialController::class, 'lack_of_potential'])->name('dashboard.lack_of_potential');
|
||||||
Route::get('/maps', [GoogleApisController::class, 'index'])->name('dashboard.maps');
|
Route::get('/maps', [GoogleApisController::class, 'index'])->name('dashboard.maps');
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Server setup untuk optimasi memory dan build
|
|
||||||
# Jalankan dengan sudo di server production
|
|
||||||
|
|
||||||
echo "🔧 Setting up server for optimized building..."
|
|
||||||
|
|
||||||
# 1. Check current memory
|
|
||||||
echo "📊 Current memory status:"
|
|
||||||
free -h
|
|
||||||
|
|
||||||
# 2. Setup swap file (temporary solution for low memory)
|
|
||||||
echo "💾 Setting up swap file (1GB)..."
|
|
||||||
if [ ! -f /swapfile ]; then
|
|
||||||
fallocate -l 1G /swapfile
|
|
||||||
chmod 600 /swapfile
|
|
||||||
mkswap /swapfile
|
|
||||||
sysctl vm.swappiness=10
|
|
||||||
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
|
||||||
echo 'vm.swappiness=10' >> /etc/sysctl.conf
|
|
||||||
swapon /swapfile
|
|
||||||
echo "✅ Swap file created and activated"
|
|
||||||
else
|
|
||||||
echo "ℹ️ Swap file already exists"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 3. Optimize Node.js for production
|
|
||||||
echo "⚙️ Optimizing Node.js..."
|
|
||||||
npm config set fund false
|
|
||||||
npm config set audit false
|
|
||||||
|
|
||||||
# 4. Install PM2 untuk process management
|
|
||||||
echo "📦 Installing PM2..."
|
|
||||||
npm install -g pm2
|
|
||||||
|
|
||||||
# 5. Create PM2 ecosystem file for build process
|
|
||||||
cat > ecosystem.config.js << 'EOF'
|
|
||||||
module.exports = {
|
|
||||||
apps: [{
|
|
||||||
name: 'build-app',
|
|
||||||
script: 'npm',
|
|
||||||
args: 'run build:prod',
|
|
||||||
instances: 1,
|
|
||||||
autorestart: false,
|
|
||||||
watch: false,
|
|
||||||
max_memory_restart: '1G',
|
|
||||||
env: {
|
|
||||||
NODE_ENV: 'production',
|
|
||||||
NODE_OPTIONS: '--max-old-space-size=1024'
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo "✅ Server setup completed!"
|
|
||||||
echo ""
|
|
||||||
echo "📝 Now you can:"
|
|
||||||
echo " 1. Build with memory limit: npm run build:prod"
|
|
||||||
echo " 2. Build with PM2: pm2 start ecosystem.config.js"
|
|
||||||
echo " 3. Monitor: pm2 monit"
|
|
||||||
echo " 4. Check memory: free -h"
|
|
||||||
@@ -4,26 +4,26 @@ import path from "path";
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: "0.0.0.0",
|
||||||
hmr: {
|
hmr: {
|
||||||
host: 'localhost'
|
host: "localhost",
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
usePolling: true
|
usePolling: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: 'public/build',
|
outDir: "public/build",
|
||||||
assetsDir: 'assets',
|
assetsDir: "assets",
|
||||||
manifest: true,
|
manifest: "manifest.json",
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
manualChunks: undefined,
|
manualChunks: undefined,
|
||||||
entryFileNames: 'assets/[name].js',
|
entryFileNames: "assets/[name].js",
|
||||||
chunkFileNames: 'assets/[name].js',
|
chunkFileNames: "assets/[name].js",
|
||||||
assetFileNames: 'assets/[name].[ext]'
|
assetFileNames: "assets/[name].[ext]",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
@@ -82,6 +82,7 @@ export default defineConfig({
|
|||||||
"resources/js/dashboards/bigdata.js",
|
"resources/js/dashboards/bigdata.js",
|
||||||
"resources/js/dashboards/potentials/inside_system.js",
|
"resources/js/dashboards/potentials/inside_system.js",
|
||||||
"resources/js/dashboards/potentials/outside_system.js",
|
"resources/js/dashboards/potentials/outside_system.js",
|
||||||
|
"resources/js/dashboards/leader.js",
|
||||||
// roles
|
// roles
|
||||||
"resources/js/roles/index.js",
|
"resources/js/roles/index.js",
|
||||||
"resources/js/roles/create.js",
|
"resources/js/roles/create.js",
|
||||||
|
|||||||
@@ -4,46 +4,46 @@ import path from "path";
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: "0.0.0.0",
|
||||||
hmr: {
|
hmr: {
|
||||||
host: 'localhost'
|
host: "localhost",
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
usePolling: true
|
usePolling: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: 'public/build',
|
outDir: "public/build",
|
||||||
assetsDir: 'assets',
|
assetsDir: "assets",
|
||||||
manifest: true,
|
manifest: "manifest.json",
|
||||||
// Optimasi untuk server dengan resource terbatas
|
// Optimasi untuk server dengan resource terbatas
|
||||||
minify: 'terser',
|
minify: "terser",
|
||||||
chunkSizeWarningLimit: 1000,
|
chunkSizeWarningLimit: 1000,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
manualChunks: {
|
manualChunks: {
|
||||||
// Split vendor chunks untuk mengurangi memory usage
|
// Split vendor chunks untuk mengurangi memory usage
|
||||||
vendor: ['bootstrap', 'moment', 'axios'],
|
vendor: ["bootstrap", "moment", "axios"],
|
||||||
charts: ['apexcharts'],
|
charts: ["apexcharts"],
|
||||||
maps: ['leaflet', 'jsvectormap', 'gmaps'],
|
maps: ["leaflet", "jsvectormap", "gmaps"],
|
||||||
ui: ['sweetalert2', 'flatpickr', 'quill', 'dropzone'],
|
ui: ["sweetalert2", "flatpickr", "quill", "dropzone"],
|
||||||
forms: ['gridjs', 'simplebar'],
|
forms: ["gridjs", "simplebar"],
|
||||||
// Group by functionality to reduce memory usage per chunk
|
// Group by functionality to reduce memory usage per chunk
|
||||||
dashboards: [
|
dashboards: [
|
||||||
'resources/js/dashboards/bigdata.js',
|
"resources/js/dashboards/bigdata.js",
|
||||||
'resources/js/dashboards/pbg.js',
|
"resources/js/dashboards/pbg.js",
|
||||||
'resources/js/dashboards/potentials/inside_system.js',
|
"resources/js/dashboards/potentials/inside_system.js",
|
||||||
'resources/js/dashboards/potentials/outside_system.js'
|
"resources/js/dashboards/potentials/outside_system.js",
|
||||||
],
|
],
|
||||||
data: [
|
data: [
|
||||||
'resources/js/data/umkm/data-umkm.js',
|
"resources/js/data/umkm/data-umkm.js",
|
||||||
'resources/js/data/tourisms/data-tourisms.js',
|
"resources/js/data/tourisms/data-tourisms.js",
|
||||||
'resources/js/data/advertisements/data-advertisements.js'
|
"resources/js/data/advertisements/data-advertisements.js",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
entryFileNames: 'assets/[name]-[hash].js',
|
entryFileNames: "assets/[name]-[hash].js",
|
||||||
chunkFileNames: 'assets/[name]-[hash].js',
|
chunkFileNames: "assets/[name]-[hash].js",
|
||||||
assetFileNames: 'assets/[name]-[hash].[ext]'
|
assetFileNames: "assets/[name]-[hash].[ext]",
|
||||||
},
|
},
|
||||||
// Optimasi memory - lebih konservatif
|
// Optimasi memory - lebih konservatif
|
||||||
maxParallelFileOps: 1,
|
maxParallelFileOps: 1,
|
||||||
@@ -54,9 +54,9 @@ export default defineConfig({
|
|||||||
terserOptions: {
|
terserOptions: {
|
||||||
compress: {
|
compress: {
|
||||||
drop_console: true,
|
drop_console: true,
|
||||||
drop_debugger: true
|
drop_debugger: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
@@ -115,6 +115,7 @@ export default defineConfig({
|
|||||||
"resources/js/dashboards/bigdata.js",
|
"resources/js/dashboards/bigdata.js",
|
||||||
"resources/js/dashboards/potentials/inside_system.js",
|
"resources/js/dashboards/potentials/inside_system.js",
|
||||||
"resources/js/dashboards/potentials/outside_system.js",
|
"resources/js/dashboards/potentials/outside_system.js",
|
||||||
|
"resources/js/dashboards/leader.js",
|
||||||
// roles
|
// roles
|
||||||
"resources/js/roles/index.js",
|
"resources/js/roles/index.js",
|
||||||
"resources/js/roles/create.js",
|
"resources/js/roles/create.js",
|
||||||
@@ -186,6 +187,6 @@ export default defineConfig({
|
|||||||
],
|
],
|
||||||
// Limit memory usage
|
// Limit memory usage
|
||||||
esbuild: {
|
esbuild: {
|
||||||
target: 'es2015'
|
target: "es2015",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user