purchase.vue 16 KB

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