231 lines
No EOL
12 KiB
PHP
231 lines
No EOL
12 KiB
PHP
<?php
|
|
require_once 'auth_check.php';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>관리자 계정 관리 | FKI JASAN</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Pretendard:wght@400;500;600;700;800&display=swap"
|
|
rel="stylesheet">
|
|
<link rel="stylesheet" href="assets/style.css">
|
|
<style>
|
|
body {
|
|
font-family: 'Pretendard', sans-serif;
|
|
}
|
|
|
|
[x-cloak] {
|
|
display: none !important;
|
|
}
|
|
|
|
.modal-bg {
|
|
background-color: rgba(15, 23, 42, 0.7);
|
|
backdrop-filter: blur(4px);
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body class="bg-[#f8fafc] text-slate-800" x-data="adminManagement()">
|
|
|
|
<?php include 'nav.php'; ?>
|
|
|
|
<main class="max-w-[1200px] mx-auto p-8 pt-10">
|
|
<header class="mb-10 flex flex-col md:flex-row md:items-center justify-between gap-4">
|
|
<div>
|
|
<h2 class="text-3xl font-extrabold text-slate-900 tracking-tight">System Administrators</h2>
|
|
<p class="text-slate-500 mt-1">시스템 관리자 계정 생성, 삭제 및 비밀번호 관리</p>
|
|
</div>
|
|
<button @click="openAddModal()"
|
|
class="px-6 py-3 bg-slate-900 text-white rounded-2xl font-bold shadow-lg shadow-slate-200 hover:bg-slate-800 transition-all flex items-center gap-2">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z" />
|
|
</svg>
|
|
관리자 추가
|
|
</button>
|
|
</header>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
<template x-for="admin in admins" :key="admin.id">
|
|
<div
|
|
class="bg-white rounded-[2rem] p-8 shadow-sm border border-slate-100 hover:shadow-xl transition-all relative overflow-hidden group">
|
|
<div
|
|
class="absolute top-0 right-0 w-32 h-32 bg-slate-50 rounded-full -translate-y-16 translate-x-16 group-hover:scale-150 transition-transform duration-500">
|
|
</div>
|
|
|
|
<div class="relative z-10">
|
|
<div
|
|
class="w-16 h-16 bg-slate-100 rounded-2xl flex items-center justify-center mb-6 shadow-inner text-slate-400 group-hover:bg-blue-600 group-hover:text-white transition-colors">
|
|
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
|
</svg>
|
|
</div>
|
|
|
|
<div class="mb-6">
|
|
<h3 class="text-xl font-black text-slate-900" x-text="admin.admin_name"></h3>
|
|
<p class="text-[10px] font-bold text-blue-500 uppercase tracking-[0.2em] mt-1"
|
|
x-text="admin.login_id"></p>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<div class="flex items-center justify-between py-3 border-t border-slate-50">
|
|
<span
|
|
class="text-[10px] font-black text-slate-400 uppercase tracking-widest">Created</span>
|
|
<span class="text-xs font-bold text-slate-600"
|
|
x-text="admin.created_at.split(' ')[0]"></span>
|
|
</div>
|
|
|
|
<div class="flex gap-2 pt-2">
|
|
<button @click="openPasswordModal(admin)"
|
|
class="flex-1 py-3 bg-slate-100 text-slate-600 rounded-xl font-bold text-xs hover:bg-slate-200 transition-all">PW
|
|
변경</button>
|
|
<button @click="deleteAdmin(admin)"
|
|
class="flex-1 py-3 bg-rose-50 text-rose-500 rounded-xl font-bold text-xs hover:bg-rose-500 hover:text-white transition-all border border-rose-100">계정
|
|
삭제</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Add Admin Modal -->
|
|
<div x-show="showAddModal" x-cloak class="fixed inset-0 z-[110] flex items-center justify-center p-4">
|
|
<div class="fixed inset-0 modal-bg" @click="showAddModal = false"></div>
|
|
<div class="bg-white rounded-[2.5rem] p-10 max-w-sm w-full relative z-[111] shadow-2xl">
|
|
<h3 class="text-2xl font-black text-slate-900 mb-8">관리자 계정 생성</h3>
|
|
<form @submit.prevent="addAdmin" class="space-y-6">
|
|
<div>
|
|
<label class="block text-[10px] font-black text-slate-400 uppercase mb-2 ml-1">이름</label>
|
|
<input type="text" x-model="formData.admin_name" required placeholder="User Name"
|
|
class="w-full px-5 py-4 bg-slate-50 border border-slate-200 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none font-bold text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block text-[10px] font-black text-slate-400 uppercase mb-2 ml-1">아이디</label>
|
|
<input type="text" x-model="formData.login_id" required placeholder="Login ID"
|
|
class="w-full px-5 py-4 bg-slate-50 border border-slate-200 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none font-bold text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block text-[10px] font-black text-slate-400 uppercase mb-2 ml-1">초기 비밀번호</label>
|
|
<input type="password" x-model="formData.password" required placeholder="Password"
|
|
class="w-full px-5 py-4 bg-slate-50 border border-slate-200 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none font-bold text-sm">
|
|
</div>
|
|
<div class="flex gap-3 pt-4">
|
|
<button type="button" @click="showAddModal = false"
|
|
class="flex-1 py-4 bg-slate-100 text-slate-600 rounded-2xl font-bold hover:bg-slate-200 transition-all">취소</button>
|
|
<button type="submit"
|
|
class="flex-1 py-4 bg-blue-600 text-white rounded-2xl font-bold hover:bg-blue-700 transition-all shadow-lg shadow-blue-200">생성하기</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Password Management Modal -->
|
|
<div x-show="showPwModal" x-cloak class="fixed inset-0 z-[110] flex items-center justify-center p-4">
|
|
<div class="fixed inset-0 modal-bg" @click="showPwModal = false"></div>
|
|
<div class="bg-white rounded-[2.5rem] p-10 max-w-sm w-full relative z-[111] shadow-2xl">
|
|
<h3 class="text-2xl font-black text-slate-900 mb-2">비밀번호 변경</h3>
|
|
<p class="text-blue-500 font-bold text-xs mb-8"
|
|
x-text="selectedAdmin?.admin_name + ' (' + selectedAdmin?.login_id + ')'"></p>
|
|
<form @submit.prevent="updatePassword" class="space-y-6">
|
|
<div>
|
|
<label class="block text-[10px] font-black text-slate-400 uppercase mb-2 ml-1">새 비밀번호</label>
|
|
<input type="password" x-model="newPassword" required placeholder="New Password"
|
|
class="w-full px-5 py-4 bg-slate-50 border border-slate-200 rounded-2xl focus:ring-2 focus:ring-blue-500 outline-none font-bold text-sm">
|
|
</div>
|
|
<div class="flex gap-3 pt-4">
|
|
<button type="button" @click="showPwModal = false"
|
|
class="flex-1 py-4 bg-slate-100 text-slate-600 rounded-2xl font-bold hover:bg-slate-200 transition-all">취소</button>
|
|
<button type="submit"
|
|
class="flex-1 py-4 bg-slate-900 text-white rounded-2xl font-bold hover:bg-slate-800 transition-all shadow-lg">변경하기</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function adminManagement() {
|
|
return {
|
|
admins: [],
|
|
showAddModal: false,
|
|
showPwModal: false,
|
|
selectedAdmin: null,
|
|
newPassword: '',
|
|
formData: { admin_name: '', login_id: '', password: '' },
|
|
|
|
init() {
|
|
this.fetchAdmins();
|
|
},
|
|
|
|
fetchAdmins() {
|
|
fetch('api.php?action=get_admins').then(res => res.json()).then(data => {
|
|
this.admins = data;
|
|
});
|
|
},
|
|
|
|
openAddModal() {
|
|
this.formData = { admin_name: '', login_id: '', password: '' };
|
|
this.showAddModal = true;
|
|
},
|
|
|
|
addAdmin() {
|
|
fetch('api.php?action=add_admin', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(this.formData)
|
|
}).then(res => res.json()).then(data => {
|
|
if (data.success) {
|
|
window.showAlert('신규 관리자가 등록되었습니다.', '성공', 'success');
|
|
this.showAddModal = false;
|
|
this.fetchAdmins();
|
|
}
|
|
});
|
|
},
|
|
|
|
openPasswordModal(admin) {
|
|
this.selectedAdmin = admin;
|
|
this.newPassword = '';
|
|
this.showPwModal = true;
|
|
},
|
|
|
|
updatePassword() {
|
|
fetch('api.php?action=update_admin_password', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ id: this.selectedAdmin.id, password: this.newPassword })
|
|
}).then(res => res.json()).then(data => {
|
|
if (data.success) {
|
|
window.showAlert('비밀번호가 성공적으로 변경되었습니다.', '성공', 'success');
|
|
this.showPwModal = false;
|
|
}
|
|
});
|
|
},
|
|
|
|
deleteAdmin(admin) {
|
|
window.showConfirm(`${admin.admin_name} 계정을 정말로 삭제하시겠습니까?`, () => {
|
|
fetch('api.php?action=delete_admin', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ id: admin.id })
|
|
}).then(res => res.json()).then(data => {
|
|
if (data.success) {
|
|
window.showAlert('계정이 삭제되었습니다.', '완료', 'success');
|
|
this.fetchAdmins();
|
|
} else {
|
|
window.showAlert(data.error, '실패', 'error');
|
|
}
|
|
});
|
|
}, '계정 삭제 확인');
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|