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