2024-04-01 20:39:22 +08:00
|
|
|
import './payment.css';
|
|
|
|
import {
|
|
|
|
Button,
|
|
|
|
ConfigProvider,
|
|
|
|
DatePicker,
|
|
|
|
Divider, Flex,
|
|
|
|
Form, GetProp, Image,
|
|
|
|
Input,
|
|
|
|
InputNumber,
|
|
|
|
message,
|
|
|
|
Radio,
|
|
|
|
Spin,
|
2024-04-02 18:45:46 +08:00
|
|
|
Upload, UploadProps
|
2024-04-01 20:39:22 +08:00
|
|
|
} from "antd";
|
|
|
|
import {
|
|
|
|
ReloadOutlined
|
|
|
|
} from '@ant-design/icons'
|
2024-04-02 18:45:46 +08:00
|
|
|
import {useEffect, useRef, useState} from "react";
|
2024-04-01 20:39:22 +08:00
|
|
|
import locale from 'antd/locale/zh_CN';
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
import 'dayjs/locale/zh-cn';
|
2024-04-02 18:45:46 +08:00
|
|
|
import {DevUserId, get, post, uploadImageUrl} from "../../util/AjaxUtils.ts";
|
2024-04-01 20:39:22 +08:00
|
|
|
import {UploadOutlined} from "@ant-design/icons";
|
|
|
|
import useMessage from "antd/es/message/useMessage";
|
|
|
|
import {errorImage} from "../../util/CommonUtil.ts";
|
|
|
|
|
|
|
|
dayjs.locale('zh-cn');
|
|
|
|
|
|
|
|
type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];
|
|
|
|
|
|
|
|
type FormFieldType = {
|
|
|
|
thirdParty: string;
|
|
|
|
rechargeMoney: number;
|
|
|
|
orgName: string;
|
|
|
|
orgBank: string;
|
|
|
|
orgNumber: string;
|
|
|
|
rechargeFinalTime: string;
|
|
|
|
rechargeVoucher: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
type PayType = {
|
|
|
|
accountRechargeId: string;
|
|
|
|
thirdPartyPayUrl: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
type PaySystemBank = {
|
|
|
|
bankAccountName: string;
|
|
|
|
bankName: string;
|
|
|
|
bankNumber: string;
|
|
|
|
bankRemark: string;
|
|
|
|
bankUnionpayNumber: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum ThirdPartyEnum {
|
|
|
|
WX = '微信',
|
|
|
|
ZFB = '支付宝',
|
|
|
|
DGZZ = '对公转账'
|
|
|
|
}
|
|
|
|
|
|
|
|
interface IPaymentProps {
|
|
|
|
handleConfirm(): void;
|
|
|
|
|
|
|
|
handleCancel(): void;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default function Payment(props: IPaymentProps) {
|
|
|
|
|
|
|
|
const [form] = Form.useForm<FormFieldType>();
|
|
|
|
const [messageApi, messageApiContext] = useMessage();
|
|
|
|
const [isRechargeMoneyEdit, setIsRechargeMoneyEdit] = useState(false);
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const [rechargeVoucherArray, setRechargeVoucherArray] = useState<string[]>([]);
|
2024-04-02 18:45:46 +08:00
|
|
|
const [thirdParty, setThirdParty] = useState<ThirdPartyEnum | null>();
|
2024-04-01 20:39:22 +08:00
|
|
|
const [accountRechargeId, setAccountRechargeId] = useState('');
|
|
|
|
const [thirdPartyPayUrl, setThirdPartyPayUrl] = useState('');
|
|
|
|
const [paySystemBank, setPaySystemBank] = useState<PaySystemBank>({
|
|
|
|
bankAccountName: '',
|
|
|
|
bankName: '',
|
|
|
|
bankNumber: '',
|
|
|
|
bankRemark: '',
|
|
|
|
bankUnionpayNumber: ''
|
|
|
|
});
|
|
|
|
const [countdownTime, setCountdownTime] = useState('');
|
|
|
|
const [isCountdownTimeout, setIsCountdownTimeout] = useState(false);
|
|
|
|
const moneyRange: number[] = [0.01, 2000];
|
2024-04-02 18:45:46 +08:00
|
|
|
const countdownIntervalRef = useRef<number | undefined>();
|
|
|
|
const [refreshQrCodeCount, setRefreshQrCodeCount] = useState(0);
|
2024-04-01 20:39:22 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 倒计时
|
|
|
|
*/
|
|
|
|
const countdown = () => {
|
2024-04-02 18:45:46 +08:00
|
|
|
if (countdownIntervalRef.current) {
|
|
|
|
clearInterval(countdownIntervalRef.current);
|
|
|
|
}
|
|
|
|
if (thirdParty == ThirdPartyEnum.DGZZ) {
|
|
|
|
return;
|
2024-04-01 20:39:22 +08:00
|
|
|
}
|
|
|
|
const Time = new Date().getTime();
|
|
|
|
// 设定计时器的时间为60秒
|
|
|
|
const countDownDate = new Date(Time + 270 * 1000).getTime();
|
|
|
|
|
|
|
|
// 更新计时器的秒数
|
|
|
|
const updateCountdown = () => {
|
|
|
|
const now = new Date().getTime();
|
|
|
|
const distance = countDownDate - now;
|
|
|
|
// 将毫秒数转换为分钟和秒数
|
|
|
|
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
|
|
|
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
|
|
|
// 渲染计时器
|
|
|
|
setCountdownTime(minutes + ":" + (seconds < 10 ? "0" : "") + seconds);
|
|
|
|
if (distance <= 0) {
|
|
|
|
setCountdownTime('已失效');
|
|
|
|
setIsCountdownTimeout(true);
|
2024-04-02 18:45:46 +08:00
|
|
|
clearInterval(countdownIntervalRef.current);
|
2024-04-01 20:39:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// 每秒更新一次计时器
|
2024-04-02 18:45:46 +08:00
|
|
|
countdownIntervalRef.current = setInterval(() => {
|
2024-04-01 20:39:22 +08:00
|
|
|
updateCountdown();
|
|
|
|
}, 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
const getPay = () => {
|
|
|
|
post<PayType>({
|
|
|
|
messageApi,
|
|
|
|
url: '/api/pay/get-pay',
|
|
|
|
body: {
|
|
|
|
rechargeMoney: form.getFieldValue('rechargeMoney'),
|
|
|
|
thirdParty: form.getFieldValue('thirdParty')
|
|
|
|
},
|
|
|
|
onBefore() {
|
|
|
|
setIsLoading(true);
|
|
|
|
},
|
|
|
|
onSuccess({data}) {
|
|
|
|
setAccountRechargeId(data.accountRechargeId);
|
|
|
|
setThirdPartyPayUrl(data.thirdPartyPayUrl);
|
2024-04-02 18:45:46 +08:00
|
|
|
countdown();
|
2024-04-01 20:39:22 +08:00
|
|
|
},
|
|
|
|
onFinally() {
|
|
|
|
setIsLoading(false);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const getPaySystemBank = () => {
|
|
|
|
get<PaySystemBank>({
|
|
|
|
messageApi,
|
|
|
|
url: '/api/pay/get-pay-system-bank',
|
|
|
|
onSuccess({data}) {
|
|
|
|
setPaySystemBank(data);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
useEffect(() => {
|
2024-04-02 18:45:46 +08:00
|
|
|
if (!thirdParty) {
|
|
|
|
getPaySystemBank();
|
|
|
|
form.setFieldsValue({
|
|
|
|
thirdParty: ThirdPartyEnum.DGZZ,
|
|
|
|
rechargeMoney: 300
|
|
|
|
})
|
|
|
|
setThirdParty(ThirdPartyEnum.DGZZ)
|
2024-07-25 11:41:08 +08:00
|
|
|
return;
|
2024-04-02 18:45:46 +08:00
|
|
|
}
|
2024-04-01 20:39:22 +08:00
|
|
|
getPay();
|
2024-04-02 18:45:46 +08:00
|
|
|
}, [thirdParty, isRechargeMoneyEdit, refreshQrCodeCount]);
|
2024-04-01 20:39:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
const renderMoney = () => {
|
2024-07-25 11:41:08 +08:00
|
|
|
console.log(form.getFieldValue('rechargeMoney'))
|
2024-04-01 20:39:22 +08:00
|
|
|
if (isRechargeMoneyEdit) {
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<InputNumber min={0.01} max={2000} defaultValue={form.getFieldValue('rechargeMoney')}/>
|
|
|
|
<Button type="link" onClick={() => {
|
|
|
|
const money = form.getFieldValue('rechargeMoney');
|
|
|
|
if (money < moneyRange[0]) {
|
|
|
|
form.setFieldValue('rechargeMoney', moneyRange[0]);
|
|
|
|
messageApi.error(`金额最小为${moneyRange[0]}`)
|
|
|
|
} else if (money > moneyRange[1]) {
|
|
|
|
form.setFieldValue('rechargeMoney', moneyRange[1]);
|
|
|
|
messageApi.error(`金额最大为${moneyRange[1]}`)
|
|
|
|
}
|
|
|
|
setIsRechargeMoneyEdit(false);
|
|
|
|
}}>确定</Button>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<span>¥</span>
|
|
|
|
<span style={{fontWeight: 'bold', fontSize: '16px'}}>{form.getFieldValue('rechargeMoney')}</span>
|
|
|
|
<Button type="link" onClick={() => {
|
|
|
|
setIsRechargeMoneyEdit(true);
|
|
|
|
}}>修改</Button>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const renderPayBody = () => {
|
|
|
|
if (thirdParty == '对公转账') {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<div>
|
|
|
|
<Divider orientation="left" plain>收款方信息</Divider>
|
|
|
|
<table className="pay-table">
|
|
|
|
<colgroup>
|
|
|
|
<col width="100"/>
|
|
|
|
<col/>
|
|
|
|
</colgroup>
|
|
|
|
<tbody>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">公司名称</td>
|
|
|
|
<td>
|
|
|
|
<span id="bankAccountName">{paySystemBank.bankAccountName}</span>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">开户银行</td>
|
|
|
|
<td>
|
|
|
|
<span id="bankName">{paySystemBank.bankName}</span>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">银行账号</td>
|
|
|
|
<td>
|
|
|
|
<span id="bankNumber">{paySystemBank.bankNumber}</span>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">银行联行号</td>
|
|
|
|
<td>
|
|
|
|
<span id="bankUnionpayNumber">{paySystemBank.bankUnionpayNumber}</span>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">打款备注</td>
|
|
|
|
<td>
|
|
|
|
<div id="bankRemark">{paySystemBank.bankRemark}</div>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">说明</td>
|
|
|
|
<td>
|
|
|
|
<div className="mark">请打款时必须按照以上备注填写</div>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<Divider orientation="left" plain>付款方信息</Divider>
|
|
|
|
<table className="pay-table">
|
|
|
|
<colgroup>
|
|
|
|
<col width="100"/>
|
|
|
|
<col/>
|
|
|
|
</colgroup>
|
|
|
|
<tbody>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">公司名称 *</td>
|
|
|
|
<td>
|
|
|
|
<Form.Item
|
|
|
|
name="orgName"
|
|
|
|
style={{marginBottom: '0'}}
|
|
|
|
rules={[{required: true, message: '请输入公司名称'}]}
|
|
|
|
>
|
|
|
|
<Input placeholder="请输入公司名称"/>
|
|
|
|
</Form.Item>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">开户银行 *</td>
|
|
|
|
<td>
|
|
|
|
<Form.Item
|
|
|
|
name="orgBank"
|
|
|
|
style={{marginBottom: '0'}}
|
|
|
|
rules={[{required: true, message: '请输入开户行'}]}
|
|
|
|
>
|
|
|
|
<Input placeholder="请输入开户行"/>
|
|
|
|
</Form.Item>
|
|
|
|
</td>
|
|
|
|
</tr>
|
2024-04-02 18:45:46 +08:00
|
|
|
<tr>
|
|
|
|
<td className="table-label">银行账号 *</td>
|
|
|
|
<td>
|
|
|
|
<Form.Item
|
|
|
|
name="orgNumber"
|
|
|
|
style={{marginBottom: '0'}}
|
|
|
|
rules={[{required: true, message: '请输入银行账号'}]}
|
|
|
|
>
|
|
|
|
<Input placeholder="请输入银行账号"/>
|
|
|
|
</Form.Item>
|
|
|
|
</td>
|
|
|
|
</tr>
|
2024-04-01 20:39:22 +08:00
|
|
|
<tr>
|
|
|
|
<td className="table-label">打款时间 *</td>
|
|
|
|
<td>
|
|
|
|
<Form.Item
|
|
|
|
name="rechargeFinalTime"
|
|
|
|
style={{marginBottom: '0'}}
|
|
|
|
rules={[{required: true, message: '请选择打款时间'}]}
|
|
|
|
>
|
|
|
|
<ConfigProvider locale={locale}>
|
2024-04-02 18:45:46 +08:00
|
|
|
<DatePicker showTime placeholder="请选择打款时间"
|
|
|
|
onChange={(_date, dateString) => {
|
|
|
|
form.setFieldValue('rechargeFinalTime', dateString);
|
|
|
|
}}/>
|
2024-04-01 20:39:22 +08:00
|
|
|
</ConfigProvider>
|
|
|
|
</Form.Item>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td className="table-label">打款凭证 *</td>
|
|
|
|
<td>
|
|
|
|
<Form.Item
|
|
|
|
name="rechargeVoucher"
|
|
|
|
style={{marginBottom: '0'}}
|
2024-07-25 11:41:08 +08:00
|
|
|
valuePropName="fileList"
|
|
|
|
getValueFromEvent={(e: any) => {
|
|
|
|
console.log(e);
|
|
|
|
if(e.file.status === 'done') {
|
|
|
|
rechargeVoucherArray.push(e.file.response.data.fileId);
|
|
|
|
setRechargeVoucherArray(rechargeVoucherArray);
|
|
|
|
}
|
|
|
|
if(e.file.status === 'removed') {
|
|
|
|
const idArray = rechargeVoucherArray.filter(item => item != e.file.response.data.fileId);
|
|
|
|
setRechargeVoucherArray(idArray);
|
|
|
|
}
|
|
|
|
return e.fileList;
|
|
|
|
}}
|
2024-04-01 20:39:22 +08:00
|
|
|
rules={[{required: true, message: '请上传打款凭证'}]}
|
|
|
|
>
|
|
|
|
<Upload name="image"
|
2024-07-25 11:41:08 +08:00
|
|
|
maxCount={2}
|
2024-04-01 20:39:22 +08:00
|
|
|
action={uploadImageUrl()}
|
|
|
|
headers={{'X-USER-ID': DevUserId}}
|
|
|
|
beforeUpload={(file: FileType) => {
|
|
|
|
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
|
|
|
|
if (!isJpgOrPng) {
|
|
|
|
message.error('只能上传 JPG/PNG 格式文件!');
|
|
|
|
}
|
|
|
|
return isJpgOrPng;
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Button icon={<UploadOutlined/>}>上传凭证图片</Button>
|
|
|
|
</Upload>
|
|
|
|
</Form.Item>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return <>
|
|
|
|
<Flex gap="middle" align="center" justify="center" vertical>
|
|
|
|
<div className="qr-code">
|
|
|
|
<Image src={thirdPartyPayUrl} fallback={errorImage} preview={false}/>
|
|
|
|
{
|
|
|
|
isCountdownTimeout ? (
|
|
|
|
<div className="qr-timeout" onClick={() => {
|
2024-04-02 18:45:46 +08:00
|
|
|
setRefreshQrCodeCount(refreshQrCodeCount + 1);
|
2024-04-01 20:39:22 +08:00
|
|
|
}}>
|
|
|
|
<ReloadOutlined/>
|
|
|
|
<span className="label">点击刷新</span>
|
|
|
|
</div>
|
|
|
|
) : <></>
|
|
|
|
}
|
|
|
|
</div>
|
|
|
|
<div>{countdownTime}</div>
|
|
|
|
</Flex>
|
|
|
|
</>
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<Spin tip="正在提交..." spinning={isLoading}>
|
|
|
|
<Form
|
|
|
|
name="basic"
|
|
|
|
form={form}
|
|
|
|
onFinish={() => {
|
|
|
|
post<any>({
|
|
|
|
messageApi,
|
|
|
|
url: `/api/pay/pay-account-recharge/${accountRechargeId}`,
|
|
|
|
body: {
|
|
|
|
thirdParty: form.getFieldValue('thirdParty'),
|
|
|
|
rechargeMoney: form.getFieldValue('rechargeMoney'),
|
|
|
|
orgName: thirdParty == ThirdPartyEnum.DGZZ ? form.getFieldValue('orgName') : '',
|
|
|
|
orgBank: thirdParty == ThirdPartyEnum.DGZZ ? form.getFieldValue('orgBank') : '',
|
|
|
|
orgNumber: thirdParty == ThirdPartyEnum.DGZZ ? form.getFieldValue('orgNumber') : '',
|
|
|
|
rechargeFinalTime: thirdParty == ThirdPartyEnum.DGZZ ? form.getFieldValue('rechargeFinalTime') : '',
|
2024-07-25 11:41:08 +08:00
|
|
|
rechargeVoucher: thirdParty == ThirdPartyEnum.DGZZ ? rechargeVoucherArray.join(',') : '',
|
2024-04-01 20:39:22 +08:00
|
|
|
},
|
|
|
|
onBefore() {
|
|
|
|
setIsLoading(true);
|
|
|
|
},
|
|
|
|
onSuccess() {
|
|
|
|
props.handleConfirm();
|
|
|
|
},
|
|
|
|
onFinally() {
|
|
|
|
setIsLoading(false);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
autoComplete="off"
|
|
|
|
>
|
|
|
|
<Form.Item
|
|
|
|
label="支付方式"
|
|
|
|
name="thirdParty"
|
|
|
|
rules={[{required: true}]}
|
|
|
|
>
|
|
|
|
<Radio.Group onChange={(e) => {
|
|
|
|
form.setFieldValue('thirdParty', e.target.value);
|
|
|
|
setThirdParty(e.target.value);
|
2024-07-25 11:41:08 +08:00
|
|
|
}}>
|
2024-04-01 20:39:22 +08:00
|
|
|
<Radio value="微信">微信</Radio>
|
|
|
|
<Radio value="支付宝">支付宝</Radio>
|
|
|
|
{/*<Radio value="银联">银联</Radio>*/}
|
|
|
|
<Radio value="对公转账">对公转账</Radio>
|
|
|
|
</Radio.Group>
|
|
|
|
</Form.Item>
|
|
|
|
<Form.Item
|
|
|
|
label="充值金额"
|
|
|
|
name="rechargeMoney"
|
|
|
|
rules={[{required: true, message: '请输入金额'}]}
|
|
|
|
>
|
|
|
|
{renderMoney()}
|
|
|
|
</Form.Item>
|
|
|
|
{renderPayBody()}
|
|
|
|
<div style={{marginTop: '15px', textAlign: 'center'}}>
|
|
|
|
<Button type="primary" htmlType="submit" style={{backgroundColor: 'var(--color-primary)'}}>
|
|
|
|
完成付款
|
|
|
|
</Button>
|
|
|
|
<Button type="default" style={{marginLeft: '15px'}} onClick={() => {
|
|
|
|
props.handleCancel();
|
|
|
|
}}>关闭窗口</Button>
|
|
|
|
</div>
|
|
|
|
</Form>
|
|
|
|
</Spin>
|
|
|
|
{messageApiContext}
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|