nc-payment.js 14 KB

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