天波h5前端应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
29KB

  1. <!--
  2. * @Date: 2023-03-14 09:32:37
  3. * @LastEditors: JinxChen
  4. * @LastEditTime: 2023-05-07 13:28:01
  5. * @FilePath: \TelpoH5FrontendWeb\src\views\package-buy\index.vue
  6. * @description:
  7. -->
  8. <template>
  9. <div class="package-buy-container">
  10. <van-nav-bar :left-arrow="true" title="套餐订购" :border="true" @click-left="onNavBack">
  11. <!-- <template #title>
  12. <h5 style="font-size: 16px">套餐订购</h5>
  13. </template> -->
  14. </van-nav-bar>
  15. <!-- 套餐内容 -->
  16. <div class="package-container">
  17. <van-tabs type="line" v-model="active" color="#1890ff" background="#fafafa" swipeable line-width="20%"
  18. line-height="4px">
  19. <van-tab title="加油包">
  20. <div class="refuel-package" v-if="refuelPackageList.length > 0">
  21. <div class="refuel-item" v-for="(item, index) in refuelPackageList" :key="index">
  22. <div class="title">
  23. <p>{{ item.packagesName }}</p>
  24. </div>
  25. <div class="bottom">
  26. <span>
  27. {{ item.packagesPrice }}
  28. <span class="price-span">元</span>
  29. </span>
  30. <div class="btn-button" @click="onBuyRefuel(item)">
  31. <p>立即订购</p>
  32. </div>
  33. </div>
  34. </div>
  35. </div>
  36. <div class="data-null" v-else>
  37. <img src="@/assets/img/news-noData.png" alt />
  38. <span>暂无加油包</span>
  39. </div>
  40. </van-tab>
  41. <van-tab title="基础套餐">
  42. <div class="base-package" v-if="basePackageList.length > 0">
  43. <div class="base-item" v-for="(item, index) in basePackageList" :key="index">
  44. <div class="base-item-content">
  45. <!-- <div class="title">
  46. <p>{{item.packagesName}}</p>
  47. </div>-->
  48. <div class="remark">
  49. <p>每月200分钟通话时长,1G流量</p>
  50. </div>
  51. <div class="details">
  52. <p>
  53. <span class="orange large">¥{{ (item.packagesPrice / (item.packageIssue === 0 ?
  54. 1 :
  55. item.packageIssue)).toFixed(0) }}</span>元/月,
  56. </p>
  57. <p class="total">
  58. <span>合计</span>
  59. <span class="orange price">{{ item.packagesPrice }}元</span>
  60. </p>
  61. </div>
  62. <div class="radios-con">
  63. <div class="pay-type">
  64. <p>支付方式:</p>
  65. </div>
  66. <van-radio-group v-model="radio" direction="horizontal" @change="onRaidoChange">
  67. <van-radio name="1">
  68. <template #default>
  69. <div class="radio-con">
  70. <span>微信</span>
  71. <img src="../../assets/wx-pay.png" />
  72. </div>
  73. </template>
  74. </van-radio>
  75. <van-radio name="2">
  76. <template #default>
  77. <div class="radio-con">
  78. <span>支付宝</span>
  79. <img src="../../assets/alipay.png" />
  80. </div>
  81. </template>
  82. </van-radio>
  83. <van-radio name="3">
  84. <template #default>
  85. <div class="radio-con">
  86. <span>12期花呗</span>
  87. <img src="../../assets/antpay.png" />
  88. </div>
  89. </template>
  90. </van-radio>
  91. </van-radio-group>
  92. </div>
  93. <div class="package-buy">
  94. <div class="buy-btn" @click="onBuyBase(item)">
  95. <p>套餐订购</p>
  96. </div>
  97. </div>
  98. </div>
  99. </div>
  100. </div>
  101. <div class="data-null" v-else>
  102. <img src="@/assets/img/news-noData.png" alt />
  103. <span>暂无基础套餐</span>
  104. </div>
  105. </van-tab>
  106. </van-tabs>
  107. </div>
  108. </div>
  109. </template>
  110. <script>
  111. import APICore from "@/api/core";
  112. import APIWx from "@/api/wx";
  113. import AppId from "@/config/appId";
  114. import { APIPay } from "@/api/pay";
  115. let wx = require("weixin-js-sdk"); // TODO 再封装,可拦截错误提示等操作
  116. export default {
  117. name: '',
  118. data() {
  119. return {
  120. basePackageList: [], //基础套餐
  121. refuelPackageList: [], //加油包
  122. outTradeNo: "", //订单号
  123. price: "", //价格,
  124. isShowNoData: false, //是否显示无套餐内容, 默认false
  125. radio: '1', //支付方式单选按钮默认值
  126. payProductId: null, //套餐id
  127. packageIssue: null, //套餐分期
  128. payType: '1', //支付方式 1 微信, 2 支付宝,支付宝又分为花呗和全额支付,全额支付分期数传0 或者1 ,花呗则传 3 6 12
  129. active: 0, //tabs默认选择的下标
  130. }
  131. },
  132. methods: {
  133. onNavBack() {
  134. this.$router.replace({
  135. name: "cardInfo",
  136. query: { imei: this.$route.query.imei, iccid: this.$route.query.iccid, isShowMenu: true, isHasCode: true }
  137. });
  138. },
  139. // 获取core token
  140. getAuth() {
  141. let manufactorId = "5bf13062-a41e-4d00-ba14-1101aad12650";
  142. APICore.getAuth({ manufactorId: manufactorId }).then(res => {
  143. this.$store.commit("gatewayToken", res.data.data);
  144. });
  145. },
  146. // 获取微信授权
  147. getWxAutograph() {
  148. let that = this;
  149. return new Promise((resolve, reject) => {
  150. APIWx.createJSSDK({
  151. sUrl: window.location.href.split("#")[0],
  152. userId: '',
  153. appId: AppId
  154. })
  155. .then(res => {
  156. let item = res.data.data;
  157. wx.config({
  158. debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  159. appId: item.appId, // 必填,公众号的唯一标识
  160. timestamp: item.timeStamp, // 必填,生成签名的时间戳
  161. nonceStr: item.nonceStr, // 必填,生成签名的随机串
  162. signature: item.signature, // 必填,签名
  163. jsApiList: ["chooseWXPay"] // 必填,需要使用的JS接口列表
  164. });
  165. wx.ready(() => {
  166. resolve(true);
  167. });
  168. })
  169. .catch(err => {
  170. reject(false);
  171. console.log(err);
  172. });
  173. });
  174. },
  175. // 获取套餐列表数据
  176. getDevicePayPackage() {
  177. this.$toast.loading({
  178. message: "加载中",
  179. duration: 1500
  180. });
  181. APICore.devicePayPackage(this.$route.query.imei)
  182. .then(res => {
  183. console.log("data", res.data);
  184. if (res.data.code === 106 || res.data.code === 104) {
  185. // token过期
  186. this.getAuth();
  187. setTimeout(() => {
  188. this.getDevicePayPackage();
  189. }, 1500);
  190. } else if (res.data.code === 0 && res.data.data === null) {
  191. this.isShowNoData = true;
  192. } else {
  193. if (res.data.data === null) {
  194. this.isShowNoData = false;
  195. } else {
  196. let data = res.data.data.packagesList;
  197. // 处理获取套餐的逻辑
  198. // 筛选 基础套餐,producModelId 1 是基础套餐;2 是加油包
  199. this.basePackageList = data.filter(item => {
  200. return item.producModelId === 1
  201. });
  202. this.refuelPackageList = data.filter(item => {
  203. return item.producModelId === 2
  204. });
  205. }
  206. this.$toast.success({
  207. message: "加载完成",
  208. duration: 1500
  209. });
  210. }
  211. })
  212. .catch(error => {
  213. this.$dialog.confirm({
  214. title: "获取套餐数据失败",
  215. message: error.message,
  216. showCancelButton: false,
  217. });
  218. })
  219. .finally(() => {
  220. setTimeout(() => {
  221. this.$toast.clear();
  222. }, 1500);
  223. });
  224. },
  225. // 购买加油包
  226. onBuyRefuel(data) {
  227. console.log("加油包", data);
  228. if (!this.isWeChat) {
  229. return this.$dialog.confirm({
  230. message: '请用微信客户端打开此页。',
  231. showCancelButton: false,
  232. })
  233. }
  234. this.price = data.packagesPrice;
  235. this.wxPay(data, 1);
  236. },
  237. // 购买基础套餐
  238. onBuyBase(data) {
  239. console.log("基础包", data);
  240. console.log("isWeChat", this.isWeChat);
  241. if (!this.isWeChat) {
  242. return this.$dialog.confirm({
  243. message: '请用微信客户端打开此页。',
  244. showCancelButton: false,
  245. })
  246. }
  247. this.price = data.packagesPrice;
  248. let payTypeToPackAgeId = data.payTypeList;
  249. if (this.payType == '2') {
  250. // 全额
  251. this.payProductId = payTypeToPackAgeId.filter(item => {
  252. return item.payType == '2'
  253. })[0].productId;
  254. this.packageIssue = 0;
  255. console.log("this.payProductId", this.payProductId);
  256. this.aliPay(data);
  257. } else if (this.payType == '3') {
  258. // 分期
  259. this.payProductId = payTypeToPackAgeId.filter(item => {
  260. return item.payType == '3'
  261. })[0].productId;
  262. this.packageIssue = 12;
  263. this.payType = '2';
  264. console.log("this.payProductId2", this.payProductId);
  265. this.aliPay(data);
  266. } else {
  267. // 微信
  268. let openId = this.$store.getters.openId;
  269. this.payProductId = payTypeToPackAgeId.filter(item => {
  270. return item.payType == '1'
  271. })[0].productId;
  272. this.packageIssue = 0;
  273. console.log("this.payProductId3", this.payProductId);
  274. if (openId === null || openId === 'null') {
  275. this.$dialog.confirm({
  276. message: '获取OpenId失败,请您重新进入',
  277. showCancelButton: false,
  278. })
  279. } else {
  280. this.wxPay(data);
  281. }
  282. }
  283. },
  284. // 支付类型切换
  285. onRaidoChange(value) {
  286. console.log("选择的支付类型是", value);
  287. this.payType = value;
  288. },
  289. // 微信支付
  290. wxPay(data, packageType) {
  291. let that = this;
  292. const orderData = data;
  293. console.log("orderData", orderData);
  294. let reqBody = {
  295. openId: this.$store.getters.openId, //openId
  296. imei: that.$route.query.imei, //imei
  297. iccid: that.$route.query.iccid,
  298. productId: orderData.payTypeList[0].productId, //套餐id
  299. packageName:
  300. orderData.productModel + "," + orderData.packagesName, //套餐名字
  301. packagePayType: '1', //支付类型, 默认微信
  302. pkId: data.packagesCardId,
  303. packageIssue: orderData.packageIssue, //分期
  304. packagePrice: orderData.packagesPrice * 100
  305. };
  306. // 1.获取微信预下单Id
  307. APICore.payLiveBaseDevice(reqBody)
  308. .then(res => {
  309. if (res.data.code === 104 || res.data.code === 106) {
  310. this.getAuth();
  311. setTimeout(() => {
  312. this.wxPay(orderData);
  313. }, 1000);
  314. } else if (res.data.code !== 0) {
  315. return this.$dialog.confirm({
  316. message: `请反馈给一线人员,\n${res.data.message},或者请您重新进入`,
  317. showCancelButton: false
  318. })
  319. }
  320. let wxData = res.data.data;
  321. let outTradeNo = wxData.out_trade_no;
  322. that.outTradeNo = wxData.out_trade_no;
  323. //this.checkWxPayResult(outTradeNo);
  324. //this.closeTime();
  325. // 调起微信支付收银台
  326. this.onWxPay(wxData, packageType);
  327. })
  328. .catch(error => {
  329. console.log("error", error);
  330. })
  331. },
  332. onWxPay(data, packageType) {
  333. let that = this;
  334. function onBridgeReady() {
  335. WeixinJSBridge.invoke(
  336. "getBrandWCPayRequest",
  337. {
  338. appId: AppId, //公众号ID,由商户传入
  339. timeStamp: data.timeStamp, //时间戳,自1970年以来的秒数
  340. nonceStr: data.nonceStr, //随机串
  341. package: data.package,
  342. signType: data.signType, //微信签名方式:
  343. paySign: data.paySign //微信签名
  344. },
  345. function (res) {
  346. if (res.err_msg == "get_brand_wcpay_request:ok") {
  347. // 使用以上方式判断前端返回,微信团队郑重提示:
  348. //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
  349. if (packageType === 1) {
  350. // 加油包不用跳转,直接提示支付成功
  351. // 2023.06.09 修改充值成功提示如下:
  352. that.$toast.success({
  353. message: '充值成功,请重启设备后,恢复正常使用。'
  354. });
  355. } else {
  356. that.$router.replace({
  357. name: "payResult",
  358. query: {
  359. outTradeNo: that.outTradeNo,
  360. price: that.price,
  361. rechargeUrl: data.rechargeUrl,
  362. iccid: that.$route.query.iccid,
  363. isAdmin: that.$route.query.isAdmin || false,
  364. serialNo: that.$route.query.imei,
  365. issue: that.packageIssue
  366. }
  367. });
  368. }
  369. } else {
  370. let cancelMessage = packageType === 1 ? '立即订购' : '套餐订购'
  371. that.$dialog.confirm({
  372. message: `请点击“${cancelMessage}”支付`,
  373. showCancelButton: false
  374. });
  375. }
  376. }
  377. );
  378. }
  379. if (typeof WeixinJSBridge == "undefined") {
  380. if (document.addEventListener) {
  381. document.addEventListener(
  382. "WeixinJSBridgeReady",
  383. onBridgeReady,
  384. false
  385. );
  386. } else if (document.attachEvent) {
  387. document.attachEvent("WeixinJSBridgeReady", onBridgeReady);
  388. document.attachEvent(
  389. "onWeixinJSBridgeReady",
  390. onBridgeReady
  391. );
  392. }
  393. } else {
  394. onBridgeReady();
  395. }
  396. },
  397. // 跳转到支付宝花呗外部链接
  398. aliPay(data) {
  399. console.log("选择了支付宝::", data);
  400. this.$toast.loading({
  401. message: "加载中"
  402. });
  403. let orderData = data;
  404. let that = this;
  405. let reqBody = {
  406. openId: this.$store.getters.openId, //openId
  407. imei: that.$route.query.imei, //imei
  408. iccid: that.$route.query.iccid,
  409. productId: this.payProductId, //套餐id
  410. pkId: data.packagesCardId,
  411. packageName: /* data.productModel + ',' + */data.packagesName, //套餐名字
  412. packagePayType: Number(this.payType), //支付类型
  413. packageIssue: this.packageIssue, //分期
  414. packagePrice: process.env.NODE_ENV === "production" ? data.packagesPrice * 100 : 1 //总金额单位为分,测试环境写死
  415. };
  416. this.$toast.clear();
  417. APICore.payLiveBaseDevice(reqBody)
  418. .then(res => {
  419. if (res.data.code === 104 || res.data.code === 106) {
  420. this.getAuth();
  421. setTimeout(() => {
  422. this.aliPay(orderData);
  423. }, 1000);
  424. }
  425. let alipayData = res.data.data.xmlStrMap;
  426. that.outTradeNo = alipayData.outTradeNo;
  427. let alipayForm = decodeURI(alipayData.payXmlStr);
  428. that.$store.commit("isFromWx", true);
  429. let alipayUserId = process.env.NODE_ENV === "production" ? 42 : 18;
  430. this.$router.replace({
  431. name: "payResult",
  432. query: {
  433. rechargeUrl:
  434. data.rechargeUrl ||
  435. `https://id.ssjlai.com/frontend/#/alipay`,
  436. outTradeNo: that.outTradeNo,
  437. price: that.price,
  438. alipayForm: alipayForm,
  439. iccid: that.$route.query.iccid,
  440. isAdmin: that.$route.query.isAdmin || false,
  441. serialNo: that.$route.query.imei,
  442. alipayUserId: alipayUserId,
  443. productId: this.payProductId
  444. }
  445. });
  446. })
  447. .catch(error => {
  448. console.log("error", error);
  449. this.$dialog.confirm({
  450. message: `${error.message}`,
  451. showCancelButton: false
  452. })
  453. })
  454. .finally(() => {
  455. this.$toast.clear();
  456. });
  457. },
  458. },
  459. computed: {
  460. isWeChat() {
  461. const ua = window.navigator.userAgent.toLowerCase();
  462. return /micromessenger/.test(ua);
  463. }
  464. },
  465. created() {
  466. // 套餐列表
  467. this.getDevicePayPackage();
  468. },
  469. }
  470. </script>
  471. <style lang="scss">
  472. .package-buy-container {
  473. .van-tabs {
  474. min-height: 100vh;
  475. background: #fafafa;
  476. &.blue {
  477. background: #1890ff !important;
  478. }
  479. .van-tabs__wrap {
  480. height: 50px;
  481. width: 100%;
  482. .van-tabs__nav {
  483. .van-tab {
  484. @include center();
  485. padding: 0;
  486. span {
  487. color: #333333;
  488. font-size: 16px;
  489. padding: 4px;
  490. }
  491. &.van-tab--active {
  492. span {
  493. color: #1890ff;
  494. font-weight: 500;
  495. font-size: 16px;
  496. }
  497. }
  498. }
  499. }
  500. }
  501. }
  502. }
  503. </style>
  504. <style scoped lang="scss">
  505. .package-buy-container {
  506. height: 100vh;
  507. overflow: hidden;
  508. .package-container {
  509. height: calc(100vh - 88px);
  510. background: #fafafa;
  511. .refuel-package {
  512. height: calc(100vh - 88px);
  513. padding: 10px 20px;
  514. overflow: scroll;
  515. .refuel-item {
  516. padding: 10px;
  517. margin-bottom: 20px;
  518. background-color: #fff;
  519. border-top-right-radius: 5px;
  520. border-bottom-right-radius: 5px;
  521. border-top-left-radius: 3px;
  522. border-bottom-left-radius: 3px;
  523. border-left: 3px solid #1890ff;
  524. box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px,
  525. rgba(60, 64, 67, 0.15) 0px 2px 6px 2px;
  526. p,
  527. span {
  528. font-size: 16px;
  529. }
  530. .title {
  531. text-align: left;
  532. padding-top: 10px;
  533. font-weight: 500;
  534. }
  535. .tips {
  536. margin-top: 10px;
  537. p {
  538. font-size: 14px;
  539. }
  540. }
  541. .bottom {
  542. padding-top: 20px;
  543. display: flex;
  544. justify-content: space-between;
  545. align-items: center;
  546. span {
  547. font-size: 20px;
  548. color: #fca842;
  549. font-weight: bold;
  550. .price-span {
  551. margin-left: 5px;
  552. font-size: 14px;
  553. }
  554. }
  555. .btn-button {
  556. height: 35px;
  557. width: 100px;
  558. @include center();
  559. background-color: #fca842;
  560. border-radius: 17px;
  561. p {
  562. font-size: 14px;
  563. color: #fff;
  564. }
  565. }
  566. }
  567. }
  568. }
  569. .base-package {
  570. height: calc(100vh - 88px);
  571. position: relative;
  572. .base-item {
  573. margin: 10px;
  574. z-index: 999;
  575. box-shadow: rgba(14, 30, 37, 0.12) 0 3px 5px 0,
  576. rgba(14, 30, 37, 0.32) 0 2px 16px 0;
  577. padding: 15px 10px;
  578. background-color: #fff;
  579. /* border-radius: 5px; */
  580. .title {
  581. display: flex;
  582. justify-content: flex-start;
  583. p {
  584. font-size: 16px;
  585. font-weight: bold;
  586. }
  587. }
  588. .details {
  589. display: flex;
  590. justify-content: flex-start;
  591. align-items: center;
  592. p {
  593. height: 40px;
  594. @include center();
  595. font-size: 14px;
  596. padding: 5px 0 5px 10px;
  597. }
  598. .total {
  599. font-size: 16px;
  600. padding: 0;
  601. }
  602. .orange {
  603. color: orange;
  604. }
  605. .large {
  606. font-size: 26px;
  607. margin: 0 2px;
  608. }
  609. .price {
  610. font-size: 16px;
  611. }
  612. /* .buy-btn {
  613. height: 30px;
  614. width: 100px;
  615. display: flex;
  616. justify-content: center;
  617. align-items: center;
  618. background: orange;
  619. border-radius: 45px;
  620. p {
  621. font-size: 16px;
  622. padding: 0;
  623. color: red;
  624. }
  625. } */
  626. }
  627. .remark {
  628. display: flex;
  629. justify-content: flex-start;
  630. p {
  631. font-size: 14px;
  632. padding: 5px 10px;
  633. /* font-weight: bold; */
  634. }
  635. }
  636. .package-buy {
  637. @include center();
  638. padding: 5px 8px;
  639. .buy-btn {
  640. height: 40px;
  641. width: 200px;
  642. padding: 0 5px;
  643. display: flex;
  644. justify-content: center;
  645. align-items: center;
  646. background: orange;
  647. border-radius: 20px;
  648. p {
  649. font-size: 16px;
  650. padding: 0;
  651. color: white;
  652. }
  653. }
  654. }
  655. .radios-con {
  656. /* padding: 20px 10px; */
  657. /* @include center(); */
  658. /* align-items: center; */
  659. padding: 10px 0 10px 10px;
  660. font-size: 14px;
  661. /* box-shadow: rgba(14, 30, 37, 0.12) 0 3px 5px 0,
  662. rgba(14, 30, 37, 0.32) 0 2px 16px 0; */
  663. img {
  664. height: 20px;
  665. width: 20px;
  666. margin: 2px;
  667. }
  668. .pay-type {
  669. text-align: left;
  670. p {
  671. font-size: 14px;
  672. padding: 0 0 10px 0;
  673. }
  674. }
  675. .radio-con {
  676. @include center();
  677. }
  678. .van-cell-text {
  679. display: flex;
  680. justify-content: flex-start;
  681. align-items: center;
  682. span {
  683. font-size: 14px;
  684. padding: 0 5px;
  685. }
  686. }
  687. }
  688. }
  689. .content {
  690. font-size: 14px;
  691. }
  692. }
  693. .data-null {
  694. height: calc(100vh - 88px);
  695. @include center();
  696. flex-direction: column;
  697. span {
  698. font-size: 14px;
  699. }
  700. }
  701. }
  702. }
  703. </style>