i18n (Phase C batch 10): map, map-gis, vouchers_packages, finance/cash_in, finance/expenses ID/EN
This commit is contained in:
1 parent
d09ab217f9
commit
fd074f8ff7
7 files changed
+401
-139
No files matched your search
@@ -2,7 +2,7 @@
|
||||
<html lang="<%= lang || 'id' %>">
|
||||
<head>
|
||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Kas Masuk | <%= company %></title>
|
||||
<title><%= t('admin.cashin.title','Kas Masuk') %> | <%= company %></title>
|
||||
<link rel="stylesheet" href="/vendor/bootstrap-icons/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="/css/admin.css">
|
||||
<style>
|
||||
@@ -16,11 +16,11 @@
|
||||
<%- include('../partials/sidebar', { activePage: 'cash_in', company }) %>
|
||||
<div class="mw">
|
||||
<div class="topbar">
|
||||
<div class="tb-title"><button class="hb-menu" onclick="toggleSidebar()"><i class="bi bi-list"></i></button><i class="bi bi-cash-stack"></i> Kas Masuk (Lain-lain)</div>
|
||||
<div class="tb-title"><button class="hb-menu" onclick="toggleSidebar()"><i class="bi bi-list"></i></button><i class="bi bi-cash-stack"></i> <%= t('admin.cashin.heading','Kas Masuk (Lain-lain)') %></div>
|
||||
<div class="tb-right">
|
||||
<span class="adm-badge" style="font-size:12px;opacity:0.7;"><%= company %></span>
|
||||
<span class="adm-badge"><i class="bi bi-person-fill"></i> <%= (typeof session !== 'undefined' && session && session.isCashier) ? 'Kasir' : 'Admin' %></span>
|
||||
<button class="btn btn-p btn-sm" onclick="openModal('addModal')"><i class="bi bi-plus-lg"></i> Tambah Kas Masuk</button>
|
||||
<button class="btn btn-p btn-sm" onclick="openModal('addModal')"><i class="bi bi-plus-lg"></i> <%= t('admin.cashin.add','Tambah Kas Masuk') %></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page">
|
||||
@@ -42,14 +42,14 @@
|
||||
<div class="val-box">
|
||||
<div class="val-icon" style="background:rgba(16, 185, 129, 0.1);color:#10b981"><i class="bi bi-graph-up-arrow"></i></div>
|
||||
<div>
|
||||
<div class="val-text">Kas Masuk Bulan Ini</div>
|
||||
<div class="val-text"><%= t('admin.cashin.month','Kas Masuk Bulan Ini') %></div>
|
||||
<div class="val-num">Rp <%= totalThisMonth.toLocaleString('id-ID') %></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="val-box">
|
||||
<div class="val-icon" style="background:rgba(59, 130, 246, 0.1);color:#3b82f6"><i class="bi bi-piggy-bank-fill"></i></div>
|
||||
<div>
|
||||
<div class="val-text">Total Kas Masuk (Lainnya)</div>
|
||||
<div class="val-text"><%= t('admin.cashin.total','Total Kas Masuk (Lainnya)') %></div>
|
||||
<div class="val-num">Rp <%= totalAll.toLocaleString('id-ID') %></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
<!-- Table -->
|
||||
<div class="card">
|
||||
<div class="card-hd"><h6><i class="bi bi-list-ul"></i> Riwayat Kas Masuk</h6></div>
|
||||
<div class="card-hd"><h6><i class="bi bi-list-ul"></i> <%= t('admin.cashin.history','Riwayat Kas Masuk') %></h6></div>
|
||||
<div class="tbl-wrap">
|
||||
<table class="dtbl">
|
||||
<thead>
|
||||
@@ -65,9 +65,9 @@
|
||||
<th><%= t('common.date','Tanggal') %></th>
|
||||
<th><%= t('common.category','Kategori') %></th>
|
||||
<th><%= t('common.desc_note','Deskripsi / Catatan') %></th>
|
||||
<th>Metode</th>
|
||||
<th><%= t('admin.cashin.th_method','Metode') %></th>
|
||||
<th class="num"><%= t('common.amount_qty','Jumlah') %></th>
|
||||
<th>Pencatat</th>
|
||||
<th><%= t('admin.cashin.th_recorder','Pencatat') %></th>
|
||||
<th><%= t('common.actions','Aksi') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -105,7 +105,7 @@
|
||||
<!-- Modal Add -->
|
||||
<div class="mo" id="addModal">
|
||||
<div class="mb">
|
||||
<div class="mh"><span class="mt"><i class="bi bi-plus-circle"></i> Catat Kas Masuk</span><button type="button" class="mc" onclick="closeModal('addModal')">×</button></div>
|
||||
<div class="mh"><span class="mt"><i class="bi bi-plus-circle"></i> <%= t('admin.cashin.modal','Catat Kas Masuk') %></span><button type="button" class="mc" onclick="closeModal('addModal')">×</button></div>
|
||||
<form method="POST" action="/admin/finance/cash-in">
|
||||
<div class="mbody">
|
||||
<div class="form-row">
|
||||
@@ -114,41 +114,41 @@
|
||||
<input type="date" class="fc" name="date" required value="<%= getNowLocal().substring(0,10) %>" max="<%= getNowLocal().substring(0,10) %>">
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl">Sumber / Kategori <span class="text-danger">*</span></label>
|
||||
<label class="fl"><%= t('admin.cashin.source','Sumber / Kategori') %> <span class="text-danger">*</span></label>
|
||||
<select class="fc" name="category" required>
|
||||
<option value="Modal Usaha">Modal Usaha / Suntikan Dana</option>
|
||||
<option value="Penjualan Aset">Penjualan Aset/Barang Bekas</option>
|
||||
<option value="Jasa Lainnya">Pendapatan Jasa Lainnya</option>
|
||||
<option value="Lain-lain">Lain-lain</option>
|
||||
<option value="Modal Usaha"><%= t('admin.cashin.opt_modal','Modal Usaha / Suntikan Dana') %></option>
|
||||
<option value="Penjualan Aset"><%= t('admin.cashin.opt_asset','Penjualan Aset/Barang Bekas') %></option>
|
||||
<option value="Jasa Lainnya"><%= t('admin.cashin.opt_service','Pendapatan Jasa Lainnya') %></option>
|
||||
<option value="<%= t('admin.cashin.opt_other','Lain-lain') %>"><%= t('admin.cashin.opt_other','Lain-lain') %></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl">Jumlah / Nominal (Rp) <span class="text-danger">*</span></label>
|
||||
<label class="fl"><%= t('admin.cashin.amount','Jumlah / Nominal (Rp)') %> <span class="text-danger">*</span></label>
|
||||
<input type="text" class="fc" name="amount" id="amountInput" required placeholder="Contoh: 500.000" style="font-size:16px;font-weight:bold" autocomplete="off">
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl"><%= t('common.desc_note2','Deskripsi / Keterangan') %> <span class="text-danger">*</span></label>
|
||||
<textarea class="fc" name="description" required placeholder="Suntikan modal dari owner..."></textarea>
|
||||
<textarea class="fc" name="description" required placeholder="<%= t('admin.cashin.ph_desc','Suntikan modal dari owner...') %>"></textarea>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="fg">
|
||||
<label class="fl">Metode Penerimaan</label>
|
||||
<label class="fl"><%= t('admin.cashin.method','Metode Penerimaan') %></label>
|
||||
<select class="fc" name="payment_method">
|
||||
<option value="cash">Tunai (Cash)</option>
|
||||
<option value="transfer">Transfer Bank</option>
|
||||
<option value="ewallet">E-Wallet (OVO/Dana/Gopay)</option>
|
||||
<option value="cash"><%= t('admin.cashin.pay_cash','Tunai (Cash)') %></option>
|
||||
<option value="transfer"><%= t('admin.cashin.pay_transfer','Transfer Bank') %></option>
|
||||
<option value="ewallet"><%= t('admin.cashin.pay_ewallet','E-Wallet (OVO/Dana/Gopay)') %></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl">No. Referensi (Opsional)</label>
|
||||
<input type="text" class="fc" name="receipt_number" placeholder="Bisa dikosongkan">
|
||||
<label class="fl"><%= t('admin.cashin.ref','No. Referensi (Opsional)') %></label>
|
||||
<input type="text" class="fc" name="receipt_number" placeholder="<%= t('admin.cashin.ph_ref','Bisa dikosongkan') %>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mf">
|
||||
<button type="button" class="btn btn-g" onclick="closeModal('addModal')"><%= t('common.cancel','Batal') %></button>
|
||||
<button type="submit" class="btn btn-p"><i class="bi bi-save"></i> Simpan Pemasukan</button>
|
||||
<button type="submit" class="btn btn-p"><i class="bi bi-save"></i> <%= t('admin.cashin.save','Simpan Pemasukan') %></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="<%= lang || 'id' %>">
|
||||
<head>
|
||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Pengeluaran | <%= company %></title>
|
||||
<title><%= t('admin.exp.title','Pengeluaran') %> | <%= company %></title>
|
||||
<link rel="stylesheet" href="/vendor/bootstrap-icons/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="/css/admin.css">
|
||||
<style>
|
||||
@@ -17,11 +17,11 @@
|
||||
<%- include('../partials/sidebar', { activePage: 'expenses', company }) %>
|
||||
<div class="mw">
|
||||
<div class="topbar">
|
||||
<div class="tb-title"><button class="hb-menu" onclick="toggleSidebar()"><i class="bi bi-list"></i></button><i class="bi bi-wallet2"></i> Pengeluaran (Cash Out)</div>
|
||||
<div class="tb-title"><button class="hb-menu" onclick="toggleSidebar()"><i class="bi bi-list"></i></button><i class="bi bi-wallet2"></i> <%= t('admin.exp.heading','Pengeluaran (Cash Out)') %></div>
|
||||
<div class="tb-right">
|
||||
<span class="adm-badge" style="font-size:12px;opacity:0.7;"><%= company %></span>
|
||||
<span class="adm-badge"><i class="bi bi-person-fill"></i> <%= (typeof session !== 'undefined' && session && session.isCashier) ? 'Kasir' : 'Admin' %></span>
|
||||
<button class="btn btn-p btn-sm" onclick="openModal('addModal')"><i class="bi bi-plus-lg"></i> Catat Pengeluaran</button>
|
||||
<button class="btn btn-p btn-sm" onclick="openModal('addModal')"><i class="bi bi-plus-lg"></i> <%= t('admin.exp.add','Catat Pengeluaran') %></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page">
|
||||
@@ -39,14 +39,14 @@
|
||||
<div class="val-box">
|
||||
<div class="val-icon" style="background:rgba(239, 68, 68, 0.1);color:#ef4444"><i class="bi bi-graph-down-arrow"></i></div>
|
||||
<div>
|
||||
<div class="val-text">Pengeluaran Bulan Ini</div>
|
||||
<div class="val-text"><%= t('admin.exp.month','Pengeluaran Bulan Ini') %></div>
|
||||
<div class="val-num">Rp <%= totalThisMonth.toLocaleString('id-ID') %></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="val-box">
|
||||
<div class="val-icon" style="background:rgba(99, 102, 241, 0.1);color:#6366f1"><i class="bi bi-wallet-fill"></i></div>
|
||||
<div>
|
||||
<div class="val-text">Total Pengeluaran Dicatat</div>
|
||||
<div class="val-text"><%= t('admin.exp.total','Total Pengeluaran Dicatat') %></div>
|
||||
<div class="val-num">Rp <%= totalAll.toLocaleString('id-ID') %></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
<!-- Table -->
|
||||
<div class="card">
|
||||
<div class="card-hd"><h6><i class="bi bi-list-ul"></i> Riwayat Pengeluaran</h6></div>
|
||||
<div class="card-hd"><h6><i class="bi bi-list-ul"></i> <%= t('admin.exp.history','Riwayat Pengeluaran') %></h6></div>
|
||||
<div class="tbl-wrap">
|
||||
<table class="dtbl">
|
||||
<thead>
|
||||
@@ -62,10 +62,10 @@
|
||||
<th><%= t('common.date','Tanggal') %></th>
|
||||
<th><%= t('common.category','Kategori') %></th>
|
||||
<th><%= t('common.desc_note','Deskripsi / Catatan') %></th>
|
||||
<th>Vendor/Toko</th>
|
||||
<th>Metode</th>
|
||||
<th><%= t('admin.exp.th_vendor','Vendor/Toko') %></th>
|
||||
<th><%= t('admin.exp.th_method','Metode') %></th>
|
||||
<th class="num"><%= t('common.amount_qty','Jumlah') %></th>
|
||||
<th>Pencatat</th>
|
||||
<th><%= t('admin.exp.th_recorder','Pencatat') %></th>
|
||||
<th><%= t('common.actions','Aksi') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -108,18 +108,18 @@
|
||||
<!-- Modal Add -->
|
||||
<div class="mo" id="addModal">
|
||||
<div class="mb">
|
||||
<div class="mh"><span class="mt"><i class="bi bi-plus-circle"></i> Catat Pengeluaran Baru</span><button type="button" class="mc" onclick="closeModal('addModal')">×</button></div>
|
||||
<div class="mh"><span class="mt"><i class="bi bi-plus-circle"></i> <%= t('admin.exp.modal','Catat Pengeluaran Baru') %></span><button type="button" class="mc" onclick="closeModal('addModal')">×</button></div>
|
||||
<form method="POST" action="/admin/finance/expenses">
|
||||
<div class="mbody">
|
||||
<div class="form-row">
|
||||
<div class="fg">
|
||||
<label class="fl">Tanggal Pengeluaran <span class="text-danger">*</span></label>
|
||||
<label class="fl"><%= t('admin.exp.date','Tanggal Pengeluaran') %> <span class="text-danger">*</span></label>
|
||||
<input type="date" class="fc" name="date" required value="<%= getNowLocal().substring(0,10) %>" max="<%= getNowLocal().substring(0,10) %>">
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl"><%= t('common.category','Kategori') %> <span class="text-danger">*</span></label>
|
||||
<select class="fc" name="category" required>
|
||||
<option value="">-- Pilih Kategori --</option>
|
||||
<option value=""><%= t('admin.exp.opt_category','-- Pilih Kategori --') %></option>
|
||||
<% categories.forEach(c => { %>
|
||||
<option value="<%= c.name %>"><%= c.name %></option>
|
||||
<% }) %>
|
||||
@@ -127,36 +127,36 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl">Jumlah / Nominal (Rp) <span class="text-danger">*</span></label>
|
||||
<label class="fl"><%= t('admin.exp.amount','Jumlah / Nominal (Rp)') %> <span class="text-danger">*</span></label>
|
||||
<input type="text" class="fc" name="amount" id="amountInput" required placeholder="Contoh: 150.000" style="font-size:16px;font-weight:bold" autocomplete="off">
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl"><%= t('common.desc_note2','Deskripsi / Keterangan') %> <span class="text-danger">*</span></label>
|
||||
<textarea class="fc" name="description" required placeholder="Beli Router Mikrotik RB750Gr3..."></textarea>
|
||||
<textarea class="fc" name="description" required placeholder="<%= t('admin.exp.ph_desc','Beli Router Mikrotik RB750Gr3...') %>"></textarea>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="fg">
|
||||
<label class="fl">Nama Toko/Vendor (Opsional)</label>
|
||||
<input type="text" class="fc" name="vendor" placeholder="Misal: Tokopedia / Toko Komputer X">
|
||||
<label class="fl"><%= t('admin.exp.vendor','Nama Toko/Vendor (Opsional)') %></label>
|
||||
<input type="text" class="fc" name="vendor" placeholder="<%= t('admin.exp.ph_vendor','Misal: Tokopedia / Toko Komputer X') %>">
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl">No. Nota / Kwitansi (Opsional)</label>
|
||||
<label class="fl"><%= t('admin.exp.receipt','No. Nota / Kwitansi (Opsional)') %></label>
|
||||
<input type="text" class="fc" name="receipt_number" placeholder="INV-123456">
|
||||
</div>
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl">Metode Pembayaran</label>
|
||||
<label class="fl"><%= t('admin.exp.method','Metode Pembayaran') %></label>
|
||||
<select class="fc" name="payment_method">
|
||||
<option value="cash">Tunai (Cash)</option>
|
||||
<option value="transfer">Transfer Bank</option>
|
||||
<option value="ewallet">E-Wallet (OVO/Dana/Gopay)</option>
|
||||
<option value="credit">Kredit / Paylater</option>
|
||||
<option value="cash"><%= t('admin.exp.pay_cash','Tunai (Cash)') %></option>
|
||||
<option value="transfer"><%= t('admin.exp.pay_transfer','Transfer Bank') %></option>
|
||||
<option value="ewallet"><%= t('admin.exp.pay_ewallet','E-Wallet (OVO/Dana/Gopay)') %></option>
|
||||
<option value="credit"><%= t('admin.exp.pay_credit','Kredit / Paylater') %></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mf">
|
||||
<button type="button" class="btn btn-g" onclick="closeModal('addModal')"><%= t('common.cancel','Batal') %></button>
|
||||
<button type="submit" class="btn btn-p"><i class="bi bi-save"></i> Simpan Pengeluaran</button>
|
||||
<button type="submit" class="btn btn-p"><i class="bi bi-save"></i> <%= t('admin.exp.save','Simpan Pengeluaran') %></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
+27
-27
@@ -268,7 +268,7 @@
|
||||
<input
|
||||
type="text"
|
||||
id="gisSearchInp"
|
||||
placeholder="Cari ODP, ODC, HTB, Pelanggan..."
|
||||
placeholder="<%= t('admin.gis.ph_search','Cari ODP, ODC, HTB, Pelanggan...') %>"
|
||||
oninput="handleGisSearch(this.value)"
|
||||
class="w-full bg-slate-900/90 border border-slate-700/70 rounded-lg pl-8 pr-7 py-1.5 text-xs text-white placeholder-slate-400 focus:outline-none focus:border-sky-500 transition"
|
||||
>
|
||||
@@ -294,18 +294,18 @@
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-300 hover:text-white text-xs font-semibold transition"
|
||||
>
|
||||
<i class="bi bi-layers text-sm"></i>
|
||||
<span>Layer Peta</span>
|
||||
<span><%= t('admin.gis.layers','Layer Peta') %></span>
|
||||
<i class="bi bi-chevron-down text-xs"></i>
|
||||
</button>
|
||||
|
||||
<!-- Layer Dropdown Box -->
|
||||
<div id="gisLayersMenu" class="hidden absolute left-0 top-full mt-2 w-64 bg-slate-900/98 backdrop-blur-2xl border border-slate-700/90 rounded-xl shadow-[0_25px_60px_rgba(0,0,0,0.95)] p-3.5 z-[1050] space-y-2.5 text-xs max-h-[calc(100vh-200px)] overflow-y-auto ring-1 ring-white/10">
|
||||
<div class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1">Tampilkan Elemen</div>
|
||||
<div class="text-[10px] font-bold text-slate-400 uppercase tracking-wider mb-1"><%= t('admin.gis.show_elems','Tampilkan Elemen') %></div>
|
||||
|
||||
<label class="flex items-center justify-between cursor-pointer py-1">
|
||||
<span class="flex items-center gap-2 text-slate-300">
|
||||
<span class="w-2.5 h-2.5 rounded bg-blue-500"></span>
|
||||
<span>Server & OLT</span>
|
||||
<span><%= t('admin.gis.el_server','Server & OLT') %></span>
|
||||
</span>
|
||||
<input type="checkbox" id="chkLayerServer" checked onchange="toggleLayerVisibility('server')" class="rounded border-slate-700 text-blue-500 focus:ring-0">
|
||||
</label>
|
||||
@@ -313,7 +313,7 @@
|
||||
<label class="flex items-center justify-between cursor-pointer py-1">
|
||||
<span class="flex items-center gap-2 text-slate-300">
|
||||
<span class="w-2.5 h-2.5 rounded bg-amber-500"></span>
|
||||
<span>ODC Feeder Hub</span>
|
||||
<span><%= t('admin.gis.el_odc','ODC Feeder Hub') %></span>
|
||||
</span>
|
||||
<input type="checkbox" id="chkLayerOdc" checked onchange="toggleLayerVisibility('odc')" class="rounded border-slate-700 text-amber-500 focus:ring-0">
|
||||
</label>
|
||||
@@ -321,7 +321,7 @@
|
||||
<label class="flex items-center justify-between cursor-pointer py-1">
|
||||
<span class="flex items-center gap-2 text-slate-300">
|
||||
<span class="w-2.5 h-2.5 rounded bg-emerald-500"></span>
|
||||
<span>ODP Distribusi</span>
|
||||
<span><%= t('admin.gis.el_odp','ODP Distribusi') %></span>
|
||||
</span>
|
||||
<input type="checkbox" id="chkLayerOdp" checked onchange="toggleLayerVisibility('odp')" class="rounded border-slate-700 text-emerald-500 focus:ring-0">
|
||||
</label>
|
||||
@@ -329,7 +329,7 @@
|
||||
<label class="flex items-center justify-between cursor-pointer py-1">
|
||||
<span class="flex items-center gap-2 text-slate-300">
|
||||
<span class="w-2.5 h-2.5 rounded bg-fuchsia-500"></span>
|
||||
<span>HTB Media Converter</span>
|
||||
<span><%= t('admin.gis.el_htb','HTB Media Converter') %></span>
|
||||
</span>
|
||||
<input type="checkbox" id="chkLayerHtb" checked onchange="toggleLayerVisibility('htb')" class="rounded border-slate-700 text-fuchsia-500 focus:ring-0">
|
||||
</label>
|
||||
@@ -346,7 +346,7 @@
|
||||
<label class="flex items-center justify-between cursor-pointer py-1">
|
||||
<span class="flex items-center gap-2 text-slate-300">
|
||||
<span class="w-3 h-0.5 bg-emerald-400"></span>
|
||||
<span>Jalur Kabel Fiber</span>
|
||||
<span><%= t('admin.gis.el_fiber','Jalur Kabel Fiber') %></span>
|
||||
</span>
|
||||
<input type="checkbox" id="chkLayerCables" checked onchange="toggleLayerVisibility('cables')" class="rounded border-slate-700 text-emerald-500 focus:ring-0">
|
||||
</label>
|
||||
@@ -354,7 +354,7 @@
|
||||
<label class="flex items-center justify-between cursor-pointer py-1">
|
||||
<span class="flex items-center gap-2 text-slate-300">
|
||||
<span class="w-2.5 h-2.5 rounded-full border border-sky-400"></span>
|
||||
<span>Radius Sinyal (150m)</span>
|
||||
<span><%= t('admin.gis.el_radius','Radius Sinyal (150m)') %></span>
|
||||
</span>
|
||||
<input type="checkbox" id="chkLayerRadius" onchange="toggleLayerVisibility('radius')" class="rounded border-slate-700 text-sky-500 focus:ring-0">
|
||||
</label>
|
||||
@@ -368,15 +368,15 @@
|
||||
onclick="toggleRulerTool()"
|
||||
id="btnRulerTool"
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-300 hover:text-white text-xs font-semibold transition"
|
||||
title="Ukur Jarak Kabel Fiber di Peta"
|
||||
title="<%= t('admin.gis.tip_ruler','Ukur Jarak Kabel Fiber di Peta') %>"
|
||||
>
|
||||
<i class="bi bi-rulers text-sm"></i>
|
||||
<span>Ukur Jarak</span>
|
||||
<span><%= t('admin.gis.ruler','Ukur Jarak') %></span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Right: Mode Switcher & Navigation to Workflow Map -->
|
||||
<!-- Right: Mode Switcher & Navigation to <%= t('admin.gis.workflow','Workflow Map') %> -->
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
|
||||
<!-- Recenter Map Button -->
|
||||
@@ -384,19 +384,19 @@
|
||||
type="button"
|
||||
onclick="resetMapCenter()"
|
||||
class="w-8 h-8 rounded-lg bg-slate-800 hover:bg-slate-700 border border-slate-700/80 text-slate-300 flex items-center justify-center transition"
|
||||
title="Pusatkan Peta ke Jaringan"
|
||||
title="<%= t('admin.gis.tip_center','Pusatkan Peta ke Jaringan') %>"
|
||||
>
|
||||
<i class="bi bi-crosshair text-sm"></i>
|
||||
</button>
|
||||
|
||||
<!-- Switch to Visual Workflow Map -->
|
||||
<!-- Switch to Visual <%= t('admin.gis.workflow','Workflow Map') %> -->
|
||||
<a
|
||||
href="/admin/map"
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-sky-600/20 border border-sky-500/30 hover:bg-sky-600/30 text-sky-300 text-xs font-semibold shadow-sm transition"
|
||||
title="Buka Visual Workflow Mapping (n8n Style)"
|
||||
title="<%= t('admin.gis.tip_workflow','Buka Visual Workflow Mapping (n8n Style)') %>"
|
||||
>
|
||||
<i class="bi bi-diagram-3 text-sm"></i>
|
||||
<span>Workflow Map</span>
|
||||
<span><%= t('admin.gis.workflow','Workflow Map') %></span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
@@ -412,7 +412,7 @@
|
||||
id="btnModeVector"
|
||||
onclick="setGisVisualMode('vector')"
|
||||
class="gis-mode-pill-btn active"
|
||||
title="Mode Vektor Gelap Berkontras Tinggi"
|
||||
title="<%= t('admin.gis.tip_dark','Mode Vektor Gelap Berkontras Tinggi') %>"
|
||||
>
|
||||
Vector Mode
|
||||
</button>
|
||||
@@ -421,7 +421,7 @@
|
||||
id="btnModeClean"
|
||||
onclick="setGisVisualMode('clean')"
|
||||
class="gis-mode-pill-btn"
|
||||
title="Mode Bersih Jalan & Bangunan Minimalis"
|
||||
title="<%= t('admin.gis.tip_clean','Mode Bersih Jalan & Bangunan Minimalis') %>"
|
||||
>
|
||||
Clean Mode
|
||||
</button>
|
||||
@@ -430,7 +430,7 @@
|
||||
id="btnModeFull"
|
||||
onclick="setGisVisualMode('full')"
|
||||
class="gis-mode-pill-btn"
|
||||
title="Mode Satelit Citra Udara Resolusi Tinggi"
|
||||
title="<%= t('admin.gis.tip_sat','Mode Satelit Citra Udara Resolusi Tinggi') %>"
|
||||
>
|
||||
Full Satelit
|
||||
</button>
|
||||
@@ -441,15 +441,15 @@
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="font-bold text-sky-300 flex items-center gap-1.5">
|
||||
<i class="bi bi-rulers text-sm"></i>
|
||||
<span>Pengukur Panjang Kabel</span>
|
||||
<span><%= t('admin.gis.ruler_title','Pengukur Panjang Kabel') %></span>
|
||||
</div>
|
||||
<button type="button" onclick="clearMeasurement()" class="text-slate-400 hover:text-white text-xs">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-[11px] text-slate-300">Klik titik di peta untuk mengukur rute kabel optik.</div>
|
||||
<div class="text-[11px] text-slate-300"><%= t('admin.gis.ruler_desc','Klik titik di peta untuk mengukur rute kabel optik.') %></div>
|
||||
<div class="pt-1 flex items-baseline gap-2">
|
||||
<span class="text-slate-400">Total Panjang:</span>
|
||||
<span class="text-slate-400"><%= t('admin.gis.total_length','Total Panjang:') %></span>
|
||||
<span id="rulerDistanceText" class="font-mono font-bold text-sm text-emerald-400">0 m</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -458,7 +458,7 @@
|
||||
<div class="absolute bottom-4 right-4 z-[1000] hidden md:flex items-center gap-3 bg-slate-900/90 backdrop-blur-md px-3.5 py-2 rounded-xl border border-slate-700/80 text-xs shadow-2xl text-slate-300">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="w-2.5 h-2.5 rounded bg-blue-500"></span>
|
||||
<span>Server / OLT</span>
|
||||
<span><%= t('admin.gis.legend_server','Server / OLT') %></span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span class="w-2.5 h-2.5 rounded bg-amber-500"></span>
|
||||
@@ -697,7 +697,7 @@
|
||||
|
||||
const m = L.marker([lat, lng], { icon: icon }).addTo(groupOdc);
|
||||
m.bindPopup(buildNodePopupHtml({
|
||||
type: isCascade ? 'ODC Cascade Feeder' : 'ODC Feeder Hub',
|
||||
type: isCascade ? 'ODC Cascade Feeder' : '<%= t('admin.gis.el_odc','ODC Feeder Hub') %>',
|
||||
title: odc.name,
|
||||
subtitle: `Kapasitas: ${odc.port_capacity || 4} Tray Out • PON ${odc.pon_port || 1}`,
|
||||
status: 'online',
|
||||
@@ -768,7 +768,7 @@
|
||||
|
||||
const m = L.marker([lat, lng], { icon: icon }).addTo(groupHtb);
|
||||
m.bindPopup(buildNodePopupHtml({
|
||||
type: 'HTB Media Converter (P2P 1:1)',
|
||||
type: '<%= t('admin.gis.el_htb','HTB Media Converter') %> (P2P 1:1)',
|
||||
title: odp.name,
|
||||
subtitle: `P2P Target: ${targetCust?.name || 'Belum Ada'}`,
|
||||
status: odpStatus,
|
||||
@@ -820,7 +820,7 @@
|
||||
|
||||
const m = L.marker([lat, lng], { icon: icon }).addTo(groupOdp);
|
||||
m.bindPopup(buildNodePopupHtml({
|
||||
type: isCascade ? 'ODP Cascade' : 'ODP Distribusi',
|
||||
type: isCascade ? 'ODP Cascade' : '<%= t('admin.gis.el_odp','ODP Distribusi') %>',
|
||||
title: odp.name,
|
||||
subtitle: `Port: ${totalCust}/${capacity} (${activeCust} Aktif)`,
|
||||
status: odpStatus,
|
||||
@@ -972,7 +972,7 @@
|
||||
<div class="text-[11px] text-slate-300">${d.subtitle}</div>
|
||||
|
||||
<div class="bg-slate-950/70 p-2 rounded-lg border border-slate-800 text-[10px] font-mono text-slate-400 flex items-center justify-between">
|
||||
<span>Koordinat:</span>
|
||||
<span><%= t('admin.gis.coord','Koordinat:') %></span>
|
||||
<span class="text-white">${d.lat ? d.lat.toFixed(6) : '-'}, ${d.lng ? d.lng.toFixed(6) : '-'}</span>
|
||||
</div>
|
||||
|
||||
|
||||
+34
-34
@@ -653,7 +653,7 @@
|
||||
<span><%= title %></span>
|
||||
</div>
|
||||
<div class="tb-right">
|
||||
<button class="btn btn-g btn-sm" id="mapsToggleBtn" onclick="toggleBillingMaps()"><i class="bi bi-map"></i> <span id="mapsToggleTxt">SEE MAPS</span></button>
|
||||
<button class="btn btn-g btn-sm" id="mapsToggleBtn" onclick="toggleBillingMaps()"><i class="bi bi-map"></i> <span id="mapsToggleTxt"><%= t('admin.map.see_maps','LIHAT PETA') %></span></button>
|
||||
<button class="btn btn-p btn-sm" onclick="if(typeof openModal==='function'){openModal('addOdpModal')}else{toggleBillingMaps()}"><i class="bi bi-plus-circle"></i> <%= t('admin.map.add_odp', 'Tambah ODP') %></button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -676,30 +676,30 @@
|
||||
<div class="msc-icon msc-s"><i class="bi bi-router-fill"></i></div>
|
||||
<div class="msc-info">
|
||||
<div class="val"><%= customers.filter(c => c.status === 'active' && c.lat && c.lng).length %></div>
|
||||
<div class="lbl">ONU Aktif (Peta)</div>
|
||||
<div class="lbl"><%= t('admin.map.onu_active','ONU Aktif (Peta)') %></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="msc">
|
||||
<div class="msc-icon msc-d"><i class="bi bi-exclamation-triangle-fill"></i></div>
|
||||
<div class="msc-info">
|
||||
<div class="val"><%= customers.filter(c => c.status !== 'active' && c.lat && c.lng).length %></div>
|
||||
<div class="lbl">ONU Isolir (Peta)</div>
|
||||
<div class="lbl"><%= t('admin.map.onu_isolir','ONU Isolir (Peta)') %></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="msc">
|
||||
<div class="msc-icon msc-p"><i class="bi bi-geo-alt-fill"></i></div>
|
||||
<div class="msc-info">
|
||||
<div class="val"><%= customers.filter(c => !c.lat || !c.lng).length %></div>
|
||||
<div class="lbl">Tanpa GPS</div>
|
||||
<div class="lbl"><%= t('admin.map.no_gps','Tanpa GPS') %></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mapsPlaceholder" class="maps-placeholder">
|
||||
<i class="bi bi-map"></i>
|
||||
<div class="maps-ph-title">Peta belum dimuat</div>
|
||||
<div class="maps-ph-sub">Klik <b>SEE MAPS</b> untuk memuat peta & daftar pelanggan/ODP (hemat resource).</div>
|
||||
<button type="button" class="btn btn-p" onclick="toggleBillingMaps()"><i class="bi bi-eye"></i> SEE MAPS</button>
|
||||
<div class="maps-ph-title"><%= t('admin.map.not_loaded','Peta belum dimuat') %></div>
|
||||
<div class="maps-ph-sub"><%- t('admin.map.not_loaded_sub','Klik <b>SEE MAPS</b> untuk memuat peta & daftar pelanggan/ODP (hemat resource).') %></div>
|
||||
<button type="button" class="btn btn-p" onclick="toggleBillingMaps()"><i class="bi bi-eye"></i> <%= t('admin.map.see_maps','LIHAT PETA') %></button>
|
||||
</div>
|
||||
|
||||
<div id="mapsContent" style="display:none">
|
||||
@@ -711,15 +711,15 @@
|
||||
id="mapGlobalSearch"
|
||||
class="map-search-input"
|
||||
type="text"
|
||||
placeholder="Cari nama pelanggan, PPPoE, No HP, SN ONU, alamat, ODP..."
|
||||
placeholder="<%= t('admin.map.ph_search','Cari nama pelanggan, PPPoE, No HP, SN ONU, alamat, ODP...') %>"
|
||||
autocomplete="off"
|
||||
>
|
||||
<button id="mapSearchClearBtn" class="map-search-clear" onclick="clearMapSearch()" title="Hapus pencarian">×</button>
|
||||
<button id="mapSearchClearBtn" class="map-search-clear" onclick="clearMapSearch()" title="<%= t('admin.map.clear_search','Hapus pencarian') %>">×</button>
|
||||
|
||||
<!-- Auto-Suggest Dropdown Results -->
|
||||
<div id="mapSearchDropdown" class="map-search-dropdown">
|
||||
<div class="ms-header">
|
||||
<span id="msHeaderCount">Hasil Pencarian</span>
|
||||
<span id="msHeaderCount"><%= t('admin.map.search_result','Hasil Pencarian') %></span>
|
||||
<span><kbd style="background:#e2e8f0; padding:1px 4px; border-radius:4px; font-size:10px;">ESC</kbd> tutup</span>
|
||||
</div>
|
||||
<div id="msResultsList"></div>
|
||||
@@ -728,26 +728,26 @@
|
||||
|
||||
<!-- Quick Filter Pills -->
|
||||
<div class="map-filter-group">
|
||||
<button type="button" class="map-pill-btn active" id="pillAll" onclick="applyStatusFilter('all')" title="Tampilkan semua marker">
|
||||
<button type="button" class="map-pill-btn active" id="pillAll" onclick="applyStatusFilter('all')" title="<%= t('admin.map.tip_all','Tampilkan semua marker') %>">
|
||||
<i class="bi bi-grid-fill"></i> <%= t('collector.filter_all','Semua') %>
|
||||
</button>
|
||||
<button type="button" class="map-pill-btn" id="pillActive" onclick="applyStatusFilter('active')" title="Hanya ONU aktif">
|
||||
<button type="button" class="map-pill-btn" id="pillActive" onclick="applyStatusFilter('active')" title="<%= t('admin.map.tip_active','Hanya ONU aktif') %>">
|
||||
<i class="bi bi-check-circle-fill text-success"></i> Aktif (<%= customers.filter(c => c.status === 'active' && c.lat && c.lng).length %>)
|
||||
</button>
|
||||
<button type="button" class="map-pill-btn" id="pillSuspended" onclick="applyStatusFilter('suspended')" title="Hanya ONU isolir">
|
||||
<button type="button" class="map-pill-btn" id="pillSuspended" onclick="applyStatusFilter('suspended')" title="<%= t('admin.map.tip_isolir','Hanya ONU isolir') %>">
|
||||
<i class="bi bi-x-circle-fill text-danger"></i> Isolir (<%= customers.filter(c => c.status !== 'active' && c.lat && c.lng).length %>)
|
||||
</button>
|
||||
<button type="button" class="map-pill-btn active" id="pillLabels" onclick="toggleMarkerLabels()" title="Sembunyikan/Tampilkan label nama di marker">
|
||||
<i class="bi bi-tag-fill text-primary"></i> <span id="labelToggleText">Label: ON</span>
|
||||
<button type="button" class="map-pill-btn active" id="pillLabels" onclick="toggleMarkerLabels()" title="<%= t('admin.map.tip_labels','Sembunyikan/Tampilkan label nama di marker') %>">
|
||||
<i class="bi bi-tag-fill text-primary"></i> <span id="labelToggleText"><%= t('admin.map.label_on','Label: ON') %></span>
|
||||
</button>
|
||||
<button type="button" class="map-pill-btn" onclick="fitAllMarkers()" title="Pusatkan peta ke semua titik">
|
||||
<button type="button" class="map-pill-btn" onclick="fitAllMarkers()" title="<%= t('admin.map.tip_fit','Pusatkan peta ke semua titik') %>">
|
||||
<i class="bi bi-arrows-fullscreen"></i> Fit Peta
|
||||
</button>
|
||||
<select id="baseMapSelect" class="map-pill-btn" style="padding:6px 8px" onchange="switchBaseMap(this.value)" title="Pilih peta dasar">
|
||||
<option value="hybrid" selected>Satelit (Hybrid)</option>
|
||||
<option value="sat">Satelit (Bersih)</option>
|
||||
<option value="hybrid" selected><%= t('admin.map.opt_hybrid','Satelit (Hybrid)') %></option>
|
||||
<option value="sat"><%= t('admin.map.opt_sat','Satelit (Bersih)') %></option>
|
||||
<option value="osm">OpenStreetMap</option>
|
||||
<option value="dark">Gelap (Dark)</option>
|
||||
<option value="dark"><%= t('admin.map.opt_dark','Gelap (Dark)') %></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -760,12 +760,12 @@
|
||||
<div class="data-tabs-nav">
|
||||
<button type="button" class="tab-btn active" onclick="switchDataTab('onu-tab', this)">
|
||||
<i class="bi bi-router-fill"></i>
|
||||
<span>Daftar ONU Pelanggan</span>
|
||||
<span><%= t('admin.map.list_onu','Daftar ONU Pelanggan') %></span>
|
||||
<span class="tab-badge"><%= customers.length %></span>
|
||||
</button>
|
||||
<button type="button" class="tab-btn" onclick="switchDataTab('odp-tab', this)">
|
||||
<i class="bi bi-box-seam-fill"></i>
|
||||
<span>Daftar ODP (Box)</span>
|
||||
<span><%= t('admin.map.list_odp','Daftar ODP (Box)') %></span>
|
||||
<span class="tab-badge"><%= odps.length %></span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -779,16 +779,16 @@
|
||||
class="table-search-input"
|
||||
style="width: 100%;"
|
||||
type="text"
|
||||
placeholder="Filter nama, PPPoE, HP, SN/Tag..."
|
||||
placeholder="<%= t('admin.map.ph_filter','Filter nama, PPPoE, HP, SN/Tag...') %>"
|
||||
>
|
||||
</div>
|
||||
<div style="display: flex; gap: 8px; align-items: center;">
|
||||
<select id="customerGpsFilter" class="table-search-input" style="min-width: 160px;" onchange="filterCustomerTable()">
|
||||
<option value="all">Semua Status GPS</option>
|
||||
<option value="all"><%= t('admin.map.all_gps','Semua Status GPS') %></option>
|
||||
<option value="has_gps">Hanya Memiliki GPS (<%= customers.filter(c => c.lat && c.lng).length %>)</option>
|
||||
<option value="no_gps">Tanpa Koordinat GPS (<%= customers.filter(c => !c.lat || !c.lng).length %>)</option>
|
||||
<option value="active">Hanya Aktif</option>
|
||||
<option value="suspended">Hanya Isolir</option>
|
||||
<option value="no_gps">Tanpa <%= t('admin.map.th_gps','Koordinat GPS') %> (<%= customers.filter(c => !c.lat || !c.lng).length %>)</option>
|
||||
<option value="active"><%= t('admin.map.only_active','Hanya Aktif') %></option>
|
||||
<option value="suspended"><%= t('admin.map.only_isolir','Hanya Isolir') %></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -798,10 +798,10 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t('common.customer','Pelanggan') %></th>
|
||||
<th>PPPoE / Tag ONU</th>
|
||||
<th><%= t('admin.map.th_pppoe','PPPoE / Tag ONU') %></th>
|
||||
<th><%= t('common.status','Status') %></th>
|
||||
<th>Paket & ODP</th>
|
||||
<th>Koordinat GPS</th>
|
||||
<th><%= t('admin.map.th_pkg_odp','Paket & ODP') %></th>
|
||||
<th><%= t('admin.map.th_gps','Koordinat GPS') %></th>
|
||||
<th style="text-align: right; width: 140px;"><%= t('common.actions','Aksi') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -813,7 +813,7 @@
|
||||
<!-- TAB 2: DAFTAR ODP -->
|
||||
<div id="odp-tab" class="tab-content">
|
||||
<div class="panel-filter-bar">
|
||||
<input id="odpSearch" class="table-search-input" type="text" placeholder="Cari ODP (nama / deskripsi)...">
|
||||
<input id="odpSearch" class="table-search-input" type="text" placeholder="<%= t('admin.map.ph_odp','Cari ODP (nama / deskripsi)...') %>">
|
||||
<button type="button" class="btn btn-p btn-sm" onclick="openModal('addOdpModal')"><i class="bi bi-plus-circle"></i> Tambah ODP</button>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
@@ -932,7 +932,7 @@
|
||||
<script id="customers-data" type="application/json"><%- JSON.stringify(customers).replace(/<\/script/g, '<\\/script').replace(/<!--/g, '<\\!--') %></script>
|
||||
<script id="odps-data" type="application/json"><%- JSON.stringify(odps).replace(/<\/script/g, '<\\/script').replace(/<!--/g, '<\\!--') %></script>
|
||||
|
||||
<!-- Bootstrap lazy-load peta (SEE MAPS / CLOSE MAPS) -->
|
||||
<!-- Bootstrap lazy-load peta (<%= t('admin.map.see_maps','LIHAT PETA') %> / CLOSE MAPS) -->
|
||||
<script>
|
||||
window.__billingMapLoaded = false;
|
||||
function loadMapScript() {
|
||||
@@ -953,7 +953,7 @@
|
||||
if (showing) {
|
||||
content.style.display = 'none';
|
||||
if (ph) ph.style.display = '';
|
||||
if (txt) txt.textContent = 'SEE MAPS';
|
||||
if (txt) txt.textContent = '<%= t('admin.map.see_maps','LIHAT PETA') %>';
|
||||
} else {
|
||||
if (ph) ph.style.display = 'none';
|
||||
content.style.display = '';
|
||||
@@ -1372,7 +1372,7 @@
|
||||
<div class="ms-item-info">
|
||||
<div class="ms-item-name">
|
||||
<span>${highlightMatch(c.name, query)}</span>
|
||||
${!hasGps ? '<span style="color:#ef4444; font-size:10px; font-weight:700;"><i class="bi bi-exclamation-triangle"></i> Tanpa GPS</span>' : ''}
|
||||
${!hasGps ? '<span style="color:#ef4444; font-size:10px; font-weight:700;"><i class="bi bi-exclamation-triangle"></i> <%= t('admin.map.no_gps','Tanpa GPS') %></span>' : ''}
|
||||
</div>
|
||||
<div class="ms-item-meta">
|
||||
${c.pppoe_username ? `<span>PPPoE: ${highlightMatch(c.pppoe_username, query)}</span> • ` : ''}
|
||||
@@ -1589,7 +1589,7 @@
|
||||
if (showLabels) {
|
||||
mapEl.classList.remove('hide-marker-labels');
|
||||
btn.classList.add('active');
|
||||
txt.textContent = 'Label: ON';
|
||||
txt.textContent = '<%= t('admin.map.label_on','Label: ON') %>';
|
||||
} else {
|
||||
mapEl.classList.add('hide-marker-labels');
|
||||
btn.classList.remove('active');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html lang="<%= lang || 'id' %>">
|
||||
<head>
|
||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Paket Voucher Hotspot | <%= company %></title>
|
||||
<title><%= t('admin.vp.title','Paket Voucher Hotspot') %> | <%= company %></title>
|
||||
<link rel="stylesheet" href="/vendor/bootstrap-icons/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="/css/admin.css">
|
||||
<style>
|
||||
@@ -36,22 +36,22 @@
|
||||
|
||||
<div class="mtabs">
|
||||
<a href="/admin/vouchers" class="mtab"><i class="bi bi-ticket-perforated"></i> Pembuatan Voucher (Batch)</a>
|
||||
<a href="/admin/vouchers/packages" class="mtab active"><i class="bi bi-ticket-detailed"></i> Konfigurasi Paket (Real-Time)</a>
|
||||
<a href="/admin/vouchers/packages" class="mtab active"><i class="bi bi-ticket-detailed"></i> <%= t('admin.vp.config','Konfigurasi Paket') %> (Real-Time)</a>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-hd">
|
||||
<h6><i class="bi bi-list-stars"></i> Daftar Paket Hotspot Real-Time</h6>
|
||||
<h6><i class="bi bi-list-stars"></i> <%= t('admin.vp.list','Daftar Paket Hotspot Real-Time') %></h6>
|
||||
<div style="display:flex;align-items:center;gap:10px">
|
||||
<% if (typeof routers !== 'undefined' && routers && routers.length > 0) { %>
|
||||
<select class="fs" style="width:160px" onchange="window.location.href='/admin/set-active-router?router_id=' + this.value">
|
||||
<option value="all" <%= (!selectedRouterId) ? 'selected' : '' %>> Semua Router</option>
|
||||
<option value="all" <%= (!selectedRouterId) ? 'selected' : '' %>> <%= t('admin.vp.all_router','Semua Router') %></option>
|
||||
<% routers.forEach(r => { %>
|
||||
<option value="<%= r.id %>" <%= (selectedRouterId === r.id) ? 'selected' : '' %>> <%= r.name %></option>
|
||||
<% }) %>
|
||||
</select>
|
||||
<% } %>
|
||||
<button class="btn btn-p btn-sm" onclick="openAddModal()"><i class="bi bi-plus-lg"></i> Tambah Konfigurasi Paket</button>
|
||||
<button class="btn btn-p btn-sm" onclick="openAddModal()"><i class="bi bi-plus-lg"></i> <%= t('admin.vp.add_config','Tambah Konfigurasi Paket') %></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tbl-wrap">
|
||||
@@ -59,18 +59,18 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Router</th>
|
||||
<th>Nama Profile</th>
|
||||
<th>Harga</th>
|
||||
<th>Masa Aktif</th>
|
||||
<th>Prefix</th>
|
||||
<th>Panjang Kode</th>
|
||||
<th>Karakter</th>
|
||||
<th><%= t('admin.vp.th_profile','Nama Profile') %></th>
|
||||
<th><%= t('admin.vp.th_price','Harga') %></th>
|
||||
<th><%= t('admin.vp.th_validity','Masa Aktif') %></th>
|
||||
<th><%= t('admin.vp.th_prefix','Prefix') %></th>
|
||||
<th><%= t('admin.vp.th_len','Panjang Kode') %></th>
|
||||
<th><%= t('admin.vp.th_chars','Karakter') %></th>
|
||||
<th><%= t('common.status','Status') %></th>
|
||||
<th><%= t('common.actions','Aksi') %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="packages-list">
|
||||
<tr><td colspan="9" class="text-center text-muted">Memuat data paket...</td></tr>
|
||||
<tr><td colspan="9" class="text-center text-muted"><%= t('admin.vp.loading','Memuat data paket...') %></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -82,7 +82,7 @@
|
||||
<div class="mo" id="packageModal">
|
||||
<div class="mb" style="max-width: 600px;">
|
||||
<div class="mh">
|
||||
<span class="mt" id="modalTitle">Konfigurasi Paket</span>
|
||||
<span class="mt" id="modalTitle"><%= t('admin.vp.config','Konfigurasi Paket') %></span>
|
||||
<button class="mc" onclick="closeModal('packageModal')">×</button>
|
||||
</div>
|
||||
<form id="packageForm" onsubmit="savePackage(event)">
|
||||
@@ -90,53 +90,53 @@
|
||||
<div class="mbody">
|
||||
|
||||
<div class="fg">
|
||||
<label class="fl">Pilih Router MikroTik <span class="text-danger">*</span></label>
|
||||
<label class="fl"><%= t('admin.vp.pick_router','Pilih Router MikroTik') %> <span class="text-danger">*</span></label>
|
||||
<select class="fc" id="form_router_id" required onchange="loadMikrotikProfiles()">
|
||||
<option value="">-- Pilih Router --</option>
|
||||
<option value=""><%= t('admin.vp.opt_router','-- Pilih Router --') %></option>
|
||||
<% routers.forEach(r => { %>
|
||||
<option value="<%= r.id %>"><%= r.name %></option>
|
||||
<% }) %>
|
||||
</select>
|
||||
<small class="text-muted d-block mt-1">Router harus dipilih untuk paket voucher</small>
|
||||
<small class="text-muted d-block mt-1"><%= t('admin.vp.router_req','Router harus dipilih untuk paket voucher') %></small>
|
||||
</div>
|
||||
|
||||
<div class="fg">
|
||||
<label class="fl">Hotspot User Profile *</label>
|
||||
<div style="display:flex;gap:8px">
|
||||
<select class="fs" id="form_profile_select" style="max-width:220px" onchange="document.getElementById('form_profile_name').value=this.value; onProfileSelected();">
|
||||
<option value="">-- Pilih dari MikroTik --</option>
|
||||
<option value=""><%= t('admin.vp.opt_from_mt','-- Pilih dari MikroTik --') %></option>
|
||||
</select>
|
||||
<input class="fc" id="form_profile_name" required placeholder="Ketik nama profile manual...">
|
||||
<input class="fc" id="form_profile_name" required placeholder="<%= t('admin.vp.ph_profile','Ketik nama profile manual...') %>">
|
||||
</div>
|
||||
<div class="hint" id="profileHint">Pilih router & profil untuk membaca durasi bawaan atau ketik manual jika MikroTik offline.</div>
|
||||
<div class="hint" id="profileHint"><%= t('admin.vp.profile_hint','Pilih router & profil untuk membaca durasi bawaan atau ketik manual jika MikroTik offline.') %></div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="fg">
|
||||
<label class="fl">Harga Jual (Rp) *</label>
|
||||
<input class="fc" id="form_price" type="number" min="500" required placeholder="Contoh: 5000">
|
||||
<label class="fl"><%= t('admin.vp.price','Harga Jual (Rp) *') %></label>
|
||||
<input class="fc" id="form_price" type="number" min="500" required placeholder="<%= t('admin.vp.ph_price','Contoh: 5000') %>">
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl">Durasi / Masa Aktif *</label>
|
||||
<input class="fc" id="form_validity" required placeholder="Contoh: 1d, 12h, 3h">
|
||||
<div class="hint">Format Mikhmon (misal: 1d = 1 hari, 12h = 12 jam)</div>
|
||||
<label class="fl"><%= t('admin.vp.validity','Durasi / Masa Aktif *') %></label>
|
||||
<input class="fc" id="form_validity" required placeholder="<%= t('admin.vp.ph_validity','Contoh: 1d, 12h, 3h') %>">
|
||||
<div class="hint"><%= t('admin.vp.validity_hint','Format Mikhmon (misal: 1d = 1 hari, 12h = 12 jam)') %></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="fg">
|
||||
<label class="fl">Prefix Kode Voucher</label>
|
||||
<input class="fc" id="form_prefix" placeholder="Opsional (misal: ALI-)">
|
||||
<label class="fl"><%= t('admin.vp.prefix','Prefix Kode Voucher') %></label>
|
||||
<input class="fc" id="form_prefix" placeholder="<%= t('admin.vp.ph_prefix','Opsional (misal: ALI-)') %>">
|
||||
</div>
|
||||
<div class="fg">
|
||||
<label class="fl">Panjang Kode (Jumlah Digit) *</label>
|
||||
<label class="fl"><%= t('admin.vp.code_len','Panjang Kode (Jumlah Digit) *') %></label>
|
||||
<input class="fc" id="form_code_length" type="number" min="4" max="16" value="6" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="fg">
|
||||
<label class="fl">Tipe Karakter Kode *</label>
|
||||
<label class="fl"><%= t('admin.vp.char_type','Tipe Karakter Kode *') %></label>
|
||||
<select class="fc" id="form_charset" required>
|
||||
<option value="numbers">Hanya Angka (0-9)</option>
|
||||
<option value="letters">Hanya Huruf Kecil (a-z)</option>
|
||||
@@ -231,7 +231,7 @@
|
||||
}
|
||||
cachedMikrotikProfiles = Array.isArray(data) ? data : [];
|
||||
|
||||
profileSelect.innerHTML = '<option value="">-- Pilih dari MikroTik --</option>';
|
||||
profileSelect.innerHTML = '<option value=""><%= t('admin.vp.opt_from_mt','-- Pilih dari MikroTik --') %></option>';
|
||||
cachedMikrotikProfiles.forEach(p => {
|
||||
profileSelect.insertAdjacentHTML('beforeend', `<option value="${p.name}">${p.name}</option>`);
|
||||
});
|
||||
@@ -290,7 +290,7 @@
|
||||
const p = currentPackages[idx];
|
||||
if (!p) return;
|
||||
|
||||
document.getElementById('modalTitle').innerText = 'Edit Konfigurasi Paket';
|
||||
document.getElementById('modalTitle').innerText = 'Edit <%= t('admin.vp.config','Konfigurasi Paket') %>';
|
||||
document.getElementById('packageId').value = p.id;
|
||||
document.getElementById('form_router_id').value = p.router_id || '';
|
||||
|
||||
|
||||
Reference in new issue
Block a user