index.tsx 6.8 KB

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