feat: [equipment] 점검항목 다른 주기로 복사 기능 추가
- 서비스: copyTemplatesToCycles 메서드 추가 (중복 항목 스킵) - 컨트롤러: copyTemplates API 엔드포인트 추가 - UI: 다른 주기에 복사 버튼 + 체크박스 모달
This commit is contained in:
@@ -2,10 +2,17 @@
|
||||
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
|
||||
<div class="flex justify-between items-center mb-4 pb-2 border-b">
|
||||
<h2 class="text-lg font-semibold text-gray-800">점검항목 템플릿</h2>
|
||||
<button onclick="document.getElementById('templateModal').classList.remove('hidden')"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded-lg text-sm transition">
|
||||
+ 항목 추가
|
||||
</button>
|
||||
<div class="flex gap-2">
|
||||
<button onclick="openCopyModal()"
|
||||
class="bg-green-600 hover:bg-green-700 text-white px-3 py-1.5 rounded-lg text-sm transition"
|
||||
id="copyTemplateBtn" style="display: none;">
|
||||
다른 주기에 복사
|
||||
</button>
|
||||
<button onclick="document.getElementById('templateModal').classList.remove('hidden')"
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1.5 rounded-lg text-sm transition">
|
||||
+ 항목 추가
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php
|
||||
@@ -144,8 +151,45 @@ class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">추가</bu
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 다른 주기에 복사 모달 -->
|
||||
<div id="copyTemplateModal" class="fixed inset-0 z-50 hidden">
|
||||
<div class="fixed inset-0 bg-black/50" onclick="document.getElementById('copyTemplateModal').classList.add('hidden')"></div>
|
||||
<div class="fixed inset-0 flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-xl shadow-xl w-full max-w-md">
|
||||
<div class="flex justify-between items-center p-6 border-b">
|
||||
<h3 class="text-lg font-semibold">점검항목 복사</h3>
|
||||
<button onclick="document.getElementById('copyTemplateModal').classList.add('hidden')" class="text-gray-400 hover:text-gray-600">×</button>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<p class="text-sm text-gray-600 mb-4">
|
||||
<span id="copySourceLabel" class="font-semibold text-blue-700"></span> 점검항목을 선택한 주기에 복사합니다.
|
||||
</p>
|
||||
<div class="space-y-2 mb-6" id="copyTargetCycles">
|
||||
@foreach($allCycles as $code => $label)
|
||||
<label class="copy-cycle-option flex items-center gap-3 p-2 rounded-lg hover:bg-gray-50 cursor-pointer" data-cycle="{{ $code }}">
|
||||
<input type="checkbox" name="target_cycles[]" value="{{ $code }}"
|
||||
class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
|
||||
<span class="text-sm text-gray-700">{{ $label }}</span>
|
||||
<span class="copy-cycle-count text-xs text-gray-400 ml-auto"></span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="flex justify-end gap-3">
|
||||
<button type="button" onclick="document.getElementById('copyTemplateModal').classList.add('hidden')"
|
||||
class="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg text-sm">취소</button>
|
||||
<button type="button" onclick="executeCopyTemplates()"
|
||||
class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg text-sm" id="copyExecuteBtn">복사</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentTemplateTab = 'daily';
|
||||
|
||||
function switchTemplateTab(cycle) {
|
||||
currentTemplateTab = cycle;
|
||||
document.querySelectorAll('.tmpl-cycle-tab').forEach(btn => {
|
||||
if (btn.dataset.cycle === cycle) {
|
||||
btn.className = 'tmpl-cycle-tab px-3 py-1.5 rounded-md text-xs font-medium transition bg-white text-blue-700 shadow-sm';
|
||||
@@ -156,8 +200,80 @@ function switchTemplateTab(cycle) {
|
||||
document.querySelectorAll('.tmpl-cycle-content').forEach(el => {
|
||||
el.classList.toggle('hidden', el.dataset.cycle !== cycle);
|
||||
});
|
||||
// 모달의 주기 기본값도 전환
|
||||
const cycleSelect = document.getElementById('tmplInspectionCycle');
|
||||
if (cycleSelect) cycleSelect.value = cycle;
|
||||
updateCopyButton();
|
||||
}
|
||||
|
||||
function updateCopyButton() {
|
||||
const btn = document.getElementById('copyTemplateBtn');
|
||||
const content = document.querySelector(`.tmpl-cycle-content[data-cycle="${currentTemplateTab}"]`);
|
||||
const hasItems = content && content.querySelector('table');
|
||||
btn.style.display = hasItems ? '' : 'none';
|
||||
}
|
||||
|
||||
function openCopyModal() {
|
||||
const cycleLabels = @json($allCycles);
|
||||
document.getElementById('copySourceLabel').textContent = cycleLabels[currentTemplateTab];
|
||||
|
||||
document.querySelectorAll('.copy-cycle-option').forEach(el => {
|
||||
const code = el.dataset.cycle;
|
||||
const checkbox = el.querySelector('input[type="checkbox"]');
|
||||
if (code === currentTemplateTab) {
|
||||
el.style.display = 'none';
|
||||
checkbox.checked = false;
|
||||
} else {
|
||||
el.style.display = '';
|
||||
checkbox.checked = false;
|
||||
const countEl = el.querySelector('.copy-cycle-count');
|
||||
const tab = document.querySelector(`.tmpl-cycle-tab[data-cycle="${code}"]`);
|
||||
const badge = tab ? tab.querySelector('span') : null;
|
||||
countEl.textContent = badge ? `${badge.textContent.trim()}개 항목` : '';
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('copyTemplateModal').classList.remove('hidden');
|
||||
}
|
||||
|
||||
function executeCopyTemplates() {
|
||||
const checked = document.querySelectorAll('#copyTargetCycles input[type="checkbox"]:checked');
|
||||
if (checked.length === 0) {
|
||||
alert('복사할 주기를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetCycles = Array.from(checked).map(cb => cb.value);
|
||||
const equipmentId = @json($equipment->id);
|
||||
const btn = document.getElementById('copyExecuteBtn');
|
||||
btn.disabled = true;
|
||||
btn.textContent = '복사 중...';
|
||||
|
||||
fetch(`/api/admin/equipment/${equipmentId}/templates/copy`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
source_cycle: currentTemplateTab,
|
||||
target_cycles: targetCycles,
|
||||
}),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert(data.message);
|
||||
location.reload();
|
||||
} else {
|
||||
alert(data.message || '복사 실패');
|
||||
}
|
||||
})
|
||||
.catch(() => alert('오류가 발생했습니다.'))
|
||||
.finally(() => {
|
||||
btn.disabled = false;
|
||||
btn.textContent = '복사';
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => updateCopyButton());
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user