feat: 체크리스트 이미지 미리보기 기능 구현
- 체크리스트 섹션에 이미지 썸네일 미리보기 추가 (16x16) - 대시보드 상단 체크리스트 카드에 이미지 미리보기 기능 추가 - 이미지 클릭 시 전체 화면 모달로 확대 보기 - 백엔드 image_url 컬럼을 TEXT 타입으로 변경하여 Base64 이미지 지원 - 파일 업로드를 이미지만 지원하도록 단순화 (file_url, file_name 제거) - 422 validation 오류 해결 및 상세 로깅 추가 - 체크리스트 렌더링 누락 문제 해결
This commit is contained in:
@@ -162,28 +162,15 @@
|
||||
}
|
||||
|
||||
// Todo 항목 로드
|
||||
function loadTodoItems() {
|
||||
// 임시 데이터 (실제로는 API에서 가져옴)
|
||||
const todoItems = [
|
||||
{
|
||||
id: 1,
|
||||
content: '프로젝트 기획서 작성',
|
||||
photo: null,
|
||||
start_date: '2024-01-20',
|
||||
status: 'scheduled',
|
||||
created_at: '2024-01-15'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
content: '팀 미팅 준비',
|
||||
photo: null,
|
||||
start_date: '2024-01-18',
|
||||
status: 'active',
|
||||
created_at: '2024-01-16'
|
||||
}
|
||||
];
|
||||
|
||||
renderTodoItems(todoItems);
|
||||
async function loadTodoItems() {
|
||||
try {
|
||||
// API에서 Todo 카테고리 항목들만 가져오기
|
||||
const items = await TodoAPI.getTodos(null, 'todo');
|
||||
renderTodoItems(items);
|
||||
} catch (error) {
|
||||
console.error('Todo 항목 로드 실패:', error);
|
||||
renderTodoItems([]);
|
||||
}
|
||||
}
|
||||
|
||||
// Todo 항목 렌더링
|
||||
@@ -218,10 +205,10 @@
|
||||
|
||||
<!-- 내용 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<h4 class="text-gray-900 font-medium mb-2">${item.content}</h4>
|
||||
<h4 class="text-gray-900 font-medium mb-2">${item.title}</h4>
|
||||
<div class="flex items-center space-x-4 text-sm text-gray-500">
|
||||
<span>
|
||||
<i class="fas fa-calendar mr-1"></i>시작일: ${formatDate(item.start_date)}
|
||||
<i class="fas fa-calendar mr-1"></i>마감일: ${formatDate(item.due_date)}
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-clock mr-1"></i>등록: ${formatDate(item.created_at)}
|
||||
@@ -232,14 +219,17 @@
|
||||
<!-- 액션 버튼 -->
|
||||
<div class="flex-shrink-0 flex space-x-2">
|
||||
${item.status !== 'completed' ? `
|
||||
<button onclick="startTodo(${item.id})" class="text-blue-500 hover:text-blue-700" title="시작하기">
|
||||
<i class="fas fa-play"></i>
|
||||
<button onclick="delayTodo('${item.id}')" class="text-orange-500 hover:text-orange-700" title="지연하기">
|
||||
<i class="fas fa-clock"></i>
|
||||
</button>
|
||||
<button onclick="completeTodo(${item.id})" class="text-green-500 hover:text-green-700" title="완료하기">
|
||||
<button onclick="completeTodo('${item.id}')" class="text-green-500 hover:text-green-700" title="완료하기">
|
||||
<i class="fas fa-check"></i>
|
||||
</button>
|
||||
<button onclick="splitTodo('${item.id}')" class="text-purple-500 hover:text-purple-700" title="분할하기">
|
||||
<i class="fas fa-cut"></i>
|
||||
</button>
|
||||
` : ''}
|
||||
<button onclick="editTodo(${item.id})" class="text-gray-400 hover:text-blue-500" title="수정하기">
|
||||
<button onclick="editTodo('${item.id}')" class="text-gray-400 hover:text-blue-500" title="수정하기">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -270,26 +260,68 @@
|
||||
|
||||
// 날짜 포맷팅
|
||||
function formatDate(dateString) {
|
||||
if (!dateString) return '날짜 없음';
|
||||
const date = new Date(dateString);
|
||||
if (isNaN(date.getTime())) return '날짜 없음';
|
||||
return date.toLocaleDateString('ko-KR');
|
||||
}
|
||||
|
||||
// Todo 시작
|
||||
function startTodo(id) {
|
||||
console.log('Todo 시작:', id);
|
||||
// TODO: API 호출하여 상태를 'active'로 변경
|
||||
// Todo 지연
|
||||
function delayTodo(id) {
|
||||
const newDate = prompt('새로운 시작 날짜를 입력하세요 (YYYY-MM-DD):');
|
||||
if (newDate && /^\d{4}-\d{2}-\d{2}$/.test(newDate)) {
|
||||
// TODO: API 호출하여 due_date 업데이트
|
||||
console.log('Todo 지연:', id, '새 날짜:', newDate);
|
||||
alert(`할 일이 ${newDate}로 지연되었습니다.`);
|
||||
loadTodoItems(); // 목록 새로고침
|
||||
} else if (newDate) {
|
||||
alert('올바른 날짜 형식을 입력해주세요 (YYYY-MM-DD)');
|
||||
}
|
||||
}
|
||||
|
||||
// Todo 완료
|
||||
function completeTodo(id) {
|
||||
console.log('Todo 완료:', id);
|
||||
// TODO: API 호출하여 상태를 'completed'로 변경
|
||||
async function completeTodo(id) {
|
||||
try {
|
||||
// TODO: API 호출하여 상태를 'completed'로 변경
|
||||
console.log('Todo 완료:', id);
|
||||
alert('할 일이 완료되었습니다!');
|
||||
loadTodoItems(); // 목록 새로고침
|
||||
} catch (error) {
|
||||
console.error('완료 처리 실패:', error);
|
||||
alert('완료 처리에 실패했습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
// Todo 분할
|
||||
function splitTodo(id) {
|
||||
const splitCount = prompt('몇 개로 분할하시겠습니까? (2-5개):');
|
||||
const count = parseInt(splitCount);
|
||||
|
||||
if (count >= 2 && count <= 5) {
|
||||
const subtasks = [];
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const subtask = prompt(`${i}번째 세부 작업을 입력하세요:`);
|
||||
if (subtask) {
|
||||
subtasks.push(subtask.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (subtasks.length > 0) {
|
||||
// TODO: API 호출하여 원본 삭제 후 세부 작업들 생성
|
||||
console.log('Todo 분할:', id, '세부 작업들:', subtasks);
|
||||
alert(`할 일이 ${subtasks.length}개의 세부 작업으로 분할되었습니다.`);
|
||||
loadTodoItems(); // 목록 새로고침
|
||||
}
|
||||
} else if (splitCount) {
|
||||
alert('2-5개 사이의 숫자를 입력해주세요.');
|
||||
}
|
||||
}
|
||||
|
||||
// Todo 편집
|
||||
function editTodo(id) {
|
||||
console.log('Todo 편집:', id);
|
||||
// TODO: 편집 모달 또는 페이지로 이동
|
||||
alert('편집 기능은 준비 중입니다.');
|
||||
}
|
||||
|
||||
// 필터링
|
||||
@@ -306,5 +338,7 @@
|
||||
// 전역 함수 등록
|
||||
window.goToDashboard = goToDashboard;
|
||||
</script>
|
||||
<script src="static/js/api.js?v=20250921110800"></script>
|
||||
<script src="static/js/auth.js?v=20250921110800"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user