index.tsx 12 KB

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