update confirm ui

This commit is contained in:
LittleBoy 2024-07-27 21:35:37 +08:00
parent 7619ee2ba9
commit b4062b1a08
8 changed files with 176 additions and 127 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -70,7 +70,11 @@ body #root{
text-decoration: none; text-decoration: none;
border-radius: 10px; border-radius: 10px;
} }
.table-operation-render{
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.page-content-container { .page-content-container {
max-width: 90%; max-width: 90%;
width: 1400px; width: 1400px;

View File

@ -12,6 +12,7 @@ import {BillStatus} from "@/service/types.ts";
type BillListProps = { type BillListProps = {
type: 'query' | 'reconciliation'; type: 'query' | 'reconciliation';
operationRender?: (record: BillModel) => React.ReactNode; operationRender?: (record: BillModel) => React.ReactNode;
operationRenderWidth?: number;
onRowSelection?: (selectedRowKeys: (string | number)[]) => void; onRowSelection?: (selectedRowKeys: (string | number)[]) => void;
source?: RecordList<BillModel>; source?: RecordList<BillModel>;
onPageChange: (pageIndex:number) => void; onPageChange: (pageIndex:number) => void;
@ -30,7 +31,7 @@ export const BillList: React.FC<BillListProps> = (props) => {
return t('bill.pay_status_pending') return t('bill.pay_status_pending')
case 'PAID': case 'PAID':
return t('bill.pay_status_paid') return t('bill.pay_status_paid')
case 'CANCELLED': case 'CANCELED':
return t('bill.pay_status_canceled') return t('bill.pay_status_canceled')
default: default:
return billStatus return billStatus
@ -58,7 +59,7 @@ export const BillList: React.FC<BillListProps> = (props) => {
title: t('base.student_number'), title: t('base.student_number'),
dataIndex: 'student_number', dataIndex: 'student_number',
width: 150, width: 150,
render: (value) => value ?? 'N/A' render: (value) => value?.length ?value: 'N/A'
}, },
{ {
title: t('base.bill_number'), title: t('base.bill_number'),
@ -87,6 +88,7 @@ export const BillList: React.FC<BillListProps> = (props) => {
title: 'Email', title: 'Email',
dataIndex: 'student_email', dataIndex: 'student_email',
width: 200, width: 200,
render: (value) => value?.length ?value: 'N/A'
// render: (_, record) => (<div>{record.student_english_name}<br/>{record.student_chinese_name}</div>) // render: (_, record) => (<div>{record.student_english_name}<br/>{record.student_chinese_name}</div>)
}, },
{ {
@ -103,12 +105,13 @@ export const BillList: React.FC<BillListProps> = (props) => {
title: t('bill.title_year'), title: t('bill.title_year'),
dataIndex: 'intake_year', dataIndex: 'intake_year',
width: 120, width: 120,
render: (_, record) => (<div>{record.intake_year}/{record.intake_semester}</div>)
}, },
{ // {
title: t('bill.title_semester'), // title: t('bill.title_semester'),
dataIndex: 'intake_semester', // dataIndex: 'intake_semester',
width: 120, // width: 120,
}, // },
{ {
title: t('bill.title_bill_detail'), title: t('bill.title_bill_detail'),
dataIndex: 'detail', dataIndex: 'detail',
@ -186,7 +189,7 @@ export const BillList: React.FC<BillListProps> = (props) => {
title: t('bill.title_operate'), title: t('bill.title_operate'),
dataIndex: 'operate', dataIndex: 'operate',
fixed: 'right', fixed: 'right',
width: props.type == 'reconciliation'?120:220, width: props.operationRenderWidth || (props.type == 'reconciliation'?120:220),
render: (_, record) => props.operationRender?.(record), render: (_, record) => props.operationRender?.(record),
}) })
} }

View File

@ -23,6 +23,7 @@
"cancel_success": "Successful cancel bill", "cancel_success": "Successful cancel bill",
"confirm": "Check", "confirm": "Check",
"confirm_batch": "Batch Confirm", "confirm_batch": "Batch Confirm",
"confirm_bill_type": "Confirm Bill",
"confirm_confirm_title": "Confirm check the Bill?", "confirm_confirm_title": "Confirm check the Bill?",
"confirm_select_empty": "Require confirm bill data", "confirm_select_empty": "Require confirm bill data",
"confirm_success": "Confirm success!", "confirm_success": "Confirm success!",
@ -32,7 +33,7 @@
"paid": "Paid", "paid": "Paid",
"paid_confirm": "Please confirm the order status is set to paid", "paid_confirm": "Please confirm the order status is set to paid",
"pay_status": "Bill Status", "pay_status": "Bill Status",
"pay_status_canceled": "CANCELLED", "pay_status_canceled": "CANCELED",
"pay_status_paid": "PAID", "pay_status_paid": "PAID",
"pay_status_pending": "PENDING", "pay_status_pending": "PENDING",
"query_amount_current_page": "The total amount of current page", "query_amount_current_page": "The total amount of current page",
@ -40,16 +41,20 @@
"reconciliation_status_pending": "UNCHECKED", "reconciliation_status_pending": "UNCHECKED",
"reconciliation_status_submitted": "CHECKED", "reconciliation_status_submitted": "CHECKED",
"require_student_number": "Search Student Number", "require_student_number": "Search Student Number",
"sort_asc": "ASC",
"sort_desc": "DESC",
"title_actual_payment_amount": "Actually Paid", "title_actual_payment_amount": "Actually Paid",
"title_amount": "Amount", "title_amount": "Amount",
"title_bill_detail": "Bill Detail", "title_bill_detail": "Bill Detail",
"title_bill_list": "Bill List", "title_bill_list": "Bill List",
"title_bill_status": "Bill Status", "title_bill_status": "Bill Status",
"title_create_at": "Input Date",
"title_department": "Department", "title_department": "Department",
"title_operate": "Operation", "title_operate": "Operation",
"title_paid_at": "Transaction Date", "title_paid_at": "Transaction Date",
"title_pay_amount": "Pay Amount", "title_pay_amount": "Pay Amount",
"title_pay_method": "Pay Method", "title_pay_method": "Pay Method",
"title_pay_sort": "Sort By",
"title_program_id": "Program ID", "title_program_id": "Program ID",
"title_program_name": "Program", "title_program_name": "Program",
"title_reconciliation_status": "Reconciliation", "title_reconciliation_status": "Reconciliation",
@ -57,11 +62,7 @@
"title_service_charge": "Service Charge", "title_service_charge": "Service Charge",
"title_student_name": "Student Name", "title_student_name": "Student Name",
"title_student_name_en": "English Name", "title_student_name_en": "English Name",
"title_year": "Year", "title_year": "Year"
"title_create_at":"Input Date",
"title_pay_sort":"Sort By",
"sort_desc":"DESC",
"sort_asc":"ASC"
}, },
"error": { "error": {
"go_back": "Go Back", "go_back": "Go Back",

View File

@ -23,6 +23,7 @@
"cancel_success": "作废账单成功", "cancel_success": "作废账单成功",
"confirm": "对账", "confirm": "对账",
"confirm_batch": "批量对账", "confirm_batch": "批量对账",
"confirm_bill_type": "确认账单",
"confirm_confirm_title": "请确定对账此账单?", "confirm_confirm_title": "请确定对账此账单?",
"confirm_select_empty": "对账账单为空", "confirm_select_empty": "对账账单为空",
"confirm_success": "对账成功!", "confirm_success": "对账成功!",
@ -40,16 +41,20 @@
"reconciliation_status_pending": "未对账", "reconciliation_status_pending": "未对账",
"reconciliation_status_submitted": "已对账", "reconciliation_status_submitted": "已对账",
"require_student_number": "请输入查询学号", "require_student_number": "请输入查询学号",
"sort_asc": "升序",
"sort_desc": "降序",
"title_actual_payment_amount": "实付金额", "title_actual_payment_amount": "实付金额",
"title_amount": "账单金额", "title_amount": "账单金额",
"title_bill_detail": "账单详情", "title_bill_detail": "账单详情",
"title_bill_list": "账单列表", "title_bill_list": "账单列表",
"title_bill_status": "账单状态", "title_bill_status": "账单状态",
"title_create_at": "创建时间",
"title_department": "学系", "title_department": "学系",
"title_operate": "操作", "title_operate": "操作",
"title_paid_at": "支付时间", "title_paid_at": "支付时间",
"title_pay_amount": "应付金额", "title_pay_amount": "应付金额",
"title_pay_method": "支付方式", "title_pay_method": "支付方式",
"title_pay_sort": "排序方式",
"title_program_id": "专业ID", "title_program_id": "专业ID",
"title_program_name": "就读专业", "title_program_name": "就读专业",
"title_reconciliation_status": "对账状态", "title_reconciliation_status": "对账状态",
@ -57,11 +62,7 @@
"title_service_charge": "手续费", "title_service_charge": "手续费",
"title_student_name": "学生姓名", "title_student_name": "学生姓名",
"title_student_name_en": "英文名称", "title_student_name_en": "英文名称",
"title_year": "学年", "title_year": "学年"
"title_create_at":"创建时间",
"title_pay_sort":"排序方式",
"sort_desc":"降序",
"sort_asc":"升序"
}, },
"error": { "error": {
"go_back": "返回上一页", "go_back": "返回上一页",

View File

@ -23,6 +23,7 @@
"cancel_success": "作廢帳單成功", "cancel_success": "作廢帳單成功",
"confirm": "對帳", "confirm": "對帳",
"confirm_batch": "批次對帳", "confirm_batch": "批次對帳",
"confirm_bill_type": "確認賬單",
"confirm_confirm_title": "請確定對帳此帳單?", "confirm_confirm_title": "請確定對帳此帳單?",
"confirm_select_empty": "對帳帳單為空", "confirm_select_empty": "對帳帳單為空",
"confirm_success": "對帳成功!", "confirm_success": "對帳成功!",
@ -40,16 +41,20 @@
"reconciliation_status_pending": "未對帳", "reconciliation_status_pending": "未對帳",
"reconciliation_status_submitted": "已對帳", "reconciliation_status_submitted": "已對帳",
"require_student_number": "請輸入查詢學號", "require_student_number": "請輸入查詢學號",
"sort_asc": "升序",
"sort_desc": "降序",
"title_actual_payment_amount": "實付金額", "title_actual_payment_amount": "實付金額",
"title_amount": "帳單金額", "title_amount": "帳單金額",
"title_bill_detail": "帳單詳情", "title_bill_detail": "帳單詳情",
"title_bill_list": "帳單清單", "title_bill_list": "帳單清單",
"title_bill_status": "帳單狀態", "title_bill_status": "帳單狀態",
"title_create_at": "創建時間",
"title_department": "學系", "title_department": "學系",
"title_operate": "操作", "title_operate": "操作",
"title_paid_at": "付款時間", "title_paid_at": "付款時間",
"title_pay_amount": "應付金額", "title_pay_amount": "應付金額",
"title_pay_method": "付款方式", "title_pay_method": "付款方式",
"title_pay_sort": "排序方式",
"title_program_id": "專業ID", "title_program_id": "專業ID",
"title_program_name": "就讀專業", "title_program_name": "就讀專業",
"title_reconciliation_status": "對帳狀態", "title_reconciliation_status": "對帳狀態",
@ -57,11 +62,7 @@
"title_service_charge": "手續費", "title_service_charge": "手續費",
"title_student_name": "學生姓名", "title_student_name": "學生姓名",
"title_student_name_en": "英文名稱", "title_student_name_en": "英文名稱",
"title_year": "學年", "title_year": "學年"
"title_create_at":"創建時間",
"title_pay_sort":"排序方式",
"sort_desc":"降序",
"sort_asc":"升序"
}, },
"error": { "error": {
"go_back": "返回上一頁", "go_back": "返回上一頁",

View File

@ -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 {useState} from "react";
import {useRequest, useSetState} from "ahooks"; import {useRequest, useSetState} from "ahooks";
import {useTranslation} from "react-i18next"; import {useTranslation} from "react-i18next";
@ -11,13 +11,13 @@ import {BillStatus, BizError} from "@/service/types.ts";
import {useDownloadReceiptPDF} from "@/service/generate-pdf.ts"; import {useDownloadReceiptPDF} from "@/service/generate-pdf.ts";
import useAuth from "@/hooks/useAuth.ts"; import useAuth from "@/hooks/useAuth.ts";
import {BillDetailItems} from "@/components/bill"; import {BillDetailItems} from "@/components/bill";
import MoneyFormat from "@/components/money-format.tsx";
const DownloadButton = ({bill,text}: { bill: BillModel;text:string }) => { const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
const {loading: downloading, downloadPDF} = useDownloadReceiptPDF() const {loading: downloading, downloadPDF} = useDownloadReceiptPDF()
return (<Button return (<Button
onClick={() => downloadPDF(bill)} size={'small'} theme={'solid'} onClick={() => downloadPDF(bill)} size={'small'} loading={downloading}>{text}</Button>)
type={'primary'} loading={downloading}>{text}</Button>)
} }
// const ConfirmPaidBill =({bill,onRefresh}: { bill: BillModel;onRefresh:()=>void }) => { // const ConfirmPaidBill =({bill,onRefresh}: { bill: BillModel;onRefresh:()=>void }) => {
@ -25,63 +25,66 @@ const DownloadButton = ({bill,text}: { bill: BillModel;text:string }) => {
// } // }
const BillQuery = () => { const BillQuery = () => {
const {user} = useAuth(); const {user} = useAuth();
const [state,setState] = useSetState<{ const [state, setState] = useSetState<{
updateBill?: BillModel updateBill?: BillModel
updateLoading?:boolean updateLoading?: boolean
}>({}) confirmBill?: BillModel
const [showBill, setShowBill] = useState<BillModel>() }>({})
const [queryParams, setBillQueryParams] = useState<BillQueryParams>({}); const [showBill, setShowBill] = useState<BillModel>()
const {data, loading, refresh} = useRequest(() => billList({ const [queryParams, setBillQueryParams] = useState<BillQueryParams>({});
...queryParams, const {data, loading, refresh} = useRequest(() => billList({
department: user?.department == 'RO' ? 'RO' : 'FO', ...queryParams,
}), { department: user?.department == 'RO' ? 'RO' : 'FO',
refreshDeps: [queryParams], }), {
onError: (e) => { refreshDeps: [queryParams],
Notification.error({title: 'Error', content: e.message}) onError: (e) => {
} Notification.error({title: 'Error', content: e.message})
}) }
const {t} = useTranslation() })
const {t} = useTranslation()
const onConfirmCancel = (bill: BillModel) => { const onConfirmCancel = (bill: BillModel) => {
modifyBillStatus(bill.id,'CANCELLED').then(() => { modifyBillStatus(bill.id, 'CANCELLED').then(() => {
Notification.success({title: 'Notice', content: t('bill.cancel_success')}) Notification.success({title: 'Notice', content: t('bill.cancel_success')})
refresh() refresh()
}).catch((e:BizError) => { }).catch((e: BizError) => {
Toast.error({ Toast.error({
content: `${t('base.operate_fail')}:${e.message}`, content: `${t('base.operate_fail')}:${e.message}`,
duration: 3 duration: 3
}) })
}) })
} }
const onConfirmPaid = () => { const onConfirmPaid = () => {
if(!state.updateBill) return; if (!state.updateBill) return;
setState({ setState({
updateLoading: true updateLoading: true
}) })
modifyBillStatus(state.updateBill.id,'PAID').then(() => { modifyBillStatus(state.updateBill.id, 'PAID').then(() => {
setState({ setState({
updateBill: undefined,updateLoading: false updateBill: undefined, updateLoading: false
}) })
Notification.success({title: 'Notice', content: t('base.operate_success')}) Notification.success({title: 'Notice', content: t('base.operate_success')})
refresh() refresh()
}).catch((e:BizError) => { }).catch((e: BizError) => {
setState({ setState({
updateLoading: false updateLoading: false
}) })
Toast.error({ Toast.error({
content: `${t('base.operate_fail')}:${e.message}`, content: `${t('base.operate_fail')}:${e.message}`,
duration: 3 duration: 3
}) })
}) })
} }
const operation = (bill: BillModel) => { const operation = (bill: BillModel) => {
return (<Space> return (<div className={'table-operation-render'}>
{bill.status != BillStatus.PAID && <Button onClick={()=>setState({updateBill:bill})} size={'small'} theme={'solid'} type={'danger'}>{t('bill.paid')}</Button> {bill.status != BillStatus.PAID &&
} <Button onClick={() => setState({updateBill: bill})} size={'small'} theme={'solid'}
{bill.status == BillStatus.PENDING && <> type={'danger'}>{t('bill.paid')}</Button>
}
{bill.status == BillStatus.PENDING && <>
<Popconfirm <Popconfirm
title={'Notice'} title={'Notice'}
content={`${t('bill.cancel_confirm')}?`} content={`${t('bill.cancel_confirm')}?`}
@ -92,51 +95,86 @@ const BillQuery = () => {
</Popconfirm> </Popconfirm>
<Button onClick={() => setShowBill(bill)} size={'small'} theme={'solid'} <Button onClick={() => setShowBill(bill)} size={'small'} theme={'solid'}
type={'primary'}>{t('base.qr-code')}</Button> type={'primary'}>{t('base.qr-code')}</Button>
{AppMode == 'development' && <a href={`/pay?bill=${bill.id}`} target={'_blank'}></a>} {AppMode == 'development' && <a href={`/pay?bill=${bill.id}`} target={'_blank'}></a>}
</>} </>}
{ {
bill.status == BillStatus.PAID && <DownloadButton bill={bill} text={t('bill.download_receipt')}/> bill.status == BillStatus.PAID && <>
} <DownloadButton bill={bill} text={t('bill.download_receipt')}/>
</Space>) <Button onClick={() => setState({confirmBill: bill})}
} size={'small'} theme={'solid'}
return (<div> type={'primary'}>{t('bill.confirm_bill_type')}</Button>
<SearchForm showApply loading={loading} onSearch={setBillQueryParams}/> </>
<BillList }
type={'query'} loading={loading} </div>)
operationRender={operation} source={data} }
onPageChange={(page_number) => { return (<div>
setBillQueryParams({ <SearchForm showApply loading={loading} onSearch={setBillQueryParams}/>
...queryParams, <BillList
page_number type={'query'} loading={loading} source={data}
}) operationRender={operation} operationRenderWidth={180}
}} onPageChange={(page_number) => {
/> setBillQueryParams({
<Modal ...queryParams,
title="Bill Detail" page_number
visible={!!showBill} })
width={620} }}
onCancel={() => setShowBill(undefined)} //>=1.16.0 />
closeOnEsc={true} <Modal
footer={null} title="Bill Detail"
closeIcon={<span></span>} visible={!!showBill}
> width={620}
{showBill && <BillDetail bill={showBill} onCancel={() => setShowBill(undefined)}/>} onCancel={() => setShowBill(undefined)} //>=1.16.0
</Modal> closeOnEsc={true}
<Modal footer={null}
title="Notice" closeIcon={<span></span>}
visible={!!state.updateBill} >
closeOnEsc={true} {showBill && <BillDetail bill={showBill} onCancel={() => setShowBill(undefined)}/>}
onCancel={()=>{ </Modal>
setState({updateBill:undefined,updateLoading:false}) <Modal
}} title="Notice"
confirmLoading={state.updateLoading} visible={!!state.updateBill}
onOk={onConfirmPaid} closeOnEsc={true}
okText={t('base.confirm_paid')} onCancel={() => {
maskClosable={false} setState({updateBill: undefined, updateLoading: false})
> }}
{state.updateBill && <div><BillDetailItems bill={state.updateBill} /></div>} confirmLoading={state.updateLoading}
<p style={{marginTop:10}}>{t('bill.paid_confirm')}</p> onOk={onConfirmPaid}
</Modal> okText={t('base.confirm_paid')}
</div>) maskClosable={false}
>
{state.updateBill && <div><BillDetailItems bill={state.updateBill}/></div>}
<p style={{marginTop: 10}}>{t('bill.paid_confirm')}</p>
</Modal>
<Modal
title="Confirm Bill Type"
visible={!!state.confirmBill}
closeOnEsc={true}
onCancel={() => {
setState({confirmBill: undefined})
}}
footer={null}
>
{state.confirmBill && <>
<div><BillDetailItems bill={state.confirmBill}/></div>
<div className="confirm-container" style={{padding:'15px 0'}}>
{
state.confirmBill.details.map((it, idx) => (<div key={idx} className="confirm-item align-center space-between">
<Space spacing={10}>
<span>{it.id}.</span>
<span>{it.bill_type}</span>
<div>
<MoneyFormat money={it.amount}/>
</div>
</Space>
<div className="confirm-item-btn">
{!!it.confirm_status ? <Tag color='light-blue'>CONFIRMED</Tag>:<Button>{t('base.confirm')}</Button>}
</div>
</div>))
}
</div>
</>}
</Modal>
</div>)
} }
export default BillQuery export default BillQuery

1
src/types/bill.d.ts vendored
View File

@ -12,6 +12,7 @@ declare type BillDetail = {
id: string | number; id: string | number;
bill_id: string | number; bill_id: string | number;
bill_type: string; bill_type: string;
confirm_status?: number;
amount: decimal; amount: decimal;
} }
/** /**