import { useEffect, useState } from 'react' import { codeList, codeGroupGet, codeCreate, codeUpdate, codeDelete } from '../../../api/uiws' import { PageHeader, SearchBar, Panel, Button, Modal, FormField, Input, Spinner, Pagination, YnBadge, DataGrid, type Column } from '../../../components/uiws/ui' import AdminGate from './AdminGate' /** * 2.7 코드(공통코드) 관리 — /api/system/codes. 그룹 목록(PageResponse) + 상세(그룹+코드값 목록) 편집. * 그룹 단위 저장(values 포함). RBAC 변경 ADMIN/MANAGER(403 + AdminGate). 색상 토큰만. */ type CodeGrp = { grpCd: string; grpNm: string; useYn: string } type CodeValue = { grpCd: string; codeVal: string; codeNm: string; sortOrd: number | null; useYn: string } type CodeGrpDetail = CodeGrp & { values: CodeValue[] } const PSIZE = 20 function friendlyError(e: any): string { if (e?.response?.status === 403) return '권한이 없습니다 (관리자 전용).' if (e?.response?.status === 409) return '이미 존재하는 코드 그룹입니다.' return e?.response?.data?.message || '요청을 처리하지 못했습니다.' } export default function CodeManagement() { const [rows, setRows] = useState([]) const [total, setTotal] = useState(0) const [page, setPage] = useState(0) const [kw, setKw] = useState('') const [loading, setLoading] = useState(false) const [open, setOpen] = useState(false) const [editing, setEditing] = useState(false) const [form, setForm] = useState({ grpCd: '', grpNm: '', useYn: 'Y', values: [] }) const [err, setErr] = useState('') async function load(p = page, keyword = kw) { setLoading(true) try { const res = await codeList({ keyword: keyword || undefined, page: p, size: PSIZE }) setRows(res.data?.data?.content || []) setTotal(res.data?.data?.total || 0) } catch { setRows([]); setTotal(0) } finally { setLoading(false) } } useEffect(() => { load(0, '') }, []) function openCreate() { setForm({ grpCd: '', grpNm: '', useYn: 'Y', values: [] }); setEditing(false); setErr(''); setOpen(true) } async function openEdit(g: CodeGrp) { setErr('') try { const res = await codeGroupGet(g.grpCd) const d = res.data?.data setForm({ grpCd: d.grpCd, grpNm: d.grpNm, useYn: d.useYn, values: d.values || [] }) setEditing(true); setOpen(true) } catch (e) { alert(friendlyError(e)) } } function addValue() { setForm(f => ({ ...f, values: [...f.values, { grpCd: f.grpCd, codeVal: '', codeNm: '', sortOrd: f.values.length + 1, useYn: 'Y' }] })) } function setVal(i: number, patch: Partial) { setForm(f => ({ ...f, values: f.values.map((v, idx) => idx === i ? { ...v, ...patch } : v) })) } function removeValue(i: number) { setForm(f => ({ ...f, values: f.values.filter((_, idx) => idx !== i) })) } async function save() { setErr('') if (!form.grpCd.trim() || !form.grpNm.trim()) { setErr('그룹 코드와 이름은 필수입니다.'); return } const body = { ...form, values: form.values.map(v => ({ ...v, grpCd: form.grpCd })) } try { if (editing) await codeUpdate(form.grpCd, body) else await codeCreate(body) setOpen(false); load() } catch (e) { setErr(friendlyError(e)) } } async function remove(grpCd: string) { if (!confirm(`코드 그룹 '${grpCd}' 을(를) 삭제할까요?`)) return try { await codeDelete(grpCd); load() } catch (e) { alert(friendlyError(e)) } } const totalPages = Math.max(1, Math.ceil(total / PSIZE)) const columns: Column>[] = [ { key: 'grpCd', header: '그룹 코드', render: r => {r.grpCd} }, { key: 'grpNm', header: '그룹명' }, { key: 'useYn', header: '사용', width: 80, render: r => }, { key: 'act', header: '', width: 64, align: 'right', render: r => ( ) }, ] return (
그룹 추가} /> {loading ? : ( <> )[]} rowKey={r => r.grpCd} onRowClick={r => openEdit(r)} empty="등록된 코드 그룹이 없습니다." /> { setPage(p); load(p) }} /> )} {open && ( setOpen(false)}>
setForm({ ...form, grpCd: v })} placeholder="예: ALARM_TYPE" style={{ width: '100%' }} /> setForm({ ...form, grpNm: v })} style={{ width: '100%' }} />
setForm({ ...form, useYn: v })} placeholder="Y / N" />
코드값
{form.values.length === 0 ? ( ) : form.values.map((v, i) => ( ))}
코드값 코드명 순서 사용
코드값이 없습니다.
setVal(i, { codeVal: x })} style={{ width: '100%', padding: '6px 8px' }} /> setVal(i, { codeNm: x })} style={{ width: '100%', padding: '6px 8px' }} /> setVal(i, { sortOrd: x === '' ? null : Number(x) })} style={{ width: '100%', padding: '6px 8px' }} /> setVal(i, { useYn: x })} style={{ width: '100%', padding: '6px 8px' }} />
{err &&

{err}

}
)}
) }