tambah data yg hilang

This commit is contained in:
rijalhabibullah 2026-06-01 21:10:52 +07:00
parent c44202b92e
commit 22ed13bf4c
6 changed files with 72 additions and 9 deletions

View File

@ -4,6 +4,7 @@ import 'package:http/http.dart' as http;
import 'dart:convert'; import 'dart:convert';
import '../main.dart'; // Mengarah ke MainNavigation di main.dart import '../main.dart'; // Mengarah ke MainNavigation di main.dart
import 'register_screen.dart'; import 'register_screen.dart';
import '../utils/api_config.dart';
class LoginScreen extends StatefulWidget { class LoginScreen extends StatefulWidget {
const LoginScreen({super.key}); const LoginScreen({super.key});
@ -35,7 +36,7 @@ class _LoginScreenState extends State<LoginScreen> {
try { try {
final response = await http final response = await http
.post( .post(
Uri.parse('https://gobony-wedgy-cathi.ngrok-free.dev/api/mobile/login'), Uri.parse('${ApiConfig.apiRoot}/mobile/login'),
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -45,7 +46,7 @@ class _LoginScreenState extends State<LoginScreen> {
'password': password, 'password': password,
}), }),
) )
.timeout(const Duration(seconds: 15)); .timeout(const Duration(seconds: 30));
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Login gagal'); throw Exception('Login gagal');

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'dart:convert'; import 'dart:convert';
// import 'login_screen.dart'; // Nanti ini dipakai untuk kembali ke halaman login import '../utils/api_config.dart';
class RegisterScreen extends StatefulWidget { class RegisterScreen extends StatefulWidget {
const RegisterScreen({super.key}); const RegisterScreen({super.key});
@ -45,7 +45,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
try { try {
final response = await http final response = await http
.post( .post(
Uri.parse('https://gobony-wedgy-cathi.ngrok-free.dev/api/mobile/register'), Uri.parse('${ApiConfig.apiRoot}/mobile/register'),
headers: { headers: {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -56,7 +56,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
'password_confirmation': confirmPassword, 'password_confirmation': confirmPassword,
}), }),
) )
.timeout(const Duration(seconds: 15)); .timeout(const Duration(seconds: 30));
if (response.statusCode != 201) { if (response.statusCode != 201) {
final jsonResponse = jsonDecode(response.body); final jsonResponse = jsonDecode(response.body);

View File

@ -213,7 +213,7 @@ class ClassificationService {
Uri.parse('$_historyUrl?page=$page&per_page=1000$userParam'), Uri.parse('$_historyUrl?page=$page&per_page=1000$userParam'),
headers: {'Accept': 'application/json'}, headers: {'Accept': 'application/json'},
) )
.timeout(const Duration(seconds: 15)); .timeout(const Duration(seconds: 30));
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Gagal mengambil riwayat'); throw Exception('Gagal mengambil riwayat');

View File

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:async'; import 'dart:async';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import '../utils/api_config.dart';
class ProductItem { class ProductItem {
final int id; final int id;
@ -44,7 +45,7 @@ class ProductItem {
class ProductService { class ProductService {
// Samakan dengan API root di classification_service.dart // 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'; static const String _productsUrl = '$_apiRoot/products';
final http.Client _httpClient; final http.Client _httpClient;
@ -55,7 +56,7 @@ class ProductService {
try { try {
final response = await _httpClient final response = await _httpClient
.get(Uri.parse(_productsUrl), headers: {'Accept': 'application/json'}) .get(Uri.parse(_productsUrl), headers: {'Accept': 'application/json'})
.timeout(const Duration(seconds: 15)); .timeout(const Duration(seconds: 30));
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Gagal mengambil produk'); throw Exception('Gagal mengambil produk');

View File

@ -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';
}

View File

@ -159,17 +159,72 @@ public function classifyAndSave(Request $request)
$diseaseInfo = $this->getDiseaseInfo($result['predicted_class']); $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([ return response()->json([
'success' => true, 'success' => true,
'message' => 'Gambar berhasil diklasifikasi dan disimpan', 'message' => 'Gambar berhasil diklasifikasi dan disimpan',
'data' => [ 'data' => [
'id' => $classification->id,
'image_path' => Storage::url($storagePath), 'image_path' => Storage::url($storagePath),
'predicted_class' => $result['predicted_class'], 'predicted_class' => $result['predicted_class'],
'confidence' => round($result['confidence'] * 100, 2) . '%', 'confidence' => round($result['confidence'] * 100, 2) . '%',
'confidence_value' => $result['confidence'], 'confidence_value' => $result['confidence'],
'all_predictions' => $result['all_predictions'], 'all_predictions' => $result['all_predictions'],
'disease_info' => $diseaseInfo, '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(), 'timestamp' => now(),
] ]
], 200); ], 200);