리셋
This commit is contained in:
parent
3e1cd3adab
commit
cfeea88124
7 changed files with 247 additions and 41 deletions
49
cards.php
49
cards.php
|
|
@ -27,15 +27,29 @@
|
|||
<?php include 'nav.php'; ?>
|
||||
|
||||
<main class="max-w-[1600px] mx-auto p-8 pt-10">
|
||||
<header class="mb-10 flex justify-between items-center">
|
||||
<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">출입증 관리</h2>
|
||||
<p class="text-slate-500 mt-1">보안실 연동 임시 출입증 및 NFC ID 관리</p>
|
||||
</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-emerald-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-emerald-500 transition-all text-sm shadow-sm"
|
||||
placeholder="카드번호, 종류, NFC ID 검색...">
|
||||
</div>
|
||||
<button
|
||||
@click="showModal = true; isEdit = false; formData = { id: '', card_number: '', card_type: '', nfc_id: '' }"
|
||||
class="bg-emerald-600 text-white px-5 py-2.5 rounded-xl font-bold shadow-lg shadow-emerald-200 hover:bg-emerald-700 transition-all">신규
|
||||
class="bg-emerald-600 text-white px-5 py-2.5 rounded-xl font-bold shadow-lg shadow-emerald-200 hover:bg-emerald-700 transition-all shrink-0">신규
|
||||
카드 등록</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Bulk Actions (Fixed Floating Bar) -->
|
||||
|
|
@ -73,7 +87,8 @@
|
|||
</div>
|
||||
|
||||
<!-- Card List Table -->
|
||||
<div class="bg-white rounded-3xl shadow-sm border border-slate-200 overflow-hidden" x-show="cards.length > 0">
|
||||
<div class="bg-white rounded-3xl shadow-sm border border-slate-200 overflow-hidden"
|
||||
x-show="!loading && filteredCards.length > 0">
|
||||
<table class="min-w-full divide-y divide-slate-100">
|
||||
<thead class="bg-slate-50/50">
|
||||
<tr>
|
||||
|
|
@ -92,7 +107,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-50">
|
||||
<template x-for="card in cards" :key="card.id">
|
||||
<template x-for="card in filteredCards" :key="card.id">
|
||||
<tr class="hover:bg-slate-50/80 transition-colors group">
|
||||
<td class="px-6 py-4">
|
||||
<input type="checkbox" :value="card.id" x-model="selectedIds"
|
||||
|
|
@ -119,6 +134,19 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div x-show="loading" class="p-20 flex justify-center">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-emerald-600"></div>
|
||||
</div>
|
||||
<div x-show="!loading && filteredCards.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>
|
||||
|
||||
<!-- Card Modal -->
|
||||
|
|
@ -154,17 +182,30 @@
|
|||
showModal: false,
|
||||
isEdit: false,
|
||||
selectedIds: [],
|
||||
loading: true,
|
||||
searchQuery: '',
|
||||
bulkStatus: '',
|
||||
bulkCardType: '',
|
||||
formData: { id: '', card_number: '', card_type: '', nfc_id: '' },
|
||||
init() { this.fetchCards(); },
|
||||
fetchCards() {
|
||||
const scrollPos = window.scrollY;
|
||||
this.loading = true;
|
||||
fetch('api.php?action=get_cards').then(res => res.json()).then(data => {
|
||||
this.cards = data;
|
||||
this.loading = false;
|
||||
this.$nextTick(() => window.scrollTo(0, scrollPos));
|
||||
});
|
||||
},
|
||||
get filteredCards() {
|
||||
if (!this.searchQuery) return this.cards;
|
||||
const q = this.searchQuery.toLowerCase();
|
||||
return this.cards.filter(c =>
|
||||
(c.card_number && c.card_number.toLowerCase().includes(q)) ||
|
||||
(c.card_type && c.card_type.toLowerCase().includes(q)) ||
|
||||
(c.nfc_id && c.nfc_id.toLowerCase().includes(q))
|
||||
);
|
||||
},
|
||||
toggleSelectAll(checked) {
|
||||
this.selectedIds = checked ? this.cards.map(c => c.id) : [];
|
||||
},
|
||||
|
|
|
|||
6
check_admins.php
Normal file
6
check_admins.php
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
require_once 'config.php';
|
||||
$stmt = $db->query("SELECT * FROM administrators");
|
||||
$admins = $stmt->fetchAll();
|
||||
print_r($admins);
|
||||
?>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<?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";
|
||||
}
|
||||
?>
|
||||
|
|
@ -44,18 +44,33 @@
|
|||
<h2 class="text-3xl font-extrabold text-slate-900 tracking-tight">일반 물품 임대</h2>
|
||||
<p class="text-slate-500 mt-1">사원별 각종 물품(어댑터, 주변기기 등) 단기 임대 및 반납 기록</p>
|
||||
</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="사원명, 품목 검색...">
|
||||
</div>
|
||||
<button @click="openAddModal()"
|
||||
class="px-6 py-3 bg-blue-600 text-white rounded-2xl font-bold shadow-lg shadow-blue-200 hover:bg-blue-700 transition-all flex items-center gap-2">
|
||||
class="px-6 py-3 bg-blue-600 text-white rounded-2xl font-bold shadow-lg shadow-blue-200 hover:bg-blue-700 transition-all flex items-center gap-2 shrink-0">
|
||||
<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="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
임대 등록
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Rental Cards Grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
<template x-for="rental in rentals" :key="rental.id">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"
|
||||
x-show="!loading && filteredRentals.length > 0">
|
||||
<template x-for="rental in filteredRentals" :key="rental.id">
|
||||
<div class="bg-white rounded-[2rem] p-6 shadow-sm border border-slate-100 hover:shadow-xl transition-all relative overflow-hidden flex flex-col h-full"
|
||||
:class="rental.status === 'returned' ? 'opacity-75' : ''">
|
||||
|
||||
|
|
@ -149,6 +164,19 @@
|
|||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<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 && filteredRentals.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>
|
||||
|
||||
<!-- Add Rental Modal -->
|
||||
|
|
@ -238,6 +266,8 @@
|
|||
return {
|
||||
rentals: [],
|
||||
users: [],
|
||||
loading: true,
|
||||
searchQuery: '',
|
||||
showAddModal: false,
|
||||
formData: {
|
||||
user_id: '',
|
||||
|
|
@ -253,11 +283,24 @@
|
|||
},
|
||||
|
||||
fetchRentals() {
|
||||
const scrollPos = window.scrollY;
|
||||
this.loading = true;
|
||||
fetch('api.php?action=get_general_rentals').then(res => res.json()).then(data => {
|
||||
this.rentals = data;
|
||||
this.loading = false;
|
||||
this.$nextTick(() => window.scrollTo(0, scrollPos));
|
||||
});
|
||||
},
|
||||
|
||||
get filteredRentals() {
|
||||
if (!this.searchQuery) return this.rentals;
|
||||
const q = this.searchQuery.toLowerCase();
|
||||
return this.rentals.filter(r =>
|
||||
(r.user_name && r.user_name.toLowerCase().includes(q)) ||
|
||||
(r.items && r.items.toLowerCase().includes(q))
|
||||
);
|
||||
},
|
||||
|
||||
fetchUsers() {
|
||||
fetch('api.php?action=get_users').then(res => res.json()).then(data => {
|
||||
this.users = data;
|
||||
|
|
|
|||
48
mfp.php
48
mfp.php
|
|
@ -27,15 +27,29 @@
|
|||
<?php include 'nav.php'; ?>
|
||||
|
||||
<main class="max-w-[1600px] mx-auto p-8 pt-10">
|
||||
<header class="mb-10 flex justify-between items-center">
|
||||
<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">복합기 계정 관리</h2>
|
||||
<p class="text-slate-500 mt-1">임시/공용 복합기 계정 및 비밀번호 관리</p>
|
||||
</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-amber-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-amber-500 transition-all text-sm shadow-sm"
|
||||
placeholder="계정 ID, 사용 목적 검색...">
|
||||
</div>
|
||||
<button
|
||||
@click="showModal = true; isEdit = false; formData = { id: '', account_id: '', account_pw: '', purpose: '' }"
|
||||
class="bg-amber-600 text-white px-5 py-2.5 rounded-xl font-bold shadow-lg shadow-amber-200 hover:bg-amber-700 transition-all">신규
|
||||
class="bg-amber-600 text-white px-5 py-2.5 rounded-xl font-bold shadow-lg shadow-amber-200 hover:bg-amber-700 transition-all shrink-0">신규
|
||||
계정 등록</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Bulk Actions (Fixed Floating Bar) -->
|
||||
|
|
@ -73,7 +87,8 @@
|
|||
</div>
|
||||
|
||||
<!-- MFP List Table -->
|
||||
<div class="bg-white rounded-3xl shadow-sm border border-slate-200 overflow-hidden" x-show="mfpList.length > 0">
|
||||
<div class="bg-white rounded-3xl shadow-sm border border-slate-200 overflow-hidden"
|
||||
x-show="!loading && filteredMfp.length > 0">
|
||||
<table class="min-w-full divide-y divide-slate-100">
|
||||
<thead class="bg-slate-50/50">
|
||||
<tr>
|
||||
|
|
@ -92,7 +107,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-50">
|
||||
<template x-for="mfp in mfpList" :key="mfp.id">
|
||||
<template x-for="mfp in filteredMfp" :key="mfp.id">
|
||||
<tr class="hover:bg-slate-50/80 transition-colors group">
|
||||
<td class="px-6 py-4">
|
||||
<input type="checkbox" :value="mfp.id" x-model="selectedIds"
|
||||
|
|
@ -127,6 +142,19 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div x-show="loading" class="p-20 flex justify-center">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-amber-600"></div>
|
||||
</div>
|
||||
<div x-show="!loading && filteredMfp.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>
|
||||
|
||||
<!-- MFP Modal -->
|
||||
|
|
@ -161,17 +189,29 @@
|
|||
showModal: false,
|
||||
isEdit: false,
|
||||
selectedIds: [],
|
||||
loading: true,
|
||||
searchQuery: '',
|
||||
bulkStatus: '',
|
||||
bulkPurpose: '',
|
||||
formData: { id: '', account_id: '', account_pw: '', purpose: '' },
|
||||
init() { this.fetchMfp(); },
|
||||
fetchMfp() {
|
||||
const scrollPos = window.scrollY;
|
||||
this.loading = true;
|
||||
fetch('api.php?action=get_mfp').then(res => res.json()).then(data => {
|
||||
this.mfpList = data;
|
||||
this.loading = false;
|
||||
this.$nextTick(() => window.scrollTo(0, scrollPos));
|
||||
});
|
||||
},
|
||||
get filteredMfp() {
|
||||
if (!this.searchQuery) return this.mfpList;
|
||||
const q = this.searchQuery.toLowerCase();
|
||||
return this.mfpList.filter(m =>
|
||||
(m.account_id && m.account_id.toLowerCase().includes(q)) ||
|
||||
(m.purpose && m.purpose.toLowerCase().includes(q))
|
||||
);
|
||||
},
|
||||
toggleSelectAll(checked) {
|
||||
this.selectedIds = checked ? this.mfpList.map(m => m.id) : [];
|
||||
},
|
||||
|
|
|
|||
64
models.php
64
models.php
|
|
@ -36,14 +36,42 @@
|
|||
<h2 class="text-3xl font-extrabold text-slate-900 tracking-tight">DB 마스터 관리</h2>
|
||||
<p class="text-slate-500 mt-1">시스템 운영을 위한 기초 자산 모델 및 조직 정보를 관리합니다.</p>
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- Search Bar for Models -->
|
||||
<div x-show="currentTab === 'models'" 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="모델명, 제조사, CPU 검색...">
|
||||
</div>
|
||||
<!-- Search Bar for Departments -->
|
||||
<div x-show="currentTab === 'depts'" 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="deptSearchQuery"
|
||||
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="부서명 검색...">
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button x-show="currentTab === 'models'" @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">신규
|
||||
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 shrink-0">신규
|
||||
모델 등록</button>
|
||||
<button x-show="currentTab === 'depts'" @click="openAddDeptModal()"
|
||||
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">신규
|
||||
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 shrink-0">신규
|
||||
부서 생성</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Tabs -->
|
||||
|
|
@ -124,7 +152,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-50">
|
||||
<template x-for="model in models" :key="model.id">
|
||||
<template x-for="model in filteredModels" :key="model.id">
|
||||
<tr class="hover:bg-slate-50/80 transition-colors group">
|
||||
<td class="px-6 py-4">
|
||||
<input type="checkbox" :value="model.id" x-model="selectedIds"
|
||||
|
|
@ -172,6 +200,9 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div x-show="filteredModels.length === 0" class="p-20 text-center bg-white rounded-3xl border border-dashed border-slate-300 mt-6">
|
||||
<p class="text-slate-400 font-medium italic">일치하는 모델 정보가 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab 2: Departments -->
|
||||
|
|
@ -189,7 +220,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-50">
|
||||
<template x-for="dept in depts" :key="dept.id">
|
||||
<template x-for="dept in filteredDepts" :key="dept.id">
|
||||
<tr class="hover:bg-slate-50/80 transition-colors group">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="flex items-center">
|
||||
|
|
@ -219,6 +250,9 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div x-show="filteredDepts.length === 0" class="p-20 text-center bg-white rounded-3xl border border-dashed border-slate-300 mt-6">
|
||||
<p class="text-slate-400 font-medium italic">일치하는 부서 정보가 없습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
|
@ -445,6 +479,7 @@
|
|||
showModal: false,
|
||||
isEdit: false,
|
||||
selectedIds: [],
|
||||
searchQuery: '',
|
||||
bulkManufacturer: '',
|
||||
bulkProductName: '',
|
||||
formData: {
|
||||
|
|
@ -455,15 +490,34 @@
|
|||
asset_status: '', fixed_ip: '', assigned_user: '', purchase_date: '',
|
||||
power_rating: '', vendor: '', options: '', remarks: '', specs: ''
|
||||
},
|
||||
get filteredModels() {
|
||||
if (!this.searchQuery) return this.models;
|
||||
const q = this.searchQuery.toLowerCase();
|
||||
return this.models.filter(m =>
|
||||
(m.model_name && m.model_name.toLowerCase().includes(q)) ||
|
||||
(m.manufacturer && m.manufacturer.toLowerCase().includes(q)) ||
|
||||
(m.cpu && m.cpu.toLowerCase().includes(q)) ||
|
||||
(m.product_name && m.product_name.toLowerCase().includes(q))
|
||||
);
|
||||
},
|
||||
|
||||
// Dept Data
|
||||
depts: [],
|
||||
deptSearchQuery: '',
|
||||
showDeptModal: false,
|
||||
showMembersModal: false,
|
||||
isDeptEdit: false,
|
||||
selectedDept: null,
|
||||
members: [],
|
||||
deptFormData: { id: '', name: '', parent_id: '', level: 1 },
|
||||
get filteredDepts() {
|
||||
if (!this.deptSearchQuery) return this.depts;
|
||||
const q = this.deptSearchQuery.toLowerCase();
|
||||
return this.depts.filter(d =>
|
||||
(d.name && d.name.toLowerCase().includes(q)) ||
|
||||
(d.path && d.path.toLowerCase().includes(q))
|
||||
);
|
||||
},
|
||||
|
||||
init() {
|
||||
this.fetchModels();
|
||||
|
|
|
|||
31
reset_admin.php
Normal file
31
reset_admin.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
// administrators 테이블이 없으면 생성
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS administrators (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
login_id TEXT UNIQUE NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
admin_name TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)");
|
||||
|
||||
$login_id = 'admin';
|
||||
$password = 'admin1234';
|
||||
$admin_name = 'Admin';
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
$stmt = $db->prepare("SELECT id FROM administrators WHERE login_id = ?");
|
||||
$stmt->execute([$login_id]);
|
||||
if ($stmt->fetch()) {
|
||||
$stmt = $db->prepare("UPDATE administrators SET password_hash = ?, admin_name = ? WHERE login_id = ?");
|
||||
$stmt->execute([$hash, $admin_name, $login_id]);
|
||||
echo "기존 admin 계정의 비밀번호를 admin1234로 초기화했습니다.<br>";
|
||||
} else {
|
||||
$stmt = $db->prepare("INSERT INTO administrators (login_id, password_hash, admin_name) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$login_id, $hash, $admin_name]);
|
||||
echo "신규 admin 계정(PW: admin1234)을 생성했습니다.<br>";
|
||||
}
|
||||
|
||||
echo "<br><a href='login.php'>로그인 페이지로 이동</a>";
|
||||
?>
|
||||
Loading…
Reference in a new issue