index.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. import { Button, Cell, Icon, Image, showConfirmDialog } from 'vant';
  2. import { defineComponent } from 'vue';
  3. import styles from './index.module.less';
  4. import request from '@/helpers/request';
  5. import iconStudent from '@common/images/icon-student.png';
  6. import iconMemberLogo from './images/member_logo.png';
  7. import iconGift from '../student-register/images/icon-gift.png';
  8. import { moneyFormat } from '@/helpers/utils';
  9. import OHeader from '@/components/m-header';
  10. import member1 from './images/member-1.png';
  11. import member2 from './images/member-2.png';
  12. import ODialog from '@/components/m-dialog';
  13. import { useEventListener, useWindowScroll } from '@vueuse/core';
  14. import dayjs from 'dayjs';
  15. export default defineComponent({
  16. name: 'MemberCenter',
  17. data() {
  18. return {
  19. functionList: [] as any,
  20. selectMember: {} as any,
  21. users: {} as any,
  22. memberStatus: false,
  23. background: 'transparent',
  24. color: '#fff',
  25. showTips: false,
  26. showMessage: ''
  27. };
  28. },
  29. computed: {
  30. userInfo() {
  31. const users: any = this.users;
  32. return {
  33. username: users?.nickname || '',
  34. phone: users?.phone || '',
  35. avatar: users?.avatar,
  36. id: users?.id,
  37. isVip: users?.vipMember,
  38. membershipGiftDays: users?.membershipGiftDays,
  39. membershipDays: users?.membershipDays,
  40. membershipEndTime: dayjs(users?.membershipEndTime).format('YYYY-MM-DD')
  41. };
  42. }
  43. },
  44. async mounted() {
  45. useEventListener(document, 'scroll', () => {
  46. const { y } = useWindowScroll();
  47. if (y.value > 15) {
  48. this.background = '#fff';
  49. this.color = '#323333';
  50. } else {
  51. this.background = 'transparent';
  52. this.color = '#fff';
  53. }
  54. });
  55. //
  56. this.__init();
  57. },
  58. methods: {
  59. async __init() {
  60. try {
  61. const userInfo = await request.get('/edu-app/student/member');
  62. this.users = userInfo.data || {};
  63. const { data } = await request.post(`/edu-app/cityFeeSetting/member`);
  64. this.selectMember = data;
  65. this.paymentOrderUnpaid();
  66. } catch {
  67. //
  68. }
  69. },
  70. // 查询未支付订单
  71. async paymentOrderUnpaid() {
  72. try {
  73. const { data } = await request.get('/edu-app/userPaymentOrder/unpaid', {
  74. requestType: 'form',
  75. params: {
  76. paymentType: 'VIP'
  77. }
  78. });
  79. // 判断是否有待支付订单
  80. if (data.id) {
  81. showConfirmDialog({
  82. message: '您有待支付的订单,是否继续支付',
  83. cancelButtonText: '取消订单',
  84. confirmButtonText: '继续支付'
  85. })
  86. .then(() => {
  87. const paymentConfig = data.paymentConfig;
  88. this.$router.push({
  89. path: '/order-detail',
  90. query: {
  91. config: JSON.stringify(paymentConfig.paymentConfig),
  92. orderNo: paymentConfig.orderNo
  93. }
  94. });
  95. })
  96. .catch(async () => {
  97. try {
  98. await request.post(
  99. '/edu-app/userPaymentOrder/cancelPayment/' + data.orderNo
  100. );
  101. } catch {
  102. //
  103. }
  104. });
  105. }
  106. } catch {
  107. //
  108. }
  109. },
  110. calcSalePrice(item: any) {
  111. // discount
  112. if (item.discount === 1) {
  113. const tempPrice = Number(
  114. (item.salePrice - item.discountPrice).toFixed(2)
  115. );
  116. return tempPrice >= 0 ? tempPrice : 0;
  117. }
  118. return item.salePrice;
  119. },
  120. // 购买
  121. async onSubmit() {
  122. try {
  123. const selectMember = this.selectMember;
  124. const params: any = [
  125. {
  126. goodsId: selectMember.id,
  127. goodsNum: 1,
  128. goodsType: 'VIP',
  129. paymentCashAmount: selectMember.salePrice, // 现金支付金额
  130. paymentCouponAmount: 0 // 优惠券金额
  131. }
  132. ]; // 支付参数
  133. // 创建订单
  134. const result = await request.post(
  135. '/edu-app/userPaymentOrder/executeOrder',
  136. {
  137. data: {
  138. orderType: 'VIP',
  139. paymentCashAmount: this.selectMember.salePrice || 0,
  140. paymentCouponAmount: 0,
  141. goodsInfos: params,
  142. orderName: '乐器AI学练工具',
  143. orderDesc: '乐器AI学练工具'
  144. }
  145. }
  146. );
  147. if (result.code === 5435) {
  148. this.showTips = true;
  149. this.showMessage = result.message;
  150. return;
  151. }
  152. const data = result.data;
  153. const res = await request.get(
  154. '/edu-app/userPaymentOrder/detail/' + data.orderNo
  155. );
  156. if (res.data.status !== 'WAIT_PAY' && res.data.status !== 'PAYING') {
  157. this.$router.push({
  158. path: '/payment-result',
  159. query: {
  160. orderNo: data.orderNo
  161. }
  162. });
  163. } else {
  164. this.$router.push({
  165. path: '/order-detail',
  166. query: {
  167. config: JSON.stringify({
  168. ...data.paymentConfig,
  169. paymentType: data.paymentType
  170. }),
  171. orderNo: data.orderNo
  172. }
  173. });
  174. }
  175. } catch (e: any) {
  176. //
  177. console.log(e);
  178. }
  179. }
  180. },
  181. render() {
  182. return (
  183. <div class={styles['member-center']}>
  184. <OHeader
  185. background={this.background}
  186. color={this.color}
  187. border={false}
  188. />
  189. <div class={styles.member_container}>
  190. <Cell
  191. class={[styles.userMember]}
  192. labelClass={styles.timeRemaining}
  193. center
  194. v-slots={{
  195. icon: () => (
  196. <div class={styles.userImgSection}>
  197. <Image
  198. class={styles.userImg}
  199. src={this.userInfo.avatar || iconStudent}
  200. fit="cover"
  201. />
  202. </div>
  203. ),
  204. title: () => (
  205. <div class={styles.userInfo}>
  206. <span class={styles.name}>{this.userInfo.username}</span>
  207. {!!this.userInfo.isVip && (
  208. <Image class={styles.level} src={iconMemberLogo} />
  209. )}
  210. {this.userInfo.phone && (
  211. <span
  212. class={styles.phone}
  213. v-html={`(${this.userInfo.phone})`}></span>
  214. )}
  215. </div>
  216. ),
  217. label: () => (
  218. <div class={styles.member_time}>
  219. <>
  220. {this.userInfo.isVip ? (
  221. <div>
  222. {/* 使用有效期剩余
  223. <span class={styles.remaining}>
  224. {this.userInfo.membershipDays}
  225. </span>
  226. 天 */}
  227. 有效期至
  228. <span class={styles.remaining}>
  229. {this.userInfo.membershipEndTime}
  230. </span>
  231. </div>
  232. ) : (
  233. <div>您还未领取器乐学练工具哟</div>
  234. )}
  235. </>
  236. </div>
  237. )
  238. }}></Cell>
  239. </div>
  240. <div class={[styles.memberContainer]}>
  241. <div
  242. class={[
  243. styles.memberItem,
  244. this.users.membershipGiftDays > 0 ? styles.memberGift : ''
  245. ]}>
  246. <p class={[styles.title]}>
  247. 乐器AI学练工具
  248. <span>12个月</span>
  249. </p>
  250. <div class={styles.priceGroup}>
  251. <p class={styles.price}>
  252. <span>¥</span>
  253. {moneyFormat(this.selectMember.salePrice)}
  254. </p>
  255. {this.selectMember.salePrice <
  256. this.selectMember.originalPrice && (
  257. <del class={styles.originalPrice}>
  258. ¥{moneyFormat(this.selectMember.originalPrice)}
  259. </del>
  260. )}
  261. </div>
  262. {this.users.membershipGiftDays > 0 && (
  263. <Cell border={false} class={styles.giftCell}>
  264. {{
  265. title: () => (
  266. <div class={styles.gift}>
  267. <img src={iconGift} class={styles.iconGift} />
  268. 现在领取赠送{' '}
  269. <span>{this.users.membershipGiftDays || 0}</span>
  270. 天有效期
  271. </div>
  272. )
  273. }}
  274. </Cell>
  275. )}
  276. </div>
  277. <div class={styles.memberImgs}>
  278. <img src={member1} />
  279. <img src={member2} />
  280. </div>
  281. </div>
  282. <div class={styles.btnGroup}>
  283. <div class={styles.priceSection}>
  284. <div class={styles.price}>
  285. <span class={styles.priceUnit}>¥</span>
  286. <span class={styles.priceNum}>
  287. {moneyFormat(this.calcSalePrice(this.selectMember) || 0)}
  288. </span>
  289. </div>
  290. {this.selectMember.originalPrice >
  291. this.calcSalePrice(this.selectMember) || 0 ? (
  292. <del class={styles.allPrice}>
  293. ¥ {moneyFormat(this.selectMember.originalPrice)}
  294. </del>
  295. ) : (
  296. ''
  297. )}
  298. </div>
  299. {this.userInfo.id ? (
  300. <Button round class={styles.btn} onClick={this.onSubmit}>
  301. 立即领取
  302. </Button>
  303. ) : (
  304. ''
  305. )}
  306. </div>
  307. <ODialog
  308. v-model:show={this.memberStatus}
  309. title="待激活团练宝"
  310. message="为让团员有效使用乐团学习工具,首次加入乐团且购买团练宝的团员,团练宝的生效时间为乐团首次训练之日,具体训练时间可查看课表。"
  311. messageAlign="left"
  312. dialogMarginTop="env(safe-area-inset-top)"
  313. confirmButtonText="我知道了"
  314. />
  315. <ODialog
  316. v-model:show={this.showTips}
  317. title="温馨提示"
  318. message={this.showMessage}
  319. messageAlign="center"
  320. dialogMarginTop="env(safe-area-inset-top)"
  321. confirmButtonText="刷新"
  322. onConfirm={async () => {
  323. // window.location.reload();
  324. window.scrollTo({
  325. top: 0,
  326. behavior: 'smooth'
  327. });
  328. this.__init();
  329. }}
  330. />
  331. </div>
  332. );
  333. }
  334. });