index.tsx 12 KB

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