index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. <template>
  2. <view class="">
  3. <!-- #ifdef MP-WEIXIN-->
  4. <view class="">
  5. <u-navbar title="收银台"></u-navbar>
  6. </view>
  7. <!-- #endif -->
  8. <view class="shopInfo">
  9. <image :src="shopDetail.cover" mode=""></image>
  10. <text>{{shopDetail.name}}</text>
  11. </view>
  12. <view class="data">
  13. <text style="color: #000;">付款金额</text>
  14. <view class="price">
  15. <view class="input-bar center" @tap="show">
  16. <view class="icon center">¥</view>
  17. <view class="input" style="display: flex; align-items: center;">
  18. <view style="font-size: 80rpx;">{{filterMoney(orderAmount)}}</view>
  19. <view class="cusor"></view>
  20. </view>
  21. </view>
  22. </view>
  23. </view>
  24. <!-- #ifdef MP-WEIXIN-->
  25. <view v-if="$isNotEmpty(channel)" @click="channelShow=true" class="channel " style="width: 100%;">
  26. <view class="left">
  27. <view class="center">
  28. <image :src="channel[0].channelLogo" mode=""></image>
  29. </view>
  30. <view class="content">
  31. <text>{{channel[0].channelName}}</text>
  32. <text>优先使用该渠道积分支付</text>
  33. </view>
  34. </view>
  35. <view class="right">
  36. <text class="cuIcon-right"></text>
  37. </view>
  38. </view>
  39. <u-popup :closeable="true" v-model="channelShow" mode="bottom" height="65%">
  40. <view class="popup-content">
  41. <view class="">
  42. <view style="border-bottom: 1rpx solid #eee;" class="fixed center text-bold text-lg padding-bottom-40">
  43. 请选择优先使用的渠道积分
  44. </view>
  45. <view @click="channelId=item.channelId" v-for="(item,index) in channel" :key="index" class="channel-item">
  46. <image :src="item.channelLogo" mode=""></image>
  47. <text class="margin-left-10">{{item.channelName}}(剩余 ¥ {{item.available}})</text>
  48. <text v-if="channelId==item.channelId" class="cuIcon-check checked"></text>
  49. </view>
  50. </view>
  51. <view class="center">
  52. <view @click="channelShow=false" class="cu-btn radius channelbtn">
  53. 确认
  54. </view>
  55. </view>
  56. </view>
  57. </u-popup>
  58. <!-- #endif -->
  59. <amountInput ref="amountInput" confirmText="付款" btnColor="#ff9900" placeholder="请输入交易金额" @change="change"
  60. @confirm="debouncePay"></amountInput>
  61. <u-modal v-model="modalShow" :mask-close-able="true" :showCancelButton="true" @cancel="payOfh5"
  62. @confirm="jumpLDT" cancel-text="直接付款" confirm-color="#FF9447" confirmText="去联兑通支付"
  63. content="去联兑通小程序付款会有更多优惠哟~"></u-modal>
  64. </view>
  65. </template>
  66. <script>
  67. import amountInput from '../../comps/amountInput/amountInput.vue';
  68. export default {
  69. components: {
  70. amountInput
  71. },
  72. data() {
  73. return {
  74. //渠道积分
  75. channel:[],
  76. channelShow:false,
  77. channelId:0,
  78. //第一次点击支付不需要防抖操作
  79. isFirstPay: true,
  80. orderAmount: '',
  81. modalShow: false,
  82. shopId: '',
  83. shopDetail: {},
  84. //支付参数
  85. payParams:{},
  86. //支付结果
  87. payResult:{
  88. isSuccess: false,
  89. msg: "交易失败",
  90. //总价
  91. totalPrice: 0,
  92. //消耗积分值
  93. pointsNum:0,
  94. //消耗现金值
  95. amountNum:0,
  96. }
  97. }
  98. },
  99. async onLoad(options) {
  100. if (!this.$isEmpty(options.query)) {
  101. //h5跳转回小程序后重新赋值
  102. let params = options.query.split(";")
  103. this.shopId = params[0]
  104. this.orderAmount = params[1]
  105. } else {
  106. this.shopId = options.id
  107. }
  108. // #ifdef MP-WEIXIN
  109. //如果是新用户通过微信支付扫码进入此页面,跳回首页
  110. if (this.$isEmpty(this.vuex_userId)) {
  111. uni.reLaunch({
  112. url: "/pages/mine/mine?query=" + this.shopId + ";" + this.orderAmount
  113. })
  114. return
  115. }
  116. //如果用户信息为空,阻断
  117. let flag=await this.fetchUserDetail()
  118. if (!flag) {
  119. this.$dialog.showModal('用户信息获取失败',false).then(()=>{
  120. uni.reLaunch({
  121. url:"/pages/mine/mine"
  122. })
  123. })
  124. return
  125. }
  126. this.getUserPonint()
  127. // #endif
  128. if (this.$isEmpty(this.shopId)) {
  129. this.$dialog.showModal('商户id不能为空', false).then(() => {
  130. uni.navigateBack()
  131. })
  132. return
  133. }
  134. this.fetchShopDetail()
  135. },
  136. methods: {
  137. //获取用户渠道积分
  138. getUserPonint(){
  139. let params={
  140. userId:this.vuex_userId
  141. }
  142. this.$api.userChannelPoint.list(params).then(res=>{
  143. if (this.$isNotEmpty(res.data.records)) {
  144. this.channel=res.data.records
  145. this.channelId=this.channel[0].channelId
  146. }
  147. })
  148. },
  149. //防抖支付
  150. debouncePay() {
  151. if (this.isFirstPay) {
  152. this.pay()
  153. this.isFirstPay = false
  154. } else {
  155. this.$u.debounce(this.pay, 500)
  156. }
  157. },
  158. //获取商户信息
  159. fetchShopDetail() {
  160. this.$api.shop.detail({
  161. id: this.shopId
  162. }).then(res => {
  163. if (this.$isEmpty(res.data)) {
  164. this.$dialog.showModal('获取不到商户信息', false).then(() => {
  165. uni.navigateBack({
  166. delta: 1
  167. })
  168. })
  169. } else {
  170. this.shopDetail = res.data
  171. }
  172. }).catch(err => {
  173. this.$dialog.showModal('获取不到商户信息', false).then(() => {
  174. uni.navigateBack({
  175. delta: 1
  176. })
  177. })
  178. })
  179. },
  180. //获取用户信息
  181. async fetchUserDetail(){
  182. let res=await this.$api.loginUser.detail({id:this.vuex_userId})
  183. if (this.$isEmpty(res.data)) {
  184. return false
  185. }else{
  186. return true
  187. }
  188. },
  189. show() {
  190. this.$refs.amountInput.show()
  191. },
  192. change(e) {
  193. if (!e) {
  194. this.orderAmount = 0
  195. } else {
  196. this.orderAmount = e
  197. }
  198. },
  199. filterMoney(value) {
  200. if (!value) {
  201. return ''
  202. } else {
  203. value = value.replace(/\$\s?|(,*)/g, '')
  204. return value.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
  205. }
  206. },
  207. async jumpLDT() {
  208. this.$dialog.showLoading('打开中..')
  209. let params = {
  210. path: "/pagesC/pages/checkstand/index",
  211. query: "query=" + this.shopId + ";" + this.orderAmount
  212. }
  213. let res = await this.$api.wxApp.getGenerateScheme(params)
  214. if (!this.$isEmpty(res.data.openlink)) {
  215. location.href = res.data.openlink
  216. } else {
  217. location.href = "weixin://dl/business/?t=X2CyIQDbgtm"
  218. }
  219. uni.hideLoading()
  220. },
  221. async payOfh5() {
  222. let expireTime = this.$dateTime.getExpireTime(5)
  223. let params = {
  224. expireTime,
  225. money: this.orderAmount,
  226. shopId: this.shopId,
  227. }
  228. let resp = await this.$api.pay.getPayOrderPamamsForH5(params)
  229. let payObj = {
  230. orderType: this.$global.orderType.USER_PAY,
  231. orderId: resp.data.id
  232. }
  233. let res = await this.$api.pay.payOrderOfscanCode(payObj)
  234. if (!this.$isEmpty(res.data.qrCodeUrl)) {
  235. location.href = res.data.qrCodeUrl
  236. } else {
  237. this.$u.toast('支付失败')
  238. }
  239. },
  240. async pay() {
  241. if (!this.orderAmount.length || this.orderAmount == 0) {
  242. this.$u.toast('请输入交易金额')
  243. return
  244. }
  245. // #ifdef H5
  246. this.modalShow = true
  247. // #endif
  248. // #ifdef MP-WEIXIN
  249. this.toWXPay()
  250. // #endif
  251. },
  252. async toWXPay() {
  253. let expireTime = this.$dateTime.getExpireTime(5)
  254. let params = {
  255. userId:this.vuex_userId,
  256. appId: this.$global.wxParams.APPID,
  257. billsTitle: '用户支付',
  258. money: this.orderAmount,
  259. expireTime,
  260. shopId: this.shopId,
  261. openId: this.$cache.get('userInfo').openId,
  262. channelId:this.channelId
  263. }
  264. let resp = await this.$api.pay.getPayOrderPamams(params)
  265. this.payParams=resp.data
  266. if (resp.data.status=='付款成功') {
  267. this.handelResult(true)
  268. }else if (resp.data.status=='待付款') {
  269. this.doWxPay(resp.data.bills.id)
  270. }else{
  271. this.handelResult(false)
  272. }
  273. },
  274. async doWxPay(orderId){
  275. let obj = {
  276. orderType: this.$global.orderType.USER_PAY,
  277. orderId,
  278. payStatus: this.$global.payStatus.IS_WAIT
  279. }
  280. let res = await this.$api.pay.payOrder(obj)
  281. let prePayTn = JSON.parse(res.data.prePayTn)
  282. this.$mpi.requestPayment(prePayTn).then((res) => {
  283. this.handelResult(true)
  284. }).catch(err => {
  285. this.handelResult(false)
  286. })
  287. },
  288. handelResult(flag){
  289. if (flag) {
  290. this.payResult={
  291. isSuccess: true,
  292. msg: "交易成功",
  293. totalPrice:this.payParams.totalPrice,
  294. amountNum: this.payParams.bills.price,
  295. pointsNum: this.$digital.floatSub(this.payParams.totalPrice,this.payParams.bills.price),
  296. }
  297. }else{
  298. this.payResult.msg='交易失败'
  299. this.payResult.isSuccess=false
  300. }
  301. uni.navigateTo({
  302. url:"/pagesC/pages/checkstand/pay-result?payResult="+JSON.stringify(this.payResult)
  303. })
  304. },
  305. }
  306. }
  307. </script>
  308. <style>
  309. page {
  310. background-color: #ffff;
  311. }
  312. </style>
  313. <style lang="scss" scoped>
  314. .shopInfo {
  315. margin: 60rpx 0 20rpx;
  316. display: flex;
  317. justify-content: center;
  318. align-items: center;
  319. flex-direction: column;
  320. image {
  321. border-radius: 50%;
  322. width: 140rpx;
  323. height: 140rpx;
  324. }
  325. text {
  326. margin-top: 30rpx;
  327. font-size: 32rpx;
  328. }
  329. }
  330. .data {
  331. padding: 50rpx;
  332. display: flex;
  333. justify-content: flex-start;
  334. flex-direction: column;
  335. .price {
  336. &-icon {
  337. font-size: 40rpx;
  338. font-weight: 800;
  339. }
  340. }
  341. }
  342. .center {
  343. display: flex;
  344. justify-content: center;
  345. align-items: center;
  346. }
  347. .input-bar {
  348. height: 150rpx;
  349. border-bottom: 1rpx solid #DDDDDD;
  350. .icon {
  351. width: 15%;
  352. font-size: 70rpx;
  353. font-weight: 900;
  354. height: 100%;
  355. }
  356. .input {
  357. width: 85%;
  358. height: 100%;
  359. overflow: hidden;
  360. font-size: 70rpx;
  361. }
  362. .cusor {
  363. margin-left: 10rpx;
  364. width: 6rpx;
  365. border-radius: 20rpx;
  366. height: 60%;
  367. background-color: #ff9900;
  368. animation: blink 1200ms infinite ease-in-out;
  369. }
  370. }
  371. @keyframes blink {
  372. from {
  373. opacity: 0;
  374. }
  375. }
  376. .channel{
  377. display: flex;
  378. justify-content: space-between;
  379. margin-top: 10rpx;
  380. padding:0 30rpx;
  381. .left{
  382. display: flex;
  383. image{
  384. width: 60rpx;
  385. height: 60rpx;
  386. display: flex;
  387. justify-content: center;
  388. align-items: center;
  389. }
  390. view{
  391. display: flex;
  392. flex-direction: column;
  393. }
  394. .content{
  395. margin-left: 16rpx;
  396. text:first-child{
  397. font-size: 34rpx;
  398. margin-bottom: 10rpx;
  399. }
  400. text:last-child{
  401. font-size: 28rpx;
  402. color: #989898;
  403. }
  404. }
  405. }
  406. .right{
  407. display: flex;
  408. justify-content: center;
  409. align-items: center;
  410. }
  411. }
  412. .popup-content{
  413. display: flex;
  414. flex-direction: column;
  415. justify-content: space-between;
  416. padding: 40rpx 0;
  417. height: 100%;
  418. .channelbtn{
  419. background-color: #18b566;
  420. color: #FFFFFF;
  421. padding: 36rpx 150rpx;
  422. }
  423. .channel-item{
  424. position: relative;
  425. display: flex;
  426. padding: 30rpx;
  427. border-bottom: 1rpx solid #eee;
  428. image{
  429. width: 40rpx;
  430. height: 40rpx;
  431. margin-right: 10rpx;
  432. }
  433. .checked{
  434. color: #18b566;
  435. font-size: 34rpx;
  436. position: absolute;
  437. font-weight: 800;
  438. right: 40rpx;
  439. bottom: 30rpx;
  440. }
  441. }
  442. }
  443. </style>