feat add bill/student number confirm

This commit is contained in:
LittleBoy 2024-08-05 12:37:06 +08:00
parent 1f16e05c01
commit f50cc00d84
14 changed files with 249 additions and 81 deletions

View File

@ -130,6 +130,9 @@ body #root{
}
}
}
.text-nowrap{
white-space: nowrap;
}
// input
.semi-input-wrapper, .semi-select,.semi-datepicker-range-input,.semi-input-textarea-wrapper {

View File

@ -1,25 +1,29 @@
import React, {useMemo} from "react";
import {useTranslation} from "react-i18next";
import {IconBillType, IconMoney, IconStudentEmail, IconStudentId} from "@/components/icons";
import {IconBillType, IconMoney, IconStudentEmail, IconStudentId, IconStudentName} from "@/components/icons";
import MoneyFormat from "@/components/money-format.tsx";
import './bill.less'
const BillDetailItem = (item: { title: React.ReactNode; value: React.ReactNode, icon?: React.ReactNode }) => {
export const BillDetailItem = (item: { title: React.ReactNode; value: React.ReactNode, icon?: React.ReactNode }) => {
return <div className={'bill-detail-item'}>
<div className={'detail-item-title'}>{item.icon} <span className={'item-title'}>{item.title}</span> :</div>
<div className={'detail-item-value'}>{item.value}</div>
</div>
}
const BillDetailItems = (prop: { bill: BillModel }) => {
type BillDetailItemsProps = {
bill: BillModel;
studentNumberRender?: React.ReactNode;
}
const BillDetailItems = (prop: BillDetailItemsProps) => {
const {t} = useTranslation();
const billType = useMemo(()=>{
return prop.bill.details[0].bill_type
},[prop.bill])
return (<>
<BillDetailItem icon={<IconBillType/>} title={t('manual.bill_type')} value={billType}/>
<BillDetailItem icon={<IconStudentId/>} title={t('manual.student_number')} value={prop.bill.student_number || prop.bill.application_number}/>
<BillDetailItem icon={<IconStudentId/>} title={t('bill.title_student_name')}
{prop.studentNumberRender?prop.studentNumberRender:<BillDetailItem icon={<IconStudentId/>} title={t('manual.student_number')} value={prop.bill.student_number || prop.bill.application_number || '-'}/>}
<BillDetailItem icon={<IconStudentName/>} title={t('bill.title_student_name')}
value={`${prop.bill.student_english_name||'-'}${prop.bill.student_chinese_name?' / '+ prop.bill.student_chinese_name : ''}`}/>
<BillDetailItem icon={<IconStudentEmail/>} title={'Email'} value={prop.bill.student_email||'-'}/>
<BillDetailItem icon={<IconMoney/>} title={t('manual.amount')} value={<MoneyFormat money={prop.bill.amount}/>}/>

View File

@ -32,7 +32,10 @@ export const BillList: React.FC<BillListProps> = (props) => {
return t('bill.pay_status_pending')
case 'PAID':
return t('bill.pay_status_paid')
case 'EXPIRED':
return t('bill.pay_status_expired')
case 'CANCELED':
case 'CANCELLED':
return t('bill.pay_status_canceled')
default:
return billStatus
@ -56,6 +59,12 @@ export const BillList: React.FC<BillListProps> = (props) => {
dataIndex: 'id',
width: 120,
},
{
title: 'Merchant Ref',
dataIndex: 'merchant_ref',
width: 200,
// render: (_) => (<MoneyFormat money={_}/>),
},
{
title: t('base.student_number'),
dataIndex: 'student_number',
@ -68,33 +77,33 @@ export const BillList: React.FC<BillListProps> = (props) => {
width: 150,
},
{
title: '开始支付时间',
title: t('bill.title_initiated_paid_at'),
dataIndex: 'initiated_paid_at',
width: 150,
width: 180,
render: (value) => value?.length ?value: 'N/A'
},
{
title: '到账时间',
title: t('bill.title_delivered_at'),
dataIndex: 'delivered_at',
width: 150,
width: 180,
render: (value) => value?.length ?value: 'N/A'
},
{
title: t('bill.title_paid_at'),
dataIndex: 'paid_at',
width: 150,
width: 180,
render: (value) => value?.length ?value: 'N/A'
},
{
title: t('bill.title_create_at'),
dataIndex: 'create_at',
width: 150,
width: 180,
render: (value) => value?.length ?value: 'N/A'
},
{
title: t('bill.title_student_name'),
dataIndex: 'student_english_name',
width: 150,
width: 180,
render: (_, record) => (<div>{record.student_english_name}<br/>{record.student_chinese_name}</div>)
},
{
@ -118,7 +127,7 @@ export const BillList: React.FC<BillListProps> = (props) => {
title: t('bill.title_year'),
dataIndex: 'intake_year',
width: 120,
render: (_, record) => (<div>{record.intake_year}/{String(record.intake_semester).length == 1 ? '0':''}{record.intake_semester}</div>)
render: (_, record) => record.intake_year?(<div>{record.intake_year}/{String(record.intake_semester).length == 1 ? '0':''}{record.intake_semester}</div>):"N/A"
},
// {
// title: t('bill.title_semester'),
@ -187,12 +196,6 @@ export const BillList: React.FC<BillListProps> = (props) => {
</div>
):'N/A'),
},
{
title: 'Merchant Ref',
dataIndex: 'merchant_ref',
width: 250,
// render: (_) => (<MoneyFormat money={_}/>),
},
{
title: t('bill.title_bill_status'),
dataIndex: 'status',

View File

@ -4,6 +4,7 @@ import dayjs from "dayjs";
import {useTranslation} from "react-i18next";
import {Card} from "@/components/card";
import {BillQueryParams} from "@/service/api/bill.ts";
import {BillTypes} from "@/service/bill-types.ts";
type SearchFormProps = {
onSearch?: (params: BillQueryParams) => void;
@ -20,6 +21,7 @@ type SearchFormFields = {
application_number?: string;
bill_number?: string;
payment_channel?: string;
confirm_status?: ConfirmStatus;
bill_status?: string;
apply_status?: string;
sort_by?: string;
@ -35,9 +37,6 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
if (value.id) {
params.id = value.id;
}
if (value.merchant_ref) {
params.merchant_ref = value.merchant_ref;
}
if (value.student_number) {
params.student_number = value.student_number;
}
@ -48,6 +47,10 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
if (value.apply_status) {
params.apply_status = value.apply_status;
}
// 确认状态
if (value.confirm_status) {
params.confirm_status = value.confirm_status;
}
// 账单状态
if (value.bill_status) {
params.status = value.bill_status;
@ -91,17 +94,19 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
<div className="bill-search-form">
<Form<SearchFormFields> onSubmit={formSubmit}>
<Row type={'flex'} gutter={16}>
<Col xxl={3} xl={6} md={8}>
<Form.Input showClear field='id' label="ID" trigger='blur' placeholder={t('base.please_enter')}/>
</Col>
<Col xxl={3} xl={6} md={8}>
<Form.Input showClear field='merchant_ref' label="Merchant Ref" trigger='blur' placeholder={t('base.please_enter')}/>
</Col>
<Col xxl={6} xl={6} md={8}>
<Form.DatePicker showClear type={'dateRange'} field="dateRange" label={t('bill.bill_date')}
<Form.DatePicker showClear type={'dateRange'} field="dateRange" label={t('bill.title_initiated_paid_at')}
style={{width: '100%'}}>
</Form.DatePicker>
</Col>
<Col xxl={6} xl={6} md={8}>
<Form.DatePicker showClear type={'dateRange'} field="delivered_at" label={t('bill.title_delivered_at')}
style={{width: '100%'}}>
</Form.DatePicker>
</Col>
<Col xxl={4} xl={6} md={8}>
<Form.Input showClear field='id' label="ID / Merchant Ref" trigger='blur' placeholder={t('base.please_enter')}/>
</Col>
<Col xxl={4} xl={6} md={8}>
<Form.Input showClear field='student_number' label={t('base.student_number')} trigger='blur'
placeholder={t('base.please_enter')}/>
@ -126,7 +131,7 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
<Form.Select.Option value="create_at asc">{t('bill.title_create_at')} {t('bill.sort_asc')}</Form.Select.Option>
</Form.Select>
</Col>
<Col xxl={6} xl={6} md={8}>
<Col xxl={4} xl={6} md={8}>
<Form.Select showClear field="payment_channel" label={t('bill.title_pay_channel')}
placeholder={t('base.please_select')} style={{width: '100%'}}>
<Form.Select.Option value="FLYWIRE">FLYWIRE</Form.Select.Option>
@ -134,23 +139,34 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
<Form.Select.Option value="PPS">PPS</Form.Select.Option>
</Form.Select>
</Col>
<Col xxl={6} xl={6} md={8}>
<Form.Select showClear field="bill_type" label={t('bill.title_bill_type')}
placeholder={t('base.please_select')} style={{width: '100%'}}>
<Form.Select.Option value="FLYWIRE">FLYWIRE</Form.Select.Option>
<Form.Select.Option value="CBP">CBP</Form.Select.Option>
<Form.Select.Option value="PPS">PPS</Form.Select.Option>
<Col xxl={4} xl={6} md={8}>
<Form.Select
field="bill_type" style={{width: '100%'}}
label={t('manual.bill_type')}
placeholder={t('manual.bill_type')}
>
{
BillTypes.map((it, idx) => (
<Form.Select.Option key={idx} value={it.label}>{it.label}</Form.Select.Option>))
}
</Form.Select>
</Col>
{props.showApply && <>
<Col xxl={6} xl={6} md={8}>
<Col xxl={4} xl={6} md={8}>
<Form.Select showClear field="confirm_status" label={t('bill.title_confirm_status')}
placeholder={t('base.please_select')} style={{width: '100%'}}>
<Form.Select.Option value="CONFIRMED">{t('bill.status_confirmed')}</Form.Select.Option>
<Form.Select.Option value="UNCONFIRMED">{t('bill.status_unconfirmed')}</Form.Select.Option>
</Form.Select>
</Col>
<Col xxl={4} xl={6} md={8}>
<Form.Select showClear field="bill_status" label={t('bill.pay_status')}
placeholder={t('base.please_select')} style={{width: '100%'}}>
{billStatusOptions.map((item, index) => (
<Form.Select.Option key={index} value={item.value}>{item.label}</Form.Select.Option>))}
</Form.Select>
</Col>
<Col xxl={6} xl={6} md={8}>
<Col xxl={4} xl={6} md={8}>
<Form.Select showClear field="apply_status" label={t('bill.title_reconciliation_status')}
placeholder={t('base.please_select')} style={{width: '100%'}}>
{applyStatusOptions.map((item, index) => (
@ -158,7 +174,7 @@ const SearchForm: React.FC<SearchFormProps> = (props) => {
</Form.Select>
</Col>
</>}
<Col xxl={6} xl={6} md={8} style={{display: 'flex', alignItems: 'flex-end', paddingBottom: 12}}>
<Col xxl={4} xl={6} md={8} style={{display: 'flex', alignItems: 'flex-end', paddingBottom: 12}}>
<Button loading={props.loading} style={{width: 100}} htmlType={'submit'} theme={'solid'}
type={'primary'}>{t('base.btn_search_submit')}</Button>
</Col>

View File

@ -60,6 +60,22 @@ export const IconMoney = ({style}: IconProps) => {
}
export const IconStudentId = ({style}: IconProps) => {
return (
<svg
className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
width="1em" height="1em" style={style}>
<path
d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32z m-40 632H136V232h752v560z"
fill="#00C479"
></path>
<path
d="M610.3 476h123.4c1.3 0 2.3-3.6 2.3-8v-48c0-4.4-1-8-2.3-8H610.3c-1.3 0-2.3 3.6-2.3 8v48c0 4.4 1 8 2.3 8zM615.1 620h185.7c3.9 0 7.1-3.6 7.1-8v-48c0-4.4-3.2-8-7.1-8H615.1c-3.9 0-7.1 3.6-7.1 8v48c0 4.4 3.2 8 7.1 8zM224 673h43.9c4.2 0 7.6-3.3 7.9-7.5 3.8-50.5 46-90.5 97.2-90.5s93.4 40 97.2 90.5c0.3 4.2 3.7 7.5 7.9 7.5H522c4.6 0 8.2-3.8 8-8.4-2.8-53.3-32-99.7-74.6-126.1 18.1-19.9 29.1-46.4 29.1-75.5 0-61.9-49.9-112-111.4-112s-111.4 50.1-111.4 112c0 29.1 11 55.5 29.1 75.5-42.7 26.5-71.8 72.8-74.6 126.1-0.4 4.6 3.2 8.4 7.8 8.4z m149-262c28.5 0 51.7 23.3 51.7 52s-23.2 52-51.7 52-51.7-23.3-51.7-52 23.2-52 51.7-52z"
></path>
</svg>
)
}
export const IconStudentName = ({style}: IconProps) => {
return (
<svg className="icon" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg"
width="1em" height="1em" style={style}>
@ -88,6 +104,7 @@ export const IconStudentId = ({style}: IconProps) => {
</g>
</svg>)
}
export const IconStudentEmail = ({style}: IconProps) => {
return (
<svg className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"

View File

@ -15,7 +15,7 @@
"student_number": "Student Number"
},
"bill": {
"bill_date": "Date",
"bill_date": "In",
"bill_number": "Bill Number",
"cancel": "Cancel",
"cancel_confirm": "Please make sure to cancel the bill",
@ -23,9 +23,13 @@
"cancel_success": "Successful cancel bill",
"confirm": "Check",
"confirm_batch": "Batch Confirm",
"confirm_bill": "Confirm Bill Information",
"confirm_bill_number": "Confirm Bill Number",
"confirm_bill_type": "Confirm Bill",
"confirm_bill_type_batch": "Batch confirm Bill Type",
"confirm_confirm_title": "Confirm check the Bill?",
"confirm_select_empty": "Require confirm bill data",
"confirm_student_number": "Confirm Student Number",
"confirm_success": "Confirm success!",
"confirmed": "Confirmed",
"download-qr-code": "Download QR Code",
@ -36,6 +40,7 @@
"paid_confirm": "Please confirm the order status is set to paid",
"pay_status": "Bill Status",
"pay_status_canceled": "CANCELED",
"pay_status_expired": "EXPIRED",
"pay_status_paid": "PAID",
"pay_status_pending": "PENDING",
"query_amount_current_page": "The total amount of current page",
@ -46,6 +51,8 @@
"set_bill_paid": "Set Bill Paid",
"sort_asc": "ASC",
"sort_desc": "DESC",
"status_confirmed": "CONFIRMED",
"status_unconfirmed": "UNCONFIRMED",
"title_actual_payment_amount": "Actually Paid",
"title_amount": "Amount",
"title_bill_detail": "Bill Detail",
@ -53,17 +60,20 @@
"title_bill_status": "Bill Status",
"title_bill_type": "Bill Type",
"title_bill_type_confirm": "Confirm Bill Type",
"title_create_at": "Input Date",
"title_confirm_status": "Confirm Status",
"title_create_at": "Input Time",
"title_delivered_at": "Delivered Time",
"title_department": "Department",
"title_initiated_paid_at": "Initiated Time",
"title_operate": "Operation",
"title_paid_at": "Transaction Date",
"title_paid_at": "Transaction Time",
"title_pay_amount": "Pay Amount",
"title_pay_channel": "Payment Channel",
"title_pay_method": "Pay Method",
"title_pay_sort": "Sort By",
"title_program_id": "Program ID",
"title_program_name": "Program",
"title_reconciliation_status": "Reconciliation",
"title_reconciliation_status": "Reconciliation Status",
"title_remark": "Remark",
"title_semester": "Semester",
"title_service_charge": "Service Charge",

View File

@ -15,7 +15,7 @@
"student_number": "学号"
},
"bill": {
"bill_date": "支付日期",
"bill_date": "开始支付时间",
"bill_number": "账单编号",
"cancel": "作废",
"cancel_confirm": "确定作废此账单",
@ -23,9 +23,13 @@
"cancel_success": "作废账单成功",
"confirm": "对账",
"confirm_batch": "批量对账",
"confirm_bill": "确认账单信息",
"confirm_bill_number": "确认账单编号",
"confirm_bill_type": "确认账单",
"confirm_bill_type_batch": "批量确认账单",
"confirm_confirm_title": "请确定对账此账单?",
"confirm_select_empty": "对账账单为空",
"confirm_student_number": "确认学号",
"confirm_success": "对账成功!",
"confirmed": "已对账",
"download-qr-code": "下载二维码",
@ -36,6 +40,7 @@
"paid_confirm": "是否将此订单状态设为已支付",
"pay_status": "账单状态",
"pay_status_canceled": "已作废",
"pay_status_expired": "已过期",
"pay_status_paid": "已支付",
"pay_status_pending": "未支付",
"query_amount_current_page": "当前页总金额",
@ -46,6 +51,8 @@
"set_bill_paid": "设置账单支付完成",
"sort_asc": "升序",
"sort_desc": "降序",
"status_confirmed": "已确认",
"status_unconfirmed": "未确认",
"title_actual_payment_amount": "实付金额",
"title_amount": "账单金额",
"title_bill_detail": "账单详情",
@ -53,8 +60,11 @@
"title_bill_status": "账单状态",
"title_bill_type": "账单类型",
"title_bill_type_confirm": "确认账单",
"title_confirm_status": "确认状态",
"title_create_at": "创建时间",
"title_delivered_at": "到账时间",
"title_department": "学系",
"title_initiated_paid_at": "开始支付时间",
"title_operate": "操作",
"title_paid_at": "支付时间",
"title_pay_amount": "应付金额",

View File

@ -15,7 +15,7 @@
"student_number": "學號"
},
"bill": {
"bill_date": "支付日期",
"bill_date": "開始支付時間",
"bill_number": "帳單編號",
"cancel": "作廢",
"cancel_confirm": "確定作廢此帳單",
@ -23,9 +23,13 @@
"cancel_success": "作廢帳單成功",
"confirm": "對帳",
"confirm_batch": "批次對帳",
"confirm_bill": "確認帳單資訊",
"confirm_bill_number": "確認帳單編號",
"confirm_bill_type": "確認賬單",
"confirm_bill_type_batch": "批次確認帳單",
"confirm_confirm_title": "請確定對帳此帳單?",
"confirm_select_empty": "對帳帳單為空",
"confirm_student_number": "確認學號",
"confirm_success": "對帳成功!",
"confirmed": "已對帳",
"download-qr-code": "下載二維碼",
@ -36,6 +40,7 @@
"paid_confirm": "是否將此訂單狀態設為已支付",
"pay_status": "帳單狀態",
"pay_status_canceled": "已作廢",
"pay_status_expired": "已過期",
"pay_status_paid": "已付款",
"pay_status_pending": "未付款",
"query_amount_current_page": "目前頁總金額",
@ -46,6 +51,8 @@
"set_bill_paid": "設定帳單支付完成",
"sort_asc": "升序",
"sort_desc": "降序",
"status_confirmed": "已確認",
"status_unconfirmed": "未確認",
"title_actual_payment_amount": "實付金額",
"title_amount": "帳單金額",
"title_bill_detail": "帳單詳情",
@ -53,8 +60,11 @@
"title_bill_status": "帳單狀態",
"title_bill_type": "帳單類型",
"title_bill_type_confirm": "確認帳單",
"title_confirm_status": "確認狀態",
"title_create_at": "創建時間",
"title_delivered_at": "到帳時間",
"title_department": "學系",
"title_initiated_paid_at": "開始支付時間",
"title_operate": "操作",
"title_paid_at": "付款時間",
"title_pay_amount": "應付金額",

View File

@ -27,15 +27,15 @@ export const BillTypeConfirm: React.FC<BillTypeConfirmProps> = (props) => {
})
}
return <div className="confirm-item align-center space-between"
style={{marginBottom: 10}}>
<div>
style={{marginBottom: 20}}>
<div style={{lineHeight:1.1}}>
<div>{it.bill_type}</div>
<div>
<div style={{fontSize:12}}>
<MoneyFormat money={it.amount}/>
</div>
</div>
<div className="confirm-item-btn">
<Space spacing={20}>
<Space spacing={15}>
{it.confirm_status != 'CONFIRMED' && <Select onChange={v=>setState({bill_type:String(v)})} defaultValue={it.bill_type} style={{width:180}} placeholder={t('manual.bill_type')}>
{
BillTypes.map((it, idx) => (
@ -43,12 +43,12 @@ export const BillTypeConfirm: React.FC<BillTypeConfirmProps> = (props) => {
}
</Select>}
{
it.confirm_status == 'CONFIRMED' ? <Tag color='light-blue'>{state.bill_type}</Tag> : <>
it.confirm_status == 'CONFIRMED' ? <Tag size={'large'} color='light-blue'>{state.bill_type}</Tag> : <>
<Popconfirm
title={'Notice'} onConfirm={() => onConfirmBill()}
position={'topRight'}
content={`${t('bill.confirm_bill_type')}?`}
><Button loading={state.loading} theme={'solid'}>{t('base.confirm')}</Button></Popconfirm>
><Button style={{width:80}} loading={state.loading} theme={'solid'}>{t('base.confirm')}</Button></Popconfirm>
</>
}
</Space>

View File

@ -0,0 +1,56 @@
import {Button, Space, Tag, Input} from "@douyinfe/semi-ui";
import React from "react";
import {useSetState} from "ahooks";
import {useTranslation} from "react-i18next";
type NumberConfirmProps = {
bill: BillModel;
type: 'student_number' | 'application_number'
}
export const NumberConfirm: React.FC<NumberConfirmProps> = (props) => {
const {t} = useTranslation()
const [state, setState] = useSetState({
loading: false,
confirmed: false,
confirmNumber: (props.type == 'application_number' ? props.bill.application_number : props.bill.student_number) || '',
})
const onConfirm = () => {
if (!state.confirmNumber.length) return
setState({loading: true})
setTimeout(() => {
setState({loading: false, confirmed: true})
}, 500)
// confirmBillType({id:it.id,type:state.bill_type}).then(() => {
// setState({loading:false})
// setItem({...it,confirm_status:'CONFIRMED'})
// }).catch(() => {
// setState({loading:false})
// })
}
return <div
className="confirm-item align-center space-between"
style={{marginBottom: 15}}>
<div>
<div>{t(props.type == 'student_number' ? 'bill.confirm_student_number' : 'bill.confirm_bill_number')}</div>
</div>
<div className="confirm-item-btn">
<Space spacing={15}>
{!state.confirmed && <Input
onChange={v => setState({confirmNumber: String(v)})}
defaultValue={state.confirmNumber}
style={{width: 180}} placeholder={t('base.please_enter')}/>}
{
state.confirmed ? <Space>
<div>{state.confirmNumber}</div>
<Tag size={'large'} color='light-blue'>CONFIRMED</Tag>
</Space> : <Button
style={{width: 80}} disabled={!state.confirmNumber} onClick={onConfirm}
loading={state.loading} theme={'solid'}>{t('base.confirm')}</Button>
}
</Space>
</div>
</div>
}

View File

@ -13,6 +13,9 @@ 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";
import {IconStudentId} from "@/components/icons";
import {BillDetailItem} from "@/components/bill/bill-detail-items.tsx";
import {NumberConfirm} from "@/pages/bill/components/number_confirm.tsx";
const DownloadButton = ({bill, text}: { bill: BillModel; text: string }) => {
@ -86,27 +89,31 @@ const BillQuery = () => {
}
</div>)
}
const onExportExcel = ()=>{
const onExportExcel = () => {
// const downloadUrl = `${AppConfig.API_PREFIX || '/api'}/bills/export?${stringify(queryParams)}`
//
//
// saveAs(downloadUrl, 'bill-result-excel.xlsx')
setState({
exporting:true
exporting: true
})
exportBillList(queryParams).then(ret=>{
exportBillList(queryParams).then(ret => {
console.log(ret)
const blob = new Blob([ret], {type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
const blob = new Blob([ret], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
saveAs(blob, 'bill-result-excel.xlsx')
}).finally(()=>{
}).finally(() => {
setState({
exporting:false
exporting: false
})
})
}
const onImportExcel = ()=>{
Toast.warning({content:'Not implemented'})
const onImportExcel = () => {
Toast.warning({content: 'Not implemented'})
}
const [selectKeys, setSelectedKeys] = useState<(string | number)[]>([])
const confirmBillTypeBatch = () => {
console.log(selectKeys)
}
return (<div>
@ -114,10 +121,22 @@ const BillQuery = () => {
<BillList
type={'query'} loading={loading} source={data}
operationRender={operation} operationRenderWidth={180}
beforeTotalAmount={<ButtonGroup style={{marginRight:20}} theme={'solid'}>
<Button onClick={onImportExcel}>{t('bill.import_excel')}</Button>
<Button loading={state.exporting} onClick={onExportExcel}>{t('bill.export_excel')}</Button>
</ButtonGroup>}
beforeTotalAmount={<ButtonGroup style={{marginRight: 20}} theme={'solid'}>
{
(selectKeys.length == 0) ? <Button disabled>{t('bill.confirm_bill_type_batch')}</Button> :
<Popconfirm
title={'Notice'}
content={`${t('bill.cancel_confirm_bills')}?`}
onConfirm={() => confirmBillTypeBatch()}
>
<Button theme={'solid'}>{t('bill.confirm_bill_type_batch')}</Button>
</Popconfirm>
}
<Button onClick={onImportExcel}>{t('bill.import_excel')}</Button>
<Button loading={state.exporting} onClick={onExportExcel}>{t('bill.export_excel')}</Button>
</ButtonGroup>}
onRowSelection={setSelectedKeys}
onPageChange={(page_number) => {
setBillQueryParams({
...queryParams,
@ -146,19 +165,34 @@ const BillQuery = () => {
}}
/>
<Modal
title="Confirm Bill Type"
title={t('bill.confirm_bill')}
visible={!!state.confirmBill}
closeOnEsc={true}
onCancel={() => {
refresh()
setState({confirmBill: undefined})
}}
width={500}
width={550}
footer={null}
>
{state.confirmBill && <>
<div><BillDetailItems bill={state.confirmBill}/></div>
<div className="confirm-container" style={{padding: '15px 0'}}>
<div><BillDetailItems bill={state.confirmBill} studentNumberRender={<>
<BillDetailItem
icon={<IconStudentId/>} title={t('manual.student_number')}
value={state.confirmBill.student_number || '-'}/>
<BillDetailItem
icon={<IconStudentId/>} title={t('base.bill_number')}
value={state.confirmBill.application_number || '-'}/>
</>}/></div>
<div className="confirm-container" style={{padding: '15px 0',marginTop:20}}>
{
!state.confirmBill.student_number_confirm &&
<NumberConfirm bill={state.confirmBill} type={'student_number'}/>
}
{
!state.confirmBill.application_number_confirm &&
<NumberConfirm bill={state.confirmBill} type={'application_number'}/>
}
{
state.confirmBill.details.map((it, idx) => (<div key={idx}>
<Divider margin='12px'/>

View File

@ -86,6 +86,20 @@ const BillReconciliation = () => {
<BillList
source={data} type={'reconciliation'}
operationRender={queryParams.apply_status == 'CHECKED' ? undefined : operation}
beforeTotalAmount={<div>{queryParams.apply_status != 'CHECKED' && (
(selectKeys.length == 0 )? <Button theme={'solid'} disabled style={{marginRight: 10}}>
{t('bill.confirm_batch')}
</Button> :
<Popconfirm
title={'Notice'}
content={`${t('bill.cancel_confirm_bills')}?`}
onConfirm={() => confirmBill(selectKeys as number[])}
>
<Button theme={'solid'} style={{marginRight: 10}}>
{t('bill.confirm_batch')}
</Button>
</Popconfirm>
)}</div>}
onRowSelection={queryParams.apply_status == 'CHECKED' ? undefined : (keys: (number | string)[]) => {
setSelectedKeys(keys);
}}
@ -94,17 +108,6 @@ const BillReconciliation = () => {
...queryParams,
page_number
})}
tableFooter={queryParams.apply_status != 'CHECKED' && selectKeys?.length > 0 && (
<Popconfirm
title={'Notice'}
content={`${t('bill.cancel_confirm_bills')}?`}
onConfirm={() => confirmBill(selectKeys as number[])}
>
<Button style={{marginRight: 10}}>
{t('bill.confirm_batch')}
</Button>
</Popconfirm>
)}
/>
</div>)
}

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

@ -44,7 +44,9 @@ declare type BillQueryParam = {
declare type BillModel = {
id: number;
student_number: string;
application_number?: null | string | number;
student_number_confirm?: string;
application_number: null | string;
application_number_confirm?: null | string;
student_email: string;
student_tc_name?: string;
student_sc_name?: string;

View File

@ -28,8 +28,8 @@ export default defineConfig(({mode}) => {
port:10086,
proxy: {
'/api': {
target: 'https://test-payment-be.hkchc.team', //
// target: 'http://127.0.0.1:50000', //
// target: 'https://test-payment-be.hkchc.team', //
target: 'http://127.0.0.1:50000', //
changeOrigin: true,
//rewrite: (path) => path.replace(/^\/api/, '')
}