purchase.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <template>
  2. <layout
  3. :bgImgName="currentLoading ? 'purchase-img' : ''"
  4. bgColor="#FDF2E3"
  5. bgHeight="219"
  6. @goBack="goBack"
  7. >
  8. <div class="purchase" v-if="currentLoading">
  9. <div class="purchase-privilege">
  10. <div>
  11. <img src="@/assets/image/claimCloudPhone/privilege-1.png" alt="" />
  12. 应用预装已完成
  13. </div>
  14. <div style="animation-delay: 0.2s">
  15. <img src="@/assets/image/claimCloudPhone/privilege-2.png" alt="" />
  16. 任意下单
  17. </div>
  18. <div style="animation-delay: 0.4s">
  19. <img src="@/assets/image/claimCloudPhone/privilege-3.png" alt="" />
  20. 立即使用云机
  21. </div>
  22. </div>
  23. <template v-for="item in packageList">
  24. <setMealItem
  25. :key="item.serialNumber"
  26. :data="item"
  27. v-if="item.mealList && item.mealList.length"
  28. :type="0"
  29. @buy="buy"
  30. />
  31. </template>
  32. <van-popup
  33. v-model="visible"
  34. position="bottom"
  35. :style="{ background: 'transparent' }"
  36. >
  37. <div class="payment-container">
  38. <div class="payment-container-title">新增云手机</div>
  39. <div class="payment-container-info">
  40. <div>
  41. <div class="payment-container-info_value">
  42. <span>¥</span>{{ currentData.actualPrice }}
  43. </div>
  44. <div class="payment-container-info_name">
  45. {{ packageType[currentData.phoneType]
  46. }}{{ currentData.day }}天卡
  47. </div>
  48. </div>
  49. </div>
  50. <div class="payment-container-num">
  51. 数量:<van-stepper button-size="18" v-model="stepper" />
  52. </div>
  53. <div class="payment-container-method">
  54. <div class="payment-container-method_title">选择支付方式</div>
  55. <div class="payment-container-method_select">
  56. <template v-for="item in paymentList">
  57. <div
  58. :key="item.key"
  59. v-if="
  60. currentData.paySupportTypeList &&
  61. currentData.paySupportTypeList.includes(item.key)
  62. "
  63. :class="{ active: active === item.key }"
  64. @click="active = item.key"
  65. >
  66. <img
  67. :src="active === item.key ? item.activeImg : item.img"
  68. alt=""
  69. />
  70. {{ item.name }}
  71. <div v-if="active === item.key" class="active-icon">
  72. <van-icon name="success" />
  73. </div>
  74. </div>
  75. </template>
  76. </div>
  77. </div>
  78. <div class="payment-container-amount">
  79. <div>
  80. 需支付金额:<span
  81. ><span>¥</span>{{ currentData.actualPrice * stepper }}
  82. </span>
  83. </div>
  84. <div @click="payment" :class="{ disabled: btnLoading }">
  85. <template v-if="btnLoading"> 正在支付中... </template>
  86. <template v-else> 确认协议并付款</template>
  87. </div>
  88. </div>
  89. <div class="payment-container-agreement">
  90. 购买前阅读<span @click="toAgreement">
  91. 《双子星云手机服务协议》
  92. </span>
  93. </div>
  94. </div>
  95. </van-popup>
  96. <van-dialog
  97. v-model="activityPurchaseVisible"
  98. @cancel="confirm(false)"
  99. @confirm="confirm(true)"
  100. show-cancel-button
  101. confirmButtonText="已完成支付"
  102. confirmButtonColor="#3367d1"
  103. >
  104. <div class="payment-tips">如果您已支付成功</div>
  105. <div class="payment-tips">请点击"已完成支付"按钮</div>
  106. </van-dialog>
  107. </div>
  108. </layout>
  109. </template>
  110. <script>
  111. import layout from './components/layout';
  112. import setMealItem from './components/setMealItem.vue';
  113. import common from './mixins/common.js';
  114. const RSA = require('@/plugins/wx_rsa.js');
  115. export default {
  116. auth: false,
  117. name: 'purchase',
  118. head: {
  119. title: '0元购机,尽情享受',
  120. },
  121. mixins: [common],
  122. data() {
  123. return {
  124. visible: false,
  125. currentData: {},
  126. packageType: {
  127. VIP: '星动',
  128. SVIP: '星曜',
  129. STARRYSKY: '星空',
  130. STAR: '唔即',
  131. STARPRO: '唔即Pro',
  132. },
  133. stepper: 1,
  134. active: '',
  135. paymentList: [
  136. {
  137. name: '微信',
  138. img: require('@/assets/image/claimCloudPhone/weChat.png'),
  139. activeImg: require('@/assets/image/claimCloudPhone/weChatActvie.png'),
  140. key: 'wxPay',
  141. },
  142. {
  143. name: '支付宝',
  144. img: require('@/assets/image/claimCloudPhone/alipay.png'),
  145. activeImg: require('@/assets/image/claimCloudPhone/alipayActive.png'),
  146. key: 'aliPay',
  147. },
  148. ],
  149. btnLoading: false,
  150. activityPurchaseVisible: false,
  151. H5_URL: process.env.H5_URL,
  152. };
  153. },
  154. mounted() {
  155. if (sessionStorage.getItem('isAgreementBool')) {
  156. this.currentData = JSON.parse(sessionStorage.getItem('currentData'));
  157. this.stepper = sessionStorage.getItem('stepper');
  158. this.active = sessionStorage.getItem('active');
  159. this.visible = true;
  160. sessionStorage.removeItem('isAgreementBool');
  161. sessionStorage.removeItem('currentData');
  162. sessionStorage.removeItem('active');
  163. sessionStorage.removeItem('stepper');
  164. }
  165. if (localStorage.getItem('activityPurchaseVisible')) {
  166. this.activityPurchaseVisible = true;
  167. localStorage.removeItem('activityPurchaseVisible');
  168. }
  169. this.getActivitySortRuleAndActivityMealList({
  170. personnelMealType: 2,
  171. });
  172. },
  173. components: { layout, setMealItem },
  174. methods: {
  175. buy(data) {
  176. this.stepper = 1;
  177. this.visible = true;
  178. this.currentData = JSON.parse(JSON.stringify(data));
  179. this.currentData.paySupportTypeList =
  180. this.currentData.paySupportTypeList.split(',');
  181. this.active = this.currentData.paySupportTypeList[0];
  182. },
  183. // 确认支付
  184. payment() {
  185. let params = {
  186. buyType: 1,
  187. quantity: this.stepper,
  188. id: this.currentData.id,
  189. phoneType: this.currentData.phoneType,
  190. activityId: 690009,
  191. returnUrl: this.H5_URL + '/h5/claimCloudPhone/confirmation',
  192. };
  193. params = this.sort_ASCII(params);
  194. const sign = this.jiaqian(JSON.stringify(params));
  195. this.btnLoading = true;
  196. this.$axios
  197. .$post('pay/v1/order/create', params, { headers: { sign } })
  198. .then((res) => {
  199. const obj = {
  200. aliPay: 'pay/v1/alipay/h5/spend',
  201. wxPay: 'pay/v1/wxPay/h5/spend',
  202. };
  203. if (res.success) {
  204. localStorage.setItem(
  205. 'activityPurchaseMyOrderNum',
  206. res.data.myOrderNum,
  207. );
  208. const data = {
  209. myOrderNum: res.data.myOrderNum,
  210. };
  211. const headers = {
  212. sign: this.jiaqian(JSON.stringify(data)),
  213. };
  214. this.$axios
  215. .$get(obj[this.active], { headers, params: data })
  216. .then((res) => {
  217. if (this.active === 'aliPay') {
  218. const div = document.createElement('div');
  219. div.innerHTML = res.data;
  220. document.body.appendChild(div);
  221. document.forms[0].submit();
  222. // 这个是为了兼容安卓支付宝没有跳转页面
  223. localStorage.setItem('activityPurchaseVisible', 1);
  224. setTimeout(() => {
  225. this.activityPurchaseVisible = true;
  226. }, 3000);
  227. div.remove();
  228. } else {
  229. window.location.replace(res.data);
  230. }
  231. })
  232. .catch((error) => {
  233. setTimeout(() => {
  234. this.$toast(error.message);
  235. });
  236. })
  237. .finally(() => {
  238. this.btnLoading = false;
  239. });
  240. }
  241. })
  242. .catch((error) => {
  243. this.$toast(error.message);
  244. this.btnLoading = false;
  245. });
  246. // function
  247. },
  248. sort_ASCII(obj) {
  249. var arr = [];
  250. var num = 0;
  251. for (const i in obj) {
  252. arr[num] = i;
  253. num++;
  254. }
  255. var sortArr = arr.sort();
  256. var sortObj = {};
  257. for (var i in sortArr) {
  258. sortObj[sortArr[i]] = obj[sortArr[i]];
  259. }
  260. return sortObj;
  261. },
  262. jiaqian(content) {
  263. const PrivateKey =
  264. '-----BEGIN PRIVATE KEY-----MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKCIK/zTSJCP4XhNsb7Mc5lALog+oAja/spMjg8U6rAmVzRtKv8qhw1HK0CRbW/XV66uM+kY7fhjaYbjbbzu2PMMfs2GVpG15jCWLug9fn2hvPT1wkXfooJX61yHK7+inxAXPi4vPNi263mSQGbhZTeqbU5p7nLeRGbdFyBQXVKpAgMBAAECgYAu/475RxZAlI8rPHvkY1EYteypoMQTs6HSslUI31PSXHc9dxSWfenqHkLwdWM30jDuiDvUa6MIDHrRrfXr0XWcQ0IJ93jT7ABkFCdxcKEOG1WE8f1kZ5JyPDJjeQiI9R4jJCukpGU0DdzO7ORvRb4oTFQ15quM+3+SjnK5TtfUsQJBAOLLk03D2s7t2R0GPLZq+WL/ebowbRSy4VHP/IQi4K1bJrll0HLznov60m9UML1ATlS2ub98fBRFXEAaAwJE2O0CQQC1NDEWhrAPU5o3xjjcxIUbbYskskbhjaiX/1Vz0UzS4XfYek4SL68WBWPGWTrSbgbvXtaXj0gmcChF5jxOHtUtAkA4mPsqxfy99UdgYeUW1P1lgkH7gAhIyRdH1nK6+wU83el9DPaHKVrgrfiEBeuf3wNtSqhyK/u/B0wtRxCHKW1FAkAXfwcGdryJoDuVE9z3s3vXDKNIRN2wDaBY5UD9XZxqk9XoeiN5dDltz5EafSOFecLocxG8YVXntg9i0PHs506ZAkEAge9AKaXisZ4jCNHRn1LR2R82RtHTLb2mN3Cc6sGo+SnAKczwRwVg9RgnmaLG4Z/7kJpq0ALgEBlkOmy+9joxAw==-----END PRIVATE KEY-----';
  265. const signature = new RSA.KJUR.crypto.Signature({
  266. alg: 'SHA256withRSA',
  267. });
  268. signature.init(PrivateKey);
  269. signature.updateString(content);
  270. const signData = signature.sign();
  271. // 将内容转成base64
  272. return RSA.hex2b64(signData);
  273. },
  274. toAgreement() {
  275. sessionStorage.setItem('currentData', JSON.stringify(this.currentData));
  276. sessionStorage.setItem('active', this.active);
  277. sessionStorage.setItem('stepper', this.stepper);
  278. this.$router.push(
  279. '/claimCloudPhone/agreement?agreementCoding=XYPZYHXY2002',
  280. );
  281. },
  282. goBack() {
  283. this.$router.push('/claimCloudPhone/inviteeExits');
  284. },
  285. confirm(bool) {
  286. if (bool) return this.$router.replace('/claimCloudPhone/confirmation');
  287. this.activityPurchaseVisible = false;
  288. localStorage.removeItem('activityPurchaseVisible');
  289. },
  290. },
  291. };
  292. </script>
  293. <style lang="less" scoped>
  294. .purchase {
  295. height: 100%;
  296. box-sizing: border-box;
  297. padding-top: 210px;
  298. .purchase-privilege {
  299. padding: 16px;
  300. height: 102px;
  301. background: #ffffff;
  302. box-shadow: 0px 2px 4px 0px #f6e5d3;
  303. border-radius: 8px;
  304. display: flex;
  305. justify-content: space-between;
  306. & > div {
  307. opacity: 0;
  308. animation: purchase 0.3s forwards linear;
  309. text-align: center;
  310. font-family: PingFangSC, PingFang SC;
  311. font-weight: 400;
  312. font-size: 14px;
  313. color: #1c2023;
  314. line-height: 20px;
  315. font-style: normal;
  316. & > img {
  317. width: 42px;
  318. height: 42px;
  319. display: block;
  320. margin: 0 auto;
  321. }
  322. }
  323. }
  324. .payment-container {
  325. border-radius: 10px 10px 0 0;
  326. padding: 16px;
  327. display: flex;
  328. flex-direction: column;
  329. background: #f4f6f8;
  330. overflow-y: auto;
  331. .payment-container-title {
  332. font-family: PingFangSC, PingFang SC;
  333. font-weight: 500;
  334. font-size: 18px;
  335. color: #0a132b;
  336. line-height: 20px;
  337. text-align: center;
  338. font-style: normal;
  339. }
  340. .payment-container-info {
  341. margin-top: 16px;
  342. height: 100px;
  343. background: #ffffff;
  344. border-radius: 16px;
  345. display: flex;
  346. justify-content: center;
  347. align-items: center;
  348. .payment-container-info_value {
  349. font-family: PingFangSC, PingFang SC;
  350. font-weight: 500;
  351. font-size: 28px;
  352. color: #0a132b;
  353. line-height: 32px;
  354. text-align: center;
  355. font-style: normal;
  356. span {
  357. font-size: 18px;
  358. }
  359. }
  360. .payment-container-info_name {
  361. font-family: PingFangSC, PingFang SC;
  362. font-weight: 400;
  363. font-size: 14px;
  364. color: #0a132b;
  365. line-height: 18px;
  366. text-align: center;
  367. font-style: normal;
  368. }
  369. }
  370. .payment-container-num {
  371. margin-top: 16px;
  372. padding: 16px;
  373. box-sizing: border-box;
  374. height: 50px;
  375. background: #ffffff;
  376. border-radius: 16px;
  377. font-family: PingFangSC, PingFang SC;
  378. font-weight: bold;
  379. font-size: 14px;
  380. color: #0a132b;
  381. line-height: 18px;
  382. text-align: left;
  383. display: flex;
  384. font-style: normal;
  385. .van-stepper {
  386. margin-left: 10px;
  387. }
  388. }
  389. .payment-container-method {
  390. .payment-container-method_title {
  391. font-family: PingFangSC, PingFang SC;
  392. font-weight: bold;
  393. font-size: 14px;
  394. color: #0a132b;
  395. line-height: 18px;
  396. text-align: left;
  397. font-style: normal;
  398. margin: 16px 0;
  399. }
  400. .payment-container-method_select {
  401. display: grid;
  402. grid-gap: 10px;
  403. grid-template-columns: repeat(3, 1fr);
  404. & > div {
  405. height: 54px;
  406. line-height: 54px;
  407. background: #edeef0;
  408. border-radius: 6px;
  409. display: flex;
  410. justify-content: center;
  411. align-items: center;
  412. font-family: PingFangSC, PingFang SC;
  413. color: #666666;
  414. border: 1px solid transparent;
  415. font-style: normal;
  416. font-weight: 500;
  417. font-size: 14px;
  418. line-height: 18px;
  419. font-style: normal;
  420. &.active {
  421. background: #ffffff;
  422. border-radius: 6px;
  423. border: 1px solid #3b7fff;
  424. position: relative;
  425. .active-icon {
  426. position: absolute;
  427. top: 0;
  428. right: 0;
  429. width: 26px;
  430. height: 15px;
  431. background: #3a86fe;
  432. border-radius: 0px 6px 0px 6px;
  433. display: flex;
  434. justify-content: center;
  435. align-items: center;
  436. .van-icon-success {
  437. color: #fff;
  438. }
  439. }
  440. }
  441. & > img {
  442. width: 24px;
  443. height: 24px;
  444. margin-right: 4px;
  445. }
  446. }
  447. }
  448. }
  449. .payment-container-amount {
  450. background: #ffffff;
  451. box-shadow: 0px 0px 13px 0px rgba(206, 206, 206, 0.5);
  452. border-radius: 16px;
  453. display: flex;
  454. justify-content: space-between;
  455. margin-top: 24px;
  456. & > div:first-of-type {
  457. font-family: PingFangSC, PingFang SC;
  458. font-weight: 500;
  459. font-size: 14px;
  460. color: #0a132b;
  461. line-height: 20px;
  462. font-style: normal;
  463. padding: 16px 0 16px 16px;
  464. & > span {
  465. font-weight: 500;
  466. font-size: 24px;
  467. color: #f04646;
  468. line-height: 20px;
  469. text-align: left;
  470. font-style: normal;
  471. span {
  472. font-size: 14px;
  473. }
  474. }
  475. }
  476. & > div:last-of-type {
  477. font-family: PingFangSC, PingFang SC;
  478. font-weight: 600;
  479. font-size: 16px;
  480. color: #ffffff;
  481. line-height: 22px;
  482. text-align: center;
  483. font-style: normal;
  484. line-height: 55px;
  485. height: 55px;
  486. width: 136px;
  487. background: linear-gradient(90deg, #38aefc 0%, #3b7fff 100%);
  488. border-radius: 16px;
  489. }
  490. }
  491. .payment-container-agreement {
  492. margin-top: 9px;
  493. font-family: PingFangSC, PingFang SC;
  494. font-weight: 500;
  495. font-size: 12px;
  496. color: #bbbbbb;
  497. line-height: 16px;
  498. text-align: center;
  499. font-style: normal;
  500. span {
  501. color: #3a86fe;
  502. }
  503. }
  504. }
  505. }
  506. .payment-tips {
  507. font-size: 18px;
  508. font-weight: bold;
  509. text-align: center;
  510. padding-top: 10px;
  511. &:last-of-type {
  512. padding-bottom: 10px;
  513. }
  514. }
  515. .disabled {
  516. opacity: 0.3;
  517. }
  518. @keyframes purchase {
  519. 0% {
  520. opacity: 0;
  521. }
  522. 100% {
  523. opacity: 1;
  524. }
  525. }
  526. </style>