give-dialog.vue 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848
  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" v-if="showComType != 'preview'">
  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. :class="{'fill-right': showComType == 'preview'}">
  73. <div class="form-wrapper" v-if="showComType == 'default'">
  74. <img
  75. class="img-mode"
  76. :src="require('@/assets/svg/img-mode.svg')"
  77. />
  78. <!-- 金额、数量 -->
  79. <div class="form-base">
  80. <div class="item currency-select-wrapper">
  81. <div
  82. class="label currency-select"
  83. :class="{'selected': currentCurrencyInfo.currencyCode}"
  84. @click="selectCurrencyPopHandle"
  85. >
  86. <img v-if="currentCurrencyInfo.iconPath"
  87. class="icon"
  88. :src="currentCurrencyInfo.iconPath"
  89. />
  90. <div class="text">
  91. {{currentCurrencyInfo.currencyCode == 'USD' ? 'USD' : currentCurrencyInfo.tokenSymbol || 'Select a reward'}}
  92. </div>
  93. <img
  94. class="arrow"
  95. :src="currentCurrencyInfo.currencyCode ?
  96. require('@/assets/svg/icon-form-arrow-down.svg') : require('@/assets/svg/icon-form-white-arrow-down.svg')
  97. "
  98. />
  99. </div>
  100. <input
  101. v-model="baseFormData.amountValue"
  102. placeholder="0"
  103. autofocus
  104. @input="onAmountInput"
  105. @blur="onAmountBlur"
  106. />
  107. </div>
  108. <div class="item">
  109. <div class="label">
  110. <img
  111. class="icon"
  112. :src="
  113. require('@/assets/svg/icon-winners.svg')
  114. "
  115. />
  116. Winners
  117. </div>
  118. <input
  119. v-model="baseFormData.totalCount"
  120. placeholder="0"
  121. @input="onCountInput"
  122. @blur="onCountBlur"
  123. />
  124. </div>
  125. </div>
  126. <!-- 刷新按钮、充值 -->
  127. <div class="form-base-help" v-show="currentCurrencyInfo.currencyCode">
  128. <div class="currency-operation">
  129. <div class="balance">
  130. <img
  131. :src="
  132. require('@/assets/svg/icon-balance.svg')
  133. "
  134. />
  135. Balance
  136. </div>
  137. <div class="amount">
  138. {{currentCurrencyInfo.balance}}
  139. <img
  140. :class="{ 'icon-refresh-rotate': refreshRotate }"
  141. @click="updateCurrencyBanlce"
  142. :src="
  143. require('@/assets/svg/icon-form-refresh.svg')
  144. "
  145. />
  146. </div>
  147. <div v-if="currentCurrencyInfo.currencyCode != 'USD'" class="top-up" @click="goTopUp">Deposit</div>
  148. </div>
  149. <div class="msg">
  150. Recommend winners 100~10000
  151. </div>
  152. </div>
  153. <div class="form-label">Tasks</div>
  154. <!-- 转推、like、关注 -->
  155. <div class="form-require">
  156. <div
  157. class="form-item"
  158. v-for="(item, index) in formList"
  159. :key="index"
  160. >
  161. <div class="item-left">
  162. <div class="label">
  163. <img
  164. class="icon"
  165. :src="item.icon"
  166. />
  167. {{ item.label }}
  168. </div>
  169. <div
  170. class="control"
  171. v-if="item.nodeType == 'textarea'"
  172. >
  173. <follow-input
  174. :isAddSelf="!isBack"
  175. :atUserList="atUserList"
  176. @addUser="addFollowUser"
  177. @setUser="setFollowUser"
  178. @delUser="delFollowUser"
  179. ></follow-input>
  180. </div>
  181. <!-- join discord -->
  182. <div
  183. class="control"
  184. v-if="item.nodeType == 'input'"
  185. >
  186. <div v-if="showDiscordInvitePop"
  187. class="discord-invite-info"
  188. @click="showDiscordInvitePop = false">
  189. <img class="icon" :src="discordInviteInfo.icon || require('@/assets/svg/icon-discord-mini.svg')" />
  190. <span class="name">{{discordInviteInfo.name}}</span>
  191. </div>
  192. <input v-model="item.text"
  193. placeholder="Enter discord invite link"
  194. class="discord-address"
  195. @input="onIptDiscordAddress($event, index)"
  196. @blur="onBlurDiscordAddress($event, index)" />
  197. </div>
  198. </div>
  199. <el-switch
  200. v-if="item.type == 2 || item.type == 7"
  201. v-model="item.checked"
  202. @change="formSwitchChange($event, item, index)"
  203. />
  204. <img
  205. v-if="item.type == 3"
  206. :src="
  207. require('@/assets/svg/icon-option-checked.svg')
  208. "
  209. />
  210. </div>
  211. </div>
  212. <!-- 机器人 -->
  213. <!-- <div class="anti-bot-wrapper">
  214. <div class="label">
  215. <img
  216. :src="
  217. require('@/assets/svg/icon-anti-bot.svg')
  218. "
  219. class="icon-bot"
  220. />
  221. Anti Bot
  222. <img
  223. :src="
  224. require('@/assets/svg/icon-beta.svg')
  225. "
  226. class="icon-beta"
  227. />
  228. <img
  229. :src="
  230. require('@/assets/svg/icon-question.svg')
  231. "
  232. class="icon-question"
  233. />
  234. </div>
  235. <el-switch v-model="openAntiBot" />
  236. </div> -->
  237. <!-- 提示 -->
  238. <ul class="tips-wrapper">
  239. <li class="row">
  240. Rewards can only be claimed after the target user completes all tasks you set.
  241. </li>
  242. <li class="row">
  243. Each user can only receive a reward once per task.
  244. </li>
  245. <li class="row">
  246. 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.
  247. </li>
  248. </ul>
  249. <div class="submit-btn-wrapper">
  250. <div class="submit-btn"
  251. :class="{ 'disabled-submit': iptErrMsgTxt != '' && !depositGuide }"
  252. @click="confirm">
  253. <img class="icon-loading"
  254. v-if="submitIng"
  255. :src="require('@/assets/svg/icon-btn-loading.svg')"
  256. />
  257. {{iptErrMsgTxt ? iptErrMsgTxt : 'NEXT'}}
  258. </div>
  259. </div>
  260. </div>
  261. <!-- 预览 -->
  262. <template v-else-if="showComType == 'preview'">
  263. <preview-card
  264. :currentCurrencyInfo="currentCurrencyInfo"
  265. :postData="publishRes"
  266. :baseFormData="baseFormData"
  267. :amountFontSize="previewFontSize"
  268. ></preview-card>
  269. </template>
  270. <!-- paypal支付按钮 -->
  271. <div v-show="showComType == 'preview'">
  272. <paypal-button
  273. :finalAmountData="finalAmountData"
  274. :payConfig="{
  275. paypalClientId,
  276. feeDesc: payConfig.feeDesc,
  277. paypalHtml,
  278. amount: baseFormData.amountValue,
  279. postId
  280. }"
  281. :currentCurrencyInfo="currentCurrencyInfo"
  282. @payPalFinsh="payPalFinsh"
  283. ></paypal-button>
  284. </div>
  285. </div>
  286. </div>
  287. </div>
  288. </div>
  289. <!-- 提示 -->
  290. <message-box
  291. :dialogVisible="showMessageBox"
  292. :title="messageBoxData.title"
  293. :content="messageBoxData.content"
  294. @cancel="messageBoxCancel"
  295. @confirm="messageBoxConfirm"
  296. ></message-box>
  297. </div>
  298. </template>
  299. <script setup>
  300. import { ref, watch, reactive, defineProps, defineEmits, onMounted, nextTick } from "vue";
  301. import { postPublish, verifyPaypalResult, syncChainTokenRechargeRecord, getCurrencyInfoByCode } from "@/http/publishApi";
  302. import { getInviteGuildInfo, saveInviteGuildInfo } from "@/http/discordApi";
  303. import { payCalcFee, getPayConfig } from "@/http/pay";
  304. import { getFrontConfig } from "@/http/account";
  305. import {setChromeStorage, getChromeStorage} from "@/uilts/chromeExtension"
  306. import { debounce } from "@/uilts/help"
  307. import Report from "@/log-center/log"
  308. import { ElMessage, ElLoading } from "element-plus";
  309. import "element-plus/es/components/message/style/css";
  310. import {create, all} from "mathjs";
  311. import messageBox from "@/view/components/message-box.vue";
  312. import currencyList from "@/view/components/currency-list.vue";
  313. import previewCard from "@/view/iframe/publish/components/preview-card";
  314. import followInput from "@/view/iframe/publish/components/follow-input";
  315. import paypalButton from "@/view/iframe/publish/components/paypal-button";
  316. import topUp from "@/view/iframe/publish/components/top-up.vue";
  317. const config = {
  318. number: 'BigNumber',
  319. }
  320. const math = create(all, config);
  321. //临时货币信息
  322. let tempCurrentCurrencyInfo = ref({});
  323. let paypalClientId = ref("");
  324. let payConfig = ref({});
  325. let paypalHtml = ref("");
  326. // 发布后返回的结果
  327. let publishRes = reactive({});
  328. //弹窗是否展示
  329. let visible = ref(false);
  330. //弹窗高度
  331. let dialogHeight = ref(680);
  332. // 当前展示组件内容 default(表单) preview(预览) topUp(充值)
  333. let showComType = ref("default");
  334. let currentComData = {
  335. default: {
  336. title: "Giveaway",
  337. },
  338. preview: {
  339. title: "Preview",
  340. },
  341. topUp: {
  342. title: "Deposit",
  343. },
  344. };
  345. // 机器人开关
  346. let openAntiBot = ref(false);
  347. // 是否正在提交
  348. let submitIng = ref(false);
  349. // 艾特关注人列表
  350. let atUserList = ref([]);
  351. // 表单错误提示
  352. let iptErrMsgTxt = ref("Select a reward");
  353. // 是否返回
  354. let isBack = ref(false);
  355. // 展示消息提示
  356. let showMessageBox = ref(false);
  357. // 展示货币列表pop
  358. let showCurrencyPop = ref(false);
  359. // 展示更多按钮下的选项
  360. let showMoreOption = ref(false);
  361. // 货币列表的dom
  362. let currencyListDom = ref('');
  363. // 刷新按钮旋转
  364. let refreshRotate = ref(false);
  365. // 预览字体大小
  366. let previewFontSize = ref(56);
  367. let postId = ref('');
  368. // 余额是否同步中
  369. let asyncIng = ref(false);
  370. // 提交按钮-充值引导提示
  371. let depositGuide = ref(false);
  372. let messageBoxData = ref({
  373. title: "",
  374. content: "",
  375. });
  376. // 真实支付金额数据
  377. let finalAmountData = ref({
  378. currencyCode: '',
  379. feeAmountValue: 0,
  380. finalAmountValue: 0,
  381. requestAmountValue: 0,
  382. });
  383. // 表单数据
  384. let baseFormData = reactive({
  385. amountCurrencyCode: '',
  386. amountValue: "",
  387. totalCount: "",
  388. });
  389. // 当前选择的货币信息
  390. let currentCurrencyInfo = ref({
  391. currencyCode: "",
  392. currencyName: "",
  393. balance: "",
  394. currencyType: "",
  395. iconPath: "",
  396. minAmount: "",
  397. tokenChain: "",
  398. tokenSymbol: "",
  399. usdEstimateBalance: ""
  400. });
  401. const discordIptErrTxt = 'Discord invite link is wrong';
  402. const discordIptEmptyErrTxt = 'Enter discord invite link';
  403. const discordIptNerverExpiresErrTxt = 'Make sure the Discord link never expires'
  404. let iptErrType = ''; //discord
  405. let formList = reactive([
  406. {
  407. label: "Follow",
  408. icon: require("@/assets/svg/icon-follow.svg"),
  409. nodeType: "textarea",
  410. type: 1,
  411. text: [],
  412. checked: true,
  413. },
  414. {
  415. label: "Retweet",
  416. icon: require("@/assets/svg/icon-retweet.svg"),
  417. nodeType: "div",
  418. type: 3,
  419. checked: true,
  420. },
  421. {
  422. label: "Like Tweet",
  423. icon: require("@/assets/svg/icon-like.svg"),
  424. nodeType: "div",
  425. type: 2,
  426. checked: true,
  427. },
  428. {
  429. label: "Join Discord",
  430. icon: require("@/assets/svg/icon-discord-mini.svg"),
  431. nodeType: "input",
  432. text: '',
  433. type: 7,
  434. checked: true,
  435. },
  436. ]);
  437. const discordInviteInfo = ref({});
  438. let showDiscordInvitePop = ref(false);
  439. const props = defineProps({
  440. dialogVisible: {
  441. type: Boolean,
  442. default: false,
  443. },
  444. });
  445. watch(
  446. () => props.dialogVisible,
  447. (newVal) => {
  448. console.log("watch", newVal);
  449. visible.value = newVal;
  450. if (newVal) {
  451. Report.reportLog({
  452. pageSource: Report.pageSource.publisherDialog,
  453. businessType: Report.businessType.pageView,
  454. });
  455. getLocalCurrencyInfoByCode();
  456. setTimeout(() => {
  457. setDialogHeight();
  458. }, 300);
  459. }
  460. }
  461. );
  462. const emits = defineEmits(["close", "confirm", "payPalFinsh"]);
  463. const close = () => {
  464. if (showComType.value != "default") {
  465. showComType.value = "default";
  466. calcDomZoom();
  467. isBack.value = true;
  468. } else {
  469. initParams();
  470. emits("close", false);
  471. }
  472. };
  473. /**
  474. * 设置弹窗高度
  475. */
  476. const setDialogHeight = (resize = false) => {
  477. nextTick(() => {
  478. let clientHeight = window.innerHeight;
  479. let gapSafe = 40;
  480. console.log('resize',resize)
  481. if (dialogHeight.value > clientHeight - gapSafe) {
  482. dialogHeight.value = clientHeight - gapSafe;
  483. } else {
  484. if(resize) {
  485. dialogHeight.value = 680;
  486. }
  487. }
  488. })
  489. };
  490. const selectCurrencyPopHandle = () => {
  491. Report.reportLog({
  492. pageSource: Report.pageSource.currencySelectorPage,
  493. businessType: Report.businessType.pageView,
  494. });
  495. showCurrencyPop.value = true;
  496. nextTick(() => {
  497. if(currencyListDom.value) {
  498. currencyListDom.value.getCurrencyInfoList && currencyListDom.value.getCurrencyInfoList();
  499. }
  500. })
  501. }
  502. /**
  503. * 获取实际支付金额
  504. */
  505. const getPayAmount = async (amountValue) => {
  506. let res = await payCalcFee({
  507. params: {
  508. amountValue,
  509. currencyCode: currentCurrencyInfo.value.currencyCode,
  510. payChannel: 'paypal',
  511. },
  512. });
  513. if (res.code == 0) {
  514. let { finalAmountValue, feeDesc } = res.data;
  515. payConfig.value.feeDesc = feeDesc;
  516. if (finalAmountValue > 0) {
  517. finalAmountData.value = res.data;
  518. }
  519. }
  520. return res.data;
  521. };
  522. const saveDiscordGuildInfo = () => {
  523. let {guildId, inviteCode, inviteUrl} = discordInviteInfo.value;
  524. if(guildId && inviteCode && inviteUrl) {
  525. saveInviteGuildInfo({
  526. params: {
  527. guildId,
  528. inviteCode,
  529. inviteUrl
  530. }
  531. })
  532. }
  533. }
  534. const confirm = () => {
  535. if(depositGuide.value) { //余额不够去充值
  536. goTopUp();
  537. return;
  538. }
  539. if (submitIng.value || iptErrMsgTxt.value) {
  540. return;
  541. }
  542. let { totalCount = 0 } = baseFormData;
  543. if (!totalCount) {
  544. return;
  545. }
  546. saveDiscordGuildInfo();
  547. submitRequest();
  548. };
  549. /**
  550. * 货币列表-选中货币
  551. */
  552. const selectCurrency = (params) => {
  553. tempCurrentCurrencyInfo.value = params;
  554. depositGuide.value = false;
  555. if(params.currencyCode != "USD" && params.balance < params.minAmount) {
  556. let tokenSymbol = params.currencyCode == 'USD' ? 'USD' : params.tokenSymbol;
  557. messageBoxBlock({
  558. title: `Whether to deposit ${tokenSymbol}`,
  559. content: `Insufficient ${tokenSymbol} balance`,
  560. });
  561. } else {
  562. currentCurrencyInfo.value = params;
  563. setLocalSelectCurrencyInfo(currentCurrencyInfo.value);
  564. showCurrencyPop.value = false;
  565. finalAmountData.value.currencyCode = currentCurrencyInfo.value.currencyCode;
  566. calcDomZoom();
  567. resetFormIpt();
  568. onIptSetErrorTxt();
  569. }
  570. };
  571. const calcDomZoom = () => {
  572. nextTick(() => {
  573. let maxWidth = 68;
  574. var textWidth = document.querySelector('.text').offsetWidth;
  575. if(textWidth > 68) {
  576. var scale = maxWidth / textWidth;
  577. document.querySelector('.text').style.zoom = scale;
  578. }
  579. })
  580. }
  581. const resetFormIpt = () => {
  582. baseFormData.amountValue = "";
  583. baseFormData.totalCount = "";
  584. }
  585. const setLocalSelectCurrencyInfo = (params = {}) => {
  586. setChromeStorage({ selectCurrencyInfo : JSON.stringify(params)})
  587. }
  588. /**
  589. * 获取完货币列表
  590. */
  591. const setCurrentCurrencyInfo = (params) => {
  592. }
  593. const messageBoxBlock = ({ title = "", content = "" }) => {
  594. showMessageBox.value = true;
  595. messageBoxData.value.title = title;
  596. messageBoxData.value.content = content;
  597. };
  598. /**
  599. * 确定
  600. */
  601. const messageBoxConfirm = () => {
  602. showMessageBox.value = false;
  603. goTopUp();
  604. };
  605. /**
  606. * 取消
  607. */
  608. const messageBoxCancel = () => {
  609. currentCurrencyInfo.value = tempCurrentCurrencyInfo.value;
  610. setLocalSelectCurrencyInfo(currentCurrencyInfo.value);
  611. showMessageBox.value = false;
  612. showCurrencyPop.value = false;
  613. calcDomZoom();
  614. resetFormIpt();
  615. onIptSetErrorTxt();
  616. };
  617. /**
  618. * 去充值
  619. */
  620. const goTopUp = () => {
  621. Report.reportLog({
  622. pageSource: Report.pageSource.rechargePage,
  623. businessType: Report.businessType.pageView,
  624. });
  625. showComType.value = 'topUp';
  626. }
  627. /**
  628. * 充值done事件
  629. */
  630. const topUpDone = () => {
  631. currentCurrencyInfo.value = tempCurrentCurrencyInfo.value;
  632. asyncIng.value = true;
  633. depositGuide.value = false;
  634. asyncIng.value = false;
  635. showCurrencyPop.value = false;
  636. showComType.value = 'default';
  637. calcDomZoom();
  638. onIptSetErrorTxt()
  639. asyncTokenRechRecord((res) => {
  640. if(res.code == 0 && res.data && res.data.length) {
  641. let currencyInfo = res.data[0];
  642. if(currencyInfo.currencyCode == currentCurrencyInfo.value.currencyCode) {
  643. currentCurrencyInfo.value.balance = currencyInfo.balance;
  644. onIptSetErrorTxt()
  645. }
  646. }
  647. })
  648. }
  649. /**
  650. * 更新货币余额
  651. */
  652. const updateCurrencyBanlce = () => {
  653. if(!refreshRotate.value) {
  654. refreshRotate.value = true;
  655. setTimeout(() => {
  656. refreshRotate.value = false;
  657. }, 1000)
  658. }
  659. asyncTokenRechRecord((res) => {
  660. if(res.code == 0 && res.data && res.data.length) {
  661. let currencyInfo = res.data[0];
  662. if(currencyInfo.currencyCode == currentCurrencyInfo.value.currencyCode) {
  663. currentCurrencyInfo.value.balance = currencyInfo.balance;
  664. }
  665. }
  666. })
  667. }
  668. /**
  669. * 同步链上交易
  670. */
  671. const asyncTokenRechRecord = (cb) => {
  672. syncChainTokenRechargeRecord({
  673. params: {
  674. currencyCode: currentCurrencyInfo.value.currencyCode
  675. }
  676. }).then(res => {
  677. cb && cb(res)
  678. })
  679. }
  680. /**
  681. * 提交表单请求
  682. */
  683. const submitRequest = async () => {
  684. let { amountValue = 0, totalCount = 0 } = baseFormData;
  685. baseFormData.amountCurrencyCode = currentCurrencyInfo.value.currencyCode;
  686. // 组装提交参数
  687. formList[0]["text"] = atUserList.value;
  688. let finishConditions = [];
  689. for (let i = 0; i < formList.length; i++) {
  690. let item = {};
  691. item.type = formList[i]["type"];
  692. if (item.type == 1 && formList[i]["text"]) {
  693. // follow 参数
  694. let relatedUsers = formList[i]["text"];
  695. item.relatedUsers = relatedUsers;
  696. finishConditions.push(item);
  697. } else if (formList[i]["type"] == 7) {
  698. // join discord
  699. if(formList[i]["checked"] && formList[i]["text"]) {
  700. item.bizData = JSON.stringify({inviteUrl: formList[i]["text"]});
  701. finishConditions.push(item);
  702. }
  703. } else if (formList[i]["checked"]) {
  704. finishConditions.push(item);
  705. }
  706. }
  707. let receiveConditions = openAntiBot.value ? "" : [];
  708. // 提交参数
  709. let formData = {
  710. amountCurrencyCode: baseFormData.amountCurrencyCode,
  711. amountValue,
  712. totalCount,
  713. finishConditions,
  714. receiveConditions,
  715. payAmountValue: amountValue
  716. };
  717. submitIng.value = true;
  718. // 法币支付需要计算费率
  719. if(formData.amountCurrencyCode == "USD") {
  720. let payAmountRes = await getPayAmount(amountValue);
  721. formData["payAmountValue"] = payAmountRes.finalAmountValue;
  722. }
  723. let data = {
  724. params: {
  725. postBizData: JSON.stringify(formData),
  726. postSrc: 1, //1 twitter
  727. postType: 1, //1 红包
  728. },
  729. };
  730. postPublish(data).then((res) => {
  731. submitIng.value = false;
  732. if (res.code == 0) {
  733. publishRes = res.data;
  734. postId.value = res.data.postId;
  735. Report.reportLog({
  736. pageSource: Report.pageSource.previewPage,
  737. businessType: Report.businessType.pageView,
  738. });
  739. showComType.value = "preview";
  740. previewFontSize.value = calcFontSize(baseFormData.amountValue, 238, 56);
  741. isBack.value = false;
  742. } else {
  743. console.log(res);
  744. }
  745. })
  746. .catch((err) => {
  747. console.log(err);
  748. });
  749. };
  750. const calcFontSize = (str, domWidth, maxSize) => {
  751. let lenstr = str.length;
  752. let num = parseInt(domWidth / lenstr);
  753. let fontSize = num < maxSize ? num : maxSize
  754. return fontSize;
  755. }
  756. /**
  757. * 初始化提交参数
  758. */
  759. const initParams = () => {
  760. resetFormIpt();
  761. // clear follow value
  762. formList[0].text = [];
  763. atUserList.value = [];
  764. submitIng.value = false;
  765. isBack.value = false;
  766. showCurrencyPop.value = false;
  767. openAntiBot.value = false;
  768. tempCurrentCurrencyInfo.value = {};
  769. currentCurrencyInfo.value = {};
  770. // clear discord value
  771. formList[3].text = '';
  772. discordInviteInfo.value = {};
  773. };
  774. /**
  775. * 支付完成回调
  776. */
  777. const payPalFinsh = (params) => {
  778. let {payNetwork, payStatus} = params;
  779. // token 支付
  780. if(payNetwork == 'bsc') {
  781. payStatusHandle(payStatus);
  782. } else {
  783. // 法币支付
  784. let transaction = params.transaction;
  785. let loadingInstance = ElLoading.service({
  786. background: "rgba(0,0,0,.3)",
  787. });
  788. verifyPaypalResult({
  789. params: {
  790. paypalTransactionId: transaction.id,
  791. postId: publishRes.postId,
  792. paypalClientId: paypalClientId.value,
  793. },
  794. }).then((res) => {
  795. loadingInstance.close();
  796. if (res.code == 0) {
  797. if (res.data) {
  798. payStatusHandle(res.data.payStatus)
  799. }
  800. }
  801. })
  802. .catch(() => {
  803. loadingInstance.close();
  804. });
  805. }
  806. };
  807. const payStatusHandle = (payStatus) => {
  808. //支付状态 0:未支付,1:支付成功,2:支付失败,3:已关闭,4:已退款
  809. switch (payStatus) {
  810. case 1:
  811. emits("payPalFinsh", { publishRes });
  812. showComType.value = "default";
  813. initParams();
  814. break;
  815. case 2:
  816. // ElMessage({
  817. // message: "Pay Fail",
  818. // type: "warning",
  819. // });
  820. break;
  821. case 3:
  822. // ElMessage({
  823. // message: "Pay Exceptions",
  824. // type: "warning",
  825. // });
  826. break;
  827. case 4:
  828. // ElMessage({
  829. // message: "Pay Exceptions",
  830. // type: "warning",
  831. // });
  832. break;
  833. }
  834. }
  835. /**
  836. * follow组件触发新增关注人
  837. */
  838. const addFollowUser = (params) => {
  839. atUserList.value.push(params);
  840. };
  841. const setFollowUser = (params) => {
  842. atUserList.value[params.index]["name"] = params.name;
  843. };
  844. const delFollowUser = (params) => {
  845. atUserList.value.splice(params.index, 1);
  846. };
  847. const onAmountInput = () => {
  848. let val = baseFormData.amountValue;
  849. // val = val.replace(/[^\d^\.]+/g, "");
  850. val = val.replace(/^\D*(\d*(?:\.\d{0,18})?).*$/g, '$1');
  851. if(val == '00') {
  852. val = '0'
  853. }
  854. if(val.indexOf('.') > -1){ //校验 例:00.12 => 0.12
  855. let arr = val.split('.');
  856. if(arr[0].startsWith('0')) {
  857. let num = +arr[0];
  858. val = num + '.' + arr[1];
  859. }
  860. }
  861. baseFormData.amountValue = val;
  862. setInputErrorMsg({from: 'amount', type:'input'});
  863. return val;
  864. };
  865. const onCountInput = () => {
  866. let val = baseFormData.totalCount;
  867. if (val == 0) {
  868. val = "";
  869. }
  870. // val = val.replace(/[^\d]/g, "");
  871. val = val.replace(/^\D*(\d*(?:\.\d{0,18})?).*$/g, '$1');
  872. baseFormData.totalCount = val;
  873. setInputErrorMsg({from: 'count', type:'input'});
  874. return val;
  875. };
  876. /**
  877. * 金额输入失焦
  878. */
  879. const onAmountBlur = () => {
  880. setInputErrorMsg({from: 'amount', type:'blur'});
  881. };
  882. /**
  883. * count失焦,校验输入结果
  884. */
  885. const onCountBlur = () => {
  886. setInputErrorMsg({from: 'count', type:'blur'});
  887. };
  888. /**
  889. * 输入结果金额和数量 (金额/数量)是否小于最小货币单位
  890. */
  891. const calcIptValue = (cb) => {
  892. let amountValue = baseFormData.amountValue;
  893. let totalCount = baseFormData.totalCount;
  894. let flag = true;
  895. if (!amountValue || !totalCount) {
  896. return {
  897. flag
  898. };
  899. }
  900. if (math.format(math.evaluate(`${baseFormData.amountValue} / ${baseFormData.totalCount}`)) < +currentCurrencyInfo.value.minAmount) {
  901. flag = false;
  902. }
  903. return {
  904. flag,
  905. count: Math.floor(math.format(math.evaluate(`${baseFormData.amountValue} / ${currentCurrencyInfo.value.minAmount}`)))
  906. }
  907. };
  908. /**
  909. * 设置输入提示语
  910. */
  911. const setInputErrorMsg = () => {
  912. onIptSetErrorTxt();
  913. };
  914. /**
  915. * 输入时 检测设置错误信息
  916. */
  917. const onIptSetErrorTxt = (params = {}) => {
  918. depositGuide.value = false;
  919. if(!currentCurrencyInfo.value.currencyCode) {
  920. iptErrMsgTxt.value = "Select a reward"
  921. } else if (!baseFormData.amountValue || baseFormData.amountValue == '0') {
  922. iptErrMsgTxt.value = "Enter an amount";
  923. } else if (!baseFormData.totalCount || baseFormData.totalCount == '0') {
  924. iptErrMsgTxt.value = "Enter the number of winners";
  925. } else if(+baseFormData.amountValue <= +currentCurrencyInfo.value.balance) {
  926. let res = calcIptValue();
  927. if (!res.flag) {
  928. iptErrMsgTxt.value = `${baseFormData.amountValue} ${currentCurrencyInfo.value.tokenSymbol} Can send up to ${res.count} winners`;
  929. } else {
  930. iptErrMsgTxt.value = "";
  931. if(params.actionType != 'discord_blur') {
  932. setDiscordErrTxt({getDuildId: true});
  933. }
  934. }
  935. } else if(currentCurrencyInfo.value.currencyCode != 'USD') {
  936. depositGuide.value = true;
  937. iptErrMsgTxt.value = `Insufficient ${currentCurrencyInfo.value.tokenSymbol} balance, please deposit`;
  938. }
  939. }
  940. /**
  941. * 监听开关触发事件
  942. */
  943. const formSwitchChange = (val, params, index) => {
  944. console.log('formSwitchChange')
  945. if(!val) {
  946. if(params.type == 7) {
  947. //错误类型 discord 清空discord错误校验
  948. if(iptErrType == 'discord') {
  949. iptErrMsgTxt.value = '';
  950. formList[index]['text'] = '';
  951. onIptSetErrorTxt();
  952. }
  953. }
  954. } else {
  955. onIptSetErrorTxt();
  956. }
  957. }
  958. /** 监听 discord 输入 */
  959. const onIptDiscordAddress = (e, index) => {
  960. let val = formList[index].text;
  961. let checked = formList[index].checked;
  962. if(val && !checked) {
  963. checked = true;
  964. formList[index].checked = checked;
  965. formList[index].text = formList[index].text.replace(/\s/g,'');
  966. }
  967. onIptDiscordDebounce()
  968. }
  969. const onBlurDiscordAddress = (e, index) => {
  970. setDiscordErrTxt({fromType: 'discord', showPop: false, actionType: 'discord_blur'});
  971. }
  972. const getDiscordIptData = () => {
  973. let discordItem = formList.find(item => item.type == 7);
  974. return discordItem;
  975. }
  976. /**
  977. * 设置输入discord错误提示信息
  978. */
  979. const setDiscordErrTxt = (params = {showPop: false}) => {
  980. let discordData = getDiscordIptData() || {};
  981. if(discordData.checked) {
  982. if(discordData.text) {
  983. let validata = checkInviteUrl(discordData.text);
  984. if(validata) {
  985. getDiscordInviteInfo({inviteUrl: discordData.text, getDuildId: params.getDuildId}, (res) => {
  986. console.log('discordData',res)
  987. // 未知的邀请链接
  988. if(res.inviteCode != res.data.code || !res.data.guildId) {
  989. iptErrMsgTxt.value = discordIptErrTxt;
  990. iptErrType = 'discord';
  991. } else {
  992. if(res.data.expires !== null) {
  993. // 不是永久邀请链接
  994. iptErrMsgTxt.value = discordIptNerverExpiresErrTxt;
  995. iptErrType = '';
  996. } else {
  997. if(iptErrMsgTxt.value) {
  998. iptErrMsgTxt.value = '';
  999. iptErrType = '';
  1000. }
  1001. if(params.showPop && res.data) {
  1002. showDiscordInvitePop.value = true;
  1003. setTimeout(() => {
  1004. showDiscordInvitePop.value = false;
  1005. }, 2000)
  1006. }
  1007. if(params.fromType == 'discord') {
  1008. onIptSetErrorTxt();
  1009. }
  1010. }
  1011. }
  1012. })
  1013. } else {
  1014. iptErrMsgTxt.value = discordIptErrTxt;
  1015. iptErrType = 'discord';
  1016. }
  1017. } else {
  1018. if(params.actionType == 'discord_blur') {
  1019. onIptSetErrorTxt({acitonType: 'discord_blur'});
  1020. } else {
  1021. // 设置空提示
  1022. iptErrMsgTxt.value = discordIptEmptyErrTxt;
  1023. iptErrType = 'discord';
  1024. }
  1025. }
  1026. }
  1027. }
  1028. const onIptDiscordDebounce = debounce(function() {
  1029. setDiscordErrTxt({fromType: 'discord', showPop: true});
  1030. }, 800)
  1031. /**
  1032. * 校验 discord邀请url
  1033. */
  1034. const checkInviteUrl = (inviteUrl) => {
  1035. let flag = false;
  1036. const INVITE_URL_PREFIX_1 = 'https://discord.gg/';
  1037. const INVITE_URL_PREFIX_2 = 'https://discord.com/invite/';
  1038. const INVITE_URL_PREFIX_3 = 'http://discord.gg/';
  1039. const INVITE_URL_PREFIX_4 = 'http://discord.com/invite/';
  1040. const INVITE_URL_PREFIX_5 = 'discord.gg/';
  1041. const INVITE_URL_PREFIX_6 = 'discord.com/invite/';
  1042. const arr = [INVITE_URL_PREFIX_1, INVITE_URL_PREFIX_2, INVITE_URL_PREFIX_3, INVITE_URL_PREFIX_4, INVITE_URL_PREFIX_5, INVITE_URL_PREFIX_6]
  1043. if(inviteUrl) {
  1044. if(arr.indexOf(inviteUrl) > -1) {
  1045. flag = false;
  1046. } else {
  1047. let isPass = false;
  1048. for(let i = 0; i < arr.length; i++) {
  1049. let item = arr[i];
  1050. if(inviteUrl.startsWith(item)) {
  1051. isPass = true;
  1052. break;
  1053. }
  1054. }
  1055. flag = isPass;
  1056. }
  1057. }
  1058. return flag;
  1059. }
  1060. /**获取discord 邀请信息 */
  1061. const getDiscordInviteInfo = ({inviteUrl, getDuildId}, cb) => {
  1062. if(!inviteUrl) return;
  1063. let inviteCode = '';
  1064. let arr = inviteUrl.split('/');
  1065. if(arr.length > 0) {
  1066. inviteCode = arr[arr.length - 1];
  1067. }
  1068. if(!getDuildId && discordInviteInfo.value.guildId && discordInviteInfo.value.inviteCode == inviteCode) {
  1069. return;
  1070. }
  1071. getInviteGuildInfo({
  1072. inviteCode
  1073. }).then(res => {
  1074. if(!res) {
  1075. res = {};
  1076. }
  1077. let {name, icon, id} = res.guild || {};
  1078. icon = icon && id ? `https://cdn.discordapp.com/icons/${id}/${icon}.png` : '';
  1079. let resData = {
  1080. inviteCode,
  1081. data: {
  1082. code: res.code,
  1083. guildId: id,
  1084. inviteUrl,
  1085. inviteCode,
  1086. expires: res.expires_at,
  1087. name,
  1088. icon,
  1089. }
  1090. }
  1091. discordInviteInfo.value = resData.data;
  1092. cb && cb(resData);
  1093. }).catch((err) => {
  1094. if(iptErrMsgTxt.value && iptErrType == 'discord') {
  1095. iptErrMsgTxt.value = '';
  1096. iptErrType = '';
  1097. }
  1098. });
  1099. }
  1100. /**
  1101. * 获取支付配置(paypalClientId)
  1102. */
  1103. const setPayConfig = () => {
  1104. getPayConfig({
  1105. params: {},
  1106. }).then((res) => {
  1107. if (res.code == 0) {
  1108. payConfig.value = res.data;
  1109. paypalClientId.value = res.data.paypalClientId;
  1110. }
  1111. });
  1112. };
  1113. /**
  1114. * 获取配置
  1115. */
  1116. const setFrontConfig = () => {
  1117. getFrontConfig({
  1118. params: {},
  1119. }).then((res) => {
  1120. if (res.code == 0) {
  1121. paypalHtml.value = res.data.paypalHtml;
  1122. }
  1123. });
  1124. };
  1125. const goTransactionsList = () => {
  1126. window.open(`${chrome.runtime.getURL('/iframe/home.html#/transactions')}`)
  1127. }
  1128. /**
  1129. * 默认获取上次选中的货币信息
  1130. */
  1131. const getLocalCurrencyInfoByCode = () => {
  1132. if(!currentCurrencyInfo.value.currencyCode) {
  1133. getChromeStorage('selectCurrencyInfo', (res) => {
  1134. if(res && res.currencyCode) {
  1135. getCurrencyInfoByCode({
  1136. params: {
  1137. currencyCode: res.currencyCode
  1138. }
  1139. }).then(res => {
  1140. if(res.code == 0 && res.data) {
  1141. currentCurrencyInfo.value = res.data;
  1142. tempCurrentCurrencyInfo.value = res.data;
  1143. onIptSetErrorTxt();
  1144. }
  1145. });
  1146. }
  1147. })
  1148. }
  1149. }
  1150. onMounted(() => {
  1151. setFrontConfig();
  1152. setPayConfig();
  1153. getLocalCurrencyInfoByCode();
  1154. document.onkeydown = function (e) {
  1155. var keyNum = window.event ? e.keyCode : e.which;
  1156. let escKey = 27;
  1157. if (keyNum == escKey) {
  1158. if (visible.value) {
  1159. // close();
  1160. }
  1161. }
  1162. };
  1163. window.addEventListener('resize', function () {
  1164. setDialogHeight(true);
  1165. })
  1166. });
  1167. </script>
  1168. <style lang="scss" scoped>
  1169. .overlay {
  1170. position: fixed;
  1171. top: 0;
  1172. right: 0;
  1173. bottom: 0;
  1174. left: 0;
  1175. z-index: 2000;
  1176. height: 100%;
  1177. background-color: rgba(0, 0, 0, 0.5);
  1178. overflow: auto;
  1179. .content {
  1180. height: 620px;
  1181. background: #ffffff;
  1182. border-radius: 20px;
  1183. position: absolute;
  1184. left: 50%;
  1185. top: 50%;
  1186. transform: translate(-50%, -50%);
  1187. box-sizing: border-box;
  1188. z-index: 2000;
  1189. .pop-mask {
  1190. width: 100%;
  1191. height:100%;
  1192. position: absolute;
  1193. z-index:900;
  1194. }
  1195. .head {
  1196. border-bottom: 1px solid #ececec;
  1197. height: 48px;
  1198. box-sizing: border-box;
  1199. display: flex;
  1200. align-items: center;
  1201. justify-content: space-between;
  1202. padding: 0 14px;
  1203. .left {
  1204. display: flex;
  1205. align-items: center;
  1206. .title {
  1207. font-size: 16px;
  1208. font-weight: 500;
  1209. }
  1210. .close-btn {
  1211. display: flex;
  1212. align-items: center;
  1213. width: max-content;
  1214. margin-right: 12px;
  1215. cursor: pointer;
  1216. }
  1217. }
  1218. .right {
  1219. .more {
  1220. cursor: pointer;
  1221. }
  1222. .area-option {
  1223. width: 100%;
  1224. height: 100%;
  1225. position: absolute;
  1226. top: 0;
  1227. left: 0;
  1228. z-index: 111;
  1229. .option {
  1230. position: absolute;
  1231. top: 43px;
  1232. right: 15px;
  1233. background: #fff;
  1234. filter: drop-shadow(0px 3px 20px rgba(0, 0, 0, 0.2));
  1235. width: 240px;
  1236. border-radius: 15px;
  1237. overflow: hidden;
  1238. .item {
  1239. width: 100%;
  1240. height: 50px;
  1241. display: flex;
  1242. align-items: center;
  1243. cursor: pointer;
  1244. border-top: 1px solid #E9E9E9;
  1245. img {
  1246. margin-left: 15px;
  1247. width: 30px;
  1248. height: 30px;
  1249. margin-right: 6px;
  1250. }
  1251. span {
  1252. font-weight: 500;
  1253. font-size: 14px;
  1254. }
  1255. }
  1256. .item:first-child {
  1257. border-top: 0;
  1258. }
  1259. .item:hover {
  1260. background: #F5F5F5;
  1261. }
  1262. }
  1263. }
  1264. }
  1265. }
  1266. .body {
  1267. box-sizing: border-box;
  1268. height: calc(100% - 48px);
  1269. display: flex;
  1270. position: relative;
  1271. .icon-guide-select {
  1272. width: 40px;
  1273. position: absolute;
  1274. top: 78px;
  1275. left: 25px;
  1276. z-index: 1000;
  1277. }
  1278. .body-content {
  1279. display:flex;
  1280. width:100%;
  1281. }
  1282. .currency-pop {
  1283. position: absolute;
  1284. width: 375px;
  1285. height: 480px;
  1286. top: 85px;
  1287. left: 88px;
  1288. z-index: 1000;
  1289. box-shadow: 0px 4px 30px rgba(0, 0, 0, 0.3);
  1290. background-color: #fff;
  1291. border-radius: 20px;
  1292. overflow-y: scroll;
  1293. }
  1294. .left,
  1295. .right {
  1296. height: 100%;
  1297. }
  1298. .left {
  1299. width: 50px;
  1300. display: flex;
  1301. flex-direction: column;
  1302. justify-content: space-between;
  1303. align-items: center;
  1304. .gift-pack-wrapper {
  1305. width: 100%;
  1306. height: 55px;
  1307. background: #f5f5f5;
  1308. display: flex;
  1309. align-items: center;
  1310. justify-content: center;
  1311. }
  1312. .bottom {
  1313. .icon {
  1314. display: block;
  1315. margin-bottom: 26px;
  1316. }
  1317. }
  1318. }
  1319. .right {
  1320. width: calc(100% - 50px);
  1321. box-sizing: border-box;
  1322. position: relative;
  1323. border-left: 1px solid #ececec;
  1324. .form-wrapper {
  1325. padding: 0px 18px 18px 18px;
  1326. height: calc(100% - 80px);
  1327. overflow-y: scroll;
  1328. overflow-x: hidden;
  1329. box-sizing: border-box;
  1330. .img-mode {
  1331. margin-left: -18px;
  1332. }
  1333. .form-base-help {
  1334. display: flex;
  1335. justify-content: space-between;
  1336. margin-top: 10px;
  1337. .currency-operation:before{
  1338. box-sizing: content-box;
  1339. width: 0px;
  1340. height: 0px;
  1341. position: absolute;
  1342. top: -16px;;
  1343. left:46px;
  1344. padding:0;
  1345. border-bottom:8px solid #FFFFFF;
  1346. border-top:8px solid transparent;
  1347. border-left:8px solid transparent;
  1348. border-right:8px solid transparent;
  1349. display: block;
  1350. content:'';
  1351. z-index: 12;
  1352. }
  1353. .currency-operation:after{
  1354. box-sizing: content-box;
  1355. width: 0px;
  1356. height: 0px;
  1357. position: absolute;
  1358. top: -18px;;
  1359. left:45px;
  1360. padding:0;
  1361. border-bottom:9px solid #EAEAEA;
  1362. border-top:9px solid transparent;
  1363. border-left:9px solid transparent;
  1364. border-right:9px solid transparent;
  1365. display: block;
  1366. content:'';
  1367. z-index:10
  1368. }
  1369. .currency-operation {
  1370. position: relative;
  1371. height: 36px;
  1372. border: 1px solid #EAEAEA;
  1373. box-sizing: border-box;
  1374. padding: 10px;
  1375. display: flex;
  1376. align-items: center;
  1377. border-radius: 100px;
  1378. .balance,
  1379. .amount {
  1380. display: flex;
  1381. align-items: center;
  1382. }
  1383. .balance {
  1384. font-weight: 400;
  1385. font-size: 13px;
  1386. img {
  1387. width: 16px;
  1388. height: 16px;
  1389. margin-right: 3px;
  1390. }
  1391. }
  1392. .amount {
  1393. font-weight: 500;
  1394. font-size: 13px;
  1395. color: #4e4e4e;
  1396. margin-left: 5px;
  1397. img {
  1398. margin-left: 5px;
  1399. cursor: pointer;
  1400. }
  1401. }
  1402. .top-up {
  1403. font-weight: 500;
  1404. font-size: 12px;
  1405. color: #ff9839;
  1406. cursor: pointer;
  1407. margin-left: 8px;
  1408. }
  1409. .icon-refresh-rotate {
  1410. transform: rotate(360deg);
  1411. transition-duration: 1s;
  1412. }
  1413. }
  1414. .msg {
  1415. font-weight: 400;
  1416. font-size: 12px;
  1417. color: #acacac;
  1418. }
  1419. }
  1420. .form-base {
  1421. display: flex;
  1422. justify-content: space-between;
  1423. align-items: center;
  1424. margin-top: 14px;
  1425. .item {
  1426. width: 250px;
  1427. height: 50px;
  1428. box-sizing: border-box;
  1429. border-radius: 14px;
  1430. border: 1px solid #D1D9DD;
  1431. display: flex;
  1432. align-items: center;
  1433. justify-content: space-between;
  1434. padding: 16px 14px;
  1435. input {
  1436. width: 102px;
  1437. text-align: right;
  1438. font-weight: 500;
  1439. font-size: 18px;
  1440. border: none;
  1441. outline: none;
  1442. box-sizing: border-box;
  1443. }
  1444. input::placeholder {
  1445. color: #c5c5c5;
  1446. }
  1447. .label {
  1448. font-weight: 500;
  1449. font-size: 15px;
  1450. display: flex;
  1451. align-items: center;
  1452. .icon {
  1453. width: 20px;
  1454. height: 20px;
  1455. margin-right: 8px;
  1456. }
  1457. }
  1458. }
  1459. .item:first-child {
  1460. margin-right: 14px
  1461. }
  1462. .currency-select-wrapper {
  1463. padding: 0 !important;
  1464. input {
  1465. padding-right: 14px;
  1466. }
  1467. .currency-select {
  1468. max-width: 136px;
  1469. cursor: pointer;
  1470. background: #1D9BF0;
  1471. margin-left: 6px;
  1472. padding: 6px 10px;
  1473. border-radius: 12px;
  1474. color: #fff;
  1475. .text {
  1476. white-space: nowrap;
  1477. zoom: 0.85;
  1478. }
  1479. .arrow {
  1480. margin-left: 5px;
  1481. }
  1482. }
  1483. .selected {
  1484. background: #F4F4F4 !important;
  1485. color: #000 !important;
  1486. }
  1487. }
  1488. }
  1489. .form-label {
  1490. margin-top: 14px;
  1491. margin-bottom: 10px;
  1492. font-weight: 500;
  1493. font-size: 14px;
  1494. }
  1495. .form-require {
  1496. box-sizing: border-box;
  1497. border-radius: 15px;
  1498. margin-top: 12px;
  1499. border: 1px solid #D1D9DD;
  1500. .form-item {
  1501. min-height: 50px;
  1502. display: flex;
  1503. align-items: center;
  1504. justify-content: space-between;
  1505. margin: 0 16px;
  1506. border-bottom: 1px solid #ececec;
  1507. padding: 8px 0;
  1508. box-sizing: border-box;
  1509. .item-left {
  1510. display: flex;
  1511. }
  1512. .label {
  1513. min-width: 76px;
  1514. display: flex;
  1515. align-items: center;
  1516. font-size: 15px;
  1517. font-weight: 500;
  1518. .icon {
  1519. margin-right: 10px;
  1520. }
  1521. }
  1522. .control {
  1523. min-width: 280px;
  1524. margin-left: 18px;
  1525. box-sizing: border-box;
  1526. border-left: 1px solid #ECECEC;
  1527. position: relative;
  1528. .discord-address {
  1529. border: none;
  1530. outline: none;
  1531. color: #1D9BF0;
  1532. font-weight: 500;
  1533. font-size: 14px;
  1534. width: 100%;
  1535. height: 34px;
  1536. padding-left: 15px;
  1537. }
  1538. .discord-address::placeholder {
  1539. color: #c5c5c5;
  1540. }
  1541. .discord-invite-info {
  1542. position: absolute;
  1543. top: 40px;
  1544. left: 0;
  1545. box-shadow: 0px 4px 30px rgba(0, 0, 0, 0.3);
  1546. background: #fff;
  1547. border-radius: 16px;
  1548. padding: 16px;
  1549. box-sizing: border-box;
  1550. display: flex;
  1551. align-items: center;
  1552. cursor: pointer;
  1553. .icon {
  1554. width: 40px;
  1555. height: 40px;
  1556. margin-right: 10px;
  1557. border-radius: 50%;
  1558. }
  1559. .name {
  1560. font-weight: 600;
  1561. font-size: 16px;
  1562. color: #101419;
  1563. width: 193px;
  1564. height: 20px;
  1565. overflow: hidden;
  1566. white-space: nowrap;
  1567. text-overflow: ellipsis;
  1568. display: inline-block;
  1569. }
  1570. }
  1571. }
  1572. }
  1573. .form-item:last-child {
  1574. border-bottom: none !important;
  1575. }
  1576. }
  1577. }
  1578. .anti-bot-wrapper {
  1579. width: 100%;
  1580. height: 50px;
  1581. display: flex;
  1582. align-items: center;
  1583. justify-content: space-between;
  1584. box-sizing: border-box;
  1585. border-radius: 15px;
  1586. padding: 0 18px;
  1587. margin-top: 14px;
  1588. border: 1px solid #D1D9DD;
  1589. .label {
  1590. display: flex;
  1591. align-items: center;
  1592. font-size: 15px;
  1593. font-weight: 500;
  1594. .icon-bot {
  1595. margin-right: 8px;
  1596. }
  1597. .icon-beta {
  1598. margin-left: 5px;
  1599. margin-right: 8px;
  1600. }
  1601. .icon-question {
  1602. cursor: pointer;
  1603. }
  1604. }
  1605. }
  1606. .tips-wrapper {
  1607. margin: 16px 0 0 12px !important;
  1608. padding: 0px !important;
  1609. .title,
  1610. .row {
  1611. font-weight: 400;
  1612. font-size: 12px;
  1613. color: #A39F9F;
  1614. }
  1615. .row {
  1616. box-sizing: border-box;
  1617. line-height: 16px;
  1618. }
  1619. .more {
  1620. color: #1D9BF0;
  1621. font-size: 13px;
  1622. padding-left: 4px;
  1623. cursor: pointer;
  1624. }
  1625. }
  1626. .submit-btn-wrapper {
  1627. width: 100%;
  1628. background: #fff;
  1629. position: absolute;
  1630. bottom: 18px;
  1631. left: 0;
  1632. box-sizing: border-box;
  1633. padding: 16px 18px 0 18px;
  1634. .submit-btn {
  1635. width: 100%;
  1636. height: 46px;
  1637. text-align: center;
  1638. background: #4a99e9;
  1639. border-radius: 100px;
  1640. color: #fff;
  1641. display: flex;
  1642. align-items: center;
  1643. justify-content: center;
  1644. font-size: 16px;
  1645. font-weight: 500;
  1646. cursor: pointer;
  1647. .icon-loading {
  1648. width: 20px;
  1649. height: 20px;
  1650. margin-right: 3px;
  1651. }
  1652. }
  1653. .disabled-submit {
  1654. background-color: #D9D9D9;
  1655. }
  1656. }
  1657. }
  1658. .fill-right {
  1659. width: 100% !important;
  1660. border-bottom-left-radius: 16px;
  1661. }
  1662. }
  1663. }
  1664. }
  1665. </style>