index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. import ColProtocol from '@/components/col-protocol'
  2. import { Button, Dialog, Icon, Popup, Sticky, Toast } from 'vant'
  3. import ColPopup from '@/components/col-popup'
  4. import { defineComponent } from 'vue'
  5. import { postMessage } from '@/helpers/native-message'
  6. import styles from './index.module.less'
  7. import UserAuth from './userAuth'
  8. import request from '@/helpers/request'
  9. // 调用原生支付
  10. // postMessage({ api: 'paymentOrder', content: { orderNo: 0 } })
  11. // listenerMessage({ api: 'paymentResult', callback: (res: any) => {
  12. // status: 'success | fail'
  13. // }})
  14. import iconTips from '@common/images/icon_tips.png'
  15. import Payment from './payment'
  16. import ColHeader from '@/components/col-header'
  17. import { state } from '@/state'
  18. import { orderInfos, orderStatus } from './orderStatus'
  19. import OrderVideo from './order-video'
  20. import OrderLive from './order-live'
  21. import OrderPractice from './order-practice'
  22. import OrderVip from './order-vip'
  23. import OrderMusic from './order-music'
  24. import { moneyFormat } from '@/helpers/utils'
  25. import OrderPinao from './order-pinao'
  26. import { getMusicDetail } from '@/student/trade/tradeOrder'
  27. import OrderActive from './order-active'
  28. export default defineComponent({
  29. name: 'order-detail',
  30. data() {
  31. const query = this.$route.query
  32. return {
  33. loading: false, // 是否加载中,为了处理0元订单()
  34. orderType: query.orderType,
  35. recomUserId: query.recomUserId, // 推荐人id
  36. activityId: query.activityId, // 活动编号
  37. id: query.id,
  38. agreeStatus: false,
  39. popupShow: false,
  40. paymentStatus: false,
  41. orderPrice: 0 // 支付金额
  42. }
  43. },
  44. unmounted() {
  45. // 销毁时解绑监听
  46. orderStatus.orderInfo = {
  47. orderNo: '',
  48. actualPrice: 0,
  49. payStatus: false
  50. }
  51. },
  52. computed: {
  53. orderList() {
  54. // 商品列表
  55. const orderObject = orderStatus.orderObject
  56. return orderObject.orderList || []
  57. }
  58. // orderInfos() {
  59. // // 商品列表
  60. // const orderList = orderStatus.orderObject.orderList || []
  61. // return orderList.map((item: any) => {
  62. // const params = {
  63. // goodType: item.orderType,
  64. // goodName: item.goodsName,
  65. // recomUserId: item.recomUserId, // 推荐人id
  66. // bizContent: {}
  67. // }
  68. // if (item.orderType === 'VIDEO') {
  69. // params.bizContent = {
  70. // videoLessonGroupId: item.courseGroupId,
  71. // payMoney: item.coursePrice || 0
  72. // }
  73. // } else if (item.orderType === 'LIVE') {
  74. // params.bizContent = {
  75. // groupId: item.courseGroupId
  76. // }
  77. // } else if (item.orderType === 'PRACTICE') {
  78. // const tempTime = item.classTime || []
  79. // const classCourse: any = []
  80. // tempTime.forEach((time: any) => {
  81. // classCourse.push({
  82. // classDate: time.classDate,
  83. // startTime: time.startTime,
  84. // endTime: time.endTime
  85. // })
  86. // })
  87. // params.bizContent = {
  88. // courseGroupName: item.courseGroupName,
  89. // courseIntroduce: item.courseIntroduce,
  90. // subjectId: item.subjectId,
  91. // singleCourseMinutes: item.singleCourseMinutes,
  92. // courseNum: item.courseNum,
  93. // coursePrice: item.coursePrice,
  94. // teacherId: item.teacherId,
  95. // classTime: classCourse
  96. // }
  97. // } else if (item.orderType === 'VIP') {
  98. // params.bizContent = item.id
  99. // } else if (item.orderType === 'MUSIC') {
  100. // params.bizContent = {
  101. // musicSheetId: item.id,
  102. // actualPrice: item.actualPrice || 0,
  103. // clientType: state.platformType
  104. // }
  105. // } else if (item.orderType === 'PINAO_ROOM') {
  106. // params.bizContent = item.id
  107. // } else if (item.orderType === 'ACTI_REGIST') {
  108. // params.bizContent = {
  109. // activityId: item.activityId
  110. // }
  111. // }
  112. // return params
  113. // })
  114. // }
  115. },
  116. async mounted() {
  117. // 判断是否是曲目购买(只有智能陪练才会有入口),其它地方不会有入口
  118. if (this.orderType == 'MUSIC' && this.id) {
  119. try {
  120. const item = await getMusicDetail(this.id)
  121. orderStatus.orderObject.orderType = 'MUSIC'
  122. orderStatus.orderObject.orderName = item.musicSheetName
  123. orderStatus.orderObject.orderDesc = item.musicSheetName
  124. orderStatus.orderObject.actualPrice = item.musicPrice
  125. orderStatus.orderObject.recomUserId = this.recomUserId
  126. orderStatus.orderObject.activityId = this.activityId
  127. // 判断当前订单是否在支付中
  128. if (['WAIT_PAY', 'PAYING'].includes(item.orderStatus)) {
  129. orderStatus.orderObject.orderNo = item.orderNo
  130. } else if (['PAID', 'CLOSE', 'FAIL'].includes(item.orderStatus)) {
  131. // 判断订单是否是其它状态
  132. Toast('订单有误')
  133. postMessage({ api: 'back', content: {} })
  134. }
  135. orderStatus.orderObject.orderList = [
  136. {
  137. orderType: 'MUSIC',
  138. goodsName: item.musicSheetName,
  139. actualPrice: item.musicPrice,
  140. ...item
  141. }
  142. ]
  143. } catch {
  144. //
  145. }
  146. }
  147. this.orderPrice = orderStatus.orderObject.actualPrice || 0
  148. // 0元支付特别处理
  149. if (this.orderPrice === 0 && orderStatus.orderObject.orderType) {
  150. this.loading = true
  151. this.onSubmit()
  152. }
  153. },
  154. methods: {
  155. onAuthSuccess() {
  156. // console.log('auth success')
  157. this.popupShow = false
  158. this.onSubmit() // 实名成功后自动支付
  159. },
  160. async onSubmit() {
  161. // console.log(this.orderInfos)
  162. if (this.orderPrice > 0) {
  163. if (!this.agreeStatus) {
  164. Toast('请先阅读并同意《酷乐秀平台服务协议》')
  165. return
  166. }
  167. const users = state.user.data
  168. // 判断是否需要实名认证
  169. if (!users?.realName || !users?.idCardNo) {
  170. this.popupShow = true
  171. return
  172. }
  173. }
  174. // 判断是否有订单号
  175. if (orderStatus.orderObject.orderNo) {
  176. this.paymentStatus = true
  177. return
  178. }
  179. // 正常支付
  180. try {
  181. const orderObject = orderStatus.orderObject
  182. const url =
  183. state.platformType === 'TEACHER'
  184. ? '/api-teacher/userOrder/executeOrder'
  185. : '/api-student/userOrder/executeOrder'
  186. const res = await request.post(url, {
  187. data: {
  188. orderName: orderObject.orderName,
  189. orderDesc: orderObject.orderDesc,
  190. orderType: orderObject.orderType,
  191. actualPrice: orderObject.actualPrice || 0,
  192. recomUserId: orderObject.recomUserId,
  193. activityId: orderObject.activityId,
  194. orderInfos: [...orderInfos()]
  195. }
  196. })
  197. const result = res.data || {}
  198. // 支付成功
  199. if (result.status == 'PAID') {
  200. this.$router.replace({
  201. path: '/tradeDetail',
  202. query: {
  203. orderNo: result.orderNo
  204. }
  205. })
  206. return
  207. }
  208. // 拉起支付方式
  209. orderStatus.orderObject.orderNo = result.orderNo
  210. orderStatus.orderObject.actualPrice = result.actualPrice
  211. this.paymentStatus = true
  212. } catch {
  213. this.loading = false
  214. if (this.orderPrice === 0) {
  215. Dialog.alert({
  216. title: '提示',
  217. message: '支付失败,请稍后重试!',
  218. confirmButtonText: '确定',
  219. confirmButtonColor: '#2dc7aa'
  220. })
  221. }
  222. }
  223. },
  224. onBackOut() {
  225. // 关闭订单后需要重置数据
  226. orderStatus.orderObject = {
  227. orderNo: '',
  228. actualPrice: 0,
  229. orderName: '',
  230. orderDesc: '',
  231. orderType: '',
  232. recomUserId: null as any,
  233. orderList: []
  234. }
  235. }
  236. },
  237. render() {
  238. return (
  239. <div class={styles['order-detail']}>
  240. <ColHeader />
  241. {!this.loading && (
  242. <>
  243. {this.orderList.map((item: any) => {
  244. if (item.orderType === 'VIDEO') {
  245. return <OrderVideo item={item} />
  246. } else if (item.orderType === 'LIVE') {
  247. return <OrderLive item={item} />
  248. } else if (item.orderType === 'PRACTICE') {
  249. return <OrderPractice item={item} />
  250. } else if (item.orderType === 'VIP') {
  251. return <OrderVip item={item} />
  252. } else if (item.orderType === 'MUSIC') {
  253. return <OrderMusic item={item} />
  254. } else if (item.orderType === 'PINAO_ROOM') {
  255. return <OrderPinao item={item} />
  256. } else if (item.orderType === 'ACTI_REGIST') {
  257. return <OrderActive item={item} />
  258. }
  259. })}
  260. {/* <div class={styles.tips}>
  261. <h3>
  262. <Icon name={iconTips} size={15} />
  263. 温馨提示
  264. </h3>
  265. {state.platformType === 'TEACHER' ? (
  266. <p>
  267. 1、琴房时长为虚拟商品,一经购买不予退费; <br />
  268. 2、琴房时长消耗以时长扣减逻辑为准。
  269. </p>
  270. ) : (
  271. <p>
  272. 1、您支付的课程费用将由平台收取; <br />
  273. 2、陪练课、直播课课程结束后,平台将单课时费用向老师结算;
  274. <br />
  275. 3、除直播课未达到开课人数外,其他服务一经购买不予退费。
  276. </p>
  277. )}
  278. </div> */}
  279. <div class={styles.paymentInfo}>
  280. {this.orderPrice > 0 && (
  281. <div class={styles.protocol}>
  282. <ColProtocol
  283. v-model={this.agreeStatus}
  284. showHeader
  285. style={{ paddingLeft: 0, paddingRight: 0 }}
  286. />
  287. </div>
  288. )}
  289. <div class={styles.btnGroup}>
  290. <div class={styles.priceSection}>
  291. 支付金额:
  292. <div class={styles.price}>
  293. <span class={styles.priceUnit}>¥</span>
  294. <span class={styles.priceNum}>
  295. {moneyFormat(this.orderPrice)}
  296. </span>
  297. </div>
  298. </div>
  299. <Button
  300. type="primary"
  301. round
  302. class={styles.btn}
  303. onClick={this.onSubmit}
  304. >
  305. 立即支付
  306. </Button>
  307. </div>
  308. </div>
  309. </>
  310. )}
  311. <ColPopup v-model={this.popupShow}>
  312. <UserAuth onSuccess={this.onAuthSuccess} />
  313. </ColPopup>
  314. <Popup
  315. show={this.paymentStatus}
  316. closeOnClickOverlay={false}
  317. position="bottom"
  318. round
  319. closeOnPopstate
  320. safeAreaInsetBottom
  321. style={{ minHeight: '30%' }}
  322. >
  323. <Payment
  324. v-model={this.paymentStatus}
  325. orderInfo={orderStatus.orderObject}
  326. onBackOut={this.onBackOut}
  327. />
  328. </Popup>
  329. </div>
  330. )
  331. }
  332. })