index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. <template>
  2. <view class="pay-popup popup" catchtouchmove="true" :class="(value && complete) ? 'show' : 'none'"
  3. @touchmove.stop.prevent="moveHandle">
  4. <!-- 页面内容开始 -->
  5. <view class="mask" @click="close('mask')"></view>
  6. <!-- 页面开始 -->
  7. <view class="confirm" v-if="!showPayPopup">
  8. <view class="layer attr-content" :style="'border-radius: 10rpx 10rpx 0 0;'">
  9. <view class="specification-wrapper">
  10. <scroll-view class="specification-wrapper-content" scroll-y="true">
  11. <view class="specification-header">
  12. <view class="specification-name">支付确认</view>
  13. </view>
  14. <view class="specification-content">
  15. <view v-if="payInfo.isLogin && ((parseFloat(payInfo.totalAmount) - (parseFloat(payInfo.totalAmount) * parseFloat(payInfo.payDiscount))) > 0)" class="pay-item">
  16. <view class="item-point">
  17. <view class="title">
  18. <text class="iconfont icon-success"></text>
  19. <text v-if="payInfo.payDiscount < 1" class="point-amount">会员{{parseFloat(payInfo.payDiscount * 10).toFixed(2)}}折优惠<text class="amount">¥{{(parseFloat(payInfo.totalAmount) - ((parseFloat(payInfo.totalAmount) * parseFloat(payInfo.payDiscount)))).toFixed(2)}}</text></text>
  20. </view>
  21. </view>
  22. </view>
  23. <view v-if="payInfo.isLogin && payInfo.pointAmount >= 0.01 && payInfo.canUsedAsMoney == 'true'" class="pay-item">
  24. <view class="item-point">
  25. <view class="title">
  26. <text class="iconfont icon-success"></text>
  27. <text v-if="payInfo.usePoint > 0" class="point-amount">使用{{ payInfo.usePoint.toFixed(0) }}积分抵扣</text>
  28. <text v-if="payInfo.usePoint > 0" class="amount">¥{{ parseFloat(payInfo.pointAmount).toFixed(2) }}</text>
  29. <text v-if="payInfo.usePoint < 1" class="point-amount">不使用积分抵扣</text>
  30. <text v-if="payInfo.maxPoint > 0" class="modify" @click="modifyPoint">修改>></text>
  31. </view>
  32. </view>
  33. </view>
  34. <view v-if="!payInfo.isLogin && payInfo.maxPoint < 1" class="pay-item">
  35. <view class="item-point">
  36. <view class="title">
  37. <text class="iconfont icon-success"></text>
  38. <text>会员可使用积分进行抵扣哦~</text>
  39. <text class="modify" @click="onGetLogin">去登录>></text>
  40. </view>
  41. </view>
  42. </view>
  43. <view v-if="payInfo.isLogin && payInfo.couponInfo !== null" class="pay-item">
  44. <view class="item-point">
  45. <view class="title">
  46. <text class="iconfont icon-success"></text>
  47. <text v-if="payInfo.couponAmount > 0" class="point-amount">使用卡券抵扣</text>
  48. <text v-if="payInfo.couponAmount > 0" class="amount">¥{{ parseFloat(payInfo.couponAmount).toFixed(2) }}</text>
  49. <text v-if="payInfo.couponAmount <= 0 && payInfo.couponInfo.amount" class="point-amount">不使用卡券抵扣?</text>
  50. <text v-if="payInfo.couponInfo.amount" class="modify" @click="modifyCoupon">修改>></text>
  51. </view>
  52. </view>
  53. </view>
  54. <view class="pay-item">
  55. <view class="item-amount">
  56. <view class="title">
  57. <text class="iconfont icon-success"></text>
  58. 实付金额:<text class="amount">¥{{ (parseFloat(payInfo.payAmount)).toFixed(2) }}</text>
  59. </view>
  60. </view>
  61. </view>
  62. </view>
  63. </scroll-view>
  64. <view class="close" @click="close('close')" v-if="showClose">
  65. <image class="close-item" :src="closeImage"></image>
  66. </view>
  67. </view>
  68. <view class="btn-wrapper">
  69. <view class="sure" @click="toPay">确认支付</view>
  70. </view>
  71. <!-- 页面结束 -->
  72. </view>
  73. <view class="point-popup">
  74. <uni-popup ref="pointPopup" type="dialog">
  75. <uni-popup-dialog mode="input" focus="false" v-model="payInfo.usePoint.toFixed(0)" title="修改积分数量" type="info" placeholder="请输入积分数量" :before-close="true" @close="closeDialog" @confirm="doUsePoint"></uni-popup-dialog>
  76. </uni-popup>
  77. </view>
  78. <view class="coupon-popup">
  79. <uni-popup ref="couponPopup" type="dialog">
  80. <uni-popup-dialog focus="false" v-if="payInfo.couponAmount > 0" v-model="payInfo.usePoint.toFixed(0)" title="确认信息" content="不使用卡券进行抵扣?" type="info" :before-close="true" @close="closeDialog" @confirm="doUseCoupon"></uni-popup-dialog>
  81. <uni-popup-dialog focus="false" v-if="payInfo.couponAmount <= 0 && payInfo.couponInfo !== null" title="确认信息" :content="'使用卡券最多可抵扣¥'+ payInfo.couponInfo.amount" type="info" :before-close="true" @close="closeDialog" @confirm="doUseCoupon"></uni-popup-dialog>
  82. </uni-popup>
  83. </view>
  84. </view>
  85. <!-- 支付方式弹窗 -->
  86. <u-popup v-model="showPayPopup" mode="bottom" :closeable="true">
  87. <view class="pay-type-popup">
  88. <view class="title">请选择支付方式</view>
  89. <view class="pop-content">
  90. <!-- 微信支付 -->
  91. <view class="pay-item dis-flex flex-x-between" @click="payNow(PayTypeEnum.WECHAT.value)">
  92. <view class="item-left dis-flex flex-y-center">
  93. <view class="item-left_icon wechat">
  94. <text class="iconfont icon-weixinzhifu"></text>
  95. </view>
  96. <view class="item-left_text">
  97. <text>{{ PayTypeEnum.WECHAT.name }}</text>
  98. </view>
  99. </view>
  100. </view>
  101. <!-- 余额支付 -->
  102. <view class="pay-item dis-flex flex-x-between" @click="payNow(PayTypeEnum.BALANCE.value)">
  103. <view class="item-left dis-flex flex-y-center">
  104. <view class="item-left_icon balance">
  105. <text class="iconfont icon-qiandai"></text>
  106. </view>
  107. <view class="item-left_text">
  108. <text>{{ PayTypeEnum.BALANCE.name }}</text>
  109. </view>
  110. </view>
  111. </view>
  112. </view>
  113. </view>
  114. </u-popup>
  115. <!-- 页面内容结束 -->
  116. </view>
  117. </template>
  118. <script>
  119. import * as SettlementApi from '@/api/settlement'
  120. import PayTypeEnum from '@/common/enum/order/PayType'
  121. import { wxPayment } from '@/utils/app'
  122. var that; // 当前页面对象
  123. var vk; // 自定义函数集
  124. export default {
  125. name: 'PayPopup',
  126. props: {
  127. // true 组件显示 false 组件隐藏
  128. value: {
  129. Type: Boolean,
  130. default: false
  131. },
  132. // vk云函数路由模式参数开始-----------------------------------------------------------
  133. // 支付信息
  134. payInfo: {
  135. Type: Object,
  136. default: {}
  137. },
  138. // vk云函数路由模式参数结束-----------------------------------------------------------
  139. // 点击遮罩是否关闭组件 true 关闭 false 不关闭 默认true
  140. maskCloseAble: {
  141. Type: Boolean,
  142. default: true
  143. },
  144. // 是否显示右上角关闭按钮
  145. showClose: {
  146. Type: Boolean,
  147. default: true
  148. },
  149. // 关闭按钮的图片地址
  150. closeImage: {
  151. Type: String,
  152. default: "https://img.alicdn.com/imgextra/i1/121022687/O1CN01ImN0O11VigqwzpLiK_!!121022687.png"
  153. }
  154. },
  155. data() {
  156. return {
  157. complete: false, // 组件是否加载完成
  158. usePoint: '',
  159. showPayPopup: false,
  160. PayTypeEnum
  161. };
  162. },
  163. mounted() {
  164. that = this;
  165. },
  166. methods: {
  167. // 初始化
  168. init() {
  169. //empty
  170. },
  171. async open() {
  172. that.complete = true;
  173. that.$emit("open", true);
  174. that.$emit("input", true);
  175. },
  176. // 监听 - 弹出层收起
  177. close(s) {
  178. if (s == "close") {
  179. that.$emit("input", false);
  180. that.$emit("close", "close");
  181. } else if (s == "mask") {
  182. if (that.maskCloseAble) {
  183. that.$emit("input", false);
  184. that.$emit("close", "mask");
  185. }
  186. }
  187. },
  188. moveHandle() {
  189. // 禁止父元素滑动
  190. },
  191. // 确认支付
  192. toPay() {
  193. if (parseFloat(that.payInfo.payAmount) <= 0) {
  194. that.payNow(PayTypeEnum.BALANCE.value);
  195. } else {
  196. that.showPayPopup = true;
  197. }
  198. },
  199. // 立即支付
  200. payNow(payType) {
  201. const app = this
  202. // 请求api
  203. let couponId = 0
  204. if (app.payInfo.couponAmount > 0) {
  205. couponId = app.payInfo.couponInfo.userCouponId;
  206. }
  207. SettlementApi.submit(0, "", "payment", app.payInfo.remark, parseFloat(app.payInfo.totalAmount).toFixed(2), parseInt(app.payInfo.usePoint), couponId, "", 0, 0, 0, "", payType)
  208. .then(result => app.onSubmitCallback(result))
  209. .catch(err => {
  210. if (err.result) {
  211. const errData = err.result.data;
  212. if (errData) {
  213. return false;
  214. }
  215. }
  216. })
  217. },
  218. // 去登录
  219. onGetLogin() {
  220. uni.navigateTo({
  221. url: "/pages/login/index"
  222. })
  223. },
  224. // 订单提交成功后回调
  225. onSubmitCallback(result) {
  226. const app = this
  227. if (result.code != '200') {
  228. if (result.message) {
  229. app.$error(result.message);
  230. } else {
  231. app.$error('支付失败');
  232. }
  233. return false
  234. }
  235. // 微信支付
  236. if (result.data.payType == PayTypeEnum.WECHAT.value) {
  237. wxPayment(result.data.payment)
  238. .then(() => {
  239. app.$navTo(`pages/pay/result`, { amount: parseFloat(result.data.orderInfo.amount).toFixed(2), point: parseInt(result.data.orderInfo.usePoint)})
  240. })
  241. .catch(err =>
  242. app.$error('订单未支付'))
  243. .finally(() => {
  244. //empty
  245. })
  246. }
  247. // 余额支付
  248. if (result.data.payType == PayTypeEnum.BALANCE.value) {
  249. if (result.data.orderInfo.payStatus == 'B') {
  250. app.$navTo(`pages/pay/result`, { amount: parseFloat(result.data.orderInfo.amount).toFixed(2), point: parseInt(result.data.orderInfo.usePoint)})
  251. } else {
  252. if (result.message) {
  253. app.$error(result.message);
  254. } else {
  255. app.$error('支付失败');
  256. }
  257. }
  258. }
  259. },
  260. modifyPoint() {
  261. this.$refs.pointPopup.open('top')
  262. },
  263. modifyCoupon() {
  264. this.$refs.couponPopup.open('top')
  265. },
  266. doUsePoint(usePoint) {
  267. if (usePoint.length < 1) {
  268. usePoint = 0
  269. }
  270. if (!(/(^[0-9]\d*$)/.test(usePoint))) {
  271. this.$error('请输入正整数')
  272.   return false
  273. }
  274. if (usePoint > this.payInfo.maxPoint) {
  275. if (this.payInfo.maxPoint > 0) {
  276. this.$error('最多使用' + this.payInfo.maxPoint + '积分')
  277. } else {
  278. this.$error('您暂无可用积分')
  279. }
  280. return false
  281. }
  282. this.payInfo.usePoint = usePoint
  283. this.$emit('modifyChoice', this.payInfo)
  284. this.$refs.pointPopup.close()
  285. },
  286. doUseCoupon() {
  287. if (this.payInfo.couponAmount > 0) {
  288. this.payInfo.couponAmount = 0
  289. } else {
  290. this.payInfo.couponAmount = this.payInfo.couponInfo.amount
  291. }
  292. this.$emit('modifyChoice', this.payInfo)
  293. this.$refs.couponPopup.close()
  294. },
  295. closeDialog() {
  296. this.$refs.pointPopup.close()
  297. this.$refs.couponPopup.close()
  298. },
  299. // 弹窗
  300. toast(title, icon) {
  301. uni.showToast({
  302. title: title,
  303. icon: icon
  304. });
  305. }
  306. },
  307. watch: {
  308. value: function(val) {
  309. if (val) {
  310. that.open();
  311. }
  312. },
  313. }
  314. };
  315. </script>
  316. <style lang="scss" scoped>
  317. // 弹出层-支付方式
  318. .pay-type-popup {
  319. padding: 25rpx 25rpx 70rpx 25rpx;
  320. .title {
  321. font-size: 30rpx;
  322. margin-bottom: 50rpx;
  323. font-weight: bold;
  324. text-align: center;
  325. }
  326. .pop-content {
  327. min-height: 140rpx;
  328. padding: 0 20rpx;
  329. .pay-item {
  330. padding: 30rpx;
  331. font-size: 30rpx;
  332. background: #fff;
  333. border: 1rpx solid $fuint-theme;
  334. border-radius: 8rpx;
  335. color: #888;
  336. margin-bottom: 12rpx;
  337. text-align: center;
  338. .item-left_icon {
  339. margin-right: 20rpx;
  340. font-size: 48rpx;
  341. &.wechat {
  342. color: #00c800;
  343. }
  344. &.balance {
  345. color: $fuint-theme;
  346. }
  347. }
  348. }
  349. }
  350. }
  351. .pay-popup {
  352. position: fixed;
  353. left: 0;
  354. top: 0;
  355. right: 0;
  356. bottom: 0;
  357. z-index: 21;
  358. overflow: hidden;
  359. &.show {
  360. display: block;
  361. .mask {
  362. animation: showPopup 0.2s linear both;
  363. }
  364. .layer {
  365. animation: showLayer 0.2s linear both;
  366. }
  367. }
  368. &.hide {
  369. .mask {
  370. animation: hidePopup 0.2s linear both;
  371. }
  372. .layer {
  373. animation: hideLayer 0.2s linear both;
  374. }
  375. }
  376. &.none {
  377. display: none;
  378. }
  379. .mask {
  380. position: fixed;
  381. top: 0;
  382. width: 100%;
  383. height: 100%;
  384. z-index: 1;
  385. background-color: rgba(0, 0, 0, 0.65);
  386. }
  387. .layer {
  388. display: flex;
  389. width: 100%;
  390. flex-direction: column;
  391. position: fixed;
  392. z-index: 99;
  393. bottom: 0;
  394. border-radius: 10rpx 10rpx 0 0;
  395. background-color: #fff;
  396. .specification-wrapper {
  397. width: 100%;
  398. padding: 30rpx 25rpx 10rpx 25rpx;
  399. box-sizing: border-box;
  400. background: #ffffff;
  401. .specification-wrapper-content {
  402. width: 100%;
  403. max-height: 900rpx;
  404. min-height: 300rpx;
  405. &::-webkit-scrollbar {
  406. /*隐藏滚轮*/
  407. display: none;
  408. }
  409. .specification-header {
  410. width: 100%;
  411. display: flex;
  412. flex-direction: row;
  413. position: relative;
  414. margin-bottom: 40rpx;
  415. text-align: center;
  416. .specification-name {
  417. font-weight: bold;
  418. width: 100%;
  419. font-size: 30rpx;
  420. padding: 10rpx;
  421. }
  422. }
  423. .specification-content {
  424. text-align: left;
  425. .pay-item {
  426. padding: 35rpx 30rpx 30rpx 100rpx;
  427. cursor: pointer;
  428. margin-bottom: 8rpx;
  429. border: solid 3rpx #cccccc;
  430. border-radius: 10rpx;
  431. .iconfont {
  432. margin-right: 10rpx;
  433. color: $fuint-theme
  434. }
  435. .item-point {
  436. .amount {
  437. color: #f9211c;
  438. }
  439. .modify {
  440. margin-left: 30rpx;
  441. color: $fuint-theme;
  442. }
  443. }
  444. .item-amount {
  445. font-size: 30rpx;
  446. .amount {
  447. color: #f9211c;
  448. font-size: 35rpx;
  449. font-weight: bold;
  450. }
  451. }
  452. }
  453. }
  454. }
  455. .close {
  456. position: absolute;
  457. top: 30rpx;
  458. right: 25rpx;
  459. width: 50rpx;
  460. height: 50rpx;
  461. text-align: center;
  462. line-height: 50rpx;
  463. .close-item {
  464. width: 40rpx;
  465. height: 40rpx;
  466. }
  467. }
  468. }
  469. .btn-wrapper {
  470. display: flex;
  471. width: 100%;
  472. height: 120rpx;
  473. flex: 0 0 120rpx;
  474. align-items: center;
  475. justify-content: space-between;
  476. padding: 0 26rpx;
  477. box-sizing: border-box;
  478. margin-bottom: 60rpx;
  479. .layer-btn {
  480. width: 335rpx;
  481. height: 76rpx;
  482. border-radius: 38rpx;
  483. color: #fff;
  484. line-height: 76rpx;
  485. text-align: center;
  486. font-weight: 500;
  487. font-size: 28rpx;
  488. &.add-cart {
  489. background: #ffbe46;
  490. }
  491. &.buy {
  492. background: #fe560a;
  493. }
  494. }
  495. .sure {
  496. width: 698rpx;
  497. height: 80rpx;
  498. border-radius: 40rpx;
  499. color: #fff;
  500. line-height: 80rpx;
  501. text-align: center;
  502. font-weight: 500;
  503. font-size: 28rpx;
  504. background:linear-gradient(to right, #f9211c, #ff6335)
  505. }
  506. .sure.add-cart {
  507. background: #ff9402;
  508. }
  509. }
  510. }
  511. @keyframes showPopup {
  512. 0% {
  513. opacity: 0;
  514. }
  515. 100% {
  516. opacity: 1;
  517. }
  518. }
  519. @keyframes hidePopup {
  520. 0% {
  521. opacity: 1;
  522. }
  523. 100% {
  524. opacity: 0;
  525. }
  526. }
  527. @keyframes showLayer {
  528. 0% {
  529. transform: translateY(120%);
  530. }
  531. 100% {
  532. transform: translateY(0%);
  533. }
  534. }
  535. @keyframes hideLayer {
  536. 0% {
  537. transform: translateY(0);
  538. }
  539. 100% {
  540. transform: translateY(120%);
  541. }
  542. }
  543. }
  544. </style>