index.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import request from '@/helpers/request'
  2. import {
  3. listenerMessage,
  4. postMessage,
  5. removeListenerMessage
  6. } from '@/helpers/native-message'
  7. import {
  8. Button,
  9. Cell,
  10. CellGroup,
  11. Icon,
  12. RadioGroup,
  13. Radio,
  14. Dialog,
  15. Toast
  16. } from 'vant'
  17. import { defineComponent, PropType } from 'vue'
  18. import styles from './index.module.less'
  19. import { state } from '@/state'
  20. interface IOrderInfo {
  21. orderNo: string | number
  22. actualPrice: string | number
  23. }
  24. const urlFix =
  25. state.platformType === 'TEACHER' ? '/api-teacher' : '/api-student'
  26. const urlType = {
  27. goodsPay: {
  28. cancelUrl: '/api-mall-portal/order/cancelUserOrder',
  29. payUrl: '/api-mall-portal/payment/orderPay'
  30. },
  31. orderPay: {
  32. cancelUrl: urlFix + '/userOrder/orderCancel',
  33. payUrl: urlFix + '/userOrder/orderPay'
  34. }
  35. }
  36. export default defineComponent({
  37. name: 'payment',
  38. props: {
  39. modelValue: {
  40. type: Boolean,
  41. default: false
  42. },
  43. orderInfo: {
  44. type: Object as PropType<IOrderInfo>,
  45. default: {
  46. orderNo: '',
  47. actualPrice: 0
  48. }
  49. },
  50. onBackOut: {
  51. type: Function,
  52. default: () => {}
  53. },
  54. paymentType: {
  55. type: String,
  56. default: 'orderPay' as 'orderPay' | 'goodsPay'
  57. }
  58. },
  59. data() {
  60. return {
  61. payType: 'ali_app',
  62. pay_channel: ''
  63. }
  64. },
  65. unmounted() {
  66. removeListenerMessage('paymentOperation', this.paymentOperation)
  67. },
  68. methods: {
  69. onClose() {
  70. Dialog.confirm({
  71. message: '是否放弃本次付款',
  72. confirmButtonText: '继续付款',
  73. cancelButtonText: '放弃'
  74. })
  75. .then(() => {})
  76. .catch(async () => {
  77. this.onCancel()
  78. })
  79. },
  80. async onCancel(noBack?: boolean) {
  81. try {
  82. await request.post(urlType[this.paymentType].cancelUrl, {
  83. data: {
  84. orderNo: this.orderInfo.orderNo
  85. }
  86. })
  87. } catch {}
  88. // 不管接口是否报错,都返回
  89. this.$emit('update:modelValue', false)
  90. !noBack && this.$router.go(-1)
  91. this.onBackOut && this.onBackOut()
  92. },
  93. async onSubmit() {
  94. // 支付...
  95. try {
  96. let params = {
  97. orderNo: this.orderInfo.orderNo,
  98. payChannel: this.payType,
  99. paymentClient: null as any
  100. }
  101. if (this.paymentType === 'goodsPay') {
  102. params.paymentClient = state.platformType
  103. }
  104. let res = await request.post(urlType[this.paymentType].payUrl, {
  105. data: {
  106. ...params
  107. }
  108. })
  109. postMessage({
  110. api: 'paymentOrder',
  111. content: {
  112. orderNo: this.orderInfo.orderNo,
  113. payChannel: this.payType,
  114. // payInfo: `alipays://platformapi/startapp?saId=10000007&qrcode=${res.data.pay_info}`
  115. payInfo: res.data.pay_info
  116. }
  117. })
  118. Toast.loading({
  119. message: '支付中...',
  120. forbidClick: true,
  121. duration: 3000,
  122. loadingType: 'spinner'
  123. })
  124. Toast.clear()
  125. this.$emit('update:modelValue', false)
  126. // 唤起支付时状态
  127. listenerMessage('paymentOperation', (result: any) =>
  128. this.paymentOperation(result)
  129. )
  130. } catch (e: any) {
  131. console.log(e)
  132. }
  133. },
  134. paymentOperation(res: any) {
  135. if (res.status === 'success') {
  136. Toast.clear()
  137. this.$emit('update:modelValue', false)
  138. this.$router.replace({
  139. path: '/tradeDetail',
  140. query: {
  141. orderNo: this.orderInfo.orderNo
  142. }
  143. })
  144. } else if (res.status === 'cancel') {
  145. Toast.clear()
  146. this.$emit('update:modelValue', false)
  147. } else if (res.status === 'fail') {
  148. Dialog.alert({
  149. title: '提示',
  150. message: '您尚未安装支付宝'
  151. }).then(() => {
  152. Toast.clear()
  153. this.$emit('update:modelValue', false)
  154. })
  155. }
  156. }
  157. },
  158. render() {
  159. return (
  160. <div class={styles.payment}>
  161. <Icon onClick={this.onClose} name="cross" size={20} />
  162. <div class={[styles.title, 'van-hairline--bottom']}>选择支付方式</div>
  163. <div class={styles.payAmount}>
  164. <p>应付金额</p>
  165. <div class={styles.amount}>
  166. {(this as any).$filters.moneyFormat(this.orderInfo.actualPrice)}
  167. <span>元</span>
  168. </div>
  169. </div>
  170. <RadioGroup v-model={this.payType}>
  171. <CellGroup border={false}>
  172. <Cell
  173. title="支付宝支付"
  174. border={false}
  175. center
  176. onClick={() => {
  177. // alipay
  178. this.payType = 'ali_app'
  179. }}
  180. v-slots={{
  181. icon: () => <Icon name="alipay" color="#009fe9" size={22} />,
  182. 'right-icon': () => <Radio name="ali_app" />
  183. }}
  184. ></Cell>
  185. <Cell
  186. title="微信支付"
  187. border={false}
  188. center
  189. onClick={() => {
  190. // wx_lite
  191. this.payType = 'wx_app'
  192. }}
  193. v-slots={{
  194. icon: () => (
  195. <Icon name="wechat-pay" color="#15c434" size={22} />
  196. ),
  197. 'right-icon': () => <Radio name="wx_app" />
  198. }}
  199. ></Cell>
  200. </CellGroup>
  201. </RadioGroup>
  202. <div class={styles.blank}></div>
  203. <Button type="primary" block onClick={this.onSubmit}>
  204. 确认支付
  205. </Button>
  206. </div>
  207. )
  208. }
  209. })