feat(purchase): 카테고리 테이블 분리 + 동적 로드 + tkuser 관리
- DB: consumable_categories 테이블 생성, ENUM→VARCHAR 변환, 시드 4개 - API: GET/POST/PUT/DEACTIVATE /api/consumable-categories - 프론트: 3개 JS 하드코딩 CAT_LABELS 제거 → API loadCategories() 동적 로드 - tkuser: 카테고리 관리 섹션 추가, select 옵션 동적 생성 - 별칭 시드 SQL (INSERT IGNORE 기반) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,10 +3,16 @@ const TKUSER_BASE_URL = location.hostname.includes('technicalkorea.net')
|
||||
? 'https://tkuser.technicalkorea.net'
|
||||
: location.protocol + '//' + location.hostname + ':30180';
|
||||
|
||||
const CAT_LABELS = { consumable: '소모품', safety: '안전용품', repair: '수선비', equipment: '설비' };
|
||||
const CAT_COLORS = { consumable: 'badge-blue', safety: 'badge-green', repair: 'badge-amber', equipment: 'badge-purple' };
|
||||
const CAT_BG = { consumable: '#dbeafe', safety: '#dcfce7', repair: '#fef3c7', equipment: '#f3e8ff' };
|
||||
const CAT_FG = { consumable: '#1e40af', safety: '#166534', repair: '#92400e', equipment: '#7e22ce' };
|
||||
// 카테고리 — API에서 동적 로드
|
||||
let _categories = null;
|
||||
async function loadCategories() {
|
||||
if (_categories) return _categories;
|
||||
try { const r = await api('/consumable-categories'); _categories = r.data || []; } catch(e) { _categories = []; }
|
||||
return _categories;
|
||||
}
|
||||
function getCatLabel(code) { return (_categories || []).find(c => c.category_code === code)?.category_name || code || '-'; }
|
||||
function getCatBg(code) { return (_categories || []).find(c => c.category_code === code)?.color_bg || '#f3f4f6'; }
|
||||
function getCatFg(code) { return (_categories || []).find(c => c.category_code === code)?.color_fg || '#374151'; }
|
||||
const STATUS_LABELS = { pending: '대기', grouped: '구매진행중', purchased: '구매완료', received: '입고완료', cancelled: '취소', returned: '반품', hold: '보류' };
|
||||
const STATUS_COLORS = { pending: 'badge-amber', grouped: 'badge-blue', purchased: 'badge-green', received: 'badge-teal', cancelled: 'badge-red', returned: 'badge-red', hold: 'badge-gray' };
|
||||
|
||||
@@ -125,9 +131,9 @@ function showDropdown(items, query) {
|
||||
let html = '';
|
||||
if (items.length > 0) {
|
||||
items.forEach((item, idx) => {
|
||||
const catLabel = CAT_LABELS[item.category] || item.category;
|
||||
const bg = CAT_BG[item.category] || '#f3f4f6';
|
||||
const fg = CAT_FG[item.category] || '#374151';
|
||||
const catLabel = getCatLabel(item.category);
|
||||
const bg = getCatBg(item.category);
|
||||
const fg = getCatFg(item.category);
|
||||
const spec = _fmtSpec(item.spec ? escapeHtml(item.spec) : '');
|
||||
const maker = item.maker ? ` (${escapeHtml(item.maker)})` : '';
|
||||
const photoSrc = item.photo_path ? (item.photo_path.startsWith('http') ? item.photo_path : TKUSER_BASE_URL + item.photo_path) : '';
|
||||
@@ -339,8 +345,8 @@ function renderRequests() {
|
||||
// 등록 품목이면 ci 데이터, 미등록이면 custom 데이터 사용
|
||||
const itemName = r.item_name || r.custom_item_name || '-';
|
||||
const category = r.category || r.custom_category;
|
||||
const catLabel = CAT_LABELS[category] || category || '-';
|
||||
const catColor = CAT_COLORS[category] || 'badge-gray';
|
||||
const catLabel = getCatLabel(category);
|
||||
const catColor = 'badge-gray';
|
||||
const statusLabel = STATUS_LABELS[r.status] || r.status;
|
||||
const statusColor = STATUS_COLORS[r.status] || 'badge-gray';
|
||||
const isCustom = !r.item_id && r.custom_item_name;
|
||||
@@ -415,7 +421,7 @@ function openPurchaseModal(requestId) {
|
||||
|
||||
document.getElementById('purchaseModalInfo').innerHTML = `
|
||||
<div class="font-medium">${escapeHtml(itemName)}${_fmtSpec(r.spec ? escapeHtml(r.spec) : '')} ${r.maker ? '(' + escapeHtml(r.maker) + ')' : ''}${isCustom ? ' <span class="text-orange-500 text-xs">(직접입력)</span>' : ''}</div>
|
||||
<div class="text-xs text-gray-500 mt-1">분류: ${CAT_LABELS[category] || category || '-'} | 기준가: ${basePrice} | 신청수량: ${r.quantity}</div>
|
||||
<div class="text-xs text-gray-500 mt-1">분류: ${getCatLabel(category)} | 기준가: ${basePrice} | 신청수량: ${r.quantity}</div>
|
||||
${r.pr_photo_path ? `<img src="${r.pr_photo_path}" class="mt-2 w-20 h-20 rounded object-cover" onerror="this.style.display='none'">` : ''}
|
||||
`;
|
||||
document.getElementById('pmUnitPrice').value = r.base_price || '';
|
||||
@@ -773,6 +779,7 @@ async function submitReceive() {
|
||||
(async function() {
|
||||
if (!await initAuth()) return;
|
||||
isAdmin = currentUser && ['admin', 'system', 'system admin'].includes(currentUser.role);
|
||||
await loadCategories();
|
||||
initItemSearch();
|
||||
await loadInitialData();
|
||||
await loadRequests();
|
||||
|
||||
Reference in New Issue
Block a user