give-dialog.vue 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  1. <template>
  2. <div class="overlay" v-if="visible">
  3. <div
  4. class="content"
  5. :style="{
  6. height: dialogHeight + 'px',
  7. width: showComType != 'preview' ? '600px' : 'auto',
  8. }"
  9. >
  10. <div class="head" @click.self="showCurrencyPop = false">
  11. <div class="left">
  12. <div class="close-btn" @click="close">
  13. <img
  14. class="icon-close"
  15. v-if="showComType == 'default'"
  16. :src="require('../../assets/svg/icon-close.svg')"
  17. />
  18. <img
  19. class="icon-close"
  20. v-else
  21. :src="require('../../assets/svg/icon-back.svg')"
  22. />
  23. </div>
  24. <div class="title">
  25. {{ currentComData[showComType]["title"] }}
  26. </div>
  27. </div>
  28. <div class="right">
  29. <img :src="require('@/assets/svg/icon-more-l.svg')"
  30. class="more"
  31. @click="showMoreOption = true">
  32. <div class="area-option"
  33. v-if="showMoreOption"
  34. @click="showMoreOption = false">
  35. <div class="option">
  36. <div class="item" @click="goTransactionsList()">
  37. <img :src="require('@/assets/svg/icon-menu.svg')">
  38. <span>Transactions</span>
  39. </div>
  40. </div>
  41. </div>
  42. </div>
  43. </div>
  44. <div class="body">
  45. <!-- 充值组件 -->
  46. <top-up v-if="showComType == 'topUp'"
  47. :currentCurrencyInfo="currentCurrencyInfo"
  48. @topUpDone="topUpDone"></top-up>
  49. <!-- 表单填写容器 -->
  50. <div class="body-content" v-if="showComType != 'topUp'">
  51. <!-- 货币列表 -->
  52. <div class="currency-pop" v-show="showCurrencyPop">
  53. <currency-list
  54. ref="currencyListDom"
  55. @selectCurrency="selectCurrency"
  56. @setCurrencyList="setCurrentCurrencyInfo"></currency-list>
  57. </div>
  58. <div class="left" @click.self="showCurrencyPop = false">
  59. <div class="gift-pack-wrapper">
  60. <img
  61. class="icon"
  62. :src="
  63. require('../../assets/svg/icon-gift-pack.svg')
  64. "
  65. />
  66. </div>
  67. <div class="bottom">
  68. </div>
  69. </div>
  70. <div class="right">
  71. <div class="form-wrapper" v-if="showComType == 'default'">
  72. <img
  73. @click.stop="showCurrencyPop = false"
  74. class="img-mode"
  75. src="../../assets/img/img-mode.png"
  76. />
  77. <!-- 金额、数量 -->
  78. <div class="form-base">
  79. <div class="item currency-select-wrapper">
  80. <div
  81. class="label currency-select"
  82. @click="showCurrencyPop = true"
  83. >
  84. <img
  85. class="icon"
  86. :src="currentCurrencyInfo.iconPath || require('../../assets/svg/icon-currency.svg')"
  87. />
  88. {{currentCurrencyInfo.currencyCode == 'USD' ? 'USD' : currentCurrencyInfo.tokenSymbol || 'Currency'}}
  89. <img
  90. class="arrow"
  91. :src="
  92. require('../../assets/svg/icon-form-arrow-down.svg')
  93. "
  94. />
  95. </div>
  96. <input
  97. v-model="baseFormData.amountValue"
  98. placeholder="0"
  99. autofocus
  100. @input="onAmountInput"
  101. @blur="onAmountBlur"
  102. />
  103. </div>
  104. <div class="item" @click.stop="showCurrencyPop = false">
  105. <div class="label">
  106. <img
  107. class="icon"
  108. :src="
  109. require('../../assets/svg/icon-winners.svg')
  110. "
  111. />
  112. Winners
  113. </div>
  114. <input
  115. v-model="baseFormData.totalCount"
  116. placeholder="0"
  117. @input="onCountInput"
  118. @blur="onCountBlur"
  119. />
  120. </div>
  121. </div>
  122. <!-- 刷新按钮、充值 -->
  123. <div class="form-base-help" @click.stop="showCurrencyPop = false">
  124. <div class="currency-operation">
  125. <div class="balance">
  126. <img
  127. :src="
  128. require('../../assets/svg/icon-balance.svg')
  129. "
  130. />
  131. Balance
  132. </div>
  133. <div class="amount">
  134. {{currentCurrencyInfo.balance}}
  135. <img
  136. :class="{ 'icon-refresh-rotate': refreshRotate }"
  137. @click="updateCurrencyBanlce"
  138. :src="
  139. require('../../assets/svg/icon-form-refresh.svg')
  140. "
  141. />
  142. </div>
  143. <div class="top-up" @click="goTopUp">Top UP</div>
  144. </div>
  145. <div class="msg">
  146. Recommend quantity 100~10000
  147. </div>
  148. </div>
  149. <div class="form-label">Tasks</div>
  150. <!-- 转推、like、关注 -->
  151. <div class="form-require" @click.stop="showCurrencyPop = false">
  152. <div
  153. class="form-item"
  154. v-for="(item, index) in formList"
  155. :key="index"
  156. >
  157. <div class="label">
  158. <img
  159. class="icon"
  160. :src="item.icon"
  161. />
  162. {{ item.label }}
  163. </div>
  164. <div
  165. class="control"
  166. v-if="item.nodeType == 'textarea'"
  167. >
  168. <follow-input
  169. :isAddSelf="!isBack"
  170. :atUserList="atUserList"
  171. @addUser="addFollowUser"
  172. @setUser="setFollowUser"
  173. @delUser="delFollowUser"
  174. ></follow-input>
  175. </div>
  176. <el-switch
  177. v-if="item.type == 2"
  178. v-model="item.checked"
  179. />
  180. <img
  181. v-if="item.type == 3"
  182. :src="
  183. require('../../assets/svg/icon-option-checked.svg')
  184. "
  185. />
  186. </div>
  187. </div>
  188. <!-- 机器人 -->
  189. <div class="anti-bot-wrapper">
  190. <div class="label">
  191. <img
  192. :src="
  193. require('../../assets/svg/icon-anti-bot.svg')
  194. "
  195. class="icon-bot"
  196. />
  197. Anti Bot
  198. <img
  199. :src="
  200. require('../../assets/svg/icon-beta.svg')
  201. "
  202. class="icon-beta"
  203. />
  204. <img
  205. :src="
  206. require('../../assets/svg/icon-question.svg')
  207. "
  208. class="icon-question"
  209. />
  210. </div>
  211. <el-switch v-model="openAntiBot" />
  212. </div>
  213. <!-- 提示 -->
  214. <div class="tips-wrapper">
  215. <div class="title">TIPS</div>
  216. <div class="row">
  217. 1. Only after the user completes the
  218. tasks you set, they can claim your red
  219. envelopes
  220. </div>
  221. <div class="row">
  222. 2. Each user can only receive one red
  223. envelope
  224. </div>
  225. <div class="row">
  226. 3. The red envelope issued is valid for
  227. 7 days. Please promote your red envelope
  228. as much as possible within the validity
  229. period. After the red envelope expires,
  230. the red envelope will be returned to
  231. your DeNet wallet.
  232. </div>
  233. <div class="more">More</div>
  234. </div>
  235. <div class="submit-btn-wrapper">
  236. <div class="submit-btn"
  237. :class="{ 'disabled-submit': iptErrMsgTxt != '' }"
  238. @click="confirm">
  239. <img
  240. class="icon-loading"
  241. v-if="submitIng"
  242. :src="
  243. require('../../assets/svg/icon-btn-loading.svg')
  244. "
  245. />
  246. {{iptErrMsgTxt ? iptErrMsgTxt : 'NEXT'}}
  247. </div>
  248. </div>
  249. </div>
  250. <!-- 预览 -->
  251. <template v-else-if="showComType == 'preview'">
  252. <preview-card
  253. :currentCurrencyInfo="currentCurrencyInfo"
  254. :postData="publishRes"
  255. :baseFormData="baseFormData"
  256. ></preview-card>
  257. </template>
  258. <!-- paypal支付按钮 -->
  259. <div v-show="showComType == 'preview'">
  260. <paypal-button
  261. :finalAmountData="finalAmountData"
  262. :payConfig="{
  263. paypalClientId,
  264. feeDesc: payConfig.feeDesc,
  265. paypalHtml,
  266. amount: baseFormData.amountValue
  267. }"
  268. :currentCurrencyInfo="currentCurrencyInfo"
  269. :postData="publishRes"
  270. @payPalFinsh="payPalFinsh"
  271. ></paypal-button>
  272. </div>
  273. </div>
  274. </div>
  275. </div>
  276. </div>
  277. <!-- 提示 -->
  278. <message-box
  279. :dialogVisible="showMessageBox"
  280. :title="messageBoxData.title"
  281. :content="messageBoxData.content"
  282. @cancel="messageBoxCancel"
  283. @confirm="messageBoxConfirm"
  284. ></message-box>
  285. </div>
  286. </template>
  287. <script setup>
  288. import { ref, watch, reactive, defineProps, defineEmits, onMounted } from "vue";
  289. import { postPublish, verifyPaypalResult, syncChainTokenRechargeRecord } from "../../http/publishApi";
  290. import { payCalcFee, getPayConfig } from "../../http/pay";
  291. import { getFrontConfig } from "../../http/account";
  292. import { scaleNumber } from "../../uilts/help"
  293. import { ElMessage, ElLoading } from "element-plus";
  294. import "element-plus/es/components/message/style/css";
  295. import previewCard from "./preview-card";
  296. import paypalButton from "./paypal-button";
  297. import followInput from "./follow-input";
  298. import messageBox from "./message-box.vue";
  299. import currencyList from "./currency-list.vue";
  300. import topUp from "./top-up.vue"
  301. let paypalClientId = ref("");
  302. let payConfig = ref({})
  303. let paypalHtml = ref("");
  304. let publishRes = reactive({});
  305. let currentComData = {
  306. default: {
  307. title: "Giveaways",
  308. },
  309. preview: {
  310. title: "Preview",
  311. },
  312. topUp: {
  313. title: "Top Up",
  314. },
  315. };
  316. let visible = ref(true);
  317. let showComType = ref("default"); // default(表单) preview(预览) topUp(充值)
  318. let openAntiBot = ref(false);
  319. let dialogHeight = ref(680);
  320. // 是否正在提交
  321. let submitIng = ref(false);
  322. // 艾特关注人列表
  323. let atUserList = ref([]);
  324. let iptErrMsgTxt = ref("Please enter the ‘reward’ amount");
  325. // 是否返回
  326. let isBack = ref(false);
  327. // 展示消息提示
  328. let showMessageBox = ref(false);
  329. // 展示货币列表pop
  330. let showCurrencyPop = ref(false);
  331. let showMoreOption = ref(false);
  332. let currencyListDom = ref(null);
  333. let refreshRotate = ref(false);
  334. let messageBoxData = ref({
  335. title: "",
  336. content: "",
  337. });
  338. // 真实支付金额数据
  339. let finalAmountData = ref({
  340. currencyCode: '',
  341. feeAmountValue: 0,
  342. finalAmountValue: 0,
  343. requestAmountValue: 0,
  344. });
  345. // 表单数据
  346. let baseFormData = reactive({
  347. amountCurrencyCode: '',
  348. amountValue: "",
  349. totalCount: "",
  350. });
  351. // 当前选择的货币信息
  352. let currentCurrencyInfo = ref({
  353. currencyCode: "",
  354. currencyName: "",
  355. balance: "",
  356. currencyType: "",
  357. iconPath: "",
  358. minAmount: "",
  359. tokenChain: "",
  360. tokenSymbol: "",
  361. usdEstimateBalance: ""
  362. });
  363. let formList = reactive([
  364. {
  365. label: "Follow",
  366. icon: require("../../assets/svg/icon-follow.svg"),
  367. nodeType: "textarea",
  368. type: 1,
  369. text: [],
  370. checked: true,
  371. },
  372. {
  373. label: "Retweet",
  374. icon: require("../../assets/svg/icon-retweet.svg"),
  375. nodeType: "div",
  376. type: 3,
  377. checked: true,
  378. },
  379. {
  380. label: "Like tweet",
  381. icon: require("../../assets/svg/icon-like.svg"),
  382. nodeType: "div",
  383. type: 2,
  384. checked: true,
  385. },
  386. ]);
  387. const props = defineProps({
  388. dialogVisible: {
  389. type: Boolean,
  390. default: false,
  391. },
  392. });
  393. watch(
  394. () => props.dialogVisible,
  395. (newVal) => {
  396. console.log("watch", newVal);
  397. if (newVal) {
  398. setTimeout(() => {
  399. setDialogHeight();
  400. }, 300);
  401. }
  402. visible.value = newVal;
  403. }
  404. );
  405. const emits = defineEmits(["close", "confirm", "payPalFinsh"]);
  406. const close = () => {
  407. if (showComType.value != "default") {
  408. showComType.value = "default";
  409. isBack.value = true;
  410. } else {
  411. initParams();
  412. emits("close", false);
  413. }
  414. };
  415. /**
  416. * 设置弹窗高度
  417. */
  418. const setDialogHeight = () => {
  419. let clientHeight = window.innerHeight;
  420. let gapSafe = 40;
  421. if (dialogHeight.value > clientHeight - gapSafe) {
  422. dialogHeight.value = clientHeight - gapSafe;
  423. }
  424. };
  425. /**
  426. * 获取实际支付金额
  427. */
  428. const getPayAmount = async (amountValue) => {
  429. let res = await payCalcFee({
  430. params: {
  431. amountValue,
  432. currencyCode: currentCurrencyInfo.value.currencyCode,
  433. payChannel: 'paypal',
  434. },
  435. });
  436. if (res.code == 0) {
  437. let { finalAmountValue, feeDesc } = res.data;
  438. payConfig.value.feeDesc = feeDesc;
  439. if (finalAmountValue > 0) {
  440. finalAmountData.value = res.data;
  441. }
  442. }
  443. return res.data;
  444. };
  445. const confirm = () => {
  446. if (submitIng.value || iptErrMsgTxt.value) {
  447. return;
  448. }
  449. let { totalCount = 0 } = baseFormData;
  450. if (!totalCount) {
  451. return;
  452. }
  453. submitRequest();
  454. };
  455. const selectCurrency = (params) => {
  456. currentCurrencyInfo.value = params;
  457. if(params.currencyCode != "USD" && params.balance < params.minAmount) {
  458. let tokenSymbol = params.currencyCode == 'USD' ? 'USD' : params.tokenSymbol;
  459. messageBoxBlock({
  460. title: `是否要充值 ${tokenSymbol}`,
  461. content: `${tokenSymbol} 可用余额为${params.balance},是否要去充值?`,
  462. });
  463. } else {
  464. showCurrencyPop.value = false;
  465. finalAmountData.value.currencyCode = currentCurrencyInfo.value.currencyCode;
  466. }
  467. };
  468. /**
  469. * 设置默认使用货币
  470. */
  471. const setCurrentCurrencyInfo = (params) => {
  472. let {list} = params;
  473. if(list && list.length && list[0].data && list[0].data.length) {
  474. currentCurrencyInfo.value = list[0].data[0];
  475. finalAmountData.value.currencyCode = currentCurrencyInfo.value.currencyCode;
  476. }
  477. }
  478. const messageBoxBlock = ({ title = "", content = "" }) => {
  479. showMessageBox.value = true;
  480. messageBoxData.value.title = title;
  481. messageBoxData.value.content = content;
  482. };
  483. const messageBoxCancel = () => {
  484. showMessageBox.value = false;
  485. };
  486. const messageBoxConfirm = () => {
  487. showMessageBox.value = false;
  488. showComType.value = "topUp";
  489. };
  490. /**
  491. * 去充值
  492. */
  493. const goTopUp = () => {
  494. showComType.value = 'topUp';
  495. }
  496. /**
  497. * 充值done事件
  498. * 更新货币列表
  499. */
  500. const topUpDone = () => {
  501. asyncTokenRechRecord(() => {
  502. showComType.value = 'default';
  503. })
  504. }
  505. const updateCurrencyBanlce = () => {
  506. if(!refreshRotate.value) {
  507. refreshRotate.value = true;
  508. setTimeout(() => {
  509. refreshRotate.value = false;
  510. }, 1000)
  511. }
  512. asyncTokenRechRecord((data) => {
  513. if(data && data.length) {
  514. let currencyInfo = data[0];
  515. if(currencyInfo.currencyCode && currentCurrencyInfo.value.currencyCode) {
  516. currentCurrencyInfo.value.balance = currencyInfo.balance;
  517. }
  518. }
  519. })
  520. }
  521. /**
  522. * 同步链上交易
  523. */
  524. const asyncTokenRechRecord = (cb) => {
  525. syncChainTokenRechargeRecord({
  526. params: {
  527. currencyCode: currentCurrencyInfo.currencyCode
  528. }
  529. }).then(res => {
  530. if(res.code == 0) {
  531. cb && cb(res.data)
  532. }
  533. })
  534. }
  535. /**
  536. * 提交表单请求
  537. */
  538. const submitRequest = async () => {
  539. let { amountValue = 0, totalCount = 0 } = baseFormData;
  540. baseFormData.amountCurrencyCode = currentCurrencyInfo.value.currencyCode;
  541. // 组装提交参数
  542. formList[0]["text"] = atUserList.value;
  543. let finishConditions = [];
  544. for (let i = 0; i < formList.length; i++) {
  545. let item = {};
  546. item.type = formList[i]["type"];
  547. if (item.type == 1 && formList[i]["text"]) {
  548. // follow 参数
  549. let relatedUsers = formList[i]["text"];
  550. item.relatedUsers = relatedUsers;
  551. finishConditions.push(item);
  552. } else if (formList[i]["checked"]) {
  553. finishConditions.push(item);
  554. }
  555. }
  556. let receiveConditions = openAntiBot.value ? "" : [];
  557. // 提交参数
  558. let formData = {
  559. amountCurrencyCode: baseFormData.amountCurrencyCode,
  560. amountValue,
  561. totalCount,
  562. finishConditions,
  563. receiveConditions,
  564. payAmountValue: amountValue
  565. };
  566. submitIng.value = true;
  567. // 法币支付需要计算费率
  568. if(formData.amountCurrencyCode == "USD") {
  569. let payAmountRes = await getPayAmount(amountValue);
  570. formData["payAmountValue"] = payAmountRes.finalAmountValue;
  571. }
  572. let data = {
  573. params: {
  574. postBizData: JSON.stringify(formData),
  575. postSrc: 1, //1 twitter
  576. postType: 1, //1 红包
  577. },
  578. };
  579. postPublish(data).then((res) => {
  580. submitIng.value = false;
  581. if (res.code == 0) {
  582. publishRes = res.data;
  583. // setPreviewDialogHeight();
  584. showComType.value = "preview";
  585. isBack.value = false;
  586. } else {
  587. console.log(res);
  588. }
  589. })
  590. .catch((err) => {
  591. console.log(err);
  592. });
  593. };
  594. /**
  595. * 初始化提交参数
  596. */
  597. const initParams = () => {
  598. baseFormData.amountValue = "";
  599. baseFormData.totalCount = "";
  600. formList[0].text = [];
  601. atUserList.value = [];
  602. submitIng.value = false;
  603. isBack.value = false;
  604. };
  605. /**
  606. * 支付完成回调
  607. */
  608. const payPalFinsh = (params) => {
  609. let {payNetwork, payStatus} = params;
  610. // token 支付
  611. if(payNetwork == 'bsc') {
  612. payStatusHandle(payStatus);
  613. } else {
  614. // 法币支付
  615. let transaction = params.transaction;
  616. let loadingInstance = ElLoading.service({
  617. background: "rgba(0,0,0,.3)",
  618. });
  619. verifyPaypalResult({
  620. params: {
  621. paypalTransactionId: transaction.id,
  622. postId: publishRes.postId,
  623. paypalClientId: paypalClientId.value,
  624. },
  625. }).then((res) => {
  626. loadingInstance.close();
  627. if (res.code == 0) {
  628. if (res.data) {
  629. payStatusHandle(res.data.payStatus)
  630. }
  631. }
  632. })
  633. .catch(() => {
  634. loadingInstance.close();
  635. });
  636. }
  637. };
  638. const payStatusHandle = (payStatus) => {
  639. //支付状态 0:未支付,1:支付成功,2:支付失败,3:已关闭,4:已退款
  640. switch (payStatus) {
  641. case 1:
  642. emits("payPalFinsh", { publishRes });
  643. showComType.value = "default";
  644. initParams();
  645. break;
  646. case 2:
  647. ElMessage({
  648. message: "Pay Fail",
  649. type: "warning",
  650. });
  651. break;
  652. case 3:
  653. ElMessage({
  654. message: "Pay Exceptions",
  655. type: "warning",
  656. });
  657. break;
  658. case 4:
  659. ElMessage({
  660. message: "Pay Exceptions",
  661. type: "warning",
  662. });
  663. break;
  664. }
  665. }
  666. /**
  667. * follow组件触发新增关注人
  668. */
  669. const addFollowUser = (params) => {
  670. atUserList.value.push(params);
  671. };
  672. const setFollowUser = (params) => {
  673. atUserList.value[params.index]["name"] = params.name;
  674. };
  675. const delFollowUser = (params) => {
  676. atUserList.value.splice(params.index, 1);
  677. };
  678. const onAmountInput = () => {
  679. let val = baseFormData.amountValue;
  680. // val = val.replace(/[^\d^\.]+/g, "");
  681. val = val.replace(/^\D*(\d*(?:\.\d{0,18})?).*$/g, '$1');
  682. baseFormData.amountValue = val;
  683. setIptAmountErrorMsg();
  684. return val;
  685. };
  686. const onCountInput = () => {
  687. let val = baseFormData.totalCount;
  688. if (val == 0) {
  689. val = "";
  690. }
  691. // val = val.replace(/[^\d]/g, "");
  692. val = val.replace(/^\D*(\d*(?:\.\d{0,18})?).*$/g, '$1');
  693. if (val > 9999) {
  694. val = 9999;
  695. }
  696. baseFormData.totalCount = val;
  697. setIptAmountErrorMsg();
  698. return val;
  699. };
  700. /**
  701. * 金额输入失焦
  702. */
  703. const onAmountBlur = () => {
  704. if (!baseFormData.amountValue) {
  705. iptErrMsgTxt.value =
  706. "Please enter the ‘reward’ amount";
  707. } else {
  708. setIptAmountErrorMsg((res) => {
  709. if (res.flag) {
  710. // if(!baseFormData.totalCount) {
  711. // iptErrMsgTxt.value = "Please enter the ‘winners' amount";
  712. // } else {
  713. iptErrMsgTxt.value = "";
  714. // }
  715. }
  716. });
  717. }
  718. };
  719. /**
  720. * count失焦,校验输入结果
  721. */
  722. const onCountBlur = () => {
  723. if (!baseFormData.totalCount) {
  724. iptErrMsgTxt.value =
  725. "Please enter the ‘winners’ amount";
  726. } else {
  727. iptErrMsgTxt.value = "";
  728. setIptAmountErrorMsg((res) => {
  729. if (res.flag) {
  730. iptErrMsgTxt.value = "";
  731. }
  732. });
  733. }
  734. };
  735. /**
  736. * 输入结果计算、校验
  737. */
  738. const calcIptValue = (cb) => {
  739. let amountValue = baseFormData.amountValue;
  740. let totalCount = baseFormData.totalCount;
  741. let flag = true;
  742. if (!amountValue || !totalCount) {
  743. return {
  744. flag
  745. };
  746. }
  747. let num = amountValue, scale = 1;
  748. if(amountValue.indexOf('.') > -1) {
  749. num = amountValue.toString();
  750. let obj = scaleNumber(num);
  751. num = obj.val;
  752. scale = obj.scale;
  753. }
  754. let minAmount = currentCurrencyInfo.value.minAmount;
  755. // 输入的token数量或者法币金额,平均分到每个红包,是否小于最小单位
  756. if (num / totalCount < minAmount * scale) {
  757. flag = false;
  758. }
  759. console.log('minAmount')
  760. cb && cb(flag);
  761. return {
  762. flag,
  763. count: math.floor((num / minAmount * scale)/ (scale * scale))
  764. };
  765. };
  766. /**
  767. * 输入金额提示语
  768. */
  769. const setIptAmountErrorMsg = (cb) => {
  770. let amountValue = baseFormData.amountValue;
  771. let num = amountValue, scale = 1;
  772. if(amountValue.indexOf('.') > -1) {
  773. num = amountValue.toString();
  774. let obj = scaleNumber(num);
  775. num = obj.val;
  776. scale = obj.scale;
  777. }
  778. if(num < currentCurrencyInfo.value.balance * scale) {
  779. let res = calcIptValue();
  780. if (!res.flag) {
  781. iptErrMsgTxt.value = `Please reduce the 'winners' amount to ${res.count}`;
  782. } else {
  783. // if(!baseFormData.totalCount) {
  784. // iptErrMsgTxt.value = "Please enter the ‘winners' amount";
  785. // } else {
  786. iptErrMsgTxt.value = "";
  787. // }
  788. }
  789. cb && cb(res);
  790. } else if(currentCurrencyInfo.value.currencyCode != 'USD') {
  791. iptErrMsgTxt.value = `Insufficient ${currentCurrencyInfo.value.currencyName} balance, please recharge`;
  792. }
  793. };
  794. /**
  795. * 获取支付配置(paypalClientId)
  796. */
  797. const setPayConfig = () => {
  798. getPayConfig({
  799. params: {},
  800. }).then((res) => {
  801. if (res.code == 0) {
  802. payConfig.value = res.data;
  803. paypalClientId.value = res.data.paypalClientId;
  804. }
  805. });
  806. };
  807. /**
  808. * 获取配置
  809. */
  810. const setFrontConfig = () => {
  811. getFrontConfig({
  812. params: {},
  813. }).then((res) => {
  814. if (res.code == 0) {
  815. paypalHtml.value = res.data.paypalHtml;
  816. }
  817. });
  818. };
  819. const goTransactionsList = () => {
  820. window.open(`${chrome.runtime.getURL('/iframe/home.html#/transactions')}`)
  821. }
  822. onMounted(() => {
  823. setFrontConfig();
  824. setPayConfig();
  825. document.onkeydown = function (e) {
  826. var keyNum = window.event ? e.keyCode : e.which;
  827. let escKey = 27;
  828. if (keyNum == escKey) {
  829. if (visible.value) {
  830. close();
  831. }
  832. }
  833. };
  834. // document.addEventListener('click',e => {
  835. // let btn = document.querySelector('.currency-select');
  836. // let box = document.querySelector('.msg-box-overlay')
  837. // let dom = document.querySelector('.currency-pop');
  838. // if(btn && !btn.contains(e.target) || box && !box.contains(e.target)) {
  839. // if (dom && !dom.contains(e.target)) {
  840. // showCurrencyPop.value = false;
  841. // }
  842. // }
  843. // })
  844. });
  845. </script>
  846. <style lang="scss" scoped>
  847. .ql-container {
  848. height: 100px;
  849. }
  850. .overlay {
  851. position: fixed;
  852. top: 0;
  853. right: 0;
  854. bottom: 0;
  855. left: 0;
  856. z-index: 1000;
  857. height: 100%;
  858. background-color: rgba(0, 0, 0, 0.5);
  859. overflow: auto;
  860. .content {
  861. height: 620px;
  862. background: #ffffff;
  863. border-radius: 20px;
  864. position: absolute;
  865. left: 50%;
  866. top: 50%;
  867. transform: translate(-50%, -50%);
  868. box-sizing: border-box;
  869. .head {
  870. border-bottom: 1px solid #ececec;
  871. height: 48px;
  872. box-sizing: border-box;
  873. display: flex;
  874. align-items: center;
  875. justify-content: space-between;
  876. padding: 0 14px;
  877. .left {
  878. display: flex;
  879. align-items: center;
  880. .title {
  881. font-size: 16px;
  882. font-weight: 500;
  883. }
  884. .close-btn {
  885. display: flex;
  886. align-items: center;
  887. width: max-content;
  888. margin-right: 12px;
  889. cursor: pointer;
  890. }
  891. }
  892. .right {
  893. .more {
  894. cursor: pointer;
  895. }
  896. .area-option {
  897. width: 100%;
  898. height: 100%;
  899. position: absolute;
  900. top: 0;
  901. left: 0;
  902. z-index: 111;
  903. .option {
  904. position: absolute;
  905. top: 43px;
  906. right: 15px;
  907. background: #fff;
  908. filter: drop-shadow(0px 3px 20px rgba(0, 0, 0, 0.2));
  909. width: 240px;
  910. border-radius: 15px;
  911. overflow: hidden;
  912. .item {
  913. width: 100%;
  914. height: 50px;
  915. display: flex;
  916. align-items: center;
  917. cursor: pointer;
  918. border-top: 1px solid #E9E9E9;
  919. img {
  920. margin-left: 15px;
  921. width: 30px;
  922. height: 30px;
  923. margin-right: 6px;
  924. }
  925. span {
  926. font-weight: 500;
  927. font-size: 14px;
  928. }
  929. }
  930. .item:first-child {
  931. border-top: 0;
  932. }
  933. .item:hover {
  934. background: #F5F5F5;
  935. }
  936. }
  937. }
  938. }
  939. }
  940. .body {
  941. box-sizing: border-box;
  942. height: calc(100% - 48px);
  943. display: flex;
  944. position: relative;
  945. .body-content {
  946. display:flex;
  947. width:100%;
  948. }
  949. .currency-pop {
  950. position: absolute;
  951. width: 375px;
  952. height: 480px;
  953. top: 85px;
  954. left: 88px;
  955. z-index: 1000;
  956. box-shadow: 0px 4px 30px rgba(0, 0, 0, 0.3);
  957. background-color: #fff;
  958. border-radius: 20px;
  959. overflow-y: scroll;
  960. }
  961. .left,
  962. .right {
  963. height: 100%;
  964. }
  965. .left {
  966. width: 50px;
  967. display: flex;
  968. flex-direction: column;
  969. justify-content: space-between;
  970. align-items: center;
  971. .gift-pack-wrapper {
  972. width: 100%;
  973. height: 54px;
  974. background: #f5f5f5;
  975. display: flex;
  976. align-items: center;
  977. justify-content: center;
  978. }
  979. .bottom {
  980. .icon {
  981. display: block;
  982. margin-bottom: 26px;
  983. }
  984. }
  985. }
  986. .right {
  987. width: calc(100% - 50px);
  988. box-sizing: border-box;
  989. position: relative;
  990. border-left: 1px solid #ececec;
  991. .form-wrapper {
  992. padding: 0px 18px 18px 18px;
  993. height: calc(100% - 80px);
  994. overflow-y: scroll;
  995. box-sizing: border-box;
  996. .img-mode {
  997. width: 553px;
  998. margin-left: -20px;
  999. }
  1000. .form-base-help {
  1001. display: flex;
  1002. justify-content: space-between;
  1003. margin-top: 10px;
  1004. .currency-operation {
  1005. width: 217px;
  1006. height: 45px;
  1007. background: url("../../assets/svg/icon-form-bg-border.svg");
  1008. box-sizing: border-box;
  1009. padding: 14px 10px 10px 10px;
  1010. display: flex;
  1011. align-items: center;
  1012. justify-content: space-around;
  1013. .balance,
  1014. .amount {
  1015. display: flex;
  1016. align-items: center;
  1017. }
  1018. .balance {
  1019. font-weight: 400;
  1020. font-size: 13px;
  1021. img {
  1022. width: 16px;
  1023. height: 16px;
  1024. margin-right: 3px;
  1025. }
  1026. }
  1027. .amount {
  1028. font-weight: 500;
  1029. font-size: 13px;
  1030. color: #4e4e4e;
  1031. img {
  1032. margin-left: 5px;
  1033. cursor: pointer;
  1034. }
  1035. }
  1036. .top-up {
  1037. font-weight: 500;
  1038. font-size: 12px;
  1039. color: #ff9839;
  1040. cursor: pointer;
  1041. }
  1042. .icon-refresh-rotate {
  1043. transform: rotate(360deg);
  1044. transition-duration: 1s;
  1045. }
  1046. }
  1047. .msg {
  1048. font-weight: 400;
  1049. font-size: 12px;
  1050. color: #acacac;
  1051. }
  1052. }
  1053. .form-base {
  1054. display: flex;
  1055. justify-content: space-between;
  1056. align-items: center;
  1057. margin-top: 14px;
  1058. .item {
  1059. width: 250px;
  1060. height: 50px;
  1061. box-sizing: border-box;
  1062. border-radius: 12px;
  1063. display: flex;
  1064. align-items: center;
  1065. justify-content: space-between;
  1066. padding: 16px 14px;
  1067. box-shadow: 0px 3px 27px 0px #0000001a;
  1068. input {
  1069. width: 102px;
  1070. text-align: right;
  1071. font-weight: 500;
  1072. font-size: 18px;
  1073. border: none;
  1074. outline: none;
  1075. box-sizing: border-box;
  1076. }
  1077. .label {
  1078. font-weight: 500;
  1079. font-size: 15px;
  1080. display: flex;
  1081. align-items: center;
  1082. .icon {
  1083. width: 20px;
  1084. height: 20px;
  1085. margin-right: 8px;
  1086. }
  1087. }
  1088. }
  1089. .currency-select-wrapper {
  1090. padding: 0 !important;
  1091. input {
  1092. padding-right: 14px;
  1093. }
  1094. .currency-select {
  1095. box-shadow: 3px 0 10px 2px #ececec;
  1096. padding: 16px 14px;
  1097. border-bottom-left-radius: 12px;
  1098. border-top-left-radius: 12px;
  1099. cursor: pointer;
  1100. .arrow {
  1101. margin-left: 5px;
  1102. }
  1103. }
  1104. }
  1105. }
  1106. .form-label {
  1107. margin-top: 14px;
  1108. margin-bottom: 10px;
  1109. font-weight: 500;
  1110. font-size: 14px;
  1111. }
  1112. .form-require {
  1113. box-sizing: border-box;
  1114. border-radius: 15px;
  1115. margin-top: 12px;
  1116. box-shadow: 0px 3px 27px 0px #0000001a;
  1117. .form-item {
  1118. min-height: 50px;
  1119. display: flex;
  1120. align-items: center;
  1121. justify-content: space-between;
  1122. margin: 0 16px;
  1123. border-bottom: 1px solid #ececec;
  1124. .label {
  1125. min-width: 88px;
  1126. display: flex;
  1127. align-items: center;
  1128. font-size: 15px;
  1129. font-weight: 500;
  1130. .icon {
  1131. margin-right: 10px;
  1132. }
  1133. }
  1134. .control {
  1135. width: 100%;
  1136. min-height: 50px;
  1137. margin-left: 18px;
  1138. box-sizing: border-box;
  1139. }
  1140. }
  1141. }
  1142. }
  1143. .anti-bot-wrapper {
  1144. width: 100%;
  1145. height: 50px;
  1146. display: flex;
  1147. align-items: center;
  1148. justify-content: space-between;
  1149. box-sizing: border-box;
  1150. border-radius: 15px;
  1151. padding: 0 18px;
  1152. margin-top: 14px;
  1153. box-shadow: 0px 3px 27px 0px #0000001a;
  1154. .label {
  1155. display: flex;
  1156. align-items: center;
  1157. font-size: 15px;
  1158. font-weight: 500;
  1159. .icon-bot {
  1160. margin-right: 8px;
  1161. }
  1162. .icon-beta {
  1163. margin-left: 5px;
  1164. margin-right: 8px;
  1165. }
  1166. .icon-question {
  1167. cursor: pointer;
  1168. }
  1169. }
  1170. }
  1171. .tips-wrapper {
  1172. margin-top: 23px;
  1173. .title,
  1174. .row {
  1175. font-weight: 400;
  1176. font-size: 13px;
  1177. color: rgba(0, 0, 0, 0.3);
  1178. }
  1179. .row {
  1180. box-sizing: border-box;
  1181. padding-left: 4px;
  1182. }
  1183. .more {
  1184. color: #389aff;
  1185. font-size: 13px;
  1186. padding-left: 4px;
  1187. cursor: pointer;
  1188. }
  1189. }
  1190. .submit-btn-wrapper {
  1191. width: 96%;
  1192. background: #fff;
  1193. position: absolute;
  1194. bottom: 18px;
  1195. left: 0;
  1196. box-sizing: border-box;
  1197. padding-top: 16px;
  1198. .submit-btn {
  1199. width: calc(100% - 36px);
  1200. height: 46px;
  1201. text-align: center;
  1202. line-height: 46px;
  1203. background: #4a99e9;
  1204. border-radius: 100px;
  1205. color: #fff;
  1206. margin-left: 18px;
  1207. display: flex;
  1208. align-items: center;
  1209. justify-content: center;
  1210. font-size: 16px;
  1211. font-weight: 500;
  1212. cursor: pointer;
  1213. .icon-loading {
  1214. width: 20px;
  1215. height: 20px;
  1216. margin-right: 3px;
  1217. }
  1218. }
  1219. .disabled-submit {
  1220. background-color: #D9D9D9;
  1221. }
  1222. }
  1223. }
  1224. }
  1225. }
  1226. }
  1227. </style>