feat(daily-logs): 항목 추가 시 prompt 대신 모달 사용 및 datalist 자동완성

- prompt() 제거하고 모달에서 담당자 입력 처리
- datalist로 본사 사용자/부서 자동완성 지원
- 팀(부서) 먼저 표시되도록 순서 조정
- openQuickAddModal 함수 추가로 아코디언 항목 추가 연동
This commit is contained in:
2025-12-04 23:13:17 +09:00
parent 1930c2ef9f
commit c91dbe7c91
2 changed files with 76 additions and 60 deletions

View File

@@ -289,8 +289,22 @@ class="bg-white rounded-lg shadow-sm overflow-hidden">
</div>
<div class="mb-4 p-3 bg-gray-50 rounded-lg">
<span class="text-xs text-gray-500">담당자</span>
<p id="pendingEditAssigneeName" class="font-medium text-gray-900"></p>
<label class="text-xs text-gray-500 block mb-1">담당자</label>
<!-- 기존 항목 수정 : 텍스트 표시 -->
<p id="pendingEditAssigneeNameText" class="font-medium text-gray-900 hidden"></p>
<!-- 항목 추가 : 입력 필드 (datalist로 자동완성) -->
<input type="text" id="pendingEditAssigneeNameInput"
list="assigneeDatalist"
class="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 hidden"
placeholder="담당자 이름 입력 또는 선택" autocomplete="off" required>
<datalist id="assigneeDatalist">
@foreach($assignees['teams'] ?? [] as $team)
<option value="{{ $team['name'] }}"></option>
@endforeach
@foreach($assignees['users'] ?? [] as $user)
<option value="{{ $user['name'] }}"></option>
@endforeach
</datalist>
</div>
<form id="pendingEditForm" onsubmit="submitPendingEditEntries(event)">
@@ -819,35 +833,9 @@ function deleteTableEntry(logId, entryId) {
}
}
// 테이블 빠른 항목 추가
// 테이블 빠른 항목 추가 - 미완료 항목 수정 모달 사용
function openQuickAddTableEntry(logId) {
const content = prompt('업무 내용을 입력하세요:');
if (content && content.trim()) {
const assigneeName = prompt('담당자 이름을 입력하세요:');
if (assigneeName && assigneeName.trim()) {
fetch(`/api/admin/daily-logs/${logId}/entries`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({
assignee_type: 'user',
assignee_name: assigneeName.trim(),
content: content.trim(),
status: 'todo'
})
})
.then(res => res.json())
.then(result => {
if (result.success) {
loadTableAccordionContent(logId);
} else {
alert(result.message || '오류가 발생했습니다.');
}
});
}
}
openQuickAddModal(logId);
}
// HTMX 로드 완료 후 테이블 아코디언 상태 리셋
@@ -977,13 +965,18 @@ class="p-0.5 text-green-500 hover:bg-green-50 rounded" title="완료">
// ========================================
let pendingEditEntries = [];
let pendingEditAssigneeName = '';
let pendingEditFromAccordion = null; // 아코디언에서 열렸으면 logId 저장
// 모달 열기
// 모달 열기 (기존 항목 수정)
function openPendingEditModal(entriesJson, assigneeName) {
pendingEditEntries = entriesJson;
pendingEditAssigneeName = assigneeName;
pendingEditFromAccordion = null; // 기존 항목 수정 모드
document.getElementById('pendingEditAssigneeName').textContent = assigneeName;
// 담당자 텍스트 표시, 입력 필드 숨김
document.getElementById('pendingEditAssigneeNameText').textContent = assigneeName;
document.getElementById('pendingEditAssigneeNameText').classList.remove('hidden');
document.getElementById('pendingEditAssigneeNameInput').classList.add('hidden');
// 컨테이너 초기화 및 항목 추가
const container = document.getElementById('pendingEditEntriesContainer');
@@ -996,11 +989,37 @@ function openPendingEditModal(entriesJson, assigneeName) {
document.getElementById('pendingEditModal').classList.remove('hidden');
}
// 모달 열기 (새 항목 추가 - 아코디언에서)
function openQuickAddModal(logId) {
pendingEditEntries = [{ id: '', content: '', status: 'todo', daily_log_id: logId }];
pendingEditAssigneeName = '';
pendingEditFromAccordion = logId;
// 담당자 입력 필드 표시, 텍스트 숨김
document.getElementById('pendingEditAssigneeNameText').classList.add('hidden');
const assigneeInput = document.getElementById('pendingEditAssigneeNameInput');
assigneeInput.value = '';
assigneeInput.classList.remove('hidden');
// 컨테이너 초기화 및 빈 항목 추가
const container = document.getElementById('pendingEditEntriesContainer');
container.innerHTML = '';
addPendingEntryRow({ id: '', content: '', status: 'todo', daily_log_id: logId }, 0);
document.getElementById('pendingEditModal').classList.remove('hidden');
// 담당자 입력 필드에 포커스
setTimeout(() => {
assigneeInput.focus();
}, 100);
}
// 모달 닫기
function closePendingEditModal() {
document.getElementById('pendingEditModal').classList.add('hidden');
pendingEditEntries = [];
pendingEditAssigneeName = '';
pendingEditFromAccordion = null;
}
// 항목 행 추가
@@ -1012,6 +1031,12 @@ function addPendingEntryRow(entry = null, index = null) {
const currentStatus = entry?.status || 'todo';
// 새 항목인 경우 기존 항목의 daily_log_id 사용
let dailyLogId = entry?.daily_log_id || '';
if (!dailyLogId && pendingEditEntries.length > 0) {
dailyLogId = pendingEditEntries[0].daily_log_id || '';
}
const html = `
<div class="pending-edit-row flex gap-2 items-start p-2 bg-gray-50 rounded-lg" data-entry-id="${entry?.id || ''}" data-index="${index}">
<!-- 상태 버튼 그룹 -->
@@ -1039,7 +1064,7 @@ class="w-full px-3 py-1.5 text-sm border border-gray-300 rounded-lg focus:ring-2
placeholder="업무 내용">${escapeHtml(entry?.content || '')}</textarea>
</div>
<input type="hidden" name="pending_entries[${index}][id]" value="${entry?.id || ''}">
<input type="hidden" name="pending_entries[${index}][daily_log_id]" value="${entry?.daily_log_id || ''}">
<input type="hidden" name="pending_entries[${index}][daily_log_id]" value="${dailyLogId}">
<button type="button" onclick="removePendingEntryRow(this)" class="p-1.5 text-red-500 hover:bg-red-50 rounded shrink-0 pt-1" title="삭제">
<svg class="w-4 h-4" 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"/>
@@ -1097,6 +1122,18 @@ function reindexPendingEntryRows() {
function submitPendingEditEntries(event) {
event.preventDefault();
// 새 항목 추가 모드일 때 입력 필드에서 담당자 이름 가져오기
let assigneeName = pendingEditAssigneeName;
if (pendingEditFromAccordion) {
const inputField = document.getElementById('pendingEditAssigneeNameInput');
assigneeName = inputField.value.trim();
if (!assigneeName) {
alert('담당자 이름을 입력해주세요.');
inputField.focus();
return;
}
}
const submitBtn = document.getElementById('pendingEditSubmitBtn');
submitBtn.disabled = true;
submitBtn.textContent = '저장 중...';
@@ -1152,7 +1189,7 @@ function submitPendingEditEntries(event) {
},
body: JSON.stringify({
assignee_type: 'user',
assignee_name: pendingEditAssigneeName,
assignee_name: assigneeName,
content,
status
})

View File

@@ -348,32 +348,11 @@ function deleteCardEntry(logId, entryId) {
}
function openQuickAddCardEntry(logId) {
const content = prompt('업무 내용을 입력하세요:');
if (content && content.trim()) {
const assigneeName = prompt('담당자 이름을 입력하세요:');
if (assigneeName && assigneeName.trim()) {
fetch(`/api/admin/daily-logs/${logId}/entries`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content || ''
},
body: JSON.stringify({
assignee_type: 'user',
assignee_name: assigneeName.trim(),
content: content.trim(),
status: 'todo'
})
})
.then(res => res.json())
.then(result => {
if (result.success) {
loadCardAccordionContent(logId);
} else {
alert(result.message || '오류가 발생했습니다.');
}
});
}
// 부모 페이지의 openQuickAddModal 함수 사용 (prompt 대신 모달에서 담당자 입력)
if (typeof openQuickAddModal === 'function') {
openQuickAddModal(logId);
} else {
alert('모달을 열 수 없습니다. 페이지를 새로고침해주세요.');
}
}