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