order.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. <template>
  2. <view class="pay">
  3. <view class="pay-info">
  4. <view class="goods-info">
  5. <image class="goods-img" :src="info.goodsPath" mode=""></image>
  6. <view class="info">
  7. <view class="goods-name">
  8. {{ info.goodsName }}
  9. </view>
  10. <view class="num">
  11. {{ info.goodsDescribe }}
  12. </view>
  13. <view class="priceColumn">
  14. <view class="price">
  15. <text class="unit">¥</text>{{ info.platformPrice?info.platformPrice.price:info.realPrice }}
  16. </view>
  17. <view class="goodsNum">
  18. x{{ realPay.reservePersons.length }}
  19. </view>
  20. </view>
  21. </view>
  22. </view>
  23. <view class="setoff">
  24. <view class="text">
  25. 出发时间
  26. </view>
  27. <view class="date">
  28. {{ reserveTimeFmt }}
  29. </view>
  30. </view>
  31. </view>
  32. <view class="appointment">
  33. <view class="title">
  34. 预定人信息
  35. </view>
  36. <view class="name">
  37. <view class="label">
  38. 姓名
  39. </view>
  40. <view class="value">
  41. {{ userInfo.name }}
  42. </view>
  43. </view>
  44. <view class="phone">
  45. <view class="label">
  46. 手机号
  47. </view>
  48. <view class="value">
  49. <text class="zone">+86</text>{{ userInfo.phoneNum }}
  50. </view>
  51. </view>
  52. <view class="desc">
  53. 预定人信息用于接受验证信息
  54. </view>
  55. </view>
  56. <view class="tour">
  57. <view class="title-top">
  58. <view class="title-text">
  59. 出游人信息
  60. </view>
  61. <view @click="addNewTourPerson" class="add">
  62. +添加
  63. </view>
  64. </view>
  65. <view v-for="(item, index) in realPay.reservePersons" :key="index" class="info-card">
  66. <view class="user-name">
  67. {{ item.userName }}
  68. <view class="tag">
  69. 出行人{{ index + 1 }}
  70. </view>
  71. </view>
  72. <view class="card-info">
  73. 身份证:{{ item.idCard }}
  74. </view>
  75. </view>
  76. </view>
  77. <view class="btn-box">
  78. <view class="total-price">
  79. <view class="label">
  80. 合计:
  81. </view>
  82. <view class="price">
  83. ¥ {{ payInfo.price }}
  84. </view>
  85. </view>
  86. <button class="btn" type="default" :loading="loading" @click="creat">提交订单</button>
  87. </view>
  88. <uni-calendar ref="calendar" :lunar="true" :showMonth="true" style="z-index: 999;" :insert="false"
  89. @confirm="confirm" />
  90. </view>
  91. </template>
  92. <script>
  93. import {
  94. studyCalculate, saveReserve
  95. } from '@/api/order.js';
  96. import {
  97. creat
  98. } from '@/api/goods.js'
  99. import {
  100. creatPayOrder,
  101. queryPayOrder,
  102. payDetails
  103. } from '@/api/payment.js'
  104. import { studyOrderCreat } from '@/api/study.js'
  105. import {
  106. calculate
  107. } from '@/api/order.js';
  108. import guid from '@/utils/guid.js'
  109. export default {
  110. data() {
  111. return {
  112. isVisual: false,//是否是虚拟商品
  113. loading: false,
  114. info: {},
  115. realPay: {
  116. goodsCouponName: '', //优惠券名
  117. couponGoodsLogId: '', //优惠券id
  118. goodsId: '', //商品id
  119. price: '', //支付价格
  120. offset: '', //实际抵扣值
  121. discount: '', //优惠券值
  122. condition: '', //优惠条件
  123. originalPrice: '', //原价
  124. reserveName: '',//预定人
  125. reservePhone: '',//预定人手机
  126. reserveTime: '',//预定时间
  127. reservePersons: [],//出游人
  128. },
  129. form: {
  130. account: ''
  131. },
  132. rules: {
  133. 'account': {
  134. type: 'string',
  135. required: true,
  136. message: '请输入充值账号',
  137. trigger: ['blur', 'change']
  138. },
  139. },
  140. query: {
  141. "msgType": "wx.unifiedOrder",
  142. "orderDesc": "测试",
  143. "orderNo": "",
  144. "channel": 'ZhongShu',
  145. "subOpenId": "",
  146. "userId": ""
  147. },
  148. // 支付信息
  149. payData: {
  150. },
  151. userInfo: {}
  152. }
  153. },
  154. computed: {
  155. // 正式支付时的信息
  156. payInfo() {
  157. return {
  158. goodsCouponName: this.realPay.goodsCouponName || '', //优惠券名
  159. couponGoodsLogId: this.info.couponId, //优惠券id
  160. goodsId: this.realPay.goodsId || this.info.goodsId, //商品id
  161. price: this.realPay.price, //支付价格
  162. offset: this.realPay.offset, //实际抵扣值
  163. discount: this.realPay.discount || 0, //优惠券值
  164. condition: this.realPay.condition || '', //优惠条件
  165. originalPrice: this.realPay.originalPrice, //原价
  166. }
  167. },
  168. reserveTimeFmt() {
  169. const date = new Date(this.info.reserveTime)
  170. // const year = date.getFullYear()
  171. const month = date.getMonth() + 1
  172. const day = date.getDate()
  173. return `${month}月${day}日`
  174. }
  175. },
  176. methods: {
  177. // 增加新的出游人
  178. addNewTourPerson() {
  179. uni.navigateTo({
  180. url: '/study/tourList/list'
  181. })
  182. },
  183. openCalendar() {
  184. this.$refs.calendar.open();
  185. },
  186. confirm(e) {
  187. console.log(e);
  188. },
  189. calculate(goodsId, shopId) {
  190. uni.showLoading({
  191. title: '计算中'
  192. })
  193. return new Promise((resolve, reject) => {
  194. calculate({
  195. couponId: this.info.couponId,
  196. "goodsId": goodsId,
  197. "shopId": shopId,
  198. "userId": JSON.parse(uni.getStorageSync('userInfo')).userId,
  199. platform:'p-0002',
  200. "number": this.realPay.reservePersons.length
  201. }).then(res => {
  202. uni.hideLoading()
  203. if (res.state == 'Success') {
  204. const reservePersons = this.realPay.reservePersons
  205. this.realPay = res.content
  206. this.realPay.reservePersons = reservePersons
  207. this.info.couponId = res.content.couponId
  208. }
  209. })
  210. })
  211. },
  212. choose() {
  213. let that = this
  214. uni.navigateTo({
  215. url: './coupon?couponId=' + this.realPay.couponLogId,
  216. success: function (res) {
  217. // 通过eventChannel向被打开页面传送数据
  218. res.eventChannel.emit('pay', that.info)
  219. }
  220. })
  221. },
  222. tempCreate() {
  223. uni.reLaunch({
  224. url: '/study/pay/orderPay'
  225. })
  226. },
  227. //创建订单
  228. creat() {
  229. if (this.loading) return
  230. if (this.realPay.reservePersons.length == 0) {
  231. uni.showToast({
  232. title: '请添加出游人',
  233. icon: 'none'
  234. })
  235. return
  236. }
  237. const user = JSON.parse(uni.getStorageSync('userInfo'))
  238. this.realPay.reserveName = user.name
  239. this.realPay.reservePhone = user.phoneNum
  240. this.realPay.reserveTime = this.info.reserveTime
  241. this.loading = true
  242. uni.showLoading({
  243. title: '支付中'
  244. })
  245. let that = this
  246. if (!this.payData.timeStamp) {
  247. // 处理扩展字段 暂时只有研学商品和视频会员 视频会员是字符串的JSON 研学是字符串
  248. let extend
  249. try {
  250. if (JSON.parse(this.info.extend)) {
  251. extend = this.info.extend
  252. }
  253. } catch (e) {
  254. extend = this.info.reservationTime || ''
  255. }
  256. studyOrderCreat({
  257. discountId: (this.payInfo.couponGoodsLogId || this.payInfo.couponGoodsLogId == -1) ? [this
  258. .payInfo.couponGoodsLogId
  259. ] : [],
  260. extend,
  261. channel: 'ZhongShu',
  262. goodsList: this.info.goodsId ? [this.info.goodsId] : [],
  263. idempotent: guid(),
  264. reserveTime: this.info.reserveTime,
  265. shopId: this.info.shopId
  266. }).then(res => {
  267. this.loading = false
  268. if (res.state == 'Success') {
  269. if (!this.payInfo.price) { //价格为0
  270. uni.hideLoading()
  271. uni.reLaunch({
  272. url: '/my/order/index'
  273. })
  274. } else {
  275. this.query.orderNo = res.content.orderNo
  276. this.query.subOpenId = JSON.parse(uni.getStorageSync('userInfo')).openId
  277. this.query.orderDesc = this.info.goodsName
  278. creatPayOrder(this.query).then(data => {
  279. that.payData = JSON.parse(data.content.miniPayRequest)
  280. if (data.content.miniPayRequest == null) return uni.hideLoading()
  281. saveReserve({
  282. ...this.realPay,
  283. orderNo: this.query.orderNo,
  284. goodsId: this.info.goodsId,
  285. }).then(res => {
  286. if (res.state == 'Success') {
  287. uni.requestPayment({
  288. "provider": "wxpay",
  289. "orderInfo": that.payData,
  290. "appid": that.payData
  291. .appId, // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
  292. "paySign": that.payData.paySign,
  293. "nonceStr": that.payData.nonceStr, // 随机字符串
  294. "package": that.payData.package, // 固定值
  295. // "prepayid": that.payData.package, // 统一下单订单号
  296. "timeStamp": that.payData.timeStamp, // 时间戳(单位:秒)
  297. "signType": that.payData.signType, //签名算法
  298. success(msg) {
  299. console.log('msg', that.query.orderNo);
  300. queryPayOrder(that.query.orderNo).then(res1 => {
  301. if (res1.state == 'Success') {
  302. uni.hideLoading()
  303. uni.reLaunch({
  304. url: '/my/order/index'
  305. })
  306. }
  307. })
  308. },
  309. fail(e) {
  310. console.log('err', e);
  311. that.loading = false
  312. uni.hideLoading()
  313. uni.showToast({
  314. title: '取消支付',
  315. icon: 'fail'
  316. })
  317. // 取消支付后,获取支付信息以备再次支付
  318. payDetails(that.query.orderNo).then(r => {
  319. if (r.state == 'Success') {
  320. that.payData = JSON.parse(r.content.miniPayRequest)
  321. }
  322. })
  323. }
  324. })
  325. } else {
  326. uni.showToast({
  327. title: res.msg,
  328. icon: 'none'
  329. })
  330. that.loading = false
  331. }
  332. })
  333. })
  334. }
  335. }
  336. })
  337. } else { // 取消支付后再次支付
  338. uni.requestPayment({
  339. "provider": "wxpay",
  340. "orderInfo": that.payData,
  341. "appid": that.payData.appId, // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
  342. "paySign": that.payData.paySign,
  343. "nonceStr": that.payData.nonceStr, // 随机字符串
  344. "package": that.payData.package, // 固定值
  345. // "prepayid": that.payData.package, // 统一下单订单号
  346. "timeStamp": that.payData.timeStamp, // 时间戳(单位:秒)
  347. "signType": that.payData.signType, //签名算法
  348. success(msg) {
  349. console.log('msg', msg);
  350. queryPayOrder(that.query.orderNo).then(res1 => {
  351. if (res1.state == 'Success') {
  352. uni.hideLoading()
  353. uni.reLaunch({
  354. url: '/my/order/index'
  355. })
  356. }
  357. })
  358. },
  359. fail(e) {
  360. that.loading = false
  361. uni.hideLoading()
  362. uni.showToast({
  363. title: '取消支付',
  364. icon: 'fail'
  365. })
  366. // 取消支付后,获取支付信息以备再次支付
  367. payDetails(that.query.orderNo).then(r => {
  368. if (r.state == 'Success') {
  369. that.payData = JSON.parse(r.content.miniPayRequest)
  370. }
  371. })
  372. console.log('err', e);
  373. }
  374. })
  375. }
  376. }
  377. },
  378. onReady() {
  379. },
  380. onLoad() {
  381. let userInfo = JSON.parse(uni.getStorageSync('userInfo'))
  382. this.query.userId = userInfo.userId
  383. this.userInfo = userInfo
  384. let that = this
  385. const eventChannel = this.getOpenerEventChannel();
  386. eventChannel.on('pay', function (data) {
  387. that.info = data
  388. try {
  389. let extend = JSON.parse(that.info.extend)
  390. if (extend.account) {
  391. that.isVisual = true
  392. that.form.account = extend.account
  393. }
  394. } catch (e) {
  395. //TODO handle the exception
  396. }
  397. console.log('data', data);
  398. // that.calculate(that.info.goodsId, that.info.shopId)
  399. })
  400. uni.$on("updateData", (data) => {
  401. this.realPay.reservePersons = data
  402. that.calculate(that.info.goodsId, that.info.shopId)
  403. this.$forceUpdate()
  404. })
  405. },
  406. destoryed() {
  407. uni.$off("updateData")
  408. }
  409. }
  410. </script>
  411. <style lang="scss">
  412. .pay {
  413. background: #F9F9F9;
  414. min-height: 100vh;
  415. padding-top: 20rpx;
  416. .shop-info {
  417. margin: 0 30rpx 20rpx;
  418. width: 690rpx;
  419. padding: 24rpx;
  420. box-sizing: border-box;
  421. background: #FFFFFF;
  422. border-radius: 16rpx 16rpx 16rpx 16rpx;
  423. .shop-name {
  424. color: #181818;
  425. font-size: 32rpx;
  426. }
  427. .address {
  428. color: #999999;
  429. font-size: 24rpx;
  430. margin-top: 12rpx;
  431. }
  432. }
  433. .pay-info {
  434. margin: 0 30rpx;
  435. background: #FFFFFF;
  436. border-radius: 16rpx 16rpx 16rpx 16rpx;
  437. padding: 24rpx;
  438. .goods-info {
  439. display: flex;
  440. margin-bottom: 26rpx;
  441. .goods-img {
  442. width: 164rpx;
  443. height: 164rpx;
  444. border-radius: 16rpx;
  445. }
  446. .info {
  447. margin-left: 28rpx;
  448. flex: 1;
  449. .goods-name {
  450. font-weight: bold;
  451. color: #181818;
  452. font-size: 32rpx;
  453. width: 100%;
  454. word-break: break-all;
  455. text-overflow: ellipsis;
  456. overflow: hidden;
  457. display: -webkit-box;
  458. -webkit-box-orient: vertical;
  459. -webkit-line-clamp: 2;
  460. /* 这里是超出几行省略 */
  461. }
  462. .num {
  463. color: #999999;
  464. font-size: 24rpx;
  465. margin-top: 16rpx;
  466. }
  467. .priceColumn {
  468. display: flex;
  469. justify-content: space-between;
  470. align-items: center;
  471. margin-top: 30rpx;
  472. .price {
  473. font-weight: bold;
  474. color: #FF4D3A;
  475. font-size: 32rpx;
  476. .unit {
  477. font-size: 20rpx;
  478. }
  479. }
  480. .goodsNum {
  481. font-size: 24rpx;
  482. color: #AAAAAA;
  483. }
  484. }
  485. }
  486. }
  487. .setoff {
  488. border-top: 1px solid #F0F0F0;
  489. display: flex;
  490. justify-content: space-between;
  491. align-items: center;
  492. font-size: 24rpx;
  493. padding-top: 24rpx;
  494. .text {
  495. color: #222222;
  496. }
  497. .date {
  498. color: #AAAAAA;
  499. }
  500. }
  501. }
  502. .appointment {
  503. padding: 24rpx;
  504. background: #FFFFFF;
  505. margin: 20rpx 30rpx;
  506. border-radius: 16rpx 16rpx 16rpx 16rpx;
  507. .title {
  508. font-size: 28rpx;
  509. color: #222222;
  510. font-weight: bold;
  511. margin-bottom: 24rpx;
  512. }
  513. .name {
  514. border-top: 1px solid #F0F0F0;
  515. padding: 24rpx 0;
  516. display: flex;
  517. .label {
  518. font: 24rpx;
  519. color: #222222;
  520. width: 152rpx;
  521. }
  522. .value {
  523. font-size: 28rpx;
  524. font-weight: bold;
  525. }
  526. }
  527. .phone {
  528. border-top: 1px solid #F0F0F0;
  529. padding: 24rpx 0;
  530. display: flex;
  531. .label {
  532. font: 24rpx;
  533. color: #222222;
  534. width: 152rpx;
  535. }
  536. .value {
  537. font-size: 28rpx;
  538. font-weight: bold;
  539. .zone {
  540. padding-right: 22rpx;
  541. margin-right: 20rpx;
  542. border-right: 1px solid #F0F0F0;
  543. }
  544. }
  545. }
  546. .desc {
  547. border-top: 1px solid #F0F0F0;
  548. padding-top: 24rpx;
  549. color: #AAAAAA;
  550. font-size: 24rpx;
  551. }
  552. }
  553. .tour {
  554. padding: 24rpx;
  555. background: #FFFFFF;
  556. margin: 0 30rpx;
  557. border-radius: 16rpx 16rpx 16rpx 16rpx;
  558. .title-top {
  559. display: flex;
  560. justify-content: space-between;
  561. align-items: center;
  562. .title-text {
  563. font-size: 28rpx;
  564. font-weight: bold;
  565. color: #222222;
  566. }
  567. .add {
  568. font-size: 24rpx;
  569. color: #3B83FF;
  570. }
  571. margin-bottom: 24rpx;
  572. }
  573. .info-card {
  574. border-top: 1px solid #F0F0F0;
  575. padding: 24rpx 0;
  576. .user-name {
  577. font-size: 28rpx;
  578. font-weight: bold;
  579. color: #222222;
  580. display: flex;
  581. align-items: center;
  582. .tag {
  583. margin-left: 20rpx;
  584. color: #222222;
  585. font-size: 20rpx;
  586. background-color: #F0F0F0;
  587. border-radius: 18rpx;
  588. line-height: 20rpx;
  589. padding: 2rpx 12rpx;
  590. }
  591. }
  592. .card-info {
  593. margin: 20rpx 0;
  594. font-size: 24rpx;
  595. color: #222222;
  596. }
  597. }
  598. }
  599. .btn-box {
  600. position: fixed;
  601. bottom: 0%;
  602. left: 0%;
  603. width: 100%;
  604. display: flex;
  605. align-items: center;
  606. justify-content: space-between;
  607. box-sizing: border-box;
  608. padding: 10rpx 30rpx env(safe-area-inset-bottom);
  609. border-top: 1rpx solid #EEEEEE;
  610. .total-price {
  611. display: flex;
  612. align-items: center;
  613. .label {
  614. color: #181818;
  615. font-size: 28rpx;
  616. }
  617. .price {
  618. font-size: 36rpx;
  619. font-weight: 800;
  620. color: #FF4848;
  621. margin-left: 10rpx;
  622. }
  623. }
  624. .btn {
  625. width: 280rpx;
  626. height: 80rpx;
  627. line-height: 80rpx;
  628. text-align: center;
  629. background: #3B83FF;
  630. box-shadow: inset 0rpx 6rpx 12rpx 2rpx rgba(255, 255, 255, 0.16);
  631. border-radius: 46rpx 46rpx 46rpx 46rpx;
  632. font-weight: 800;
  633. color: #FFFFFF;
  634. font-size: 28rpx;
  635. margin: 0;
  636. }
  637. }
  638. }
  639. </style>