Files
sam-manage/resources/views/boards/index.blade.php
kent 0db6e99a22 feat(board): 슈퍼관리자 삭제 게시물 관리 및 회사명 표시 기능 추가
## 슈퍼관리자 삭제 게시물 관리
- 삭제된 게시물 목록에 표시 (빨간색 배경, 취소선)
- 게시물 복원 기능 추가 (POST /{post}/restore)
- 게시물 영구삭제 기능 추가 (DELETE /{post}/force)
- 통계 카드에 삭제됨 카운트 추가

## 페이지 타이틀 회사명 표시
- /boards: "회사명 게시판 관리" 형식으로 표시
- /boards/{code}/posts: "회사명 게시판명" 형식으로 표시
- 회사명 파란색으로 구분 표시

## 버그 수정
- 통계 카드 CSS: Tailwind 동적 클래스 문제 해결
  (grid-cols-{{ }} → 정적 클래스로 변경)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 09:11:21 +09:00

163 lines
5.6 KiB
PHP

@extends('layouts.app')
@section('title', ($currentTenant?->company_name ?? '') . ' 게시판 관리')
@section('content')
<!-- 페이지 헤더 -->
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4 mb-6">
<h1 class="text-2xl font-bold text-gray-800">
@if($currentTenant?->company_name)
<span class="text-blue-600">{{ $currentTenant->company_name }}</span>
@endif
게시판 관리
</h1>
<a href="{{ route('boards.create') }}" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition text-center w-full sm:w-auto">
+ 게시판
</a>
</div>
<!-- 필터 영역 -->
<x-filter-collapsible id="boardFilter">
<form id="filterForm" class="flex flex-wrap gap-2 sm:gap-4">
<!-- 검색 -->
<div class="flex-1 min-w-0 w-full sm:w-auto">
<input type="text"
name="search"
placeholder="게시판명, 코드로 검색..."
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
<!-- 게시판 유형 필터 -->
<div class="w-full sm:w-40">
<select name="board_type" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="">전체 유형</option>
<option value="notice">공지사항</option>
<option value="qna">1:1 문의</option>
<option value="faq">FAQ</option>
<option value="free">자유게시판</option>
@foreach($boardTypes as $type)
@if(!in_array($type, ['notice', 'qna', 'faq', 'free']))
<option value="{{ $type }}">{{ $type }}</option>
@endif
@endforeach
</select>
</div>
<!-- 활성 상태 필터 -->
<div class="w-full sm:w-32">
<select name="is_active" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="">전체</option>
<option value="1">활성</option>
<option value="0">비활성</option>
</select>
</div>
<!-- 삭제된 항목 포함 -->
<div class="w-full sm:w-36">
<select name="trashed" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<option value="">활성만</option>
<option value="with">삭제 포함</option>
<option value="only">삭제만</option>
</select>
</div>
<!-- 검색 버튼 -->
<button type="submit" class="bg-gray-600 hover:bg-gray-700 text-white px-6 py-2 rounded-lg transition w-full sm:w-auto">
검색
</button>
</form>
</x-filter-collapsible>
<!-- 테이블 영역 -->
<div id="board-table" class="bg-white rounded-lg shadow-sm overflow-hidden">
<!-- 로딩 스피너 -->
<div class="flex justify-center items-center p-12">
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
</div>
</div>
<!-- 인라인 스크립트 (HTMX 스왑 후에도 실행됨) -->
<script>
(function() {
const csrfToken = '{{ csrf_token() }}';
const boardTable = document.getElementById('board-table');
const filterForm = document.getElementById('filterForm');
// 테이블 로드 함수
function loadTable() {
const formData = new FormData(filterForm);
const params = new URLSearchParams(formData).toString();
fetch(`/api/admin/boards?${params}`, {
headers: {
'X-CSRF-TOKEN': csrfToken,
'HX-Request': 'true'
}
})
.then(response => response.text())
.then(html => {
boardTable.innerHTML = html;
})
.catch(error => {
console.error('Error:', error);
});
}
// 폼 제출 이벤트
filterForm.addEventListener('submit', function(e) {
e.preventDefault();
loadTable();
});
// 삭제 확인
window.confirmDelete = function(id, name) {
showDeleteConfirm(name, () => {
fetch(`/api/admin/boards/${id}`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': csrfToken
}
}).then(() => loadTable());
});
};
// 복원 확인
window.confirmRestore = function(id, name) {
showConfirm(`"${name}" 게시판을 복원하시겠습니까?`, () => {
fetch(`/api/admin/boards/${id}/restore`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken
}
}).then(() => loadTable());
}, { title: '복원 확인', icon: 'question' });
};
// 영구삭제 확인
window.confirmForceDelete = function(id, name) {
showPermanentDeleteConfirm(name, () => {
fetch(`/api/admin/boards/${id}/force`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': csrfToken
}
}).then(() => loadTable());
});
};
// 활성/비활성 토글
window.toggleActive = function(id) {
fetch(`/api/admin/boards/${id}/toggle-active`, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken
}
}).then(() => loadTable());
};
// 즉시 테이블 로드
loadTable();
})();
</script>
@endsection