Add Customs page to Common Information menu

This commit is contained in:
backuppc
2025-12-02 15:27:21 +09:00
parent e82f86191a
commit 2d160ceabb
3 changed files with 141 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import { Layout } from '@/components/layout';
import { Dashboard, Todo, Kuntae, Jobreport, Project, Login, CommonCodePage, ItemsPage, UserListPage, MonthlyWorkPage, MailFormPage, UserAuthPage, Note } from '@/pages';
import { PatchList } from '@/pages/PatchList';
import { MailList } from '@/pages/MailList';
import { Customs } from '@/pages/Customs';
import { comms } from '@/communication';
import { UserInfo } from '@/types';
import { Loader2 } from 'lucide-react';
@@ -90,6 +91,7 @@ export default function App() {
<Route path="/project" element={<Project />} />
<Route path="/common" element={<CommonCodePage />} />
<Route path="/items" element={<ItemsPage />} />
<Route path="/customs" element={<Customs />} />
<Route path="/user/list" element={<UserListPage />} />
<Route path="/user/auth" element={<UserAuthPage />} />
<Route path="/monthly-work" element={<MonthlyWorkPage />} />

View File

@@ -19,6 +19,7 @@ import {
Shield,
List,
AlertTriangle,
Building,
Star,
} from 'lucide-react';
import { clsx } from 'clsx';
@@ -96,6 +97,7 @@ const dropdownMenus: DropdownMenuConfig[] = [
items: [
{ type: 'link', path: '/common', icon: Code, label: '공용코드' },
{ type: 'link', path: '/items', icon: Package, label: '품목정보' },
{ type: 'link', path: '/customs', icon: Building, label: '업체정보' },
{
type: 'submenu',
icon: Users,

View File

@@ -0,0 +1,137 @@
import { useState, useEffect } from 'react';
import { Building, Search, RefreshCw } from 'lucide-react';
// 임시 타입 정의 (실제 타입은 백엔드에 맞게 수정 필요)
interface CustomItem {
idx: number;
ccode: string;
cname: string;
gubun: string;
addr: string;
tel: string;
fax: string;
email: string;
ceo: string;
busino: string;
uptae: string;
jongmok: string;
}
export function Customs() {
const [customsList, setCustomsList] = useState<CustomItem[]>([]);
const [loading, setLoading] = useState(false);
const [searchKey, setSearchKey] = useState('');
useEffect(() => {
loadData();
}, []);
const loadData = async () => {
setLoading(true);
try {
// TODO: 실제 API 호출로 변경 필요
// const response = await comms.getCustomsList(searchKey);
// if (response.Success && response.Data) {
// setCustomsList(response.Data);
// }
// 임시 데이터
console.log('업체정보 조회 (구현 필요):', { searchKey });
alert('업체정보 API가 아직 구현되지 않았습니다.');
setCustomsList([]);
} catch (error) {
console.error('업체정보 로드 오류:', error);
alert('데이터를 불러오는 중 오류가 발생했습니다.');
} finally {
setLoading(false);
}
};
const handleSearch = () => {
loadData();
};
return (
<div className="space-y-6 animate-fade-in">
{/* 검색 필터 */}
<div className="glass-effect rounded-2xl p-6">
<div className="flex items-center gap-4">
<div className="flex items-center gap-2 flex-1">
<label className="text-white/70 text-sm font-medium whitespace-nowrap"></label>
<input
type="text"
value={searchKey}
onChange={(e) => setSearchKey(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSearch()}
placeholder="업체명, 사업자번호, 대표자 등"
className="flex-1 h-10 bg-white/20 border border-white/30 rounded-lg px-3 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400"
/>
</div>
<button
onClick={handleSearch}
disabled={loading}
className="h-10 bg-primary-500 hover:bg-primary-600 text-white px-6 rounded-lg transition-colors flex items-center justify-center disabled:opacity-50"
>
{loading ? (
<RefreshCw className="w-4 h-4 mr-2 animate-spin" />
) : (
<Search className="w-4 h-4 mr-2" />
)}
</button>
</div>
</div>
{/* 업체 목록 */}
<div className="glass-effect rounded-2xl overflow-hidden">
<div className="px-6 py-4 border-b border-white/10 flex items-center justify-between">
<h3 className="text-lg font-semibold text-white flex items-center">
<Building className="w-5 h-5 mr-2" />
</h3>
<span className="text-white/60 text-sm">{customsList.length}</span>
</div>
<div className="divide-y divide-white/10 max-h-[calc(100vh-300px)] overflow-y-auto">
{loading ? (
<div className="px-6 py-8 text-center">
<div className="flex items-center justify-center">
<RefreshCw className="w-5 h-5 mr-2 animate-spin text-white/50" />
<span className="text-white/50"> ...</span>
</div>
</div>
) : customsList.length === 0 ? (
<div className="px-6 py-8 text-center">
<Building className="w-12 h-12 mx-auto mb-3 text-white/30" />
<p className="text-white/50"> .</p>
<p className="text-white/40 text-sm mt-2"> API .</p>
</div>
) : (
customsList.map((item) => (
<div
key={item.idx}
className="px-6 py-4 hover:bg-white/5 transition-colors"
>
<div className="flex items-center justify-between gap-4">
<div className="flex-1 min-w-0">
<h4 className="text-white font-medium mb-1">{item.cname}</h4>
<div className="flex items-center gap-4 text-white/60 text-sm">
<div>: {item.ceo}</div>
<div>: {item.busino}</div>
<div>: {item.uptae}</div>
</div>
</div>
<div className="flex flex-col items-end gap-1 flex-shrink-0 text-white/60 text-sm">
<div>{item.tel}</div>
<div>{item.email}</div>
</div>
</div>
</div>
))
)}
</div>
</div>
</div>
);
}