nc-payment.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. export default {
  2. props: {
  3. outTradeNo: {
  4. type: String,
  5. default: ''
  6. }
  7. },
  8. data() {
  9. return {
  10. type: 'third',
  11. payType: {
  12. third: {
  13. type: 'third',
  14. name: '付款码支付',
  15. icon: 'iconsaomaqiang',
  16. background: '#f7931e'
  17. },
  18. cash: {
  19. type: 'cash',
  20. name: '现金支付',
  21. icon: 'iconxianjin1',
  22. background: '#f5b719'
  23. },
  24. own_wechatpay: {
  25. type: 'own_wechatpay',
  26. name: '个人微信',
  27. icon: 'iconwxpay',
  28. background: '#09bb07'
  29. },
  30. own_alipay: {
  31. type: 'own_alipay',
  32. name: '个人支付宝',
  33. icon: 'iconzhifubaozhifu',
  34. background: '#1890ff'
  35. },
  36. own_pos: {
  37. type: 'own_pos',
  38. name: '个人POS刷卡',
  39. icon: 'iconyinhangqia',
  40. background: '#ec6a55'
  41. }
  42. },
  43. payInfo: null,
  44. paystatus: 'pay',
  45. isRepeat: false,
  46. qrcodeShow: false,
  47. payQrcode: [],
  48. timer: null,
  49. moneyPopup: {
  50. money: 0,
  51. type: '',
  52. title: ''
  53. },
  54. cash: 0,
  55. discount: {},
  56. scanCodeType: 'scancode',
  57. scancodeFocus: true,
  58. authCode: '',
  59. autoComplete: {
  60. time: 8,
  61. timer: null
  62. },
  63. remark: '',
  64. autoPrintTicket: true,
  65. balanceSafeVerify: false, // 余额使用安全验证
  66. dynacodeData: {
  67. key: '',
  68. seconds: 120,
  69. timer: null,
  70. codeText: '获取验证码',
  71. isSend: false
  72. },
  73. smsCode: '',
  74. paymentCode: '',
  75. safeVerifyType: 'payment_code'
  76. }
  77. },
  78. computed: {
  79. balance() {
  80. if (this.memberInfo) {
  81. return parseFloat(this.memberInfo.balance_money) + parseFloat(this.memberInfo.balance);
  82. }
  83. return 0;
  84. },
  85. promotionShow() {
  86. if (this.payInfo && (this.payInfo.offset.coupon_array || this.payInfo.collectmoney_config.reduction == 1)) {
  87. return true;
  88. }
  89. return false;
  90. }
  91. },
  92. created() {
  93. if (this.outTradeNo) this.calculation();
  94. if (typeof uni.getStorageSync('payAutoPrintTicket') == 'boolean') this.autoPrintTicket = uni.getStorageSync(
  95. 'payAutoPrintTicket');
  96. },
  97. destroyed() {
  98. clearInterval(this.timer);
  99. },
  100. methods: {
  101. /**
  102. * 取消支付
  103. */
  104. cancelPayment() {
  105. this.$emit('cancel', {})
  106. this.clearPay();
  107. },
  108. /**
  109. * 支付成功
  110. */
  111. paySuccess() {
  112. this.$emit('success', {})
  113. this.clearPay();
  114. },
  115. clearPay() {
  116. clearInterval(this.timer);
  117. this.type = 'third';
  118. this.payInfo = null;
  119. this.paystatus = 'pay';
  120. this.payQrcode = [];
  121. this.cash = 0;
  122. this.discount = {};
  123. this.isRepeat = false;
  124. if (this.autoComplete.timer) clearInterval(this.autoComplete.timer);
  125. this.autoComplete.time = 8;
  126. this.remark = '';
  127. this.balanceSafeVerify = false;
  128. this.smsCode = '';
  129. this.paymentCode = '';
  130. this.safeVerifyType = 'payment_code';
  131. this.refreshDynacodeData();
  132. },
  133. confirm() {
  134. if (this.isRepeat) return;
  135. uni.showLoading({})
  136. if (this.type == 'cash') {
  137. if (!this.cash) {
  138. this.cash = this.payInfo.pay_money;
  139. } else if (isNaN(parseFloat(this.cash)) || parseFloat(this.cash) < parseFloat(this.payInfo.pay_money)) {
  140. this.$util.showToast({
  141. title: '现金收款金额错误'
  142. });
  143. return;
  144. }
  145. }
  146. this.isRepeat = true;
  147. let data = {
  148. pay_type: this.type,
  149. out_trade_no: this.outTradeNo,
  150. member_id: this.memberInfo ? this.memberInfo.member_id : 0,
  151. promotion: JSON.stringify(this.$util.deepClone(this.discount)),
  152. cash: this.type == 'cash' ? this.cash : 0
  153. }
  154. this.$api.sendRequest({
  155. url: '/cashier/storeapi/cashierpay/confirm',
  156. data,
  157. success: res => {
  158. uni.hideLoading();
  159. if (res.code == 0) {
  160. this.paystatus = 'success';
  161. this.$emit('getMemberInfo');
  162. } else {
  163. this.isRepeat = false;
  164. this.$util.showToast({
  165. title: res.message
  166. })
  167. }
  168. },
  169. fail: res => {
  170. uni.hideLoading();
  171. }
  172. })
  173. },
  174. calculation() {
  175. let data = {
  176. pay_type: this.type,
  177. out_trade_no: this.outTradeNo,
  178. member_id: this.memberInfo ? this.memberInfo.member_id : 0,
  179. promotion: JSON.stringify(this.$util.deepClone(this.discount)),
  180. cash: this.type == 'cash' ? this.cash : 0
  181. }
  182. this.$api.sendRequest({
  183. url: '/cashier/storeapi/cashierpay/paycalculate',
  184. data,
  185. success: res => {
  186. if (res.code == 0) {
  187. this.payInfo = res.data;
  188. if (this.payInfo.pay_status == 1) {
  189. this.paystatus = 'success';
  190. this.$emit('getMemberInfo');
  191. }
  192. } else {
  193. this.$util.showToast({
  194. title: res.message
  195. })
  196. }
  197. },
  198. fail: res => {}
  199. })
  200. },
  201. /**
  202. * 打印小票
  203. */
  204. printTicket() {
  205. this.$api.sendRequest({
  206. url: '/cashier/storeapi/cashierorder/printticket',
  207. data: {
  208. order_id: this.payInfo.order_id
  209. },
  210. success: res => {
  211. if (res.code != 0) {
  212. this.$util.showToast({
  213. title: res.message ? res.message : '小票打印失败'
  214. })
  215. }
  216. }
  217. })
  218. },
  219. thirdConfirm() {
  220. this.authCode = '';
  221. this.scanCodeType = 'scancode';
  222. this.scancodeFocus = true;
  223. this.$refs.thirdPopup.open();
  224. },
  225. /**
  226. * 获取支付二维码
  227. */
  228. getQrcode() {
  229. this.$api.sendRequest({
  230. url: '/cashier/storeapi/cashierpay/payqrcode',
  231. data: {
  232. out_trade_no: this.outTradeNo
  233. },
  234. success: res => {
  235. if (res.code == 0 && res.data.length) {
  236. this.payQrcode = res.data;
  237. this.checkPayStatus();
  238. }
  239. }
  240. })
  241. },
  242. popupChange() {
  243. if (this.timer) {
  244. clearInterval(this.timer);
  245. }
  246. },
  247. /**
  248. * 扫码枪
  249. */
  250. scancode(e) {
  251. if (!e.detail.value) return;
  252. if (this.isRepeat) return;
  253. uni.showLoading({})
  254. this.isRepeat = true;
  255. this.$api.sendRequest({
  256. url: '/cashier/storeapi/cashierpay/createpay',
  257. data: {
  258. out_trade_no: this.outTradeNo
  259. },
  260. success: res => {
  261. if (res.code == 0) {
  262. this.$api.sendRequest({
  263. url: '/pay/pay/authcodepay',
  264. data: {
  265. out_trade_no: this.outTradeNo,
  266. auth_code: e.detail.value
  267. },
  268. success: res => {
  269. this.authCode = '';
  270. uni.hideLoading();
  271. if (res.code >= 0) {
  272. this.$refs.thirdPopup.close();
  273. this.paystatus = 'success';
  274. } else {
  275. this.isRepeat = false;
  276. this.$util.showToast({
  277. title: res.message
  278. })
  279. }
  280. }
  281. })
  282. } else {
  283. uni.hideLoading();
  284. this.isRepeat = false;
  285. this.$util.showToast({
  286. title: res.message
  287. })
  288. }
  289. }
  290. })
  291. },
  292. /**
  293. * 查询支付状态
  294. */
  295. checkPayStatus() {
  296. this.timer = setInterval(() => {
  297. this.$api.sendRequest({
  298. url: '/cashier/storeapi/cashierpay/info',
  299. data: {
  300. out_trade_no: this.outTradeNo
  301. },
  302. success: res => {
  303. if (res.code == 0 && res.data && res.data.pay_status == 2) {
  304. this.paystatus = 'success';
  305. clearInterval(this.timer)
  306. }
  307. }
  308. })
  309. }, 1500)
  310. },
  311. /**
  312. * 打开金额弹窗
  313. * @param {Object} data
  314. */
  315. openMoneyPopup(data) {
  316. this.moneyPopup = Object.assign(this.moneyPopup, data);
  317. this.$refs.moneyPopup.open();
  318. },
  319. deleteCode() {
  320. this.moneyPopup.money = this.moneyPopup.money.substr(0, this.moneyPopup.money.length - 1);
  321. },
  322. moneyPopupConfirm() {
  323. if (!this.moneyPopup.money.length) {
  324. this.$util.showToast({
  325. title: '请输入金额'
  326. })
  327. return;
  328. }
  329. if (this.moneyPopup.type == 'reduction') {
  330. this.discount.reduction = parseFloat(this.moneyPopup.money);
  331. } else if (this.moneyPopup.type == 'cash') {
  332. this.cash = parseFloat(this.moneyPopup.money);
  333. }
  334. this.calculation();
  335. this.$refs.moneyPopup.close();
  336. },
  337. keydown(value) {
  338. let arr = this.moneyPopup.money.split('.');
  339. if (arr[1]) {
  340. if (value == '.' || arr[1].length == 2) return;
  341. if (value == '00' && arr[1].length == 1) value = '0';
  342. }
  343. if (this.moneyPopup.type == 'reduction' && parseFloat(this.moneyPopup.money + value) > parseFloat(this
  344. .payInfo.pay_money)) return;
  345. if (parseFloat(this.moneyPopup.money + value) > 1000000) {
  346. this.$util.showToast({
  347. title: '最大不能超过1000000'
  348. })
  349. return;
  350. }
  351. this.moneyPopup.money += value;
  352. },
  353. /**
  354. * 切换支付方式
  355. * @param {Object} type
  356. */
  357. switchPayType(type) {
  358. this.type = type;
  359. if (type == 'cash') {
  360. if (this.cash) {
  361. this.openMoneyPopup({
  362. title: '收款金额',
  363. money: this.$util.moneyFormat(this.cash),
  364. type: 'cash'
  365. })
  366. } else {
  367. this.openMoneyPopup({
  368. title: '收款金额',
  369. money: this.$util.moneyFormat(this.payInfo.pay_money),
  370. type: 'cash'
  371. })
  372. }
  373. } else {
  374. this.calculation();
  375. }
  376. },
  377. /**
  378. * 减免金额
  379. */
  380. reduction() {
  381. if (this.discount.reduction) {
  382. delete this.discount.reduction;
  383. this.calculation();
  384. } else {
  385. this.openMoneyPopup({
  386. title: '减免金额',
  387. money: '',
  388. type: 'reduction'
  389. })
  390. }
  391. },
  392. /**
  393. * 使用积分
  394. */
  395. usePoint() {
  396. if (this.payInfo.offset.point_array.point == 0) return;
  397. if (this.discount.is_use_point) {
  398. delete this.discount.is_use_point;
  399. } else {
  400. this.discount.is_use_point = 1;
  401. }
  402. this.calculation();
  403. },
  404. useBalance() {
  405. if (this.balance == 0) return;
  406. // 如果开启了余额安全验证
  407. if (this.payInfo.collectmoney_config.balance_safe == 1 && !this.balanceSafeVerify) {
  408. this.$refs.safeVerifyPopup.open();
  409. return;
  410. }
  411. if (this.discount.is_use_balance) {
  412. delete this.discount.is_use_balance;
  413. } else {
  414. this.discount.is_use_balance = 1;
  415. }
  416. this.calculation();
  417. },
  418. selectCoupon() {
  419. if (!this.payInfo.offset.coupon_array.member_coupon_list.length) return;
  420. this.$refs.couponPopup.open();
  421. },
  422. selectCouponItem(data) {
  423. if (!this.discount.coupon_id) {
  424. this.discount.coupon_id = data.coupon_id;
  425. } else if (this.discount.coupon_id != data.coupon_id) {
  426. this.discount.coupon_id = data.coupon_id;
  427. } else {
  428. delete this.discount.coupon_id;
  429. }
  430. this.$forceUpdate();
  431. this.calculation();
  432. },
  433. openRemark() {
  434. this.remark = this.payInfo.remark;
  435. this.$refs.remarkPopup.open()
  436. },
  437. /**
  438. * 设置备注
  439. */
  440. remarkConfirm() {
  441. if (!this.remark) return;
  442. this.$api.sendRequest({
  443. url: '/cashier/storeapi/cashierorder/orderRemark',
  444. data: {
  445. order_id: this.payInfo.order_id,
  446. remark: this.remark
  447. },
  448. success: res => {
  449. this.payInfo.remark = this.remark;
  450. this.$refs.remarkPopup.close();
  451. }
  452. });
  453. },
  454. /**
  455. * 发送短信验证码
  456. */
  457. sendMobileCode() {
  458. if (this.dynacodeData.seconds != 120 || this.dynacodeData.isSend) return;
  459. this.dynacodeData.isSend = true;
  460. this.dynacodeData.timer = setInterval(() => {
  461. this.dynacodeData.seconds--;
  462. this.dynacodeData.codeText = this.dynacodeData.seconds + 's后可重新获取';
  463. }, 1000);
  464. this.$api.sendRequest({
  465. url: '/cashier/storeapi/member/memberverifycode',
  466. data: {
  467. member_id: this.payInfo.member_id
  468. },
  469. success: res => {
  470. if (res.code >= 0) {
  471. this.dynacodeData.key = res.data.key;
  472. this.smsCode = '';
  473. this.$refs.smsCodePopup.open()
  474. this.dynacodeData.isSend = false;
  475. } else {
  476. this.$util.showToast({
  477. title: res.message
  478. });
  479. this.refreshDynacodeData();
  480. }
  481. },
  482. fail: () => {
  483. this.$util.showToast({
  484. title: 'request:fail'
  485. });
  486. this.refreshDynacodeData();
  487. }
  488. });
  489. },
  490. refreshDynacodeData() {
  491. clearInterval(this.dynacodeData.timer);
  492. this.dynacodeData = {
  493. key: '',
  494. seconds: 120,
  495. timer: null,
  496. codeText: '获取动态码',
  497. isSend: false
  498. };
  499. },
  500. /**
  501. * 验证短信验证码是否正确
  502. */
  503. verifySmsCode() {
  504. if (this.smsCode.trim() == '') {
  505. this.$util.showToast({
  506. title: '请输入验证码'
  507. });
  508. return;
  509. }
  510. if (this.isRepeat) return;
  511. this.isRepeat = true;
  512. this.$api.sendRequest({
  513. url: '/cashier/storeapi/member/checksmscode',
  514. data: {
  515. key: this.dynacodeData.key,
  516. code: this.smsCode.trim()
  517. },
  518. success: res => {
  519. if (res.code == 0) {
  520. this.balanceSafeVerify = true;
  521. this.$refs.safeVerifyPopup.close();
  522. this.useBalance();
  523. } else {
  524. this.$util.showToast({
  525. title: res.message
  526. });
  527. }
  528. this.isRepeat = false;
  529. }
  530. })
  531. },
  532. verifyPaymentCode(e) {
  533. if (e.detail.value) this.paymentCode = e.detail.value
  534. if (this.paymentCode.trim() == '') {
  535. this.$util.showToast({
  536. title: '请输入付款码'
  537. });
  538. return;
  539. }
  540. if (this.isRepeat) return;
  541. this.isRepeat = true;
  542. this.$api.sendRequest({
  543. url: '/cashier/storeapi/member/checkpaymentcode',
  544. data: {
  545. member_id: this.payInfo.member_id,
  546. code: this.paymentCode.trim()
  547. },
  548. success: res => {
  549. if (res.code == 0) {
  550. this.balanceSafeVerify = true;
  551. this.$refs.safeVerifyPopup.close();
  552. this.useBalance();
  553. } else {
  554. this.$util.showToast({
  555. title: res.message
  556. });
  557. }
  558. this.isRepeat = false;
  559. }
  560. })
  561. }
  562. },
  563. watch: {
  564. outTradeNo: function(nval, oval) {
  565. if (nval) this.calculation();
  566. },
  567. type: function(nval) {
  568. if (nval != 'third' && this.timer) {
  569. clearInterval(this.timer);
  570. }
  571. },
  572. scanCodeType: function(nval) {
  573. if (nval == 'scancode') {
  574. this.scancodeFocus = true;
  575. if (this.timer) clearInterval(this.timer);
  576. } else {
  577. this.getQrcode();
  578. }
  579. },
  580. paystatus: function(nval) {
  581. if (nval == 'success') {
  582. if (this.autoPrintTicket) this.printTicket();
  583. this.isRepeat = false;
  584. this.autoComplete.timer = setInterval(() => {
  585. if (this.autoComplete.time == 0) {
  586. this.paySuccess();
  587. } else {
  588. this.autoComplete.time--;
  589. }
  590. }, 1000)
  591. }
  592. },
  593. autoPrintTicket: function(nval) {
  594. uni.setStorageSync('payAutoPrintTicket', nval)
  595. },
  596. 'dynacodeData.seconds': {
  597. handler(newValue, oldValue) {
  598. if (newValue == 0) {
  599. this.refreshDynacodeData();
  600. }
  601. },
  602. immediate: true,
  603. deep: true
  604. }
  605. }
  606. }