index.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. // index.ts
  2. import { api_shopInstruments, api_shopProduct } from "../../api/login";
  3. import { api_getOpenId, api_trackPointLog } from "../../api/new";
  4. import { debounce, formatPrice, formatTime } from "../../utils/util";
  5. // 获取应用实例
  6. const app = getApp<IAppOption>();
  7. // pages/orders/orders.ts
  8. Page({
  9. /**
  10. * 页面的初始数据
  11. */
  12. data: {
  13. imgList: [
  14. // 'https://oss.dayaedu.com/ktyq/1732585725698.png',
  15. // 'https://oss.dayaedu.com/ktyq/1732519468124.png',
  16. // 'https://oss.dayaedu.com/ktyq/1732519479416.png',
  17. // 'https://oss.dayaedu.com/ktyq/1733110029242.png',
  18. // 'https://oss.dayaedu.com/ktyq/1732519500580.png'
  19. "https://oss.dayaedu.com/ktyq/1733449062928.png",
  20. "https://oss.dayaedu.com/ktyq/1733449075055.png",
  21. "https://oss.dayaedu.com/ktyq/1733449085983.png",
  22. "https://oss.dayaedu.com/ktyq/1733449097054.png",
  23. ],
  24. goodsImgList: [
  25. "https://oss.dayaedu.com/ktyq/1739353790443.png",
  26. "https://oss.dayaedu.com/ktyq/1739353815962.png",
  27. "https://oss.dayaedu.com/ktyq/1739353843494.png",
  28. "https://oss.dayaedu.com/ktyq/1739353862133.png",
  29. ],
  30. detailImgList: [
  31. {
  32. url: "https://oss.dayaedu.com/ktyq/1733403675345.png",
  33. text: "合作学校音乐数字课堂公开课",
  34. },
  35. {
  36. url: "https://oss.dayaedu.com/ktyq/1733403707851.png",
  37. text: "音乐课课堂器乐教学",
  38. },
  39. {
  40. url: "https://oss.dayaedu.com/ktyq/1733403725644.png",
  41. text: "学期末汇报演出",
  42. },
  43. ],
  44. serviceShow: true,
  45. scrollTop: 0,
  46. current: 0,
  47. detailCurrent: 0,
  48. autoplay: false,
  49. interval: 5000,
  50. duration: 500,
  51. popupShow: false,
  52. videoHeight: "255px",
  53. list: [] as any,
  54. instrumentList: [] as any,
  55. isOverSaled: false, // 是否所有商品都没有库存
  56. selected: {} as any,
  57. selectInstrumentId: '', // 选中的乐器
  58. selectedInstrument: {} as any,
  59. formatSelectGood: {
  60. typeName: '',
  61. showSalePrice: '', // 显示的现价
  62. originalPrice: 0, // 原价
  63. salePrice: 0, // 现价
  64. discountPrice: '' // 已省
  65. } as any, // 格式化所有选中的数据
  66. opacity: 0,
  67. // showSelectedProduct: false, // 是否显示选中商品值
  68. scrolIntoViewStr: "",
  69. scrolIntoView: "",
  70. scrollDiscount: false, // 是否扣减启
  71. isScrollTT: false,
  72. scrollIntoViewType: false,
  73. headerHeight: 0, // 头部的高度
  74. initialScrollHeight: 0, // 滚动高度
  75. isFromPreviewImage: false,
  76. bannerPlay: false, // 视频是否播放
  77. titleControls: false, // 详情是否显示控制条
  78. liuControls: false, // 详情是否显示控制条
  79. bannerImageloaded: false, // Banner图片是否加载完成
  80. },
  81. /**
  82. * 生命周期函数--监听页面加载
  83. */
  84. onLoad() {
  85. // this.onInit()
  86. const wxWindowInfo = wx.getWindowInfo();
  87. this.setData({
  88. videoHeight: (wxWindowInfo.windowWidth / 16) * 9 + "px",
  89. });
  90. // 首页进入页面埋点
  91. this.onHomePageTrackPoint()
  92. },
  93. onHomePageTrackPoint() {
  94. // openId
  95. const openId = wx.getStorageSync("openId")
  96. if(openId) {
  97. this.onTrackPoint({
  98. openId,
  99. elementName: '首页'
  100. })
  101. } else {
  102. wx.login({
  103. success: async (res) => {
  104. await api_getOpenId({
  105. code: res.code,
  106. appId: app.globalData.appId
  107. }).then((res: any) => {
  108. // 存储openId
  109. const openId = res.data.data
  110. wx.setStorageSync("openId", openId);
  111. this.onTrackPoint({
  112. openId,
  113. elementName: '首页'
  114. })
  115. })
  116. }
  117. })
  118. }
  119. },
  120. onReady() {
  121. const that = this;
  122. wx.createSelectorQuery()
  123. .select("#scroll-header")
  124. .boundingClientRect(function (rect) {
  125. that.setData({
  126. headerHeight: rect.height,
  127. });
  128. })
  129. .exec();
  130. wx.createSelectorQuery()
  131. .select("#scroll-view")
  132. .boundingClientRect(function (rect) {
  133. // console.log(rect, 'rect')
  134. that.setData({
  135. initialScrollHeight: rect.height,
  136. });
  137. })
  138. .exec();
  139. },
  140. onBannerVideoLoad() {
  141. this.setData({
  142. bannerImageloaded: true,
  143. });
  144. },
  145. onBannerPlay() {
  146. const bannerVideo = wx.createVideoContext("bannerVideo");
  147. const titleVideo = wx.createVideoContext("titleVideo");
  148. //
  149. this.setData(
  150. {
  151. bannerPlay: true,
  152. },
  153. () => {
  154. bannerVideo.play();
  155. titleVideo.pause();
  156. // liuVideo.stop()
  157. }
  158. );
  159. },
  160. onBannerVideoPlay() {
  161. const titleVideo = wx.createVideoContext("titleVideo");
  162. titleVideo.pause();
  163. // const liuVideo = wx.createVideoContext('liuVideo')
  164. // liuVideo.stop()
  165. },
  166. onTitlePlay() {
  167. const bannerVideo = wx.createVideoContext("bannerVideo");
  168. bannerVideo.pause();
  169. // const liuVideo = wx.createVideoContext('liuVideo')
  170. // liuVideo.stop()
  171. },
  172. onTItleVideoPlay() {
  173. const bannerVideo = wx.createVideoContext("bannerVideo");
  174. const titleVideo = wx.createVideoContext("titleVideo");
  175. // const liuVideo = wx.createVideoContext('liuVideo')
  176. this.setData(
  177. {
  178. titleControls: true,
  179. },
  180. () => {
  181. titleVideo.play();
  182. bannerVideo.pause();
  183. // liuVideo.stop()
  184. }
  185. );
  186. },
  187. onLiuPlay() {
  188. const bannerVideo = wx.createVideoContext("bannerVideo");
  189. bannerVideo.pause();
  190. const titleVideo = wx.createVideoContext("titleVideo");
  191. titleVideo.pause();
  192. },
  193. onLiuVideoPlay() {
  194. const bannerVideo = wx.createVideoContext("bannerVideo");
  195. const titleVideo = wx.createVideoContext("titleVideo");
  196. // const liuVideo = wx.createVideoContext('liuVideo')
  197. bannerVideo.pause();
  198. titleVideo.pause();
  199. this.setData(
  200. {
  201. liuControls: true,
  202. },
  203. () => {
  204. // liuVideo.play()
  205. }
  206. );
  207. },
  208. /**
  209. * 获取基础信息
  210. */
  211. async onInit() {
  212. try {
  213. const result = await api_shopInstruments({ appId: app.globalData.appId })
  214. const instrumentList = result.data.data || []
  215. instrumentList.forEach((item: any) => {
  216. item.showSalePrice = formatPrice(item.salePrice || 0, 'ALL')
  217. item.showOriginalPrice = formatPrice(item.originalPrice || 0, 'ALL')
  218. })
  219. const { data } = await api_shopProduct({ appId: app.globalData.appId });
  220. const list = data.data || [];
  221. let selected: any = {};
  222. let isOverSaled = true; // 是否销售完
  223. list.forEach((item: any) => {
  224. item.originalPrice = formatPrice(item.originalPrice, "ALL");
  225. item.showSalePrice = formatPrice(item.salePrice, "ALL");
  226. item.typeName = this.formatPeriod(item.num, item.period);
  227. item.discountPrice = formatPrice(
  228. item.originalPrice - item.salePrice,
  229. "ALL"
  230. );
  231. const prices: any = formatPrice(item.salePrice);
  232. item.integerPart = prices.integerPart;
  233. item.decimalPart = prices.decimalPart;
  234. // 格式化赠送内容
  235. item.giftLongTime = item.giftFlag
  236. ? this.formatGiftPeriod(item.giftVipDay, item.giftPeriod)
  237. : "";
  238. if (item.stockNum > 0) {
  239. isOverSaled = false;
  240. if (!selected.id) {
  241. selected = item;
  242. }
  243. }
  244. });
  245. if (isOverSaled) {
  246. // 没有可购买商品则默认选中第一个商品
  247. selected = list[0];
  248. }
  249. this.setData({
  250. list,
  251. instrumentList, // 乐器列表
  252. isOverSaled,
  253. selected,
  254. selectInstrumentId: '',
  255. selectedInstrument: {}
  256. }, () => {
  257. this.onFormatGoods()
  258. });
  259. } catch (e) {
  260. console.log(e, "e");
  261. }
  262. },
  263. // 格式化类型
  264. formatPeriod(num: number, type: string) {
  265. const template: any = {
  266. DAY: "天卡",
  267. MONTH: "月卡",
  268. YEAR: "年卡",
  269. };
  270. if (type === "YEAR" && num >= 99) {
  271. return "永久卡";
  272. }
  273. return num + template[type];
  274. },
  275. formatGiftPeriod(num: number, type: string) {
  276. if (!num || !type) {
  277. return "";
  278. }
  279. const template: any = {
  280. DAY: "天",
  281. MONTH: "个月",
  282. YEAR: "年",
  283. };
  284. return num + template[type];
  285. },
  286. // 选择
  287. onSelectGoods(e: any) {
  288. const { dataset } = e.currentTarget;
  289. const item = this.data.list.find((item: any) => item.id === dataset.id);
  290. // 判断是否有库存
  291. if (item.stockNum <= 0) {
  292. return;
  293. }
  294. this.setData({
  295. selected: item || {}
  296. }, () => {
  297. this.onFormatGoods()
  298. });
  299. },
  300. /** 选中乐器 */
  301. onSelectInstrument(e: any) {
  302. const { dataset } = e.currentTarget;
  303. if (dataset.id === this.data.selectInstrumentId) {
  304. this.setData({
  305. selectInstrumentId: '',
  306. selectedInstrument: {}
  307. }, () => {
  308. this.onFormatGoods()
  309. })
  310. } else {
  311. const item = this.data.instrumentList.find((item: any) => item.id === dataset.id);
  312. this.setData({
  313. selectInstrumentId: dataset.id,
  314. selectedInstrument: item || {}
  315. }, () => {
  316. this.onFormatGoods()
  317. })
  318. }
  319. },
  320. /** 格式化选中的商品 */
  321. onFormatGoods() {
  322. const selected = this.data.selected;
  323. const selectedInstrument = this.data.selectedInstrument
  324. const params = {
  325. typeName: '',
  326. showSalePrice: '' as any, // 显示的现价
  327. originalPrice: 0, // 原价
  328. salePrice: 0, // 现价
  329. discountPrice: '' as any, // 已省
  330. integerPart: '',
  331. decimalPart: '',
  332. }
  333. // 选中期限
  334. if (selected.id) {
  335. params.typeName = selected.typeName
  336. params.showSalePrice = selected.showSalePrice
  337. params.originalPrice = selected.originalPrice
  338. params.salePrice = selected.salePrice
  339. params.discountPrice = selected.discountPrice
  340. const prices: any = formatPrice(params.salePrice);
  341. params.integerPart = prices.integerPart
  342. params.decimalPart = prices.decimalPart
  343. }
  344. // 选中乐器
  345. if (selectedInstrument.id) {
  346. params.typeName = selected.typeName ? selected.typeName + '+' + selectedInstrument.name : selectedInstrument.name
  347. params.originalPrice = Number(selected.originalPrice) + Number(selectedInstrument.originalPrice)
  348. params.salePrice = Number(selected.salePrice) + Number(selectedInstrument.salePrice)
  349. params.showSalePrice = formatPrice(params.salePrice, "ALL");
  350. params.discountPrice = formatPrice(
  351. params.originalPrice - params.salePrice,
  352. "ALL"
  353. );
  354. const prices: any = formatPrice(params.salePrice);
  355. params.integerPart = prices.integerPart
  356. params.decimalPart = prices.decimalPart
  357. }
  358. this.setData({
  359. formatSelectGood: params
  360. })
  361. },
  362. // 事件处理函数
  363. changeSwiper(e: any) {
  364. const detail = e.detail;
  365. if (detail.source === "touch" || detail.source == "autoplay") {
  366. this.setData({
  367. current: detail.current,
  368. });
  369. this.onTitlePlay();
  370. }
  371. },
  372. changeSwiperDetail(e: any) {
  373. const detail = e.detail;
  374. if (detail.source === "touch" || detail.source == "autoplay") {
  375. this.setData({
  376. detailCurrent: detail.current,
  377. });
  378. }
  379. },
  380. isLogin() {
  381. // 判断是否登录
  382. if (!app.globalData.isLogin) {
  383. wx.navigateTo({
  384. url: "../login/login",
  385. });
  386. return false;
  387. }
  388. return true;
  389. },
  390. /** 我的订单 */
  391. onOrder() {
  392. // 判断是否登录
  393. if (!this.isLogin()) {
  394. return;
  395. }
  396. wx.navigateTo({
  397. url: "../orders/orders",
  398. });
  399. },
  400. onBuyShop() {
  401. // 判断是否登录
  402. if (!this.isLogin()) {
  403. return;
  404. }
  405. this.setData({
  406. popupShow: true,
  407. // showSelectedProduct: true,
  408. });
  409. },
  410. // 进行埋点
  411. onTrackPoint(options: { openId: string, elementName: string }) {
  412. const traceId = wx.getStorageSync("traceId");
  413. const deviceInfo = wx.getDeviceInfo();
  414. api_trackPointLog({
  415. traceId,
  416. openId: options.openId,
  417. elementName: options.elementName,
  418. deviceInfo: deviceInfo.brand + '_' + deviceInfo.model + '_' + deviceInfo.system + '_' + deviceInfo.platform,
  419. appName: "音乐数字AI",
  420. // extParams: '',
  421. clickTime: formatTime(new Date(), '-') // 点击时间
  422. })
  423. },
  424. onClose() {
  425. this.setData({
  426. popupShow: false,
  427. });
  428. },
  429. onSubmit() {
  430. // 判断是否登录
  431. const that = this;
  432. debounce(function () {
  433. if (!that.isLogin()) {
  434. return;
  435. }
  436. const params = [] as any
  437. const selected = that.data.selected
  438. if (selected.id) {
  439. params.push({
  440. pic: selected.pic,
  441. name: selected.name,
  442. originalPrice: selected.originalPrice,
  443. salePrice: selected.salePrice,
  444. shopId: selected.shopId,
  445. id: selected.id,
  446. goodsType: 'ACTIVATION_CODE', // INSTRUMENTS
  447. })
  448. }
  449. const selectedInstrument = that.data.selectedInstrument
  450. if (selectedInstrument.id) {
  451. params.push({
  452. pic: selectedInstrument.pic,
  453. name: selectedInstrument.name,
  454. originalPrice: selectedInstrument.originalPrice,
  455. salePrice: selectedInstrument.salePrice,
  456. shopId: selectedInstrument.shopId,
  457. id: selectedInstrument.id,
  458. goodsType: 'INSTRUMENTS', // INSTRUMENTS
  459. })
  460. }
  461. // openId
  462. const openId = wx.getStorageSync("openId")
  463. that.onTrackPoint({
  464. openId,
  465. elementName: "去结算"
  466. })
  467. let info = JSON.stringify({
  468. ...params
  469. });
  470. info = encodeURIComponent(info);
  471. wx.navigateTo({
  472. url: `../orders/order-detail?orderInfo=${info}`,
  473. success: () => {
  474. that.setData({
  475. popupShow: false,
  476. });
  477. },
  478. });
  479. }, 200)();
  480. },
  481. onPreivewBannerImg(e: { currentTarget: { dataset: any } }) {
  482. wx.previewImage({
  483. current: e.currentTarget.dataset.src,
  484. urls: this.data.imgList,
  485. success: () => {
  486. this.setData({
  487. isFromPreviewImage: true,
  488. });
  489. },
  490. });
  491. },
  492. onPreivewDetailImg(e: { currentTarget: { dataset: any } }) {
  493. wx.previewImage({
  494. current: e.currentTarget.dataset.src,
  495. urls: [
  496. "https://oss.dayaedu.com/ktyq/1733403675345.png",
  497. "https://oss.dayaedu.com/ktyq/1733403707851.png",
  498. "https://oss.dayaedu.com/ktyq/1733403725644.png",
  499. ],
  500. success: () => {
  501. this.setData({
  502. isFromPreviewImage: true,
  503. });
  504. },
  505. });
  506. },
  507. onPreivewGoodsImg(e: { currentTarget: { dataset: any } }) {
  508. wx.previewImage({
  509. current: e.currentTarget.dataset.src,
  510. urls: this.data.goodsImgList,
  511. success: () => {
  512. this.setData({
  513. isFromPreviewImage: true,
  514. });
  515. },
  516. });
  517. },
  518. onPreivewGoods(e: { currentTarget: { dataset: any } }) {
  519. wx.previewImage({
  520. current: e.currentTarget.dataset.src,
  521. urls: [e.currentTarget.dataset.src],
  522. success: () => {
  523. this.setData({
  524. isFromPreviewImage: true,
  525. });
  526. },
  527. });
  528. },
  529. /**
  530. * 生命周期函数--监听页面显示
  531. */
  532. onShow() {
  533. if (!this.data.isFromPreviewImage) {
  534. this.onInit();
  535. } else {
  536. this.setData({
  537. isFromPreviewImage: false,
  538. });
  539. }
  540. this.setData({
  541. serviceShow: true,
  542. });
  543. },
  544. onHide() {
  545. this.setData({
  546. serviceShow: false,
  547. });
  548. },
  549. // 页面滚动时颜色变化
  550. onScrollView(e: { detail: any }) {
  551. const top = e.detail.scrollTop || 0;
  552. // const scrollHeight = e.detail.scrollHeight || 0;
  553. // 从100开始显示
  554. this.setData({
  555. // opacity: top < 100 ? 0 : (top - 100) > 150 ? 1 : (top - 100) / 150
  556. opacity: top < 100 ? 0 : top - 100 > 150 ? 1 : 1,
  557. });
  558. // if (top + this.data.initialScrollHeight >= scrollHeight - 80) {
  559. // // console.log('已经滑动到底部了');
  560. // // 相应业务逻辑处理
  561. // this.setData({
  562. // scrolIntoViewStr: "type2",
  563. // });
  564. // } else {
  565. // console.log(this.data.scrollDiscount, top, this.data.headerHeight, "top");
  566. if (this.data.scrollIntoViewType) {
  567. this.setData({
  568. scrollTop: this.data.scrollDiscount
  569. ? top - this.data.headerHeight
  570. : top,
  571. scrollIntoViewType: false,
  572. scrollDiscount: false,
  573. isScrollTT: true,
  574. });
  575. } else {
  576. if (!this.data.isScrollTT) {
  577. this.onChangeScroll();
  578. } else {
  579. this.setData({
  580. isScrollTT: false,
  581. });
  582. }
  583. }
  584. // }
  585. },
  586. onChangeScroll() {
  587. const that = this;
  588. debounce(function () {
  589. wx.createSelectorQuery()
  590. .select("#type3")
  591. .boundingClientRect(function (rect) {
  592. let check = false;
  593. if (rect.top > 0 && rect.top <= that.data.headerHeight) {
  594. that.setData({
  595. scrolIntoViewStr: "type3",
  596. });
  597. check = true;
  598. }
  599. if (rect.top > 0 && rect.top > that.data.headerHeight) {
  600. that.setData({
  601. scrolIntoViewStr: "type1",
  602. });
  603. check = true;
  604. }
  605. // console.log('checked', check)
  606. if (!check) {
  607. wx.createSelectorQuery()
  608. .select("#type2")
  609. .boundingClientRect(function (rect) {
  610. if (rect.top > 0 && rect.top <= that.data.headerHeight) {
  611. that.setData({
  612. scrolIntoViewStr: "type2",
  613. });
  614. }
  615. if (rect.top > 0 && rect.top > that.data.headerHeight) {
  616. that.setData({
  617. scrolIntoViewStr: "type3",
  618. });
  619. }
  620. })
  621. .exec();
  622. }
  623. })
  624. .exec();
  625. }, 100)();
  626. },
  627. onTapAnchor(e: { currentTarget: { dataset: any } }) {
  628. const type = e.currentTarget.dataset.type;
  629. this.setData({
  630. scrolIntoView: type,
  631. scrolIntoViewStr: type,
  632. scrollDiscount: true, // type !== 'type2' ? true : false,
  633. scrollIntoViewType: true,
  634. });
  635. },
  636. onShareAppMessage() {
  637. return {
  638. title: "音乐数字AI",
  639. path: "/pages/index/index",
  640. imageUrl: "https://oss.dayaedu.com/ktyq/1739870592907.png",
  641. };
  642. },
  643. onShareTimeline() {
  644. return {
  645. title: "音乐数字AI",
  646. path: "/pages/index/index",
  647. imageUrl: "https://oss.dayaedu.com/ktyq/1739870592907.png",
  648. };
  649. },
  650. });