149 lines
6.5 KiB
TypeScript
149 lines
6.5 KiB
TypeScript
|
|
import { useState } from 'react';
|
||
|
|
import { Alert, Form, Input, InputNumber, Modal, Space, Tag, message } from 'antd';
|
||
|
|
import { ProCard } from '@ant-design/pro-components';
|
||
|
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||
|
|
import type { ColDef } from '@ag-grid-community/core';
|
||
|
|
import PageContainer from '@/components/common/PageContainer';
|
||
|
|
import SearchForm from '@/components/common/SearchForm';
|
||
|
|
import DataGrid from '@/components/common/DataGrid';
|
||
|
|
import PermissionButton from '@/components/common/PermissionButton';
|
||
|
|
import { operationApi, GuaranteeInsuranceRow } from '@/api/operation';
|
||
|
|
import { GRAY, RADIUS, SHADOW } from '@/theme/tokens';
|
||
|
|
|
||
|
|
const fmt = (v: unknown) => (v as number)?.toLocaleString() ?? '-';
|
||
|
|
const cardStyle = { background: '#fff', borderRadius: RADIUS.lg, border: `1px solid ${GRAY[100]}`, boxShadow: SHADOW.sm };
|
||
|
|
|
||
|
|
const STATUS_COLOR: Record<string, string> = { ACTIVE: 'green', EXPIRED: 'default', CANCELLED: 'red' };
|
||
|
|
const STATUS_LABEL: Record<string, string> = { ACTIVE: '유효', EXPIRED: '만료', CANCELLED: '해지' };
|
||
|
|
|
||
|
|
const COLS: ColDef<GuaranteeInsuranceRow>[] = [
|
||
|
|
{ field: 'agentName', headerName: '설계사', width: 130 },
|
||
|
|
{ field: 'policyNo', headerName: '증권번호', width: 160 },
|
||
|
|
{ field: 'carrierName', headerName: '보증보험사', width: 130 },
|
||
|
|
{ field: 'guaranteeAmount', headerName: '보증금액', width: 150, type: 'numericColumn', valueFormatter: (p) => fmt(p.value) },
|
||
|
|
{ field: 'startDate', headerName: '시작일', width: 110 },
|
||
|
|
{ field: 'endDate', headerName: '종료일', width: 110 },
|
||
|
|
{ field: 'status', headerName: '상태', width: 100,
|
||
|
|
cellRenderer: (p: { value: string }) => (
|
||
|
|
<Tag color={STATUS_COLOR[p.value] ?? 'default'}>{STATUS_LABEL[p.value] ?? p.value}</Tag>
|
||
|
|
) },
|
||
|
|
];
|
||
|
|
|
||
|
|
export default function GuaranteeInsurance() {
|
||
|
|
const qc = useQueryClient();
|
||
|
|
const [searchParams, setSearchParams] = useState<{ agentName?: string; status?: string }>({});
|
||
|
|
const [modalOpen, setModalOpen] = useState(false);
|
||
|
|
const [editingRow, setEditingRow] = useState<GuaranteeInsuranceRow | null>(null);
|
||
|
|
const [form] = Form.useForm();
|
||
|
|
|
||
|
|
const { data, isLoading, isError } = useQuery({
|
||
|
|
queryKey: ['guarantee-insurance', 'list', searchParams],
|
||
|
|
queryFn: () => operationApi.guaranteeInsuranceList(searchParams),
|
||
|
|
retry: false,
|
||
|
|
});
|
||
|
|
|
||
|
|
const rows = data?.list ?? [];
|
||
|
|
|
||
|
|
const openCreate = () => { setEditingRow(null); form.resetFields(); setModalOpen(true); };
|
||
|
|
const openEdit = (row: GuaranteeInsuranceRow) => { setEditingRow(row); form.setFieldsValue(row); setModalOpen(true); };
|
||
|
|
|
||
|
|
const handleSave = async () => {
|
||
|
|
const values = await form.validateFields();
|
||
|
|
try {
|
||
|
|
if (editingRow) {
|
||
|
|
await operationApi.guaranteeInsuranceUpdate(editingRow.guaranteeId, values);
|
||
|
|
message.success('수정 완료');
|
||
|
|
} else {
|
||
|
|
await operationApi.guaranteeInsuranceCreate(values);
|
||
|
|
message.success('등록 완료');
|
||
|
|
}
|
||
|
|
qc.invalidateQueries({ queryKey: ['guarantee-insurance', 'list'] });
|
||
|
|
setModalOpen(false);
|
||
|
|
} catch { /* request.ts 처리 */ }
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleDelete = (id: number) => Modal.confirm({
|
||
|
|
title: '보증보험 삭제', content: '삭제하시겠습니까?',
|
||
|
|
onOk: async () => {
|
||
|
|
await operationApi.guaranteeInsuranceDelete(id);
|
||
|
|
message.success('삭제 완료');
|
||
|
|
qc.invalidateQueries({ queryKey: ['guarantee-insurance', 'list'] });
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
const actionCol: ColDef<GuaranteeInsuranceRow> = {
|
||
|
|
headerName: '액션', width: 160, pinned: 'right',
|
||
|
|
cellRenderer: (p: { data: GuaranteeInsuranceRow }) => (
|
||
|
|
<Space>
|
||
|
|
<PermissionButton menuCode="GUARANTEE_INS" permCode="UPDATE" size="small" onClick={() => openEdit(p.data)}>수정</PermissionButton>
|
||
|
|
<PermissionButton menuCode="GUARANTEE_INS" permCode="DELETE" size="small" danger onClick={() => handleDelete(p.data.guaranteeId)}>삭제</PermissionButton>
|
||
|
|
</Space>
|
||
|
|
),
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<PageContainer title="보증보험" description="설계사 신원보증보험 가입현황 관리">
|
||
|
|
{isError && (
|
||
|
|
<Alert type="warning" showIcon message="API 미응답" description="/api/guarantee-insurances 를 확인하세요." style={{ marginBottom: 16 }} />
|
||
|
|
)}
|
||
|
|
|
||
|
|
<SearchForm
|
||
|
|
conditions={[
|
||
|
|
{ type: 'text', name: 'agentName', label: '설계사명', span: 6 },
|
||
|
|
{ type: 'text', name: 'status', label: '상태', span: 6 },
|
||
|
|
]}
|
||
|
|
onSearch={(v) => setSearchParams({ agentName: v.agentName as string, status: v.status as string })}
|
||
|
|
onReset={() => setSearchParams({})}
|
||
|
|
/>
|
||
|
|
|
||
|
|
<ProCard style={cardStyle}>
|
||
|
|
<div style={{ marginBottom: 12 }}>
|
||
|
|
<PermissionButton menuCode="GUARANTEE_INS" permCode="CREATE" type="primary" onClick={openCreate}>
|
||
|
|
+ 보증보험 등록
|
||
|
|
</PermissionButton>
|
||
|
|
</div>
|
||
|
|
<DataGrid<GuaranteeInsuranceRow>
|
||
|
|
rows={rows}
|
||
|
|
columns={[...COLS, actionCol]}
|
||
|
|
loading={isLoading}
|
||
|
|
height={520}
|
||
|
|
rowKey="guaranteeId"
|
||
|
|
/>
|
||
|
|
</ProCard>
|
||
|
|
|
||
|
|
<Modal
|
||
|
|
title={editingRow ? '보증보험 수정' : '보증보험 등록'}
|
||
|
|
open={modalOpen}
|
||
|
|
onOk={handleSave}
|
||
|
|
onCancel={() => setModalOpen(false)}
|
||
|
|
okText="저장"
|
||
|
|
cancelText="취소"
|
||
|
|
>
|
||
|
|
<Form form={form} layout="vertical">
|
||
|
|
<Form.Item name="agentId" label="설계사ID" rules={[{ required: true }]}>
|
||
|
|
<InputNumber style={{ width: '100%' }} min={1} />
|
||
|
|
</Form.Item>
|
||
|
|
<Form.Item name="policyNo" label="증권번호" rules={[{ required: true }]}>
|
||
|
|
<Input />
|
||
|
|
</Form.Item>
|
||
|
|
<Form.Item name="carrierId" label="보증보험사ID">
|
||
|
|
<InputNumber style={{ width: '100%' }} min={1} />
|
||
|
|
</Form.Item>
|
||
|
|
<Form.Item name="guaranteeAmount" label="보증금액" rules={[{ required: true }]}>
|
||
|
|
<InputNumber style={{ width: '100%' }} min={0} />
|
||
|
|
</Form.Item>
|
||
|
|
<Form.Item name="startDate" label="보증시작(YYYY-MM-DD)" rules={[{ required: true }]}>
|
||
|
|
<Input placeholder="2025-01-01" />
|
||
|
|
</Form.Item>
|
||
|
|
<Form.Item name="endDate" label="보증종료(YYYY-MM-DD)" rules={[{ required: true }]}>
|
||
|
|
<Input placeholder="2026-01-01" />
|
||
|
|
</Form.Item>
|
||
|
|
<Form.Item name="status" label="상태">
|
||
|
|
<Input placeholder="ACTIVE / EXPIRED / CANCELLED" />
|
||
|
|
</Form.Item>
|
||
|
|
</Form>
|
||
|
|
</Modal>
|
||
|
|
</PageContainer>
|
||
|
|
);
|
||
|
|
}
|