import { useState } from 'react'; import { Alert, Form, Input, InputNumber, Modal, Select, Space, Tabs, message } from 'antd'; import { ProCard } from '@ant-design/pro-components'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import type { ColDef } from '@ag-grid-community/core'; import dayjs from 'dayjs'; 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 { commissionApi, RecruiterRuleRow, RecruiterLedgerRow, CommissionSearchParam, } from '@/api/commission'; import { GRAY, RADIUS, SHADOW } from '@/theme/tokens'; const fmt = (v: unknown) => (v as number)?.toLocaleString() ?? '-'; const RECRUITER_TYPE_OPTIONS = [ { value: 'NEW_RECRUIT', label: '신인도입' }, { value: 'DEVELOPMENT', label: '육성' }, { value: 'TRAINING', label: '교육' }, ]; const RULE_COLS: ColDef[] = [ { field: 'recruiterType', headerName: '유형', width: 120 }, { field: 'calcType', headerName: '계산방식', width: 110 }, { field: 'commissionRate', headerName: '수수료율', width: 110, type: 'numericColumn' }, { field: 'fixedAmount', headerName: '정액', flex: 1, type: 'numericColumn', valueFormatter: (p) => fmt(p.value) }, { field: 'effectiveFrom', headerName: '적용시작', width: 120 }, { field: 'effectiveTo', headerName: '적용종료', width: 120 }, ]; const LEDGER_COLS: ColDef[] = [ { field: 'settleMonth', headerName: '정산월', width: 110, pinned: 'left' }, { field: 'recruiterAgentName', headerName: '도입자', width: 130 }, { field: 'recruitAgentName', headerName: '피도입자', width: 130 }, { field: 'recruiterType', headerName: '유형', width: 110 }, { field: 'baseAmount', headerName: '기준금액', flex: 1, type: 'numericColumn', valueFormatter: (p) => fmt(p.value) }, { field: 'commissionAmount', headerName: '수수료', flex: 1, type: 'numericColumn', valueFormatter: (p) => fmt(p.value) }, { field: 'status', headerName: '상태', width: 110 }, ]; export default function RecruiterCommission() { const qc = useQueryClient(); const [ledgerParams, setLedgerParams] = useState({ settleMonth: dayjs().format('YYYYMM'), pageSize: 200, }); const [ruleModalOpen, setRuleModalOpen] = useState(false); const [editingRule, setEditingRule] = useState(null); const [form] = Form.useForm(); const { data: rulesData, isLoading: rulesLoading, isError: rulesError } = useQuery({ queryKey: ['recruiterCommission', 'rules'], queryFn: () => commissionApi.recruiterRules(), retry: false, }); const { data: ledgersData, isLoading: ledgersLoading } = useQuery({ queryKey: ['recruiterCommission', 'ledgers', ledgerParams], queryFn: () => commissionApi.recruiterLedgers(ledgerParams), retry: false, }); const rules = rulesData?.list ?? []; const ledgers = ledgersData?.list ?? []; const saveMutation = useMutation({ mutationFn: async (values: Partial) => { if (editingRule) { return commissionApi.recruiterRuleUpdate(editingRule.ruleId, values); } return commissionApi.recruiterRuleCreate(values); }, onSuccess: () => { message.success(editingRule ? '수정 완료' : '등록 완료'); qc.invalidateQueries({ queryKey: ['recruiterCommission', 'rules'] }); setRuleModalOpen(false); }, }); const openCreate = () => { setEditingRule(null); form.resetFields(); setRuleModalOpen(true); }; const openEdit = (row: RecruiterRuleRow) => { setEditingRule(row); form.setFieldsValue(row); setRuleModalOpen(true); }; const handleSave = async () => { const values = await form.validateFields(); saveMutation.mutate(values); }; const handleDelete = (id: number) => Modal.confirm({ title: '룰 삭제', content: '삭제하시겠습니까?', onOk: async () => { await commissionApi.recruiterRuleDelete(id); message.success('삭제 완료'); qc.invalidateQueries({ queryKey: ['recruiterCommission', 'rules'] }); }, }); const pinnedLedger = ledgers.length > 0 ? { recruiterAgentName: '합계', baseAmount: ledgers.reduce((s, r) => s + (r.baseAmount ?? 0), 0), commissionAmount: ledgers.reduce((s, r) => s + (r.commissionAmount ?? 0), 0), } as Partial : undefined; const cardStyle = { background: '#fff', borderRadius: RADIUS.lg, border: `1px solid ${GRAY[100]}`, boxShadow: SHADOW.sm }; return ( {rulesError && ( )}
+ 룰 등록
rows={rules} columns={[ ...RULE_COLS, { headerName: '액션', width: 160, pinned: 'right', cellRenderer: (p: { data: RecruiterRuleRow }) => ( openEdit(p.data)}>수정 handleDelete(p.data.ruleId)}>삭제 ), }, ]} loading={rulesLoading} height={520} rowKey="ruleId" /> ), }, { key: 'ledgers', label: '원장', children: ( <> setLedgerParams({ ...v as CommissionSearchParam, pageSize: 200 })} onReset={() => setLedgerParams({ settleMonth: dayjs().format('YYYYMM'), pageSize: 200 })} /> rows={ledgers} columns={LEDGER_COLS} loading={ledgersLoading} height={520} rowKey="ledgerId" pinnedBottomRow={pinnedLedger} /> ), }, ]} /> setRuleModalOpen(false)} okText="저장" cancelText="취소" confirmLoading={saveMutation.isPending} >
); }