import { Button, Col, Descriptions, Divider, Form, InputNumber, Modal, Row, Select, Space, Toast } from "@douyinfe/semi-ui"; import {IconAlertCircle} from "@douyinfe/semi-icons"; import {Data} from "@douyinfe/semi-ui/lib/es/descriptions"; import React, {useMemo} from "react"; import {useTranslation} from "react-i18next"; import {useSetState} from "ahooks"; import {useBillTypes} from "@/hooks/useBillTypes.ts"; import {usePaymentChannels} from "@/hooks/usePaymentChannels.ts"; import {addBillRecord} from "@/service/api/bill.ts" import dayjs from "dayjs"; import MoneyFormat from "@/components/money-format.tsx"; import {BizError} from "@/service/types.ts"; type BillPaidModalProps = { onConfirm: () => void onCancel?: () => void } type BillTypeListProps = { onClose?: (refresh?: boolean) => void; onChange?: (confirms: ConfirmedBillDetail[]) => void; } export const BillTypeList: React.FC = (props) => { const {t} = useTranslation() const [state, setState] = useSetState<{ confirmed: ConfirmedBillDetail[] }>({ confirmed: [{bill_type: '', amount: 0}] }) const BillTypes = useBillTypes() const onChange = (value: string, index: number, type: 'type' | 'amount') => { if (state.confirmed.length <= index || !value) return; const confirmed = [...state.confirmed] if (type == 'type') { confirmed[index].bill_type = value } else { confirmed[index].amount = Number(value) } setState({confirmed}) props.onChange?.(confirmed) } const addOrRemove = (index: number) => { // 不允许删除最后一个 if (index > -1 && state.confirmed.length <= 1) return; const confirmed = [...state.confirmed, ...(index == -1 ? [{bill_type: '', amount: 0}] : [])] if (index > -1) confirmed.splice(index, 1) setState({confirmed}) props.onChange?.(confirmed) } return (
{t('bill.title_bill_detail')} { state.confirmed.map((item, index) => (
onChange(String(v), index, 'amount')} style={{width: 140}}/>
)) }
) } export const AddBillModal: React.FC = (props) => { const {t, i18n} = useTranslation() const {paymentChannelList, paymentMethodList} = usePaymentChannels(); const [state, setState] = useSetState<{ loading?: boolean; confirmLoading?: boolean; open?: boolean; details: ConfirmedBillDetail[]; errorMessage?: string; errorConfirmMessage?: string; errorConfirmOk?: boolean; values?: CreateBillRecordModel; }>({ details: [] }) const onSubmit = (values: CreateBillRecordModel) => { if (state.details.length == 0) { setState({errorMessage: t('base.validate.error_details_message')}) return; } for (const it of state.details) { if (!it.bill_type || it.amount <= 0) { setState({errorMessage: t('base.validate.error_details_message')}) return; } } values.details = state.details values.check_student = true; values.initiated_paid_date = dayjs(values.initiated_paid_date).format("YYYY-MM-DD") values.paid_date = dayjs(values.paid_date).format("YYYY-MM-DD") values.delivered_date = dayjs(values.delivered_date).format("YYYY-MM-DD") setState({ loading: true, errorMessage: undefined, values,errorConfirmOk:false }) addBillRecord(values).then(() => { setState({open: false}) Toast.success(t('base.add_success')) props.onConfirm() }).catch((e: BizError) => { if (e.code == -50415) { // STUDENT_INFO_NOT_FOUND // duplicate setState({errorConfirmMessage: e.message,errorConfirmOk:true}) } else { setState({errorConfirmMessage: e.message}) } }).finally(() => { setState({ loading: false }) }) // } const handleClose = () => { setState({ loading: false, open: false, errorMessage: undefined }) } // process confirm const handleCloseConfirm = () => { setState({errorConfirmMessage: undefined}) } const handleConfirmAdd = () => { if (!state.values) return; setState({confirmLoading: true}) state.values.check_student = false; addBillRecord(state.values).then(() => { setState({ loading: false, open: false, errorMessage: undefined, errorConfirmMessage: undefined, }) Toast.success(t('base.add_success')) props.onConfirm() }).catch(e => { setState({errorConfirmMessage: e.message}) }).finally(() => { setState({ confirmLoading: false, }) }) } const details = useMemo(() => { if (!state.values) return; const { application_number, payment_channel, payment_method, student_email, merchant_ref, paid_area, initiated_paid_date, paid_date, delivered_date } = state.values //, span: 2 const _data: Data[] = [ {key: 'Merchant Ref', value: merchant_ref}, {key: t('bill.bill_number'), value: application_number}, {key: 'Email', value: student_email}, {key: t('bill.title_pay_channel'), value: payment_channel}, {key: t('bill.title_pay_method'), value: payment_method}, {key: t('bill.create.pay_area'), value: paid_area}, {key: t('bill.title_initiated_paid_at'), value: initiated_paid_date}, {key: t('bill.title_paid_at'), value: paid_date}, {key: t('bill.title_delivered_at'), value: delivered_date, span: 2}, ] state.details.forEach(it => { _data.push({key: t('bill.title_bill_type'), value: it.bill_type}) _data.push({key: t('bill.title_amount'), value: }) }); return _data }, [i18n.language, state.values]); return (<> onSubmit={onSubmit} initValues={{ merchant_ref: '', application_number: '', student_email: '', paid_area: '', initiated_paid_date: '', paid_date: '', delivered_date: '', payment_method: '', payment_channel: '', check_student: true, details: [] }}>
setState({details})}/> {state.errorMessage &&
{state.errorMessage}
}
{state.errorConfirmOk && } } > {t('base.title_error_tip')} {state.errorConfirmMessage &&
{state.errorConfirmMessage}
}
) }