give-dialog.vue 49 KB

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