From 22ed13bf4c1d0fe00068ddde7f299d8c08461441 Mon Sep 17 00:00:00 2001 From: rijalhabibullah Date: Mon, 1 Jun 2026 21:10:52 +0700 Subject: [PATCH] tambah data yg hilang --- mobile_TA/padi_app/lib/screen/login.dart | 5 +- .../padi_app/lib/screen/register_screen.dart | 6 +- .../lib/services/classification_service.dart | 2 +- .../lib/services/product_service.dart | 5 +- mobile_TA/padi_app/lib/utils/api_config.dart | 6 ++ .../Controllers/ClassificationController.php | 57 ++++++++++++++++++- 6 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 mobile_TA/padi_app/lib/utils/api_config.dart diff --git a/mobile_TA/padi_app/lib/screen/login.dart b/mobile_TA/padi_app/lib/screen/login.dart index d276cb4..f6673db 100644 --- a/mobile_TA/padi_app/lib/screen/login.dart +++ b/mobile_TA/padi_app/lib/screen/login.dart @@ -4,6 +4,7 @@ import 'package:http/http.dart' as http; import 'dart:convert'; import '../main.dart'; // Mengarah ke MainNavigation di main.dart import 'register_screen.dart'; +import '../utils/api_config.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @@ -35,7 +36,7 @@ class _LoginScreenState extends State { try { final response = await http .post( - Uri.parse('https://gobony-wedgy-cathi.ngrok-free.dev/api/mobile/login'), + Uri.parse('${ApiConfig.apiRoot}/mobile/login'), headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', @@ -45,7 +46,7 @@ class _LoginScreenState extends State { 'password': password, }), ) - .timeout(const Duration(seconds: 15)); + .timeout(const Duration(seconds: 30)); if (response.statusCode != 200) { throw Exception('Login gagal'); diff --git a/mobile_TA/padi_app/lib/screen/register_screen.dart b/mobile_TA/padi_app/lib/screen/register_screen.dart index f9e4381..c300966 100644 --- a/mobile_TA/padi_app/lib/screen/register_screen.dart +++ b/mobile_TA/padi_app/lib/screen/register_screen.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; -// import 'login_screen.dart'; // Nanti ini dipakai untuk kembali ke halaman login +import '../utils/api_config.dart'; class RegisterScreen extends StatefulWidget { const RegisterScreen({super.key}); @@ -45,7 +45,7 @@ class _RegisterScreenState extends State { try { final response = await http .post( - Uri.parse('https://gobony-wedgy-cathi.ngrok-free.dev/api/mobile/register'), + Uri.parse('${ApiConfig.apiRoot}/mobile/register'), headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', @@ -56,7 +56,7 @@ class _RegisterScreenState extends State { 'password_confirmation': confirmPassword, }), ) - .timeout(const Duration(seconds: 15)); + .timeout(const Duration(seconds: 30)); if (response.statusCode != 201) { final jsonResponse = jsonDecode(response.body); diff --git a/mobile_TA/padi_app/lib/services/classification_service.dart b/mobile_TA/padi_app/lib/services/classification_service.dart index 757862b..107a974 100644 --- a/mobile_TA/padi_app/lib/services/classification_service.dart +++ b/mobile_TA/padi_app/lib/services/classification_service.dart @@ -213,7 +213,7 @@ class ClassificationService { Uri.parse('$_historyUrl?page=$page&per_page=1000$userParam'), headers: {'Accept': 'application/json'}, ) - .timeout(const Duration(seconds: 15)); + .timeout(const Duration(seconds: 30)); if (response.statusCode != 200) { throw Exception('Gagal mengambil riwayat'); diff --git a/mobile_TA/padi_app/lib/services/product_service.dart b/mobile_TA/padi_app/lib/services/product_service.dart index 45419d1..3cd6ef7 100644 --- a/mobile_TA/padi_app/lib/services/product_service.dart +++ b/mobile_TA/padi_app/lib/services/product_service.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:async'; import 'package:http/http.dart' as http; +import '../utils/api_config.dart'; class ProductItem { final int id; @@ -44,7 +45,7 @@ class ProductItem { class ProductService { // Samakan dengan API root di classification_service.dart - static const String _apiRoot = 'https://gobony-wedgy-cathi.ngrok-free.dev/api'; + static const String _apiRoot = ApiConfig.apiRoot; static const String _productsUrl = '$_apiRoot/products'; final http.Client _httpClient; @@ -55,7 +56,7 @@ class ProductService { try { final response = await _httpClient .get(Uri.parse(_productsUrl), headers: {'Accept': 'application/json'}) - .timeout(const Duration(seconds: 15)); + .timeout(const Duration(seconds: 30)); if (response.statusCode != 200) { throw Exception('Gagal mengambil produk'); diff --git a/mobile_TA/padi_app/lib/utils/api_config.dart b/mobile_TA/padi_app/lib/utils/api_config.dart new file mode 100644 index 0000000..f742765 --- /dev/null +++ b/mobile_TA/padi_app/lib/utils/api_config.dart @@ -0,0 +1,6 @@ +class ApiConfig { + // Ganti URL ini jika ngrok Anda di-restart atau jika menggunakan IP server lokal + // Contoh Ngrok: 'https://YOUR_SUBDOMAIN.ngrok-free.dev/api' + // Contoh IP Lokal (WiFi): 'http://192.168.1.16:8000/api' + static const String apiRoot = 'https://gobony-wedgy-cathi.ngrok-free.dev/api'; +} diff --git a/web_TA/app/Http/Controllers/ClassificationController.php b/web_TA/app/Http/Controllers/ClassificationController.php index 9f42e2b..c75f088 100644 --- a/web_TA/app/Http/Controllers/ClassificationController.php +++ b/web_TA/app/Http/Controllers/ClassificationController.php @@ -159,17 +159,72 @@ public function classifyAndSave(Request $request) $diseaseInfo = $this->getDiseaseInfo($result['predicted_class']); - // Skip database save for now - just return prediction result + // Extract location components + $locationAddress = $request->input('location_address'); + $locationLat = $request->input('location_lat'); + $locationLng = $request->input('location_lng'); + $kabupaten = $request->input('kabupaten'); + $kecamatan = $request->input('kecamatan'); + $kelurahan = $request->input('kelurahan'); + + // Fallback parsing if address is provided but components are missing + if ($locationAddress && (!$kabupaten || !$kecamatan || !$kelurahan)) { + $parsedLoc = $this->extractLocationComponents($locationAddress, $locationLat, $locationLng); + $kabupaten = $kabupaten ?: $parsedLoc['kabupaten']; + $kecamatan = $kecamatan ?: $parsedLoc['kecamatan']; + $kelurahan = $kelurahan ?: $parsedLoc['kelurahan']; + } + + // Simpan ke database Model Classification (untuk riwayat di mobile) + $classification = Classification::create([ + 'user_id' => $request->input('user_id'), + 'image_path' => $storagePath, + 'filename' => $file->getClientOriginalName(), + 'predicted_class' => $result['predicted_class'], + 'confidence' => (float) $result['confidence'], + 'all_predictions' => $result['all_predictions'], + 'disease_name' => $diseaseInfo['name'] ?? null, + 'severity' => $diseaseInfo['severity'] ?? null, + 'notes' => $request->input('notes'), + 'location_address' => $locationAddress, + 'location_lat' => $locationLat, + 'location_lng' => $locationLng, + 'kabupaten' => $kabupaten, + 'kecamatan' => $kecamatan, + 'kelurahan' => $kelurahan, + ]); + + // Simpan ke database Model ClassificationHistory (untuk riwayat di web admin) + if ($request->filled('user_id')) { + ClassificationHistory::create([ + 'user_id' => $request->input('user_id'), + 'jenis_penyakit' => $diseaseInfo['name'] ?? $result['predicted_class'], + 'location_address' => $locationAddress, + 'location_lat' => $locationLat, + 'location_lng' => $locationLng, + 'kabupaten' => $kabupaten, + 'kecamatan' => $kecamatan, + 'kelurahan' => $kelurahan, + ]); + } + return response()->json([ 'success' => true, 'message' => 'Gambar berhasil diklasifikasi dan disimpan', 'data' => [ + 'id' => $classification->id, 'image_path' => Storage::url($storagePath), 'predicted_class' => $result['predicted_class'], 'confidence' => round($result['confidence'] * 100, 2) . '%', 'confidence_value' => $result['confidence'], 'all_predictions' => $result['all_predictions'], 'disease_info' => $diseaseInfo, + 'location_address' => $classification->location_address, + 'location_lat' => $classification->location_lat, + 'location_lng' => $classification->location_lng, + 'kabupaten' => $classification->kabupaten, + 'kecamatan' => $classification->kecamatan, + 'kelurahan' => $classification->kelurahan, 'timestamp' => now(), ] ], 200);