//source-code file: /config/database.
php :
<?php
// Konfigurasi Database PDO untuk SPK Promosi Jabatan
class Database {
private static $instance = null;
private $host = 'localhost';
private $db_name = 'spk_promosi_jabatan';
private $username = 'root';
private $password = '';
private $conn; public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function getConnection() {
$this->conn = null;
try {
$dsn = "mysql:host=" . $this->host . ";dbname=" . $this->db_name .
";charset=utf8mb4";
$this->conn = new PDO($dsn, $this->username, $this->password);
// Set PDO options
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,
PDO::FETCH_ASSOC);
$this->conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $e) {
echo "Connection Error: " . $e->getMessage();
die();
}
return $this->conn;
}
// Method untuk test koneksi
public function testConnection() {
try {
$pdo = $this->getConnection();
if ($pdo) {
return true;
}
} catch (Exception $e) {
return false;
}
return false;
}
}
// Inisialisasi koneksi global
$database = new Database();
$pdo = $database->getConnection();
// Function helper untuk execute query
function executeQuery($pdo, $sql, $params = []) {
try {
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
} catch (PDOException $e) {
error_log("Database Error: " . $e->getMessage());
return false;
}
}
// Function helper untuk fetch single row
function fetchRow($pdo, $sql, $params = []) {
$stmt = executeQuery($pdo, $sql, $params);
return $stmt ? $stmt->fetch() : false;
}
// Function helper untuk fetch multiple rows
function fetchAll($pdo, $sql, $params = []) {
$stmt = executeQuery($pdo, $sql, $params);
return $stmt ? $stmt->fetchAll() : false;
}
// Function helper untuk insert dan return last insert id
function insertAndGetId($pdo, $sql, $params = []) {
$stmt = executeQuery($pdo, $sql, $params);
return $stmt ? $pdo->lastInsertId() : false;
}?>
//source-code file: /config/session.php :
<?php
// Start session jika belum
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
class SessionManager {
// Fungsi untuk login user
public static function login($userData) {
$_SESSION['user_id'] = $userData['idUser'];
$_SESSION['username'] = $userData['username'];
$_SESSION['role'] = $userData['role'];
$_SESSION['status'] = $userData['status'];
$_SESSION['login_time'] = time();
// Set data tambahan berdasarkan role
if ($userData['role'] == 'Admin') {
$_SESSION['nama'] = $userData['namaAdmin'];
$_SESSION['noHP'] = $userData['noHP'];
} elseif ($userData['role'] == 'Manager') {
$_SESSION['nama'] = $userData['namaManager'];
$_SESSION['noHP'] = $userData['noHP'];
} elseif ($userData['role'] == 'Karyawan') {
$_SESSION['nama'] = $userData['namaKaryawan'];
$_SESSION['noHP'] = $userData['noHP'];
$_SESSION['karyawan_id'] = $userData['idKaryawan'];
}
return true;
}
// Fungsi untuk logout
public static function logout() {
session_unset();
session_destroy();
return true;
}
// Cek apakah user sudah login
public static function isLoggedIn() {
return isset($_SESSION['user_id']) && isset($_SESSION['role']);
}
// Get user data
public static function getUserData() {
if (self::isLoggedIn()) {
return [
'user_id' => $_SESSION['user_id'],
'username' => $_SESSION['username'],
'role' => $_SESSION['role'],
'nama' => $_SESSION['nama'] ?? '',
'noHP' => $_SESSION['noHP'] ?? '',
'karyawan_id' => $_SESSION['karyawan_id'] ?? null
];
}
return false;
}
// Get user role
public static function getRole() {
return $_SESSION['role'] ?? null;
}
// Get user ID
public static function getUserId() {
return $_SESSION['user_id'] ?? null;
}
// Cek authorization berdasarkan role
public static function checkRole($allowedRoles) {
if (!self::isLoggedIn()) {
return false;
}
$userRole = self::getRole();
if (is_string($allowedRoles)) {
return $userRole === $allowedRoles;
}
if (is_array($allowedRoles)) {
return in_array($userRole, $allowedRoles);
}
return false;
}
// Redirect jika tidak ada akses
public static function requireRole($allowedRoles, $redirectUrl =
'../index.php') {
if (!self::checkRole($allowedRoles)) {
header("Location: $redirectUrl");
exit();
}
}
// Redirect ke dashboard sesuai role
public static function redirectToDashboard() {
$role = self::getRole();
switch ($role) {
case 'Admin':
header("Location: dashboard/admin/index.php");
break;
case 'Manager':
header("Location: dashboard/manager/index.php");
break;
case 'Karyawan':
header("Location: dashboard/karyawan/index.php");
break;
default:
header("Location: index.php");
}
exit();
}
// Set flash message
public static function setFlash($type, $message) {
$_SESSION['flash'][$type] = $message;
}
// Get dan hapus flash message
public static function getFlash($type) {
if (isset($_SESSION['flash'][$type])) {
$message = $_SESSION['flash'][$type];
unset($_SESSION['flash'][$type]);
return $message;
}
return null;
}
// Cek session timeout (30 menit)
public static function checkTimeout($timeout = 1800) {
if (isset($_SESSION['login_time'])) {
if (time() - $_SESSION['login_time'] > $timeout) {
self::logout();
return false;
}
// Update login time
$_SESSION['login_time'] = time();
}
return true;
}
// Generate CSRF token
public static function generateCSRF() {
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
// Verify CSRF token
public static function verifyCSRF($token) {
return isset($_SESSION['csrf_token']) &&
hash_equals($_SESSION['csrf_token'], $token);
}
}
// Auto check timeout pada setiap page load
if (SessionManager::isLoggedIn()) {
if (!SessionManager::checkTimeout()) {
header("Location: index.php?timeout=1");
exit();
}
}?>
//source-code file: index.php (halaman login) :
<?php
// index.php - Landing Page / Login
require_once 'config/database.php';
require_once 'config/session.php';
// Redirect jika sudah login
if (SessionManager::isLoggedIn()) {
SessionManager::redirectToDashboard();
}
// Handle login form submission
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['login'])) {
$username = trim($_POST['username']);
$password = $_POST['password'];
if (empty($username) || empty($password)) {
$error = "Username dan password harus diisi!";
} else {
// Query untuk mendapatkan data user dengan join ke tabel detail
$sql = "SELECT u.*,
CASE
WHEN u.role = 'Admin' THEN a.namaAdmin
WHEN u.role = 'Manager' THEN m.namaManager
WHEN u.role = 'Karyawan' THEN k.namaKaryawan
END as nama,
CASE
WHEN u.role = 'Admin' THEN a.noHP
WHEN u.role = 'Manager' THEN m.noHP
WHEN u.role = 'Karyawan' THEN k.noHP
END as noHP,
k.idKaryawan
FROM users u
LEFT JOIN admin a ON u.idUser = a.idUser
LEFT JOIN managerfbs m ON u.idUser = m.idUser
LEFT JOIN karyawanfbs k ON u.idUser = k.idUser
WHERE u.username = ? AND u.status = 'Aktif'";
$user = fetchRow($pdo, $sql, [$username]);
if ($user && password_verify($password, $user['password'])) {
// Login berhasil
$userData = [
'idUser' => $user['idUser'],
'username' => $user['username'],
'role' => $user['role'],
'status' => $user['status']
];
// Tambahkan data spesifik role
if ($user['role'] == 'Admin') {
$userData['namaAdmin'] = $user['nama'];
$userData['noHP'] = $user['noHP'];
} elseif ($user['role'] == 'Manager') {
$userData['namaManager'] = $user['nama'];
$userData['noHP'] = $user['noHP'];
} elseif ($user['role'] == 'Karyawan') {
$userData['namaKaryawan'] = $user['nama'];
$userData['noHP'] = $user['noHP'];
$userData['idKaryawan'] = $user['idKaryawan'];
}
SessionManager::login($userData);
SessionManager::redirectToDashboard();
} else {
$error = "Username atau password salah!";
}
}
}
// Handle timeout message
$timeout_message = '';
if (isset($_GET['timeout'])) {
$timeout_message = "Sesi Anda telah berakhir. Silakan login kembali.";
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SPK Promosi Jabatan - Hotel Le Polonia</title>
<!-- Bootstrap 5 CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet">
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/
all.min.css" rel="stylesheet">
<!-- Custom CSS -->
<link href="assets/css/custom.css" rel="stylesheet">
<style>
</style>
</head>
<body>
<div class="login-wrapper">
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-12">
<div class="login-container">
<div class="row g-0">
<!-- Logo Section -->
<div class="col-md-6">
<div class="logo-section">
<i class="fas fa-hotel logo-icon"></i>
<h2 class="fw-bold mb-3">Hotel Le Polonia</h2>
<h4 class="mb-4">Sistem Pendukung
Keputusan</h4>
<p class="lead text-center">Promosi Jabatan
Karyawan Departemen FBS</p>
<div class="mt-4">
<small class="text-light opacity-75">
Menggunakan Metode Simple Additive
Weighting (SAW)
</small>
</div>
</div>
</div>
<!-- Login Form Section -->
<div class="col-md-6">
<div class="form-section">
<h3 class="form-title">Login Sistem</h3>
<?php if (isset($error)): ?>
<div class="alert alert-danger alert-
dismissible fade show" role="alert">
<i class="fas fa-exclamation-triangle
me-2"></i>
<?= htmlspecialchars($error) ?>
<button type="button" class="btn-close"
data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if ($timeout_message): ?>
<div class="alert alert-warning alert-
dismissible fade show" role="alert">
<i class="fas fa-clock me-2"></i>
<?=
htmlspecialchars($timeout_message) ?>
<button type="button" class="btn-close"
data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<form method="POST" action="">
<div class="form-group">
<label for="username" class="form-
label">Username</label>
<div class="input-wrapper">
<input type="text" class="form-
control"
id="username"
name="username"
placeholder="Masukkan
username Anda"
value="<?=
isset($_POST['username']) ? htmlspecialchars($_POST['username']) : '' ?>"
required>
</div>
</div>
<div class="form-group">
<label for="password" class="form-
label">Password</label>
<div class="input-wrapper">
<div class="password-wrapper">
<input type="password"
class="form-control"
id="password"
name="password"
placeholder="Masukkan
password Anda"
required>
<span class="password-toggle"
onclick="togglePassword()">
<i class="fas fa-eye"
id="toggleIcon"></i>
</span>
</div>
</div>
</div>
<div class="form-group">
<button type="submit" name="login"
class="btn btn-login">
<i class="fas fa-sign-in-alt me-
2"></i>
Masuk Sistem
</button>
</div>
</form>
<div class="footer-links">
<small class="text-muted">
Belum punya akun?
<a href="auth/register.php">Daftar di
sini</a>
</small>
</div>
<div class="security-badge">
<i class="fas fa-shield-alt me-2"></i>
<small>Sistem Keamanan Terjamin</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Bootstrap 5 JS -->
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js">
</script>
<script>
// Toggle password visibility
function togglePassword() {
const passwordInput = document.getElementById('password');
const toggleIcon = document.getElementById('toggleIcon');
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
toggleIcon.classList.remove('fa-eye');
toggleIcon.classList.add('fa-eye-slash');
} else {
passwordInput.type = 'password';
toggleIcon.classList.remove('fa-eye-slash');
toggleIcon.classList.add('fa-eye');
}
}
// Auto dismiss alerts after 5 seconds
setTimeout(function() {
const alerts = document.querySelectorAll('.alert');
alerts.forEach(function(alert) {
const bsAlert = new bootstrap.Alert(alert);
bsAlert.close();
});
}, 5000);
// Add focus animations
document.querySelectorAll('.form-control').forEach(function(input) {
input.addEventListener('focus', function() {
this.parentElement.classList.add('focused');
});
input.addEventListener('blur', function() {
this.parentElement.classList.remove('focused');
});
});
</script>
</body>
</html>
//source-code file: /auth/login.php :
<?php
// auth/login.php - Process Login
require_once '../config/database.php';
require_once '../config/session.php';
// Redirect jika sudah login
if (SessionManager::isLoggedIn()) {
SessionManager::redirectToDashboard();
}
$response = ['success' => false, 'message' => ''];
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Verify CSRF token if available
if (isset($_POST['csrf_token']) && !
SessionManager::verifyCSRF($_POST['csrf_token'])) {
$response['message'] = 'Token keamanan tidak valid!';
echo json_encode($response);
exit;
}
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
// Validasi input
if (empty($username) || empty($password)) {
$response['message'] = 'Username dan password harus diisi!';
} else {
try {
// Query untuk mendapatkan data user dengan join ke tabel detail
$sql = "SELECT u.*,
CASE
WHEN u.role = 'Admin' THEN a.namaAdmin
WHEN u.role = 'Manager' THEN m.namaManager
WHEN u.role = 'Karyawan' THEN k.namaKaryawan
END as nama,
CASE
WHEN u.role = 'Admin' THEN a.noHP
WHEN u.role = 'Manager' THEN m.noHP
WHEN u.role = 'Karyawan' THEN k.noHP
END as noHP,
k.idKaryawan
FROM users u
LEFT JOIN admin a ON u.idUser = a.idUser AND u.role = 'Admin'
LEFT JOIN managerfbs m ON u.idUser = m.idUser AND u.role =
'Manager'
LEFT JOIN karyawanfbs k ON u.idUser = k.idUser AND u.role =
'Karyawan'
WHERE u.username = ? AND u.status = 'Aktif'";
$user = fetchRow($pdo, $sql, [$username]);
if ($user && password_verify($password, $user['password'])) {
// Cek status khusus untuk karyawan
if ($user['role'] == 'Karyawan') {
$sqlKaryawan = "SELECT statusKerja FROM karyawanfbs WHERE
idUser = ?";
$karyawan = fetchRow($pdo, $sqlKaryawan, [$user['idUser']]);
if ($karyawan && $karyawan['statusKerja'] != 'Aktif') {
$response['message'] = 'Akun karyawan tidak dalam status
aktif!';
echo json_encode($response);
exit;
}
}
// Prepare user data for session
$userData = [
'idUser' => $user['idUser'],
'username' => $user['username'],
'role' => $user['role'],
'status' => $user['status']
];
// Tambahkan data spesifik role
if ($user['role'] == 'Admin') {
$userData['namaAdmin'] = $user['nama'];
$userData['noHP'] = $user['noHP'];
} elseif ($user['role'] == 'Manager') {
$userData['namaManager'] = $user['nama'];
$userData['noHP'] = $user['noHP'];
} elseif ($user['role'] == 'Karyawan') {
$userData['namaKaryawan'] = $user['nama'];
$userData['noHP'] = $user['noHP'];
$userData['idKaryawan'] = $user['idKaryawan'];
}
// Login berhasil
if (SessionManager::login($userData)) {
// Log activity
if (function_exists('SPKHelper::logActivity')) {
SPKHelper::logActivity($pdo, $user['idUser'], 'LOGIN',
'User berhasil login');
}
$response['success'] = true;
$response['message'] = 'Login berhasil!';
// set redirect berdasarkan role
switch ($user['role']) {
case 'Admin' || 'manager':
$response['redirect'] = '../dashboard/admin/index.php';
break;
case 'Manager':
$response['redirect'] =
'../dashboard/manager/index.php';
break;
case 'Karyawan':
$response['redirect'] =
'../dashboard/karyawan/index.php';
break;
default:
$response['redirect'] = '../index.php';
}
} else {
$response['message'] = 'Gagal membuat sesi login!';
}
} else {
$response['message'] = 'Username atau password salah!';
// log login gagal
if (function_exists('SPKHelper::logActivity')) {
SPKHelper::logActivity($pdo, 0, 'LOGIN_FAILED', "Failed login
attempt for username: $username");
}
}
} catch (Exception $e) {
$response['message'] = 'Terjadi kesalahan sistem. Silakan coba lagi.';
error_log("Login Error: " . $e->getMessage());
}
}
}
// return respon dengan format JSON untuk AJAX
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
header('Content-Type: application/json');
echo json_encode($response);
exit;
}
// arahkan kembali ke halaman login dengan pesan
if ($response['success']) {
header("Location: " . $response['redirect']);
} else {
SessionManager::setFlash('error', $response['message']);
header("Location: ../index.php");
}
exit;
?>
//source-code file: /auth/register.php :
<?php
require_once '../config/database.php';
require_once '../config/session.php';
require_once '../includes/functions.php';
// Redirect jika sudah login
if (SessionManager::isLoggedIn()) {
SessionManager::redirectToDashboard();
}
$errors = [];
$success = '';
// menangani registrasi form
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['register'])) {
// verifikasi token CSRF
if (!SessionManager::verifyCSRF($_POST['csrf_token'] ?? '')) {
$errors[] = 'Token keamanan tidak valid!';
} else {
// Validasi input
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
$confirm_password = $_POST['confirm_password'] ?? '';
$role = $_POST['role'] ?? 'Karyawan';
$nama = trim($_POST['nama'] ?? '');
$noHP = trim($_POST['noHP'] ?? '');
// Validasi data umum
if (empty($username)) $errors[] = 'Username harus diisi!';
if (empty($password)) $errors[] = 'Password harus diisi!';
if (empty($confirm_password)) $errors[] = 'Konfirmasi password harus
diisi!';
if (empty($nama)) $errors[] = 'Nama harus diisi!';
if ($password != $confirm_password) {
$errors[] = 'Password dan konfirmasi password tidak sama!';
}
if (strlen($password) < 6) {
$errors[] = 'Password minimal 6 karakter!';
}
// Validasi khusus untuk karyawan
if ($role == 'Karyawan') {
$jenisKelamin = $_POST['jenisKelamin'] ?? '';
$tanggalLahir = $_POST['tanggalLahir'] ?? '';
$pendidikan = $_POST['pendidikan'] ?? '';
$Alamat = $_POST['Alamat'] ?? '';
$jabatan = $_POST['jabatan'] ?? '';
$tanggalMasuk = $_POST['tanggalMasuk'] ?? '';
$statusKerja = $_POST['statusKerja'] ?? 'Aktif';
if (empty($jenisKelamin)) $errors[] = 'Jenis kelamin harus dipilih!';
if (empty($tanggalLahir)) $errors[] = 'Tanggal lahir harus diisi!';
if (empty($jabatan)) $errors[] = 'Jabatan harus dipilih!';
if (empty($tanggalMasuk)) $errors[] = 'Tanggal masuk harus diisi!';
}
// Cek username sudah ada atau belum
if (empty($errors)) {
$sqlCheck = "SELECT idUser FROM users WHERE username = ?";
$existingUser = fetchRow($pdo, $sqlCheck, [$username]);
if ($existingUser) {
$errors[] = 'Username sudah digunakan!';
}
}
// Proses registrasi jika tidak ada error
if (empty($errors)) {
try {
$pdo->beginTransaction();
// Hash password
$hashedPassword = SPKHelper::hashPassword($password);
// Insert ke tabel users
$sqlUser = "INSERT INTO users (username, password, role, status)
VALUES (?, ?, ?, 'Aktif')";
$userId = insertAndGetId($pdo, $sqlUser, [$username,
$hashedPassword, $role]);
if ($userId) {
// Insert ke tabel detail berdasarkan role
if ($role == 'Admin') {
$sqlDetail = "INSERT INTO admin (idUser, namaAdmin, noHP)
VALUES (?, ?, ?)";
executeQuery($pdo, $sqlDetail, [$userId, $nama, $noHP]);
} elseif ($role == 'Manager') {
$sqlDetail = "INSERT INTO managerfbs (idUser, namaManager,
noHP) VALUES (?, ?, ?)";
executeQuery($pdo, $sqlDetail, [$userId, $nama, $noHP]);
} elseif ($role == 'Karyawan') {
$sqlDetail = "INSERT INTO karyawanfbs (idUser,
namaKaryawan, jenisKelamin, tanggalLahir, noHP, jabatan, pendidikan, Alamat,
tanggalMasuk, statusKerja)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
executeQuery($pdo, $sqlDetail, [
$userId, $nama, $jenisKelamin, $tanggalLahir,
$noHP, $jabatan, $pendidikan, $Alamat, $tanggalMasuk,
$statusKerja
]);
}
$pdo->commit();
$success = 'Registrasi berhasil! Silakan login dengan akun yang
telah dibuat.';
// membersihkan data POST untuk menghindari pengiriman ulang
$_POST = [];
} else {
$pdo->rollback();
$errors[] = 'Gagal membuat akun. Silakan coba lagi.';
}
} catch (Exception $e) {
$pdo->rollback();
$errors[] = 'Terjadi kesalahan sistem. Silakan coba lagi.';
error_log("Registration Error: " . $e->getMessage());
}
}
}
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registrasi - SPK Promosi Jabatan</title>
<!-- Bootstrap 5 CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet">
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/
all.min.css" rel="stylesheet">
<link rel="stylesheet" href="../assets/css/custom.css">
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8 col-xl-7">
<div class="register-container p-5">
<div class="text-center mb-4">
<i class="fas fa-user-plus fa-3x text-primary mb-3"></i>
<h2 class="fw-bold">Registrasi Akun</h2>
<p class="text-muted">Buat akun baru untuk mengakses
sistem</p>
</div>
<?php if (!empty($errors)): ?>
<div class="alert alert-danger alert-dismissible fade show"
role="alert">
<i class="fas fa-exclamation-triangle me-2"></i>
<ul class="mb-0">
<?php foreach ($errors as $error): ?>
<li><?= htmlspecialchars($error) ?></li>
<?php endforeach; ?>
</ul>
<button type="button" class="btn-close" data-bs-
dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success alert-dismissible fade
show" role="alert">
<i class="fas fa-check-circle me-2"></i>
<?= htmlspecialchars($success) ?>
<button type="button" class="btn-close" data-bs-
dismiss="alert"></button>
</div>
<?php endif; ?>
<form method="POST" action="" id="registerForm">
<input type="hidden" name="csrf_token" value="<?=
SessionManager::generateCSRF() ?>">
<div class="row">
<div class="col-md-6 mb-3">
<label for="username" class="form-label fw-
semibold">
<i class="fas fa-user me-2"></i>Username
</label>
<input type="text" class="form-control"
id="username" name="username"
placeholder="Masukkan username"
value="<?=
htmlspecialchars($_POST['username'] ?? '') ?>" required>
</div>
<div class="col-md-6 mb-3">
<label for="role" class="form-label fw-semibold">
<i class="fas fa-user-tag me-2"></i>Role
</label>
<select class="form-select" id="role" name="role"
onchange="toggleKaryawanFields()" required>
<option value="">Pilih Role</option>
<option value="Karyawan" <?= ($_POST['role'] ??
'') == 'Karyawan' ? 'selected' : '' ?>>Karyawan</option>
<option value="Manager" <?= ($_POST['role'] ??
'') == 'Manager' ? 'selected' : '' ?>>Manager</option>
<option value="Admin" <?= ($_POST['role'] ??
'') == 'Admin' ? 'selected' : '' ?>>Admin</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="password" class="form-label fw-
semibold">
<i class="fas fa-lock me-2"></i>Password
</label>
<div class="input-group">
<input type="password" class="form-control"
id="password" name="password"
placeholder="Masukkan password"
required>
<span class="input-group-text password-toggle"
onclick="togglePassword('password')">
<i class="fas fa-eye"
id="password-eye"></i>
</span>
</div>
</div>
<div class="col-md-6 mb-3">
<label for="confirm_password" class="form-label fw-
semibold">
<i class="fas fa-lock me-2"></i>Konfirmasi
Password
</label>
<div class="input-group">
<input type="password" class="form-control"
id="confirm_password" name="confirm_password"
placeholder="Konfirmasi password"
required>
<span class="input-group-text password-toggle"
onclick="togglePassword('confirm_password')">
<i class="fas fa-eye" id="confirm_password-
eye"></i>
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="nama" class="form-label fw-semibold">
<i class="fas fa-id-card me-2"></i>Nama Lengkap
</label>
<input type="text" class="form-control" id="nama"
name="nama"
placeholder="Masukkan nama lengkap"
value="<?=
htmlspecialchars($_POST['nama'] ?? '') ?>" required>
</div>
<div class="col-md-6 mb-3">
<label for="noHP" class="form-label fw-semibold">
<i class="fas fa-phone me-2"></i>No. HP
</label>
<input type="tel" class="form-control" id="noHP"
name="noHP"
placeholder="Masukkan nomor HP"
value="<?=
htmlspecialchars($_POST['noHP'] ?? '') ?>">
</div>
<div class="text-center mt-3">
<p class="mb-0">Sudah punya akun?
<a href="login.php" class="btn-link fw-
semibold">Login di sini</a>
</p>
</div>
</div>
<!-- Fields khusus untuk Karyawan -->
<div id="karyawan-fields" class="karyawan-fields">
<hr class="my-4">
<h5 class="text-primary mb-3">
<i class="fas fa-user-tie me-2"></i>Data Karyawan
</h5>
<div class="row">
<div class="col-md-6 mb-3">
<label for="jenisKelamin" class="form-label fw-
semibold">
<i class="fas fa-venus-mars me-2"></i>Jenis
Kelamin
</label>
<select class="form-select" id="jenisKelamin"
name="jenisKelamin">
<option value="">Pilih Jenis
Kelamin</option>
<option value="Laki-laki" <?=
($_POST['jenisKelamin'] ?? '') == 'Laki-laki' ? 'selected' : ''
?>>Laki-laki</option>
<option value="Perempuan" <?=
($_POST['jenisKelamin'] ?? '') == 'Perempuan' ? 'selected' : ''
?>>Perempuan</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="Alamat" class="form-label fw-semibold">
<i class="fas fa-id-card me-2"></i>Alamat
</label>
<input type="text" class="form-control" id="Alamat"
name="Alamat"
placeholder="Masukkan Alamat"
value="<?= htmlspecialchars($_POST['Alamat']
?? '') ?>" required>
</div>
<div class="col-md-6 mb-3">
<label for="tanggalLahir" class="form-label fw-
semibold">
<i class="fas fa-calendar me-2"></i>Tanggal
Lahir
</label>
<input type="date" class="form-control"
id="tanggalLahir" name="tanggalLahir"
value="<?=
htmlspecialchars($_POST['tanggalLahir'] ?? '') ?>">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="jabatan" class="form-label fw-
semibold">
<i class="fas fa-briefcase
me-2"></i>Jabatan
</label>
<select class="form-select" id="jabatan"
name="jabatan">
<option value="">Pilih Jabatan</option>
<option value="Waiter" <?=
($_POST['jabatan'] ?? '') == 'Waiter' ? 'selected' : '' ?>>Waiter</option>
<option value="Waitress" <?=
($_POST['jabatan'] ?? '') == 'Waitress' ? 'selected' : '' ?>>Waitress</option>
<option value="Captain" <?=
($_POST['jabatan'] ?? '') == 'Captain' ? 'selected' : '' ?>>Captain</option>
<option value="Assistant Restauran Manager"
<?= ($_POST['jabatan'] ?? '') == 'Assistant Restauran Manager' ? 'selected' : '' ?
>>Assistant Restauran Manager</option>
</select>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="pendidikan" class="form-label fw-
semibold">
<i class="fas fa-briefcase
me-2"></i>pendidikan
</label>
<select class="form-select" id="pendidikan"
name="pendidikan">
<option value="">Pilih pendidikan</option>
<option value="SMK/SMA" <?=
($_POST['pendidikan'] ?? '') == 'SMK/SMA' ? 'selected' : '' ?>>SMK/SMA</option>
<option value="Diploma 1" <?=
($_POST['pendidikan'] ?? '') == 'Diploma 1' ? 'selected' : '' ?>>Diploma 1</option>
<option value="Diploma 3" <?=
($_POST['pendidikan'] ?? '') == 'Diploma 3' ? 'selected' : '' ?>>Diploma 3</option>
<option value="Strata 1" <?=
($_POST['pendidikan'] ?? '') == 'Strata 1' ? 'selected' : '' ?>>Strata 1</option>
<option value="Strata 2" <?=
($_POST['pendidikan'] ?? '') == 'Strata 2' ? 'selected' : '' ?>>Strata 2</option>
</select>
</div>
<div class="col-md-6 mb-3">
<label for="tanggalMasuk" class="form-label fw-
semibold">
<i class="fas fa-calendar-plus
me-2"></i>Tanggal Masuk
</label>
<input type="date" class="form-control"
id="tanggalMasuk" name="tanggalMasuk"
value="<?=
htmlspecialchars($_POST['tanggalMasuk'] ?? '') ?>">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="statusKerja" class="form-label fw-
semibold">
<i class="fas fa-user-check
me-2"></i>Status Kerja
</label>
<select class="form-select" id="statusKerja"
name="statusKerja">
<option value="Aktif" <?=
($_POST['statusKerja'] ?? 'Aktif') == 'Aktif' ? 'selected' : '' ?>>Aktif</option>
<option value="Cuti" <?=
($_POST['statusKerja'] ?? '') == 'Cuti' ? 'selected' : '' ?>>Cuti</option>
<option value="Non-Aktif" <?=
($_POST['statusKerja'] ?? '') == 'Non-Aktif' ? 'selected' : ''
?>>Non-Aktif</option>
</select>
</div>
</div>
</div>
<div class="d-grid gap-2 mt-4">
<button type="submit" name="register" class="btn btn-
primary btn-register">
<i class="fas fa-user-plus me-2"></i>Daftar
Sekarang
</button>
</div>
<div class="text-center mt-3">
<p class="mb-0">Sudah punya akun?
<a href="login.php" class="btn-link fw-
semibold">Login di sini</a>
</p>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Bootstrap 5 JS -->
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js">
</script>
<script>
// fungsi untuk hide/show password
function togglePassword(fieldId) {
const field = document.getElementById(fieldId);
const eye = document.getElementById(fieldId + '-eye');
if (field.type === 'password') {
field.type = 'text';
eye.classList.remove('fa-eye');
eye.classList.add('fa-eye-slash');
} else {
field.type = 'password';
eye.classList.remove('fa-eye-slash');
eye.classList.add('fa-eye');
}
}
// fungsi untuk toggle fields khusus karyawan
function toggleKaryawanFields() {
const role = document.getElementById('role').value;
const karyawanFields = document.getElementById('karyawan-fields');
if (role === 'Karyawan') {
karyawanFields.style.display = 'block';
//atribut yang diperlukan untuk karyawan
document.getElementById('jenisKelamin').required = true;
document.getElementById('tanggalLahir').required = true;
document.getElementById('jabatan').required = true;
document.getElementById('tanggalMasuk').required = true;
} else {
karyawanFields.style.display = 'none';
// hapus atribut yang diperlukan
document.getElementById('jenisKelamin').required = false;
document.getElementById('tanggalLahir').required = false;
document.getElementById('jabatan').required = false;
document.getElementById('tanggalMasuk').required = false;
}
}
// inisialisasi tampilan karyawan fields
document.addEventListener('DOMContentLoaded', function() {
toggleKaryawanFields();
// set maks date untuk tanggal lahir dan tanggal masuk
// agar tidak bisa memilih tanggal di masa depan
const today = new Date().toISOString().split('T')[0];
document.getElementById('tanggalLahir').max = today;
document.getElementById('tanggalMasuk').max = today;
});
// Form validation
document.getElementById('registerForm').addEventListener('submit',
function(e) {
const password = document.getElementById('password').value;
const confirmPassword =
document.getElementById('confirm_password').value;
if (password !== confirmPassword) {
e.preventDefault();
alert('Password dan konfirmasi password tidak sama!');
return false;
}
if (password.length < 6) {
e.preventDefault();
alert('Password minimal 6 karakter!');
return false;
}
});
</script>
</body>
</html>
//source-code file: /includes/header.php :
<?php
// Tentukan base path berdasarkan lokasi file saat ini
$currentPath = $_SERVER['PHP_SELF'];
$basePath = '';
// Jika di dalam folder dashboard/admin, base path adalah ../../
if (strpos($currentPath, '/dashboard/admin/') !== false) {
$basePath = '../../';
} elseif (strpos($currentPath, '/dashboard/manager/') !== false) {
$basePath = '../../';
} elseif (strpos($currentPath, '/dashboard/karyawan/') !== false) {
$basePath = '../../';
}
// Tentukan apakah ini halaman login atau register
$isLoginPage = (strpos($currentPath, 'login.php') !== false);
$isRegisterPage = (strpos($currentPath, 'register.php') !== false ||
strpos($currentPath, 'registrasi.php') !== false);
$bodyClass = '';
if ($isLoginPage) {
$bodyClass = 'login-page';
} elseif ($isRegisterPage) {
$bodyClass = 'register-page';
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Aplikasi SPK FBS</title>
<!-- Bootstrap CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet">
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/
all.min.css" rel="stylesheet">
<!-- Custom CSS -->
<link href="<?= $basePath ?>assets/css/custom.css" rel="stylesheet">
</head>
<body<?= !empty($bodyClass) ? ' class="' . $bodyClass . '"' : '' ?>>
<?php if (!$isLoginPage && !$isRegisterPage): ?>
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container-fluid">
<a class="navbar-brand" href="<?= $basePath ?>index.php">
<img src="<?= $basePath ?>assets/img/logo.jpg" alt="Logo"
height="30" class="d-inline-block align-text-top me-2">
SPK Promosi Jabatan Departemen FBS <i><b>Le-Polonia </b></i> Hotel
Medan
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<a>
<i class="fas fa-user me-1"></i>
<?= isset($_SESSION['nama']) ?
htmlspecialchars($_SESSION['nama']) : 'User' ?> |
</a>
<a href="<?= $basePath ?>auth/logout.php">
<i class="fas fa-sign-out-alt me-1" style="color:
black;"></i> Logout
</a>
</ul>
</div>
</div>
</nav>
<?php endif; ?>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js">
</script>
//source-code file: /includes/sidebar.php :
<?php
// Tentukan current page untuk active menu
$currentPage = basename($_SERVER['PHP_SELF']);
// Cek apakah ini halaman login atau register
$currentPath = $_SERVER['PHP_SELF'];
$isLoginPage = (strpos($currentPath, 'login.php') !== false);
$isRegisterPage = (strpos($currentPath, 'register.php') !== false ||
strpos($currentPath, 'registrasi.php') !== false);
// Jangan tampilkan sidebar untuk halaman login dan register
if (!$isLoginPage && !$isRegisterPage):
?>
<div class="d-flex">
<nav id="sidebar" class="bg-light border-end shadow-sm">
<div class="p-3">
<h6 class="text-muted text-uppercase fw-bold mb-3">Menu <?=
ucfirst($_SESSION['role']) ?></h6>
</div>
<div class="list-group list-group-flush">
<?php if($_SESSION['role'] === 'Admin'): ?>
<a href="index.php" class="list-group-item list-group-item-action
<?= $currentPage == 'index.php' ? 'active' : '' ?>">
<i class="fas fa-tachometer-alt me-2"></i> Dashboard Admin
</a>
<a href="users.php" class="list-group-item list-group-item-action
<?= $currentPage == 'users.php' ? 'active' : '' ?>">
<i class="fas fa-users me-2"></i> Pengguna
</a>
<a href="kriteria.php" class="list-group-item list-group-item-
action <?= $currentPage == 'kriteria.php' ? 'active' : '' ?>">
<i class="fas fa-list me-2"></i> Kriteria
</a>
<a href="subkriteria.php" class="list-group-item list-group-item-
action <?= $currentPage == 'subkriteria.php' ? 'active' : '' ?>">
<i class="fas fa-list-ul me-2"></i> Subkriteria
</a>
<a href="penilaian.php" class="list-group-item list-group-item-
action <?= $currentPage == 'penilaian.php' ? 'active' : '' ?>">
<i class="fas fa-star me-2"></i> Penilaian
</a>
<a href="analisis.php" class="list-group-item list-group-item-
action <?= $currentPage == 'analisis.php' ? 'active' : '' ?>">
<i class="fas fa-chart-line me-2"></i> Analisis
</a>
<?php elseif($_SESSION['role'] === 'Manager'): ?>
<a href="index.php" class="list-group-item list-group-item-action
<?= $currentPage == 'index.php' ? 'active' : '' ?>">
<i class="fas fa-tachometer-alt me-2"></i> Dashboard Manager
</a>
<a href="karyawan.php" class="list-group-item list-group-item-
action <?= $currentPage == 'karyawan.php' ? 'active' : '' ?>">
<i class="fas fa-users me-2"></i> Karyawan
</a>
<a href="kriteria.php" class="list-group-item list-
group-item-action <?= $currentPage == 'kriteria.php' ? 'active' : '' ?>">
<i class="fas fa-list me-2"></i> Kriteria
</a>
<a href="subkriteria.php" class="list-group-item list-group-item-
action <?= $currentPage == 'subkriteria.php' ? 'active' : '' ?>">
<i class="fas fa-list-ul me-2"></i> Subkriteria
</a>
<a href="penilaian.php" class="list-group-item list-group-item-
action <?= $currentPage == 'penilaian.php' ? 'active' : '' ?>">
<i class="fas fa-star me-2"></i> Penilaian
</a>
<a href="analisis.php" class="list-group-item list-group-item-
action <?= $currentPage == 'analisis.php' ? 'active' : '' ?>">
<i class="fas fa-chart-line me-2"></i> Analisis
</a>
<?php else: ?>
<a href="index.php" class="list-group-item list-group-item-action
<?= $currentPage == 'index.php' ? 'active' : '' ?>">
<i class="fas fa-tachometer-alt me-2"></i> Dashboard Karyawan
</a>
<a href="profil.php" class="list-group-item list-group-item-action
<?= $currentPage == 'profil.php' ? 'active' : '' ?>">
<i class="fas fa-user me-2"></i> Profil
</a>
<a href="riwayat.php" class="list-group-item list-group-item-action
<?= $currentPage == 'riwayat.php' ? 'active' : '' ?>">
<i class="fas fa-history me-2"></i> Riwayat hasil perangkingan
</a>
<?php endif; ?>
</div>
</nav>
<?php endif; ?>
//source-code file: /includes/footer.php :
<?php
// Cek apakah ini halaman login atau register
$currentPath = $_SERVER['PHP_SELF'];
$isLoginPage = (strpos($currentPath, 'login.php') !== false);
$isRegisterPage = (strpos($currentPath, 'register.php') !== false ||
strpos($currentPath, 'registrasi.php') !== false);
// Tutup div flex container jika bukan halaman login/register
if (!$isLoginPage && !$isRegisterPage):
?>
</div> <!-- End of d-flex from sidebar -->
<?php endif; ?>
<!-- Footer -->
<?php if (!$isLoginPage && !$isRegisterPage): ?>
<footer class="bg-light mt-auto py-3">
<div class="container-fluid">
<div class="row">
<div class="col-12 text-center">
<small class="text-muted">
© <?= date('Y') ?> Hotel Le Polonia - SPK Promosi
Jabatan FBS
</small>
</div>
</div>
</div>
</footer>
<?php endif; ?>
<!-- Bootstrap JS Bundle -->
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js">
</script>
<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Custom JS -->
<script src="<?= isset($basePath) ? $basePath : '../../'
?>assets/js/custom.js"></script>
</body>
</html>
//source-code file: /dashboard/admin/index.php :<?php
// Start session terlebih dahulu
require_once __DIR__ . '/../../config/session.php';
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../../includes/functions.php';
// Pastikan hanya Admin yang dapat mengakses
SessionManager::requireRole('Admin' );
// Ambil data sesi pengguna
$user = SessionManager::getUserData();
// Query untuk statistik dinamis dengan nama tabel yang benar
$db = Database::getInstance()->getConnection();
try {
// Gunakan nama tabel yang sesuai dengan database Anda
$totalPengguna = $db->query("SELECT COUNT(*) FROM users WHERE status =
'Aktif'")->fetchColumn();
$totalKriteria = $db->query("SELECT COUNT(*) FROM kriteria WHERE status =
'Aktif'")->fetchColumn();
$totalKaryawan = $db->query("SELECT COUNT(*) FROM karyawanfbs WHERE statusKerja
= 'Aktif'")->fetchColumn();
$totalAnalisis = $db->query("SELECT COUNT(*) FROM hasilspk")->fetchColumn();
} catch (Exception $e) {
// Jika terjadi error, set nilai default
$totalPengguna = 0;
$totalKriteria = 0;
$totalKaryawan = 0;
$totalAnalisis = 0;
}
?>
<?php include __DIR__ . '/../../includes/header.php'; ?>
<?php include __DIR__ . '/../../includes/sidebar.php'; ?>
<main class="content">
<div class="container-fluid p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="mb-0">Dashboard Admin</h1>
<div class="text-muted">
<i class="fas fa-calendar-alt me-1"></i>
<?= date('d F Y') ?>
</div>
</div>
<div class="card mb-4">
<div class="card-body">
<h5 class="card-title">
<i class="fas fa-user-shield me-2 text-primary"></i>
Selamat datang, <?= htmlspecialchars($user['nama']); ?>!
</h5>
<p class="card-text">Anda memiliki akses penuh untuk mengelola
sistem SPK promosi jabatan karyawan departemen FBS.</p>
</div>
</div>
<!-- Widget Statistik -->
<div class="row mb-4">
<div class="col-lg-3 col-md-6 mb-3">
<div class="card text-white bg-primary h-100">
<div class="card-body d-flex justify-content-between align-
items-center">
<div>
<h5 class="card-title mb-1 text-white">Total
Pengguna</h5>
<p class="card-text display-6 mb-0 text-white fw-
bold"><?= $totalPengguna ?></p>
</div>
<i class="fas fa-users fa-2x" style="opacity: 0.75; color:
rgba(255,255,255,0.75);"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<div class="card text-white bg-success h-100">
<div class="card-body d-flex justify-content-between align-
items-center">
<div>
<h5 class="card-title mb-1 text-white">Total
Kriteria</h5>
<p class="card-text display-6 mb-0 text-white fw-
bold"><?= $totalKriteria ?></p>
</div>
<i class="fas fa-list fa-2x" style="opacity: 0.75; color:
rgba(255,255,255,0.75);"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<div class="card text-white bg-warning h-100">
<div class="card-body d-flex justify-content-between align-
items-center">
<div>
<h5 class="card-title mb-1 text-white">Total
Karyawan</h5>
<p class="card-text display-6 mb-0 text-white fw-
bold"><?= $totalKaryawan ?></p>
</div>
<i class="fas fa-user-tie fa-2x" style="opacity: 0.75;
color: rgba(255,255,255,0.75);"></i>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<div class="card text-white bg-info h-100">
<div class="card-body d-flex justify-content-between align-
items-center">
<div>
<h5 class="card-title mb-1 text-white">Total
Analisis</h5>
<p class="card-text display-6 mb-0 text-white fw-
bold"><?= $totalAnalisis ?></p>
</div>
<i class="fas fa-chart-line fa-2x" style="opacity: 0.75;
color: rgba(255,255,255,0.75);"></i>
</div>
</div>
</div>
</div>
<!-- Grafik Statistik -->
<div class="row mb-4">
<div class="col-md-6 mb-3">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-chart-bar me-2"></i>
Grafik Batang
</h5>
</div>
<div class="card-body">
<canvas id="barChart" height="300"></canvas>
</div>
</div>
</div>
<div class="col-md-6 mb-3">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-chart-pie me-2"></i>
Grafik Pie
</h5>
</div>
<div class="card-body">
<canvas id="pieChart" height="300"></canvas>
</div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-bolt me-2"></i>
Aksi Cepat
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-lg-3 col-md-6 mb-3">
<a href="users.php" class="btn btn-outline-primary w-100">
<i class="fas fa-users me-2"></i>
Kelola Pengguna
</a>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<a href="kriteria.php" class="btn btn-outline-success w-
100">
<i class="fas fa-list me-2"></i>
Kelola Kriteria
</a>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<a href="analisis.php" class="btn btn-outline-warning w-
100">
<i class="fas fa-chart-line me-2"></i>
Analisis SPK
</a>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<a href="laporan.php" class="btn btn-outline-info w-100">
<i class="fas fa-file-alt me-2"></i>
Lihat Laporan
</a>
</div>
</div>
</div>
</div>
</div>
</main>
<script>
// Render Charts
document.addEventListener('DOMContentLoaded', function() {
// Bar Chart
const barCtx = document.getElementById('barChart').getContext('2d');
new Chart(barCtx, {
type: 'bar',
data: {
labels: ['Pengguna', 'Kriteria', 'Karyawan', 'Analisis'],
datasets: [{
label: 'Jumlah',
data: [<?= $totalPengguna ?>, <?= $totalKriteria ?>, <?=
$totalKaryawan ?>, <?= $totalAnalisis ?>],
backgroundColor: [
'rgba(13, 110, 253, 0.8)',
'rgba(25, 135, 84, 0.8)',
'rgba(255, 193, 7, 0.8)',
'rgba(13, 202, 240, 0.8)'
],
borderColor: [
'rgba(13, 110, 253, 1)',
'rgba(25, 135, 84, 1)',
'rgba(255, 193, 7, 1)',
'rgba(13, 202, 240, 1)'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
// Pie Chart
const pieCtx = document.getElementById('pieChart').getContext('2d');
new Chart(pieCtx, {
type: 'pie',
data: {
labels: ['Pengguna', 'Kriteria', 'Karyawan', 'Analisis'],
datasets: [{
data: [<?= $totalPengguna ?>, <?= $totalKriteria ?>, <?=
$totalKaryawan ?>, <?= $totalAnalisis ?>],
backgroundColor: [
'rgba(13, 110, 253, 0.8)',
'rgba(25, 135, 84, 0.8)',
'rgba(255, 193, 7, 0.8)',
'rgba(13, 202, 240, 0.8)'
],
borderColor: '#fff',
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom'
}
}
}
});
});
</script>
<?php include __DIR__ . '/../../includes/footer.php'; ?>
//source-code file: /dashboard/admin/kriteia.php :
<?php
require_once __DIR__ . '/../../config/session.php';
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../../includes/functions.php';
SessionManager::requireRole('Admin');
$db = Database::getInstance()->getConnection();
// Menangani berbagai aksi CRUD
$action = $_GET['action'] ?? 'list';
$id = $_GET['id'] ?? null;
$message = '';
$messageType = '';
// CRUD Operations
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
if (isset($_POST['create_kriteria'])) {
// CREATE KRITERIA
$namaKriteria = $_POST['namaKriteria'];
$bobot = $_POST['bobot'];
$jenisKriteria = $_POST['jenisKriteria'];
$status = $_POST['status'];
// Validasi total bobot tidak melebihi 1.00
$stmt = $db->prepare("SELECT SUM(bobot) as totalBobot FROM kriteria
WHERE status = 'Aktif' AND idKriteria != ?");
$stmt->execute([0]); // 0 karena ini create baru
$totalBobot = $stmt->fetch(PDO::FETCH_ASSOC)['totalBobot'] ?? 0;
if (($totalBobot + $bobot) > 1.00) {
throw new Exception("Total bobot kriteria tidak boleh melebihi
1.00. Sisa bobot yang tersedia: " . (1.00 - $totalBobot));
}
// Insert ke tabel kriteria
$stmt = $db->prepare("INSERT INTO kriteria (namaKriteria, bobot,
jenisKriteria, status, created_at) VALUES (?, ?, ?, ?, NOW())");
$stmt->execute([$namaKriteria, $bobot, $jenisKriteria, $status]);
$message = "Kriteria berhasil ditambahkan!";
$messageType = "success";
} elseif (isset($_POST['update_kriteria'])) {
// UPDATE KRITERIA
$kriteriaId = $_POST['kriteria_id'];
$namaKriteria = $_POST['namaKriteria'];
$bobot = $_POST['bobot'];
$jenisKriteria = $_POST['jenisKriteria'];
$status = $_POST['status'];
// Validasi total bobot tidak melebihi 1.00 (kecuali kriteria yang
sedang di-update)
$stmt = $db->prepare("SELECT SUM(bobot) as totalBobot FROM kriteria
WHERE status = 'Aktif' AND idKriteria != ?");
$stmt->execute([$kriteriaId]);
$totalBobot = $stmt->fetch(PDO::FETCH_ASSOC)['totalBobot'] ?? 0;
if (($totalBobot + $bobot) > 1.00) {
throw new Exception("Total bobot kriteria tidak boleh melebihi
1.00. Sisa bobot yang tersedia: " . (1.00 - $totalBobot));
}
// Update tabel kriteria
$stmt = $db->prepare("UPDATE kriteria SET namaKriteria = ?, bobot = ?,
jenisKriteria = ?, status = ? WHERE idKriteria = ?");
$stmt->execute([$namaKriteria, $bobot, $jenisKriteria, $status,
$kriteriaId]);
$message = "Kriteria berhasil diupdate!";
$messageType = "success";
} elseif (isset($_POST['delete_kriteria'])) {
// DELETE KRITERIA
$kriteriaId = $_POST['kriteria_id'];
// Cek apakah kriteria sudah digunakan dalam penilaian
$stmt = $db->prepare("SELECT COUNT(*) as jumlah FROM penilaiankaryawan
WHERE idKriteria = ?");
$stmt->execute([$kriteriaId]);
$jumlahPenilaian = $stmt->fetch(PDO::FETCH_ASSOC)['jumlah'];
if ($jumlahPenilaian > 0) {
throw new Exception("Kriteria tidak dapat dihapus karena sudah
digunakan dalam " . $jumlahPenilaian . " penilaian karyawan.");
}
// Hapus sub kriteria terlebih dahulu
$db->prepare("DELETE FROM subkriteria WHERE idKriteria = ?")-
>execute([$kriteriaId]);
// Hapus kriteria
$stmt = $db->prepare("DELETE FROM kriteria WHERE idKriteria = ?");
$stmt->execute([$kriteriaId]);
$message = "Kriteria berhasil dihapus!";
$messageType = "success";
}
} catch (Exception $e) {
$message = "Error: " . $e->getMessage();
$messageType = "danger";
}
}
// Ambil data kriteria untuk edit jika diperlukan
$editKriteria = null;
if ($action === 'edit' && $id) {
$stmt = $db->prepare("SELECT * FROM kriteria WHERE idKriteria = ?");
$stmt->execute([$id]);
$editKriteria = $stmt->fetch(PDO::FETCH_ASSOC);
}
// Ambil semua data kriteria untuk tampilan list
$kriteria = $db->query("SELECT k.*,
(SELECT COUNT(*) FROM subkriteria s WHERE
s.idKriteria = k.idKriteria) as jumlahSubKriteria,
(SELECT COUNT(*) FROM penilaiankaryawan p WHERE
p.idKriteria = k.idKriteria) as jumlahPenilaian
FROM kriteria k
ORDER BY k.bobot DESC")->fetchAll(PDO::FETCH_ASSOC);
// Hitung total bobot kriteria aktif
$totalBobotAktif = $db->query("SELECT SUM(bobot) as total FROM kriteria WHERE
status = 'Aktif'")->fetch(PDO::FETCH_ASSOC)['total'] ?? 0;
?>
<?php include __DIR__ . '/../../includes/header.php'; ?>
<?php include __DIR__ . '/../../includes/sidebar.php'; ?>
<main class="content p-4">
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1><i class="fas fa-chart-line me-2"></i>Kelola Kriteria SPK</h1>
<div>
<?php if ($action !== 'create' && $action !== 'edit'): ?>
<a href="?action=create" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>Tambah Kriteria
</a>
<?php endif; ?>
<?php if ($action === 'create' || $action === 'edit'): ?>
<a href="?" class="btn btn-secondary">
<i class="fas fa-arrow-left me-1"></i>Kembali
</a>
<?php endif; ?>
</div>
</div>
<!-- Alert Total Bobot -->
<?php if ($action === 'list'): ?>
<div class="alert alert-<?= $totalBobotAktif == 1.00 ? 'success' :
($totalBobotAktif < 1.00 ? 'warning' : 'danger') ?>" role="alert">
<i class="fas fa-info-circle me-2"></i>
<strong>Total Bobot Kriteria Aktif: <?= number_format($totalBobotAktif,
2) ?></strong>
<?php if ($totalBobotAktif == 1.00): ?>
- Bobot sudah seimbang dan siap digunakan untuk analisis SPK.
<?php elseif ($totalBobotAktif < 1.00): ?>
- Masih tersisa <?= number_format(1.00 - $totalBobotAktif, 2) ?>
bobot yang dapat dialokasikan.
<?php else: ?>
- Total bobot melebihi 1.00! Silakan sesuaikan bobot kriteria.
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Alert Messages -->
<?php if ($message): ?>
<div class="alert alert-<?= $messageType ?> alert-dismissible fade show"
role="alert">
<?= $message ?>
<button type="button" class="btn-close"
data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if ($action === 'create' || $action === 'edit'): ?>
<!-- FORM CREATE/EDIT -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-<?= $action === 'create' ? 'plus' : 'edit' ?>
me-2"></i>
<?= $action === 'create' ? 'Tambah' : 'Edit' ?> Kriteria
</h5>
</div>
<div class="card-body">
<form method="POST">
<?php if ($action === 'edit'): ?>
<input type="hidden" name="kriteria_id" value="<?=
$editKriteria['idKriteria'] ?>">
<?php endif; ?>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Nama Kriteria *</label>
<input type="text" class="form-control"
name="namaKriteria"
value="<?=
htmlspecialchars($editKriteria['namaKriteria'] ?? '') ?>"
placeholder="Contoh: Masa Kerja, Kemampuan
Komunikasi" required>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Bobot Kriteria *</label>
<div class="input-group">
<input type="number" class="form-control"
name="bobot"
value="<?= $editKriteria['bobot'] ??
'' ?>"
step="0.01" min="0.01" max="1.00"
placeholder="0.00" required>
<span class="input-group-text">
<small>Max: 1.00</small>
</span>
</div>
<small class="form-text text-muted">
Total bobot semua kriteria aktif harus = 1.00
<?php if ($action === 'create'): ?>
(Sisa: <?= number_format(1.00 -
$totalBobotAktif, 2) ?>)
<?php endif; ?>
</small>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Jenis Kriteria *</label>
<select class="form-select" name="jenisKriteria"
required>
<option value="">Pilih Jenis Kriteria</option>
<option value="Benefit" <?=
($editKriteria['jenisKriteria'] ?? '') === 'Benefit' ? 'selected' : '' ?>>
Benefit (Semakin tinggi semakin baik)
</option>
<option value="Cost" <?=
($editKriteria['jenisKriteria'] ?? '') === 'Cost' ? 'selected' : '' ?>>
Cost (Semakin rendah semakin baik)
</option>
</select>
<small class="form-text text-muted">
<strong>Benefit:</strong> Nilai tinggi lebih
diinginkan (misal: Pengalaman kerja)<br>
<strong>Cost:</strong> Nilai rendah lebih
diinginkan (misal: Jumlah pelanggaran)
</small>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Status *</label>
<select class="form-select" name="status" required>
<option value="Aktif" <?=
($editKriteria['status'] ?? 'Aktif') === 'Aktif' ? 'selected' : ''
?>>Aktif</option>
<option value="Non-Aktif" <?=
($editKriteria['status'] ?? '') === 'Non-Aktif' ? 'selected' : ''
?>>Non-Aktif</option>
</select>
<small class="form-text text-muted">
Hanya kriteria dengan status "Aktif" yang akan
digunakan dalam perhitungan SPK
</small>
</div>
</div>
</div>
<div class="mt-4">
<button type="submit" name="<?= $action === 'create' ?
'create_kriteria' : 'update_kriteria' ?>"
class="btn btn-<?= $action === 'create' ? 'primary'
: 'warning' ?>">
<i class="fas fa-save me-1"></i>
<?= $action === 'create' ? 'Simpan' : 'Update' ?>
</button>
<a href="?" class="btn btn-secondary ms-2">
<i class="fas fa-times me-1"></i>Batal
</a>
</div>
</form>
</div>
</div>
<?php else: ?>
<!-- TABEL LIST KRITERIA -->
<div class="card">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-list me-2"></i>Daftar Kriteria
SPK</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered"
id="kriteriaTable">
<thead class="table-dark">
<tr>
<th width="5%">#</th>
<th>Nama Kriteria</th>
<th width="10%">Bobot</th>
<th width="10%">Jenis</th>
<th width="8%">Status</th>
<th width="12%">Sub Kriteria</th>
<th width="12%">Penilaian</th>
<th width="12%">Tanggal</th>
<th width="15%">Aksi</th>
</tr>
</thead>
<tbody>
<?php foreach($kriteria as $index => $item): ?>
<tr>
<td><?= $index + 1 ?></td>
<td>
<strong><?=
htmlspecialchars($item['namaKriteria']) ?></strong>
<?php if ($item['status'] === 'Aktif'): ?>
<span class="badge bg-success ms-
2">Aktif</span>
<?php endif; ?>
</td>
<td>
<span class="badge bg-primary fs-6">
<?= number_format($item['bobot'], 2) ?>
</span>
</td>
<td>
<span class="badge bg-<?=
$item['jenisKriteria'] === 'Benefit' ? 'success' : 'warning' ?>">
<?= $item['jenisKriteria'] ?>
</span>
</td>
<td>
<span class="badge bg-<?= $item['status'] ===
'Aktif' ? 'success' : 'secondary' ?>">
<?= $item['status'] ?>
</span>
</td>
<td>
<span class="badge bg-info">
<?= $item['jumlahSubKriteria'] ?> Sub
</span>
<?php if ($item['jumlahSubKriteria'] > 0): ?>
<a href="../admin/subkriteria.php?
kriteria=<?= $item['idKriteria'] ?>"
class="btn btn-sm btn-outline-info ms-1"
title="Kelola Sub Kriteria">
<i class="fas fa-list"></i>
</a>
<?php endif; ?>
</td>
<td>
<?php if ($item['jumlahPenilaian'] > 0): ?>
<span class="badge bg-warning">
<?= $item['jumlahPenilaian'] ?> Data
</span>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
<td><?= date('d/m/Y',
strtotime($item['created_at'])) ?></td>
<td>
<div class="btn-group" role="group">
<a href="?action=edit&id=<?=
$item['idKriteria'] ?>"
class="btn btn-sm btn-warning"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<a href="../admin/subkriteria.php?
kriteria=<?= $item['idKriteria'] ?>"
class="btn btn-sm btn-info" title="Sub
Kriteria">
<i class="fas fa-list"></i>
</a>
<button type="button" class="btn btn-sm
btn-danger"
onclick="deleteKriteria(<?=
$item['idKriteria'] ?>, '<?= htmlspecialchars($item['namaKriteria']) ?>', <?=
$item['jumlahPenilaian'] ?>)"
title="Hapus"
<?= $item['jumlahPenilaian'] > 0 ?
'disabled' : '' ?>>
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php endif; ?>
</div>
</main>
<!-- Modal Konfirmasi Hapus -->
<div class="modal fade" id="deleteModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Konfirmasi Hapus</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Apakah Anda yakin ingin menghapus kriteria <strong
id="deleteKriteriaName"></strong>?</p>
<div id="deleteWarning" class="alert alert-warning" style="display:
none;">
<i class="fas fa-exclamation-triangle me-2"></i>
Kriteria ini sudah digunakan dalam <span
id="jumlahPenilaianText"></span> penilaian dan tidak dapat dihapus!
</div>
<p class="text-danger"><small>Tindakan ini akan menghapus semua sub
kriteria yang terkait dan tidak dapat dibatalkan!</small></p>
</div>
<div class="modal-footer">
<form method="POST" id="deleteForm">
<input type="hidden" name="kriteria_id" id="deleteKriteriaId">
<button type="button" class="btn btn-secondary" data-bs-
dismiss="modal">Batal</button>
<button type="submit" name="delete_kriteria" class="btn btn-
danger" id="confirmDeleteBtn">Hapus</button>
</form>
</div>
</div>
</div>
</div>
<script>
// Delete kriteria function
function deleteKriteria(kriteriaId, kriteriaName, jumlahPenilaian) {
document.getElementById('deleteKriteriaId').value = kriteriaId;
document.getElementById('deleteKriteriaName').textContent = kriteriaName;
const deleteWarning = document.getElementById('deleteWarning');
const confirmDeleteBtn = document.getElementById('confirmDeleteBtn');
if (jumlahPenilaian > 0) {
deleteWarning.style.display = 'block';
document.getElementById('jumlahPenilaianText').textContent =
jumlahPenilaian + ' penilaian';
confirmDeleteBtn.disabled = true;
confirmDeleteBtn.textContent = 'Tidak Dapat Dihapus';
} else {
deleteWarning.style.display = 'none';
confirmDeleteBtn.disabled = false;
confirmDeleteBtn.textContent = 'Hapus';
}
new bootstrap.Modal(document.getElementById('deleteModal')).show();
}
// Initialize DataTable if available
$(document).ready(function() {
if ($.fn.DataTable) {
$('#kriteriaTable').DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.10.24/i18n/Indonesian.json"
},
"pageLength": 10,
"order": [[2, "desc"]], // Sort by bobot descending
"columnDefs": [
{ "orderable": false, "targets": [8] } // Disable sorting on Action
column
]
});
}
});
// Form validation for bobot
document.addEventListener('DOMContentLoaded', function() {
const bobotInput = document.querySelector('input[name="bobot"]');
if (bobotInput) {
bobotInput.addEventListener('input', function() {
const value = parseFloat(this.value);
if (value > 1.00) {
this.setCustomValidity('Bobot tidak boleh lebih dari 1.00');
} else if (value <= 0) {
this.setCustomValidity('Bobot harus lebih dari 0');
} else {
this.setCustomValidity('');
}
});
}
});
</script>
<?php include __DIR__ . '/../../includes/footer.php'; ?>
//source-code file: /dashboard/admin/subkriteria.php :
<?php
require_once __DIR__ . '/../../config/session.php';
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../../includes/functions.php';
SessionManager::requireRole('Admin');
$db = Database::getInstance()->getConnection();
// Menangani berbagai aksi CRUD
$action = $_GET['action'] ?? 'list';
$id = $_GET['id'] ?? null;
$kriteriaId = $_GET['kriteria'] ?? null;
$message = '';
$messageType = '';
// Ambil data kriteria yang dipilih
$selectedKriteria = null;
if ($kriteriaId) {
$stmt = $db->prepare("SELECT * FROM kriteria WHERE idKriteria = ?");
$stmt->execute([$kriteriaId]);
$selectedKriteria = $stmt->fetch(PDO::FETCH_ASSOC);
}
// CRUD Operations
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
if (isset($_POST['create_subkriteria'])) {
// CREATE SUBKRITERIA
$idKriteria = $_POST['idKriteria'];
$namaSubKriteria = $_POST['namaSubKriteria'];
$nilaiSkor = $_POST['nilaiSkor'];
$deskripsi = $_POST['deskripsi'];
// Validasi bahwa nilai skor belum digunakan untuk kriteria yang sama
$stmt = $db->prepare("SELECT COUNT(*) as jumlah FROM subkriteria WHERE
idKriteria = ? AND nilaiSkor = ?");
$stmt->execute([$idKriteria, $nilaiSkor]);
$jumlahSkorSama = $stmt->fetch(PDO::FETCH_ASSOC)['jumlah'];
if ($jumlahSkorSama > 0) {
throw new Exception("Nilai skor $nilaiSkor sudah digunakan untuk
kriteria ini. Silakan pilih nilai skor yang berbeda.");
}
// Insert ke tabel subkriteria
$stmt = $db->prepare("INSERT INTO subkriteria (idKriteria,
namaSubKriteria, nilaiSkor, deskripsi) VALUES (?, ?, ?, ?)");
$stmt->execute([$idKriteria, $namaSubKriteria, $nilaiSkor,
$deskripsi]);
$message = "Sub kriteria berhasil ditambahkan!";
$messageType = "success";
} elseif (isset($_POST['update_subkriteria'])) {
// UPDATE SUBKRITERIA
$subKriteriaId = $_POST['subkriteria_id'];
$idKriteria = $_POST['idKriteria'];
$namaSubKriteria = $_POST['namaSubKriteria'];
$nilaiSkor = $_POST['nilaiSkor'];
$deskripsi = $_POST['deskripsi'];
// Validasi bahwa nilai skor belum digunakan untuk kriteria yang sama
(kecuali yang sedang di-update)
$stmt = $db->prepare("SELECT COUNT(*) as jumlah FROM subkriteria WHERE
idKriteria = ? AND nilaiSkor = ? AND idSubKriteria != ?");
$stmt->execute([$idKriteria, $nilaiSkor, $subKriteriaId]);
$jumlahSkorSama = $stmt->fetch(PDO::FETCH_ASSOC)['jumlah'];
if ($jumlahSkorSama > 0) {
throw new Exception("Nilai skor $nilaiSkor sudah digunakan untuk
kriteria ini. Silakan pilih nilai skor yang berbeda.");
}
// Update tabel subkriteria
$stmt = $db->prepare("UPDATE subkriteria SET idKriteria = ?,
namaSubKriteria = ?, nilaiSkor = ?, deskripsi = ? WHERE idSubKriteria = ?");
$stmt->execute([$idKriteria, $namaSubKriteria, $nilaiSkor, $deskripsi,
$subKriteriaId]);
$message = "Sub kriteria berhasil diupdate!";
$messageType = "success";
} elseif (isset($_POST['delete_subkriteria'])) {
// DELETE SUBKRITERIA
$subKriteriaId = $_POST['subkriteria_id'];
// Cek apakah sub kriteria sudah digunakan dalam penilaian
$stmt = $db->prepare("SELECT COUNT(*) as jumlah FROM penilaiankaryawan
WHERE idSubKriteria = ?");
$stmt->execute([$subKriteriaId]);
$jumlahPenilaian = $stmt->fetch(PDO::FETCH_ASSOC)['jumlah'];
if ($jumlahPenilaian > 0) {
throw new Exception("Sub kriteria tidak dapat dihapus karena sudah
digunakan dalam " . $jumlahPenilaian . " penilaian karyawan.");
}
// Hapus sub kriteria
$stmt = $db->prepare("DELETE FROM subkriteria WHERE idSubKriteria
= ?");
$stmt->execute([$subKriteriaId]);
$message = "Sub kriteria berhasil dihapus!";
$messageType = "success";
}
} catch (Exception $e) {
$message = "Error: " . $e->getMessage();
$messageType = "danger";
}
}
// Ambil data sub kriteria untuk edit jika diperlukan
$editSubKriteria = null;
if ($action === 'edit' && $id) {
$stmt = $db->prepare("SELECT s.*, k.namaKriteria FROM subkriteria s
INNER JOIN kriteria k ON s.idKriteria = k.idKriteria
WHERE s.idSubKriteria = ?");
$stmt->execute([$id]);
$editSubKriteria = $stmt->fetch(PDO::FETCH_ASSOC);
if ($editSubKriteria) {
$kriteriaId = $editSubKriteria['idKriteria'];
$selectedKriteria = ['idKriteria' => $editSubKriteria['idKriteria'],
'namaKriteria' => $editSubKriteria['namaKriteria']];
}
}
// Ambil semua data kriteria untuk dropdown
$kriteriaList = $db->query("SELECT idKriteria, namaKriteria, status FROM kriteria
ORDER BY namaKriteria")->fetchAll(PDO::FETCH_ASSOC);
// Ambil data sub kriteria berdasarkan kriteria yang dipilih atau semua jika tidak
ada filter
$subKriteriaQuery = "SELECT s.*, k.namaKriteria, k.status as statusKriteria,
(SELECT COUNT(*) FROM penilaiankaryawan p WHERE
p.idSubKriteria = s.idSubKriteria) as jumlahPenilaian
FROM subkriteria s
INNER JOIN kriteria k ON s.idKriteria = k.idKriteria";
if ($kriteriaId) {
$subKriteriaQuery .= " WHERE s.idKriteria = ?";
$stmt = $db->prepare($subKriteriaQuery . " ORDER BY s.nilaiSkor ASC");
$stmt->execute([$kriteriaId]);
} else {
$stmt = $db->prepare($subKriteriaQuery . " ORDER BY k.namaKriteria, s.nilaiSkor
ASC");
$stmt->execute();
}
$subKriteria = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Hitung statistik sub kriteria jika ada kriteria yang dipilih
$statistik = null;
if ($kriteriaId) {
$stmt = $db->prepare("SELECT
COUNT(*) as totalSubKriteria,
MIN(nilaiSkor) as minSkor,
MAX(nilaiSkor) as maxSkor,
AVG(nilaiSkor) as avgSkor
FROM subkriteria WHERE idKriteria = ?");
$stmt->execute([$kriteriaId]);
$statistik = $stmt->fetch(PDO::FETCH_ASSOC);
}
?>
<?php include __DIR__ . '/../../includes/header.php'; ?>
<?php include __DIR__ . '/../../includes/sidebar.php'; ?>
<main class="content p-4">
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1>
<i class="fas fa-sitemap me-2"></i>Kelola Sub Kriteria SPK
<?php if ($selectedKriteria): ?>
<small class="text-muted">- <?=
htmlspecialchars($selectedKriteria['namaKriteria']) ?></small>
<?php endif; ?>
</h1>
<div>
<?php if ($action !== 'create' && $action !== 'edit'): ?>
<a href="?action=create<?= $kriteriaId ? '&kriteria=' . $kriteriaId
: '' ?>" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>Tambah Sub Kriteria
</a>
<?php endif; ?>
<?php if ($action === 'create' || $action === 'edit'): ?>
<a href="?<?= $kriteriaId ? 'kriteria=' . $kriteriaId : '' ?>"
class="btn btn-secondary">
<i class="fas fa-arrow-left me-1"></i>Kembali
</a>
<?php endif; ?>
<a href="kriteria.php" class="btn btn-outline-secondary">
<i class="fas fa-chart-line me-1"></i>Kelola Kriteria
</a>
</div>
</div>
<!-- Filter Kriteria -->
<?php if ($action === 'list'): ?>
<div class="card mb-4">
<div class="card-body">
<div class="row align-items-end">
<div class="col-md-6">
<label class="form-label">Filter berdasarkan
Kriteria:</label>
<select class="form-select" id="filterKriteria"
onchange="filterByKriteria()">
<option value="">-- Semua Kriteria --</option>
<?php foreach($kriteriaList as $kriteria): ?>
<option value="<?= $kriteria['idKriteria'] ?>"
<?= $kriteriaId == $kriteria['idKriteria'] ?
'selected' : '' ?>>
<?= htmlspecialchars($kriteria['namaKriteria']) ?>
<?php if ($kriteria['status'] === 'Non-Aktif'): ?>
(Non-Aktif)
<?php endif; ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<?php if ($selectedKriteria && $statistik): ?>
<div class="row">
<div class="col-6">
<small class="text-muted">Total Sub
Kriteria:</small>
<div class="h5 mb-0"><?=
$statistik['totalSubKriteria'] ?></div>
</div>
<div class="col-6">
<small class="text-muted">Range Skor:</small>
<div class="h5 mb-0"><?= $statistik['minSkor'] ?> -
<?= $statistik['maxSkor'] ?></div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php endif; ?>
<!-- Alert Messages -->
<?php if ($message): ?>
<div class="alert alert-<?= $messageType ?> alert-dismissible fade show"
role="alert">
<?= $message ?>
<button type="button" class="btn-close"
data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if ($action === 'create' || $action === 'edit'): ?>
<!-- FORM CREATE/EDIT -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-<?= $action === 'create' ? 'plus' : 'edit' ?>
me-2"></i>
<?= $action === 'create' ? 'Tambah' : 'Edit' ?> Sub Kriteria
</h5>
</div>
<div class="card-body">
<form method="POST">
<?php if ($action === 'edit'): ?>
<input type="hidden" name="subkriteria_id" value="<?=
$editSubKriteria['idSubKriteria'] ?>">
<?php endif; ?>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Kriteria Induk *</label>
<select class="form-select" name="idKriteria"
required>
<option value="">Pilih Kriteria</option>
<?php foreach($kriteriaList as $kriteria): ?>
<option value="<?= $kriteria['idKriteria'] ?>"
<?= ($editSubKriteria['idKriteria'] ??
$kriteriaId) == $kriteria['idKriteria'] ? 'selected' : '' ?>>
<?=
htmlspecialchars($kriteria['namaKriteria']) ?>
<?php if ($kriteria['status'] === 'Non-
Aktif'): ?>
(Non-Aktif)
<?php endif; ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Nilai Skor *</label>
<input type="number" class="form-control"
name="nilaiSkor"
value="<?= $editSubKriteria['nilaiSkor'] ??
'' ?>"
min="1" max="10"
placeholder="1-10" required>
<small class="form-text text-muted">
Nilai skor harus unik untuk setiap kriteria
(rentang 1-10)
</small>
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Nama Sub Kriteria *</label>
<input type="text" class="form-control"
name="namaSubKriteria"
value="<?=
htmlspecialchars($editSubKriteria['namaSubKriteria'] ?? '') ?>"
placeholder="Contoh: Sangat Baik, Baik, Cukup,
Kurang" required>
</div>
<div class="mb-3">
<label class="form-label">Deskripsi</label>
<textarea class="form-control" name="deskripsi" rows="3"
placeholder="Deskripsi detail mengenai sub
kriteria ini..."><?= htmlspecialchars($editSubKriteria['deskripsi'] ?? '')
?></textarea>
<small class="form-text text-muted">
Berikan penjelasan yang jelas agar memudahkan proses
penilaian
</small>
</div>
<div class="mt-4">
<button type="submit" name="<?= $action === 'create' ?
'create_subkriteria' : 'update_subkriteria' ?>"
class="btn btn-<?= $action === 'create' ? 'primary'
: 'warning' ?>">
<i class="fas fa-save me-1"></i>
<?= $action === 'create' ? 'Simpan' : 'Update' ?>
</button>
<a href="?<?= $kriteriaId ? 'kriteria=' . $kriteriaId :
'' ?>" class="btn btn-secondary ms-2">
<i class="fas fa-times me-1"></i>Batal
</a>
</div>
</form>
</div>
</div>
<?php else: ?>
<!-- TABEL LIST SUB KRITERIA -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-list me-2"></i>Daftar Sub Kriteria SPK
<?php if ($selectedKriteria): ?>
<span class="badge bg-primary ms-2"><?= count($subKriteria)
?> item</span>
<?php endif; ?>
</h5>
</div>
<div class="card-body">
<?php if (empty($subKriteria)): ?>
<div class="text-center py-5">
<i class="fas fa-inbox fa-3x text-muted mb-3"></i>
<h5 class="text-muted">Belum ada data sub kriteria</h5>
<p class="text-muted">
<?php if ($kriteriaId): ?>
Belum ada sub kriteria untuk kriteria "<?=
htmlspecialchars($selectedKriteria['namaKriteria']) ?>"
<?php else: ?>
Silakan tambah sub kriteria terlebih dahulu atau pilih
kriteria untuk melihat data
<?php endif; ?>
</p>
<a href="?action=create<?= $kriteriaId ? '&kriteria=' .
$kriteriaId : '' ?>" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>Tambah Sub Kriteria
</a>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-striped table-bordered"
id="subKriteriaTable">
<thead class="table-dark">
<tr>
<th width="5%">#</th>
<?php if (!$kriteriaId): ?>
<th>Kriteria</th>
<?php endif; ?>
<th>Nama Sub Kriteria</th>
<th width="10%">Skor</th>
<th>Deskripsi</th>
<th width="10%">Penilaian</th>
<th width="15%">Aksi</th>
</tr>
</thead>
<tbody>
<?php foreach($subKriteria as $index => $item): ?>
<tr>
<td><?= $index + 1 ?></td>
<?php if (!$kriteriaId): ?>
<td>
<strong><?=
htmlspecialchars($item['namaKriteria']) ?></strong>
<?php if ($item['statusKriteria'] === 'Non-
Aktif'): ?>
<span class="badge bg-secondary ms-1">Non-
Aktif</span>
<?php endif; ?>
</td>
<?php endif; ?>
<td>
<strong><?=
htmlspecialchars($item['namaSubKriteria']) ?></strong>
</td>
<td>
<span class="badge bg-primary fs-6">
<?= $item['nilaiSkor'] ?>
</span>
</td>
<td>
<?php if ($item['deskripsi']): ?>
<span title="<?=
htmlspecialchars($item['deskripsi']) ?>">
<?=
htmlspecialchars(substr($item['deskripsi'], 0, 50)) ?>
<?= strlen($item['deskripsi']) > 50 ?
'...' : '' ?>
</span>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
<td>
<?php if ($item['jumlahPenilaian'] > 0): ?>
<span class="badge bg-warning">
<?= $item['jumlahPenilaian'] ?> Data
</span>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
<td>
<div class="btn-group" role="group">
<a href="?action=edit&id=<?=
$item['idSubKriteria'] ?>"
class="btn btn-sm btn-warning"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-sm
btn-danger"
onclick="deleteSubKriteria(<?=
$item['idSubKriteria'] ?>, '<?= htmlspecialchars($item['namaSubKriteria']) ?>', <?=
$item['jumlahPenilaian'] ?>)"
title="Hapus"
<?= $item['jumlahPenilaian'] > 0 ?
'disabled' : '' ?>>
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
</div>
</main>
<!-- Modal Konfirmasi Hapus -->
<div class="modal fade" id="deleteModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Konfirmasi Hapus</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Apakah Anda yakin ingin menghapus sub kriteria <strong
id="deleteSubKriteriaName"></strong>?</p>
<div id="deleteWarning" class="alert alert-warning" style="display:
none;">
<i class="fas fa-exclamation-triangle me-2"></i>
Sub kriteria ini sudah digunakan dalam <span
id="jumlahPenilaianText"></span> penilaian dan tidak dapat dihapus!
</div>
<p class="text-danger"><small>Tindakan ini tidak dapat dibatalkan!
</small></p>
</div>
<div class="modal-footer">
<form method="POST" id="deleteForm">
<input type="hidden" name="subkriteria_id"
id="deleteSubKriteriaId">
<button type="button" class="btn btn-secondary" data-bs-
dismiss="modal">Batal</button>
<button type="submit" name="delete_subkriteria" class="btn btn-
danger" id="confirmDeleteBtn">Hapus</button>
</form>
</div>
</div>
</div>
</div>
<script>
// Filter by kriteria function
function filterByKriteria() {
const kriteriaId = document.getElementById('filterKriteria').value;
if (kriteriaId) {
window.location.href = '?kriteria=' + kriteriaId;
} else {
window.location.href = '?';
}
}
// Delete sub kriteria function
function deleteSubKriteria(subKriteriaId, subKriteriaName, jumlahPenilaian) {
document.getElementById('deleteSubKriteriaId').value = subKriteriaId;
document.getElementById('deleteSubKriteriaName').textContent = subKriteriaName;
const deleteWarning = document.getElementById('deleteWarning');
const confirmDeleteBtn = document.getElementById('confirmDeleteBtn');
if (jumlahPenilaian > 0) {
deleteWarning.style.display = 'block';
document.getElementById('jumlahPenilaianText').textContent =
jumlahPenilaian + ' penilaian';
confirmDeleteBtn.disabled = true;
confirmDeleteBtn.textContent = 'Tidak Dapat Dihapus';
} else {
deleteWarning.style.display = 'none';
confirmDeleteBtn.disabled = false;
confirmDeleteBtn.textContent = 'Hapus';
}
new bootstrap.Modal(document.getElementById('deleteModal')).show();
}
// Initialize DataTable if available
$(document).ready(function() {
if ($.fn.DataTable) {
$('#subKriteriaTable').DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.10.24/i18n/Indonesian.json"
},
"pageLength": 10,
"order": [[<?= !$kriteriaId ? '2' : '1' ?>, "asc"]], // Sort by nama
sub kriteria ascending
"columnDefs": [
{ "orderable": false, "targets": [-1] } // Disable sorting on
Action column
]
});
}
});
// Form validation for nilai skor
document.addEventListener('DOMContentLoaded', function() {
const skorInput = document.querySelector('input[name="nilaiSkor"]');
if (skorInput) {
skorInput.addEventListener('input', function() {
const value = parseInt(this.value);
if (value > 10) {
this.setCustomValidity('Nilai skor tidak boleh lebih dari 10');
} else if (value < 1) {
this.setCustomValidity('Nilai skor harus minimal 1');
} else {
this.setCustomValidity('');
}
});
}
});
</script>
<?php include __DIR__ . '/../../includes/footer.php'; ?>
//source-code file: /dashboard/admin/users.php : <?php
require_once __DIR__ . '/../../config/session.php';
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../../includes/functions.php';
SessionManager::requireRole('Admin');
$db = Database::getInstance()->getConnection();
// Menangani berbagai aksi CRUD
$action = $_GET['action'] ?? 'list';
$id = $_GET['id'] ?? null;
$message = '';
$messageType = '';
// CRUD Operations
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
if (isset($_POST['create_user'])) {
// CREATE USER
$username = $_POST['username'];
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$role = $_POST['role'];
$status = $_POST['status'];
// Insert ke tabel users
$stmt = $db->prepare("INSERT INTO users (username, password, role,
status, created_at, updated_at) VALUES (?, ?, ?, ?, NOW(), NOW())");
$stmt->execute([$username, $password, $role, $status]);
$userId = $db->lastInsertId();
// Insert ke tabel role-specific berdasarkan role
switch ($role) {
case 'Admin':
$stmt = $db->prepare("INSERT INTO admin (idUser, namaAdmin,
noHP) VALUES (?, ?, ?)");
$stmt->execute([$userId, $_POST['nama'], $_POST['noHP'] ??
null]);
break;
case 'Manager':
$stmt = $db->prepare("INSERT INTO managerfbs (idUser,
namaManager, noHP) VALUES (?, ?, ?)");
$stmt->execute([$userId, $_POST['nama'], $_POST['noHP'] ??
null]);
break;
case 'Karyawan':
// Perbaiki query INSERT - pastikan jumlah kolom sesuai dengan
nilai
$stmt = $db->prepare("INSERT INTO karyawanfbs (idUser,
namaKaryawan, jenisKelamin, tanggalLahir, noHP, jabatan, pendidikan, tanggalMasuk,
Alamat, statusKerja) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([
$userId,
$_POST['nama'],
$_POST['jenisKelamin'] ?? 'Laki-laki',
$_POST['tanggalLahir'] ?? null,
$_POST['noHP'] ?? null,
$_POST['jabatan'] ?? 'Waiter', // Ambil hanya 1 nilai
$_POST['pendidikan'] ?? 'SMK/SMA', // Ambil hanya 1 nilai
$_POST['tanggalMasuk'] ?? date('Y-m-d'),
$_POST['Alamat'] ?? null, // Tambahkan null check
$_POST['statusKerja'] ?? 'Aktif'
]);
break;
}
$message = "User berhasil ditambahkan!";
$messageType = "success";
} elseif (isset($_POST['update_user'])) {
// UPDATE USER
$userId = $_POST['user_id'];
$username = $_POST['username'];
$role = $_POST['role'];
$status = $_POST['status'];
// Update tabel users
if (!empty($_POST['password'])) {
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$stmt = $db->prepare("UPDATE users SET username = ?, password = ?,
role = ?, status = ?, updated_at = NOW() WHERE idUser = ?");
$stmt->execute([$username, $password, $role, $status, $userId]);
} else {
$stmt = $db->prepare("UPDATE users SET username = ?, role = ?,
status = ?, updated_at = NOW() WHERE idUser = ?");
$stmt->execute([$username, $role, $status, $userId]);
}
// Update tabel role-specific
switch ($role) {
case 'Admin':
$stmt = $db->prepare("UPDATE admin SET namaAdmin = ?, noHP = ?
WHERE idUser = ?");
$stmt->execute([$_POST['nama'], $_POST['noHP'] ?? null,
$userId]);
break;
case 'Manager':
$stmt = $db->prepare("UPDATE managerfbs SET namaManager = ?,
noHP = ? WHERE idUser = ?");
$stmt->execute([$_POST['nama'], $_POST['noHP'] ?? null,
$userId]);
break;
case 'Karyawan':
// Sesuaikan dengan struktur tabel karyawanfbs yang sebenarnya
$stmt = $db->prepare("UPDATE karyawanfbs SET namaKaryawan = ?,
jenisKelamin = ?, tanggalLahir = ?, noHP = ?, jabatan = ?, pendidikan = ?,
tanggalMasuk = ?, Alamat = ?, statusKerja = ? WHERE idUser = ?");
$stmt->execute([
$_POST['nama'],
$_POST['jenisKelamin'] ?? 'Laki-laki',
$_POST['tanggalLahir'] ?? null,
$_POST['noHP'] ?? null,
$_POST['jabatan'] ?? 'Waiter', // Ambil dari form, bukan
hardcoded
$_POST['pendidikan'] ?? 'SMK/SMA',
$_POST['tanggalMasuk'] ?? date('Y-m-d'),
$_POST['Alamat'] ?? null,
$_POST['statusKerja'] ?? 'Aktif',
$userId
]);
break;
}
$message = "User berhasil diupdate!";
$messageType = "success";
} elseif (isset($_POST['delete_user'])) {
// DELETE USER
$userId = $_POST['user_id'];
// Hapus dari tabel role-specific terlebih dahulu
$db->prepare("DELETE FROM admin WHERE idUser = ?")->execute([$userId]);
$db->prepare("DELETE FROM managerfbs WHERE idUser = ?")-
>execute([$userId]);
$db->prepare("DELETE FROM karyawanfbs WHERE idUser = ?")-
>execute([$userId]);
// Hapus dari tabel users
$stmt = $db->prepare("DELETE FROM users WHERE idUser = ?");
$stmt->execute([$userId]);
$message = "User berhasil dihapus!";
$messageType = "success";
}
} catch (Exception $e) {
$message = "Error: " . $e->getMessage();
$messageType = "danger";
}
}
// Ambil data user untuk edit jika diperlukan
$editUser = null;
if ($action === 'edit' && $id) {
$stmt = $db->prepare("SELECT u.*,
a.namaAdmin, a.noHP as adminHP,
m.namaManager, m.noHP as managerHP,
k.namaKaryawan, k.jenisKelamin, k.tanggalLahir, k.noHP
as karyawanHP,
k.jabatan, k.pendidikan, k.tanggalMasuk, k.Alamat,
k.statusKerja as karyawanStatus
FROM users u
LEFT JOIN admin a ON u.idUser = a.idUser
LEFT JOIN managerfbs m ON u.idUser = m.idUser
LEFT JOIN karyawanfbs k ON u.idUser = k.idUser
WHERE u.idUser = ?");
$stmt->execute([$id]);
$editUser = $stmt->fetch(PDO::FETCH_ASSOC);
}
// Ambil semua data users untuk tampilan list
$users = $db->query("SELECT u.idUser, u.username, u.role, u.status, u.created_at,
u.updated_at,
a.namaAdmin, a.noHP as adminHP,
m.namaManager, m.noHP as managerHP,
k.namaKaryawan, k.jenisKelamin, k.tanggalLahir, k.noHP
as karyawanHP,
k.jabatan, k.pendidikan, k.tanggalMasuk, k.Alamat,
k.statusKerja as karyawanStatus
FROM users u
LEFT JOIN admin a ON u.idUser = a.idUser
LEFT JOIN managerfbs m ON u.idUser = m.idUser
LEFT JOIN karyawanfbs k ON u.idUser = k.idUser
ORDER BY u.username")->fetchAll(PDO::FETCH_ASSOC);
?>
<?php include __DIR__ . '/../../includes/header.php'; ?>
<?php include __DIR__ . '/../../includes/sidebar.php'; ?>
<main class="content p-4">
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1><i class="fas fa-users me-2"></i>Kelola Pengguna</h1>
<div>
<?php if ($action !== 'create' && $action !== 'edit'): ?>
<a href="?action=create" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>Tambah Pengguna
</a>
<?php endif; ?>
<?php if ($action === 'create' || $action === 'edit'): ?>
<a href="?" class="btn btn-secondary">
<i class="fas fa-arrow-left me-1"></i>Kembali
</a>
<?php endif; ?>
</div>
</div>
<!-- Alert Messages -->
<?php if ($message): ?>
<div class="alert alert-<?= $messageType ?> alert-dismissible fade show"
role="alert">
<?= $message ?>
<button type="button" class="btn-close"
data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if ($action === 'create' || $action === 'edit'): ?>
<!-- FORM CREATE/EDIT -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-<?= $action === 'create' ? 'plus' : 'edit' ?>
me-2"></i>
<?= $action === 'create' ? 'Tambah' : 'Edit' ?> Pengguna
</h5>
</div>
<div class="card-body">
<form method="POST">
<?php if ($action === 'edit'): ?>
<input type="hidden" name="user_id" value="<?=
$editUser['idUser'] ?>">
<?php endif; ?>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Username *</label>
<input type="text" class="form-control"
name="username"
value="<?= $editUser['username'] ?? '' ?>"
required>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Password <?= $action ===
'edit' ? '(kosongkan jika tidak diubah)' : '*' ?></label>
<input type="password" class="form-control"
name="password"
<?= $action === 'create' ? 'required' : '' ?
>>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Role *</label>
<select class="form-select" name="role" required
onchange="toggleRoleFields(this.value)">
<option value="">Pilih Role</option>
<option value="Admin" <?= ($editUser['role'] ??
'') === 'Admin' ? 'selected' : '' ?>>Admin</option>
<option value="Manager" <?=
($editUser['role'] ?? '') === 'Manager' ? 'selected' : '' ?>>Manager</option>
<option value="Karyawan" <?= ($editUser['role']
?? '') === 'Karyawan' ? 'selected' : '' ?>>Karyawan</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Status *</label>
<select class="form-select" name="status" required>
<option value="Aktif" <?=
($editUser['status'] ?? '') === 'Aktif' ? 'selected' : '' ?>>Aktif</option>
<option value="Non-Aktif" <?=
($editUser['status'] ?? '') === 'Non-Aktif' ? 'selected' : '' ?>>Non-Aktif</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Nama *</label>
<input type="text" class="form-control" name="nama"
value="<?= $editUser['namaAdmin'] ??
$editUser['namaManager'] ?? $editUser['namaKaryawan'] ?? '' ?>" required>
</div>
</div>
<div class="col-md-6" id="noHP-field">
<div class="mb-3">
<label class="form-label">No. HP</label>
<input type="text" class="form-control" name="noHP"
value="<?= $editUser['adminHP'] ??
$editUser['managerHP'] ?? $editUser['karyawanHP'] ?? '' ?>">
</div>
</div>
</div>
<!-- Fields khusus untuk Karyawan -->
<div id="karyawan-fields" style="display: none;">
<hr>
<h6><i class="fas fa-user-tie me-2"></i>Informasi
Karyawan</h6>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Jenis Kelamin</label>
<select class="form-select"
name="jenisKelamin">
<option value="Laki-laki" <?=
($editUser['jenisKelamin'] ?? '') === 'Laki-laki' ? 'selected' : ''
?>>Laki-laki</option>
<option value="Perempuan" <?=
($editUser['jenisKelamin'] ?? '') === 'Perempuan' ? 'selected' : ''
?>>Perempuan</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Tanggal Lahir</label>
<input type="date" class="form-control"
name="tanggalLahir"
value="<?= $editUser['tanggalLahir'] ??
'' ?>">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Jabatan</label>
<select class="form-select" name="jabatan">
<option value="Waiter" <?=
($editUser['jabatan'] ?? '') === 'Waiter' ? 'selected' : '' ?>>Waiter</option>
<option value="Waitress" <?=
($editUser['jabatan'] ?? '') === 'Waitress' ? 'selected' : '' ?>>Waitress</option>
<option value="Captain" <?=
($editUser['jabatan'] ?? '') === 'Captain' ? 'selected' : '' ?>>Captain</option>
<option value="Assistant Restaurant
Manager" <?= ($editUser['jabatan'] ?? '') === 'Assistant Restaurant Manager' ?
'selected' : '' ?>>Assistant Restaurant Manager</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Tanggal Masuk
Kerja</label>
<input type="date" class="form-control"
name="tanggalMasuk"
value="<?= $editUser['tanggalMasuk'] ??
date('Y-m-d') ?>">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Pendidikan</label>
<select class="form-select" name="pendidikan">
<option value="SMK/SMA" <?=
($editUser['pendidikan'] ?? '') === 'SMK/SMA' ? 'selected' : '' ?>>SMK/SMA</option>
<option value="Diploma 1" <?=
($editUser['pendidikan'] ?? '') === 'Diploma 1' ? 'selected' : '' ?>>Diploma
1</option>
<option value="Diploma 3" <?=
($editUser['pendidikan'] ?? '') === 'Diploma 3' ? 'selected' : '' ?>>Diploma
3</option>
<option value="Strata 1" <?=
($editUser['pendidikan'] ?? '') === 'Strata 1' ? 'selected' : '' ?>>Strata
1</option>
<option value="Strata 2" <?=
($editUser['pendidikan'] ?? '') === 'Strata 2' ? 'selected' : '' ?>>Strata
2</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Alamat *</label>
<textarea class="form-control" name="Alamat"
rows="2" required><?= $editUser['Alamat'] ?? '' ?></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Status Kerja</label>
<select class="form-select" name="statusKerja">
<option value="Aktif" <?=
($editUser['karyawanStatus'] ?? '') === 'Aktif' ? 'selected' : '' ?>>Aktif</option>
<option value="Cuti" <?=
($editUser['karyawanStatus'] ?? '') === 'Cuti' ? 'selected' : '' ?>>Cuti</option>
<option value="Non-Aktif" <?=
($editUser['karyawanStatus'] ?? '') === 'Non-Aktif' ? 'selected' : '' ?>>Non-
Aktif</option>
</select>
</div>
</div>
</div>
</div>
<div class="mt-4">
<button type="submit" name="<?= $action === 'create' ?
'create_user' : 'update_user' ?>"
class="btn btn-<?= $action === 'create' ? 'primary'
: 'warning' ?>">
<i class="fas fa-save me-1"></i>
<?= $action === 'create' ? 'Simpan' : 'Update' ?>
</button>
<a href="?" class="btn btn-secondary ms-2">
<i class="fas fa-times me-1"></i>Batal
</a>
</div>
</form>
</div>
</div>
<?php else: ?>
<!-- TABEL LIST USERS -->
<div class="card">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-list me-2"></i>Daftar
Pengguna</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered"
id="usersTable">
<thead class="table-dark">
<tr>
<th width="5%">#</th>
<th>Username</th>
<th>Nama</th>
<th>Role</th>
<th>Status</th>
<th>Info Tambahan</th>
<th>Tanggal Dibuat</th>
<th width="15%">Aksi</th>
</tr>
</thead>
<tbody>
<?php foreach($users as $index => $user): ?>
<tr>
<td><?= $index + 1 ?></td>
<td><?= htmlspecialchars($user['username']) ?></td>
<td><?= htmlspecialchars($user['namaAdmin'] ??
$user['namaManager'] ?? $user['namaKaryawan'] ?? '-') ?></td>
<td>
<span class="badge bg-<?= $user['role'] ===
'Admin' ? 'danger' : ($user['role'] === 'Manager' ? 'warning' : 'info') ?>">
<?= htmlspecialchars($user['role']) ?>
</span>
</td>
<td>
<span class="badge bg-<?= $user['status'] ===
'Aktif' ? 'success' : 'secondary' ?>">
<?= htmlspecialchars($user['status']) ?>
</span>
</td>
<td>
<?php if ($user['role'] === 'Karyawan'): ?>
<small>
<?= $user['jenisKelamin'] ? 'JK: ' .
$user['jenisKelamin'] : '' ?>
<?= $user['jabatan'] ? ', Jabatan: ' .
$user['jabatan'] : '' ?>
<?= $user['tanggalMasuk'] ? ', Masuk: '
. date('d/m/Y', strtotime($user['tanggalMasuk'])) : '' ?>
</small>
<?php else: ?>
<small><?= $user['adminHP'] ??
$user['managerHP'] ?? $user['karyawanHP'] ?? '-' ?></small>
<?php endif; ?>
</td>
<td><?= date('d/m/Y',
strtotime($user['created_at'])) ?></td>
<td>
<div class="btn-group" role="group">
<a href="?action=edit&id=<?=
$user['idUser'] ?>"
class="btn btn-sm btn-warning"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-sm
btn-danger"
onclick="deleteUser(<?=
$user['idUser'] ?>, '<?= htmlspecialchars($user['username']) ?>')"
title="Hapus">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php endif; ?>
</div>
</main>
<!-- Modal Konfirmasi Hapus -->
<div class="modal fade" id="deleteModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Konfirmasi Hapus</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Apakah Anda yakin ingin menghapus pengguna <strong
id="deleteUsername"></strong>?</p>
<p class="text-danger"><small>Tindakan ini tidak dapat dibatalkan!
</small></p>
</div>
<div class="modal-footer">
<form method="POST" id="deleteForm">
<input type="hidden" name="user_id" id="deleteUserId">
<button type="button" class="btn btn-secondary" data-bs-
dismiss="modal">Batal</button>
<button type="submit" name="delete_user" class="btn btn-
danger">Hapus</button>
</form>
</div>
</div>
</div>
</div>
<script>
// Toggle role-specific fields
function toggleRoleFields(role) {
const karyawanFields = document.getElementById('karyawan-fields');
const noHPField = document.getElementById('noHP-field');
if (role === 'Karyawan') {
karyawanFields.style.display = 'block';
noHPField.style.display = 'block'; // Karyawan juga punya noHP
} else {
karyawanFields.style.display = 'none';
noHPField.style.display = 'block';
}
}
// Initialize role fields on page load
document.addEventListener('DOMContentLoaded', function() {
const roleSelect = document.querySelector('select[name="role"]');
if (roleSelect && roleSelect.value) {
toggleRoleFields(roleSelect.value);
}
});
// Delete user function
function deleteUser(userId, username) {
document.getElementById('deleteUserId').value = userId;
document.getElementById('deleteUsername').textContent = username;
new bootstrap.Modal(document.getElementById('deleteModal')).show();
}
// Initialize DataTable if available
$(document).ready(function() {
if ($.fn.DataTable) {
$('#usersTable').DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.10.24/i18n/Indonesian.json"
},
"pageLength": 10,
"order": [[1, "asc"]]
});
}
});
</script>
<?php include __DIR__ . '/../../includes/footer.php'; ?>
//source-code file: /dashboard/admin/penilaian.php :
<?php
require_once __DIR__ . '/../../config/session.php';
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../../includes/functions.php';
SessionManager::requireRole('Admin');
$db = Database::getInstance()->getConnection();
// Menangani berbagai aksi CRUD
$action = $_GET['action'] ?? 'list';
$id = $_GET['id'] ?? null;
$message = '';
$messageType = '';
// CRUD Operations
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
if (isset($_POST['create_penilaian'])) {
// CREATE PENILAIAN
$idKaryawan = $_POST['idKaryawan'];
$tanggalPenilaian = $_POST['tanggalPenilaian'];
$catatan = $_POST['catatan'] ?? '';
$idPenilai = $_SESSION['user_id'];
// Validasi: cek apakah sudah ada penilaian untuk karyawan ini pada
tanggal yang sama
$stmt = $db->prepare("SELECT COUNT(*) as jumlah FROM penilaiankaryawan
WHERE idKaryawan = ? AND tanggalPenilaian = ?");
$stmt->execute([$idKaryawan, $tanggalPenilaian]);
$existingCount = $stmt->fetch(PDO::FETCH_ASSOC)['jumlah'];
if ($existingCount > 0) {
throw new Exception("Penilaian untuk karyawan ini pada tanggal
tersebut sudah ada. Silakan edit penilaian yang sudah ada atau pilih tanggal
lain.");
}
$db->beginTransaction();
// Simpan penilaian untuk setiap kriteria
$kriteria = $_POST['kriteria'] ?? [];
$insertedCount = 0;
foreach ($kriteria as $idKriteria => $idSubKriteria) {
if (!empty($idSubKriteria)) {
$stmt = $db->prepare("INSERT INTO penilaiankaryawan
(idKaryawan, idKriteria, idSubKriteria,
tanggalPenilaian, idPenilai, catatan)
VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$idKaryawan, $idKriteria, $idSubKriteria,
$tanggalPenilaian, $idPenilai, $catatan]);
$insertedCount++;
}
}
if ($insertedCount == 0) {
throw new Exception("Tidak ada kriteria yang dinilai. Minimal satu
kriteria harus diisi.");
}
$db->commit();
$message = "Penilaian berhasil disimpan untuk {$insertedCount}
kriteria!";
$messageType = "success";
// Log activity
SPKHelper::logActivity($db, $_SESSION['user_id'], 'CREATE_PENILAIAN',
"Menambah penilaian karyawan ID: {$idKaryawan}
untuk {$insertedCount} kriteria");
} elseif (isset($_POST['update_penilaian'])) {
// UPDATE PENILAIAN
$idKaryawan = $_POST['idKaryawan'];
$tanggalPenilaian = $_POST['tanggalPenilaian'];
$catatan = $_POST['catatan'] ?? '';
$idPenilai = $_SESSION['user_id'];
$db->beginTransaction();
// Hapus penilaian lama untuk karyawan dan tanggal ini
$stmt = $db->prepare("DELETE FROM penilaiankaryawan
WHERE idKaryawan = ? AND tanggalPenilaian = ?");
$stmt->execute([$idKaryawan, $tanggalPenilaian]);
// Simpan penilaian baru
$kriteria = $_POST['kriteria'] ?? [];
$insertedCount = 0;
foreach ($kriteria as $idKriteria => $idSubKriteria) {
if (!empty($idSubKriteria)) {
$stmt = $db->prepare("INSERT INTO penilaiankaryawan
(idKaryawan, idKriteria, idSubKriteria,
tanggalPenilaian, idPenilai, catatan)
VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$idKaryawan, $idKriteria, $idSubKriteria,
$tanggalPenilaian, $idPenilai, $catatan]);
$insertedCount++;
}
}
if ($insertedCount == 0) {
throw new Exception("Tidak ada kriteria yang dinilai. Minimal satu
kriteria harus diisi.");
}
$db->commit();
$message = "Penilaian berhasil diupdate untuk {$insertedCount}
kriteria!";
$messageType = "success";
} elseif (isset($_POST['delete_penilaian'])) {
// DELETE PENILAIAN
$idKaryawan = $_POST['idKaryawan'];
$tanggalPenilaian = $_POST['tanggalPenilaian'];
$stmt = $db->prepare("DELETE FROM penilaiankaryawan
WHERE idKaryawan = ? AND tanggalPenilaian = ?");
$stmt->execute([$idKaryawan, $tanggalPenilaian]);
$deletedCount = $stmt->rowCount();
$message = "Penilaian berhasil dihapus ({$deletedCount} kriteria)!";
$messageType = "success";
}
} catch (Exception $e) {
if ($db->inTransaction()) {
$db->rollback();
}
$message = "Error: " . $e->getMessage();
$messageType = "danger";
}
}
// Ambil data untuk form
$karyawanAktif = $db->query("SELECT idKaryawan, namaKaryawan, jabatan
FROM karyawanfbs WHERE statusKerja = 'Aktif'
ORDER BY namaKaryawan")->fetchAll(PDO::FETCH_ASSOC);
$kriteriaAktif = $db->query("SELECT idKriteria, namaKriteria, bobot, jenisKriteria
FROM kriteria WHERE status = 'Aktif'
ORDER BY bobot DESC")->fetchAll(PDO::FETCH_ASSOC);
// Ambil data penilaian untuk edit jika diperlukan
$editPenilaian = null;
$editSubKriteria = [];
if ($action === 'edit' && isset($_GET['karyawan']) && isset($_GET['tanggal'])) {
$idKaryawan = $_GET['karyawan'];
$tanggalPenilaian = $_GET['tanggal'];
$stmt = $db->prepare("SELECT p.*, k.namaKaryawan, kr.namaKriteria,
sk.namaSubKriteria
FROM penilaiankaryawan p
JOIN karyawanfbs k ON p.idKaryawan = k.idKaryawan
JOIN kriteria kr ON p.idKriteria = kr.idKriteria
JOIN subkriteria sk ON p.idSubKriteria = sk.idSubKriteria
WHERE p.idKaryawan = ? AND p.tanggalPenilaian = ?");
$stmt->execute([$idKaryawan, $tanggalPenilaian]);
$editPenilaian = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($editPenilaian) {
foreach ($editPenilaian as $penilaian) {
$editSubKriteria[$penilaian['idKriteria']] =
$penilaian['idSubKriteria'];
}
}
}
// Ambil semua data penilaian untuk tampilan list dengan pagination
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$limit = 10;
$offset = ($page - 1) * $limit;
$searchQuery = $_GET['search'] ?? '';
$whereClause = '';
$params = [];
if ($searchQuery) {
$whereClause = "WHERE k.namaKaryawan LIKE ? OR k.jabatan LIKE ?";
$params = ["%{$searchQuery}%", "%{$searchQuery}%"];
}
// Count total records
$countSql = "SELECT COUNT(DISTINCT CONCAT(p.idKaryawan, '-', p.tanggalPenilaian))
as total
FROM penilaiankaryawan p
JOIN karyawanfbs k ON p.idKaryawan = k.idKaryawan
{$whereClause}";
$totalStmt = $db->prepare($countSql);
$totalStmt->execute($params);
$totalRecords = $totalStmt->fetch(PDO::FETCH_ASSOC)['total'];
// Get paginated data
$sql = "SELECT p.idKaryawan, p.tanggalPenilaian, k.namaKaryawan, k.jabatan,
COUNT(p.idKriteria) as jumlahKriteria,
AVG(sk.nilaiSkor) as rataRataSkor,
MAX(p.tanggalPenilaian) as tanggalTerakhir,
p.idPenilai
FROM penilaiankaryawan p
JOIN karyawanfbs k ON p.idKaryawan = k.idKaryawan
JOIN subkriteria sk ON p.idSubKriteria = sk.idSubKriteria
{$whereClause}
GROUP BY p.idKaryawan, p.tanggalPenilaian
ORDER BY p.tanggalPenilaian DESC, k.namaKaryawan
LIMIT {$limit} OFFSET {$offset}";
$penilaianList = $db->prepare($sql);
$penilaianList->execute($params);
$penilaianList = $penilaianList->fetchAll(PDO::FETCH_ASSOC);
// Generate pagination menggunakan SPKHelper
$pagination = SPKHelper::paginate($page, $totalRecords, $limit);
// Build base URL dengan parameter search
$baseUrl = '?';
$urlParams = [];
if ($searchQuery) {
$urlParams[] = 'search=' . urlencode($searchQuery);
}
$baseUrl .= implode('&', $urlParams);
?>
<?php include __DIR__ . '/../../includes/header.php'; ?>
<?php include __DIR__ . '/../../includes/sidebar.php'; ?>
<main class="content p-4">
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1><i class="fas fa-clipboard-check me-2"></i>Kelola Penilaian
Karyawan</h1>
<div>
<?php if ($action !== 'create' && $action !== 'edit'): ?>
<a href="?action=create" class="btn btn-primary">
<i class="fas fa-plus me-1"></i>Tambah Penilaian
</a>
<?php endif; ?>
<?php if ($action === 'create' || $action === 'edit'): ?>
<a href="?" class="btn btn-secondary">
<i class="fas fa-arrow-left me-1"></i>Kembali
</a>
<?php endif; ?>
</div>
</div>
<!-- Alert Messages -->
<?php if ($message): ?>
<div class="alert alert-<?= $messageType ?> alert-dismissible fade show"
role="alert">
<?= $message ?>
<button type="button" class="btn-close"
data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if (empty($kriteriaAktif)): ?>
<div class="alert alert-warning" role="alert">
<i class="fas fa-exclamation-triangle me-2"></i>
<strong>Perhatian!</strong> Belum ada kriteria aktif. Silakan <a
href="kriteria.php">kelola kriteria</a> terlebih dahulu.
</div>
<?php endif; ?>
<?php if ($action === 'create' || $action === 'edit'): ?>
<!-- FORM CREATE/EDIT -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-<?= $action === 'create' ? 'plus' : 'edit' ?>
me-2"></i>
<?= $action === 'create' ? 'Tambah' : 'Edit' ?> Penilaian
Karyawan
</h5>
</div>
<div class="card-body">
<form method="POST" id="penilaianForm">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Pilih Karyawan *</label>
<select class="form-select" name="idKaryawan"
id="karyawanSelect" required
<?= $action === 'edit' ? 'disabled' : '' ?
>>
<option value="">Pilih Karyawan</option>
<?php foreach($karyawanAktif as $karyawan): ?>
<option value="<?= $karyawan['idKaryawan'] ?>"
<?= ($editPenilaian &&
$editPenilaian[0]['idKaryawan'] == $karyawan['idKaryawan']) ? 'selected' : '' ?>
data-jabatan="<?=
htmlspecialchars($karyawan['jabatan']) ?>">
<?=
htmlspecialchars($karyawan['namaKaryawan']) ?> - <?=
htmlspecialchars($karyawan['jabatan']) ?>
</option>
<?php endforeach; ?>
</select>
<?php if ($action === 'edit'): ?>
<input type="hidden" name="idKaryawan" value="<?=
$editPenilaian[0]['idKaryawan'] ?>">
<?php endif; ?>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Tanggal Penilaian
*</label>
<input type="date" class="form-control"
name="tanggalPenilaian"
value="<?= $editPenilaian ?
$editPenilaian[0]['tanggalPenilaian'] : date('Y-m-d') ?>"
max="<?= date('Y-m-d') ?>" required
<?= $action === 'edit' ? 'readonly' : '' ?>>
</div>
</div>
</div>
<!-- Info Karyawan Terpilih -->
<div id="karyawanInfo" class="alert alert-info" style="display:
none;">
<h6><i class="fas fa-user me-2"></i>Informasi Karyawan</h6>
<div class="row">
<div class="col-md-12">
<strong>Nama:</strong> <span
id="infoNama"></span><br>
<strong>Jabatan:</strong> <span
id="infoJabatan"></span>
</div>
</div>
</div>
<!-- Kriteria Penilaian -->
<div class="card mt-4">
<div class="card-header">
<h6 class="mb-0"><i class="fas fa-star
me-2"></i>Kriteria Penilaian</h6>
</div>
<div class="card-body">
<?php foreach($kriteriaAktif as $kriteria): ?>
<div class="mb-4 kriteria-section">
<div class="row align-items-center">
<div class="col-md-4">
<h6 class="mb-2">
<?=
htmlspecialchars($kriteria['namaKriteria']) ?>
<span class="badge bg-primary ms-
2">Bobot: <?= $kriteria['bobot'] ?></span>
</h6>
<small class="text-muted">
Jenis: <?= $kriteria['jenisKriteria'] ?
>
</small>
</div>
<div class="col-md-8">
<select class="form-select subkriteria-
select"
name="kriteria[<?=
$kriteria['idKriteria'] ?>]"
data-kriteria="<?=
$kriteria['idKriteria'] ?>"
required>
<option value="">Pilih Sub
Kriteria</option>
</select>
<div class="form-text">Pilih sub kriteria
yang sesuai dengan penilaian</div>
</div>
</div>
<hr class="my-3">
</div>
<?php endforeach; ?>
</div>
</div>
<!-- Preview Perhitungan -->
<div id="previewSection" class="card mt-4" style="display:
none;">
<div class="card-header">
<h6 class="mb-0"><i class="fas fa-calculator
me-2"></i>Preview Perhitungan</h6>
</div>
<div class="card-body">
<div id="previewContent">
<!-- Preview akan dimuat via AJAX -->
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Catatan (Opsional)</label>
<textarea class="form-control" name="catatan" rows="3"
placeholder="Tambahkan catatan atau keterangan
tambahan..."><?= $editPenilaian ? htmlspecialchars($editPenilaian[0]['catatan']) :
'' ?></textarea>
</div>
<div class="mt-4">
<button type="button" id="previewBtn" class="btn btn-info
me-2">
<i class="fas fa-eye me-1"></i>Preview Perhitungan
</button>
<button type="submit" name="<?= $action === 'create' ?
'create_penilaian' : 'update_penilaian' ?>"
class="btn btn-<?= $action === 'create' ? 'primary'
: 'warning' ?>">
<i class="fas fa-save me-1"></i>
<?= $action === 'create' ? 'Simpan' : 'Update' ?>
</button>
<a href="?" class="btn btn-secondary ms-2">
<i class="fas fa-times me-1"></i>Batal
</a>
</div>
</form>
</div>
</div>
<?php else: ?>
<!-- SEARCH & FILTER -->
<div class="card mb-4">
<div class="card-body">
<form method="GET" class="row g-3">
<div class="col-md-6">
<input type="text" class="form-control" name="search"
value="<?= htmlspecialchars($searchQuery) ?>"
placeholder="Cari berdasarkan nama karyawan atau
jabatan...">
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary">
<i class="fas fa-search me-1"></i>Cari
</button>
<a href="?" class="btn btn-secondary">Reset</a>
</div>
</form>
</div>
</div>
<!-- TABEL LIST PENILAIAN -->
<div class="card">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-list me-2"></i>Daftar Penilaian
Karyawan</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead class="table-dark">
<tr>
<th width="5%">#</th>
<th>Nama Karyawan</th>
<th>Jabatan</th>
<th width="12%">Tanggal</th>
<th width="10%">Kriteria</th>
<th width="10%">Rata-rata</th>
<th>Penilai</th>
<th width="15%">Aksi</th>
</tr>
</thead>
<tbody>
<?php if (empty($penilaianList)): ?>
<tr>
<td colspan="9" class="text-center text-muted">
<i class="fas fa-inbox fa-2x mb-2"></i><br>
Belum ada data penilaian
</td>
</tr>
<?php else: ?>
<?php foreach($penilaianList as $index => $item): ?>
<tr>
<td><?= $offset + $index + 1 ?></td>
<td>
<strong><?=
htmlspecialchars($item['namaKaryawan']) ?></strong>
</td>
<td><?= htmlspecialchars($item['jabatan']) ?></td>
<td><?= date('d/m/Y',
strtotime($item['tanggalPenilaian'])) ?></td>
<td>
<span class="badge bg-info">
<?= $item['jumlahKriteria'] ?>/<?=
count($kriteriaAktif) ?>
</span>
</td>
<td>
<span class="badge bg-<?= $item['rataRataSkor']
>= 3 ? 'success' : ($item['rataRataSkor'] >= 2 ? 'warning' : 'danger') ?>">
<?= number_format($item['rataRataSkor'], 2)
?>
</span>
</td>
<td><?= htmlspecialchars($item['idPenilai'])
?></td>
<td>
<div class="btn-group" role="group">
<a href="?action=edit&karyawan=<?=
$item['idKaryawan'] ?>&tanggal=<?= $item['tanggalPenilaian'] ?>"
class="btn btn-sm btn-warning"
title="Edit">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-sm
btn-info"
onclick="viewDetail(<?=
$item['idKaryawan'] ?>, '<?= $item['tanggalPenilaian'] ?>')"
title="Detail">
<i class="fas fa-eye"></i>
</button>
<button type="button" class="btn btn-sm
btn-danger"
onclick="deletePenilaian(<?=
$item['idKaryawan'] ?>, '<?= $item['tanggalPenilaian'] ?>', '<?=
htmlspecialchars($item['namaKaryawan']) ?>')"
title="Hapus">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<?php if ($pagination['total_pages'] > 1): ?>
<div class="mt-3">
<?= SPKHelper::generatePaginationHTML($pagination,
$baseUrl) ?>
<!-- Info pagination -->
<div class="text-center mt-2">
<small class="text-muted">
Menampilkan <?= min($pagination['offset'] + 1,
$totalRecords) ?> - <?= min($pagination['offset'] + $limit, $totalRecords) ?>
dari <?= $totalRecords ?> data (Halaman <?=
$pagination['current_page'] ?> dari <?= $pagination['total_pages'] ?>)
</small>
</div>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
</div>
</main>
<!-- Modal Detail Penilaian -->
<div class="modal fade" id="detailModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Detail Penilaian</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="detailContent">
<!-- Detail akan dimuat via AJAX -->
</div>
</div>
</div>
</div>
<!-- Modal Konfirmasi Hapus -->
<div class="modal fade" id="deleteModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Konfirmasi Hapus</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Apakah Anda yakin ingin menghapus penilaian untuk <strong
id="deleteKaryawanName"></strong> pada tanggal <strong
id="deleteTanggal"></strong>?</p>
<p class="text-danger"><small>Tindakan ini tidak dapat dibatalkan!
</small></p>
</div>
<div class="modal-footer">
<form method="POST" id="deleteForm">
<input type="hidden" name="idKaryawan" id="deleteKaryawanId">
<input type="hidden" name="tanggalPenilaian"
id="deleteTanggalPenilaian">
<button type="button" class="btn btn-secondary" data-bs-
dismiss="modal">Batal</button>
<button type="submit" name="delete_penilaian" class="btn btn-
danger">Hapus</button>
</form>
</div>
</div>
</div>
</div>
<script>
// Function to view detail penilaian
function viewDetail(idKaryawan, tanggalPenilaian) {
const modal = new bootstrap.Modal(document.getElementById('detailModal'));
const content = document.getElementById('detailContent');
content.innerHTML = `
<div class="text-center p-4">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Mengambil detail penilaian...</p>
</div>
`;
fetch(`../../ajax/get_detail_penilaian.php?idKaryawan=${idKaryawan}&tanggal=$
{tanggalPenilaian}`)
.then(response => response.json())
.then(data => {
if (!data.success) {
content.innerHTML = `<div class="alert alert-danger">Gagal memuat
detail penilaian.</div>`;
return;
}
let html = `
<h6>Nama Karyawan: ${data.karyawan.namaKaryawan}</h6>
<p><strong>Jabatan:</strong> ${data.karyawan.jabatan}<br>
<strong>Tanggal Penilaian:</strong> ${data.tanggal}</p>
<table class="table table-sm table-bordered">
<thead><tr><th>Kriteria</th><th>Subkriteria</th><th>Skor</th></tr></thead><tbody>
`;
data.penilaian.forEach(row => {
html += `<tr><td>${row.namaKriteria}</td><td>$
{row.namaSubKriteria}</td><td>${row.nilaiSkor}</td></tr>`;
});
html += `</tbody></table>`;
if (data.catatan) {
html += `<p><strong>Catatan:</strong> ${data.catatan}</p>`;
}
content.innerHTML = html;
})
.catch(err => {
console.error(err);
content.innerHTML = `<div class="alert alert-danger">Terjadi kesalahan
saat mengambil data.</div>`;
});
modal.show();
}
// Function to delete penilaian
function deletePenilaian(idKaryawan, tanggalPenilaian, namaKaryawan) {
const modal = new bootstrap.Modal(document.getElementById('deleteModal'));
document.getElementById('deleteKaryawanName').textContent = namaKaryawan;
document.getElementById('deleteTanggal').textContent = new
Date(tanggalPenilaian).toLocaleDateString('id-ID');
document.getElementById('deleteKaryawanId').value = idKaryawan;
document.getElementById('deleteTanggalPenilaian').value = tanggalPenilaian;
modal.show();
}
// Load sub kriteria when page loads (for edit mode)
<?php if ($action === 'edit' && $editPenilaian): ?>
document.addEventListener('DOMContentLoaded', function() {
// Set karyawan info
const karyawanSelect = document.getElementById('karyawanSelect');
const selectedOption = karyawanSelect.options[karyawanSelect.selectedIndex];
if (selectedOption) {
showKaryawanInfo(selectedOption);
}
// Load sub kriteria for edit
<?php foreach($editSubKriteria as $kriteriaId => $subKriteriaId): ?>
loadSubKriteria(<?= $kriteriaId ?>, <?= $subKriteriaId ?>);
<?php endforeach; ?>
});
<?php endif; ?>
// Handle karyawan selection
document.getElementById('karyawanSelect')?.addEventListener('change', function() {
if (this.value) {
showKaryawanInfo(this.options[this.selectedIndex]);
// Load all sub kriteria
document.querySelectorAll('.subkriteria-select').forEach(select => {
const kriteriaId = select.dataset.kriteria;
loadSubKriteria(kriteriaId);
});
} else {
document.getElementById('karyawanInfo').style.display = 'none';
}
});
function showKaryawanInfo(option) {
document.getElementById('infoNama').textContent = option.text.split(' - ')[0];
document.getElementById('infoJabatan').textContent = option.dataset.jabatan;
document.getElementById('karyawanInfo').style.display = 'block';
}
function loadSubKriteria(kriteriaId, selectedId = null) {
const select = document.querySelector(`select[data-kriteria="${kriteriaId}"]`);
if (!select) return;
fetch(`../../ajax/get_subkriteria.php?idKriteria=${kriteriaId}`)
.then(resp => resp.json())
.then(json => {
if (!json.success) throw new Error(json.error || 'Gagal mengambil
data');
select.innerHTML = '<option value="">Pilih Sub Kriteria</option>';
json.data.forEach(sub => {
const option = new Option(
`${sub.namaSubKriteria} (Skor: ${sub.nilaiSkor})`,
sub.idSubKriteria
);
if (selectedId && sub.idSubKriteria == selectedId) {
option.selected = true;
}
select.appendChild(option);
});
})
.catch(error => {
console.error('Error loading sub kriteria:', error);
select.innerHTML = '<option value="">Error loading data</option>';
});
}
// Preview calculation
document.getElementById('previewBtn')?.addEventListener('click', function() {
const form = document.getElementById('penilaianForm');
if (!form.checkValidity()) {
form.reportValidity();
return;
}
const previewSection = document.getElementById('previewSection');
const previewContent = document.getElementById('previewContent');
previewContent.innerHTML = `
<div class="text-center p-4">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Menghitung preview...</p>
</div>`;
previewSection.style.display = 'block';
fetch('../../ajax/perhitungan_saw.php', {
method: 'POST',
body: new FormData(form),
})
.then(response => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then(json => {
if (!json.success) {
throw new Error(json.error || 'Gagal menghitung');
}
// *** Mulai render hasil ke HTML ***
const d = json.data;
let html = `
<h6>Hasil Perhitungan (${d.metode})</h6>
<p><strong>${d.karyawan.namaKaryawan}</strong><br>
Tanggal: ${d.tanggal_penilaian}<br>
Periode: ${d.periode}</p>
<table class="table table-sm">
<thead>
<tr>
<th>Kriteria</th>
<th>Sub-kriteria</th>
<th>Skor</th>
<th>Normalisasi</th>
<th>Bobot</th>
<th>Skor Terbobot</th>
</tr>
</thead>
<tbody>`;
for (const id in d.detail_penilaian) {
const det = d.detail_penilaian[id];
const norm = d.perhitungan.normalisasi[id];
html += `
<tr>
<td>${det.namaKriteria}</td>
<td>${det.namaSubKriteria}</td>
<td>${det.nilaiSkor}</td>
<td>${norm.normalisasi}</td>
<td>${norm.bobot}</td>
<td>${norm.skor_terbobot}</td>
</tr>`;
}
html += `</tbody></table>
<p>
<strong>Total Bobot:</strong> ${d.perhitungan.total_bobot}<br>
<strong>Total Skor:</strong> ${d.perhitungan.total_skor}<br>
<strong>Skor Final:</strong> ${d.perhitungan.skor_final}%<br>
<strong>Status:</strong> ${d.perhitungan.status_kelayakan}
</p>`;
previewContent.innerHTML = html;
})
.catch(err => {
console.error('Preview error:', err);
previewContent.innerHTML = `
<div class="alert alert-danger">
<strong>Error:</strong> ${err.message}
</div>`;
});
});
</script>
//source-code file: /dashboard/admin/analisis.php :
<?php
require_once __DIR__ . '/../../config/session.php';
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../../includes/functions.php';
SessionManager::requireRole('Admin');
$db = Database::getInstance()->getConnection();
$message = '';
$messageType = '';
$hasilAnalisis = [];
$periode = $_GET['periode'] ?? date('Y-m');
$action = $_GET['action'] ?? 'view';
// Handle form submission untuk trigger analisis
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['trigger_analisis'])) {
try {
$periodeAnalisis = $_POST['periode'];
$idAnalisis = $_SESSION['user_id'];
$db->beginTransaction();
// Hapus hasil analisis lama untuk periode yang sama
$stmtDelete = $db->prepare("DELETE FROM hasilspk WHERE periode = ?");
$stmtDelete->execute([$periodeAnalisis]);
// Ambil semua penilaian dalam periode tersebut
$stmtPenilaian = $db->prepare("
SELECT DISTINCT p.idKaryawan, k.namaKaryawan, k.jabatan
FROM penilaiankaryawan p
JOIN karyawanfbs k ON p.idKaryawan = k.idKaryawan
WHERE DATE_FORMAT(p.tanggalPenilaian, '%Y-%m') = ?
AND k.statusKerja = 'Aktif'
");
$stmtPenilaian->execute([$periodeAnalisis]);
$karyawanList = $stmtPenilaian->fetchAll(PDO::FETCH_ASSOC);
if (empty($karyawanList)) {
throw new Exception("Tidak ada penilaian ditemukan untuk periode
$periodeAnalisis");
}
// Ambil kriteria aktif
$stmtKriteria = $db->prepare("SELECT idKriteria, namaKriteria, bobot,
jenisKriteria
FROM kriteria WHERE status = 'Aktif'");
$stmtKriteria->execute();
$kriteriaList = $stmtKriteria->fetchAll(PDO::FETCH_ASSOC);
if (empty($kriteriaList)) {
throw new Exception("Tidak ada kriteria aktif");
}
// Hitung nilai min/max untuk normalisasi
$nilaiMinMax = [];
foreach ($kriteriaList as $kriteria) {
$stmtMinMax = $db->prepare("
SELECT MAX(sk.nilaiSkor) as nilai_max, MIN(sk.nilaiSkor) as
nilai_min
FROM penilaiankaryawan p
JOIN subkriteria sk ON p.idSubKriteria = sk.idSubKriteria
WHERE p.idKriteria = ? AND DATE_FORMAT(p.tanggalPenilaian, '%Y-%m')
= ?
");
$stmtMinMax->execute([$kriteria['idKriteria'], $periodeAnalisis]);
$minMax = $stmtMinMax->fetch(PDO::FETCH_ASSOC);
$nilaiMinMax[$kriteria['idKriteria']] = [
'max' => $minMax['nilai_max'] ?? 1,
'min' => $minMax['nilai_min'] ?? 1,
'bobot' => $kriteria['bobot'],
'jenis' => $kriteria['jenisKriteria']
];
}
// Hitung skor SAW untuk setiap karyawan
$hasilSAW = [];
foreach ($karyawanList as $karyawan) {
$idKaryawan = $karyawan['idKaryawan'];
// Ambil penilaian terbaru untuk karyawan ini dalam periode
$stmtNilai = $db->prepare("
SELECT p.idKriteria, sk.nilaiSkor, p.tanggalPenilaian
FROM penilaiankaryawan p
JOIN subkriteria sk ON p.idSubKriteria = sk.idSubKriteria
WHERE p.idKaryawan = ? AND DATE_FORMAT(p.tanggalPenilaian, '%Y-%m')
= ?
ORDER BY p.tanggalPenilaian DESC
");
$stmtNilai->execute([$idKaryawan, $periodeAnalisis]);
$nilaiKaryawan = $stmtNilai->fetchAll(PDO::FETCH_ASSOC);
// Ambil nilai terbaru per kriteria
$nilaiPerKriteria = [];
foreach ($nilaiKaryawan as $nilai) {
if (!isset($nilaiPerKriteria[$nilai['idKriteria']])) {
$nilaiPerKriteria[$nilai['idKriteria']] = $nilai['nilaiSkor'];
}
}
// Hitung skor SAW
$totalSkor = 0;
$totalBobot = 0;
$validKriteria = 0;
foreach ($kriteriaList as $kriteria) {
$idKriteria = $kriteria['idKriteria'];
if (isset($nilaiPerKriteria[$idKriteria])) {
$nilai = $nilaiPerKriteria[$idKriteria];
$bobot = $kriteria['bobot'];
$jenis = $kriteria['jenisKriteria'];
$max = $nilaiMinMax[$idKriteria]['max'];
$min = $nilaiMinMax[$idKriteria]['min'];
// Normalisasi
if ($jenis === 'Benefit') {
$normalisasi = $max > 0 ? $nilai / $max : 0;
} else {
$normalisasi = $nilai > 0 ? $min / $nilai : 0;
}
$skorTerbobot = $normalisasi * $bobot;
$totalSkor += $skorTerbobot;
$totalBobot += $bobot;
$validKriteria++;
}
}
// Hanya proses jika semua kriteria dinilai
if ($validKriteria == count($kriteriaList)) {
$skorFinal = $totalBobot > 0 ? $totalSkor / $totalBobot : 0;
$hasilSAW[] = [
'idKaryawan' => $idKaryawan,
'namaKaryawan' => $karyawan['namaKaryawan'],
'jabatan' => $karyawan['jabatan'],
'totalSkor' => $skorFinal
];
}
}
// Urutkan berdasarkan skor (descending) dan tentukan ranking
usort($hasilSAW, function($a, $b) {
return $b['totalSkor'] <=> $a['totalSkor'];
});
// Simpan hasil ke database
$threshold = 0.75; // 75% dari skor maksimal
foreach ($hasilSAW as $index => $hasil) {
$ranking = $index + 1;
$statusPromosi = $hasil['totalSkor'] >= $threshold ? 'Layak' : 'Tidak
Layak';
$stmtInsert = $db->prepare("
INSERT INTO hasilspk (idKaryawan, totalSkor, ranking,
statusPromosi,
tanggalAnalisis, idAnalisis, periode)
VALUES (?, ?, ?, ?, CURDATE(), ?, ?)
");
$stmtInsert->execute([
$hasil['idKaryawan'],
$hasil['totalSkor'],
$ranking,
$statusPromosi,
$idAnalisis,
$periodeAnalisis
]);
}
$db->commit();
$message = "Analisis SPK berhasil! Diproses " . count($hasilSAW) . "
karyawan untuk periode $periodeAnalisis";
$messageType = "success";
$periode = $periodeAnalisis;
// Log activity
SPKHelper::logActivity($db, $idAnalisis, 'RUN_SPK_ANALYSIS',
"Menjalankan analisis SPK untuk periode
$periodeAnalisis");
} catch (Exception $e) {
if ($db->inTransaction()) {
$db->rollBack();
}
$message = "Error: " . $e->getMessage();
$messageType = "error";
}
}
// Ambil hasil analisis untuk ditampilkan
try {
$stmtHasil = $db->prepare("
SELECT h.*, k.namaKaryawan, k.jabatan
FROM hasilspk h
JOIN karyawanfbs k ON h.idKaryawan = k.idKaryawan
WHERE h.periode = ?
ORDER BY h.ranking ASC
");
$stmtHasil->execute([$periode]);
$hasilAnalisis = $stmtHasil->fetchAll(PDO::FETCH_ASSOC);
// Ambil statistik
$stmtStats = $db->prepare("
SELECT
COUNT(*) as total_karyawan,
COUNT(CASE WHEN statusPromosi = 'Layak' THEN 1 END) as layak_promosi,
AVG(totalSkor) as rata_rata_skor,
MAX(totalSkor) as skor_tertinggi,
MIN(totalSkor) as skor_terendah
FROM hasilspk
WHERE periode = ?
");
$stmtStats->execute([$periode]);
$statistik = $stmtStats->fetch(PDO::FETCH_ASSOC);
} catch (Exception $e) {
$message = "Error mengambil data: " . $e->getMessage();
$messageType = "error";
}
// Handle export to PDF/Excel
if ($action === 'export' && !empty($hasilAnalisis)) {
$format = $_GET['format'] ?? 'pdf';
if ($format === 'pdf') {
// Pastikan file TCPDF sudah ada dan path benar
$tcpdfPath = __DIR__ . '/../../includes/tcpdf/tcpdf.php';
if (!file_exists($tcpdfPath)) {
die('TCPDF library file not found. Please check the path and make sure
TCPDF is installed.');
}
require_once $tcpdfPath;
if (!class_exists('TCPDF')) {
die('TCPDF class not found after require. Please check your TCPDF
installation.');
}
$pdf = new \TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
$pdf->SetCreator('SPK Promosi Karyawan');
$pdf->SetAuthor('Admin');
$pdf->SetTitle('Hasil Analisis SPK - ' . $periode);
$pdf->AddPage();
$pdf->SetFont('helvetica', 'B', 16);
$pdf->Cell(0, 10, 'Hasil Analisis SPK Promosi Karyawan', 0, 1, 'C');
$pdf->Cell(0, 10, 'Periode: ' . date('F Y', strtotime($periode . '-01')),
0, 1, 'C');
$pdf->Ln(10);
// Table header
$pdf->SetFont('helvetica', 'B', 10);
$pdf->Cell(10, 8, 'No', 1, 0, 'C');
$pdf->Cell(50, 8, 'Nama Karyawan', 1, 0, 'C');
$pdf->Cell(30, 8, 'Jabatan', 1, 0, 'C');
$pdf->Cell(25, 8, 'Skor', 1, 0, 'C');
$pdf->Cell(20, 8, 'Ranking', 1, 0, 'C');
$pdf->Cell(30, 8, 'Status', 1, 1, 'C');
// Table content
$pdf->SetFont('helvetica', '', 9);
foreach ($hasilAnalisis as $hasil) {
$pdf->Cell(10, 8, $hasil['ranking'], 1, 0, 'C');
$pdf->Cell(50, 8, $hasil['namaKaryawan'], 1, 0, 'L');
$pdf->Cell(30, 8, $hasil['jabatan'], 1, 0, 'L');
$pdf->Cell(25, 8, number_format($hasil['totalSkor'], 3), 1, 0, 'C');
$pdf->Cell(20, 8, $hasil['ranking'], 1, 0, 'C');
$pdf->Cell(30, 8, $hasil['statusPromosi'], 1, 1, 'C');
}
$pdf->Output('hasil_analisis_spk_' . $periode . '.pdf', 'D');
exit;
} elseif ($format === 'excel') {
header('Content-Type: application/vnd.ms-excel');
header('Content-Disposition: attachment; filename="hasil_analisis_spk_' .
$periode . '.xls"');
echo "<table border='1'>";
echo "<tr><th colspan='6'>Hasil Analisis SPK Promosi Karyawan - Periode:
" . date('F Y', strtotime($periode . '-01')) . "</th></tr>";
echo "<tr><th>No</th><th>Nama
Karyawan</th><th>Jabatan</th><th>Skor</th><th>Ranking</th><th>Status
Promosi</th></tr>";
foreach ($hasilAnalisis as $hasil) {
echo "<tr>";
echo "<td>" . $hasil['ranking'] . "</td>";
echo "<td>" . $hasil['namaKaryawan'] . "</td>";
echo "<td>" . $hasil['jabatan'] . "</td>";
echo "<td>" . number_format($hasil['totalSkor'], 3) . "</td>";
echo "<td>" . $hasil['ranking'] . "</td>";
echo "<td>" . $hasil['statusPromosi'] . "</td>";
echo "</tr>";
}
echo "</table>";
exit;
}
}
$pageTitle = "Analisis SPK";
require_once __DIR__ . '/../../includes/header.php';
?>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-
center">
<h5 class="mb-0">
<i class="fas fa-chart-line me-2"></i>Analisis SPK Promosi
Karyawan
</h5>
<div class="btn-group">
<button type="button" class="btn btn-primary btn-sm" data-
bs-toggle="modal" data-bs-target="#modalTriggerAnalisis">
<i class="fas fa-play me-1"></i>Jalankan Analisis
</button>
<a href="index.php" class="btn btn-secondary">
<i class="fas fa-arrow-left me-1"></i>Kembali
</a>
<?php if (!empty($hasilAnalisis)): ?>
<div class="btn-group">
<button type="button" class="btn btn-success btn-sm
dropdown-toggle"
data-bs-toggle="dropdown"
aria-expanded="false"
id="exportDropdown">
<i class="fas fa-download me-1"></i>Export
</button>
<ul class="dropdown-menu" aria-
labelledby="exportDropdown">
<li>
<a class="dropdown-item export-link"
href="?action=export&format=pdf&periode=<?=
urlencode($periode) ?>"
data-format="pdf">
<i class="fas fa-file-pdf me-1 text-
danger"></i>Export PDF
</a>
</li>
<li>
<a class="dropdown-item export-link"
href="?action=export&format=excel&periode=<?
= urlencode($periode) ?>"
data-format="excel">
<i class="fas fa-file-excel me-1 text-
success"></i>Export Excel
</a>
</li>
</ul>
</div>
<?php endif; ?>
</div>
</div>
<div class="card-body">
<?php if ($message): ?>
<div class="alert alert-<?= $messageType === 'success' ?
'success' : 'danger' ?> alert-dismissible fade show">
<?= htmlspecialchars($message) ?>
<button type="button" class="btn-close" data-bs-
dismiss="alert"></button>
</div>
<?php endif; ?>
<!-- Filter Periode -->
<div class="row mb-4">
<div class="col-md-4">
<label for="filterPeriode" class="form-label">Filter
Periode:</label>
<div class="input-group">
<input type="month" id="filterPeriode" class="form-
control" value="<?= $periode ?>">
<button class="btn btn-outline-secondary"
type="button" onclick="filterPeriode()">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</div>
<?php if (!empty($hasilAnalisis)): ?>
<!-- Statistik -->
<div class="row mb-4">
<div class="col-md-2">
<div class="card bg-primary text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h6 class="card-title">Total
Karyawan</h6>
<h4><?= $statistik['total_karyawan'] ??
0 ?></h4>
</div>
<i class="fas fa-users fa-2x"></i>
</div>
</div>
</div>
</div>
<div class="col-md-2">
<div class="card bg-success text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h6 class="card-title">Layak
Promosi</h6>
<h4><?= $statistik['layak_promosi'] ??
0 ?></h4>
</div>
<i class="fas fa-thumbs-up fa-2x"></i>
</div>
</div>
</div>
</div>
<div class="col-md-2">
<div class="card bg-info text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h6 class="card-title">Rata-rata
Skor</h6>
<h4><?=
number_format($statistik['rata_rata_skor'] ?? 0, 2) ?></h4>
</div>
<i class="fas fa-chart-bar fa-2x"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-warning text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h6 class="card-title">Skor
Tertinggi</h6>
<h4><?=
number_format($statistik['skor_tertinggi'] ?? 0, 3) ?></h4>
</div>
<i class="fas fa-trophy fa-2x"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-secondary text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h6 class="card-title">Skor
Terendah</h6>
<h4><?=
number_format($statistik['skor_terendah'] ?? 0, 3) ?></h4>
</div>
<i class="fas fa-chart-line fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Tabel Hasil -->
<div class="table-responsive">
<table class="table table-striped table-hover"
id="tabelHasil">
<thead class="table-dark">
<tr>
<th>Ranking</th>
<th>Nama Karyawan</th>
<th>Jabatan</th>
<th>Total Skor</th>
<th>Status Promosi</th>
<th>Tanggal Analisis</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php foreach ($hasilAnalisis as $hasil): ?>
<tr class="<?= $hasil['statusPromosi'] ===
'Layak' ? 'table-success' : '' ?>">
<td>
<span class="badge bg-primary fs-6">#<?=
$hasil['ranking'] ?></span>
</td>
<td>
<strong><?=
htmlspecialchars($hasil['namaKaryawan']) ?></strong>
</td>
<td><?= htmlspecialchars($hasil['jabatan']) ?
></td>
<td>
<span class="badge bg-info"><?=
number_format($hasil['totalSkor'], 3) ?></span>
</td>
<td>
<span class="badge bg-<?=
$hasil['statusPromosi'] === 'Layak' ? 'success' : 'danger' ?>">
<?= $hasil['statusPromosi'] ?>
</span>
</td>
<td><?= date('d/m/Y',
strtotime($hasil['tanggalAnalisis'])) ?></td>
<td>
<button class="btn btn-info btn-sm"
onclick="showDetail(<?= $hasil['idKaryawan'] ?>, '<?= $periode ?>')">
<i class="fas fa-eye"></i> Detail
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="text-center py-5">
<i class="fas fa-chart-line fa-3x text-muted mb-3"></i>
<h5 class="text-muted">Belum ada hasil analisis untuk
periode <?= date('F Y', strtotime($periode . '-01')) ?></h5>
<p class="text-muted">Klik tombol "Jalankan Analisis" untuk
memulai analisis SPK</p>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Trigger Analisis -->
<div class="modal fade" id="modalTriggerAnalisis" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<form method="POST">
<div class="modal-header">
<h5 class="modal-title">Jalankan Analisis SPK</h5>
<button type="button" class="btn-close" data-bs-
dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="alert alert-info">
<i class="fas fa-info-circle"></i>
Analisis akan memproses semua penilaian karyawan dalam
periode yang dipilih menggunakan metode SAW (Simple Additive Weighting).
</div>
<div class="mb-3">
<label for="periode" class="form-label">Pilih
Periode</label>
<input type="month" class="form-control" id="periode"
name="periode" value="<?= date('Y-m') ?>" required>
</div>
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle"></i>
<strong>Perhatian:</strong> Hasil analisis lama untuk
periode yang sama akan dihapus.
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-
dismiss="modal">Batal</button>
<button type="submit" name="trigger_analisis" class="btn btn-
primary">
<i class="fas fa-play me-1"></i>Jalankan Analisis
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modal Detail -->
<div class="modal fade" id="modalDetail" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Detail Perhitungan SPK</h5>
<button type="button" class="btn-close"
data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="detailContent">
<!-- Content akan diload via AJAX -->
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM loaded, initializing export functions...');
// Fix untuk dropdown export
const exportDropdown = document.getElementById('exportDropdown');
if (exportDropdown) {
console.log('Export dropdown found');
// Manual dropdown toggle
exportDropdown.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const dropdownMenu = this.nextElementSibling;
if (dropdownMenu) {
const isOpen = dropdownMenu.classList.contains('show');
// Close all other dropdowns first
document.querySelectorAll('.dropdown-menu.show').forEach(menu => {
menu.classList.remove('show');
});
// Toggle current dropdown
if (!isOpen) {
dropdownMenu.classList.add('show');
console.log('Dropdown opened');
} else {
dropdownMenu.classList.remove('show');
console.log('Dropdown closed');
}
}
});
}
// Handle export link clicks
const exportLinks = document.querySelectorAll('.export-link');
exportLinks.forEach(link => {
link.addEventListener('click', function(e) {
console.log('Export link clicked:', this.href);
// Show loading state
const originalText = this.innerHTML;
const format = this.getAttribute('data-format');
this.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>'
+ 'Mengunduh '
+ (format === 'pdf' ? 'PDF' : 'Excel')
+ '...';
this.style.pointerEvents = 'none';
// Create a temporary link to trigger download
const tempLink = document.createElement('a');
tempLink.href = this.href;
tempLink.target = '_blank';
tempLink.style.display = 'none';
document.body.appendChild(tempLink);
tempLink.click();
document.body.removeChild(tempLink);
// Reset tombol setelah delay
setTimeout(() => {
this.innerHTML = originalText;
this.style.pointerEvents = 'auto';
// Close dropdown
const dropdownMenu = this.closest('.dropdown-menu');
if (dropdownMenu) dropdownMenu.classList.remove('show');
}, 2000);
// Prevent default
e.preventDefault();
return false;
});
});
// Close dropdown when clicking outside
document.addEventListener('click', function(e) {
const dropdowns = document.querySelectorAll('.dropdown-menu.show');
dropdowns.forEach(dropdown => {
if (!dropdown.parentElement.contains(e.target)) {
dropdown.classList.remove('show');
}
});
});
});
function showDetail(idKaryawan, periode) {
const detailContent = document.getElementById('detailContent');
if (detailContent) {
detailContent.innerHTML = `<div class="text-center py-4">
<i class="fas fa-spinner fa-spin fa-2x text-primary mb-3"></i>
<p>Memuat detail penilaian...</p>
</div>`;
}
// Tampilkan modal
const modalElem = document.getElementById('modalDetail');
if (modalElem) {
const bsModal = new bootstrap.Modal(modalElem);
bsModal.show();
}
fetch('../../ajax/get_detail_penilaian.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `idKaryawan=${encodeURIComponent(idKaryawan)}&tanggal=$
{encodeURIComponent(periode)}`
})
.then(resp => {
if (!resp.ok) throw new Error(`HTTP error! status: ${resp.status}`);
return resp.json();
})
.then(data => {
if (!data.success) throw new Error(data.message);
// Awali HTML-nya
let html = `
<h5>Detail Penilaian: ${data.karyawan.namaKaryawan} ($
{data.karyawan.jabatan})</h5>
`;
if (data.isPeriode) {
html += `<p><strong>Periode:</strong> ${data.tanggalRaw} (menampilkan $
{data.daftarTanggal.length} tanggal)</p>`;
} else {
html += `<p><strong>Tanggal Penilaian:</strong>
${data.tanggalRaw}</p>`;
}
// Kita akan grouping berdasarkan setiap tanggal jika isPeriode = true
const groupedByTanggal = {};
data.penilaian.forEach(row => {
const tgl = row.tanggalPenilaian;
if (!groupedByTanggal[tgl]) groupedByTanggal[tgl] = [];
groupedByTanggal[tgl].push(row);
});
// Loop per tanggal
for (const tgl of Object.keys(groupedByTanggal)) {
html += `
<hr class="my-2">
<h6><i class="fas fa-calendar-alt me-1"></i> Tanggal: ${tgl}</h6>
<table class="table table-bordered table-sm mb-3">
<thead class="table-light">
<tr>
<th>Kriteria</th>
<th>Subkriteria</th>
<th>Skor</th>
<th>Bobot</th>
</tr>
</thead>
<tbody>
`;
groupedByTanggal[tgl].forEach(item => {
html += `
<tr>
<td>${item.namaKriteria}</td>
<td>${item.namaSubKriteria}</td>
<td>${item.nilaiSkor}</td>
<td>${item.bobot}</td>
</tr>`;
});
html += `</tbody></table>`;
}
if (data.catatan) {
html += `<p><strong>Catatan:</strong> ${data.catatan}</p>`;
}
detailContent.innerHTML = html;
})
.catch(err => {
console.error('Error loading detail:', err);
detailContent.innerHTML = `<div class="alert alert-danger">
<i class="fas fa-exclamation-triangle me-2"></i>
Gagal memuat detail penilaian. Error: ${err.message}
</div>`;
});
}
// Filter periode function
function filterPeriode() {
const periode = document.getElementById('filterPeriode').value;
if (periode) {
console.log('Filtering by periode:', periode);
window.location.href = `analisis.php?periode=$
{encodeURIComponent(periode)}`;
}
}
// Initialize DataTable when jQuery is ready
$(document).ready(function() {
console.log('jQuery ready, initializing DataTable...');
if ($.fn.DataTable) {
$('#tabelHasil').DataTable({
"language": {
"url": "//cdn.datatables.net/plug-ins/1.11.5/i18n/id.json"
},
"order": [[ 0, "asc" ]], // Order by ranking
"pageLength": 10,
"responsive": true,
"columnDefs": [
{ "orderable": false, "targets": -1 } // Disable sorting on action
column
]
});
console.log('DataTable initialized');
}
});
// Handle form submission untuk analisis
document.addEventListener('DOMContentLoaded', function() {
const formAnalisis = document.querySelector('#modalTriggerAnalisis
form[method="POST"]');
if (formAnalisis) {
formAnalisis.addEventListener('submit', function(e) {
const submitBtn =
this.querySelector('button[name="trigger_analisis"]');
if (submitBtn) {
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin
me-1"></i>Memproses Analisis...';
submitBtn.disabled = true;
// Show progress indication
const modalBody = this.closest('.modal-
content').querySelector('.modal-body');
const progressDiv = document.createElement('div');
progressDiv.innerHTML = `
<div class="alert alert-info mt-3">
<i class="fas fa-info-circle me-2"></i>
Sedang memproses analisis SAW, mohon tunggu...
</div>
`;
modalBody.appendChild(progressDiv);
}
});
}
});
// Debug function
function debugExport(format, periode) {
console.log('Debug export:', format, periode);
const url = `analisis.php?action=export&format=${format}&periode=${periode}`;
console.log('Export URL:', url);
window.open(url, '_blank');
}
</script>
<?php require_once __DIR__ . '/../../includes/footer.php'; ?>