feat: PC 등급 뱃지 색상 CSS 추가 및 Win11 불가 PC 교체 대상 등급 강제 적용
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { ASSET_SCHEMA, UI_TEXT } from './schema';
|
||||
import { getActionButtonsHTML } from './utils';
|
||||
import { generateOptionsHTML } from '../components/Modal/ModalUtils';
|
||||
import { CORP_LIST } from '../components/Modal/SharedData';
|
||||
|
||||
@@ -16,9 +15,18 @@ export interface FilterOptions {
|
||||
showField?: boolean;
|
||||
showType?: boolean;
|
||||
showStatus?: boolean;
|
||||
showPosition?: boolean;
|
||||
extraHTML?: string;
|
||||
onFilterChange: (filters: any) => void;
|
||||
initialFilters?: any;
|
||||
fullList?: any[]; // For populating dynamic filters
|
||||
}
|
||||
|
||||
/**
|
||||
* 전역 액션 버튼 그룹 생성 (자산 추가 등)
|
||||
*/
|
||||
export function getActionButtonsHTML(): string {
|
||||
return `<div id="filter-bar-actions" class="header-action-group"></div>`;
|
||||
}
|
||||
|
||||
export function renderFilterBar(container: HTMLElement, options: FilterOptions) {
|
||||
@@ -30,11 +38,31 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
|
||||
showField = false,
|
||||
showType = false,
|
||||
showStatus = false,
|
||||
showPosition = false,
|
||||
extraHTML = '',
|
||||
onFilterChange,
|
||||
initialFilters = { keyword: '', corp: '', dept: '', loc: '', field: '', type: '', status: '' }
|
||||
initialFilters = { keyword: '', corp: '', dept: '', loc: '', field: '', type: '', status: '', position: '' },
|
||||
fullList = []
|
||||
} = options;
|
||||
|
||||
container.classList.add('search-bar'); // Restored class
|
||||
|
||||
// Helper to get unique sorted values
|
||||
const getUnique = (key: keyof typeof ASSET_SCHEMA | string) => {
|
||||
const schemaItem = (ASSET_SCHEMA as any)[key];
|
||||
const fieldKey = schemaItem ? schemaItem.key : key;
|
||||
const dbKey = schemaItem ? schemaItem.db : null;
|
||||
return Array.from(new Set(fullList.map(item => {
|
||||
const val = item[fieldKey];
|
||||
if (val !== undefined && val !== null) return val;
|
||||
if (dbKey) return item[dbKey];
|
||||
return null;
|
||||
}).filter(Boolean))).sort() as string[];
|
||||
};
|
||||
|
||||
const hasDeptName = fullList.some(item => 'dept_name' in item);
|
||||
const deptUniqueKey = hasDeptName ? 'dept_name' : 'CURRENT_DEPT';
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="search-item flex-1">
|
||||
<label>${keywordLabel}</label>
|
||||
@@ -45,6 +73,7 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
|
||||
<label>${ASSET_SCHEMA.ASSET_TYPE.ui}</label>
|
||||
<select id="filter-type">
|
||||
<option value="">전체 유형</option>
|
||||
${getUnique('ASSET_TYPE').map(v => `<option value="${v}" ${initialFilters.type === v ? 'selected' : ''}>${v}</option>`).join('')}
|
||||
</select>
|
||||
</div>` : ''}
|
||||
${showStatus ? `
|
||||
@@ -52,6 +81,7 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
|
||||
<label>${ASSET_SCHEMA.HW_STATUS.ui}</label>
|
||||
<select id="filter-status">
|
||||
<option value="">전체 상태</option>
|
||||
${getUnique('HW_STATUS').map(v => `<option value="${v}" ${initialFilters.status === v ? 'selected' : ''}>${v}</option>`).join('')}
|
||||
</select>
|
||||
</div>` : ''}
|
||||
${showField ? `
|
||||
@@ -73,16 +103,30 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
|
||||
${showLoc ? `
|
||||
<div class="search-item">
|
||||
<label>${ASSET_SCHEMA.LOCATION.ui}</label>
|
||||
<select id="filter-loc"><option value="">전체 위치</option></select>
|
||||
<select id="filter-loc">
|
||||
<option value="">전체 위치</option>
|
||||
${getUnique('LOCATION').map(v => `<option value="${v}" ${initialFilters.loc === v ? 'selected' : ''}>${v}</option>`).join('')}
|
||||
</select>
|
||||
</div>` : ''}
|
||||
${showDept ? `
|
||||
<div class="search-item">
|
||||
<label>${ASSET_SCHEMA.CURRENT_DEPT.ui}</label>
|
||||
<select id="filter-dept"><option value="">전체 조직</option></select>
|
||||
<label>조직</label>
|
||||
<select id="filter-dept">
|
||||
<option value="">전체 조직</option>
|
||||
${getUnique(deptUniqueKey).map(v => `<option value="${v}" ${initialFilters.dept === v ? 'selected' : ''}>${v}</option>`).join('')}
|
||||
</select>
|
||||
</div>` : ''}
|
||||
${showPosition ? `
|
||||
<div class="search-item">
|
||||
<label>직무</label>
|
||||
<select id="filter-position">
|
||||
<option value="">전체 직무</option>
|
||||
${getUnique('position').map(v => `<option value="${v}" ${initialFilters.position === v ? 'selected' : ''}>${v}</option>`).join('')}
|
||||
</select>
|
||||
</div>` : ''}
|
||||
${extraHTML}
|
||||
<button id="btn-reset-filters" class="btn btn-outline btn-reset">
|
||||
<i data-lucide="refresh-ccw"></i> ${UI_TEXT.ACTION.RESET_FILTER}
|
||||
<i data-lucide="refresh-ccw" class="icon-sm"></i> ${UI_TEXT.ACTION.RESET_FILTER}
|
||||
</button>
|
||||
${getActionButtonsHTML()}
|
||||
`;
|
||||
@@ -96,7 +140,8 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
|
||||
loc: (container.querySelector('#filter-loc') as HTMLSelectElement)?.value || '',
|
||||
field: (container.querySelector('#filter-field') as HTMLSelectElement)?.value || '',
|
||||
type: (container.querySelector('#filter-type') as HTMLSelectElement)?.value || '',
|
||||
status: (container.querySelector('#filter-status') as HTMLSelectElement)?.value || ''
|
||||
status: (container.querySelector('#filter-status') as HTMLSelectElement)?.value || '',
|
||||
position: (container.querySelector('#filter-position') as HTMLSelectElement)?.value || ''
|
||||
};
|
||||
onFilterChange(filters);
|
||||
};
|
||||
@@ -108,9 +153,10 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
|
||||
container.querySelector('#filter-field')?.addEventListener('change', triggerChange);
|
||||
container.querySelector('#filter-type')?.addEventListener('change', triggerChange);
|
||||
container.querySelector('#filter-status')?.addEventListener('change', triggerChange);
|
||||
container.querySelector('#filter-position')?.addEventListener('change', triggerChange);
|
||||
|
||||
container.querySelector('#btn-reset-filters')?.addEventListener('click', () => {
|
||||
['filter-keyword', 'filter-corp', 'filter-dept', 'filter-loc', 'filter-field', 'filter-type', 'filter-status'].forEach(id => {
|
||||
['filter-keyword', 'filter-corp', 'filter-dept', 'filter-loc', 'filter-field', 'filter-type', 'filter-status', 'filter-position'].forEach(id => {
|
||||
const el = container.querySelector(`#${id}`);
|
||||
if (el) (el as any).value = '';
|
||||
});
|
||||
@@ -121,18 +167,37 @@ export function renderFilterBar(container: HTMLElement, options: FilterOptions)
|
||||
/**
|
||||
* 공통 필터링 로직
|
||||
*/
|
||||
export function applyCommonFilters(list: any[], filters: any, searchKeys: (keyof typeof ASSET_SCHEMA)[]) {
|
||||
export function applyCommonFilters(list: any[], filters: any, searchKeys: any[]) {
|
||||
return list.filter(item => {
|
||||
const matchKeyword = !filters.keyword || searchKeys.some(key =>
|
||||
String(item[ASSET_SCHEMA[key].key] || item[ASSET_SCHEMA[key].db] || '').toLowerCase().includes(filters.keyword)
|
||||
);
|
||||
// 1. 키워드 검색
|
||||
const matchKeyword = !filters.keyword || searchKeys.some(key => {
|
||||
const schemaItem = (ASSET_SCHEMA as any)[key];
|
||||
if (schemaItem) {
|
||||
return String(item[schemaItem.key] || item[schemaItem.db] || '').toLowerCase().includes(filters.keyword);
|
||||
}
|
||||
return String(item[key] || '').toLowerCase().includes(filters.keyword);
|
||||
});
|
||||
|
||||
// 2. 부서 필터링 (사용자 페이지 dept_name, 자산 페이지 current_dept)
|
||||
let matchDept = true;
|
||||
if (filters.dept) {
|
||||
const itemDept = item.dept_name || item[ASSET_SCHEMA.CURRENT_DEPT.key] || item[ASSET_SCHEMA.CURRENT_DEPT.db];
|
||||
matchDept = itemDept === filters.dept;
|
||||
}
|
||||
|
||||
// 3. 직무 필터링
|
||||
let matchPosition = true;
|
||||
if (filters.position) {
|
||||
matchPosition = item.position === filters.position;
|
||||
}
|
||||
|
||||
// 4. 나머지 필터링
|
||||
const matchCorp = !filters.corp || (item[ASSET_SCHEMA.PURCHASE_CORP.key] || item[ASSET_SCHEMA.PURCHASE_CORP.db]) === filters.corp;
|
||||
const matchDept = !filters.dept || (item[ASSET_SCHEMA.CURRENT_DEPT.key] || item[ASSET_SCHEMA.CURRENT_DEPT.db]) === filters.dept;
|
||||
const matchLoc = !filters.loc || (item[ASSET_SCHEMA.LOCATION.key] || item[ASSET_SCHEMA.LOCATION.db]) === filters.loc;
|
||||
const matchField = !filters.field || (item[ASSET_SCHEMA.SW_FIELD.key] || item[ASSET_SCHEMA.SW_FIELD.db]) === filters.field;
|
||||
const matchType = !filters.type || (item[ASSET_SCHEMA.ASSET_TYPE.key] || item[ASSET_SCHEMA.ASSET_TYPE.db]) === filters.type;
|
||||
const matchStatus = !filters.status || (item[ASSET_SCHEMA.HW_STATUS.key] || item[ASSET_SCHEMA.HW_STATUS.db]) === filters.status;
|
||||
|
||||
return matchKeyword && matchCorp && matchDept && matchLoc && matchField && matchType && matchStatus;
|
||||
return matchKeyword && matchCorp && matchDept && matchLoc && matchField && matchType && matchStatus && matchPosition;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -242,7 +242,8 @@ export function calculatePcScoreDeductive(cpu: string, ram: string, gpu: string,
|
||||
gpuDeduction = 0;
|
||||
} else if (
|
||||
gpuUpper.includes('RTX 3070') || gpuUpper.includes('RTX 3060') || gpuUpper.includes('RTX 2060') ||
|
||||
gpuUpper.includes('RTX A2000') || gpuUpper.includes('RTX A3000') || gpuUpper.includes('QUADRO')
|
||||
gpuUpper.includes('RTX A2000') || gpuUpper.includes('RTX A3000') || gpuUpper.includes('QUADRO') ||
|
||||
gpuUpper.includes('RTX 4060') || gpuUpper.includes('RTX 4050')
|
||||
) {
|
||||
gpuDeduction = 5;
|
||||
} else if (
|
||||
@@ -289,10 +290,12 @@ export function calculatePcScoreDeductive(cpu: string, ram: string, gpu: string,
|
||||
* 성능 점수 기준 등급 뱃지 메타 정보 가져오기
|
||||
*/
|
||||
export function getPcGrade(score: number, isWin11Incompatible?: boolean): { name: string; class: string; color: string } {
|
||||
// Windows 11 업그레이드 불가 PC는 성능 점수와 무관하게 교체 대상으로 분류
|
||||
if (isWin11Incompatible) return { name: '교체 대상', class: 'badge-danger', color: '#EF4444' };
|
||||
if (score >= 85) return { name: '최상급', class: 'b-purple', color: '#7C3AED' };
|
||||
if (score >= 70) return { name: '상급', class: 'b-primary', color: '#4F46E5' };
|
||||
if (score >= 40) return { name: '중급', class: 'b-green', color: '#10B981' };
|
||||
if (score >= 20 && !isWin11Incompatible) return { name: '보급', class: 'b-yellow', color: '#F59E0B' };
|
||||
if (score >= 20) return { name: '보급', class: 'b-yellow', color: '#F59E0B' };
|
||||
return { name: '교체 대상', class: 'badge-danger', color: '#EF4444' };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user