diff --git a/public/favicon.png b/public/favicon.png deleted file mode 100644 index 58a0e94..0000000 Binary files a/public/favicon.png and /dev/null differ diff --git a/src/assets/index.less b/src/assets/index.less index 8983bb3..bad1278 100644 --- a/src/assets/index.less +++ b/src/assets/index.less @@ -70,7 +70,11 @@ body #root{ text-decoration: none; border-radius: 10px; } - +.table-operation-render{ + display: flex; + gap: 5px; + flex-wrap: wrap; +} .page-content-container { max-width: 90%; width: 1400px; diff --git a/src/components/bill/list.tsx b/src/components/bill/list.tsx index 8eca652..f0a7899 100644 --- a/src/components/bill/list.tsx +++ b/src/components/bill/list.tsx @@ -12,6 +12,7 @@ import {BillStatus} from "@/service/types.ts"; type BillListProps = { type: 'query' | 'reconciliation'; operationRender?: (record: BillModel) => React.ReactNode; + operationRenderWidth?: number; onRowSelection?: (selectedRowKeys: (string | number)[]) => void; source?: RecordList; onPageChange: (pageIndex:number) => void; @@ -30,7 +31,7 @@ export const BillList: React.FC = (props) => { return t('bill.pay_status_pending') case 'PAID': return t('bill.pay_status_paid') - case 'CANCELLED': + case 'CANCELED': return t('bill.pay_status_canceled') default: return billStatus @@ -58,7 +59,7 @@ export const BillList: React.FC = (props) => { title: t('base.student_number'), dataIndex: 'student_number', width: 150, - render: (value) => value ?? 'N/A' + render: (value) => value?.length ?value: 'N/A' }, { title: t('base.bill_number'), @@ -87,6 +88,7 @@ export const BillList: React.FC = (props) => { title: 'Email', dataIndex: 'student_email', width: 200, + render: (value) => value?.length ?value: 'N/A' // render: (_, record) => (
{record.student_english_name}
{record.student_chinese_name}
) }, { @@ -103,12 +105,13 @@ export const BillList: React.FC = (props) => { title: t('bill.title_year'), dataIndex: 'intake_year', width: 120, + render: (_, record) => (
{record.intake_year}/{record.intake_semester}
) }, - { - title: t('bill.title_semester'), - dataIndex: 'intake_semester', - width: 120, - }, + // { + // title: t('bill.title_semester'), + // dataIndex: 'intake_semester', + // width: 120, + // }, { title: t('bill.title_bill_detail'), dataIndex: 'detail', @@ -186,7 +189,7 @@ export const BillList: React.FC = (props) => { title: t('bill.title_operate'), dataIndex: 'operate', fixed: 'right', - width: props.type == 'reconciliation'?120:220, + width: props.operationRenderWidth || (props.type == 'reconciliation'?120:220), render: (_, record) => props.operationRender?.(record), }) } diff --git a/src/i18n/translations/en.json b/src/i18n/translations/en.json index e81a63b..4c7c6c4 100644 --- a/src/i18n/translations/en.json +++ b/src/i18n/translations/en.json @@ -23,6 +23,7 @@ "cancel_success": "Successful cancel bill", "confirm": "Check", "confirm_batch": "Batch Confirm", + "confirm_bill_type": "Confirm Bill", "confirm_confirm_title": "Confirm check the Bill?", "confirm_select_empty": "Require confirm bill data", "confirm_success": "Confirm success!", @@ -32,7 +33,7 @@ "paid": "Paid", "paid_confirm": "Please confirm the order status is set to paid", "pay_status": "Bill Status", - "pay_status_canceled": "CANCELLED", + "pay_status_canceled": "CANCELED", "pay_status_paid": "PAID", "pay_status_pending": "PENDING", "query_amount_current_page": "The total amount of current page", @@ -40,16 +41,20 @@ "reconciliation_status_pending": "UNCHECKED", "reconciliation_status_submitted": "CHECKED", "require_student_number": "Search Student Number", + "sort_asc": "ASC", + "sort_desc": "DESC", "title_actual_payment_amount": "Actually Paid", "title_amount": "Amount", "title_bill_detail": "Bill Detail", "title_bill_list": "Bill List", "title_bill_status": "Bill Status", + "title_create_at": "Input Date", "title_department": "Department", "title_operate": "Operation", "title_paid_at": "Transaction Date", "title_pay_amount": "Pay Amount", "title_pay_method": "Pay Method", + "title_pay_sort": "Sort By", "title_program_id": "Program ID", "title_program_name": "Program", "title_reconciliation_status": "Reconciliation", @@ -57,11 +62,7 @@ "title_service_charge": "Service Charge", "title_student_name": "Student Name", "title_student_name_en": "English Name", - "title_year": "Year", - "title_create_at":"Input Date", - "title_pay_sort":"Sort By", - "sort_desc":"DESC", - "sort_asc":"ASC" + "title_year": "Year" }, "error": { "go_back": "Go Back", diff --git a/src/i18n/translations/sc.json b/src/i18n/translations/sc.json index 516cedb..baa0037 100644 --- a/src/i18n/translations/sc.json +++ b/src/i18n/translations/sc.json @@ -23,6 +23,7 @@ "cancel_success": "作废账单成功", "confirm": "对账", "confirm_batch": "批量对账", + "confirm_bill_type": "确认账单", "confirm_confirm_title": "请确定对账此账单?", "confirm_select_empty": "对账账单为空", "confirm_success": "对账成功!", @@ -40,16 +41,20 @@ "reconciliation_status_pending": "未对账", "reconciliation_status_submitted": "已对账", "require_student_number": "请输入查询学号", + "sort_asc": "升序", + "sort_desc": "降序", "title_actual_payment_amount": "实付金额", "title_amount": "账单金额", "title_bill_detail": "账单详情", "title_bill_list": "账单列表", "title_bill_status": "账单状态", + "title_create_at": "创建时间", "title_department": "学系", "title_operate": "操作", "title_paid_at": "支付时间", "title_pay_amount": "应付金额", "title_pay_method": "支付方式", + "title_pay_sort": "排序方式", "title_program_id": "专业ID", "title_program_name": "就读专业", "title_reconciliation_status": "对账状态", @@ -57,11 +62,7 @@ "title_service_charge": "手续费", "title_student_name": "学生姓名", "title_student_name_en": "英文名称", - "title_year": "学年", - "title_create_at":"创建时间", - "title_pay_sort":"排序方式", - "sort_desc":"降序", - "sort_asc":"升序" + "title_year": "学年" }, "error": { "go_back": "返回上一页", diff --git a/src/i18n/translations/tc.json b/src/i18n/translations/tc.json index 8d740b3..f16a23d 100644 --- a/src/i18n/translations/tc.json +++ b/src/i18n/translations/tc.json @@ -23,6 +23,7 @@ "cancel_success": "作廢帳單成功", "confirm": "對帳", "confirm_batch": "批次對帳", + "confirm_bill_type": "確認賬單", "confirm_confirm_title": "請確定對帳此帳單?", "confirm_select_empty": "對帳帳單為空", "confirm_success": "對帳成功!", @@ -40,16 +41,20 @@ "reconciliation_status_pending": "未對帳", "reconciliation_status_submitted": "已對帳", "require_student_number": "請輸入查詢學號", + "sort_asc": "升序", + "sort_desc": "降序", "title_actual_payment_amount": "實付金額", "title_amount": "帳單金額", "title_bill_detail": "帳單詳情", "title_bill_list": "帳單清單", "title_bill_status": "帳單狀態", + "title_create_at": "創建時間", "title_department": "學系", "title_operate": "操作", "title_paid_at": "付款時間", "title_pay_amount": "應付金額", "title_pay_method": "付款方式", + "title_pay_sort": "排序方式", "title_program_id": "專業ID", "title_program_name": "就讀專業", "title_reconciliation_status": "對帳狀態", @@ -57,11 +62,7 @@ "title_service_charge": "手續費", "title_student_name": "學生姓名", "title_student_name_en": "英文名稱", - "title_year": "學年", - "title_create_at":"創建時間", - "title_pay_sort":"排序方式", - "sort_desc":"降序", - "sort_asc":"升序" + "title_year": "學年" }, "error": { "go_back": "返回上一頁", diff --git a/src/pages/bill/query.tsx b/src/pages/bill/query.tsx index d1e34e7..aca0554 100644 --- a/src/pages/bill/query.tsx +++ b/src/pages/bill/query.tsx @@ -1,4 +1,4 @@ -import {Button, Modal, Notification, Popconfirm, Space, Toast} from "@douyinfe/semi-ui"; +import {Button, Modal, Notification, Popconfirm, Space, Tag, Toast} from "@douyinfe/semi-ui"; import {useState} from "react"; import {useRequest, useSetState} from "ahooks"; import {useTranslation} from "react-i18next"; @@ -11,13 +11,13 @@ import {BillStatus, BizError} from "@/service/types.ts"; import {useDownloadReceiptPDF} from "@/service/generate-pdf.ts"; import useAuth from "@/hooks/useAuth.ts"; import {BillDetailItems} from "@/components/bill"; +import MoneyFormat from "@/components/money-format.tsx"; -const DownloadButton = ({bill,text}: { bill: BillModel;text:string }) => { - const {loading: downloading, downloadPDF} = useDownloadReceiptPDF() - return () +const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => { + const {loading: downloading, downloadPDF} = useDownloadReceiptPDF() + return () } // const ConfirmPaidBill =({bill,onRefresh}: { bill: BillModel;onRefresh:()=>void }) => { @@ -25,63 +25,66 @@ const DownloadButton = ({bill,text}: { bill: BillModel;text:string }) => { // } const BillQuery = () => { - const {user} = useAuth(); - const [state,setState] = useSetState<{ - updateBill?: BillModel - updateLoading?:boolean - }>({}) - const [showBill, setShowBill] = useState() - const [queryParams, setBillQueryParams] = useState({}); - const {data, loading, refresh} = useRequest(() => billList({ - ...queryParams, - department: user?.department == 'RO' ? 'RO' : 'FO', - }), { - refreshDeps: [queryParams], - onError: (e) => { - Notification.error({title: 'Error', content: e.message}) - } - }) - const {t} = useTranslation() + const {user} = useAuth(); + const [state, setState] = useSetState<{ + updateBill?: BillModel + updateLoading?: boolean + confirmBill?: BillModel + }>({}) + const [showBill, setShowBill] = useState() + const [queryParams, setBillQueryParams] = useState({}); + const {data, loading, refresh} = useRequest(() => billList({ + ...queryParams, + department: user?.department == 'RO' ? 'RO' : 'FO', + }), { + refreshDeps: [queryParams], + onError: (e) => { + Notification.error({title: 'Error', content: e.message}) + } + }) + const {t} = useTranslation() - const onConfirmCancel = (bill: BillModel) => { - modifyBillStatus(bill.id,'CANCELLED').then(() => { - Notification.success({title: 'Notice', content: t('bill.cancel_success')}) - refresh() - }).catch((e:BizError) => { - Toast.error({ - content: `${t('base.operate_fail')}:${e.message}`, - duration: 3 - }) - }) - } + const onConfirmCancel = (bill: BillModel) => { + modifyBillStatus(bill.id, 'CANCELLED').then(() => { + Notification.success({title: 'Notice', content: t('bill.cancel_success')}) + refresh() + }).catch((e: BizError) => { + Toast.error({ + content: `${t('base.operate_fail')}:${e.message}`, + duration: 3 + }) + }) + } - const onConfirmPaid = () => { - if(!state.updateBill) return; - setState({ - updateLoading: true - }) - modifyBillStatus(state.updateBill.id,'PAID').then(() => { - setState({ - updateBill: undefined,updateLoading: false - }) - Notification.success({title: 'Notice', content: t('base.operate_success')}) - refresh() - }).catch((e:BizError) => { + const onConfirmPaid = () => { + if (!state.updateBill) return; + setState({ + updateLoading: true + }) + modifyBillStatus(state.updateBill.id, 'PAID').then(() => { + setState({ + updateBill: undefined, updateLoading: false + }) + Notification.success({title: 'Notice', content: t('base.operate_success')}) + refresh() + }).catch((e: BizError) => { setState({ updateLoading: false }) - Toast.error({ - content: `${t('base.operate_fail')}:${e.message}`, - duration: 3 - }) - }) - } - const operation = (bill: BillModel) => { + Toast.error({ + content: `${t('base.operate_fail')}:${e.message}`, + duration: 3 + }) + }) + } + const operation = (bill: BillModel) => { - return ( - {bill.status != BillStatus.PAID && - } - {bill.status == BillStatus.PENDING && <> + return (
+ {bill.status != BillStatus.PAID && + + } + {bill.status == BillStatus.PENDING && <> { - {AppMode == 'development' && 支付} + {AppMode == 'development' && 支付} } - { - bill.status == BillStatus.PAID && - } - ) - } - return (
- - { - setBillQueryParams({ - ...queryParams, - page_number - }) - }} - /> - setShowBill(undefined)} //>=1.16.0 - closeOnEsc={true} - footer={null} - closeIcon={} - > - {showBill && setShowBill(undefined)}/>} - - { - setState({updateBill:undefined,updateLoading:false}) - }} - confirmLoading={state.updateLoading} - onOk={onConfirmPaid} - okText={t('base.confirm_paid')} - maskClosable={false} - > - {state.updateBill &&
} -

{t('bill.paid_confirm')}

-
-
) + { + bill.status == BillStatus.PAID && <> + + + + } +
) + } + return (
+ + { + setBillQueryParams({ + ...queryParams, + page_number + }) + }} + /> + setShowBill(undefined)} //>=1.16.0 + closeOnEsc={true} + footer={null} + closeIcon={} + > + {showBill && setShowBill(undefined)}/>} + + { + setState({updateBill: undefined, updateLoading: false}) + }} + confirmLoading={state.updateLoading} + onOk={onConfirmPaid} + okText={t('base.confirm_paid')} + maskClosable={false} + > + {state.updateBill &&
} +

{t('bill.paid_confirm')}

+
+ { + setState({confirmBill: undefined}) + }} + footer={null} + > + {state.confirmBill && <> +
+
+ { + state.confirmBill.details.map((it, idx) => (
+ + {it.id}. + {it.bill_type} +
+ +
+
+
+ {!!it.confirm_status ? CONFIRMED:} + +
+
)) + } +
+ } +
+
) } export default BillQuery \ No newline at end of file diff --git a/src/types/bill.d.ts b/src/types/bill.d.ts index 7f1e5fc..b119cc5 100644 --- a/src/types/bill.d.ts +++ b/src/types/bill.d.ts @@ -12,6 +12,7 @@ declare type BillDetail = { id: string | number; bill_id: string | number; bill_type: string; + confirm_status?: number; amount: decimal; } /**