confirmMixin.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. import QueryPos from './QueryPos'
  2. import ReadValueCard from './ReadValueCard'
  3. import Collapse from '@/components/Collapse'
  4. import { payRefresh } from '@/api/pay'
  5. import handlePay, { getPayType } from '../common/handlePay'
  6. import { debounce } from 'throttle-debounce'
  7. import { checkWayList } from '@/assets/staticData'
  8. import { createValueCardOrder } from '@/api/valueCard'
  9. import { createOrder, getSingleOrder } from '@/api/order'
  10. import { EventBus } from '@/utils/eventBus'
  11. export default {
  12. props: {
  13. tickets: {
  14. type: Array,
  15. default: () => []
  16. },
  17. orderItems: {
  18. type: Array,
  19. default: () => []
  20. },
  21. createOrderRemark: {
  22. type: String,
  23. default: ''
  24. },
  25. orderPrice: {
  26. type: Number,
  27. default: 0
  28. },
  29. formData: {
  30. type: Object,
  31. default: () => { }
  32. },
  33. payChannel: {
  34. type: String,
  35. default: ''
  36. },
  37. totalCount: {
  38. type: Number,
  39. default: 0
  40. },
  41. currentTicket: {
  42. type: Object,
  43. default: () => null
  44. },
  45. // 登记出票:创单传 isRegisterOrder=1,不做支付与轮询
  46. isRegisterOrder: {
  47. type: Boolean,
  48. default: false
  49. }
  50. },
  51. components: {
  52. Collapse,
  53. ReadValueCard,
  54. QueryPos
  55. },
  56. computed: {
  57. payType () {
  58. return getPayType(this.currentPayChannel)
  59. },
  60. showRefresh () {
  61. return this.payType === 'B_SCAN_C_PAY' && this.submitDisable
  62. },
  63. showPosQrcode () {
  64. // 需要手动扫码的景区
  65. const list = ['东方绿舟', '天津之眼', '绿博园']
  66. if (this.scenicName === '绿博园' && (!this.$localStore.get('posName') || this.$localStore.get('posName') === 'jianhang')) {
  67. return false
  68. }
  69. return list.indexOf(this.scenicName) > -1
  70. },
  71. scenicName () {
  72. return this.$localStore.get('scenicName') || this.$store.state.user.scenicName
  73. },
  74. maxNum () {
  75. return this.$store.state.app.systemConfig?.find(i => i.configKey === 'ticket_checkNum_limit')?.configValue || 0
  76. },
  77. playDate () {
  78. return this.currentTicket ? this.currentTicket.playDate : ''
  79. }
  80. },
  81. data () {
  82. return {
  83. isPrint: false,
  84. isPrintSmallTicket: false,
  85. submitDisable: false,
  86. visible: false,
  87. active: '',
  88. orderInfo: [],
  89. printArray: [],
  90. isRefresh: false,
  91. countNum: 5,
  92. orderTempInfo: {}, // 临时订单信息,防止重复创建订单
  93. timer: null, // 检查订单是否支付成功计时器
  94. currentPrint: null,
  95. currentPayChannel: '',
  96. payStatus: 0, // 支付状态
  97. createOrderStatus: 0, // 创建订单状态
  98. payCode: '',
  99. payCodeDialogVisible: false
  100. }
  101. },
  102. methods: {
  103. show () {
  104. this.visible = true
  105. this.submitDisable = false
  106. this.payStatus = 0
  107. this.createOrderStatus = 0
  108. this.orderInfo = JSON.parse(JSON.stringify(this.orderItems))
  109. this.currentPayChannel = this.payChannel
  110. this.$nextTick(() => {
  111. this.isPrint = this.formData.checkWay === 3 ? false : (this.$localStore.get('autoPrint') || false)
  112. this.isPrintSmallTicket = this.$localStore.get('autoPrintSmallTicket')
  113. })
  114. },
  115. changePayChannel (n) {
  116. let i = this.payChannelOptions.findIndex(channel => channel === this.currentPayChannel)
  117. let l = this.payChannelOptions.length
  118. let j = (i - n + l) % l
  119. this.currentPayChannel = this.payChannelOptions[j]
  120. },
  121. payRefresh () {
  122. // if (!this.orderTempInfo.extraInfo) return
  123. this.countTimer && clearTimeout(this.countTimer)
  124. this.isRefresh = true
  125. this.countNum = 5
  126. this.countdown()
  127. payRefresh({ type: 'TICKET', id: this.orderTempInfo })
  128. },
  129. countdown () {
  130. this.countTimer = setTimeout(() => {
  131. this.countNum--
  132. this.countdown()
  133. if (this.countNum === 0) {
  134. this.isRefresh = false
  135. }
  136. }, 1000)
  137. },
  138. arrowUp () {
  139. this.changePayChannel(1)
  140. },
  141. arrowDown () {
  142. this.changePayChannel(-1)
  143. },
  144. getCheckWayName (val) {
  145. let a = checkWayList.find(i => i.val === val)
  146. return a && a.name
  147. },
  148. handleClose () {
  149. this.timer && clearTimeout(this.timer)
  150. if (this.submitDisable) {
  151. this.$confirm('支付尚未完成,是否强制关闭?', '提示', {
  152. confirmButtonText: '确认',
  153. cancelButtonText: '取消',
  154. type: 'warning'
  155. }).then(() => {
  156. this.$log.info('支付进程被强制关闭')
  157. this.visible = false
  158. // 结束支付进程
  159. this.killAllPosProcess()
  160. }).catch(() => { })
  161. return
  162. }
  163. this.visible = false
  164. // 结束支付进程
  165. this.killAllPosProcess()
  166. },
  167. // 使用现有pos消费信息进行出票
  168. handleQueryPos (posInfo) {
  169. this.setParams()
  170. this.params.bocTradeNo = JSON.stringify(posInfo)
  171. if (this.$NP.divide(posInfo.amount, 100) !== this.params.price) {
  172. this.$message.error('消费金额与当前出票信息不符。')
  173. return
  174. }
  175. this.createOrder(this.params)
  176. },
  177. submit: debounce(1000, true, function (qrcode, cardInfo) {
  178. this.handleSubmit(qrcode, cardInfo)
  179. }),
  180. handleSubmit (qrcode, cardInfo) {
  181. console.log(this.payType)
  182. // 登记出票:跳过全部支付流程,创单即完成
  183. if (this.isRegisterOrder) {
  184. return this.submitRegister()
  185. }
  186. // 西宁景区储值卡支付预留
  187. if (this.payType === 'VALUECARD' && this.scenicName === '西宁景区') {
  188. this.setParams()
  189. this.$refs.readValueCard.show(this.params)
  190. return
  191. }
  192. // POS支付是否使用外部扫码
  193. if (this.payType === 'POS' && this.currentPayChannel === '聚合扫码' && !qrcode && this.showPosQrcode) {
  194. this.$refs.posQrCodeReader.show()
  195. return
  196. }
  197. // debugger;
  198. // 是否使用外部扫码
  199. if (this.payType === 'B_SCAN_C_PAY' && !qrcode) {
  200. if (this.submitDisable) return
  201. this.setParams()
  202. this.submitDisable = true
  203. createOrder(this.params).then(res => {
  204. this.$log.warn(this.pageName + '下单成功')
  205. this.createOrderStatus = 1
  206. this.orderTempInfo = res.data.order || {}
  207. this.payCodeDialogVisible = true
  208. // this.$refs.XSCQrCodeReader.show(this.tickets, this.currentPayChannel)
  209. this.submitDisable = false
  210. })
  211. .catch(e => {
  212. this.submitDisable = false
  213. })
  214. return
  215. }
  216. // 储值卡支付
  217. if (this.currentPayChannel === '储值卡支付' && !cardInfo) {
  218. this.$refs.ValueCardInput.show(this.tickets, this.currentPayChannel)
  219. return
  220. }
  221. // 防止重复提交
  222. if (this.submitDisable) return
  223. this.submitDisable = true
  224. // 支付已成功只提交订单
  225. if (this.payStatus === 1) {
  226. this.createOrder(this.params)
  227. return
  228. }
  229. // 设置参数
  230. this.setParams()
  231. if (typeof this.params.guestId === 'string') {
  232. this.params.guideName = this.params.guestId
  233. this.params.guestId = null
  234. }
  235. this.params.qrCode = (qrcode || '').trim()
  236. this.params.discount = cardInfo ? cardInfo.discount : ''
  237. this.params.password = cardInfo ? cardInfo.password : ''
  238. this.params.memberSystemId = cardInfo ? cardInfo.memberSystemId : ''
  239. this.$log.warn(this.pageName + '支付下单')
  240. this.createOrder(this.params)
  241. },
  242. handleValueCardPay (cardInfo) {
  243. console.log('储值卡信息', cardInfo)
  244. this.$log.info('储值卡信息', JSON.stringify(cardInfo))
  245. createValueCardOrder({
  246. cardNo: cardInfo.cardCode,
  247. cardVendor: 'CHANGYI',
  248. order: this.params
  249. }).then(res => {
  250. this.handleCreateSuccess(this.params, res)
  251. })
  252. },
  253. submitOnlinePay () {
  254. // 扫码盒子通常会在码值末尾追加回车/空格,提交前需要去掉
  255. const payCode = (this.payCode || '').trim()
  256. if (!payCode) {
  257. this.$message.error('请输入支付码')
  258. return
  259. }
  260. this.payCodeDialogVisible = false
  261. // 直接调用 handleSubmit,避免被 submit 的 1000ms 前置节流吞掉(扫码盒子输入极快时必现)
  262. this.handleSubmit(payCode)
  263. // this.createOrder(this.params, true)
  264. },
  265. cancelOnlinePay () {
  266. this.payCodeDialogVisible = false
  267. this.payCode = ''
  268. },
  269. submitRegister () {
  270. // 防止重复提交
  271. if (this.submitDisable) return
  272. this.submitDisable = true
  273. this.setParams()
  274. const params = this.params
  275. params.isRegisterOrder = 1
  276. this.createOrder(params)
  277. },
  278. createOrder (params, isOnlinePay = false) {
  279. // if (this.payType === 'B_SCAN_C_PAY' && !isOnlinePay) {
  280. // this.payCodeDialogVisible = true
  281. // return
  282. // }
  283. this.submitDisable = true
  284. params.tickets.forEach(ticket => {
  285. if (params.checkWay !== 5) {
  286. ticket.ticketNo = ''
  287. ticket.isStorage = 0
  288. } else {
  289. ticket.isStorage = 1 // 预印票
  290. }
  291. ticket.face = {
  292. faceImg: ticket.face
  293. }
  294. ticket.batchConfigId = params.batchConfigId || ticket.batchConfigId || ''
  295. })
  296. params.discountDescription = params.tickets.map((item) => item.discountDescription).filter(i => i).join(',')
  297. params.createOrderRemark = this.createOrderRemark
  298. this.tickets = params.tickets
  299. // debugger;
  300. if (this.createOrderStatus === 1) {
  301. handlePay(this.params, this.orderTempInfo, this, () => { })
  302. if (this.payStatus !== 1) {
  303. this.getSingleOrder(this.orderTempInfo, params)
  304. }
  305. } else {
  306. createOrder(params).then(res => {
  307. const order = res.data.order
  308. this.$log.warn(`下单成功,订单号ID:${order.id}`)
  309. this.createOrderStatus = 1
  310. this.orderTempInfo = order
  311. // 登记出票:创单即完成,不发起支付、不轮询支付状态
  312. if (this.isRegisterOrder) {
  313. EventBus.$emit('orderCreated', order)
  314. this.handleCreateSuccess(params, order)
  315. return
  316. }
  317. handlePay(this.params, order, this, () => { })
  318. if (this.payStatus !== 1) {
  319. this.getSingleOrder(order, params)
  320. }
  321. EventBus.$emit('orderCreated', order)
  322. }).catch(e => {
  323. this.submitDisable = false
  324. EventBus.$emit('orderCreated')
  325. })
  326. }
  327. },
  328. getSingleOrder (order, params) {
  329. const orderId = order?.id
  330. if (!orderId) return
  331. this.timer && clearTimeout(this.timer)
  332. getSingleOrder(orderId).then(res => {
  333. if (res.data?.payStatus === 'PAYED') {
  334. this.$log.warn(`支付成功,订单号:${res.data.orderNo}`)
  335. this.submitDisable = false
  336. this.handleCreateSuccess(params, res.data)
  337. } else if (res.data?.payStatus === 'CLOSED') {
  338. this.$message.error('交易失败,订单关闭,请重新创建订单')
  339. this.submitDisable = false
  340. this.visible = false
  341. } else {
  342. this.timer = setTimeout(() => {
  343. this.getSingleOrder(order, params)
  344. }, 2000)
  345. }
  346. })
  347. },
  348. handleCreateSuccess (params, order) {
  349. this.$message.success('出票成功')
  350. this.submitDisable = false
  351. this.payCode = ''
  352. // 获取订单详情
  353. // 自动打印
  354. getSingleOrder(order?.id).then(async res => {
  355. this.isPrintSmallTicket && this.$printSmallTicket(order)
  356. const order2 = JSON.parse(JSON.stringify(res.data))
  357. this.isPrint && this.$print(order2)
  358. })
  359. // 关闭弹窗
  360. this.handleClose()
  361. this.$emit('complete')
  362. this.createSuccessCallback && this.createSuccessCallback()
  363. },
  364. beforeDestroy () {
  365. this.killAllPosProcess()
  366. this.payCode = ''
  367. },
  368. handlePayCodeInput (e) {
  369. this.timer && clearTimeout(this.timer)
  370. this.timer = setTimeout(() => {
  371. if ((this.payCode || '').trim().length > 10) {
  372. this.submitOnlinePay()
  373. }
  374. }, 200)
  375. }
  376. },
  377. watch: {
  378. payCode (val) {
  379. if (val) {
  380. this.handlePayCodeInput()
  381. }
  382. },
  383. payCodeDialogVisible (val) {
  384. if (val) {
  385. this.$nextTick(() => {
  386. if (this.$refs.payCodeInputRef) {
  387. this.payCode = ''
  388. this.$refs.payCodeInputRef.focus()
  389. }
  390. })
  391. }
  392. }
  393. }
  394. }