index.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. import React, { useEffect, useState } from 'react';
  2. import { API, isMobile, showError, showInfo, showSuccess } from '../../helpers';
  3. import {
  4. renderNumber,
  5. renderQuota,
  6. renderQuotaWithAmount,
  7. } from '../../helpers/render';
  8. import {
  9. Col,
  10. Layout,
  11. Row,
  12. Typography,
  13. Card,
  14. Button,
  15. Form,
  16. Divider,
  17. Space,
  18. Modal,
  19. Toast,
  20. } from '@douyinfe/semi-ui';
  21. import Title from '@douyinfe/semi-ui/lib/es/typography/title';
  22. import Text from '@douyinfe/semi-ui/lib/es/typography/text';
  23. import { Link } from 'react-router-dom';
  24. import { useTranslation } from 'react-i18next';
  25. const TopUp = () => {
  26. const { t } = useTranslation();
  27. const [redemptionCode, setRedemptionCode] = useState('');
  28. const [topUpCode, setTopUpCode] = useState('');
  29. const [topUpCount, setTopUpCount] = useState(0);
  30. const [minTopupCount, setMinTopUpCount] = useState(1);
  31. const [amount, setAmount] = useState(0.0);
  32. const [minTopUp, setMinTopUp] = useState(1);
  33. const [topUpLink, setTopUpLink] = useState('');
  34. const [enableOnlineTopUp, setEnableOnlineTopUp] = useState(false);
  35. const [userQuota, setUserQuota] = useState(0);
  36. const [isSubmitting, setIsSubmitting] = useState(false);
  37. const [open, setOpen] = useState(false);
  38. const [payWay, setPayWay] = useState('');
  39. const topUp = async () => {
  40. if (redemptionCode === '') {
  41. showInfo(t('请输入兑换码!'));
  42. return;
  43. }
  44. setIsSubmitting(true);
  45. try {
  46. const res = await API.post('/api/user/topup', {
  47. key: redemptionCode,
  48. });
  49. const { success, message, data } = res.data;
  50. if (success) {
  51. showSuccess(t('兑换成功!'));
  52. Modal.success({
  53. title: t('兑换成功!'),
  54. content: t('成功兑换额度:') + renderQuota(data),
  55. centered: true,
  56. });
  57. setUserQuota((quota) => {
  58. return quota + data;
  59. });
  60. setRedemptionCode('');
  61. } else {
  62. showError(message);
  63. }
  64. } catch (err) {
  65. showError(t('请求失败'));
  66. } finally {
  67. setIsSubmitting(false);
  68. }
  69. };
  70. const openTopUpLink = () => {
  71. if (!topUpLink) {
  72. showError(t('超级管理员未设置充值链接!'));
  73. return;
  74. }
  75. window.open(topUpLink, '_blank');
  76. };
  77. const preTopUp = async (payment) => {
  78. if (!enableOnlineTopUp) {
  79. showError(t('管理员未开启在线充值!'));
  80. return;
  81. }
  82. await getAmount();
  83. if (topUpCount < minTopUp) {
  84. showError(t('充值数量不能小于') + minTopUp);
  85. return;
  86. }
  87. setPayWay(payment);
  88. setOpen(true);
  89. };
  90. const onlineTopUp = async () => {
  91. if (amount === 0) {
  92. await getAmount();
  93. }
  94. if (topUpCount < minTopUp) {
  95. showError('充值数量不能小于' + minTopUp);
  96. return;
  97. }
  98. setOpen(false);
  99. try {
  100. const res = await API.post('/api/user/pay', {
  101. amount: parseInt(topUpCount),
  102. top_up_code: topUpCode,
  103. payment_method: payWay,
  104. });
  105. if (res !== undefined) {
  106. const { message, data } = res.data;
  107. // showInfo(message);
  108. if (message === 'success') {
  109. let params = data;
  110. let url = res.data.url;
  111. let form = document.createElement('form');
  112. form.action = url;
  113. form.method = 'POST';
  114. // 判断是否为safari浏览器
  115. let isSafari =
  116. navigator.userAgent.indexOf('Safari') > -1 &&
  117. navigator.userAgent.indexOf('Chrome') < 1;
  118. if (!isSafari) {
  119. form.target = '_blank';
  120. }
  121. for (let key in params) {
  122. let input = document.createElement('input');
  123. input.type = 'hidden';
  124. input.name = key;
  125. input.value = params[key];
  126. form.appendChild(input);
  127. }
  128. document.body.appendChild(form);
  129. form.submit();
  130. document.body.removeChild(form);
  131. } else {
  132. showError(data);
  133. // setTopUpCount(parseInt(res.data.count));
  134. // setAmount(parseInt(data));
  135. }
  136. } else {
  137. showError(res);
  138. }
  139. } catch (err) {
  140. console.log(err);
  141. } finally {
  142. }
  143. };
  144. const getUserQuota = async () => {
  145. let res = await API.get(`/api/user/self`);
  146. const { success, message, data } = res.data;
  147. if (success) {
  148. setUserQuota(data.quota);
  149. } else {
  150. showError(message);
  151. }
  152. };
  153. useEffect(() => {
  154. let status = localStorage.getItem('status');
  155. if (status) {
  156. status = JSON.parse(status);
  157. if (status.top_up_link) {
  158. setTopUpLink(status.top_up_link);
  159. }
  160. if (status.min_topup) {
  161. setMinTopUp(status.min_topup);
  162. }
  163. if (status.enable_online_topup) {
  164. setEnableOnlineTopUp(status.enable_online_topup);
  165. }
  166. }
  167. getUserQuota().then();
  168. }, []);
  169. const renderAmount = () => {
  170. // console.log(amount);
  171. return amount + ' ' + t('元');
  172. };
  173. const getAmount = async (value) => {
  174. if (value === undefined) {
  175. value = topUpCount;
  176. }
  177. try {
  178. const res = await API.post('/api/user/amount', {
  179. amount: parseFloat(value),
  180. top_up_code: topUpCode,
  181. });
  182. if (res !== undefined) {
  183. const { message, data } = res.data;
  184. // showInfo(message);
  185. if (message === 'success') {
  186. setAmount(parseFloat(data));
  187. } else {
  188. setAmount(0);
  189. Toast.error({ content: '错误:' + data, id: 'getAmount' });
  190. // setTopUpCount(parseInt(res.data.count));
  191. // setAmount(parseInt(data));
  192. }
  193. } else {
  194. showError(res);
  195. }
  196. } catch (err) {
  197. console.log(err);
  198. } finally {
  199. }
  200. };
  201. const handleCancel = () => {
  202. setOpen(false);
  203. };
  204. return (
  205. <div>
  206. <Layout>
  207. <Layout.Header>
  208. <h3>{t('我的钱包')}</h3>
  209. </Layout.Header>
  210. <Layout.Content>
  211. <Modal
  212. title={t('确定要充值吗')}
  213. visible={open}
  214. onOk={onlineTopUp}
  215. onCancel={handleCancel}
  216. maskClosable={false}
  217. size={'small'}
  218. centered={true}
  219. >
  220. <p>{t('充值数量')}:{topUpCount}</p>
  221. <p>{t('实付金额')}:{renderAmount()}</p>
  222. <p>{t('是否确认充值?')}</p>
  223. </Modal>
  224. <div
  225. style={{ marginTop: 20, display: 'flex', justifyContent: 'center' }}
  226. >
  227. <Card style={{ width: '500px', padding: '20px' }}>
  228. <Title level={3} style={{ textAlign: 'center' }}>
  229. {t('余额')} {renderQuota(userQuota)}
  230. </Title>
  231. <div style={{ marginTop: 20 }}>
  232. <Divider>{t('兑换余额')}</Divider>
  233. <Form>
  234. <Form.Input
  235. field={'redemptionCode'}
  236. label={t('兑换码')}
  237. placeholder={t('兑换码')}
  238. name='redemptionCode'
  239. value={redemptionCode}
  240. onChange={(value) => {
  241. setRedemptionCode(value);
  242. }}
  243. />
  244. <Space>
  245. {topUpLink ? (
  246. <Button
  247. type={'primary'}
  248. theme={'solid'}
  249. onClick={openTopUpLink}
  250. >
  251. {t('获取兑换码')}
  252. </Button>
  253. ) : null}
  254. <Button
  255. type={'warning'}
  256. theme={'solid'}
  257. onClick={topUp}
  258. disabled={isSubmitting}
  259. >
  260. {isSubmitting ? t('兑换中...') : t('兑换')}
  261. </Button>
  262. </Space>
  263. </Form>
  264. </div>
  265. <div style={{ marginTop: 20 }}>
  266. <Divider>{t('在线充值')}</Divider>
  267. <Form>
  268. <Form.Input
  269. disabled={!enableOnlineTopUp}
  270. field={'redemptionCount'}
  271. label={t('实付金额:') + ' ' + renderAmount()}
  272. placeholder={t('充值数量,最低 ') + renderQuotaWithAmount(minTopUp)}
  273. name='redemptionCount'
  274. type={'number'}
  275. value={topUpCount}
  276. onChange={async (value) => {
  277. if (value < 1) {
  278. value = 1;
  279. }
  280. setTopUpCount(value);
  281. await getAmount(value);
  282. }}
  283. />
  284. <Space>
  285. <Button
  286. type={'primary'}
  287. theme={'solid'}
  288. onClick={async () => {
  289. preTopUp('zfb');
  290. }}
  291. >
  292. {t('支付宝')}
  293. </Button>
  294. <Button
  295. style={{
  296. backgroundColor: 'rgba(var(--semi-green-5), 1)',
  297. }}
  298. type={'primary'}
  299. theme={'solid'}
  300. onClick={async () => {
  301. preTopUp('wx');
  302. }}
  303. >
  304. {t('微信')}
  305. </Button>
  306. </Space>
  307. </Form>
  308. </div>
  309. {/*<div style={{ display: 'flex', justifyContent: 'right' }}>*/}
  310. {/* <Text>*/}
  311. {/* <Link onClick={*/}
  312. {/* async () => {*/}
  313. {/* window.location.href = '/topup/history'*/}
  314. {/* }*/}
  315. {/* }>充值记录</Link>*/}
  316. {/* </Text>*/}
  317. {/*</div>*/}
  318. </Card>
  319. </div>
  320. </Layout.Content>
  321. </Layout>
  322. </div>
  323. );
  324. };
  325. export default TopUp;