update: guid tester
parent
46229fccbb
commit
d8684446e6
|
@ -7,6 +7,8 @@ namespace eSPJ.Controllers.SpjAdminController;
|
|||
[Route("admin")]
|
||||
public class SpjAdminController : Controller
|
||||
{
|
||||
private static readonly Guid DummySpjGuid = new Guid("9f5b8f3a-1c2d-4a5b-9a7c-1234567890ab");
|
||||
private const string DummySpjNumber = "SPJ/08-2025/PKM/000519";
|
||||
|
||||
[HttpGet("")]
|
||||
public IActionResult Index()
|
||||
|
@ -32,4 +34,58 @@ public class SpjAdminController : Controller
|
|||
ViewData["Id"] = id;
|
||||
return View("~/Views/Admin/Transport/SpjAdmin/History/Details.cshtml");
|
||||
}
|
||||
|
||||
[ValidateAntiForgeryToken]
|
||||
[HttpPost("scan/process/{id:guid}", Name = "Admin_Scan_Process")]
|
||||
public IActionResult Process(Guid id)
|
||||
{
|
||||
// Dummy rule: hanya GUID dummy yang dianggap valid
|
||||
if (id == DummySpjGuid)
|
||||
{
|
||||
return Json(new { success = true, data = new { id, status = "Valid" } });
|
||||
}
|
||||
return Json(new { success = false, message = "SPJ tidak ditemukan." });
|
||||
}
|
||||
|
||||
// Resolve kode SPJ (contoh: "SPJ/08-2025/PKM/000519") menjadi GUID.
|
||||
// Catatan: Saat ini dummy (development): setiap format SPJ yang valid bakal ke GUID baru.
|
||||
// Integrasi produksi: ganti dengan query DB untuk mencari SPJ berdasarkan nomor, lalu kembalikan Id GUID yang sebenarnya.
|
||||
[ValidateAntiForgeryToken]
|
||||
[HttpPost("scan/resolve", Name = "Admin_Scan_Resolve")]
|
||||
public IActionResult Resolve([FromForm] string code)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(code))
|
||||
{
|
||||
return Json(new { success = false, message = "Kode kosong." });
|
||||
}
|
||||
|
||||
code = code.Trim();
|
||||
|
||||
// Jika sudah GUID, langsung kembalikan (tetap izinkan test langsung GUID dummy)
|
||||
if (Guid.TryParse(code, out var guid))
|
||||
{
|
||||
return Json(new { success = true, id = guid });
|
||||
}
|
||||
|
||||
// Pola SPJ
|
||||
var isSpj = System.Text.RegularExpressions.Regex.IsMatch(
|
||||
code,
|
||||
@"^SPJ/\d{2}-\d{4}/[A-Z]+/\d{6}$",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase
|
||||
);
|
||||
|
||||
if (!isSpj)
|
||||
{
|
||||
return Json(new { success = false, message = "Format kode tidak dikenali." });
|
||||
}
|
||||
|
||||
// Dummy mapping: jika persis sesuai nomor di atas, kembalikan GUID tetap; selain itu anggap tidak ditemukan
|
||||
if (string.Equals(code, DummySpjNumber, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Json(new { success = true, id = DummySpjGuid });
|
||||
}
|
||||
|
||||
return Json(new { success = false, message = "SPJ tidak ditemukan." });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@
|
|||
|
||||
<div class="border-t pt-4">
|
||||
<h3 class="text-gray-700 font-medium mb-3">Atau input manual:</h3>
|
||||
<form id="manual-form" method="post" action="@Url.Action("ProcessScan", "Scan")">
|
||||
<form id="manual-form" method="post" action="#" novalidate>
|
||||
@Html.AntiForgeryToken()
|
||||
<div class="flex gap-2">
|
||||
<input type="text"
|
||||
|
@ -427,95 +427,88 @@
|
|||
}
|
||||
}
|
||||
|
||||
processScanCode(code) {
|
||||
isGuid(value) {
|
||||
const re = /^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$/;
|
||||
return re.test((value || '').trim());
|
||||
}
|
||||
|
||||
isSpjCode(value) {
|
||||
const re = /^SPJ\/\d{2}-\d{4}\/[A-Z]+\/\d{6}$/i;
|
||||
return re.test((value || '').trim());
|
||||
}
|
||||
|
||||
processUrlFor(id) {
|
||||
const basePath = '@Url.Content("~/admin/scan/process/")';
|
||||
return basePath + encodeURIComponent(id);
|
||||
}
|
||||
|
||||
postGuid(id) {
|
||||
const url = this.processUrlFor(id);
|
||||
return $.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
headers: { 'RequestVerificationToken': $('input[name="__RequestVerificationToken"]').val() }
|
||||
});
|
||||
}
|
||||
|
||||
resolveSpj(code) {
|
||||
const url = '@Url.Content("~/admin/scan/resolve")';
|
||||
return $.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
headers: { 'RequestVerificationToken': $('input[name="__RequestVerificationToken"]').val() },
|
||||
data: { code }
|
||||
});
|
||||
}
|
||||
|
||||
async processScanCode(code) {
|
||||
this.showModal('loading', 'Memproses...', 'Sedang memverifikasi kode SPJ...', false);
|
||||
|
||||
// Testing mode - uncomment kalau testing udah selesai
|
||||
this.mockResponse(code);
|
||||
return;
|
||||
try {
|
||||
let guid = null;
|
||||
const trimmed = (code || '').trim();
|
||||
|
||||
// ini bagian ajax yang asli
|
||||
/*
|
||||
$.ajax({
|
||||
url: @Url.Action("ProcessScan", "Scan")', // nanti tinggal ganti aja yaa
|
||||
type: 'POST',
|
||||
data: {
|
||||
barcode: code
|
||||
},
|
||||
success: (response) => {
|
||||
if (response.success) {
|
||||
this.showModal('success', 'Scan Berhasil!', 'SPJ berhasil ditemukan dan diproses.', true);
|
||||
setTimeout(() => {
|
||||
this.hideResult();
|
||||
this.manualInput.value = '';
|
||||
}, 2000);
|
||||
} else {
|
||||
this.showModal('error', 'SPJ Tidak Ditemukan', response.message || 'Kode SPJ tidak ditemukan dalam database.', true);
|
||||
if (this.isGuid(trimmed)) {
|
||||
guid = trimmed;
|
||||
} else if (this.isSpjCode(trimmed)) {
|
||||
// minta backend resolve SPJ ke GUID
|
||||
const rs = await this.resolveSpj(trimmed);
|
||||
if (!rs || rs.success !== true || !rs.id) {
|
||||
throw new Error((rs && rs.message) ? rs.message : 'Gagal resolve SPJ ke GUID.');
|
||||
}
|
||||
},
|
||||
error: (xhr, status, error) => {
|
||||
let errorMessage = 'Terjadi kesalahan saat memproses scan.';
|
||||
|
||||
if (xhr.responseJSON && xhr.responseJSON.message) {
|
||||
errorMessage = xhr.responseJSON.message;
|
||||
} else if (xhr.status === 404) {
|
||||
errorMessage = 'SPJ tidak ditemukan dalam database.';
|
||||
} else if (xhr.status === 500) {
|
||||
errorMessage = 'Terjadi kesalahan server. Silakan coba lagi.';
|
||||
}
|
||||
|
||||
this.showModal('error', 'Error', errorMessage, true);
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
// Mock response untuk testing
|
||||
mockResponse(code) {
|
||||
console.log(`Testing scan untuk kode: ${code}`);
|
||||
|
||||
setTimeout(() => {
|
||||
const validCodes = [
|
||||
'SPJ001', 'SPJ002', 'SPJ003', 'SPJ004', 'SPJ005',
|
||||
'TEST123', 'TEST456', 'TEST789',
|
||||
'12345', '67890', '11111', '22222',
|
||||
'ABCDEF', 'GHIJKL', 'MNOPQR'
|
||||
];
|
||||
|
||||
const isValid = validCodes.some(validCode =>
|
||||
validCode.toLowerCase() === code.toLowerCase()
|
||||
);
|
||||
|
||||
if (isValid) {
|
||||
console.log(`✅ Kode ${code} VALID - menampilkan success`);
|
||||
|
||||
// Format tanggal Indonesia
|
||||
const now = new Date();
|
||||
const tanggal = now.toLocaleDateString('id-ID', {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
const waktu = now.toLocaleTimeString('id-ID', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
|
||||
this.showSuccessModal(code, tanggal, waktu);
|
||||
|
||||
// Scanner tetap aktif, tidak perlu reset tombol
|
||||
setTimeout(() => {
|
||||
this.hideResult();
|
||||
this.manualInput.value = '';
|
||||
}, 3000);
|
||||
guid = rs.id;
|
||||
} else {
|
||||
console.log(`❌ Kode ${code} TIDAK VALID - menampilkan error`);
|
||||
this.showErrorModal(code);
|
||||
throw new Error('Format kode tidak dikenali. Masukkan GUID atau nomor SPJ yang valid.');
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// POST GUID ke process endpoint
|
||||
const resp = await this.postGuid(guid);
|
||||
console.debug('process response', resp);
|
||||
if (resp && resp.success) {
|
||||
const now = new Date();
|
||||
const tanggal = now.toLocaleDateString('id-ID', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||
const waktu = now.toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' });
|
||||
this.showSuccessModal(trimmed, tanggal, waktu);
|
||||
} else {
|
||||
this.showModal('error', 'SPJ Tidak Ditemukan', (resp && resp.message) ? resp.message : 'Kode SPJ tidak ditemukan dalam database.', true);
|
||||
}
|
||||
} catch (xhrOrErr) {
|
||||
let message = '';
|
||||
if (xhrOrErr && xhrOrErr.responseJSON) {
|
||||
message = xhrOrErr.responseJSON.message || 'Terjadi kesalahan saat memproses.';
|
||||
} else if (xhrOrErr && xhrOrErr.responseText) {
|
||||
message = xhrOrErr.responseText;
|
||||
} else if (xhrOrErr instanceof Error) {
|
||||
message = xhrOrErr.message;
|
||||
} else {
|
||||
message = 'Terjadi kesalahan saat memproses scan.';
|
||||
}
|
||||
console.error('processScanCode error', xhrOrErr);
|
||||
this.showModal('error', 'Error', message, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async retryScan() {
|
||||
this.hideResult();
|
||||
this.hideError();
|
||||
|
|
|
@ -32,10 +32,12 @@
|
|||
<div class="upload-area border-2 border-dashed border-gray-300 rounded-xl p-6 text-center hover:border-orange-400 transition-colors cursor-pointer" id="upload-area">
|
||||
<input type="file" name="FotoKondisiKendaraan" accept="image/jpeg,image/png" class="hidden" id="foto-upload">
|
||||
<label for="foto-upload" class="cursor-pointer w-full block">
|
||||
<div class="relative w-full h-32 bg-gray-100 rounded-xl flex items-center justify-center mx-auto mb-3 overflow-hidden preview-container" id="preview-container">
|
||||
<div class="relative w-full h-60 bg-center bg-gray-100 rounded-xl flex items-center justify-center mx-auto mb-3 overflow-hidden preview-container" id="preview-container">
|
||||
<div id="default-state">
|
||||
<div class="upload-icon-container">
|
||||
<i class="w-8 h-8 text-orange-600" data-lucide="upload-cloud" id="preview-icon"></i>
|
||||
<img src="~/driver/images/trukk.jpg" alt="contoh gambar">
|
||||
<p class="absolute inset-0 flex items-center justify-center text-white">Contoh Foto</p>
|
||||
@* <i class="w-8 h-8 text-orange-600" data-lucide="upload-cloud" id="preview-icon"></i> *@
|
||||
</div>
|
||||
</div>
|
||||
<img id="preview-image" src="#" alt="Preview" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;object-fit:cover;" />
|
||||
|
@ -73,6 +75,7 @@
|
|||
<div class="location-badge rounded-2xl p-4">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<div class="w-8 h-8 bg-gradient-to-br from-blue-100 to-blue-200 rounded-full flex items-center justify-center">
|
||||
|
||||
<i class="w-4 h-4 text-blue-600" data-lucide="map-pin"></i>
|
||||
</div>
|
||||
<span class="text-sm font-medium text-gray-700">Lokasi Anda:</span>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 640 KiB |
Loading…
Reference in New Issue