天波h5前端应用

585 Zeilen
22KB

  1. <!--
  2. * @Date: 2022-03-29 16:57:58
  3. * @LastEditors: JinxChen
  4. * @LastEditTime: 2023-02-25 18:14:46
  5. * @FilePath: \TelpoH5FrontendWeb\src\views\package-list\index.vue
  6. * @description: TODO 小台风充值h5
  7. -->
  8. <template>
  9. <div class="package-list-container">
  10. <van-nav-bar :left-arrow="false" :border="true">
  11. <template #title>
  12. <h5 style="font-size: 16px">{{topupTitle}}</h5>
  13. </template>
  14. </van-nav-bar>
  15. <!-- 灰色线条 -->
  16. <div class="gray-line"></div>
  17. <!-- 套餐说明 -->
  18. <div class="order-description" v-show="packageOrderList.length">
  19. <h5>套餐说明:</h5>
  20. <h5>每月200分钟通话时长,1G流量。</h5>
  21. </div>
  22. <!-- 套餐列表 -->
  23. <div class="topup-container">
  24. <div class="main">
  25. <!-- <div class="tips" v-show="!isCanTopup">
  26. <p>非本公司发行的SIM卡,</p>
  27. <p>无此服务。</p>
  28. <div class="cancel-button" @click="onNavBack">返回</div>
  29. </div> -->
  30. <!-- 无套餐时显示 -->
  31. <div class="noData_container" v-show="packageOrderList.length === 0 && isShowNoData">
  32. <p>暂无相关套餐数据,请您联系管理员~</p>
  33. </div>
  34. <!-- 套餐订购 -->
  35. <div
  36. class="package-order-container"
  37. v-for="(item, index) in packageOrderList"
  38. :key="index"
  39. >
  40. <!-- 推荐 -->
  41. <div class="recom" v-show="index === 0">
  42. <div class="shape"></div>
  43. <div class="square">
  44. <p>推荐</p>
  45. </div>
  46. </div>
  47. <!-- 套餐内容 -->
  48. <div class="order-content">
  49. <div class="title">
  50. <p>{{item.packageName}}<!-- :{{(item.packagePrice/item.packageIssue).toFixed(0)}}元/月 --></p>
  51. </div>
  52. <div class="details">
  53. <p>
  54. 低至
  55. <span
  56. class="orange"
  57. >{{(item.packagePrice/(item.packageIssue === 0 ? 1: item.packageIssue)).toFixed(0)}}</span>元/月
  58. </p>
  59. <p class="orange">
  60. <span class="orange price">{{item.packagePrice}}</span>
  61. </p>
  62. <div class="buy-btn" @click="onBuy(item)">
  63. <p>话费充值</p>
  64. </div>
  65. </div>
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. </template>
  72. <script>
  73. import APIWx from "@/api/wx";
  74. import { APIPay } from "@/api/pay";
  75. let wx = require("weixin-js-sdk"); // TODO 再封装,可拦截错误提示等操作
  76. import APICore from "@/api/core";
  77. import axios from "axios";
  78. import { isNotNull } from "@/utils/index";
  79. export default {
  80. name: "packageList",
  81. data() {
  82. return {
  83. topupTitle: "请选择套餐充值激活电话卡",
  84. wxItem: "",
  85. packageOrderList: [],
  86. outTradeNo: "", //订单号
  87. price: "", //价格,
  88. isShowNoData: false, //是否显示无套餐内容, 默认false
  89. params: {
  90. imei: '',
  91. iccid: '',
  92. manufactorId: '',
  93. appId: '',
  94. },
  95. };
  96. },
  97. computed: {
  98. isCanTopup() {
  99. return this.$route.query.isCanTopup;
  100. },
  101. serialNo() {
  102. return this.$route.query.serialNo;
  103. }
  104. },
  105. created() {
  106. this.getParams();
  107. this.getWxAutograph();
  108. this.getLiveBasePackage();
  109. },
  110. /* mounted() {
  111. this.getParams();
  112. this.getWxAutograph();
  113. this.getLiveBasePackage();
  114. }, */
  115. methods: {
  116. // 根据code获取openId
  117. getOpenId() {
  118. let code = this.$store.getters.wxAuthCode;
  119. let openId = this.$store.getters.openId;
  120. if(isNotNull(openId)) {
  121. console.log("已经存在openId");
  122. } else {
  123. APIPay.getOpenId(code).then(res => {
  124. let data= res.data;
  125. if(data.code === 20000) {
  126. this.$store.commit("openId", data.data.openId);
  127. }
  128. })
  129. }
  130. },
  131. // 获取b端接口的token
  132. getAuth() {
  133. let manufactorId = "5bf13062-a41e-4d00-ba14-1101aad12650";
  134. APICore.getAuth({ manufactorId: manufactorId }).then(res => {
  135. this.$store.commit("gatewayToken", res.data.data);
  136. });
  137. },
  138. // 获取url传过来的参数
  139. getParams() {
  140. let params = this.$route.query;
  141. if (params) {
  142. let url = window.location.href.split("?code=")[1];
  143. if ( isNotNull(url) || window.location.href.indexOf("code") > -1) {
  144. let timeStamp = new Date().getTime();
  145. let code = url.split("&")[0];
  146. if (isNotNull(code)) {
  147. this.$store.commit("wxAuthCode", `${code}`);
  148. this.getOpenId();
  149. }
  150. }
  151. this.params = {...params};
  152. }
  153. },
  154. // 获取基本套餐信息
  155. getLiveBasePackage() {
  156. this.$toast.loading({
  157. message: "获取套餐中",
  158. duration: 1500
  159. });
  160. let reqBody = {
  161. manufactorId:"",
  162. productModelId:0,
  163. iccid:"",
  164. pageNumber:1,
  165. begNumber:20
  166. }
  167. APICore.cardPackageList(reqBody)
  168. .then(res => {
  169. console.log("data", res.data);
  170. if (res.data.code === 106 || res.data.code === 104) {
  171. // token过期
  172. this.getAuth();
  173. setTimeout(() => {
  174. this.getLiveBasePackage();
  175. }, 1500);
  176. } else if (res.data.code === 0 && res.data.data === null) {
  177. this.isShowNoData = true;
  178. }else {
  179. let data = res.data.data.list;
  180. if(data === null) {
  181. this.isShowNoData = true;
  182. } else {
  183. this.packageOrderList = data.filter(item => {
  184. return item.pechargeUrl === '1629405716684029952' || item.pechargeUrl === '1629405558344859648';
  185. });
  186. console.log("套餐数据::", data);
  187. }
  188. }
  189. this.$toast.success({
  190. message: "成功获取套餐",
  191. duration: 1500
  192. });
  193. })
  194. .catch(error => {
  195. this.$dialog.confirm({
  196. title: "获取套餐数据失败",
  197. message: error
  198. });
  199. })
  200. .finally(() => {
  201. setTimeout(() => {
  202. this.$toast.clear();
  203. }, 1500);
  204. });
  205. },
  206. // 返回
  207. onNavBack() {
  208. },
  209. // 获取微信jssdk
  210. getWxAutograph() {
  211. let that = this;
  212. return new Promise((resolve, reject) => {
  213. APIWx.createJSSDK({
  214. sUrl: window.location.href.split("#")[0],
  215. userId: '',
  216. appId: this.params.appId
  217. })
  218. .then(res => {
  219. let item = res.data.data;
  220. this.wxItem = res.data.data;
  221. wx.config({
  222. debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  223. appId: item.appId, // 必填,公众号的唯一标识
  224. timestamp: item.timeStamp, // 必填,生成签名的时间戳
  225. nonceStr: item.nonceStr, // 必填,生成签名的随机串
  226. signature: item.signature, // 必填,签名
  227. jsApiList: ["chooseWXPay"] // 必填,需要使用的JS接口列表
  228. });
  229. wx.ready(() => {
  230. resolve(true);
  231. /* that.canScan = true; */
  232. });
  233. })
  234. .catch(err => {
  235. reject(false);
  236. console.log(err);
  237. });
  238. });
  239. },
  240. // 话费充值
  241. onBuy(data) {
  242. let payType = data.packagePayType;
  243. this.price = data.packagePrice;
  244. // 需要区分是要用微信支付还是支付宝花呗支付
  245. if (payType === 2) {
  246. this.aliPay(data);
  247. } else {
  248. let openId = this.$store.getters.openId;
  249. if(openId === null || openId === 'null') {
  250. this.$dialog.confirm({
  251. message: '微信支付在调整中,请选择其它支付方式'
  252. })
  253. } else {
  254. this.wxPay(data);
  255. console.log("openid为空");
  256. }
  257. }
  258. },
  259. // 微信支付
  260. wxPay(data) {
  261. this.$toast.loading({
  262. message: "加载中"
  263. });
  264. console.log("微信支付", data);
  265. let orderData = data;
  266. let reqBody = {
  267. openId: this.$store.getters.openId, //openId
  268. imei: this.params.imei, //imei
  269. productId: data.pechargeUrl, //套餐id
  270. packageName: data.productModel + ',' + data.packageName, //套餐名字
  271. packagePayType: data.packagePayType, //支付类型
  272. packageIssue: data.packageIssue, //分期
  273. packagePrice: process.env.NODE_ENV === "production" ? data.packagePrice * 100 : 1 //总金额单位为分,测试环境写死
  274. };
  275. APICore.payLiveBaseDevice(reqBody)
  276. .then(res => {
  277. this.$toast.clear();
  278. if (res.data.code === 104 || res.data.code === 106) {
  279. this.getAuth();
  280. setTimeout(() => {
  281. this.wxPay(orderData);
  282. }, 1000);
  283. }
  284. let that = this;
  285. let wxData = res.data.data;
  286. that.outTradeNo = wxData.out_trade_no;
  287. console.log("wxData", wxData);
  288. // 本地测试
  289. /* that.$router.push({
  290. name: "payResult",
  291. query: {
  292. outTradeNo: that.outTradeNo,
  293. price: that.price,
  294. rechargeUrl: data.rechargeUrl || '',
  295. iccid: this.params.iccid,
  296. isAdmin: this.$route.query.isAdmin,
  297. serialNo: this.params.imei,
  298. routerName: this.params.routerName,
  299. issue: data.packageIssue
  300. }
  301. }); */
  302. wx.chooseWXPay({
  303. timestamp: wxData.timeStamp, // 支付签名时间戳,注意微信 jssdk 中的所有使用 timestamp 字段均为小写。但最新版的支付后台生成签名使用的 timeStamp 字段名需大写其中的 S 字符
  304. nonceStr: wxData.nonceStr, // 支付签名随机串,不长于 32 位
  305. package: wxData.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
  306. signType: wxData.signType, // 微信支付V3的传入 RSA ,微信支付V2的传入格式与V2统一下单的签名格式保持一致
  307. paySign: wxData.paySign, // 支付签名
  308. success: function(res) {
  309. // 支付成功后的回调函数
  310. that.$router.push({
  311. name: "payResult",
  312. query: {
  313. outTradeNo: that.outTradeNo,
  314. price: that.price,
  315. rechargeUrl: data.rechargeUrl,
  316. iccid: that.params.iccid,
  317. isAdmin: that.$route.query.isAdmin || false,
  318. serialNo: that.params.imei,
  319. issue: data.packageIssue
  320. }
  321. });
  322. console.log("微信支付成功::", res);
  323. },
  324. fail: err => {
  325. console.log("支付出错了::", err);
  326. that.$dialog.confirm({
  327. title: "支付失败",
  328. message: "出错了,请您重新进入"
  329. });
  330. },
  331. cancel: function(err) {
  332. // 用户取消支付
  333. that.$dialog.confirm({
  334. message: "您取消了支付"
  335. });
  336. console.log("用户取消了支付::", err);
  337. }
  338. });
  339. })
  340. .catch(error => {
  341. console.log("error", error);
  342. })
  343. .finally(() => {
  344. this.$toast.clear();
  345. });
  346. },
  347. // 跳转到支付宝花呗外部链接
  348. aliPay(data) {
  349. console.log("选择了支付宝::", data);
  350. this.$toast.loading({
  351. message: "加载中"
  352. });
  353. let orderData = data;
  354. let reqBody = {
  355. openId: this.$store.getters.openId, //openId
  356. imei: this.params.imei, //imei
  357. productId: data.pechargeUrl, //套餐id
  358. packageName: data.productModel + ',' + data.packageName, //套餐名字
  359. packagePayType: data.packagePayType, //支付类型
  360. packageIssue: data.packageIssue, //分期
  361. packagePrice: process.env.NODE_ENV === "production" ? data.packagePrice * 100 : 1 //总金额单位为分,测试环境写死
  362. };
  363. this.$toast.clear();
  364. APICore.payLiveBaseDevice(reqBody)
  365. .then(res => {
  366. if (res.data.code === 104 || res.data.code === 106) {
  367. this.getAuth();
  368. setTimeout(() => {
  369. this.aliPay(orderData);
  370. }, 1000);
  371. }
  372. let that = this;
  373. let alipayData = res.data.data.xmlStrMap;
  374. that.outTradeNo = alipayData.outTradeNo;
  375. let alipayForm = decodeURI(alipayData.payXmlStr);
  376. that.$store.commit("isFromWx", true);
  377. let alipayUserId = process.env.NODE_ENV === "production" ? 42 : 18
  378. this.$router.push({
  379. name: "payResult",
  380. query: {
  381. rechargeUrl:
  382. data.rechargeUrl ||
  383. `https://id.ssjlai.com/frontend/#/alipay`,
  384. outTradeNo: that.outTradeNo,
  385. price: that.price,
  386. alipayForm: alipayForm,
  387. iccid: that.params.iccid,
  388. isAdmin: that.$route.query.isAdmin || false,
  389. serialNo: that.params.imei,
  390. alipayUserId: alipayUserId,
  391. productId: data.pechargeUrl
  392. }
  393. });
  394. })
  395. .catch(error => {
  396. console.log("error", error);
  397. })
  398. .finally(() => {
  399. this.$toast.clear();
  400. });
  401. },
  402. // 转换类型
  403. shiftType(type) {
  404. switch (type) {
  405. case "微信":
  406. return "1"
  407. /* break; */
  408. case "支付宝花呗":
  409. return "2"
  410. /* break; */
  411. }
  412. }
  413. }
  414. };
  415. </script>
  416. <style lang="scss">
  417. .van-nav-bar__title {
  418. max-width: 80% !important;
  419. font-size: 16px;
  420. }
  421. </style>
  422. <style lang="scss" scoped>
  423. .package-list-container {
  424. background-color: white;
  425. height: 100vh;
  426. .topup-container {
  427. display: flex;
  428. justify-content: space-between;
  429. align-items: center;
  430. flex-direction: column;
  431. background-color: white;
  432. overflow: scroll;
  433. height: calc(100vh - 4rem);
  434. .main {
  435. padding: 0 10px;
  436. display: flex;
  437. justify-content: center;
  438. align-items: center;
  439. flex-direction: column;
  440. .tips {
  441. padding: 10px;
  442. }
  443. .noData_container {
  444. margin: 100px auto 0;
  445. height: 120px;
  446. /* background: url(../../../assets/img/news-noData.png) center no-repeat; */
  447. background-size: 165px 120px;
  448. display: flex;
  449. justify-content: center;
  450. align-items: flex-end;
  451. font-size: 16px;
  452. color: #999;
  453. p {
  454. font-size: 16px;
  455. }
  456. /* @include colorAndFont(#999, 28); */
  457. }
  458. p {
  459. padding: 10px;
  460. font-size: 16px;
  461. }
  462. .cancel-button {
  463. width: 30vw;
  464. border-radius: 5px;
  465. background-color: #2599ff;
  466. color: #fff;
  467. min-height: 40px;
  468. display: flex;
  469. justify-content: center;
  470. align-items: center;
  471. font-size: 16px;
  472. }
  473. .package-order-container {
  474. position: relative;
  475. height: 120px;
  476. width: 300px;
  477. padding: 5px 20px;
  478. margin: 10px 0;
  479. z-index: 999;
  480. box-shadow: rgba(14, 30, 37, 0.12) 0 3px 5px 0,
  481. rgba(14, 30, 37, 0.32) 0 2px 16px 0;
  482. .recom {
  483. position: absolute;
  484. top: -7px;
  485. left: -26px;
  486. border-style: solid;
  487. border-width: 0 40px 40px;
  488. border-color: transparent transparent red;
  489. transform: rotate(-45deg);
  490. text-align: center;
  491. z-index: 9999;
  492. p {
  493. padding: 0;
  494. color: white;
  495. font-size: 14px;
  496. }
  497. .shape {
  498. position: absolute;
  499. top: -1px;
  500. left: -21px;
  501. border-style: solid;
  502. border-width: 0 21px 21px;
  503. border-color: transparent transparent white;
  504. }
  505. .square {
  506. height: 15px;
  507. width: 35px;
  508. position: absolute;
  509. top: 21px;
  510. left: -20px;
  511. background: red;
  512. font-size: 14px;
  513. }
  514. }
  515. .order-content {
  516. padding-top: 25px;
  517. .title {
  518. display: flex;
  519. justify-content: flex-start;
  520. p {
  521. font-size: 14px;
  522. font-weight: bold;
  523. }
  524. }
  525. .details {
  526. display: flex;
  527. justify-content: space-between;
  528. align-items: center;
  529. p {
  530. font-size: 14px;
  531. }
  532. .orange {
  533. color: orange;
  534. }
  535. .price {
  536. font-size: 14px;
  537. font-weight: bold;
  538. padding-right: 5px;
  539. }
  540. .buy-btn {
  541. height: 30px;
  542. width: 90px;
  543. display: flex;
  544. justify-content: center;
  545. align-items: center;
  546. background: orange;
  547. border-radius: 20px;
  548. p {
  549. padding: 0;
  550. color: white;
  551. }
  552. }
  553. }
  554. }
  555. .content {
  556. font-size: 14px;
  557. }
  558. }
  559. }
  560. }
  561. .gray-line {
  562. height: 10px;
  563. width: 100%;
  564. background: #f2f4f5;
  565. }
  566. .order-description {
  567. height: 60px;
  568. display: flex;
  569. justify-content: flex-start;
  570. align-items: flex-start;
  571. flex-direction: column;
  572. padding: 5px 0 10px 25px;
  573. h5 {
  574. font-size: 14px;
  575. padding: 10px 0 0 0;
  576. }
  577. }
  578. }
  579. </style>