Files
tk-factory-services/system1-factory/web/pages/work/nonconformity.html
Hyungi Ahn 4388628788 refactor: TBM/작업보고 코드 통합 및 API 쿼리 버그 수정
- 공통 유틸리티 추출 (common/utils.js, common/base-state.js)
- TBM 모바일 인라인 JS/CSS 외부 파일로 분리 (tbm-mobile.js, tbm-mobile.css)
- 미사용 코드 삭제 (index.js, work-report-*.js 등 5개 파일)
- TBM/작업보고 state.js, utils.js를 공통 모듈 기반으로 전환
- 작업보고서 SSO 인증 호환 수정 (token/user 함수)
- tbmModel.js: incomplete-reports 쿼리에서 users→sso_users 조인 수정, leader_name 조인 추가
- docker-compose.yml: system1-web 볼륨 마운트 추가
- 모바일 인계(handover) 기능 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 07:51:24 +09:00

307 lines
8.9 KiB
HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>부적합 현황 | (주)테크니컬코리아</title>
<link rel="stylesheet" href="/css/design-system.css">
<link rel="stylesheet" href="/css/common.css?v=2">
<link rel="stylesheet" href="/css/project-management.css?v=3">
<link rel="icon" type="image/png" href="/img/favicon.png">
<script src="/js/api-base.js?v=2"></script>
<script src="/js/app-init.js?v=9" defer></script>
<script src="https://instant.page/5.2.0" type="module"></script>
<style>
/* 통계 카드 */
.stats-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
margin-bottom: 1.5rem;
}
.stat-card {
background: white;
padding: 1.25rem;
border-radius: 0.75rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
text-align: center;
}
.stat-number {
font-size: 2rem;
font-weight: 700;
margin-bottom: 0.25rem;
}
.stat-label {
font-size: 0.875rem;
color: #6b7280;
}
.stat-card.reported .stat-number { color: #3b82f6; }
.stat-card.received .stat-number { color: #f97316; }
.stat-card.in_progress .stat-number { color: #8b5cf6; }
.stat-card.completed .stat-number { color: #10b981; }
/* 필터 바 */
.filter-bar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
padding: 1rem 1.25rem;
background: white;
border-radius: 0.75rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.filter-bar select,
.filter-bar input {
padding: 0.625rem 0.875rem;
border: 1px solid #d1d5db;
border-radius: 0.5rem;
font-size: 0.875rem;
background: white;
}
.filter-bar select:focus,
.filter-bar input:focus {
outline: none;
border-color: #f97316;
box-shadow: 0 0 0 3px rgba(249, 115, 22, 0.1);
}
.btn-new-report {
margin-left: auto;
padding: 0.625rem 1.25rem;
background: #f97316;
color: white;
border: none;
border-radius: 0.5rem;
font-size: 0.875rem;
font-weight: 600;
cursor: pointer;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 0.5rem;
transition: background 0.2s;
}
.btn-new-report:hover {
background: #ea580c;
}
/* 신고 목록 */
.issue-list {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.issue-card {
background: white;
border-radius: 0.75rem;
padding: 1.25rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
cursor: pointer;
transition: all 0.2s;
border: 1px solid transparent;
}
.issue-card:hover {
border-color: #fed7aa;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.issue-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 0.75rem;
}
.issue-id {
font-size: 0.875rem;
color: #9ca3af;
}
.issue-status {
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 600;
}
.issue-status.reported {
background: #dbeafe;
color: #1d4ed8;
}
.issue-status.received {
background: #fed7aa;
color: #c2410c;
}
.issue-status.in_progress {
background: #e9d5ff;
color: #7c3aed;
}
.issue-status.completed {
background: #d1fae5;
color: #047857;
}
.issue-status.closed {
background: #f3f4f6;
color: #4b5563;
}
.issue-title {
font-size: 1rem;
font-weight: 600;
margin-bottom: 0.5rem;
color: #1f2937;
}
.issue-category-badge {
display: inline-block;
padding: 0.125rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.75rem;
font-weight: 500;
margin-right: 0.5rem;
background: #fff7ed;
color: #c2410c;
}
.issue-meta {
display: flex;
flex-wrap: wrap;
gap: 1rem;
font-size: 0.875rem;
color: #6b7280;
}
.issue-meta-item {
display: flex;
align-items: center;
gap: 0.375rem;
}
.issue-photos {
display: flex;
gap: 0.5rem;
margin-top: 0.75rem;
}
.issue-photos img {
width: 56px;
height: 56px;
object-fit: cover;
border-radius: 0.375rem;
border: 1px solid #e5e7eb;
}
/* 빈 상태 */
.empty-state {
text-align: center;
padding: 4rem 1.5rem;
color: #6b7280;
background: white;
border-radius: 0.75rem;
}
.empty-state-title {
font-size: 1.125rem;
font-weight: 600;
margin-bottom: 0.5rem;
color: #374151;
}
@media (max-width: 768px) {
.filter-bar {
flex-direction: column;
align-items: stretch;
}
.btn-new-report {
width: 100%;
justify-content: center;
}
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
}
</style>
</head>
<body>
<div class="work-report-container">
<div id="navbar-container"></div>
<main class="work-report-main">
<div class="dashboard-main">
<div class="page-header">
<div class="page-title-section">
<h1 class="page-title">부적합 현황</h1>
<p class="page-description">자재, 설계, 검사 등 작업 관련 부적합 신고 현황입니다.</p>
</div>
</div>
<!-- 통계 카드 -->
<div class="stats-grid" id="statsGrid">
<div class="stat-card reported">
<div class="stat-number" id="statReported">-</div>
<div class="stat-label">신고</div>
</div>
<div class="stat-card received">
<div class="stat-number" id="statReceived">-</div>
<div class="stat-label">접수</div>
</div>
<div class="stat-card in_progress">
<div class="stat-number" id="statProgress">-</div>
<div class="stat-label">처리중</div>
</div>
<div class="stat-card completed">
<div class="stat-number" id="statCompleted">-</div>
<div class="stat-label">완료</div>
</div>
</div>
<!-- 필터 바 -->
<div class="filter-bar">
<select id="filterStatus">
<option value="">전체 상태</option>
<option value="reported">신고</option>
<option value="received">접수</option>
<option value="in_progress">처리중</option>
<option value="completed">완료</option>
<option value="closed">종료</option>
</select>
<input type="date" id="filterStartDate" title="시작일">
<input type="date" id="filterEndDate" title="종료일">
<a href="/pages/safety/report.html?type=nonconformity" class="btn-new-report">
+ 부적합 신고
</a>
</div>
<!-- 신고 목록 -->
<div class="issue-list" id="issueList">
<div class="empty-state">
<div class="empty-state-title">로딩 중...</div>
</div>
</div>
</div>
</main>
</div>
<script src="/js/nonconformity-list.js?v=2"></script>
</body>
</html>