refactor(tkqc): UI 스타일 통일 + 일일공수 제거 + 메뉴 정리

- UI: tkuser 스타일로 통일 (dark slate 헤더, flat 배경, gradient/glass 제거)
- tkqc-common.css 공통 스타일시트 신규 생성
- 의견 제시 API 별도 엔드포인트 추가 (모든 사용자 접근 가능)
- 일일 공수 기능 완전 제거 (라우터, 모델, 스키마, DB 테이블 DROP)
- 프로젝트 관리/사용자 관리 메뉴 숨김 (통합관리 페이지로 이관)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-02-13 10:43:37 +09:00
parent ce270b9e4a
commit c52734154f
26 changed files with 294 additions and 782 deletions

View File

@@ -6,96 +6,55 @@
<title>부적합 현황판</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- 공통 스타일 -->
<link rel="stylesheet" href="/static/css/tkqc-common.css">
<style>
.fade-in { opacity: 0; animation: fadeIn 0.5s ease-in forwards; }
@keyframes fadeIn { to { opacity: 1; } }
.header-fade-in { opacity: 0; animation: headerFadeIn 0.6s ease-out forwards; }
@keyframes headerFadeIn { to { opacity: 1; transform: translateY(0); } from { transform: translateY(-10px); } }
.content-fade-in { opacity: 0; animation: contentFadeIn 0.7s ease-out 0.2s forwards; }
@keyframes contentFadeIn { to { opacity: 1; transform: translateY(0); } from { transform: translateY(20px); } }
.content-fade-in { opacity: 0; animation: contentFadeIn 0.4s ease-out 0.2s forwards; }
@keyframes contentFadeIn { to { opacity: 1; transform: translateY(0); } from { transform: translateY(10px); } }
/* 대시보드 카드 스타일 */
.dashboard-card {
transition: all 0.3s ease;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
transition: all 0.2s ease;
}
.dashboard-card:hover {
transform: translateY(-5px);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
/* 이슈 카드 스타일 (세련된 모던 스타일) */
.issue-card {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border-left: 4px solid transparent;
background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
}
.issue-card:hover {
transform: translateY(-8px) scale(1.02);
border-left-color: #3b82f6;
box-shadow:
0 25px 50px -12px rgba(0, 0, 0, 0.15),
0 0 0 1px rgba(59, 130, 246, 0.1),
0 0 20px rgba(59, 130, 246, 0.1);
}
.issue-card label {
font-weight: 600;
color: #374151;
}
.issue-card .bg-gray-50 {
background-color: #f9fafb;
border: 1px solid #e5e7eb;
transition: all 0.2s ease;
}
.issue-card .bg-gray-50:hover {
background-color: #f3f4f6;
}
.issue-card .fas.fa-image:hover {
transform: scale(1.2);
color: #3b82f6;
}
/* 진행 중 애니메이션 */
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
/* 날짜 그룹 스타일 */
.date-group {
margin-bottom: 1.5rem;
}
.date-header {
cursor: pointer;
transition: all 0.2s ease;
}
.date-header:hover {
background-color: #f3f4f6 !important;
}
.collapse-content {
transition: all 0.3s ease;
}
.progress-bar {
background: linear-gradient(90deg, #10b981 0%, #059669 100%);
background: #10b981;
transition: width 0.8s ease;
}
/* 반응형 그리드 */
.dashboard-grid {
display: grid;
@@ -104,7 +63,7 @@
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<body>
<!-- 로딩 스크린 -->
<div id="loadingScreen" class="fixed inset-0 bg-white z-50 flex items-center justify-center">
<div class="text-center">
@@ -139,7 +98,7 @@
<div id="commonHeader"></div>
<!-- 메인 콘텐츠 -->
<main class="container mx-auto px-4 py-8 content-fade-in" style="padding-top: 80px;">
<main class="container mx-auto px-4 py-8 content-fade-in" style="padding-top: 72px;">
<!-- 페이지 헤더 -->
<div class="bg-white rounded-xl shadow-sm p-6 mb-6">
<div class="flex items-center justify-between">
@@ -155,7 +114,7 @@
<!-- 전체 통계 대시보드 -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div class="dashboard-card text-white p-6 rounded-xl">
<div class="bg-blue-500 text-white p-6 rounded-xl dashboard-card">
<div class="flex items-center justify-between">
<div>
<p class="text-blue-100 text-sm flex items-center space-x-1">
@@ -167,43 +126,43 @@
<i class="fas fa-tasks text-4xl text-blue-200"></i>
</div>
</div>
<div class="bg-gradient-to-br from-green-400 to-green-600 text-white p-6 rounded-xl dashboard-card">
<div class="bg-emerald-500 text-white p-6 rounded-xl dashboard-card">
<div class="flex items-center justify-between">
<div>
<p class="text-green-100 text-sm flex items-center space-x-1">
<p class="text-emerald-100 text-sm flex items-center space-x-1">
<span>오늘 신규</span>
<div class="w-1.5 h-1.5 bg-green-200 rounded-full animate-pulse"></div>
<div class="w-1.5 h-1.5 bg-emerald-200 rounded-full animate-pulse"></div>
</p>
<p class="text-3xl font-bold" id="todayNew">0</p>
</div>
<i class="fas fa-plus-circle text-4xl text-green-200"></i>
<i class="fas fa-plus-circle text-4xl text-emerald-200"></i>
</div>
</div>
<div class="bg-gradient-to-br from-purple-400 to-purple-600 text-white p-6 rounded-xl dashboard-card">
<div class="bg-amber-500 text-white p-6 rounded-xl dashboard-card">
<div class="flex items-center justify-between">
<div>
<p class="text-purple-100 text-sm flex items-center space-x-1">
<p class="text-amber-100 text-sm flex items-center space-x-1">
<span>완료 대기</span>
<div class="w-1.5 h-1.5 bg-purple-200 rounded-full animate-pulse"></div>
<div class="w-1.5 h-1.5 bg-amber-200 rounded-full animate-pulse"></div>
</p>
<p class="text-3xl font-bold" id="pendingCompletion">0</p>
</div>
<i class="fas fa-hourglass-half text-4xl text-purple-200"></i>
<i class="fas fa-hourglass-half text-4xl text-amber-200"></i>
</div>
</div>
<div class="bg-gradient-to-br from-red-400 to-red-600 text-white p-6 rounded-xl dashboard-card">
<div class="bg-slate-500 text-white p-6 rounded-xl dashboard-card">
<div class="flex items-center justify-between">
<div>
<p class="text-red-100 text-sm flex items-center space-x-1">
<p class="text-slate-200 text-sm flex items-center space-x-1">
<span>지연 중</span>
<div class="w-1.5 h-1.5 bg-red-200 rounded-full animate-pulse"></div>
<div class="w-1.5 h-1.5 bg-slate-300 rounded-full animate-pulse"></div>
</p>
<p class="text-3xl font-bold" id="overdue">0</p>
</div>
<i class="fas fa-clock text-4xl text-red-200"></i>
<i class="fas fa-clock text-4xl text-slate-300"></i>
</div>
</div>
</div>
@@ -2131,44 +2090,15 @@
}
try {
// 현재 이슈 정보 가져오기
const issueResponse = await fetch(`/api/issues/${selectedOpinionIssueId}`, {
headers: {
'Authorization': `Bearer ${TokenManager.getToken()}`
}
});
if (!issueResponse.ok) {
throw new Error('이슈 정보를 가져올 수 없습니다.');
}
const issue = await issueResponse.json();
// 새 의견 형식: [작성자] (날짜시간)\n내용
const now = new Date();
const dateStr = now.toLocaleString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
const newOpinion = `[${currentUser.full_name || currentUser.username}] (${dateStr})\n${opinionText}`;
// 기존 solution에 추가 (최신이 위로)
const updatedSolution = issue.solution
? `${newOpinion}\n${'─'.repeat(50)}\n${issue.solution}`
: newOpinion;
// 백엔드 업데이트
const response = await fetch(`/api/issues/${selectedOpinionIssueId}/management`, {
method: 'PUT',
// 별도 의견 제시 API 사용 (권한 체크 없음, 로그인만 필요)
const response = await fetch(`/api/issues/${selectedOpinionIssueId}/opinion`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TokenManager.getToken()}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
solution: updatedSolution
opinion: opinionText
})
});