마감
This commit is contained in:
parent
5e7a53e731
commit
3e1cd3adab
5 changed files with 321 additions and 18 deletions
100
api.php
100
api.php
|
|
@ -488,6 +488,15 @@ last_confirmed_date
|
|||
$old_stmt->execute([$data['id']]);
|
||||
$old_asset = $old_stmt->fetch();
|
||||
|
||||
// Auto-relocate based on status if needed (optional)
|
||||
|
||||
// If assigned_user_name is missing but current_user_id exists, try to fill it for logging
|
||||
if (empty($data['assigned_user_name']) && !empty($data['current_user_id'])) {
|
||||
$u_stmt = $db->prepare("SELECT name FROM users WHERE id = ?");
|
||||
$u_stmt->execute([$data['current_user_id']]);
|
||||
$data['assigned_user_name'] = $u_stmt->fetchColumn() ?: '';
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("UPDATE laptop_assets SET
|
||||
asset_tag = ?, model_id = ?, current_user_id = ?, status = ?, serial_number = ?, purchase_date = ?, ip_address = ?,
|
||||
cpu = ?, npu = ?, hdd0_model = ?, hdd0_capacity = ?, hdd1_model = ?, hdd1_capacity = ?, ram = ?,
|
||||
|
|
@ -523,10 +532,11 @@ WHERE id = ?");
|
|||
]);
|
||||
|
||||
// Auto-log assignment change
|
||||
if ($data['assigned_user_name'] && $data['assigned_user_name'] !== ($old_asset['assigned_user_name'] ?? '')) {
|
||||
$log_stmt = $db->prepare("INSERT INTO asset_history (asset_id, log_type, user_name, action_date) VALUES (?,
|
||||
'assignment', ?, ?)");
|
||||
$log_stmt->execute([$data['id'], $data['assigned_user_name'], date('Y-m-d')]);
|
||||
$new_name = $data['assigned_user_name'] ?: '';
|
||||
$old_name = $old_asset['assigned_user_name'] ?? '';
|
||||
if ($new_name !== $old_name) {
|
||||
$log_stmt = $db->prepare("INSERT INTO asset_history (asset_id, log_type, user_name, action_date) VALUES (?, 'assignment', ?, ?)");
|
||||
$log_stmt->execute([$data['id'], $new_name ?: '재고(반납)', date('Y-m-d')]);
|
||||
}
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
|
|
@ -632,6 +642,11 @@ LIMIT 1")->fetchColumn();
|
|||
if ($newStatus) {
|
||||
$updates[] = "status = ?";
|
||||
$params[] = $newStatus;
|
||||
// 만약 상태를 'stock'(재고)으로 변경하는 경우 배정 정보도 초기화
|
||||
if ($newStatus === 'stock') {
|
||||
$updates[] = "current_user_id = NULL";
|
||||
$updates[] = "assigned_user_name = NULL";
|
||||
}
|
||||
}
|
||||
if ($newModelId) {
|
||||
$updates[] = "model_id = ?";
|
||||
|
|
@ -799,6 +814,83 @@ LIMIT 1")->fetchColumn();
|
|||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
|
||||
case 'archive_users':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$userIds = $data['user_ids'];
|
||||
if (empty($userIds)) {
|
||||
echo json_encode(['success' => false, 'error' => 'No users selected']);
|
||||
break;
|
||||
}
|
||||
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
$placeholders = implode(',', array_fill(0, count($userIds), '?'));
|
||||
// Copy to archive
|
||||
$db->prepare("INSERT INTO users_archive (id, emp_id, name, department_id, position, email, phone, mobile, accounting_type, status)
|
||||
SELECT id, emp_id, name, department_id, position, email, phone, mobile, accounting_type, status FROM users WHERE id IN ($placeholders)")
|
||||
->execute($userIds);
|
||||
// Delete from original
|
||||
$db->prepare("DELETE FROM users WHERE id IN ($placeholders)")->execute($userIds);
|
||||
$db->commit();
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'get_archived_users':
|
||||
$query = "SELECT u.*, dp.path as dept_name
|
||||
FROM users_archive u
|
||||
LEFT JOIN (
|
||||
WITH RECURSIVE dept_path(id, path) AS (
|
||||
SELECT id, name FROM departments WHERE parent_id IS NULL
|
||||
UNION ALL
|
||||
SELECT d.id, dp.path || ' > ' || d.name
|
||||
FROM departments d JOIN dept_path dp ON d.parent_id = dp.id
|
||||
) SELECT * FROM dept_path
|
||||
) dp ON u.department_id = dp.id
|
||||
ORDER BY u.archived_at DESC";
|
||||
echo json_encode($db->query($query)->fetchAll());
|
||||
break;
|
||||
|
||||
case 'restore_users':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$userIds = $data['user_ids'];
|
||||
if (empty($userIds)) {
|
||||
echo json_encode(['success' => false, 'error' => 'No users selected']);
|
||||
break;
|
||||
}
|
||||
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
$placeholders = implode(',', array_fill(0, count($userIds), '?'));
|
||||
// Restore to users
|
||||
$db->prepare("INSERT INTO users (id, emp_id, name, department_id, position, email, phone, mobile, accounting_type, status)
|
||||
SELECT id, emp_id, name, department_id, position, email, phone, mobile, accounting_type, status FROM users_archive WHERE id IN ($placeholders)")
|
||||
->execute($userIds);
|
||||
// Delete from archive
|
||||
$db->prepare("DELETE FROM users_archive WHERE id IN ($placeholders)")->execute($userIds);
|
||||
$db->commit();
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bulk_delete_users':
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$userIds = $data['user_ids'];
|
||||
if (empty($userIds)) {
|
||||
echo json_encode(['success' => false, 'error' => 'No users selected']);
|
||||
break;
|
||||
}
|
||||
$placeholders = implode(',', array_fill(0, count($userIds), '?'));
|
||||
$db->prepare("DELETE FROM users WHERE id IN ($placeholders)")->execute($userIds);
|
||||
echo json_encode(['success' => true]);
|
||||
break;
|
||||
|
||||
case 'get_general_rentals':
|
||||
$query = "SELECT r.*, GROUP_CONCAT(i.item_name, ', ') as items
|
||||
FROM general_rentals r
|
||||
|
|
|
|||
BIN
assets.db
BIN
assets.db
Binary file not shown.
9
fix_missing_column.php
Normal file
9
fix_missing_column.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
require_once 'config.php';
|
||||
try {
|
||||
$db->exec("ALTER TABLE laptop_assets ADD COLUMN last_confirmed_date TEXT");
|
||||
echo "Column 'last_confirmed_date' added successfully to laptop_assets table.\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Error or column already exists: " . $e->getMessage() . "\n";
|
||||
}
|
||||
?>
|
||||
58
laptops.php
58
laptops.php
|
|
@ -38,6 +38,18 @@
|
|||
</div>
|
||||
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="relative group">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg class="h-4 w-4 text-slate-400 group-focus-within:text-blue-500 transition-colors"
|
||||
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input type="text" x-model="searchQuery"
|
||||
class="block w-64 pl-10 pr-3 py-2.5 border border-slate-200 rounded-xl leading-5 bg-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all text-sm shadow-sm"
|
||||
placeholder="자산번호, 모델명, 사용자, IP 검색...">
|
||||
</div>
|
||||
<button @click="exportToExcel()"
|
||||
class="bg-white border border-slate-200 text-slate-700 px-5 py-2.5 rounded-xl font-bold hover:bg-slate-50 transition-all flex items-center shadow-sm text-sm">
|
||||
<svg class="w-4 h-4 mr-2 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
|
|
@ -94,7 +106,7 @@
|
|||
|
||||
<!-- Laptop List Table -->
|
||||
<div class="bg-white rounded-3xl shadow-sm border border-slate-200 overflow-hidden"
|
||||
x-show="!loading && assets.length > 0">
|
||||
x-show="!loading && filteredAssets.length > 0">
|
||||
<table class="min-w-full divide-y divide-slate-100">
|
||||
<thead class="bg-slate-50/50">
|
||||
<tr>
|
||||
|
|
@ -205,9 +217,14 @@
|
|||
<div x-show="loading" class="p-20 flex justify-center">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
|
||||
</div>
|
||||
<div x-show="!loading && assets.length === 0"
|
||||
<div x-show="!loading && filteredAssets.length === 0"
|
||||
class="p-20 text-center bg-white rounded-3xl border border-dashed border-slate-300">
|
||||
<template x-if="searchQuery">
|
||||
<p class="text-slate-400 font-medium italic">검색 결과와 일치하는 자산이 없습니다.</p>
|
||||
</template>
|
||||
<template x-if="!searchQuery">
|
||||
<p class="text-slate-400 font-medium italic">등록된 노트북 자산이 없습니다.</p>
|
||||
</template>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
|
@ -263,7 +280,7 @@
|
|||
<div>
|
||||
<label class="block text-[10px] font-black text-slate-400 uppercase mb-2 ml-1">배정
|
||||
사용자</label>
|
||||
<select x-model="formData.current_user_id"
|
||||
<select x-model="formData.current_user_id" @change="updateAssignedUserName()"
|
||||
class="w-full px-4 py-3 bg-white border border-slate-200 rounded-xl focus:ring-2 focus:ring-blue-500 outline-none transition-all text-sm font-bold text-slate-700">
|
||||
<option value="">미배정 (재고)</option>
|
||||
<template x-for="user in allUsers" :key="user.id">
|
||||
|
|
@ -398,6 +415,7 @@
|
|||
selectedIds: [],
|
||||
bulkStatus: '',
|
||||
bulkModelId: '',
|
||||
searchQuery: '',
|
||||
sortKey: 'asset_tag',
|
||||
sortOrder: 'asc',
|
||||
formData: {
|
||||
|
|
@ -458,8 +476,23 @@
|
|||
});
|
||||
},
|
||||
|
||||
get filteredAssets() {
|
||||
let result = [...this.assets];
|
||||
if (this.searchQuery) {
|
||||
const q = this.searchQuery.toLowerCase();
|
||||
result = result.filter(a => (a.asset_tag && a.asset_tag.toLowerCase().includes(q)) ||
|
||||
(a.model_name && a.model_name.toLowerCase().includes(q)) ||
|
||||
(a.manufacturer && a.manufacturer.toLowerCase().includes(q)) ||
|
||||
(a.user_name && a.user_name.toLowerCase().includes(q)) ||
|
||||
(a.ip_address && a.ip_address.toLowerCase().includes(q)) ||
|
||||
(a.serial_number && a.serial_number.toLowerCase().includes(q))
|
||||
);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
get sortedAssets() {
|
||||
return [...this.assets].sort((a, b) => {
|
||||
return this.filteredAssets.sort((a, b) => {
|
||||
let v1 = a[this.sortKey] || '';
|
||||
let v2 = b[this.sortKey] || '';
|
||||
if (this.sortOrder === 'asc') return v1 > v2 ? 1 : -1;
|
||||
|
|
@ -533,12 +566,29 @@
|
|||
body: JSON.stringify(this.formData)
|
||||
}).then(res => res.json()).then(data => {
|
||||
if (data.success) {
|
||||
window.showAlert(this.isEdit ? '자산 정보가 수정되었습니다.' : '새 자산이 등록되었습니다.', '성공', 'success');
|
||||
this.showModal = false;
|
||||
this.fetchAssets();
|
||||
} else {
|
||||
window.showAlert(data.error || '처리 중 오류가 발생했습니다.', '오류', 'error');
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
window.showAlert('서버 통신 오류가 발생했습니다.', '시스템 오류', 'error');
|
||||
});
|
||||
},
|
||||
|
||||
updateAssignedUserName() {
|
||||
if (!this.formData.current_user_id) {
|
||||
this.formData.assigned_user_name = '';
|
||||
return;
|
||||
}
|
||||
const user = this.allUsers.find(u => u.id == this.formData.current_user_id);
|
||||
if (user) {
|
||||
this.formData.assigned_user_name = user.name;
|
||||
}
|
||||
},
|
||||
|
||||
exportToExcel() {
|
||||
if (this.assets.length === 0) return;
|
||||
const headers = ['자산관리번호', '모델명', '제조사', '프로세서', 'RAM', 'SSD', 'IP주소', '시리얼', '사용자', '상태', '취득일'];
|
||||
|
|
|
|||
152
users.php
152
users.php
|
|
@ -71,6 +71,7 @@
|
|||
class="block w-64 pl-10 pr-3 py-2.5 border border-slate-200 rounded-xl leading-5 bg-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all text-sm"
|
||||
placeholder="이름, 사번, 이메일 검색...">
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button @click="openAddModal()"
|
||||
class="bg-blue-600 text-white px-5 py-2.5 rounded-xl font-bold shadow-lg shadow-blue-200 hover:bg-blue-700 transition-all flex items-center shrink-0">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
|
|
@ -79,6 +80,15 @@
|
|||
</svg>
|
||||
신규 등록
|
||||
</button>
|
||||
<button @click="openRestoreModal()"
|
||||
class="bg-slate-800 text-white px-5 py-2.5 rounded-xl font-bold shadow-lg shadow-slate-200 hover:bg-slate-900 transition-all flex items-center shrink-0">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
|
||||
</svg>
|
||||
불러오기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
|
@ -139,6 +149,26 @@
|
|||
<button @click="applyBulkUpdate"
|
||||
class="bg-blue-600 hover:bg-blue-700 px-6 py-2 rounded-xl text-xs font-black transition-all shadow-lg shadow-blue-500/20 active:scale-95">일괄
|
||||
적용</button>
|
||||
|
||||
<div class="h-8 w-px bg-white/10 mx-1"></div>
|
||||
|
||||
<button @click="archiveUsers"
|
||||
class="bg-emerald-600 hover:bg-emerald-700 px-6 py-2 rounded-xl text-xs font-black transition-all shadow-lg shadow-emerald-500/20 active:scale-95 flex items-center gap-2">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4" />
|
||||
</svg>
|
||||
내보내기
|
||||
</button>
|
||||
<button @click="bulkDelete"
|
||||
class="bg-rose-600 hover:bg-rose-700 px-6 py-2 rounded-xl text-xs font-black transition-all shadow-lg shadow-rose-500/20 active:scale-95 flex items-center gap-2">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||
</svg>
|
||||
삭제
|
||||
</button>
|
||||
|
||||
<button @click="selectedIds = []"
|
||||
class="ml-2 w-8 h-8 flex items-center justify-center rounded-full hover:bg-white/10 text-slate-400 hover:text-white transition-all">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
|
|
@ -532,6 +562,67 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Restore (Import) Modal -->
|
||||
<div x-show="showRestoreModal" x-cloak class="fixed inset-0 z-[120] flex items-center justify-center p-4">
|
||||
<div class="fixed inset-0 modal-bg" @click="showRestoreModal = false"></div>
|
||||
<div
|
||||
class="bg-white rounded-[2.5rem] p-8 max-w-2xl w-full relative z-[121] shadow-2xl overflow-hidden flex flex-col max-h-[85vh]">
|
||||
<div class="flex justify-between items-start mb-6">
|
||||
<div>
|
||||
<h3 class="text-2xl font-black text-slate-900">아카이브에서 불러오기</h3>
|
||||
<p class="text-xs font-bold text-slate-400 uppercase tracking-widest mt-1">Select Archived Employees
|
||||
to Restore</p>
|
||||
</div>
|
||||
<button @click="showRestoreModal = false" class="text-slate-300 hover:text-slate-900 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="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-y-auto pr-2 no-scrollbar">
|
||||
<template x-if="archivedUsers.length === 0">
|
||||
<div class="text-center py-20">
|
||||
<div class="w-16 h-16 bg-slate-50 rounded-2xl flex items-center justify-center mx-auto mb-4">
|
||||
<svg class="w-8 h-8 text-slate-200" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-slate-400 font-bold">내보내기된 직원이 없습니다.</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="grid grid-cols-1 gap-3">
|
||||
<template x-for="user in archivedUsers" :key="user.id">
|
||||
<div
|
||||
class="p-4 bg-slate-50 border border-slate-100 rounded-2xl flex items-center justify-between group hover:bg-white hover:shadow-lg hover:border-blue-200 transition-all">
|
||||
<div class="flex items-center gap-4">
|
||||
<div
|
||||
class="w-10 h-10 bg-white rounded-xl flex items-center justify-center shadow-sm text-slate-400 group-hover:text-blue-500 transition-colors">
|
||||
<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="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>
|
||||
<div class="text-sm font-black text-slate-900" x-text="user.name"></div>
|
||||
<div class="text-[10px] font-bold text-slate-400"
|
||||
x-text="user.dept_name + ' / ' + user.position"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button @click="restoreUser(user.id)"
|
||||
class="px-4 py-2 bg-slate-900 text-white text-[11px] font-black rounded-xl hover:bg-blue-600 transition-all active:scale-95">
|
||||
불러오기
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function userManagement() {
|
||||
return {
|
||||
|
|
@ -551,7 +642,9 @@
|
|||
bulkDeptId: '',
|
||||
bulkPosition: '',
|
||||
showRentalListModal: false,
|
||||
showRestoreModal: false,
|
||||
userRentals: [],
|
||||
archivedUsers: [],
|
||||
formData: { id: '', name: '', emp_id: '', department_id: '', position: '', email: '', mobile: '', accounting_type: '일반회계', status: 'active', phone: '' },
|
||||
|
||||
init() {
|
||||
|
|
@ -765,6 +858,65 @@
|
|||
resetForm() {
|
||||
this.isEdit = false;
|
||||
this.formData = { id: '', name: '', emp_id: '', department_id: '', position: '', email: '', mobile: '', accounting_type: '일반회계', status: 'active', phone: '' };
|
||||
},
|
||||
|
||||
archiveUsers() {
|
||||
window.showConfirm(`선택한 ${this.selectedIds.length}명의 직원을 내보내기 하시겠습니까?\n내보내기된 정보는 '불러오기' 메뉴에서 확인 가능합니다.`, () => {
|
||||
fetch('api.php?action=archive_users', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ user_ids: this.selectedIds })
|
||||
}).then(res => res.json()).then(data => {
|
||||
if (data.success) {
|
||||
window.showAlert('선택한 인원이 아카이브로 내보내기 되었습니다.', '내보내기 완료', 'success');
|
||||
this.selectedIds = [];
|
||||
this.fetchUsers();
|
||||
}
|
||||
});
|
||||
}, '내보내기 확인');
|
||||
},
|
||||
|
||||
bulkDelete() {
|
||||
window.showConfirm(`선택한 ${this.selectedIds.length}명의 직원을 영구 삭제하시겠습니까?\n이 작업은 되돌릴 수 없습니다.`, () => {
|
||||
fetch('api.php?action=bulk_delete_users', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ user_ids: this.selectedIds })
|
||||
}).then(res => res.json()).then(data => {
|
||||
if (data.success) {
|
||||
window.showAlert('영구 삭제되었습니다.', '삭제 완료', 'success');
|
||||
this.selectedIds = [];
|
||||
this.fetchUsers();
|
||||
}
|
||||
});
|
||||
}, '영구 삭제 확인');
|
||||
},
|
||||
|
||||
openRestoreModal() {
|
||||
this.fetchArchivedUsers();
|
||||
},
|
||||
|
||||
fetchArchivedUsers() {
|
||||
fetch('api.php?action=get_archived_users')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
this.archivedUsers = data;
|
||||
this.showRestoreModal = true;
|
||||
});
|
||||
},
|
||||
|
||||
restoreUser(id) {
|
||||
fetch('api.php?action=restore_users', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ user_ids: [id] })
|
||||
}).then(res => res.json()).then(data => {
|
||||
if (data.success) {
|
||||
window.showAlert('직원 정보가 복구되었습니다.', '불러오기 성공', 'success');
|
||||
this.fetchArchivedUsers();
|
||||
this.fetchUsers();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue