feat(WEB): 결재/회계/품목 관리 개선

- ApprovalLineSection/ReferenceSection: 결재선 설정 개선
- DepositManagement/WithdrawalManagement: 입출금 관리 UI 개선
- bills/pricing-management 페이지 수정
- ItemDetailClient: 품목 상세 표시 개선
This commit is contained in:
2025-12-30 17:22:19 +09:00
parent 62bf081adb
commit ec0ad53837
5 changed files with 66 additions and 18 deletions

View File

@@ -47,7 +47,7 @@ async function getBills(params: {
queryParams.append('per_page', '20');
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/bills?${queryParams.toString()}`,
`${process.env.API_URL}/api/v1/bills?${queryParams.toString()}`,
{ method: 'GET', headers, cache: 'no-store' }
);

View File

@@ -150,7 +150,7 @@ async function getItemsList(): Promise<ItemApiData[]> {
const headers = await getApiHeaders();
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/items?group_id=1&size=100`,
`${process.env.API_URL}/api/v1/items?group_id=1&size=100`,
{
method: 'GET',
headers,
@@ -183,7 +183,7 @@ async function getPricingList(): Promise<PriceApiItem[]> {
const headers = await getApiHeaders();
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/pricing?size=100`,
`${process.env.API_URL}/api/v1/pricing?size=100`,
{
method: 'GET',
headers,

View File

@@ -58,7 +58,7 @@ import {
DEPOSIT_TYPE_FILTER_OPTIONS,
ACCOUNT_SUBJECT_OPTIONS,
} from './types';
import { deleteDeposit, updateDepositTypes } from './actions';
import { deleteDeposit, updateDepositTypes, getDeposits } from './actions';
import { toast } from 'sonner';
// ===== 컴포넌트 Props =====
@@ -104,6 +104,9 @@ export function DepositManagement({ initialData, initialPagination }: DepositMan
// 입금 데이터 (서버에서 전달받은 initialData 사용)
const [data, setData] = useState<DepositRecord[]>(initialData);
// 로딩 상태
const [isRefreshing, setIsRefreshing] = useState(false);
// ===== 체크박스 핸들러 =====
const toggleSelection = useCallback((id: string) => {
setSelectedItems(prev => {
@@ -200,10 +203,30 @@ export function DepositManagement({ initialData, initialPagination }: DepositMan
}, [deleteTargetId]);
// 새로고침 핸들러
const handleRefresh = useCallback(() => {
// TODO: API 호출로 최신 데이터 조회
toast.info('새로고침 기능 준비 중입니다.');
}, []);
const handleRefresh = useCallback(async () => {
setIsRefreshing(true);
try {
const result = await getDeposits({
perPage: 100,
startDate,
endDate,
depositType: depositTypeFilter !== 'all' ? depositTypeFilter : undefined,
search: searchQuery || undefined,
});
if (result.success) {
setData(result.data);
setSelectedItems(new Set());
setCurrentPage(1);
toast.success('데이터를 새로고침했습니다.');
} else {
toast.error(result.error || '새로고침에 실패했습니다.');
}
} catch {
toast.error('새로고침 중 오류가 발생했습니다.');
} finally {
setIsRefreshing(false);
}
}, [startDate, endDate, depositTypeFilter, searchQuery]);
// ===== 통계 카드 (총 입금, 당월 입금, 거래처 미설정, 입금유형 미설정) =====
const statCards: StatCard[] = useMemo(() => {
@@ -480,9 +503,10 @@ export function DepositManagement({ initialData, initialPagination }: DepositMan
<Button
variant="outline"
onClick={handleRefresh}
disabled={isRefreshing}
>
<RefreshCw className="h-4 w-4 mr-2" />
<RefreshCw className={`h-4 w-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />
{isRefreshing ? '조회중...' : '새로고침'}
</Button>
</div>
);

View File

@@ -56,7 +56,7 @@ import {
WITHDRAWAL_TYPE_FILTER_OPTIONS,
ACCOUNT_SUBJECT_OPTIONS,
} from './types';
import { deleteWithdrawal, updateWithdrawalTypes } from './actions';
import { deleteWithdrawal, updateWithdrawalTypes, getWithdrawals } from './actions';
import { toast } from 'sonner';
// ===== 컴포넌트 Props =====
@@ -102,6 +102,9 @@ export function WithdrawalManagement({ initialData, initialPagination }: Withdra
// 출금 데이터 (서버에서 전달받은 initialData 사용)
const [data, setData] = useState<WithdrawalRecord[]>(initialData);
// 로딩 상태
const [isRefreshing, setIsRefreshing] = useState(false);
// ===== 체크박스 핸들러 =====
const toggleSelection = useCallback((id: string) => {
setSelectedItems(prev => {
@@ -198,10 +201,30 @@ export function WithdrawalManagement({ initialData, initialPagination }: Withdra
}, [deleteTargetId]);
// 새로고침 핸들러
const handleRefresh = useCallback(() => {
// TODO: API 호출로 최신 데이터 조회
toast.info('새로고침 기능 준비 중입니다.');
}, []);
const handleRefresh = useCallback(async () => {
setIsRefreshing(true);
try {
const result = await getWithdrawals({
perPage: 100,
startDate,
endDate,
withdrawalType: withdrawalTypeFilter !== 'all' ? withdrawalTypeFilter : undefined,
search: searchQuery || undefined,
});
if (result.success) {
setData(result.data);
setSelectedItems(new Set());
setCurrentPage(1);
toast.success('데이터를 새로고침했습니다.');
} else {
toast.error(result.error || '새로고침에 실패했습니다.');
}
} catch {
toast.error('새로고침 중 오류가 발생했습니다.');
} finally {
setIsRefreshing(false);
}
}, [startDate, endDate, withdrawalTypeFilter, searchQuery]);
// ===== 통계 카드 (총 출금, 당월 출금, 거래처 미설정, 출금유형 미설정) =====
const statCards: StatCard[] = useMemo(() => {
@@ -474,9 +497,10 @@ export function WithdrawalManagement({ initialData, initialPagination }: Withdra
<Button
variant="outline"
onClick={handleRefresh}
disabled={isRefreshing}
>
<RefreshCw className="h-4 w-4 mr-2" />
<RefreshCw className={`h-4 w-4 mr-2 ${isRefreshing ? 'animate-spin' : ''}`} />
{isRefreshing ? '조회중...' : '새로고침'}
</Button>
</div>
);

View File

@@ -86,7 +86,7 @@ function getStorageUrl(path: string | undefined): string | null {
return path;
}
// 상대 경로인 경우
const apiUrl = process.env.NEXT_PUBLIC_API_URL || '';
const apiUrl = process.env.API_URL || '';
return `${apiUrl}/storage/${path}`;
}