update
This commit is contained in:
parent
45115b3367
commit
1365a65409
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ForgotUsernameController extends Controller
|
||||
{
|
||||
// Tampilkan form lupa username
|
||||
public function showForm()
|
||||
{
|
||||
return view('admin.pages.auth.forgot-username');
|
||||
}
|
||||
|
||||
// Proses kirim username ke email
|
||||
public function sendUsername(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email|exists:users,email',
|
||||
]);
|
||||
|
||||
$user = User::where('email', $request->email)->first();
|
||||
|
||||
if (!$user) {
|
||||
return back()->withErrors(['email' => 'Email tidak ditemukan.']);
|
||||
}
|
||||
|
||||
Mail::send('emails.username-reminder', ['user' => $user], function ($message) use ($user) {
|
||||
$message->to($user->email);
|
||||
$message->subject('Pengingat Username Anda');
|
||||
});
|
||||
|
||||
return back()->with('status', 'Username telah dikirim ke email Anda.');
|
||||
}
|
||||
}
|
||||
|
|
@ -17,10 +17,12 @@ class HomeController extends Controller
|
|||
{
|
||||
public function index()
|
||||
{
|
||||
// Mengambil semua subkriteria beserta relasi kriterianya, lalu mengelompokkan berdasarkan nama kriteria
|
||||
$subKriteria = SubKriteria::with('kriteria')->get()->groupBy(function ($item) {
|
||||
return $item->kriteria->nama_kriteria;
|
||||
});
|
||||
|
||||
// Mengambil semua data pakaian beserta relasi ke subkriteria
|
||||
$pakaians = Pakaian::with('subKriterias')->get();
|
||||
|
||||
return view('landingpage.master', [
|
||||
|
@ -30,31 +32,33 @@ class HomeController extends Controller
|
|||
}
|
||||
public function prosesRekomendasi(Request $request)
|
||||
{
|
||||
// Input validation and processing
|
||||
// Memproses input pengguna dari form
|
||||
$userInput = $this->processUserInput($request->input('sub_kriteria', []));
|
||||
|
||||
// Jika tidak ada input yang valid, tampilkan pesan error
|
||||
if (empty($userInput)) {
|
||||
return $this->returnNoResults('Silakan pilih minimal satu kriteria.');
|
||||
}
|
||||
|
||||
// \Log::debug('User Input:', $userInput);
|
||||
|
||||
// Get selected subcriteria data
|
||||
// Mengambil data subkriteria berdasarkan input user
|
||||
$selectedSubkriteria = SubKriteria::whereIn('id', collect($userInput)->flatten())
|
||||
->get()
|
||||
->keyBy('id');
|
||||
|
||||
// Extract criteria inputs
|
||||
// Menyusun input berdasarkan jenis kriteria
|
||||
$criteriaInputs = $this->extractCriteriaInputs($userInput, $selectedSubkriteria);
|
||||
|
||||
// Apply strict filtering
|
||||
// Filter ketat berdasarkan input wajib
|
||||
$filteredClothing = $this->applyStrictFiltering($criteriaInputs);
|
||||
|
||||
// Jika tidak ada hasil setelah filter, tampilkan pesan
|
||||
if ($filteredClothing->isEmpty()) {
|
||||
return $this->returnNoResults('Tidak ada pakaian yang sesuai dengan kriteria yang Anda pilih.');
|
||||
}
|
||||
|
||||
// Calculate recommendations using weighted scoring
|
||||
// Hitung rekomendasi menggunakan metode SAW
|
||||
$recommendations = $this->calculateRecommendations($filteredClothing, $userInput);
|
||||
|
||||
return view('landingpage.hasil', compact('recommendations'));
|
||||
|
@ -70,11 +74,12 @@ class HomeController extends Controller
|
|||
foreach ($userInput as $kriteria_id => $subkriteria) {
|
||||
$subkriteriaArray = (array) $subkriteria;
|
||||
|
||||
// Remove empty values and validate
|
||||
// Buang nilai kosong dan pastikan hanya angka yang valid
|
||||
$cleanedSubkriteria = array_filter($subkriteriaArray, function($value) {
|
||||
return !empty($value) && is_numeric($value);
|
||||
});
|
||||
|
||||
// Simpan hanya jika ada nilai yang valid
|
||||
if (!empty($cleanedSubkriteria)) {
|
||||
$processedInput[$kriteria_id] = array_map('intval', $cleanedSubkriteria);
|
||||
}
|
||||
|
@ -96,7 +101,7 @@ class HomeController extends Controller
|
|||
'lokasi' => $userInput[5] ?? [] // Criteria 5: Location
|
||||
];
|
||||
|
||||
// Calculate price range if price criteria is selected
|
||||
// Jika kriteria harga dipilih, hitung rentang harga min dan max
|
||||
if (!empty($inputs['harga'])) {
|
||||
$hargaRanges = $selectedSubkriteria->only($inputs['harga']);
|
||||
$inputs['harga_min'] = $hargaRanges->min('min_value');
|
||||
|
@ -115,7 +120,7 @@ class HomeController extends Controller
|
|||
{
|
||||
$query = Pakaian::with(['penilaian.subkriteria.kriteria']);
|
||||
|
||||
// Mandatory filter: Clothing Type (highest weight criteria)
|
||||
// Filter berdasarkan jenis pakaian (wajib)
|
||||
if (!empty($criteriaInputs['jenis_pakaian'])) {
|
||||
// \Log::debug('Applying clothing type filter:', $criteriaInputs['jenis_pakaian']);
|
||||
|
||||
|
@ -125,7 +130,7 @@ class HomeController extends Controller
|
|||
});
|
||||
}
|
||||
|
||||
// Mandatory filter: Price Range (if specified)
|
||||
// Filter berdasarkan harga jika ada
|
||||
if (isset($criteriaInputs['harga_min']) && isset($criteriaInputs['harga_max'])) {
|
||||
// \Log::debug("Applying price filter: {$criteriaInputs['harga_min']} - {$criteriaInputs['harga_max']}");
|
||||
|
||||
|
@ -138,7 +143,7 @@ class HomeController extends Controller
|
|||
|
||||
$filteredClothing = $query->get();
|
||||
|
||||
// Validate filtering results
|
||||
// Validasi hasil filter agar benar-benar sesuai
|
||||
$this->validateFilterResults($filteredClothing, $criteriaInputs);
|
||||
|
||||
// \Log::debug('Filtered clothing count: ' . $filteredClothing->count());
|
||||
|
@ -170,19 +175,19 @@ class HomeController extends Controller
|
|||
*/
|
||||
private function calculateRecommendations($clothing, array $userInput): \Illuminate\Support\Collection
|
||||
{
|
||||
// Get criteria with weights
|
||||
// Ambil data kriteria dan bobotnya
|
||||
$criteria = Kriteria::with('subkriteria')
|
||||
->whereIn('id', [1, 2, 3, 4, 5])
|
||||
->orderByDesc('bobot') // Order by weight (highest first)
|
||||
->get();
|
||||
|
||||
// Build decision matrix
|
||||
// Susun decision matrix
|
||||
$decisionMatrix = $this->buildDecisionMatrix($clothing, $criteria, $userInput);
|
||||
|
||||
// Calculate min/max values for normalization
|
||||
// Hitung nilai normalisasi (min & max)
|
||||
$normalizationValues = $this->calculateNormalizationValues($decisionMatrix, $criteria);
|
||||
|
||||
// Calculate preference scores
|
||||
// Hitung skor preferensi
|
||||
$results = $this->calculatePreferenceScores(
|
||||
$clothing,
|
||||
$decisionMatrix,
|
||||
|
@ -191,7 +196,7 @@ class HomeController extends Controller
|
|||
$userInput
|
||||
);
|
||||
|
||||
// Sort by score (descending)
|
||||
// Urutkan hasil berdasarkan skor
|
||||
$recommendations = collect($results)
|
||||
->sortByDesc('score')
|
||||
->values();
|
||||
|
@ -218,13 +223,13 @@ class HomeController extends Controller
|
|||
continue; // Skip criteria not selected by user
|
||||
}
|
||||
|
||||
// Get matching assessments for this criterion
|
||||
// Ambil penilaian yang sesuai
|
||||
$matchingAssessments = $item->penilaian->filter(function ($assessment) use ($userSubIds) {
|
||||
return in_array($assessment->sub_kriteria_id, $userSubIds);
|
||||
});
|
||||
|
||||
if ($matchingAssessments->isNotEmpty()) {
|
||||
// Use average if multiple matches, first match for clothing type
|
||||
// Gunakan nilai rata-rata (kecuali jenis pakaian, cukup satu)
|
||||
$value = ($criterion->id == 3)
|
||||
? $matchingAssessments->first()->nilai
|
||||
: $matchingAssessments->avg('nilai');
|
||||
|
@ -290,7 +295,7 @@ class HomeController extends Controller
|
|||
|
||||
if ($value <= 0) continue;
|
||||
|
||||
// Normalize value based on criterion type
|
||||
// Normalisasi nilai sesuai jenis kriteria (benefit atau cost)
|
||||
$normalizedValue = $this->normalizeValue(
|
||||
$value,
|
||||
$normValues['max'][$criterion->id],
|
||||
|
@ -298,7 +303,7 @@ class HomeController extends Controller
|
|||
$criterion->jenis
|
||||
);
|
||||
|
||||
// Calculate weighted contribution
|
||||
// Hitung skor kontribusi berdasarkan bobot
|
||||
$weight = $criterion->bobot;
|
||||
$contribution = $normalizedValue * $weight;
|
||||
$preferenceScore += $contribution;
|
||||
|
@ -307,6 +312,7 @@ class HomeController extends Controller
|
|||
// \Log::debug("Item {$item->id} - Criterion {$criterion->id}: Value={$value}, Normalized={$normalizedValue}, Weight={$weight}, Contribution={$contribution}");
|
||||
}
|
||||
|
||||
// Ambil nama jenis pakaian untuk ditampilkan
|
||||
$clothingType = $item->penilaian
|
||||
->firstWhere('subkriteria.kriteria_id', 3)
|
||||
?->subkriteria->nama ?? 'Lainnya';
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Lupa Username</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="flex justify-center items-center min-h-screen bg-white text-gray-800 font-sans">
|
||||
<div class="bg-green-100 border border-green-200 p-6 rounded-xl shadow-md w-full max-w-md">
|
||||
<h2 class="text-2xl font-bold mb-4">Lupa Username?</h2>
|
||||
<p class="text-gray-600 mb-6">
|
||||
Masukkan email yang terdaftar untuk mengetahui username Anda.
|
||||
</p>
|
||||
|
||||
@if (session('status'))
|
||||
<div class="bg-blue-100 text-blue-800 border border-blue-300 p-3 rounded mb-4">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('forgot.username.send') }}">
|
||||
@csrf
|
||||
<div class="mb-4">
|
||||
<label for="email" class="block text-sm mb-1">Email</label>
|
||||
<input type="email" id="email" name="email" required class="w-full px-3 py-2 border rounded bg-white text-gray-900 focus:outline-none focus:ring-2 focus:ring-blue-400" />
|
||||
@error('email')
|
||||
<span class="text-red-600 text-sm">{{ $message }}</span>
|
||||
@enderror
|
||||
</div>
|
||||
<button type="submit" class="w-full bg-green-700 hover:bg-green-800 text-white px-4 py-2 rounded font-semibold">
|
||||
Kirim Username
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p class="text-center text-sm text-gray-700 mt-4">
|
||||
<a href="{{ route('login') }}" class="text-black hover:underline font-medium">
|
||||
Kembali ke halaman login
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -30,6 +30,9 @@
|
|||
<a href="{{ route('forgot.password.form') }}" class="text-green-700 hover:underline font-medium">
|
||||
Lupa Password?
|
||||
</a>
|
||||
<a href="{{ route('forgot.username.form') }}" class="text-green-700 hover:underline font-medium">
|
||||
Lupa Username?
|
||||
</a>
|
||||
</div>
|
||||
<button type="submit" class="w-full bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded font-semibold">
|
||||
Login
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Pengingat Username</title>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; color: #333;">
|
||||
<div style="max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<h2 style="color: #2f855a;">Halo {{ $user->name ?? 'Pengguna' }},</h2>
|
||||
<p>Berikut adalah username yang terdaftar dengan email ini:</p>
|
||||
<p><strong>Username Anda:</strong> {{ $user->username }}</p>
|
||||
<br>
|
||||
<p>Jika Anda tidak meminta informasi ini, abaikan email ini.</p>
|
||||
<p>Terima kasih.</p>
|
||||
<hr>
|
||||
<p style="font-size: 12px; color: #888;">Email ini dikirim secara otomatis oleh sistem kami.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Auth;
|
|||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\UserController;
|
||||
use App\Http\Controllers\PakaianController;
|
||||
use App\Http\Controllers\RiwayatController;
|
||||
use App\Http\Controllers\KriteriaController;
|
||||
use App\Http\Controllers\PenilaianController;
|
||||
use App\Http\Controllers\Admin\AuthController;
|
||||
|
@ -12,7 +13,8 @@ use App\Http\Controllers\Admin\DashboardController;
|
|||
use App\Http\Controllers\SubKriteriaShowController;
|
||||
use App\Http\Controllers\Landingpage\HomeController;
|
||||
use App\Http\Controllers\Admin\ResetPasswordController;
|
||||
use App\Http\Controllers\RiwayatController;
|
||||
use App\Http\Controllers\Admin\ForgotPasswordController;
|
||||
use App\Http\Controllers\Admin\ForgotUsernameController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -34,17 +36,21 @@ Route::post('/proses-rekomendasi', [HomeController::class, 'prosesRekomendasi'])
|
|||
Route::get('/login', [AuthController::class, 'showLogin'])->name('login');
|
||||
Route::post('/login', [AuthController::class, 'login']);
|
||||
|
||||
// Menampilkan form lupa password
|
||||
Route::get('/forgot-password', [\App\Http\Controllers\Admin\ForgotPasswordController::class, 'showForm'])->name('forgot.password.form');
|
||||
// === Forgot Username (tanpa prefix 'admin') ===
|
||||
Route::get('/forgot-username', [ForgotUsernameController::class, 'showForm'])
|
||||
->name('forgot.username.form');
|
||||
Route::post('/forgot-username', [ForgotUsernameController::class, 'sendUsername'])
|
||||
->name('forgot.username.send');
|
||||
|
||||
// Mengirim email reset link
|
||||
Route::post('/forgot-password', [\App\Http\Controllers\Admin\ForgotPasswordController::class, 'sendResetLink'])->name('forgot.password.send');
|
||||
|
||||
// Menampilkan form reset password (dari email)
|
||||
Route::get('/reset-password/{token}', [ResetPasswordController::class, 'showResetForm'])->name('password.reset');
|
||||
|
||||
// Menyimpan password baru
|
||||
Route::post('/reset-password', [ResetPasswordController::class, 'reset'])->name('password.update');
|
||||
// === Forgot Password (tanpa prefix 'admin') ===
|
||||
Route::get('/forgot-password', [ForgotPasswordController::class, 'showForm'])
|
||||
->name('forgot.password.form');
|
||||
Route::post('/forgot-password', [ForgotPasswordController::class, 'sendResetLink'])
|
||||
->name('forgot.password.send');
|
||||
Route::get('/reset-password/{token}', [ResetPasswordController::class, 'showResetForm'])
|
||||
->name('password.reset');
|
||||
Route::post('/reset-password', [ResetPasswordController::class, 'reset'])
|
||||
->name('password.update');
|
||||
|
||||
// Logout
|
||||
Route::post('/logout', function () {
|
||||
|
@ -62,7 +68,6 @@ Route::prefix('admin')->middleware(['auth'])->as('admin.')->group(function () {
|
|||
|
||||
Route::resource('penilaian', PenilaianController::class);
|
||||
Route::resource('user', UserController::class);
|
||||
Route::get('riwayat', [RiwayatController::class, 'index'])->name('riwayat.index');
|
||||
});
|
||||
|
||||
// // Kriteria
|
||||
|
|
Loading…
Reference in New Issue