655 lines
20 KiB
PHP
655 lines
20 KiB
PHP
|
|
<?= $this->extend('layouts/main.php') ?>
|
||
|
|
|
||
|
|
<?= $this->section('content') ?>
|
||
|
|
|
||
|
|
<div class="page-wrapper">
|
||
|
|
<div class="container-fluid">
|
||
|
|
<div class="row page-titles">
|
||
|
|
<div class="col-md-5 align-self-center">
|
||
|
|
<h4 class="text-themecolor">Certificates Calibration Management</h4>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="row">
|
||
|
|
<div class="col-12">
|
||
|
|
<div class="card">
|
||
|
|
<div class="card-body">
|
||
|
|
<div class="row mb-3">
|
||
|
|
<div class="col-12 mb-3">
|
||
|
|
<div class="input-group input-group-sm">
|
||
|
|
<span class="input-group-text"><i class="fas fa-search"></i></span>
|
||
|
|
<input type="text" id="searchInput" class="form-control"
|
||
|
|
placeholder="Search certificates by name, product, type, vendor, or dates...">
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div class="col-md-4 mb-2">
|
||
|
|
<select id="statusFilter" class="form-select form-select-sm">
|
||
|
|
<option value="">All Status</option>
|
||
|
|
<option value="active">Active</option>
|
||
|
|
<option value="expired">Expired</option>
|
||
|
|
<option value="expiring">Expiring Soon</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
<div class="col-md-4 mb-2">
|
||
|
|
<select id="typeFilter" class="form-select form-select-sm">
|
||
|
|
<option value="">All Types</option>
|
||
|
|
<option value="calibration">calibration</option>
|
||
|
|
<option value="training">Training</option>
|
||
|
|
<option value="maintenance">Maintenance</option>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
<div class="col-md-4 mb-2">
|
||
|
|
<button onclick="resetFilters()" class="btn btn-secondary btn-sm w-100">
|
||
|
|
<i class="fas fa-redo"></i> Reset Filters
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="">
|
||
|
|
<button type="button" class="btn btn-info text-white btn-sm" data-bs-toggle="modal"
|
||
|
|
data-bs-target="#createModal">
|
||
|
|
<i class="fas fa-plus-circle"></i> Create
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="table-responsive">
|
||
|
|
<table id="certificatesTable" class="table table-striped table-hover border">
|
||
|
|
<thead class="table-primary">
|
||
|
|
<tr>
|
||
|
|
<th class="text-center" style="width: 5%;">No</th>
|
||
|
|
<th style="width: 15%;">Certificate Name</th>
|
||
|
|
<th style="width: 15%;">Product/Equipment</th>
|
||
|
|
<th style="width: 12%;">Type</th>
|
||
|
|
<th style="width: 12%;">Issue Date</th>
|
||
|
|
<th style="width: 12%;">Expiry Date</th>
|
||
|
|
<th style="width: 10%;">Status</th>
|
||
|
|
<th style="width: 10%;">Vendor</th>
|
||
|
|
<th class="text-center" style="width: 9%;">Action</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
<?php
|
||
|
|
if(isset($certificates) && !empty($certificates)) {
|
||
|
|
$no = 1;
|
||
|
|
foreach($certificates as $cert) {
|
||
|
|
$certid = $cert['certid'] ?? '';
|
||
|
|
$certname = $cert['certname'] ?? '-';
|
||
|
|
$productname = $cert['productname'] ?? '-';
|
||
|
|
$productnumber = $cert['productnumber'] ?? '';
|
||
|
|
$type = $cert['type'] ?? '-';
|
||
|
|
$issuedate = $cert['issuedate'] ?? '';
|
||
|
|
$expirydate = $cert['expirydate'] ?? '';
|
||
|
|
$vendor = $cert['vendor'] ?? '-';
|
||
|
|
|
||
|
|
// Format dates
|
||
|
|
if($issuedate && $issuedate != '0000-00-00') {
|
||
|
|
$issuedate = date('M d, Y', strtotime($issuedate));
|
||
|
|
} else {
|
||
|
|
$issuedate = '-';
|
||
|
|
}
|
||
|
|
|
||
|
|
if($expirydate && $expirydate != '0000-00-00') {
|
||
|
|
$expirydate = date('M d, Y', strtotime($expirydate));
|
||
|
|
// Check expiry status
|
||
|
|
$today = date('Y-m-d');
|
||
|
|
$expiryCheck = date('Y-m-d', strtotime($cert['expirydate']));
|
||
|
|
$daysUntilExpiry = (strtotime($expiryCheck) - strtotime($today)) / (60 * 60 * 24);
|
||
|
|
|
||
|
|
if($daysUntilExpiry < 0) {
|
||
|
|
$statusBadge = '<span class="badge bg-danger">Expired</span>';
|
||
|
|
$statusClass = 'expired';
|
||
|
|
} elseif($daysUntilExpiry <= 30) {
|
||
|
|
$statusBadge = '<span class="badge bg-warning text-dark">Expiring Soon</span>';
|
||
|
|
$statusClass = 'expiring';
|
||
|
|
} else {
|
||
|
|
$statusBadge = '<span class="badge bg-success">Active</span>';
|
||
|
|
$statusClass = 'active';
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
$expirydate = '-';
|
||
|
|
$statusBadge = '<span class="badge bg-secondary">N/A</span>';
|
||
|
|
$statusClass = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Type badge
|
||
|
|
$typeBadge = '';
|
||
|
|
switch(strtolower($type)) {
|
||
|
|
case 'calibration':
|
||
|
|
$typeBadge = '<span class="badge bg-info">calibration</span>';
|
||
|
|
break;
|
||
|
|
case 'training':
|
||
|
|
$typeBadge = '<span class="badge bg-primary">Training</span>';
|
||
|
|
break;
|
||
|
|
case 'maintenance':
|
||
|
|
$typeBadge = '<span class="badge bg-warning text-dark">Maintenance</span>';
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
$typeBadge = '<span class="badge bg-secondary">' . htmlspecialchars($type) . '</span>';
|
||
|
|
}
|
||
|
|
?>
|
||
|
|
<tr>
|
||
|
|
<td class="text-center"><?= $no++; ?></td>
|
||
|
|
<td>
|
||
|
|
<strong><?= htmlspecialchars($certname) ?></strong>
|
||
|
|
<br>
|
||
|
|
<small class="text-muted">ID: <?= $certid ?></small>
|
||
|
|
</td>
|
||
|
|
<td>
|
||
|
|
<?= htmlspecialchars($productname) ?>
|
||
|
|
<?php if($productnumber): ?>
|
||
|
|
<br><small class="text-muted">SN:
|
||
|
|
<?= htmlspecialchars($productnumber) ?></small>
|
||
|
|
<?php endif; ?>
|
||
|
|
</td>
|
||
|
|
<td><?= $typeBadge ?></td>
|
||
|
|
<td><?= $issuedate ?></td>
|
||
|
|
<td><?= $expirydate ?></td>
|
||
|
|
<td><?= $statusBadge ?></td>
|
||
|
|
<td><?= htmlspecialchars($vendor) ?></td>
|
||
|
|
<td class="text-center">
|
||
|
|
<div class="btn-group btn-group-sm">
|
||
|
|
<button type="button" class="btn btn-success btn-view"
|
||
|
|
data-certid="<?= $certid ?>" data-certprod="<?= $productname ?>" data-certtype="<?= $type ?>"
|
||
|
|
title="View PDF">
|
||
|
|
<i class="fas fa-file-pdf"></i>
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<?php
|
||
|
|
}
|
||
|
|
}
|
||
|
|
?>
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Create Modal -->
|
||
|
|
<div class="modal fade" id="createModal" tabindex="-1" aria-labelledby="createModalLabel" aria-hidden="true">
|
||
|
|
<div class="modal-dialog modal-xl modal-dialog-centered">
|
||
|
|
<div class="modal-content">
|
||
|
|
<div class="modal-header bg-info text-white">
|
||
|
|
<h5 class="modal-title" id="createModalLabel">
|
||
|
|
<i class="fas fa-plus-circle"></i> Create New Certificate Calibration
|
||
|
|
</h5>
|
||
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"
|
||
|
|
aria-label="Close"></button>
|
||
|
|
</div>
|
||
|
|
<form id="createForm" action="<?= base_url('certificates/create') ?>" method="post">
|
||
|
|
<div class="modal-body">
|
||
|
|
|
||
|
|
<div class="row">
|
||
|
|
<div class="col-md-6 mb-3">
|
||
|
|
<label for="certname" class="form-label">Certificate Name <span
|
||
|
|
class="text-danger">*</span></label>
|
||
|
|
<input type="text" class="form-control" id="certname" name="certname" required>
|
||
|
|
</div>
|
||
|
|
<div class="col-md-6 mb-3">
|
||
|
|
<label for="address" class="form-label">Address</label>
|
||
|
|
<input type="text" class="form-control" id="address" name="address">
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="row">
|
||
|
|
<div class="col-md-6 mb-3">
|
||
|
|
<label for="issuedate" class="form-label">Start Date <span
|
||
|
|
class="text-danger">*</span></label>
|
||
|
|
<input type="date" class="form-control" id="issuedate" name="issuedate">
|
||
|
|
</div>
|
||
|
|
<div class="col-md-6 mb-3">
|
||
|
|
<label for="expirydate" class="form-label">Expiry Date <span
|
||
|
|
class="text-danger">*</span></label>
|
||
|
|
<input type="date" class="form-control" id="expirydate" name="expirydate">
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="row">
|
||
|
|
<div class="col-md-6 mb-3">
|
||
|
|
<label for="type" class="form-label">Site <span class="text-danger">*</span></label>
|
||
|
|
<select class="form-select select2" id="type" name="type" required>
|
||
|
|
<option value=''>-- Choose one --</option>
|
||
|
|
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="col-md-6 mb-3">
|
||
|
|
<label for="productid" class="form-label">Product/Equipment <span
|
||
|
|
class="text-danger">*</span></label>
|
||
|
|
<select class="form-select select2" id="productid" name="productid">
|
||
|
|
<option value=''>-- Choose one --</option>
|
||
|
|
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="row">
|
||
|
|
<div class="col-md-4 mb-3">
|
||
|
|
<label for="reqmaterial" class="form-label">Required Material</label>
|
||
|
|
<textarea class="form-control" id="reqmaterial" name="reqmaterial" rows="4"></textarea>
|
||
|
|
</div>
|
||
|
|
<div class="col-md-4 mb-3">
|
||
|
|
<label for="procedure" class="form-label">Procedure</label>
|
||
|
|
<textarea class="form-control" id="procedure" name="procedure" rows="4"></textarea>
|
||
|
|
</div>
|
||
|
|
<div class="col-md-4 mb-3">
|
||
|
|
<label for="requirement" class="form-label">Requirement</label>
|
||
|
|
<textarea class="form-control" id="requirement" name="requirement" rows="4"></textarea>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="row">
|
||
|
|
<div class="controls">
|
||
|
|
<label>Nama Kolom (koma):
|
||
|
|
<input type="text" id="namaKolom" placeholder="No, Nama, Alamat"
|
||
|
|
value="No, Nama, Pekerjaan">
|
||
|
|
</label>
|
||
|
|
<label>Jumlah Baris:
|
||
|
|
<input type="number" id="inputBaris" value="3" min="1" style="width: 50px;">
|
||
|
|
</label>
|
||
|
|
<button type="button" onclick="buatTabelCustom()">Generate Tabel</button>
|
||
|
|
<button type="button" onclick="ambilData()" style="background: #4CAF50;">Cetak Data ke
|
||
|
|
Konsol</button>
|
||
|
|
<button type="button" onclick="resetTabel()" style="background: #dc3545;">Reset
|
||
|
|
Tabel</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="row">
|
||
|
|
<div id="containerTabel"></div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<style>
|
||
|
|
/* Styling untuk tabel yang di-generate */
|
||
|
|
#myTable {
|
||
|
|
width: 100%;
|
||
|
|
border-collapse: collapse;
|
||
|
|
margin-top: 15px;
|
||
|
|
background-color: #fff;
|
||
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||
|
|
}
|
||
|
|
|
||
|
|
#myTable thead {
|
||
|
|
background-color: #17a2b8;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
#myTable th {
|
||
|
|
padding: 12px;
|
||
|
|
text-align: left;
|
||
|
|
font-weight: 600;
|
||
|
|
border: 1px solid #dee2e6;
|
||
|
|
}
|
||
|
|
|
||
|
|
#myTable tbody tr {
|
||
|
|
border-bottom: 1px solid #dee2e6;
|
||
|
|
}
|
||
|
|
|
||
|
|
#myTable tbody tr:hover {
|
||
|
|
background-color: #f8f9fa;
|
||
|
|
}
|
||
|
|
|
||
|
|
#myTable td {
|
||
|
|
padding: 10px;
|
||
|
|
border: 1px solid #dee2e6;
|
||
|
|
min-width: 100px;
|
||
|
|
min-height: 35px;
|
||
|
|
}
|
||
|
|
|
||
|
|
#myTable td:focus {
|
||
|
|
outline: 2px solid #17a2b8;
|
||
|
|
background-color: #e9ecef;
|
||
|
|
}
|
||
|
|
|
||
|
|
#myTable td[contenteditable="true"]:hover {
|
||
|
|
background-color: #f1f8ff;
|
||
|
|
cursor: text;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Styling untuk container tabel */
|
||
|
|
#containerTabel {
|
||
|
|
margin-top: 20px;
|
||
|
|
padding: 15px;
|
||
|
|
background-color: #f8f9fa;
|
||
|
|
border-radius: 8px;
|
||
|
|
border: 1px solid #dee2e6;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Styling untuk controls */
|
||
|
|
.controls {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 15px;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
padding: 15px;
|
||
|
|
background-color: #e9ecef;
|
||
|
|
border-radius: 8px;
|
||
|
|
margin-bottom: 15px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls label {
|
||
|
|
margin: 0;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls input[type="text"],
|
||
|
|
.controls input[type="number"] {
|
||
|
|
padding: 8px 12px;
|
||
|
|
border: 1px solid #ced4da;
|
||
|
|
border-radius: 4px;
|
||
|
|
margin-left: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls button {
|
||
|
|
padding: 8px 16px;
|
||
|
|
border: none;
|
||
|
|
border-radius: 4px;
|
||
|
|
cursor: pointer;
|
||
|
|
font-weight: 500;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls button:first-of-type {
|
||
|
|
background-color: #17a2b8;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls button:first-of-type:hover {
|
||
|
|
background-color: #138496;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls button:last-of-type {
|
||
|
|
background-color: #28a745;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls button:last-of-type:hover {
|
||
|
|
background-color: #218838;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls button:nth-last-of-type(2) {
|
||
|
|
background-color: #dc3545;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.controls button:nth-last-of-type(2):hover {
|
||
|
|
background-color: #c82333;
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
|
||
|
|
<!-- <div class="mb-3">
|
||
|
|
<label for="description" class="form-label">Description</label>
|
||
|
|
<textarea class="form-control" id="description" name="description" rows="2"></textarea>
|
||
|
|
</div> -->
|
||
|
|
</div>
|
||
|
|
<div class="modal-footer">
|
||
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||
|
|
<i class="fas fa-times"></i> Cancel
|
||
|
|
</button>
|
||
|
|
<button type="submit" class="btn btn-info text-white">
|
||
|
|
<i class="fas fa-save"></i> Save
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<?= $this->endSection() ?>
|
||
|
|
|
||
|
|
<?= $this->section('script') ?>
|
||
|
|
<script>
|
||
|
|
$(function () {
|
||
|
|
// Store DataTable instance
|
||
|
|
let table = null;
|
||
|
|
|
||
|
|
// Initialize DataTable
|
||
|
|
table = $('#certificatesTable').DataTable({
|
||
|
|
"order": [
|
||
|
|
[0, "asc"]
|
||
|
|
],
|
||
|
|
"pageLength": 25,
|
||
|
|
"lengthMenu": [
|
||
|
|
[10, 25, 50, 100, -1],
|
||
|
|
[10, 25, 50, 100, "All"]
|
||
|
|
],
|
||
|
|
"language": {
|
||
|
|
"emptyTable": "No certificates available",
|
||
|
|
"info": "Showing _START_ to _END_ of _TOTAL_ certificates",
|
||
|
|
"infoEmpty": "No certificates found",
|
||
|
|
"infoFiltered": "(filtered from _MAX_ total certificates)"
|
||
|
|
},
|
||
|
|
"dom": '<"row"<"col-md-6"l>>rtip',
|
||
|
|
"columnDefs": [{
|
||
|
|
"orderable": false,
|
||
|
|
"targets": [8]
|
||
|
|
}, // Disable sorting on Action column
|
||
|
|
{
|
||
|
|
"searchable": true,
|
||
|
|
"targets": [0, 1, 2, 3, 4, 5, 6, 7]
|
||
|
|
} // Enable search on all columns except Action
|
||
|
|
]
|
||
|
|
});
|
||
|
|
|
||
|
|
// Hide default DataTables search
|
||
|
|
$('#certificatesTable_filter').hide();
|
||
|
|
|
||
|
|
// Initialize Select2
|
||
|
|
$('.select2').select2({
|
||
|
|
theme: 'bootstrap-5',
|
||
|
|
width: '100%',
|
||
|
|
dropdownParent: $('.modal')
|
||
|
|
});
|
||
|
|
|
||
|
|
// Custom search functionality
|
||
|
|
$('#searchInput').on('keyup', function () {
|
||
|
|
let searchValue = $(this).val().toLowerCase();
|
||
|
|
table.search(searchValue).draw();
|
||
|
|
});
|
||
|
|
|
||
|
|
// Status filter using DataTables column filter
|
||
|
|
$('#statusFilter').on('change', function () {
|
||
|
|
let status = $(this).val();
|
||
|
|
|
||
|
|
// Filter by status column (index 6)
|
||
|
|
if (status === '') {
|
||
|
|
table.column(6).search('').draw();
|
||
|
|
} else {
|
||
|
|
// Search for the badge text in status column
|
||
|
|
let statusText = '';
|
||
|
|
switch (status) {
|
||
|
|
case 'active':
|
||
|
|
statusText = 'Active';
|
||
|
|
break;
|
||
|
|
case 'expired':
|
||
|
|
statusText = 'Expired';
|
||
|
|
break;
|
||
|
|
case 'expiring':
|
||
|
|
statusText = 'Expiring Soon';
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
table.column(6).search(statusText).draw();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Type filter using DataTables column filter
|
||
|
|
$('#typeFilter').on('change', function () {
|
||
|
|
let type = $(this).val();
|
||
|
|
|
||
|
|
// Filter by type column (index 3)
|
||
|
|
if (type === '') {
|
||
|
|
table.column(3).search('').draw();
|
||
|
|
} else {
|
||
|
|
// Capitalize first letter for search
|
||
|
|
let typeText = type.charAt(0).toUpperCase() + type.slice(1);
|
||
|
|
table.column(3).search(typeText).draw();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// Reset filters
|
||
|
|
window.resetFilters = function () {
|
||
|
|
$('#searchInput').val('');
|
||
|
|
$('#statusFilter').val('');
|
||
|
|
$('#typeFilter').val('');
|
||
|
|
|
||
|
|
// Reset DataTables search and filters
|
||
|
|
table.search('').columns().search('').draw();
|
||
|
|
|
||
|
|
// Re-apply default ordering
|
||
|
|
table.order([5, 'asc']).draw();
|
||
|
|
};
|
||
|
|
|
||
|
|
// View button click - Open PDF in new tab based on certificate type
|
||
|
|
$(document).on('click', '.btn-view', function () {
|
||
|
|
let certid = $(this).data('certid');
|
||
|
|
// let certType = $(this).data('certtype');s
|
||
|
|
let certProd = $(this).data('certprod');
|
||
|
|
|
||
|
|
let url = '';
|
||
|
|
url = '<?= base_url('certificates/calibration/show') ?>/' + certid + '/' + certProd;
|
||
|
|
|
||
|
|
// switch (certType) {
|
||
|
|
// case 'training':
|
||
|
|
// url = '<?= base_url('certificates/training/show') ?>/' + certid;
|
||
|
|
// break;
|
||
|
|
// case 'calibration':
|
||
|
|
// url = '<?= base_url('certificates/calibration/show') ?>/' + certid;
|
||
|
|
// break;
|
||
|
|
// case 'maintenance':
|
||
|
|
// url = '<?= base_url('certificates/maintenance/show') ?>/' + certid;
|
||
|
|
// break;
|
||
|
|
// default:
|
||
|
|
// url = '<?= base_url('certificates/view') ?>/' + certid;
|
||
|
|
// }
|
||
|
|
|
||
|
|
window.open(url, '_blank');
|
||
|
|
});
|
||
|
|
|
||
|
|
// Print button
|
||
|
|
$('#btnPrint').on('click', function () {
|
||
|
|
window.print();
|
||
|
|
});
|
||
|
|
|
||
|
|
// Date picker enhancement
|
||
|
|
$('input[type="date"]').on('focus', function () {
|
||
|
|
this.showPicker();
|
||
|
|
});
|
||
|
|
|
||
|
|
// Re-attach event handlers after DataTables pagination/draw
|
||
|
|
table.on('draw.dt', function () {
|
||
|
|
// Event handlers are already attached using $(document).on(), so no need to re-attach
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
function buatTabelCustom() {
|
||
|
|
const headerInput = document.getElementById('namaKolom').value;
|
||
|
|
const jumlahBaris = document.getElementById('inputBaris').value;
|
||
|
|
const kontainer = document.getElementById('containerTabel');
|
||
|
|
|
||
|
|
const daftarKolom = headerInput.split(',').map(item => item.trim());
|
||
|
|
|
||
|
|
if (headerInput === "" || daftarKolom[0] === "") {
|
||
|
|
alert("Mohon isi nama kolom terlebih dahulu!");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
kontainer.innerHTML = "";
|
||
|
|
const tabel = document.createElement('table');
|
||
|
|
tabel.id = "myTable";
|
||
|
|
tabel.className = "table table-bordered table-striped table-hover";
|
||
|
|
tabel.style.width = "100%";
|
||
|
|
tabel.style.borderCollapse = "collapse";
|
||
|
|
tabel.style.backgroundColor = "#fff";
|
||
|
|
tabel.style.boxShadow = "0 2px 4px rgba(0,0,0,0.1)";
|
||
|
|
|
||
|
|
// --- HEADER ---
|
||
|
|
const thead = document.createElement('thead');
|
||
|
|
thead.style.backgroundColor = "#17a2b8";
|
||
|
|
thead.style.color = "white";
|
||
|
|
|
||
|
|
const barisHeader = document.createElement('tr');
|
||
|
|
daftarKolom.forEach(teksKolom => {
|
||
|
|
const th = document.createElement('th');
|
||
|
|
th.textContent = teksKolom;
|
||
|
|
th.style.padding = "12px";
|
||
|
|
th.style.textAlign = "left";
|
||
|
|
th.style.fontWeight = "600";
|
||
|
|
th.style.border = "1px solid #dee2e6";
|
||
|
|
barisHeader.appendChild(th);
|
||
|
|
});
|
||
|
|
thead.appendChild(barisHeader);
|
||
|
|
tabel.appendChild(thead);
|
||
|
|
|
||
|
|
// --- BODY (EDITABLE) ---
|
||
|
|
const tbody = document.createElement('tbody');
|
||
|
|
for (let i = 1; i <= jumlahBaris; i++) {
|
||
|
|
const baris = document.createElement('tr');
|
||
|
|
baris.style.borderBottom = "1px solid #dee2e6";
|
||
|
|
baris.style.transition = "background-color 0.2s ease";
|
||
|
|
|
||
|
|
daftarKolom.forEach(() => {
|
||
|
|
const td = document.createElement('td');
|
||
|
|
td.contentEditable = "true";
|
||
|
|
td.textContent = "";
|
||
|
|
td.style.padding = "10px";
|
||
|
|
td.style.border = "1px solid #dee2e6";
|
||
|
|
td.style.minWidth = "100px";
|
||
|
|
td.style.minHeight = "35px";
|
||
|
|
td.style.cursor = "text";
|
||
|
|
|
||
|
|
// Add hover effect
|
||
|
|
td.addEventListener('mouseenter', function () {
|
||
|
|
this.style.backgroundColor = "#f1f8ff";
|
||
|
|
});
|
||
|
|
td.addEventListener('mouseleave', function () {
|
||
|
|
this.style.backgroundColor = "";
|
||
|
|
});
|
||
|
|
|
||
|
|
// Add focus effect
|
||
|
|
td.addEventListener('focus', function () {
|
||
|
|
this.style.outline = "2px solid #17a2b8";
|
||
|
|
this.style.backgroundColor = "#e9ecef";
|
||
|
|
});
|
||
|
|
td.addEventListener('blur', function () {
|
||
|
|
this.style.outline = "none";
|
||
|
|
this.style.backgroundColor = "";
|
||
|
|
});
|
||
|
|
|
||
|
|
baris.appendChild(td);
|
||
|
|
});
|
||
|
|
|
||
|
|
tbody.appendChild(baris);
|
||
|
|
}
|
||
|
|
tabel.appendChild(tbody);
|
||
|
|
kontainer.appendChild(tabel);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fungsi tambahan untuk membuktikan data bisa diambil
|
||
|
|
function ambilData() {
|
||
|
|
const tabel = document.getElementById('myTable');
|
||
|
|
if (!tabel) return;
|
||
|
|
|
||
|
|
const rows = Array.from(tabel.querySelectorAll('tbody tr'));
|
||
|
|
const data = rows.map(row => {
|
||
|
|
return Array.from(row.querySelectorAll('td')).map(td => td.textContent);
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log("Data Tabel:", data);
|
||
|
|
alert("Data sudah dicetak di Console (F12) dalam bentuk Array.");
|
||
|
|
}
|
||
|
|
|
||
|
|
// Fungsi untuk mereset/hapus tabel
|
||
|
|
function resetTabel() {
|
||
|
|
const kontainer = document.getElementById('containerTabel');
|
||
|
|
if (kontainer) {
|
||
|
|
kontainer.innerHTML = "";
|
||
|
|
// alert("Tabel berhasil dihapus!");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
<?= $this->endSection() ?>
|