This commit is contained in:
NAS-Admin 2026-02-08 18:40:00 +09:00
parent 9584156f9a
commit e1372061e1
6 changed files with 219 additions and 107 deletions

83
api.php
View file

@ -60,34 +60,56 @@ try {
case 'add_user': case 'add_user':
$data = json_decode(file_get_contents('php://input'), true); $data = json_decode(file_get_contents('php://input'), true);
$status = $data['status'] ?? 'active';
$department_id = $data['department_id'];
// Auto-relocate based on status
if ($status === 'on_leave' || $status === 'retired') {
$dept_name = ($status === 'on_leave') ? '휴직' : '퇴사';
$target_dept = $db->query("SELECT id FROM departments WHERE name = '$dept_name'")->fetchColumn();
if ($target_dept)
$department_id = $target_dept;
}
$stmt = $db->prepare("INSERT INTO users (emp_id, name, department_id, position, email, phone, mobile, accounting_type, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt = $db->prepare("INSERT INTO users (emp_id, name, department_id, position, email, phone, mobile, accounting_type, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([ $stmt->execute([
$data['emp_id'], $data['emp_id'],
$data['name'], $data['name'],
$data['department_id'], $department_id,
$data['position'], $data['position'],
$data['email'], $data['email'],
$data['phone'] ?? '', $data['phone'] ?? '',
$data['mobile'], $data['mobile'],
$data['accounting_type'], $data['accounting_type'],
$data['status'] ?? 'active' $status
]); ]);
echo json_encode(['success' => true]); echo json_encode(['success' => true]);
break; break;
case 'update_user': case 'update_user':
$data = json_decode(file_get_contents('php://input'), true); $data = json_decode(file_get_contents('php://input'), true);
$status = $data['status'];
$department_id = $data['department_id'];
// Auto-relocate based on status
if ($status === 'on_leave' || $status === 'retired') {
$dept_name = ($status === 'on_leave') ? '휴직' : '퇴사';
$target_dept = $db->query("SELECT id FROM departments WHERE name = '$dept_name'")->fetchColumn();
if ($target_dept)
$department_id = $target_dept;
}
$stmt = $db->prepare("UPDATE users SET emp_id = ?, name = ?, department_id = ?, position = ?, email = ?, phone = ?, mobile = ?, accounting_type = ?, status = ? WHERE id = ?"); $stmt = $db->prepare("UPDATE users SET emp_id = ?, name = ?, department_id = ?, position = ?, email = ?, phone = ?, mobile = ?, accounting_type = ?, status = ? WHERE id = ?");
$stmt->execute([ $stmt->execute([
$data['emp_id'], $data['emp_id'],
$data['name'], $data['name'],
$data['department_id'], $department_id,
$data['position'], $data['position'],
$data['email'], $data['email'],
$data['phone'] ?? '', $data['phone'] ?? '',
$data['mobile'], $data['mobile'],
$data['accounting_type'], $data['accounting_type'],
$data['status'], $status,
$data['id'] $data['id']
]); ]);
echo json_encode(['success' => true]); echo json_encode(['success' => true]);
@ -352,8 +374,49 @@ try {
case 'update_dept': case 'update_dept':
$data = json_decode(file_get_contents('php://input'), true); $data = json_decode(file_get_contents('php://input'), true);
$stmt = $db->prepare("UPDATE departments SET name = ?, parent_id = ? WHERE id = ?"); $new_name = $data['name'];
$stmt->execute([$data['name'], $data['parent_id'] ?: null, $data['id']]); $parent_id = $data['parent_id'] ?: null;
$dept_id = $data['id'];
$merge_target_id = $data['merge_target_id'] ?? null;
if ($merge_target_id) {
// Scenario: Merge members to an existing department with the same name
$db->prepare("UPDATE users SET department_id = ? WHERE department_id = ?")->execute([$merge_target_id, $dept_id]);
// Recursively move children? For now, we delete the source dept after merging members
$db->prepare("DELETE FROM departments WHERE id = ?")->execute([$dept_id]);
echo json_encode(['success' => true, 'merged' => true]);
} else {
// Check if a department with the same name exists under the same parent (excluding itself)
$check_stmt = $db->prepare("SELECT id FROM departments WHERE name = ? AND (parent_id <=> ?) AND id != ?");
$check_stmt->execute([$new_name, $parent_id, $dept_id]);
$existing = $check_stmt->fetch();
if ($existing) {
echo json_encode(['success' => false, 'conflict' => true, 'existing_id' => $existing['id']]);
} else {
$stmt = $db->prepare("UPDATE departments SET name = ?, parent_id = ? WHERE id = ?");
$stmt->execute([$new_name, $parent_id, $dept_id]);
echo json_encode(['success' => true]);
}
}
break;
case 'delete_dept':
$dept_id = $_GET['id'];
// 1. Find the '미소속' department ID
$miso_id = $db->query("SELECT id FROM departments WHERE name = '미소속'")->fetchColumn();
if (!$miso_id) {
// Fallback creation if not exists
$db->exec("INSERT INTO departments (name, level) VALUES ('미소속', 0)");
$miso_id = $db->lastInsertId();
}
// 2. Move members to '미소속'
$db->prepare("UPDATE users SET department_id = ? WHERE department_id = ?")->execute([$miso_id, $dept_id]);
// 3. Delete the department
$db->prepare("DELETE FROM departments WHERE id = ?")->execute([$dept_id]);
echo json_encode(['success' => true]); echo json_encode(['success' => true]);
break; break;
@ -500,6 +563,14 @@ try {
break; break;
} }
// Enhanced logic: if status is changed to leave/retired, override dept
if ($newStatus === 'on_leave' || $newStatus === 'retired') {
$dept_name = ($newStatus === 'on_leave') ? '휴직' : '퇴사';
$target_dept = $db->query("SELECT id FROM departments WHERE name = '$dept_name'")->fetchColumn();
if ($target_dept)
$newDeptId = $target_dept;
}
$sql = "UPDATE users SET "; $sql = "UPDATE users SET ";
$params = []; $params = [];
$updates = []; $updates = [];

View file

@ -37,34 +37,38 @@
카드 등록</button> 카드 등록</button>
</header> </header>
<!-- Bulk Actions --> <!-- Bulk Actions (Fixed Floating Bar) -->
<div x-show="selectedIds.length > 0" x-transition x-cloak <div x-show="selectedIds.length > 0" x-transition x-cloak
class="mb-6 bg-slate-900 text-white px-6 py-3 rounded-2xl flex items-center justify-between shadow-xl"> class="fixed bottom-10 left-10 z-[200] bg-slate-900 text-white px-6 py-4 rounded-3xl flex items-center gap-6 shadow-2xl border border-white/10 animate-in fade-in slide-in-from-left-4 duration-300">
<div class="flex items-center gap-4"> <div class="flex items-center gap-2">
<div class="flex items-center gap-2"> <div class="w-10 h-10 bg-emerald-600 rounded-full flex items-center justify-center font-black text-sm shadow-lg shadow-emerald-500/30"
<span class="text-emerald-400 font-black" x-text="selectedIds.length"></span> x-text="selectedIds.length"></div>
<span class="text-xs font-bold text-slate-400"> 선택됨</span> <div class="flex flex-col">
</div> <span class="text-[10px] font-black text-slate-400 uppercase tracking-tighter">Selected</span>
<div class="h-4 w-px bg-slate-700"></div> <span class="text-xs font-bold">출입증 선택됨</span>
<div class="flex items-center gap-3">
<span class="text-xs font-bold text-slate-400 uppercase">일괄 변경:</span>
<select x-model="bulkStatus"
class="bg-slate-800 border-none rounded-lg text-xs font-bold px-3 py-1.5 focus:ring-1 focus:ring-emerald-500">
<option value="">상태 변경...</option>
<option value="available">가용됨(available)</option>
<option value="in_use">사용중(in_use)</option>
</select>
<input type="text" x-model="bulkCardType" placeholder="카드 종류 일괄 입력..."
class="bg-slate-800 border-none rounded-lg text-xs font-bold px-3 py-1.5 focus:ring-1 focus:ring-emerald-500 w-48">
<button @click="applyBulkUpdate"
class="bg-emerald-500 hover:bg-emerald-600 px-4 py-1.5 rounded-lg text-xs font-black transition-all">적용</button>
</div> </div>
</div> </div>
<button @click="selectedIds = []" class="text-slate-400 hover:text-white transition-colors"> <div class="h-8 w-px bg-white/10 mx-2"></div>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <div class="flex items-center gap-3">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> <select x-model="bulkStatus"
</svg> class="bg-slate-800 border-none rounded-xl text-xs font-bold px-4 py-2 focus:ring-2 focus:ring-emerald-500 appearance-none shadow-inner min-w-[150px]">
</button> <option value="">상태 변경...</option>
<option value="available">가용됨(available)</option>
<option value="in_use">사용중(in_use)</option>
</select>
<input type="text" x-model="bulkCardType" placeholder="카드 종류 일괄 입력..."
class="bg-slate-800 border-none rounded-xl text-xs font-bold px-4 py-2 focus:ring-2 focus:ring-emerald-500 shadow-inner w-48">
<button @click="applyBulkUpdate"
class="bg-emerald-500 hover:bg-emerald-600 px-6 py-2 rounded-xl text-xs font-black transition-all shadow-lg shadow-emerald-500/20 active:scale-95">일괄
적용</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">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div> </div>
<!-- Card List Table --> <!-- Card List Table -->

View file

@ -86,7 +86,13 @@
<div x-show="showModal" x-cloak class="fixed inset-0 z-[110] flex items-center justify-center p-4"> <div x-show="showModal" x-cloak class="fixed inset-0 z-[110] flex items-center justify-center p-4">
<div class="fixed inset-0 modal-bg" @click="showModal = false"></div> <div class="fixed inset-0 modal-bg" @click="showModal = false"></div>
<div class="bg-white rounded-3xl p-8 max-w-md w-full relative z-[111] shadow-2xl"> <div class="bg-white rounded-3xl p-8 max-w-md w-full relative z-[111] shadow-2xl">
<h3 class="text-2xl font-black mb-6" x-text="isEdit ? '부서 정보 수정' : '신규 부서 생성'"></h3> <div class="flex justify-between items-center mb-6">
<h3 class="text-2xl font-black text-slate-900" x-text="isEdit ? '부서 정보 수정' : '신규 부서 생성'"></h3>
<button x-show="isEdit" type="button" @click="deleteDept()"
class="text-xs font-bold text-rose-500 hover:text-rose-700 bg-rose-50 px-3 py-1.5 rounded-lg border border-rose-100 transition-colors">
부서 제거
</button>
</div>
<form @submit.prevent="submitDept" class="space-y-4"> <form @submit.prevent="submitDept" class="space-y-4">
<div> <div>
<label class="block text-xs font-bold text-slate-500 uppercase mb-2">부서명</label> <label class="block text-xs font-bold text-slate-500 uppercase mb-2">부서명</label>
@ -205,28 +211,50 @@
this.showModal = true; this.showModal = true;
}, },
submitDept() { submitDept(mergeTargetId = null) {
const action = this.isEdit ? 'update_dept' : 'add_dept'; const action = this.isEdit ? 'update_dept' : 'add_dept';
// Calculate level based on parent if (!mergeTargetId && this.formData.parent_id) {
if (this.formData.parent_id) {
const parent = this.depts.find(d => d.id == this.formData.parent_id); const parent = this.depts.find(d => d.id == this.formData.parent_id);
this.formData.level = this.getDeptLevel(parent.path) + 1; this.formData.level = (parent ? this.getDeptLevel(parent.path) : 0) + 1;
} else { } else if (!mergeTargetId) {
this.formData.level = 0; this.formData.level = 0;
} }
const payload = { ...this.formData };
if (mergeTargetId) payload.merge_target_id = mergeTargetId;
fetch(`api.php?action=${action}`, { fetch(`api.php?action=${action}`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(this.formData) body: JSON.stringify(payload)
}).then(res => res.json()).then(data => { }).then(res => res.json()).then(data => {
if (data.success) { if (data.success) {
this.showModal = false; this.showModal = false;
this.fetchDepts(); this.fetchDepts();
if (data.merged) {
alert('부서원이 기존 부서로 이동되었으며, 해당 부서는 삭제되었습니다.');
}
} else if (data.conflict) {
if (confirm(`동일한 위치에 '${this.formData.name}' 부서가 이미 존재합니다.\n부서 정보를 통합하여 부서원을 이동시키겠습니까?`)) {
this.submitDept(data.existing_id);
}
} }
}); });
}, },
deleteDept() {
if (confirm(`정말로 '${this.formData.name}' 부서를 제거하시겠습니까?\n이 명령을 수행하면 소속된 부서원들은 자동으로 '[한국경제인협회] - 미소속' 부서로 이동됩니다.\n이 작업은 되돌릴 수 없습니다.`)) {
fetch(`api.php?action=delete_dept&id=${this.formData.id}`)
.then(res => res.json())
.then(data => {
if (data.success) {
this.showModal = false;
this.fetchDepts();
}
});
}
},
viewMembers(dept) { viewMembers(dept) {
this.selectedDept = dept; this.selectedDept = dept;
fetch(`api.php?action=get_dept_users&dept_id=${dept.id}`).then(res => res.json()).then(data => { fetch(`api.php?action=get_dept_users&dept_id=${dept.id}`).then(res => res.json()).then(data => {

View file

@ -52,40 +52,43 @@
</div> </div>
</header> </header>
<!-- Bulk Actions --> <!-- Bulk Actions (Fixed Floating Bar) -->
<div x-show="selectedIds.length > 0" x-transition x-cloak <div x-show="selectedIds.length > 0" x-transition x-cloak
class="mb-6 bg-slate-900 text-white px-6 py-3 rounded-2xl flex items-center justify-between shadow-xl"> class="fixed bottom-10 left-10 z-[200] bg-slate-900 text-white px-6 py-4 rounded-3xl flex items-center gap-6 shadow-2xl border border-white/10 animate-in fade-in slide-in-from-left-4 duration-300">
<div class="flex items-center gap-4"> <div class="flex items-center gap-2">
<div class="flex items-center gap-2"> <div class="w-10 h-10 bg-blue-600 rounded-full flex items-center justify-center font-black text-sm shadow-lg shadow-blue-500/30"
<span class="text-blue-400 font-black" x-text="selectedIds.length"></span> x-text="selectedIds.length"></div>
<span class="text-xs font-bold text-slate-400"> 선택됨</span> <div class="flex flex-col">
</div> <span class="text-[10px] font-black text-slate-400 uppercase tracking-tighter">Selected</span>
<div class="h-4 w-px bg-slate-700"></div> <span class="text-xs font-bold">자산 선택됨</span>
<div class="flex items-center gap-3">
<span class="text-xs font-bold text-slate-400 uppercase">일괄 변경:</span>
<select x-model="bulkStatus"
class="bg-slate-800 border-none rounded-lg text-xs font-bold px-3 py-1.5 focus:ring-1 focus:ring-blue-500">
<option value="">상태 변경...</option>
<option value="assigned">지급됨(assigned)</option>
<option value="stock">재고(stock)</option>
</select>
<select x-model="bulkModelId"
class="bg-slate-800 border-none rounded-lg text-xs font-bold px-3 py-1.5 focus:ring-1 focus:ring-blue-500">
<option value="">모델 변경...</option>
<template x-for="model in models" :key="model.id">
<option :value="model.id" x-text="'[' + model.manufacturer + '] ' + model.model_name">
</option>
</template>
</select>
<button @click="applyBulkUpdate"
class="bg-blue-500 hover:bg-blue-600 px-4 py-1.5 rounded-lg text-xs font-black transition-all">적용</button>
</div> </div>
</div> </div>
<button @click="selectedIds = []" class="text-slate-400 hover:text-white transition-colors"> <div class="h-8 w-px bg-white/10 mx-2"></div>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <div class="flex items-center gap-3">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> <select x-model="bulkStatus"
</svg> class="bg-slate-800 border-none rounded-xl text-xs font-bold px-4 py-2 focus:ring-2 focus:ring-blue-500 appearance-none shadow-inner min-w-[150px]">
</button> <option value="">상태 변경...</option>
<option value="assigned">지급됨(assigned)</option>
<option value="stock">재고(stock)</option>
</select>
<select x-model="bulkModelId"
class="bg-slate-800 border-none rounded-xl text-xs font-bold px-4 py-2 focus:ring-2 focus:ring-blue-500 appearance-none shadow-inner min-w-[200px]">
<option value="">모델 변경...</option>
<template x-for="model in models" :key="model.id">
<option :value="model.id" x-text="'[' + model.manufacturer + '] ' + model.model_name"></option>
</template>
</select>
<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>
<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">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div> </div>
<!-- Laptop List Table --> <!-- Laptop List Table -->

54
mfp.php
View file

@ -37,34 +37,38 @@
계정 등록</button> 계정 등록</button>
</header> </header>
<!-- Bulk Actions --> <!-- Bulk Actions (Fixed Floating Bar) -->
<div x-show="selectedIds.length > 0" x-transition x-cloak <div x-show="selectedIds.length > 0" x-transition x-cloak
class="mb-6 bg-slate-900 text-white px-6 py-3 rounded-2xl flex items-center justify-between shadow-xl"> class="fixed bottom-10 left-10 z-[200] bg-slate-900 text-white px-6 py-4 rounded-3xl flex items-center gap-6 shadow-2xl border border-white/10 animate-in fade-in slide-in-from-left-4 duration-300">
<div class="flex items-center gap-4"> <div class="flex items-center gap-2">
<div class="flex items-center gap-2"> <div class="w-10 h-10 bg-amber-600 rounded-full flex items-center justify-center font-black text-sm shadow-lg shadow-amber-500/30"
<span class="text-amber-400 font-black" x-text="selectedIds.length"></span> x-text="selectedIds.length"></div>
<span class="text-xs font-bold text-slate-400"> 선택됨</span> <div class="flex flex-col">
</div> <span class="text-[10px] font-black text-slate-400 uppercase tracking-tighter">Selected</span>
<div class="h-4 w-px bg-slate-700"></div> <span class="text-xs font-bold">계정 선택됨</span>
<div class="flex items-center gap-3">
<span class="text-xs font-bold text-slate-400 uppercase">일괄 변경:</span>
<select x-model="bulkStatus"
class="bg-slate-800 border-none rounded-lg text-xs font-bold px-3 py-1.5 focus:ring-1 focus:ring-amber-500">
<option value="">상태 변경...</option>
<option value="active">사용중(active)</option>
<option value="inactive">비활성(inactive)</option>
</select>
<input type="text" x-model="bulkPurpose" placeholder="사용 목적 일괄 입력..."
class="bg-slate-800 border-none rounded-lg text-xs font-bold px-3 py-1.5 focus:ring-1 focus:ring-amber-500 w-48">
<button @click="applyBulkUpdate"
class="bg-amber-500 hover:bg-amber-600 px-4 py-1.5 rounded-lg text-xs font-black transition-all">적용</button>
</div> </div>
</div> </div>
<button @click="selectedIds = []" class="text-slate-400 hover:text-white transition-colors"> <div class="h-8 w-px bg-white/10 mx-2"></div>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <div class="flex items-center gap-3">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> <select x-model="bulkStatus"
</svg> class="bg-slate-800 border-none rounded-xl text-xs font-bold px-4 py-2 focus:ring-2 focus:ring-amber-500 appearance-none shadow-inner min-w-[150px]">
</button> <option value="">상태 변경...</option>
<option value="active">사용중(active)</option>
<option value="inactive">비활성(inactive)</option>
</select>
<input type="text" x-model="bulkPurpose" placeholder="사용 목적 일괄 입력..."
class="bg-slate-800 border-none rounded-xl text-xs font-bold px-4 py-2 focus:ring-2 focus:ring-amber-500 shadow-inner w-48">
<button @click="applyBulkUpdate"
class="bg-amber-500 hover:bg-amber-600 px-6 py-2 rounded-xl text-xs font-black transition-all shadow-lg shadow-amber-500/20 active:scale-95">일괄
적용</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">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div> </div>
<!-- MFP List Table --> <!-- MFP List Table -->

View file

@ -98,36 +98,37 @@
</button> </button>
</div> </div>
<!-- Bulk Command Center (appears when checked) --> <!-- Bulk Command Center (Fixed Floating Bar) -->
<div x-show="selectedIds.length > 0" x-transition x-cloak <div x-show="selectedIds.length > 0" x-transition x-cloak
class="bg-slate-900 text-white px-6 py-3 rounded-2xl flex items-center gap-6 shadow-xl animate-in fade-in slide-in-from-top-4 duration-300"> class="fixed bottom-10 left-10 z-[200] bg-slate-900 text-white px-6 py-4 rounded-3xl flex items-center gap-6 shadow-2xl border border-white/10 animate-in fade-in slide-in-from-left-4 duration-300">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="text-blue-400 font-black" x-text="selectedIds.length"></span> <div class="w-10 h-10 bg-blue-600 rounded-full flex items-center justify-center font-black text-sm shadow-lg shadow-blue-500/30" x-text="selectedIds.length"></div>
<span class="text-xs font-bold text-slate-400"> 선택됨</span> <div class="flex flex-col">
<span class="text-[10px] font-black text-slate-400 uppercase tracking-tighter">Selected</span>
<span class="text-xs font-bold">인원 선택됨</span>
</div>
</div> </div>
<div class="h-4 w-px bg-slate-700"></div> <div class="h-8 w-px bg-white/10 mx-2"></div>
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<span class="text-xs font-bold text-slate-400 uppercase">일괄 변경:</span>
<select x-model="bulkStatus" <select x-model="bulkStatus"
class="bg-slate-800 border-none rounded-lg text-xs font-bold px-3 py-1.5 focus:ring-1 focus:ring-blue-500"> class="bg-slate-800 border-none rounded-xl text-xs font-bold px-4 py-2 focus:ring-2 focus:ring-blue-500 appearance-none shadow-inner min-w-[120px]">
<option value="">상태 변경...</option> <option value="">상태 변경...</option>
<option value="active">재직</option> <option value="active">재직</option>
<option value="retired">퇴사</option> <option value="retired">퇴사</option>
<option value="on_leave">휴직</option> <option value="on_leave">휴직</option>
</select> </select>
<select x-model="bulkDeptId" <select x-model="bulkDeptId"
class="max-w-[150px] bg-slate-800 border-none rounded-lg text-xs font-bold px-3 py-1.5 focus:ring-1 focus:ring-blue-500"> class="bg-slate-800 border-none rounded-xl text-xs font-bold px-4 py-2 focus:ring-2 focus:ring-blue-500 appearance-none shadow-inner min-w-[150px]">
<option value="">부서 이동...</option> <option value="">부서 이동...</option>
<template x-for="dept in depts" :key="dept.id"> <template x-for="dept in depts" :key="dept.id">
<option :value="dept.id" x-text="dept.name"></option> <option :value="dept.id" x-text="dept.name"></option>
</template> </template>
</select> </select>
<button @click="applyBulkUpdate" <button @click="applyBulkUpdate"
class="bg-blue-500 hover:bg-blue-600 px-4 py-1.5 rounded-lg text-xs font-black transition-all">적용</button> 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>
<button @click="selectedIds = []" class="text-slate-400 hover:text-white transition-colors"> <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"> <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" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
d="M6 18L18 6M6 6l12 12" />
</svg> </svg>
</button> </button>
</div> </div>
@ -198,7 +199,8 @@
</div> </div>
</td> </td>
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" @click="editUser(user)"> <td class="px-6 py-4 whitespace-nowrap cursor-pointer" @click="editUser(user)">
<div class="text-sm font-semibold text-slate-700" x-text="user.dept_name || '미소속'"> <div class="text-sm font-semibold text-slate-700"
x-text="user.dept_name ? user.dept_name.split(' > ').pop() : '미소속'">
</div> </div>
<div class="text-xs text-slate-400" x-text="user.position || '-'"></div> <div class="text-xs text-slate-400" x-text="user.position || '-'"></div>
</td> </td>