system-copyright-react/src/components/payment/Payment.tsx

505 lines
23 KiB
TypeScript
Raw Normal View History

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-07-25 18:33:29 +08:00
Upload, UploadProps,
Tag
2024-04-01 20:39:22 +08:00
} from "antd";
import {
ReloadOutlined
} from '@ant-design/icons'
2024-07-25 15:20:54 +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-07-25 15:20:54 +08:00
import { DevUserId, get, post, uploadImageUrl } from "../../util/AjaxUtils.ts";
import { UploadOutlined } from "@ant-design/icons";
2024-04-01 20:39:22 +08:00
import useMessage from "antd/es/message/useMessage";
2024-07-25 15:20:54 +08:00
import { errorImage } from "../../util/CommonUtil.ts";
2024-04-01 20:39:22 +08:00
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) {
2024-07-25 15:20:54 +08:00
const [mask, setMask] = useState(false)
2024-04-01 20:39:22 +08:00
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('');
2024-07-25 15:20:54 +08:00
// const [isCountdownTimeout, setIsCountdownTimeout] = useState(false);
2024-04-01 20:39:22 +08:00
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);
}
2024-07-25 15:20:54 +08:00
// 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();
2024-07-25 15:20:54 +08:00
// const countDownDate = new Date(Time + 5 * 1000).getTime();
2024-04-01 20:39:22 +08:00
// 更新计时器的秒数
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('已失效');
2024-07-25 15:20:54 +08:00
// setIsCountdownTimeout(true);
2024-04-02 18:45:46 +08:00
clearInterval(countdownIntervalRef.current);
2024-07-25 15:20:54 +08:00
setMask(true)
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);
},
2024-07-25 15:20:54 +08:00
onSuccess({ data }) {
2024-04-01 20:39:22 +08:00
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',
2024-07-25 15:20:54 +08:00
onSuccess({ data }) {
2024-04-01 20:39:22 +08:00
setPaySystemBank(data);
}
})
}
useEffect(() => {
2024-04-02 18:45:46 +08:00
if (!thirdParty) {
getPaySystemBank();
form.setFieldsValue({
thirdParty: ThirdPartyEnum.DGZZ,
2024-07-25 18:33:29 +08:00
rechargeMoney: 280
2024-04-02 18:45:46 +08:00
})
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-07-25 15:20:54 +08:00
// countdown()
2024-07-25 15:59:10 +08:00
}, [thirdParty, 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>
2024-07-25 18:33:29 +08:00
<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);
getPay()
}}></Button>
<span style={{ color: '#1677ff', cursor: 'pointer' }}
onClick={() => {
setIsRechargeMoneyEdit(false)
}}
></span>
</div>
2024-04-01 20:39:22 +08:00
</div>
)
}
return (
<div>
2024-07-25 18:33:29 +08:00
<div>
<span></span>
<span style={{ fontWeight: 'bold', fontSize: '16px' }}>{form.getFieldValue('rechargeMoney')}</span>
<Button type="link" onClick={() => {
setIsRechargeMoneyEdit(true);
}}></Button>
</div>
<div className='moneyBox' >
<Tag style={{ cursor: 'pointer' }} onClick={() => {
form.setFieldValue('rechargeMoney', '100');
setIsRechargeMoneyEdit(false)
getPay()
}} color="volcano">100</Tag>
<Tag style={{ cursor: 'pointer' }} onClick={() => {
form.setFieldValue('rechargeMoney', '200');
setIsRechargeMoneyEdit(false)
getPay()
}} color="volcano">200</Tag>
<Tag style={{ cursor: 'pointer' }} onClick={() => {
form.setFieldValue('rechargeMoney', '300');
setIsRechargeMoneyEdit(false)
getPay()
}} color="volcano">300</Tag>
<Tag style={{ cursor: 'pointer' }} onClick={() => {
form.setFieldValue('rechargeMoney', '400');
setIsRechargeMoneyEdit(false)
getPay()
}} color="volcano">400</Tag>
<Tag style={{ cursor: 'pointer' }} onClick={() => {
form.setFieldValue('rechargeMoney', '500');
setIsRechargeMoneyEdit(false)
getPay()
}} color="volcano">500</Tag>
</div>
2024-04-01 20:39:22 +08:00
</div>
)
}
const renderPayBody = () => {
if (thirdParty == '对公转账') {
return (
2024-07-25 15:20:54 +08:00
<div >
<div>:{countdownTime}</div>
2024-04-01 20:39:22 +08:00
<div>
<Divider orientation="left" plain></Divider>
<table className="pay-table">
<colgroup>
2024-07-25 15:20:54 +08:00
<col width="100" />
<col />
2024-04-01 20:39:22 +08:00
</colgroup>
<tbody>
2024-07-25 15:20:54 +08:00
<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>
2024-04-01 20:39:22 +08:00
</tbody>
</table>
</div>
<div>
<Divider orientation="left" plain></Divider>
<table className="pay-table">
<colgroup>
2024-07-25 15:20:54 +08:00
<col width="100" />
<col />
2024-04-01 20:39:22 +08:00
</colgroup>
<tbody>
2024-07-25 15:20:54 +08:00
<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>
<tr>
<td className="table-label"> *</td>
<td>
<Form.Item
name="orgNumber"
style={{ marginBottom: '0' }}
rules={[{ required: true, message: '请输入银行账号' }]}
>
<Input placeholder="请输入银行账号" />
</Form.Item>
</td>
</tr>
<tr>
<td className="table-label"> *</td>
<td>
<Form.Item
name="rechargeFinalTime"
style={{ marginBottom: '0' }}
rules={[{ required: true, message: '请选择打款时间' }]}
>
<ConfigProvider locale={locale}>
<DatePicker showTime placeholder="请选择打款时间"
onChange={(_date, dateString) => {
form.setFieldValue('rechargeFinalTime', dateString);
}} />
</ConfigProvider>
</Form.Item>
</td>
</tr>
<tr>
<td className="table-label"> *</td>
<td>
<Form.Item
name="rechargeVoucher"
style={{ marginBottom: '0' }}
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;
}}
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()}
2024-07-25 15:20:54 +08:00
headers={{ 'X-USER-ID': DevUserId }}
2024-04-01 20:39:22 +08:00
beforeUpload={(file: FileType) => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('只能上传 JPG/PNG 格式文件!');
}
return isJpgOrPng;
}}
2024-07-25 15:20:54 +08:00
>
<Button icon={<UploadOutlined />}></Button>
</Upload>
</Form.Item>
</td>
</tr>
2024-04-01 20:39:22 +08:00
</tbody>
</table>
</div>
2024-07-25 15:20:54 +08:00
</div>
2024-04-01 20:39:22 +08:00
)
}
return <>
<Flex gap="middle" align="center" justify="center" vertical>
2024-07-25 16:58:56 +08:00
<div className="qr-code" style={{ position: 'relative' }}>
2024-07-25 18:33:29 +08:00
<div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', background: "rgba(0,0,0,0.6)", backdropFilter: 'blur(10px)', zIndex: 99, display: isRechargeMoneyEdit ? 'block' : 'none' }}>
<div style={{ color: '#fff', width: '100%', height: '100%', fontSize: 30, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
2024-07-25 16:58:56 +08:00
,...
</div>
</div>
2024-07-25 15:20:54 +08:00
<Image src={thirdPartyPayUrl} fallback={errorImage} preview={false} />
{/* {
2024-04-01 20:39:22 +08:00
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
}}>
2024-07-25 15:20:54 +08:00
<ReloadOutlined />
2024-04-01 20:39:22 +08:00
<span className="label"></span>
</div>
) : <></>
2024-07-25 15:20:54 +08:00
} */}
2024-04-01 20:39:22 +08:00
</div>
<div>{countdownTime}</div>
</Flex>
</>
}
return (
2024-07-25 15:20:54 +08:00
<div style={{ position: 'relative' }}>
<div style={{ position: 'absolute', width: '100%', height: '100%', top: 0, left: 0, background: 'rgba(0,0,0,0.6)', zIndex: 99, display: mask ? 'block' : 'none' }}>
2024-07-25 16:58:56 +08:00
<div style={{ color: '#FFF', fontSize: 16, width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }} >
<div style={{ cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }} onClick={() => {
2024-07-25 15:20:54 +08:00
setMask(false)
setRefreshQrCodeCount(refreshQrCodeCount + 1);
}}>
2024-07-25 16:58:56 +08:00
<div style={{ fontSize: 70 }}><ReloadOutlined /></div>
2024-07-25 15:20:54 +08:00
,
</div>
</div>
</div>
2024-04-01 20:39:22 +08:00
<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"
2024-07-25 15:20:54 +08:00
rules={[{ required: true }]}
2024-04-01 20:39:22 +08:00
>
<Radio.Group onChange={(e) => {
form.setFieldValue('thirdParty', e.target.value);
setThirdParty(e.target.value);
2024-07-25 15:59:10 +08:00
setIsRechargeMoneyEdit(false)
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"
2024-07-25 15:20:54 +08:00
rules={[{ required: true, message: '请输入金额' }]}
2024-04-01 20:39:22 +08:00
>
{renderMoney()}
</Form.Item>
{renderPayBody()}
2024-07-25 15:20:54 +08:00
<div style={{ marginTop: '15px', textAlign: 'center' }}>
<Button type="primary" htmlType="submit" style={{ backgroundColor: 'var(--color-primary)' }}>
2024-04-01 20:39:22 +08:00
</Button>
2024-07-25 15:20:54 +08:00
<Button type="default" style={{ marginLeft: '15px' }} onClick={() => {
2024-04-01 20:39:22 +08:00
props.handleCancel();
}}></Button>
</div>
</Form>
</Spin>
{messageApiContext}
2024-07-25 15:20:54 +08:00
</div>
2024-04-01 20:39:22 +08:00
)
}