feat:export query bill to excel; payment channel only flywire
This commit is contained in:
parent
9c7bf8c1cb
commit
6741e61e13
@ -1,4 +1,4 @@
|
||||
import {Table, Typography} from "@douyinfe/semi-ui";
|
||||
import {Space, Table, Typography} from "@douyinfe/semi-ui";
|
||||
import {ColumnProps} from "@douyinfe/semi-ui/lib/es/table";
|
||||
import React, {useMemo, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
@ -18,6 +18,7 @@ type BillListProps = {
|
||||
onPageChange: (pageIndex:number) => void;
|
||||
tableFooter?: React.ReactNode;
|
||||
loading?: boolean;
|
||||
beforeTotalAmount?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const BillList: React.FC<BillListProps> = (props) => {
|
||||
@ -213,16 +214,19 @@ export const BillList: React.FC<BillListProps> = (props) => {
|
||||
|
||||
return <Card
|
||||
title={t('bill.title_bill_list')}
|
||||
headerRight={<div className="bill-info">
|
||||
<div className="bill-info-item">
|
||||
<span className="bill-info-title">{t('bill.query_amount_total')} :</span>
|
||||
<MoneyFormat money={props.source?.pagination.recordTotal || 0}/>
|
||||
headerRight={<Space spacing={20}>
|
||||
{props.beforeTotalAmount}
|
||||
<div className="bill-info">
|
||||
<div className="bill-info-item">
|
||||
<span className="bill-info-title">{t('bill.query_amount_total')} :</span>
|
||||
<MoneyFormat money={props.source?.pagination.recordTotal || 0}/>
|
||||
</div>
|
||||
<div className="bill-info-item">
|
||||
<span className="bill-info-title current-amount">{t('bill.query_amount_current_page')} :</span>
|
||||
<MoneyFormat money={currentTotalAmount || 0}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bill-info-item">
|
||||
<span className="bill-info-title current-amount">{t('bill.query_amount_current_page')} :</span>
|
||||
<MoneyFormat money={currentTotalAmount || 0}/>
|
||||
</div>
|
||||
</div>}
|
||||
</Space>}
|
||||
>
|
||||
<div className="bill-list-table">
|
||||
<Table<BillModel>
|
||||
|
@ -104,7 +104,7 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
|
||||
placeholder={t('base.please_enter')}/>
|
||||
</Col>
|
||||
<Col xxl={6} xl={6} md={8}>
|
||||
<Form.Select showClear field="payment_channel" label={t('bill.title_pay_method')}
|
||||
<Form.Select showClear field="payment_channel" label={t('bill.title_pay_channel')}
|
||||
placeholder={t('base.please_select')} style={{width: '100%'}}>
|
||||
<Form.Select.Option value="ASIAPAY">ASIAPAY</Form.Select.Option>
|
||||
<Form.Select.Option value="FLYWIRE">FLYWIRE</Form.Select.Option>
|
||||
|
@ -30,6 +30,7 @@
|
||||
"confirmed": "Confirmed",
|
||||
"download-qr-code": "Download QR Code",
|
||||
"download_receipt": "Download receipt",
|
||||
"export_excel": "Export Excel",
|
||||
"paid": "Paid",
|
||||
"paid_confirm": "Please confirm the order status is set to paid",
|
||||
"pay_status": "Bill Status",
|
||||
|
@ -30,6 +30,7 @@
|
||||
"confirmed": "已对账",
|
||||
"download-qr-code": "下载二维码",
|
||||
"download_receipt": "下载收据",
|
||||
"export_excel": "导出账单列表",
|
||||
"paid": "已支付",
|
||||
"paid_confirm": "是否将此订单状态设为已支付",
|
||||
"pay_status": "账单状态",
|
||||
|
@ -30,6 +30,7 @@
|
||||
"confirmed": "已對帳",
|
||||
"download-qr-code": "下載二維碼",
|
||||
"download_receipt": "下載收據",
|
||||
"export_excel": "Export Excel",
|
||||
"paid": "已支付",
|
||||
"paid_confirm": "是否將此訂單狀態設為已支付",
|
||||
"pay_status": "帳單狀態",
|
||||
|
@ -37,7 +37,7 @@ export const BillPaidModal: React.FC<BillPaidModalProps> = (props) => {
|
||||
}
|
||||
const onSubmit = (values: BillUpdateParams) => {
|
||||
if (!props.bill) return;
|
||||
finishBill({bill:props.bill,param:values}).then(props.onConfirm)
|
||||
finishBill({bill: props.bill, param: values}).then(props.onConfirm)
|
||||
// setState({
|
||||
// loading: true
|
||||
// })
|
||||
@ -69,7 +69,7 @@ export const BillPaidModal: React.FC<BillPaidModalProps> = (props) => {
|
||||
|
||||
<Form<BillUpdateParams> onSubmit={onSubmit} initValues={{
|
||||
payment_channel: 'FLYWIRE',
|
||||
payment_method: 'card',
|
||||
payment_method: '',
|
||||
merchant_ref: props.bill?.merchant_ref,
|
||||
payment_amount: props.bill?.amount,
|
||||
actual_payment_amount: props.bill?.amount
|
||||
@ -88,19 +88,34 @@ export const BillPaidModal: React.FC<BillPaidModalProps> = (props) => {
|
||||
</Form.Select>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
{/*<Form.AutoComplete*/}
|
||||
{/* rules={[*/}
|
||||
{/* {required: true, message: 'required error'},*/}
|
||||
{/* ]}*/}
|
||||
{/* placeholder={t('base.please_select')} style={{width: '100%'}}*/}
|
||||
{/* data={[*/}
|
||||
{/* {value:'card',label:'Card(VISA,MasterCard,UnionPay,JCB...)'},*/}
|
||||
{/* {value:'wechat',label:'Wechat'},*/}
|
||||
{/* {value:'alipay',label:'Alipay'},*/}
|
||||
{/* {value:'other',label:'Other'},*/}
|
||||
{/* ]}*/}
|
||||
{/* // renderItem={()=>{*/}
|
||||
{/* //*/}
|
||||
{/* // }}*/}
|
||||
{/* showClear field="payment_method" label={t('bill.title_pay_method')}*/}
|
||||
{/*/>*/}
|
||||
<Form.Select
|
||||
rules={[
|
||||
{required: true, message: 'required error'},
|
||||
]}
|
||||
showClear field="payment_method" label={t('bill.title_pay_method')}
|
||||
placeholder={t('base.please_select')} style={{width: '100%'}}>
|
||||
<Form.Select.Option value="card">Card(VISA,MasterCard,UnionPay,JCB...)</Form.Select.Option>
|
||||
<Form.Select.Option value="wechat">Wechat</Form.Select.Option>
|
||||
<Form.Select.Option value="alipay">Alipay</Form.Select.Option>
|
||||
<Form.Select.Option value="other">Other</Form.Select.Option>
|
||||
{/*<Form.Select.Option value="ASIAPAY">ASIAPAY</Form.Select.Option>*/}
|
||||
{/*<Form.Select.Option value="PPS">PPS</Form.Select.Option>*/}
|
||||
</Form.Select>
|
||||
optionList={[
|
||||
{value: 'card', label: 'Card(VISA,MasterCard,UnionPay,JCB...)'},
|
||||
{value: 'wechat', label: 'Wechat'},
|
||||
{value: 'alipay', label: 'Alipay'},
|
||||
{value: 'other', label: 'Other'},
|
||||
]}
|
||||
allowCreate filter showClear field="payment_method" label={t('bill.title_pay_method')}
|
||||
placeholder={t('base.please_select')} style={{width: '100%'}}/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row gutter={20}>
|
||||
@ -139,7 +154,9 @@ export const BillPaidModal: React.FC<BillPaidModalProps> = (props) => {
|
||||
<div className={'text-right'} style={{margin: '10px 0 20px'}}>
|
||||
<Space spacing={12}>
|
||||
<Button onClick={props.onCancel} type={'tertiary'}>{t('base.cancel')}</Button>
|
||||
<Button loading={state.loading} htmlType={'submit'} theme={'solid'} type={'primary'}>{t('base.confirm_paid')}</Button>
|
||||
<Button
|
||||
loading={state.loading} htmlType={'submit'} theme={'solid'}
|
||||
type={'primary'}>{t('base.confirm_paid')}</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</Form>
|
||||
|
@ -2,6 +2,7 @@ import {Button, Divider, Modal, Notification, Popconfirm, Toast} from "@douyinfe
|
||||
import {useState} from "react";
|
||||
import {useRequest, useSetState} from "ahooks";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {stringify} from "qs"
|
||||
|
||||
import {BillList} from "@/components/bill/list.tsx";
|
||||
import SearchForm from "@/components/bill/search-form.tsx";
|
||||
@ -12,6 +13,7 @@ import {useDownloadReceiptPDF} from "@/service/generate-pdf.ts";
|
||||
import {BillDetailItems} from "@/components/bill";
|
||||
import {BillPaidModal} from "@/pages/bill/components/bill_paid_modal.tsx";
|
||||
import {BillTypeConfirm} from "@/pages/bill/components/bill_type_confirm.tsx";
|
||||
import {saveAs} from "file-saver";
|
||||
|
||||
|
||||
const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
|
||||
@ -84,11 +86,17 @@ const BillQuery = () => {
|
||||
}
|
||||
</div>)
|
||||
}
|
||||
const onExportExcel = ()=>{
|
||||
const downloadUrl = `${AppConfig.API_PREFIX || '/api'}/bills/export?${stringify(queryParams)}`
|
||||
saveAs(downloadUrl, 'bill-result-excel.xlsx')
|
||||
}
|
||||
|
||||
return (<div>
|
||||
<SearchForm showApply loading={loading} onSearch={setBillQueryParams}/>
|
||||
<BillList
|
||||
type={'query'} loading={loading} source={data}
|
||||
operationRender={operation} operationRenderWidth={180}
|
||||
beforeTotalAmount={<Button onClick={onExportExcel} theme={'solid'} type={'secondary'}>{t('bill.export_excel')}</Button>}
|
||||
onPageChange={(page_number) => {
|
||||
setBillQueryParams({
|
||||
...queryParams,
|
||||
|
@ -107,7 +107,7 @@ export default function Index() {
|
||||
<div className={styles.QRCodeContainer}>
|
||||
<QRCode size={250} className={styles.qrCode} bill={billInfo}/>
|
||||
</div>
|
||||
{billInfo && <div
|
||||
{billInfo && billInfo.expiration_time && <div
|
||||
className={styles.billExpTime}> {t('manual.exp_time')} {dayjs(billInfo.expiration_time).format('YYYY-MM-DD HH:mm')} </div>}
|
||||
</div>
|
||||
</Space>
|
||||
|
@ -1,16 +1,12 @@
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {useEffect, useState} from "react";
|
||||
import {useNavigate, useSearchParams} from "react-router-dom";
|
||||
import {Radio, RadioGroup} from '@douyinfe/semi-ui';
|
||||
|
||||
import styles from './pay.module.less'
|
||||
import {PayLogo} from "@/pages/pay/component";
|
||||
import MoneyFormat from "@/components/money-format.tsx";
|
||||
import FlywireLogo from "@/assets/images/pay/flywire.tsx";
|
||||
import AsiaPayLogo from "@/assets/images/pay/asia_pay.tsx";
|
||||
import {getBillDetail} from "@/service/api/bill.ts";
|
||||
import {BillStatus} from "@/service/types.ts";
|
||||
import {StartAsiaPay} from "@/pages/pay/component/start-asia-pay.tsx";
|
||||
import {StartFlyWire} from "@/pages/pay/component/start-fly-wire.tsx";
|
||||
|
||||
|
||||
@ -28,7 +24,7 @@ const PayIndex = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const payChannel = search.get('pay_channel') || 'asia_pay'
|
||||
const payChannel = search.get('pay_channel') || 'flywire'
|
||||
setPayChannel(payChannel)
|
||||
getBillDetail(Number(billId)).then((bill) => {
|
||||
// 判断bill状态
|
||||
@ -59,19 +55,19 @@ const PayIndex = () => {
|
||||
</div>}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.payChanel}>
|
||||
<RadioGroup style={{width: '100%'}} type={'card'} onChange={(e) => setPayChannel(e.target.value)}
|
||||
value={payChannel}>
|
||||
<Radio value={'asia_pay'} style={{flex: 1}}>
|
||||
<AsiaPayLogo/>
|
||||
<span style={{marginLeft: 5}}>AsiaPay</span>
|
||||
</Radio>
|
||||
<Radio value={'flywire'} style={{flex: 1}}>
|
||||
<FlywireLogo/>
|
||||
<span style={{marginLeft: 5}}>Flywire</span>
|
||||
</Radio>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
{/*<div className={styles.payChanel}>*/}
|
||||
{/* <RadioGroup style={{width: '100%'}} type={'card'} onChange={(e) => setPayChannel(e.target.value)}*/}
|
||||
{/* value={payChannel}>*/}
|
||||
{/* <Radio value={'asia_pay'} style={{flex: 1}}>*/}
|
||||
{/* <AsiaPayLogo/>*/}
|
||||
{/* <span style={{marginLeft: 5}}>AsiaPay</span>*/}
|
||||
{/* </Radio>*/}
|
||||
{/* <Radio value={'flywire'} style={{flex: 1}}>*/}
|
||||
{/* <FlywireLogo/>*/}
|
||||
{/* <span style={{marginLeft: 5}}>Flywire</span>*/}
|
||||
{/* </Radio>*/}
|
||||
{/* </RadioGroup>*/}
|
||||
{/*</div>*/}
|
||||
<div className={styles.payDetail}>
|
||||
{bill.details.length == 1 ? <div className="pay-item">
|
||||
<div className="title">Payment Type:</div>
|
||||
@ -96,7 +92,7 @@ const PayIndex = () => {
|
||||
<div className={styles.payConfirm}>
|
||||
{bill.student_email && <div className="student-email">Your Email: {bill.student_email}</div> }
|
||||
<div className="pay-submit">
|
||||
{ payChannel == 'asia_pay' && <StartAsiaPay bill={bill} />}
|
||||
{/*{ payChannel == 'asia_pay' && <StartAsiaPay bill={bill} />}*/}
|
||||
<StartFlyWire bill={bill} open={payChannel == 'flywire'} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -89,16 +89,16 @@ export async function finishFlywire({bill,param}: BillUpdateFormParams){
|
||||
"data": {
|
||||
"remark": param.remark,
|
||||
"payment_id": param.merchant_ref,
|
||||
"amount_from": param.actual_payment_amount,
|
||||
"amount_from": Number(param.actual_payment_amount) * 100,
|
||||
"currency_from": "HKD",
|
||||
"amount_to": param.payment_amount,
|
||||
"amount_to": Number(param.payment_amount) * 100,
|
||||
"currency_to": "HKD",
|
||||
"status": "guaranteed",
|
||||
"expiration_date": dayjs().format('YYYY-MM-DDTHH:mm:ss[Z]'),
|
||||
"external_reference": bill.id,
|
||||
"country": "CN",
|
||||
"payment_method": {
|
||||
"type": param.payment_channel
|
||||
"type": param.payment_method
|
||||
},
|
||||
"fields": {
|
||||
"student_email": bill.student_email,
|
||||
|
@ -35,7 +35,7 @@ export function GeneratePdf(bill: BillModel) {
|
||||
title: 'Programme:',
|
||||
content: bill.programme_english_name
|
||||
}, 56)
|
||||
drawItem(doc, {title: 'Mode of Study:', content: bill.attendance_mode}, bill.programme_english_name.length > 70?70:64)
|
||||
drawItem(doc, {title: 'Mode of Study:', content: bill.attendance_mode == 'FT' ? 'FULL-TIME': bill.attendance_mode}, bill.programme_english_name.length > 70?70:64)
|
||||
// draw table
|
||||
autoTable(doc, {
|
||||
startY: 80,
|
||||
@ -61,7 +61,7 @@ export function GeneratePdf(bill: BillModel) {
|
||||
`#${it.id}`,
|
||||
dayjs(bill.paid_at).format('YYYY-MM-DD'),
|
||||
it.bill_type,
|
||||
`${bill.payment_channel}` + bill.payment_channel != bill.payment_method ? `(${bill.payment_method})` : '',
|
||||
`${bill.payment_channel}` + (bill.payment_channel != bill.payment_method ? `(${bill.payment_method})` : ''),
|
||||
`${it.amount}`
|
||||
];
|
||||
})),
|
||||
|
Loading…
x
Reference in New Issue
Block a user