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;
border-radius: 10px;
}
.table-operation-render{
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.page-content-container {
max-width: 90%;
width: 1400px;

View File

@ -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<BillModel>;
onPageChange: (pageIndex:number) => void;
@ -30,7 +31,7 @@ export const BillList: React.FC<BillListProps> = (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<BillListProps> = (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<BillListProps> = (props) => {
title: 'Email',
dataIndex: 'student_email',
width: 200,
render: (value) => value?.length ?value: 'N/A'
// 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'),
dataIndex: 'intake_year',
width: 120,
render: (_, record) => (<div>{record.intake_year}/{record.intake_semester}</div>)
},
{
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<BillListProps> = (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),
})
}

View File

@ -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",

View File

@ -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": "返回上一页",

View File

@ -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": "返回上一頁",

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 {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 (<Button
onClick={() => downloadPDF(bill)} size={'small'} theme={'solid'}
type={'primary'} loading={downloading}>{text}</Button>)
const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
const {loading: downloading, downloadPDF} = useDownloadReceiptPDF()
return (<Button
onClick={() => downloadPDF(bill)} size={'small'} loading={downloading}>{text}</Button>)
}
// 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<BillModel>()
const [queryParams, setBillQueryParams] = useState<BillQueryParams>({});
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<BillModel>()
const [queryParams, setBillQueryParams] = useState<BillQueryParams>({});
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 (<Space>
{bill.status != BillStatus.PAID && <Button onClick={()=>setState({updateBill:bill})} size={'small'} theme={'solid'} type={'danger'}>{t('bill.paid')}</Button>
}
{bill.status == BillStatus.PENDING && <>
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.PENDING && <>
<Popconfirm
title={'Notice'}
content={`${t('bill.cancel_confirm')}?`}
@ -92,51 +95,86 @@ const BillQuery = () => {
</Popconfirm>
<Button onClick={() => setShowBill(bill)} size={'small'} theme={'solid'}
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')}/>
}
</Space>)
}
return (<div>
<SearchForm showApply loading={loading} onSearch={setBillQueryParams}/>
<BillList
type={'query'} loading={loading}
operationRender={operation} source={data}
onPageChange={(page_number) => {
setBillQueryParams({
...queryParams,
page_number
})
}}
/>
<Modal
title="Bill Detail"
visible={!!showBill}
width={620}
onCancel={() => setShowBill(undefined)} //>=1.16.0
closeOnEsc={true}
footer={null}
closeIcon={<span></span>}
>
{showBill && <BillDetail bill={showBill} onCancel={() => setShowBill(undefined)}/>}
</Modal>
<Modal
title="Notice"
visible={!!state.updateBill}
closeOnEsc={true}
onCancel={()=>{
setState({updateBill:undefined,updateLoading:false})
}}
confirmLoading={state.updateLoading}
onOk={onConfirmPaid}
okText={t('base.confirm_paid')}
maskClosable={false}
>
{state.updateBill && <div><BillDetailItems bill={state.updateBill} /></div>}
<p style={{marginTop:10}}>{t('bill.paid_confirm')}</p>
</Modal>
</div>)
{
bill.status == BillStatus.PAID && <>
<DownloadButton bill={bill} text={t('bill.download_receipt')}/>
<Button onClick={() => setState({confirmBill: bill})}
size={'small'} theme={'solid'}
type={'primary'}>{t('bill.confirm_bill_type')}</Button>
</>
}
</div>)
}
return (<div>
<SearchForm showApply loading={loading} onSearch={setBillQueryParams}/>
<BillList
type={'query'} loading={loading} source={data}
operationRender={operation} operationRenderWidth={180}
onPageChange={(page_number) => {
setBillQueryParams({
...queryParams,
page_number
})
}}
/>
<Modal
title="Bill Detail"
visible={!!showBill}
width={620}
onCancel={() => setShowBill(undefined)} //>=1.16.0
closeOnEsc={true}
footer={null}
closeIcon={<span></span>}
>
{showBill && <BillDetail bill={showBill} onCancel={() => setShowBill(undefined)}/>}
</Modal>
<Modal
title="Notice"
visible={!!state.updateBill}
closeOnEsc={true}
onCancel={() => {
setState({updateBill: undefined, updateLoading: false})
}}
confirmLoading={state.updateLoading}
onOk={onConfirmPaid}
okText={t('base.confirm_paid')}
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

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

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