give-dialog.vue 78 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289
  1. <template>
  2. <div class="overlay" v-if="visible">
  3. <div class="content"
  4. :style="{
  5. height: showComType === 'preview' ? 'calc(100vh - 40px)' : dialogStyle.dialogHeight + 'px',
  6. width: dialogStyle.dialogContentWidth + 'px',
  7. }">
  8. <div class="pop-mask"
  9. v-show="showCurrencyPop || showCurrencySelect"
  10. @click.stop="showCurrencyPop = false; showCurrencySelect=false">
  11. </div>
  12. <!-- 头部 -->
  13. <div class="head">
  14. <div class="left">
  15. <!-- 关闭按钮 -->
  16. <div class="close-btn" @click="close">
  17. <img class="icon-close"
  18. :src="require('@/assets/svg/icon-close.svg')"
  19. v-if="showComType == 'default'"/>
  20. <img class="icon-close"
  21. :src="require('@/assets/svg/icon-back.svg')"
  22. v-else/>
  23. </div>
  24. <!-- 标题 -->
  25. <div class="title">
  26. {{ currentComData[showComType]["title"] }}
  27. </div>
  28. </div>
  29. <div class="right">
  30. <!-- 更多按钮 -->
  31. <img :src="require('@/assets/svg/icon-more-l.svg')"
  32. class="more"
  33. @click="showMoreOption = true">
  34. <div class="area-option"
  35. v-if="showMoreOption"
  36. @click="showMoreOption = false">
  37. <div class="option">
  38. <div class="item" @click="goTransactionsList()">
  39. <img :src="require('@/assets/svg/icon-menu.svg')">
  40. <span>Transaction History</span>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. <!-- 内容 -->
  47. <div class="body">
  48. <!-- 充值组件 -->
  49. <top-up v-if="showComType == 'topUp'"
  50. :asyncIng="asyncIng"
  51. :currentCurrencyInfo="tempCurrentCurrencyInfo"
  52. @topUpDone="topUpDone"></top-up>
  53. <!-- 表单填写容器 -->
  54. <div class="body-content" v-if="showComType != 'topUp'">
  55. <!-- 货币列表 -->
  56. <div class="currency-pop" v-show="showCurrencyPop">
  57. <currency-list
  58. ref="currencyListDom"
  59. @selectCurrency="selectCurrency"
  60. @setCurrencyList="setCurrentCurrencyInfo"></currency-list>
  61. </div>
  62. <div class="currency-pop-select" v-show="showCurrencySelect">
  63. <currency-select
  64. ref="currencySelectDom"
  65. :list="tempCurrentCurrencyList"
  66. @selectCurrency="selectCurrencyAfter"></currency-select>
  67. </div>
  68. <div class="left" v-if="showComType != 'preview'">
  69. <div class="gift-pack-wrapper">
  70. <img class="icon" :src="require('@/assets/svg/icon-gift-pack.svg')"/>
  71. </div>
  72. <div class="bottom">
  73. </div>
  74. </div>
  75. <div class="right"
  76. :class="{'fill-right': showComType == 'preview'}">
  77. <global-tip :type="'2'"></global-tip>
  78. <div class="form-wrapper" v-if="showComType == 'default'">
  79. <div class="form-cell-item base-form-wrapper">
  80. <div class="title">
  81. <img class="icon" :src="require('@/assets/svg/icon-reward-v2.svg')"/>
  82. Reward
  83. </div>
  84. <div class="form-cell-content">
  85. <div class="select-mode-ele">
  86. <img v-for="(item, index) in publishModeList"
  87. :key="index"
  88. :src="selectModeInfo.index == index ? item.imgActive : item.imgInActive"
  89. @click="selectPublishMode(item, index)">
  90. </div>
  91. <!-- 金额、数量 -->
  92. <div class="form-base">
  93. <div class="item currency-select-wrapper">
  94. <div>
  95. <div class="label currency-select"
  96. :class="{'selected': currentCurrencyInfo.currencyCode}"
  97. @click="selectCurrencyPopHandle">
  98. <img class="icon"
  99. v-if="currentCurrencyInfo.iconPath"
  100. :src="currentCurrencyInfo.iconPath"/>
  101. <div class="text">
  102. {{currentCurrencyInfo.currencyCode == 'USD' ? 'USD' : currentCurrencyInfo.tokenSymbol || 'Select a reward'}}
  103. </div>
  104. <img class="arrow"
  105. :src="currentCurrencyInfo.currencyCode ?
  106. require('@/assets/svg/icon-form-arrow-down.svg') : require('@/assets/svg/icon-form-white-arrow-down.svg')"/>
  107. </div>
  108. <!-- 刷新按钮、充值 -->
  109. <div class="currency-operation"
  110. v-if="currentCurrencyInfo.currencyCode">
  111. <div class="amount">
  112. Balance:
  113. <a-tooltip :title="currentCurrencyInfo.balance">
  114. {{ getBit(currentCurrencyInfo.balance) }}
  115. </a-tooltip>
  116. <img :class="{ 'icon-refresh-rotate': refreshRotate }"
  117. :src="require('@/assets/svg/icon-form-refresh.svg')"
  118. @click="updateCurrencyBanlce"/>
  119. </div>
  120. <div v-if="currentCurrencyInfo.currencyCode != 'USD'"
  121. class="top-up"
  122. @click="goTopUp">Deposit</div>
  123. </div>
  124. </div>
  125. <input v-model="baseFormData.amountValue"
  126. placeholder="0"
  127. autofocus
  128. @input="onAmountInput"
  129. @blur="onAmountBlur"/>
  130. </div>
  131. <div class="item winners-count-input">
  132. <div>
  133. <div class="label">
  134. <img class="icon"
  135. :src="require('@/assets/svg/icon-winner-v2.svg')"/>
  136. Winner Count
  137. </div>
  138. <div class="msg" v-show="selectModeInfo.type == 1">Recommend Winners 100~10000</div>
  139. </div>
  140. <input v-model="baseFormData.totalCount"
  141. placeholder="0"
  142. @input="onCountInput"
  143. @blur="onCountBlur"/>
  144. </div>
  145. <div class="item automatically-input" v-if="selectModeInfo.type == 2">
  146. <div class="label">
  147. <img class="icon"
  148. :src="require('@/assets/svg/icon-automatically.svg')"/>
  149. Automatically Draw in
  150. </div>
  151. <div class="input-wrapper">
  152. <input v-model="baseFormData.validityDuration"
  153. placeholder="0"
  154. @input="onValidityDurationInput"
  155. @blur="onValidityDurationBlur"/>
  156. <span class="unit">h</span>
  157. </div>
  158. </div>
  159. </div>
  160. <!-- 提示 -->
  161. <ul class="tips-wrapper">
  162. <li class="row">
  163. Rewards can only be claimed after the target user completes all tasks you set.
  164. </li>
  165. <li class="row">
  166. Each user can only receive a reward once per task.
  167. </li>
  168. <li class="row" v-show="selectModeInfo.type == 1">
  169. 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.
  170. </li>
  171. </ul>
  172. </div>
  173. </div>
  174. <div class="form-cell-item task-wrapper">
  175. <div class="title">
  176. <img class="icon" :src="require('@/assets/svg/icon-tasks-v2.svg')"/>
  177. Tasks
  178. </div>
  179. <div class="form-cell-content form-require">
  180. <!-- 转推、like、关注 -->
  181. <div v-for="(item, index) in formList"
  182. :key="index">
  183. <div v-if="item.show" class="form-item"
  184. :class="{ 'border-hide': formList.length - 1 == index }">
  185. <div class="item-left">
  186. <div class="label">
  187. <img class="icon" :src="item.icon"/>
  188. {{ item.label }}
  189. </div>
  190. <div class="control"
  191. v-if="item.nodeType == 'textarea'">
  192. <follow-input
  193. :isAddSelf="!isBack"
  194. :atUserList="atUserList"
  195. @addUser="addFollowUser"
  196. @setUser="setFollowUser"
  197. @delUser="delFollowUser"></follow-input>
  198. </div>
  199. <div class="control"
  200. v-if="item.nodeType == 'input'">
  201. <div v-if="showDiscordInvitePop"
  202. class="discord-invite-info"
  203. @click="showDiscordInvitePop = false">
  204. <img class="icon" :src="discordInviteInfo.icon || require('@/assets/svg/icon-discord-mini.svg')" />
  205. <span class="name">{{discordInviteInfo.name}}</span>
  206. </div>
  207. <input v-model="item.text"
  208. placeholder="Enter discord invite link"
  209. class="discord-address"
  210. @input="onIptDiscordAddress($event, index)"
  211. @blur="onBlurDiscordAddress($event, index)" />
  212. </div>
  213. </div>
  214. <div>
  215. <a-switch
  216. v-if="item.type > 3"
  217. v-model:checked="item.checked"
  218. @change="formSwitchChange($event, item, index)"/>
  219. </div>
  220. </div>
  221. </div>
  222. </div>
  223. </div>
  224. <div class="submit-btn-wrapper">
  225. <div class="submit-btn"
  226. :class="{ 'disabled-submit': iptErrMsgTxt != ''}"
  227. @click="confirm">
  228. <img class="icon-loading"
  229. v-if="submitIng"
  230. :src="require('@/assets/svg/icon-btn-loading.svg')"
  231. />
  232. {{iptErrMsgTxt ? iptErrMsgTxt : 'NEXT'}}
  233. </div>
  234. </div>
  235. </div>
  236. <!-- 预览 -->
  237. <template v-else-if="showComType == 'preview'">
  238. <div class="preview">
  239. <div class="card"
  240. :class="{ center: Number(baseFormData.amountValue) <= Number(currentCurrencyInfo.balance) }">
  241. <div class="card-title">
  242. <img class="img"
  243. v-if="Number(baseFormData.amountValue) > Number(currentCurrencyInfo.balance)"
  244. :src=" require('@/assets/subject/top-01.svg') " />
  245. <div class="font">
  246. Preview: <span>{{installStatus ? 'After' : 'Before' }}</span> DeNet Installed
  247. </div>
  248. </div>
  249. <div class="flash">
  250. <preview-card
  251. :currentCurrencyInfo="currentCurrencyInfo"
  252. :postData="publishRes"
  253. :baseFormData="baseFormData"
  254. :amountFontSize="previewFontSize"
  255. ></preview-card>
  256. </div>
  257. </div>
  258. <!-- 需充值 -->
  259. <div class="card-content" v-if="Number(baseFormData.amountValue) > Number(currentCurrencyInfo.balance)">
  260. <template v-if="currentCurrencyInfo.currencyCode === 'USD'">
  261. <div class="card-title">
  262. <img class="img" :src=" require('@/assets/subject/top-02.svg') " />
  263. <div class="font">Deposit to Send Giveaway</div>
  264. </div>
  265. <div class="card-list">
  266. <div class="item">
  267. <div class="l">Giveaway Amount</div>
  268. <div class="r"></div>
  269. </div>
  270. <div class="item">
  271. <div class="l">Balance</div>
  272. <div class="r"></div>
  273. </div>
  274. <div class="item">
  275. <div class="l">Paypal charges fee ()</div>
  276. <div class="r"></div>
  277. </div>
  278. <div class="item">
  279. <div class="l">Deposit Amount</div>
  280. <div class="r"></div>
  281. </div>
  282. </div>
  283. </template>
  284. <template v-else>
  285. <div class="card-title">
  286. <img class="img" :src=" require('@/assets/subject/top-02.svg') " />
  287. <div class="font">Deposit to Send Giveaway</div>
  288. </div>
  289. <top-up2
  290. :asyncIng="asyncIng"
  291. :currentCurrencyInfo="tempCurrentCurrencyInfo"
  292. @topUpDone="topUpDone">
  293. </top-up2>
  294. <div class="card-title">
  295. <img class="img" :src=" require('@/assets/subject/top-03.svg') " />
  296. <div class="font">Wait for the amount to arrive</div>
  297. </div>
  298. <div class="card-amount">
  299. <img class="icon" src="@/assets/subject/icon-balance.png" />
  300. <div class="con">
  301. <div class="desc">Balance</div>
  302. <div class="price">{{currentCurrencyInfo.balance}} {{currentCurrencyInfo.tokenSymbol}}</div>
  303. </div>
  304. <img
  305. class="refresh"
  306. :class="{ 'icon-refresh-rotate': refreshRotate }"
  307. @click="updateCurrencyBanlce"
  308. :src=" require('@/assets/svg/icon-form-refresh-blue.svg') "
  309. />
  310. </div>
  311. </template>
  312. </div>
  313. </div>
  314. </template>
  315. <!-- paypal支付按钮 -->
  316. <div class="payment" v-show="showComType == 'preview'">
  317. <paypal-button
  318. :finalAmountData="finalAmountData"
  319. :payConfig="{
  320. paypalClientId,
  321. feeDesc: payConfig.feeDesc,
  322. paypalHtml,
  323. amount: baseFormData.amountValue,
  324. postId
  325. }"
  326. :currentCurrencyInfo="currentCurrencyInfo"
  327. @payPalFinsh="payPalFinsh">
  328. <template v-slot:balance>
  329. <div class="balance" v-if="Number(baseFormData.amountValue) <= Number(currentCurrencyInfo.balance)">
  330. <img class="icon" src="@/assets/subject/icon-balance.png" />
  331. <div class="con">
  332. <div class="desc">Balance</div>
  333. <div class="price">{{currentCurrencyInfo.balance}} {{currentCurrencyInfo.tokenSymbol}}</div>
  334. </div>
  335. <img class="refresh"
  336. :class="{ 'icon-refresh-rotate': refreshRotate }"
  337. :src=" require('@/assets/svg/icon-form-refresh.svg')"
  338. @click="updateCurrencyBanlce"/>
  339. </div>
  340. </template>
  341. </paypal-button>
  342. </div>
  343. </div>
  344. </div>
  345. </div>
  346. </div>
  347. <!-- 提示 -->
  348. <message-box
  349. :dialogVisible="showMessageBox"
  350. :title="messageBoxData.title"
  351. :content="messageBoxData.content"
  352. @cancel="messageBoxCancel"
  353. @confirm="messageBoxConfirm"
  354. ></message-box>
  355. </div>
  356. </template>
  357. <script setup>
  358. import { ref, watch, reactive, defineProps, defineEmits, onMounted, nextTick, provide } from "vue";
  359. import { postPublish, verifyPaypalResult, syncChainTokenRechargeRecord, getCurrencyInfoByCode } from "@/http/publishApi";
  360. import { getInviteGuildInfo, getInviteGuildInfoByOpenApi, saveInviteGuildInfo } from "@/http/discordApi";
  361. import { payCalcFee, getPayConfig } from "@/http/pay";
  362. import { getFrontConfig } from "@/http/account";
  363. import {setChromeStorage, getChromeStorage} from "@/uilts/chromeExtension"
  364. import { debounce, getBit } from "@/uilts/help"
  365. import Report from "@/log-center/log"
  366. import { ElMessage, ElLoading } from "element-plus";
  367. import "element-plus/es/components/message/style/css";
  368. import "element-plus/es/components/loading/style/css";
  369. import {create, all} from "mathjs";
  370. import messageBox from "@/view/components/message-box.vue";
  371. import currencyList from "@/view/components/currency-list.vue";
  372. import currencySelect from "@/view/components/currency-select.vue";
  373. import previewCard from "@/view/iframe/publish/components/preview-card";
  374. import followInput from "@/view/iframe/publish/components/follow-input";
  375. import paypalButton from "@/view/iframe/publish/components/paypal-button";
  376. import topUp from "@/view/iframe/publish/components/top-up.vue";
  377. import topUp2 from "@/view/iframe/publish/components/top-up2.vue";
  378. import GlobalTip from '@/view/components/global-tip.vue'
  379. const config = {
  380. number: 'BigNumber',
  381. }
  382. const math = create(all, config);
  383. //临时货币信息
  384. let tempCurrentCurrencyInfo = ref({});
  385. let tempCurrentCurrencyList = ref([]);
  386. let paypalClientId = ref("");
  387. let payConfig = ref({});
  388. let paypalHtml = ref("");
  389. let installStatus = ref(false);
  390. let timer = ref(null);
  391. provide('installStatus', installStatus)
  392. // 发布后返回的结果
  393. let publishRes = reactive({});
  394. //弹窗是否展示
  395. let visible = ref(false);
  396. //弹窗高度
  397. let dialogStyle = reactive({
  398. dialogHeight: 670,
  399. dialogContentWidth: 1100
  400. })
  401. // 当前展示组件内容 default(表单) preview(预览) topUp(充值)
  402. let showComType = ref("default");
  403. let currentComData = {
  404. default: {
  405. title: "Giveaway",
  406. },
  407. preview: {
  408. title: "Giveaway",
  409. },
  410. topUp: {
  411. title: "Deposit",
  412. },
  413. };
  414. // 机器人开关
  415. let openAntiBot = ref(false);
  416. // 是否正在提交
  417. let submitIng = ref(false);
  418. // 艾特关注人列表
  419. let atUserList = ref([]);
  420. // 表单错误提示
  421. let iptErrMsgTxt = ref("Select a reward");
  422. // 是否返回
  423. let isBack = ref(false);
  424. // 展示消息提示
  425. let showMessageBox = ref(false);
  426. // 展示货币列表pop
  427. let showCurrencyPop = ref(false);
  428. let showCurrencySelect = ref(false);
  429. // 展示更多按钮下的选项
  430. let showMoreOption = ref(false);
  431. // 货币列表的dom
  432. let currencyListDom = ref('');
  433. // 刷新按钮旋转
  434. let refreshRotate = ref(false);
  435. // 预览字体大小
  436. let previewFontSize = ref(56);
  437. let postId = ref('');
  438. let selectModeInfo = reactive({
  439. index: 0,
  440. type: 2 // 1: 红包 2: 抽奖
  441. })
  442. // 余额是否同步中
  443. let asyncIng = ref(false);
  444. let messageBoxData = ref({
  445. title: "",
  446. content: "",
  447. });
  448. // 真实支付金额数据
  449. let finalAmountData = ref({
  450. currencyCode: '',
  451. feeAmountValue: 0,
  452. finalAmountValue: 0,
  453. requestAmountValue: 0,
  454. });
  455. // 表单数据
  456. let baseFormData = reactive({
  457. amountCurrencyCode: "",
  458. amountValue: "",
  459. totalCount: "",
  460. validityDuration: "",
  461. type: selectModeInfo.type
  462. });
  463. // 当前选择的货币信息
  464. let currentCurrencyInfo = ref({
  465. currencyCode: "",
  466. currencyName: "",
  467. balance: "",
  468. currencyType: "",
  469. iconPath: "",
  470. minAmount: "",
  471. tokenChain: "",
  472. tokenSymbol: "",
  473. usdEstimateBalance: ""
  474. });
  475. const discordIptErrTxt = 'Discord invite link is wrong';
  476. const discordIptEmptyErrTxt = 'Enter discord invite link';
  477. const discordIptNerverExpiresErrTxt = 'Make sure the Discord link never expires'
  478. let iptErrType = ''; //discord
  479. let formList = reactive([
  480. {
  481. label: "Follow",
  482. icon: require("@/assets/svg/icon-task-twitter.svg"),
  483. nodeType: "textarea",
  484. type: 1,
  485. text: [],
  486. checked: true,
  487. show: true
  488. },
  489. {
  490. label: "Retweet & Like",
  491. icon: require("@/assets/svg/icon-task-twitter.svg"),
  492. nodeType: "div",
  493. type: 3,
  494. checked: true,
  495. show: true
  496. },
  497. {
  498. label: "Like Tweet",
  499. icon: require("@/assets/svg/icon-task-twitter.svg"),
  500. nodeType: "div",
  501. type: 2,
  502. checked: true,
  503. show: false
  504. },
  505. {
  506. label: "Comment and Tag 3 friends",
  507. icon: require("@/assets/svg/icon-task-twitter.svg"),
  508. nodeType: "div",
  509. type: 9,
  510. checked: true,
  511. show: true
  512. },
  513. {
  514. label: "Repost to Facebook",
  515. icon: require("@/assets/svg/icon-task-facebook.svg"),
  516. nodeType: "div",
  517. text: '',
  518. type: 8,
  519. checked: false,
  520. show: true
  521. },
  522. {
  523. label: "Join Discord",
  524. icon: require("@/assets/svg/icon-discord-mini.svg"),
  525. nodeType: "input",
  526. text: '',
  527. type: 7,
  528. checked: false,
  529. show: true
  530. },
  531. ]);
  532. let publishModeList = reactive([
  533. {
  534. imgActive: require("@/assets/svg/img-A1.svg"),
  535. imgInActive: require("@/assets/svg/img-A0.svg"),
  536. type: 2
  537. },
  538. {
  539. imgActive: require("@/assets/svg/img-B1.svg"),
  540. imgInActive: require("@/assets/svg/img-B0.svg"),
  541. type: 1
  542. }
  543. ])
  544. let discordInviteInfo = ref({});
  545. let showDiscordInvitePop = ref(false);
  546. let lotteryMaxHourDuration = 168;
  547. const props = defineProps({
  548. dialogVisible: {
  549. type: Boolean,
  550. default: false,
  551. },
  552. });
  553. watch(
  554. () => props.dialogVisible,
  555. (newVal) => {
  556. console.log("watch", newVal);
  557. visible.value = newVal;
  558. if (newVal) {
  559. Report.reportLog({
  560. pageSource: Report.pageSource.publisherDialog,
  561. businessType: Report.businessType.pageView,
  562. });
  563. getLocalCurrencyInfoByCode();
  564. setTimeout(() => {
  565. setDialogStyle();
  566. }, 300);
  567. // 更新余额
  568. clearInterval(timer.value);
  569. timer.value = setInterval(() => {
  570. getCurrencyInfo({loop: true});
  571. }, 10000)
  572. } else {
  573. clearInterval(timer.value);
  574. }
  575. }
  576. );
  577. const emits = defineEmits(["close", "confirm", "payPalFinsh"]);
  578. const close = () => {
  579. if (showComType.value != "default") {
  580. showComType.value = "default";
  581. isBack.value = true;
  582. } else {
  583. initParams();
  584. emits("close", false);
  585. }
  586. };
  587. /**
  588. * 设置弹窗高度
  589. */
  590. const setDialogStyle = (resize = false) => {
  591. nextTick(() => {
  592. let clientHeight = window.innerHeight;
  593. let clientWidth = window.innerWidth;
  594. let gapSafe = 40;
  595. if (dialogStyle.dialogHeight > clientHeight - gapSafe) {
  596. dialogStyle.dialogHeight = clientHeight - gapSafe;
  597. } else {
  598. if(resize) {
  599. dialogStyle.dialogHeight = 680;
  600. }
  601. }
  602. if(dialogStyle.dialogContentWidth > clientWidth - gapSafe) {
  603. dialogStyle.dialogContentWidth = clientWidth - gapSafe;
  604. } else {
  605. if(resize) {
  606. dialogStyle.dialogContentWidth = 1080;
  607. }
  608. }
  609. })
  610. };
  611. const selectCurrencyPopHandle = () => {
  612. Report.reportLog({
  613. pageSource: Report.pageSource.currencySelectorPage,
  614. businessType: Report.businessType.pageView,
  615. });
  616. showCurrencyPop.value = true;
  617. nextTick(() => {
  618. if(currencyListDom.value) {
  619. currencyListDom.value.getCurrencyInfoList && currencyListDom.value.getCurrencyInfoList();
  620. }
  621. })
  622. }
  623. /**
  624. * 获取实际支付金额
  625. */
  626. const getPayAmount = async (amountValue) => {
  627. let res = await payCalcFee({
  628. params: {
  629. amountValue,
  630. currencyCode: currentCurrencyInfo.value.currencyCode,
  631. payChannel: 'paypal',
  632. },
  633. });
  634. if (res.code == 0) {
  635. let { finalAmountValue, feeDesc } = res.data;
  636. payConfig.value.feeDesc = feeDesc;
  637. if (finalAmountValue > 0) {
  638. finalAmountData.value = res.data;
  639. }
  640. }
  641. return res.data;
  642. };
  643. const saveDiscordGuildInfo = () => {
  644. let {guildId, inviteCode, inviteUrl} = discordInviteInfo.value;
  645. //保存服务器信息
  646. Report.reportLog({
  647. pageSource: Report.pageSource.publisherDialog,
  648. businessType: Report.businessType.buttonClick,
  649. objectType: Report.objectType.saveDiscordGuildData
  650. }, {
  651. reportData: discordInviteInfo.value
  652. });
  653. if(guildId && inviteCode && inviteUrl) {
  654. saveInviteGuildInfo({
  655. params: {
  656. guildId,
  657. inviteCode,
  658. inviteUrl
  659. }
  660. })
  661. }
  662. }
  663. const confirm = () => {
  664. if (submitIng.value || iptErrMsgTxt.value) {
  665. return;
  666. }
  667. let { totalCount = 0 } = baseFormData;
  668. if (!totalCount) {
  669. return;
  670. }
  671. saveDiscordGuildInfo();
  672. submitRequest();
  673. };
  674. /**
  675. * 货币列表-选中货币
  676. */
  677. const selectCurrency = (params) => {
  678. let { currencies } = params;
  679. tempCurrentCurrencyList.value = currencies;
  680. if (currencies.length > 1) {
  681. showCurrencyPop.value = false;
  682. showCurrencySelect.value = true;
  683. } else {
  684. selectCurrencyAfter(currencies[0])
  685. }
  686. };
  687. const selectCurrencyAfter = (params, openWindow = true) => {
  688. tempCurrentCurrencyInfo.value = params;
  689. showCurrencySelect.value = false;
  690. currentCurrencyInfo.value = params;
  691. setLocalSelectCurrencyInfo(currentCurrencyInfo.value);
  692. if (openWindow === false) {
  693. return
  694. };
  695. if (params.currencyCode != "USD" && params.balance < params.minAmount) {
  696. let tokenSymbol = params.currencyCode == 'USD' ? 'USD' : params.tokenSymbol;
  697. messageBoxBlock({
  698. title: `Whether to deposit ${tokenSymbol}`,
  699. content: `Insufficient ${tokenSymbol} balance`,
  700. });
  701. } else {
  702. setCurrentCurrencyListInfo(tempCurrentCurrencyList.value);
  703. showCurrencyPop.value = false;
  704. finalAmountData.value.currencyCode = currentCurrencyInfo.value.currencyCode;
  705. resetFormIpt(false);
  706. onIptSetErrorTxt();
  707. }
  708. }
  709. const resetFormIpt = (clearMode = true) => {
  710. baseFormData.amountValue = "";
  711. baseFormData.totalCount = "";
  712. baseFormData.validityDuration = "";
  713. if(clearMode) {
  714. selectModeInfo.index = 0;
  715. selectModeInfo.type = publishModeList[selectModeInfo.index]['type'];
  716. baseFormData.type = selectModeInfo.type;
  717. }
  718. }
  719. const setLocalSelectCurrencyInfo = (params = {}) => {
  720. setChromeStorage({ selectCurrencyInfo : JSON.stringify(params)})
  721. }
  722. const setCurrentCurrencyListInfo = (params = {}) => {
  723. setChromeStorage({ selectCurrencyList : JSON.stringify(params)})
  724. }
  725. /**
  726. * 获取完货币列表
  727. */
  728. const setCurrentCurrencyInfo = (params) => {
  729. }
  730. const messageBoxBlock = ({ title = "", content = "" }) => {
  731. showMessageBox.value = true;
  732. messageBoxData.value.title = title;
  733. messageBoxData.value.content = content;
  734. };
  735. /**
  736. * 确定
  737. */
  738. const messageBoxConfirm = () => {
  739. showMessageBox.value = false;
  740. goTopUp();
  741. };
  742. /**
  743. * 取消
  744. */
  745. const messageBoxCancel = () => {
  746. currentCurrencyInfo.value = tempCurrentCurrencyInfo.value;
  747. setLocalSelectCurrencyInfo(currentCurrencyInfo.value);
  748. setCurrentCurrencyListInfo(tempCurrentCurrencyList.value);
  749. showMessageBox.value = false;
  750. showCurrencyPop.value = false;
  751. showCurrencySelect.value = false;
  752. resetFormIpt(false);
  753. onIptSetErrorTxt();
  754. };
  755. /**
  756. * 去充值
  757. */
  758. const goTopUp = () => {
  759. Report.reportLog({
  760. pageSource: Report.pageSource.rechargePage,
  761. businessType: Report.businessType.pageView,
  762. });
  763. showComType.value = 'topUp';
  764. }
  765. /**
  766. * 充值done事件
  767. */
  768. const topUpDone = () => {
  769. currentCurrencyInfo.value = tempCurrentCurrencyInfo.value;
  770. asyncIng.value = true;
  771. asyncIng.value = false;
  772. showCurrencyPop.value = false;
  773. showCurrencySelect.value = false;
  774. showComType.value = 'default';
  775. onIptSetErrorTxt()
  776. asyncTokenRechRecord((res) => {
  777. if(res.code == 0 && res.data && res.data.length) {
  778. let currencyInfo = res.data[0];
  779. if(currencyInfo.currencyCode == currentCurrencyInfo.value.currencyCode) {
  780. currentCurrencyInfo.value.balance = currencyInfo.balance;
  781. onIptSetErrorTxt()
  782. }
  783. }
  784. })
  785. }
  786. /**
  787. * 更新货币余额
  788. */
  789. const updateCurrencyBanlce = () => {
  790. if(!refreshRotate.value) {
  791. refreshRotate.value = true;
  792. setTimeout(() => {
  793. refreshRotate.value = false;
  794. }, 1000)
  795. }
  796. asyncTokenRechRecord((res) => {
  797. if(res.code == 0 && res.data && res.data.length) {
  798. let currencyInfo = res.data[0];
  799. if(currencyInfo.currencyCode == currentCurrencyInfo.value.currencyCode) {
  800. currentCurrencyInfo.value.balance = currencyInfo.balance;
  801. }
  802. }
  803. })
  804. }
  805. /**
  806. * 同步链上交易
  807. */
  808. const asyncTokenRechRecord = (cb) => {
  809. syncChainTokenRechargeRecord({
  810. params: {
  811. currencyCode: currentCurrencyInfo.value.currencyCode
  812. }
  813. }).then(res => {
  814. cb && cb(res)
  815. })
  816. }
  817. /**
  818. * 提交表单请求
  819. */
  820. const submitRequest = async () => {
  821. let { amountValue = 0, totalCount = 0 } = baseFormData;
  822. baseFormData.amountCurrencyCode = currentCurrencyInfo.value.currencyCode;
  823. // 组装提交参数
  824. let finishConditions = [];
  825. for (let i = 0; i < formList.length; i++) {
  826. let item = {};
  827. item.type = formList[i]["type"];
  828. if (item.type == 1 && atUserList.value.length) {
  829. // follow 参数
  830. let relatedUsers = atUserList.value.filter(item => item.name);
  831. item.relatedUsers = relatedUsers;
  832. finishConditions.push(item);
  833. } else if (formList[i]["type"] == 7) {
  834. // join discord
  835. if(formList[i]["checked"] && formList[i]["text"]) {
  836. item.bizData = JSON.stringify({inviteUrl: formList[i]["text"]});
  837. finishConditions.push(item);
  838. }
  839. } else if (formList[i]["checked"]) {
  840. // 其余任务
  841. finishConditions.push(item);
  842. }
  843. }
  844. let receiveConditions = openAntiBot.value ? "" : [];
  845. let validityDuration = '';
  846. if(baseFormData.type == 2) {
  847. //小时转毫秒
  848. // let unit = process.env.NODE_ENV != 'production' ? 60 * 1000 : 60 * 60 * 1000;
  849. let unit = 60 * 60 * 1000
  850. validityDuration = baseFormData.validityDuration * unit;
  851. } else {
  852. validityDuration = '';
  853. }
  854. // 提交参数
  855. let formData = {
  856. amountCurrencyCode: baseFormData.amountCurrencyCode,
  857. amountValue,
  858. totalCount,
  859. finishConditions,
  860. receiveConditions,
  861. payAmountValue: amountValue,
  862. type: baseFormData.type,
  863. validityDuration
  864. };
  865. submitIng.value = true;
  866. // 法币支付需要计算费率
  867. if(formData.amountCurrencyCode == "USD") {
  868. let payAmountRes = await getPayAmount(amountValue);
  869. formData["payAmountValue"] = payAmountRes.finalAmountValue;
  870. }
  871. let data = {
  872. params: {
  873. postBizData: JSON.stringify(formData),
  874. postSrc: 1, //1 twitter
  875. postType: 1, //1 红包
  876. },
  877. };
  878. postPublish(data).then((res) => {
  879. submitIng.value = false;
  880. if (res.code == 0) {
  881. publishRes = res.data;
  882. postId.value = res.data.postId;
  883. Report.reportLog({
  884. pageSource: Report.pageSource.previewPage,
  885. businessType: Report.businessType.pageView,
  886. });
  887. showComType.value = "preview";
  888. previewFontSize.value = calcFontSize(baseFormData.amountValue, 238, 56);
  889. isBack.value = false;
  890. } else {
  891. console.log(res);
  892. }
  893. })
  894. .catch((err) => {
  895. console.log(err);
  896. });
  897. };
  898. const calcFontSize = (str, domWidth, maxSize) => {
  899. let lenstr = str.length;
  900. let num = parseInt(domWidth / lenstr);
  901. let fontSize = num < maxSize ? num : maxSize
  902. return fontSize;
  903. }
  904. /**
  905. * 初始化提交参数
  906. */
  907. const initParams = () => {
  908. resetFormIpt();
  909. // clear follow value
  910. atUserList.value = [];
  911. submitIng.value = false;
  912. isBack.value = false;
  913. showCurrencyPop.value = false;
  914. showCurrencySelect.value = false;
  915. openAntiBot.value = false;
  916. tempCurrentCurrencyInfo.value = {};
  917. currentCurrencyInfo.value = {};
  918. // clear discord value
  919. setDiscordIptTxt({text: ''});
  920. discordInviteInfo.value = {};
  921. };
  922. const setDiscordIptTxt = ({text}) => {
  923. const index = formList.findIndex(item => item.type == 7);
  924. formList[index]['text'] = text;
  925. }
  926. /**
  927. * 支付完成回调
  928. */
  929. const payPalFinsh = (params) => {
  930. let {payNetwork, payStatus} = params;
  931. // token 支付
  932. if(payNetwork == 'bsc') {
  933. payStatusHandle(payStatus);
  934. } else {
  935. // 法币支付
  936. let transaction = params.transaction;
  937. let loadingInstance = ElLoading.service({
  938. background: "rgba(0,0,0,.3)",
  939. });
  940. verifyPaypalResult({
  941. params: {
  942. paypalTransactionId: transaction.id,
  943. postId: publishRes.postId,
  944. paypalClientId: paypalClientId.value,
  945. },
  946. }).then((res) => {
  947. loadingInstance.close();
  948. if (res.code == 0) {
  949. if (res.data) {
  950. payStatusHandle(res.data.payStatus)
  951. }
  952. }
  953. })
  954. .catch(() => {
  955. loadingInstance.close();
  956. });
  957. }
  958. };
  959. const payStatusHandle = (payStatus) => {
  960. //支付状态 0:未支付,1:支付成功,2:支付失败,3:已关闭,4:已退款
  961. switch (payStatus) {
  962. case 1:
  963. emits("payPalFinsh", { publishRes });
  964. showComType.value = "default";
  965. initParams();
  966. break;
  967. case 2:
  968. // ElMessage({
  969. // message: "Pay Fail",
  970. // type: "warning",
  971. // });
  972. break;
  973. case 3:
  974. // ElMessage({
  975. // message: "Pay Exceptions",
  976. // type: "warning",
  977. // });
  978. break;
  979. case 4:
  980. // ElMessage({
  981. // message: "Pay Exceptions",
  982. // type: "warning",
  983. // });
  984. break;
  985. }
  986. }
  987. /**
  988. * follow组件触发新增关注人
  989. */
  990. const addFollowUser = (params) => {
  991. atUserList.value.push(params);
  992. };
  993. const setFollowUser = (params) => {
  994. atUserList.value[params.index]["name"] = params.name;
  995. };
  996. const delFollowUser = (params) => {
  997. atUserList.value.splice(params.index, 1);
  998. };
  999. const onAmountInput = () => {
  1000. let val = baseFormData.amountValue;
  1001. // val = val.replace(/[^\d^\.]+/g, "");
  1002. val = val.replace(/^\D*(\d*(?:\.\d{0,18})?).*$/g, '$1');
  1003. if(val == '00') {
  1004. val = '0'
  1005. }
  1006. if(val.indexOf('.') > -1){ //校验 例:00.12 => 0.12
  1007. let arr = val.split('.');
  1008. if(arr[0].startsWith('0')) {
  1009. let num = +arr[0];
  1010. val = num + '.' + arr[1];
  1011. }
  1012. }
  1013. baseFormData.amountValue = val;
  1014. setInputErrorMsg({from: 'amount', type:'input'});
  1015. return val;
  1016. };
  1017. const onCountInput = () => {
  1018. let val = baseFormData.totalCount;
  1019. const maxCount = 100000000;
  1020. if (val == 0) {
  1021. val = "";
  1022. }
  1023. val = val.replace(/^\D*(\d*(?:\.\d{0,18})?).*$/g, '$1');
  1024. if(val > maxCount) {
  1025. val = maxCount
  1026. }
  1027. baseFormData.totalCount = val;
  1028. setInputErrorMsg({from: 'count', type:'input'});
  1029. return val;
  1030. };
  1031. const onValidityDurationInput = () => {
  1032. let val = baseFormData.validityDuration;
  1033. if (val == 0) {
  1034. val = "";
  1035. } else if(val > lotteryMaxHourDuration) {
  1036. val = lotteryMaxHourDuration+'';
  1037. }
  1038. val = val.replace(/[^\d]/g, "");
  1039. baseFormData.validityDuration = val;
  1040. setInputErrorMsg();
  1041. return val;
  1042. }
  1043. const onValidityDurationBlur = () => {
  1044. let val = baseFormData.validityDuration;
  1045. if (val == 0) {
  1046. val = "";
  1047. } else if(val > lotteryMaxHourDuration) {
  1048. val = lotteryMaxHourDuration+'';
  1049. }
  1050. val = val.replace(/[^\d]/g, "");
  1051. baseFormData.validityDuration = val;
  1052. setInputErrorMsg();
  1053. return val;
  1054. }
  1055. /**
  1056. * 金额输入失焦
  1057. */
  1058. const onAmountBlur = () => {
  1059. setInputErrorMsg({from: 'amount', type:'blur'});
  1060. };
  1061. /**
  1062. * count失焦,校验输入结果
  1063. */
  1064. const onCountBlur = () => {
  1065. setInputErrorMsg({from: 'count', type:'blur'});
  1066. };
  1067. /**
  1068. * 输入结果金额和数量 (金额/数量)是否小于最小货币单位
  1069. */
  1070. const calcIptValue = (cb) => {
  1071. let amountValue = baseFormData.amountValue;
  1072. let totalCount = baseFormData.totalCount;
  1073. let flag = true;
  1074. if (!amountValue || !totalCount) {
  1075. return {
  1076. flag
  1077. };
  1078. }
  1079. if (math.format(math.evaluate(`${baseFormData.amountValue} / ${baseFormData.totalCount}`)) < +currentCurrencyInfo.value.minAmount) {
  1080. flag = false;
  1081. }
  1082. return {
  1083. flag,
  1084. count: Math.floor(math.format(math.evaluate(`${baseFormData.amountValue} / ${currentCurrencyInfo.value.minAmount}`)))
  1085. }
  1086. };
  1087. /**
  1088. * 设置输入提示语
  1089. */
  1090. const setInputErrorMsg = () => {
  1091. onIptSetErrorTxt();
  1092. };
  1093. /**
  1094. * 输入时 检测设置错误信息
  1095. */
  1096. const onIptSetErrorTxt = (params = {}) => {
  1097. if(!currentCurrencyInfo.value.currencyCode) {
  1098. iptErrMsgTxt.value = "Select a reward"
  1099. } else if (!baseFormData.amountValue || baseFormData.amountValue == '0') {
  1100. iptErrMsgTxt.value = "Enter an amount";
  1101. } else if (!baseFormData.totalCount || baseFormData.totalCount == '0') {
  1102. iptErrMsgTxt.value = "Enter the number of winners";
  1103. } else if(+baseFormData.amountValue <= +currentCurrencyInfo.value.balance) {
  1104. // 输入金额 小于 余额
  1105. let res = calcIptValue();
  1106. if (!res.flag) {
  1107. iptErrMsgTxt.value = `${baseFormData.amountValue} ${currentCurrencyInfo.value.tokenSymbol} Can send up to ${res.count} winners`;
  1108. } else {
  1109. if(baseFormData.type == 2 && !baseFormData.validityDuration) {
  1110. iptErrMsgTxt.value = "Enter Automatically Draw";
  1111. } else {
  1112. //清空错误提示
  1113. iptErrMsgTxt.value = "";
  1114. if(params.actionType != 'discord_blur') {
  1115. setDiscordErrTxt({getDuildId: true});
  1116. }
  1117. }
  1118. }
  1119. } else if(baseFormData.type == 2 && !baseFormData.validityDuration) {
  1120. // 抽奖模式 没有输入时长
  1121. iptErrMsgTxt.value = "Enter Automatically Draw";
  1122. } else {
  1123. setDiscordErrTxt({getDuildId: true}, () => {
  1124. iptErrMsgTxt.value = '';
  1125. });
  1126. }
  1127. }
  1128. /**
  1129. * 监听开关触发事件
  1130. */
  1131. const formSwitchChange = (val, params, index) => {
  1132. closeDiscordTask(val, params, index);
  1133. }
  1134. const hideTask = (params, index) => {
  1135. formList[index]['checked'] = false;
  1136. formList[index]['show'] = false;
  1137. closeDiscordTask(false, {type: 7}, index)
  1138. }
  1139. const clickDropdown = (params, index) => {
  1140. formList[index]['show'] = true;
  1141. formList[index]['checked'] = true;
  1142. }
  1143. const closeDiscordTask = (val, params, index) => {
  1144. if(params.type == 7) {
  1145. if(!val) {
  1146. //错误类型 discord 清空discord错误校验
  1147. if(iptErrType == 'discord') {
  1148. iptErrMsgTxt.value = '';
  1149. formList[index]['text'] = '';
  1150. onIptSetErrorTxt();
  1151. }
  1152. } else {
  1153. onIptSetErrorTxt();
  1154. }
  1155. }
  1156. }
  1157. /** 监听 discord 输入 */
  1158. const onIptDiscordAddress = (e, index) => {
  1159. let val = formList[index].text;
  1160. let checked = formList[index].checked;
  1161. if(val && !checked) {
  1162. checked = true;
  1163. formList[index].checked = checked;
  1164. formList[index].text = formList[index].text.replace(/\s/g,'');
  1165. } else if(!val){
  1166. discordInviteInfo.value = {};
  1167. }
  1168. onIptDiscordDebounce()
  1169. }
  1170. const onBlurDiscordAddress = (e, index) => {
  1171. setDiscordErrTxt({fromType: 'discord', showPop: false, actionType: 'discord_blur'});
  1172. }
  1173. const getDiscordIptData = () => {
  1174. let discordItem = formList.find(item => item.type == 7);
  1175. return discordItem;
  1176. }
  1177. /**
  1178. * 设置输入discord错误提示信息
  1179. */
  1180. const setDiscordErrTxt = (params = {showPop: false}, cb) => {
  1181. let discordData = getDiscordIptData() || {};
  1182. if(discordData.checked) {
  1183. if(discordData.text) {
  1184. let validata = checkInviteUrl(discordData.text);
  1185. if(validata) {
  1186. getDiscordInviteInfo({inviteUrl: discordData.text, getDuildId: params.getDuildId}, (res) => {
  1187. console.log('discordData',res)
  1188. // 未知的邀请链接
  1189. if(res.inviteCode != res.data.code || !res.data.guildId) {
  1190. iptErrMsgTxt.value = discordIptErrTxt;
  1191. iptErrType = 'discord';
  1192. } else {
  1193. if(res.data.expires !== null) {
  1194. // 不是永久邀请链接
  1195. iptErrMsgTxt.value = discordIptNerverExpiresErrTxt;
  1196. iptErrType = '';
  1197. } else {
  1198. if(iptErrMsgTxt.value) {
  1199. iptErrMsgTxt.value = '';
  1200. iptErrType = '';
  1201. }
  1202. if(params.showPop && res.data) {
  1203. showDiscordInvitePop.value = true;
  1204. setTimeout(() => {
  1205. showDiscordInvitePop.value = false;
  1206. }, 2000)
  1207. }
  1208. if(params.fromType == 'discord') {
  1209. onIptSetErrorTxt();
  1210. }
  1211. }
  1212. }
  1213. cb && cb(res)
  1214. })
  1215. } else {
  1216. iptErrMsgTxt.value = discordIptErrTxt;
  1217. iptErrType = 'discord';
  1218. }
  1219. } else {
  1220. if(params.actionType == 'discord_blur') {
  1221. onIptSetErrorTxt({acitonType: 'discord_blur'});
  1222. } else {
  1223. // 设置空提示
  1224. iptErrMsgTxt.value = discordIptEmptyErrTxt;
  1225. iptErrType = 'discord';
  1226. }
  1227. }
  1228. } else {
  1229. cb && cb();
  1230. }
  1231. }
  1232. const onIptDiscordDebounce = debounce(function() {
  1233. setDiscordErrTxt({fromType: 'discord', showPop: true});
  1234. }, 800)
  1235. /**
  1236. * 校验 discord邀请url
  1237. */
  1238. const checkInviteUrl = (inviteUrl) => {
  1239. let flag = false;
  1240. const INVITE_URL_PREFIX_1 = 'https://discord.gg/';
  1241. const INVITE_URL_PREFIX_2 = 'https://discord.com/invite/';
  1242. const INVITE_URL_PREFIX_3 = 'http://discord.gg/';
  1243. const INVITE_URL_PREFIX_4 = 'http://discord.com/invite/';
  1244. const INVITE_URL_PREFIX_5 = 'discord.gg/';
  1245. const INVITE_URL_PREFIX_6 = 'discord.com/invite/';
  1246. 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]
  1247. if(inviteUrl) {
  1248. if(arr.indexOf(inviteUrl) > -1) {
  1249. flag = false;
  1250. } else {
  1251. let isPass = false;
  1252. for(let i = 0; i < arr.length; i++) {
  1253. let item = arr[i];
  1254. if(inviteUrl.startsWith(item)) {
  1255. isPass = true;
  1256. break;
  1257. }
  1258. }
  1259. flag = isPass;
  1260. }
  1261. }
  1262. return flag;
  1263. }
  1264. /**获取discord 邀请信息 */
  1265. const getDiscordInviteInfo = ({inviteUrl, getDuildId}, cb) => {
  1266. if(!inviteUrl) return;
  1267. let inviteCode = '';
  1268. let arr = inviteUrl.split('/');
  1269. if(arr.length > 0) {
  1270. inviteCode = arr[arr.length - 1];
  1271. }
  1272. if(!getDuildId && discordInviteInfo.value.guildId && discordInviteInfo.value.inviteCode == inviteCode) {
  1273. return;
  1274. }
  1275. getInviteGuildInfo({
  1276. inviteCode
  1277. }).then(res => {
  1278. let resData = inviteGuildResHandler(res, {inviteCode, inviteUrl});
  1279. if(resData.data.guildId) {
  1280. cb && cb(resData);
  1281. } else {
  1282. //DISCORD 接口未获取到服务器信息 resdata
  1283. Report.reportLog({
  1284. pageSource: Report.pageSource.publisherDialog,
  1285. businessType: Report.businessType.buttonClick,
  1286. objectType: Report.objectType.getDiscordGuildNoData
  1287. }, {
  1288. resData: resData
  1289. });
  1290. getGuildInfoByOpenApi({inviteCode}, cb);
  1291. }
  1292. }).catch((err) => {
  1293. //DISCORD 接口 catch
  1294. Report.reportLog({
  1295. pageSource: Report.pageSource.publisherDialog,
  1296. businessType: Report.businessType.buttonClick,
  1297. objectType: Report.objectType.getDiscordGuildCatch
  1298. }, {
  1299. err: err
  1300. });
  1301. let errMsg = err;
  1302. if(typeof errMsg == 'object') {
  1303. errMsg = JSON.stringify(err);
  1304. }
  1305. if(errMsg.indexOf('code 404') > -1) {
  1306. discordInviteInfo.value = {};
  1307. iptErrMsgTxt.value = discordIptErrTxt;
  1308. } else {
  1309. getGuildInfoByOpenApi({inviteCode}, cb);
  1310. }
  1311. });
  1312. }
  1313. const getGuildInfoByOpenApi = (params, cb) => {
  1314. let { inviteCode } = params;
  1315. getInviteGuildInfoByOpenApi({
  1316. inviteCode
  1317. }).then(res => {
  1318. let resData = inviteGuildResHandler(res, {inviteCode, inviteUrl});
  1319. if(resData.data.guildId) {
  1320. cb && cb(resData);
  1321. } else {
  1322. //OPENAPI 接口未获取到服务器信息 resdata
  1323. Report.reportLog({
  1324. pageSource: Report.pageSource.publisherDialog,
  1325. businessType: Report.businessType.buttonClick,
  1326. objectType: Report.objectType.getDiscordGuildOpenApiNoData
  1327. }, {
  1328. resData: resData
  1329. });
  1330. }
  1331. }).catch((err) => {
  1332. // OPENAPI 接口 catch 限频
  1333. Report.reportLog({
  1334. pageSource: Report.pageSource.publisherDialog,
  1335. businessType: Report.businessType.buttonClick,
  1336. objectType: Report.objectType.getDiscordGuildOpenApiCatch
  1337. }, {
  1338. err: err
  1339. });
  1340. if(iptErrMsgTxt.value && iptErrType == 'discord') {
  1341. iptErrMsgTxt.value = '';
  1342. iptErrType = '';
  1343. }
  1344. });
  1345. }
  1346. const inviteGuildResHandler = (res, params) => {
  1347. let {inviteCode, inviteUrl} = params;
  1348. if(!res) {
  1349. res = {};
  1350. }
  1351. let {name, icon, id} = res.guild || {};
  1352. icon = icon && id ? `https://cdn.discordapp.com/icons/${id}/${icon}.png` : '';
  1353. let resData = {
  1354. inviteCode,
  1355. data: {
  1356. code: res.code,
  1357. guildId: id,
  1358. inviteUrl,
  1359. inviteCode,
  1360. expires: res.expires_at,
  1361. name,
  1362. icon,
  1363. }
  1364. }
  1365. if(res.code == inviteCode) {
  1366. discordInviteInfo.value = resData.data;
  1367. } else {
  1368. discordInviteInfo.value = {};
  1369. iptErrMsgTxt.value = discordIptErrTxt;
  1370. }
  1371. return resData;
  1372. };
  1373. /**
  1374. * 获取支付配置(paypalClientId)
  1375. */
  1376. const setPayConfig = () => {
  1377. getPayConfig({
  1378. params: {},
  1379. }).then((res) => {
  1380. if (res.code == 0) {
  1381. payConfig.value = res.data;
  1382. paypalClientId.value = res.data.paypalClientId;
  1383. }
  1384. });
  1385. };
  1386. /**
  1387. * 获取配置
  1388. */
  1389. const setFrontConfig = () => {
  1390. getFrontConfig({
  1391. params: {},
  1392. }).then((res) => {
  1393. if (res.code == 0) {
  1394. paypalHtml.value = res.data.paypalHtml;
  1395. lotteryMaxHourDuration = res.data.lotteryMaxHourDuration;
  1396. }
  1397. });
  1398. };
  1399. const goTransactionsList = () => {
  1400. window.open(`${chrome.runtime.getURL('/iframe/home.html#/transactions')}`)
  1401. }
  1402. /**
  1403. * 默认获取上次选中的货币信息
  1404. */
  1405. const getLocalCurrencyInfoByCode = () => {
  1406. if(!currentCurrencyInfo.value.currencyCode) {
  1407. getCurrencyInfo();
  1408. }
  1409. }
  1410. const getCurrencyInfo = async (_params) => {
  1411. let { loop = false} = _params || {};
  1412. let {accessToken = ''} = await getChromeStorage('userInfo') || {};
  1413. if (accessToken) {
  1414. getChromeStorage('selectCurrencyInfo', (res) => {
  1415. if(res && res.currencyCode) {
  1416. getCurrencyInfoByCode({
  1417. params: {
  1418. currencyCode: res.currencyCode
  1419. }
  1420. }).then(res => {
  1421. if(res.code == 0 && res.data) {
  1422. currentCurrencyInfo.value = res.data;
  1423. tempCurrentCurrencyInfo.value = res.data;
  1424. if(!loop) {
  1425. onIptSetErrorTxt();
  1426. }
  1427. }
  1428. });
  1429. }
  1430. })
  1431. getChromeStorage('selectCurrencyList', (res) => {
  1432. if (showCurrencySelect.value === false) {
  1433. tempCurrentCurrencyList.value = res;
  1434. }
  1435. })
  1436. }
  1437. }
  1438. const selectPublishMode = (params, index) => {
  1439. selectModeInfo.index = index;
  1440. selectModeInfo.type = params.type;
  1441. baseFormData.type = params.type;
  1442. setInputErrorMsg();
  1443. }
  1444. onMounted(() => {
  1445. setFrontConfig();
  1446. setPayConfig();
  1447. getLocalCurrencyInfoByCode();
  1448. window.addEventListener('resize', function () {
  1449. setDialogStyle(true);
  1450. })
  1451. });
  1452. </script>
  1453. <style lang="scss" scoped>
  1454. :deep() .ant-switch {
  1455. background-color: #E9ECEE;
  1456. height: 14px;
  1457. line-height: 16px;
  1458. min-width: 36px;
  1459. }
  1460. :deep() .ant-switch-checked {
  1461. background-color: #AED8F5 !important;
  1462. }
  1463. :deep() .ant-switch::after {
  1464. width: 20px;
  1465. height: 20px;
  1466. top: -4px;
  1467. left: -1px;
  1468. }
  1469. :deep() .ant-switch-checked::after {
  1470. background-color: #1D9BF0 !important;
  1471. margin-left: 3px;
  1472. left: 100% !important;
  1473. }
  1474. .overlay {
  1475. position: fixed;
  1476. top: 0;
  1477. right: 0;
  1478. bottom: 0;
  1479. left: 0;
  1480. z-index: 1000;
  1481. width: 100%;
  1482. height: 100%;
  1483. background-color: rgba(0, 0, 0, 0.5);
  1484. overflow: auto;
  1485. .content {
  1486. height: 620px;
  1487. background: #ffffff;
  1488. border-radius: 20px;
  1489. position: absolute;
  1490. left: 50%;
  1491. top: 50%;
  1492. transform: translate(-50%, -50%);
  1493. box-sizing: border-box;
  1494. z-index: 2000;
  1495. max-height: 825px;
  1496. .pop-mask {
  1497. width: 100%;
  1498. height:100%;
  1499. position: absolute;
  1500. z-index:900;
  1501. }
  1502. .head {
  1503. border-bottom: 1px solid #ececec;
  1504. height: 48px;
  1505. box-sizing: border-box;
  1506. display: flex;
  1507. align-items: center;
  1508. justify-content: space-between;
  1509. padding: 0 14px;
  1510. .left {
  1511. display: flex;
  1512. align-items: center;
  1513. .title {
  1514. font-size: 16px;
  1515. font-weight: 500;
  1516. }
  1517. .close-btn {
  1518. display: flex;
  1519. align-items: center;
  1520. width: max-content;
  1521. margin-right: 12px;
  1522. cursor: pointer;
  1523. }
  1524. }
  1525. .right {
  1526. .more {
  1527. cursor: pointer;
  1528. }
  1529. .area-option {
  1530. width: 100%;
  1531. height: 100%;
  1532. position: absolute;
  1533. top: 0;
  1534. left: 0;
  1535. z-index: 111;
  1536. .option {
  1537. position: absolute;
  1538. top: 43px;
  1539. right: 15px;
  1540. background: #fff;
  1541. filter: drop-shadow(0px 3px 20px rgba(0, 0, 0, 0.2));
  1542. width: 240px;
  1543. border-radius: 15px;
  1544. overflow: hidden;
  1545. .item {
  1546. width: 100%;
  1547. height: 50px;
  1548. display: flex;
  1549. align-items: center;
  1550. cursor: pointer;
  1551. border-top: 1px solid #E9E9E9;
  1552. img {
  1553. margin-left: 15px;
  1554. width: 30px;
  1555. height: 30px;
  1556. margin-right: 6px;
  1557. }
  1558. span {
  1559. font-weight: 500;
  1560. font-size: 14px;
  1561. }
  1562. }
  1563. .item:first-child {
  1564. border-top: 0;
  1565. }
  1566. .item:hover {
  1567. background: #F5F5F5;
  1568. }
  1569. }
  1570. }
  1571. }
  1572. }
  1573. .body {
  1574. box-sizing: border-box;
  1575. height: calc(100% - 48px);
  1576. display: flex;
  1577. position: relative;
  1578. .body-content {
  1579. display:flex;
  1580. width:100%;
  1581. }
  1582. .currency-pop {
  1583. position: absolute;
  1584. width: 375px;
  1585. height: 480px;
  1586. top: 85px;
  1587. left: 88px;
  1588. z-index: 1000;
  1589. box-shadow: 0px 4px 30px rgba(0, 0, 0, 0.3);
  1590. background-color: #fff;
  1591. border-radius: 20px;
  1592. overflow-y: auto;
  1593. }
  1594. .currency-pop-select {
  1595. position: absolute;
  1596. width: 375px;
  1597. max-height: 480px;
  1598. top: 85px;
  1599. left: 88px;
  1600. z-index: 1000;
  1601. box-shadow: 0px 4px 30px rgba(0, 0, 0, 0.3);
  1602. background-color: #fff;
  1603. border-radius: 20px;
  1604. overflow-y: scroll;
  1605. }
  1606. .left,
  1607. .right {
  1608. height: 100%;
  1609. }
  1610. .left {
  1611. width: 50px;
  1612. display: flex;
  1613. flex-direction: column;
  1614. justify-content: space-between;
  1615. align-items: center;
  1616. .gift-pack-wrapper {
  1617. width: 100%;
  1618. height: 55px;
  1619. background: #f5f5f5;
  1620. display: flex;
  1621. align-items: center;
  1622. justify-content: center;
  1623. }
  1624. .bottom {
  1625. .icon {
  1626. display: block;
  1627. margin-bottom: 26px;
  1628. }
  1629. }
  1630. }
  1631. .right {
  1632. width: calc(100% - 50px);
  1633. box-sizing: border-box;
  1634. position: relative;
  1635. border-left: 1px solid #ececec;
  1636. .form-wrapper {
  1637. padding: 18px 18px 18px 18px;
  1638. height: calc(100% - 80px);
  1639. overflow: auto;
  1640. box-sizing: border-box;
  1641. display: flex;
  1642. .task-wrapper {
  1643. width: 480px;
  1644. }
  1645. .form-cell-item {
  1646. height: 100%;
  1647. .title {
  1648. display: flex;
  1649. align-items: center;
  1650. font-weight: 500;
  1651. font-size: 15px;
  1652. .icon {
  1653. width: 20px;
  1654. height: 20px;
  1655. margin-right: 5px;
  1656. }
  1657. }
  1658. .form-cell-content {
  1659. margin-top: 12px;
  1660. box-sizing: border-box;
  1661. }
  1662. }
  1663. .base-form-wrapper {
  1664. width: 450px;
  1665. margin-right: 30px;
  1666. .form-cell-content {
  1667. .select-mode-ele {
  1668. display: flex;
  1669. cursor: pointer;
  1670. img:first-child {
  1671. margin-right: 10px;
  1672. }
  1673. img {
  1674. -webkit-user-drag: none;
  1675. width: 220px;
  1676. height: 160px;
  1677. }
  1678. }
  1679. .form-base {
  1680. margin-top: 14px;
  1681. border: 1px solid #D1D9DD;
  1682. border-radius: 14px;
  1683. box-sizing: border-box;
  1684. padding-left: 14px;
  1685. .item {
  1686. box-sizing: border-box;
  1687. padding: 7px 0;
  1688. min-height: 76px;
  1689. display: flex;
  1690. align-items: center;
  1691. justify-content: space-between;
  1692. input {
  1693. width: 178px;
  1694. text-align: right;
  1695. font-weight: 700;
  1696. font-size: 26px;
  1697. border: none;
  1698. outline: none;
  1699. box-sizing: border-box;
  1700. }
  1701. input::placeholder {
  1702. color: #c5c5c5;
  1703. }
  1704. input {
  1705. padding-right: 16px;
  1706. }
  1707. .label {
  1708. font-weight: 500;
  1709. font-size: 15px;
  1710. display: flex;
  1711. align-items: center;
  1712. .icon {
  1713. width: 20px;
  1714. height: 20px;
  1715. margin-right: 8px;
  1716. }
  1717. }
  1718. }
  1719. .currency-select-wrapper {
  1720. overflow: hidden;
  1721. .currency-select {
  1722. cursor: pointer;
  1723. background: #1D9BF0;
  1724. padding: 6px 10px;
  1725. border-radius: 12px;
  1726. color: #fff;
  1727. width: max-content;
  1728. max-width: 234px;
  1729. .text {
  1730. word-break: break-all;
  1731. }
  1732. .arrow {
  1733. margin-left: 5px;
  1734. }
  1735. }
  1736. .selected {
  1737. background: #F4F4F4 !important;
  1738. color: #000 !important;
  1739. }
  1740. }
  1741. .winners-count-input {
  1742. border-top: 1px solid #D1D9DD;
  1743. .msg {
  1744. font-weight: 400;
  1745. font-size: 12px;
  1746. color: #A39F9F;
  1747. margin-top: 8px
  1748. }
  1749. }
  1750. .automatically-input {
  1751. border-top: 1px solid #D1D9DD;
  1752. .input-wrapper {
  1753. margin-right: 16px;
  1754. box-sizing: border-box;
  1755. input {
  1756. padding-right: 4px !important;
  1757. }
  1758. .unit {
  1759. font-weight: 700;
  1760. font-size: 26px;
  1761. opacity: 0.5;
  1762. }
  1763. }
  1764. }
  1765. }
  1766. }
  1767. }
  1768. .currency-operation {
  1769. position: relative;
  1770. box-sizing: border-box;
  1771. display: flex;
  1772. align-items: center;
  1773. margin-top: 8px;
  1774. .balance,
  1775. .amount {
  1776. display: flex;
  1777. align-items: center;
  1778. }
  1779. .amount {
  1780. font-weight: 400;
  1781. font-size: 12px;
  1782. color: #A39F9F;
  1783. img {
  1784. margin-left: 6px;
  1785. cursor: pointer;
  1786. }
  1787. }
  1788. .top-up {
  1789. font-weight: 500;
  1790. font-size: 12px;
  1791. color: #1D9BF0;
  1792. cursor: pointer;
  1793. margin-left: 4px;
  1794. }
  1795. }
  1796. .form-label {
  1797. margin-top: 14px;
  1798. margin-bottom: 10px;
  1799. font-weight: 500;
  1800. font-size: 14px;
  1801. display: flex;
  1802. align-items: center;
  1803. justify-content: space-between;
  1804. .icon-add-task {
  1805. cursor: pointer;
  1806. }
  1807. }
  1808. .form-require {
  1809. box-sizing: border-box;
  1810. border-radius: 15px;
  1811. border: 1px solid #D1D9DD;
  1812. .form-item {
  1813. min-height: 54px;
  1814. display: flex;
  1815. align-items: center;
  1816. justify-content: space-between;
  1817. margin: 0 16px;
  1818. border-bottom: 1px solid #ececec;
  1819. padding: 8px 0;
  1820. box-sizing: border-box;
  1821. .item-left {
  1822. display: flex;
  1823. }
  1824. .label {
  1825. min-width: 76px;
  1826. display: flex;
  1827. align-items: center;
  1828. font-size: 15px;
  1829. font-weight: 500;
  1830. .icon {
  1831. margin-right: 10px;
  1832. }
  1833. }
  1834. .control {
  1835. min-width: 258px;
  1836. margin-left: 6px;
  1837. box-sizing: border-box;
  1838. position: relative;
  1839. .discord-address {
  1840. border: none;
  1841. outline: none;
  1842. color: #1D9BF0;
  1843. font-weight: 500;
  1844. font-size: 14px;
  1845. width: 100%;
  1846. height: 34px;
  1847. padding-left: 15px;
  1848. }
  1849. .discord-address::placeholder {
  1850. color: #c5c5c5;
  1851. }
  1852. .discord-invite-info {
  1853. position: absolute;
  1854. top: 40px;
  1855. left: 0;
  1856. box-shadow: 0px 4px 30px rgba(0, 0, 0, 0.3);
  1857. background: #fff;
  1858. border-radius: 16px;
  1859. padding: 16px;
  1860. box-sizing: border-box;
  1861. display: flex;
  1862. align-items: center;
  1863. cursor: pointer;
  1864. .icon {
  1865. width: 40px;
  1866. height: 40px;
  1867. margin-right: 10px;
  1868. border-radius: 50%;
  1869. }
  1870. .name {
  1871. font-weight: 600;
  1872. font-size: 16px;
  1873. color: #101419;
  1874. width: 193px;
  1875. height: 20px;
  1876. overflow: hidden;
  1877. white-space: nowrap;
  1878. text-overflow: ellipsis;
  1879. display: inline-block;
  1880. }
  1881. }
  1882. }
  1883. .icon-task-close {
  1884. margin-left: 6px;
  1885. cursor: pointer;
  1886. }
  1887. }
  1888. .border-hide {
  1889. border-bottom: none !important;
  1890. }
  1891. }
  1892. }
  1893. .tips-wrapper {
  1894. margin: 16px 0 0 12px !important;
  1895. padding: 0px !important;
  1896. .title,
  1897. .row {
  1898. font-weight: 400;
  1899. font-size: 12px;
  1900. color: #A39F9F;
  1901. }
  1902. .row {
  1903. box-sizing: border-box;
  1904. line-height: 16px;
  1905. }
  1906. }
  1907. .submit-btn-wrapper {
  1908. width: 100%;
  1909. background: #fff;
  1910. position: absolute;
  1911. bottom: 18px;
  1912. left: 0;
  1913. box-sizing: border-box;
  1914. padding: 16px 18px 0 18px;
  1915. .submit-btn {
  1916. width: 100%;
  1917. height: 46px;
  1918. text-align: center;
  1919. background: #4a99e9;
  1920. border-radius: 100px;
  1921. color: #fff;
  1922. display: flex;
  1923. align-items: center;
  1924. justify-content: center;
  1925. font-size: 16px;
  1926. font-weight: 500;
  1927. cursor: pointer;
  1928. .icon-loading {
  1929. width: 20px;
  1930. height: 20px;
  1931. margin-right: 3px;
  1932. }
  1933. }
  1934. .disabled-submit {
  1935. background-color: #D9D9D9;
  1936. }
  1937. }
  1938. }
  1939. .fill-right {
  1940. width: 100% !important;
  1941. border-bottom-left-radius: 16px;
  1942. }
  1943. }
  1944. }
  1945. }
  1946. .preview {
  1947. padding: 30px 40px;
  1948. height: calc(100% - 80px);
  1949. overflow-y: auto;
  1950. .card {
  1951. float: left;
  1952. width: 480px;
  1953. position: relative;
  1954. .flash {
  1955. overflow: hidden;
  1956. height: 600px;
  1957. border-radius: 26px;
  1958. border: solid 1px #ECECEC;
  1959. }
  1960. &.center {
  1961. margin-left: 50%;
  1962. transform: translateX(-50%);
  1963. }
  1964. }
  1965. .card-title {
  1966. height: 32px;
  1967. .img {
  1968. float: left;
  1969. width: 20px;
  1970. height: 20px;
  1971. margin-right: 8px;
  1972. }
  1973. .font {
  1974. float: left;
  1975. font-size: 17px;
  1976. font-weight: 500;
  1977. span {
  1978. color: #0091e9;
  1979. }
  1980. }
  1981. }
  1982. .card-content {
  1983. float: right;
  1984. width: 500px;
  1985. }
  1986. .card-amount {
  1987. overflow: hidden;
  1988. display: flex;
  1989. height: 80px;
  1990. align-items: center;
  1991. padding: 20px;
  1992. border-radius: 20px;
  1993. border: 1px solid #E6E6E6;
  1994. .icon {
  1995. width: 40px;
  1996. height: 40px;
  1997. }
  1998. .con {
  1999. flex: 1;
  2000. padding: 0 10px;
  2001. .desc {
  2002. color: rgba($color: #000000, $alpha: 0.5);
  2003. font-size: 12px;
  2004. margin-bottom: 4px;
  2005. }
  2006. .price {
  2007. font-size: 16px;
  2008. font-weight: bold;
  2009. word-break: break-all;
  2010. }
  2011. }
  2012. .refresh {
  2013. cursor: pointer;
  2014. width: 30px;
  2015. height: 30px;
  2016. margin-top: -5px;
  2017. }
  2018. }
  2019. .card-list {
  2020. padding: 20px;
  2021. border-radius: 20px;
  2022. border: 1px solid #E6E6E6;
  2023. .item {
  2024. display: flex;
  2025. justify-content: space-between;
  2026. align-items: center;
  2027. height: 47px;
  2028. font-size: 14px;
  2029. font-weight: 500;
  2030. box-shadow: inset 0px -1px 0px #EAEAEA;
  2031. }
  2032. }
  2033. }
  2034. .icon-refresh-rotate {
  2035. transform: rotate(360deg);
  2036. transition-duration: 1s;
  2037. }
  2038. .payment {
  2039. .balance {
  2040. display: flex;
  2041. margin-right: 20px;
  2042. .icon {
  2043. width: 40px;
  2044. height: 40px;
  2045. }
  2046. .con {
  2047. padding: 0 5px;
  2048. .desc {
  2049. color: rgba($color: #000000, $alpha: 0.5);
  2050. font-size: 12px;
  2051. margin-bottom: 4px;
  2052. }
  2053. .price {
  2054. font-size: 14px;
  2055. font-weight: bold;
  2056. word-break: break-all;
  2057. }
  2058. }
  2059. .refresh {
  2060. width: 40px;
  2061. cursor: pointer;
  2062. margin-left: -5px;
  2063. }
  2064. }
  2065. }
  2066. </style>