Files
ITAM/src/views/List/PartsMasterListView.ts
Taehoon 2cb4b87c0a style: surgically unify Admin page UI and sub-tabs
- Standardized sub-tab rendering in PartsMasterListView to prevent duplication
- Updated badge classes to match system design guide (badge-success/warning)
- Refactored JobSpecModal to use unified .grid-form and header identity
- Preserved all functional logic and tab-switching behavior from collaborator
2026-06-17 13:16:15 +09:00

175 lines
6.3 KiB
TypeScript

import { state } from '../../core/state';
import { openPartsMasterModal } from '../../components/Modal/PartsMasterModal';
import { openJobSpecModal } from '../../components/Modal/JobSpecModal';
import { formatInline } from '../../core/utils';
import { createListView } from './ListFactory';
export let activePartsMasterSubTab: 'parts-master' | 'job-spec' = 'parts-master';
export function renderPartsMasterList(container: HTMLElement) {
if (activePartsMasterSubTab === 'parts-master') {
createListView(container, {
title: '부품 마스터',
dataSource: () => state.masterData.partsMaster || [],
searchKeys: ['component_name', 'category', 'score_tier'],
filterOptions: {
keywordLabel: '부품명 / 등급 검색',
showLoc: false,
showDept: false,
showType: false
},
onRowClick: (component) => openPartsMasterModal(component, 'view'),
columns: [
{
header: 'ID',
sortKey: 'id',
align: 'center',
width: '5%',
render: c => c.id.toString()
},
{
header: '분류',
sortKey: 'category',
align: 'center',
width: '15%',
render: c => {
let badgeClass = 'badge-primary';
if (c.category === 'CPU') badgeClass = 'badge-primary';
else if (c.category === 'GPU') badgeClass = 'badge-success';
else if (c.category === 'RAM') badgeClass = 'badge-warning';
return `<span class="badge ${badgeClass}">${c.category}</span>`;
}
},
{
header: '부품 표준 명칭',
sortKey: 'component_name',
render: c => formatInline(c.component_name || '-')
},
{
header: '성능 등급',
sortKey: 'score_tier',
align: 'center',
width: '15%',
render: c => c.score_tier || '-'
},
{
header: '감점 점수',
sortKey: 'deduction',
align: 'center',
width: '15%',
render: c => {
const score = c.deduction || 0;
let color = '#3b82f6'; // blue
if (score >= 20) color = '#ef4444'; // red
else if (score >= 10) color = '#f59e0b'; // orange
return `<strong style="color: ${color}; font-size: 14px;">-${score}점</strong>`;
}
}
]
});
} else {
createListView(container, {
title: '직무별 기준 사양',
dataSource: () => state.masterData.jobSpecs || [],
searchKeys: ['job_name', 'cpu_standard', 'ram_standard', 'gpu_standard', 'remarks'],
filterOptions: {
keywordLabel: '직무명 / 사양 검색',
showLoc: false,
showDept: false,
showType: false
},
onRowClick: (jobSpec) => openJobSpecModal(jobSpec, 'view'),
columns: [
{
header: 'ID',
sortKey: 'id',
align: 'center',
width: '5%',
render: j => j.id.toString()
},
{
header: '직무명',
sortKey: 'job_name',
width: '15%',
render: j => `<strong style="color: var(--primary-color); font-size: 14px;">${formatInline(j.job_name || '-')}</strong>`
},
{
header: '권장 CPU 사양',
sortKey: 'cpu_standard',
render: j => formatInline(j.cpu_standard || '-')
},
{
header: '권장 RAM 사양',
sortKey: 'ram_standard',
width: '12%',
render: j => formatInline(j.ram_standard || '-')
},
{
header: '권장 GPU 사양',
sortKey: 'gpu_standard',
render: j => formatInline(j.gpu_standard || '-')
},
{
header: '기준 점수',
sortKey: 'min_score',
align: 'center',
width: '10%',
render: j => `<span style="font-weight: 700;">${j.min_score || 0}점 이상</span>`
},
{
header: '비고',
sortKey: 'remarks',
width: '20%',
render: j => formatInline(j.remarks || '-')
}
]
});
}
renderSubTabs(container);
}
function renderSubTabs(container: HTMLElement) {
const header = container.querySelector('.page-header');
if (!header) return;
// 기존에 생성된 탭 바가 있다면 제거하여 중복 방지 (스타일만 수정하는 최소 침습 방식)
const existingTabs = container.querySelector('.sub-tab-container');
if (existingTabs) existingTabs.remove();
const tabContainer = document.createElement('div');
tabContainer.className = 'sub-tab-container';
tabContainer.style.cssText = 'display: flex; gap: 1rem; padding: 0 2rem; border-bottom: 1px solid var(--hairline); background: var(--canvas);';
const tab1Active = activePartsMasterSubTab === 'parts-master';
const tab2Active = activePartsMasterSubTab === 'job-spec';
tabContainer.innerHTML = `
<button id="tab-parts-master" class="sub-tab-btn ${tab1Active ? 'active' : ''}" style="padding: 1rem 0.5rem; border: none; background: none; font-size: var(--fs-sm); font-weight: 600; cursor: pointer; color: ${tab1Active ? 'var(--primary)' : 'var(--mute)'}; position: relative; border-bottom: 2px solid ${tab1Active ? 'var(--primary)' : 'transparent'}; margin-bottom: -1px;">
부품 표준 등급
</button>
<button id="tab-job-spec" class="sub-tab-btn ${tab2Active ? 'active' : ''}" style="padding: 1rem 0.5rem; border: none; background: none; font-size: var(--fs-sm); font-weight: 600; cursor: pointer; color: ${tab2Active ? 'var(--primary)' : 'var(--mute)'}; position: relative; border-bottom: 2px solid ${tab2Active ? 'var(--primary)' : 'transparent'}; margin-bottom: -1px;">
직무별 기준 사양
</button>
`;
header.parentNode!.insertBefore(tabContainer, header.nextSibling);
const tabPartsMaster = tabContainer.querySelector('#tab-parts-master')!;
const tabJobSpec = tabContainer.querySelector('#tab-job-spec')!;
tabPartsMaster.addEventListener('click', () => {
if (activePartsMasterSubTab !== 'parts-master') {
activePartsMasterSubTab = 'parts-master';
renderPartsMasterList(container);
}
});
tabJobSpec.addEventListener('click', () => {
if (activePartsMasterSubTab !== 'job-spec') {
activePartsMasterSubTab = 'job-spec';
renderPartsMasterList(container);
}
});
}