index.ts 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. // index.ts
  2. import { api_queryByParamNameList, 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. const PURCHASE_TYPE = {
  8. STUDENT: "WECHAT_MINI",
  9. TEACHER: "TEACHER_VIP",
  10. };
  11. const TEACHER_VIP_PARAM_NAME = "teacher_vip_purchase_list";
  12. const purchaseDataCache: any = {};
  13. let purchaseDataRequestId = 0;
  14. function getProductImage(item: any, userType: string) {
  15. if (!item) {
  16. return "";
  17. }
  18. if (userType === PURCHASE_TYPE.TEACHER) {
  19. return item.coverImg || item.pic || "";
  20. }
  21. return item.pic || item.coverImg || "";
  22. }
  23. function parseTeacherVipList(paramValue: any) {
  24. if (!paramValue) {
  25. return [];
  26. }
  27. const value = typeof paramValue === "string" ? JSON.parse(paramValue) : paramValue;
  28. if (Array.isArray(value)) {
  29. return value;
  30. }
  31. return value.list || value.goodsList || value.packages || [];
  32. }
  33. function formatPeriodText(num: any, type: string) {
  34. const unitText: any = {
  35. DAY: "天",
  36. MONTH: "个月",
  37. YEAR: "年",
  38. };
  39. if (!num || !type) {
  40. return "";
  41. }
  42. return `${num}${unitText[type] || ""}`;
  43. }
  44. function formatGiftText(item: any) {
  45. if (!item) {
  46. return "";
  47. }
  48. if (item.free?.number && item.free?.unit) {
  49. return formatPeriodText(item.free.number, item.free.unit);
  50. }
  51. if (item.giftFlag && item.giftVipDay && item.giftPeriod) {
  52. return formatPeriodText(item.giftVipDay, item.giftPeriod);
  53. }
  54. return "";
  55. }
  56. function buildPeriodList(list: any[]) {
  57. return list.map((item: any, index: number) => ({
  58. label: item.typeName || item.title || item.name || formatPeriodText(item.num, item.period),
  59. value: String(item.id),
  60. disabled: Number(item.stockNum ?? 1) <= 0,
  61. viewId: `period-${index}`,
  62. }));
  63. }
  64. function getPeriodScrollIntoView(periodList: any[], selectedPeriod: string) {
  65. return periodList.find((item: any) => String(item.value) === String(selectedPeriod))?.viewId || "";
  66. }
  67. function markPeriodListActive(periodList: any[], selectedPeriod: string) {
  68. return periodList.map((item: any) => ({
  69. ...item,
  70. active: String(item.value) === String(selectedPeriod),
  71. }));
  72. }
  73. function syncPurchaseDataCache(userType: string, patch: any) {
  74. if (!purchaseDataCache[userType]) {
  75. return;
  76. }
  77. purchaseDataCache[userType] = {
  78. ...purchaseDataCache[userType],
  79. ...patch,
  80. };
  81. }
  82. function selectDefaultTeacherVip(list: any[]) {
  83. const saleableList = list.filter((item: any) => Number(item.stockNum ?? 1) > 0);
  84. const candidates = saleableList.length ? saleableList : list;
  85. const getSearchText = (item: any) => [
  86. item.name,
  87. item.title,
  88. item.label,
  89. item.typeName,
  90. ].filter(Boolean).join("");
  91. const isOneYear = (item: any) => {
  92. const text = getSearchText(item);
  93. return (Number(item.num) === 1 && item.period === "YEAR") || /(?:1|一)年/.test(text);
  94. };
  95. const isTrial = (item: any) => /体验卡/.test(getSearchText(item));
  96. return candidates.find((item: any) => isOneYear(item) && isTrial(item))
  97. || candidates.find(isOneYear)
  98. || candidates.find((item: any) => item.isHot)
  99. || candidates[0]
  100. || {};
  101. }
  102. // pages/orders/orders.ts
  103. Page({
  104. /**
  105. * 页面的初始数据
  106. */
  107. data: {
  108. imgList: [
  109. // 'https://oss.dayaedu.com/ktyq/1732585725698.png',
  110. // 'https://oss.dayaedu.com/ktyq/1732519468124.png',
  111. // 'https://oss.dayaedu.com/ktyq/1732519479416.png',
  112. // 'https://oss.dayaedu.com/ktyq/1733110029242.png',
  113. // 'https://oss.dayaedu.com/ktyq/1732519500580.png'
  114. "https://oss.dayaedu.com/ktyq/1733449062928.png",
  115. "https://oss.dayaedu.com/ktyq/1733449075055.png",
  116. "https://oss.dayaedu.com/ktyq/1733449085983.png",
  117. "https://oss.dayaedu.com/ktyq/1733449097054.png",
  118. ],
  119. goodsImgList: [
  120. "https://oss.dayaedu.com/ktyq/1739353790443.png",
  121. "https://oss.dayaedu.com/ktyq/1739353815962.png",
  122. "https://oss.dayaedu.com/ktyq/1739353843494.png",
  123. "https://oss.dayaedu.com/ktyq/03/1772550951364.png",
  124. ],
  125. detailImgList: [
  126. {
  127. url: "https://oss.dayaedu.com/ktyq/1733403675345.png",
  128. text: "合作学校音乐数字课堂公开课",
  129. },
  130. {
  131. url: "https://oss.dayaedu.com/ktyq/1733403707851.png",
  132. text: "音乐课课堂器乐教学",
  133. },
  134. {
  135. url: "https://oss.dayaedu.com/ktyq/1733403725644.png",
  136. text: "学期末汇报演出",
  137. },
  138. ],
  139. serviceShow: true,
  140. scrollTop: 0,
  141. current: 0,
  142. detailCurrent: 0,
  143. autoplay: false,
  144. interval: 5000,
  145. duration: 500,
  146. popupShow: false,
  147. videoHeight: "255px",
  148. list: [] as any,
  149. instrumentList: [] as any,
  150. isOverSaled: false, // 是否所有商品都没有库存
  151. selected: {} as any,
  152. selectInstrumentId: '', // 选中的乐器
  153. selectedInstrument: {} as any,
  154. formatSelectGood: {
  155. typeName: '',
  156. name: '',
  157. productImage: '',
  158. giftText: '',
  159. showSalePrice: '', // 显示的现价
  160. originalPrice: 0, // 原价
  161. salePrice: 0, // 现价
  162. discountPrice: '' // 已省
  163. } as any, // 格式化所有选中的数据
  164. opacity: 0,
  165. // showSelectedProduct: false, // 是否显示选中商品值
  166. scrolIntoViewStr: "",
  167. scrolIntoView: "",
  168. scrollDiscount: false, // 是否扣减启
  169. isScrollTT: false,
  170. scrollIntoViewType: false,
  171. headerHeight: 0, // 头部的高度
  172. initialScrollHeight: 0, // 滚动高度
  173. isFromPreviewImage: false,
  174. bannerPlay: false, // 视频是否播放
  175. titleControls: false, // 详情是否显示控制条
  176. liuControls: false, // 详情是否显示控制条
  177. bannerImageloaded: false, // Banner 图片是否加载完成
  178. userTypes: PURCHASE_TYPE.STUDENT, // 用户类型:WECHAT_MINI | TEACHER_VIP
  179. periodList: [] as any,
  180. selectedPeriod: '', // 选中的期限
  181. periodScrollIntoView: '',
  182. showBonusGift: false, // 是否显示额外赠送
  183. },
  184. /**
  185. * 生命周期函数--监听页面加载
  186. */
  187. onLoad() {
  188. // this.onInit()
  189. const wxWindowInfo = wx.getWindowInfo();
  190. this.setData({
  191. videoHeight: (wxWindowInfo.windowWidth / 16) * 9 + "px",
  192. });
  193. // 首页进入页面埋点
  194. this.onHomePageTrackPoint()
  195. },
  196. onHomePageTrackPoint() {
  197. // openId
  198. const openId = wx.getStorageSync("openId")
  199. if(openId) {
  200. this.onTrackPoint({
  201. openId,
  202. elementName: '首页'
  203. })
  204. } else {
  205. wx.login({
  206. success: async (res) => {
  207. await api_getOpenId({
  208. code: res.code,
  209. appId: app.globalData.appId
  210. }).then((res: any) => {
  211. // 存储 openId
  212. const openId = res.data.data
  213. wx.setStorageSync("openId", openId);
  214. this.onTrackPoint({
  215. openId,
  216. elementName: '首页'
  217. })
  218. })
  219. }
  220. })
  221. }
  222. },
  223. onReady() {
  224. const that = this;
  225. wx.createSelectorQuery()
  226. .select("#scroll-header")
  227. .boundingClientRect(function (rect) {
  228. that.setData({
  229. headerHeight: rect.height,
  230. });
  231. })
  232. .exec();
  233. wx.createSelectorQuery()
  234. .select("#scroll-view")
  235. .boundingClientRect(function (rect) {
  236. // console.log(rect, 'rect')
  237. that.setData({
  238. initialScrollHeight: rect.height,
  239. });
  240. })
  241. .exec();
  242. },
  243. onBannerVideoLoad() {
  244. this.setData({
  245. bannerImageloaded: true,
  246. });
  247. },
  248. onBannerPlay() {
  249. const bannerVideo = wx.createVideoContext("bannerVideo");
  250. const titleVideo = wx.createVideoContext("titleVideo");
  251. //
  252. this.setData(
  253. {
  254. bannerPlay: true,
  255. },
  256. () => {
  257. bannerVideo.play();
  258. titleVideo.pause();
  259. // liuVideo.stop()
  260. }
  261. );
  262. },
  263. onBannerVideoPlay() {
  264. const titleVideo = wx.createVideoContext("titleVideo");
  265. titleVideo.pause();
  266. // const liuVideo = wx.createVideoContext('liuVideo')
  267. // liuVideo.stop()
  268. },
  269. onTitlePlay() {
  270. const bannerVideo = wx.createVideoContext("bannerVideo");
  271. bannerVideo.pause();
  272. // const liuVideo = wx.createVideoContext('liuVideo')
  273. // liuVideo.stop()
  274. },
  275. onTItleVideoPlay() {
  276. const bannerVideo = wx.createVideoContext("bannerVideo");
  277. const titleVideo = wx.createVideoContext("titleVideo");
  278. // const liuVideo = wx.createVideoContext('liuVideo')
  279. this.setData(
  280. {
  281. titleControls: true,
  282. },
  283. () => {
  284. titleVideo.play();
  285. bannerVideo.pause();
  286. // liuVideo.stop()
  287. }
  288. );
  289. },
  290. onLiuPlay() {
  291. const bannerVideo = wx.createVideoContext("bannerVideo");
  292. bannerVideo.pause();
  293. const titleVideo = wx.createVideoContext("titleVideo");
  294. titleVideo.pause();
  295. },
  296. onLiuVideoPlay() {
  297. const bannerVideo = wx.createVideoContext("bannerVideo");
  298. const titleVideo = wx.createVideoContext("titleVideo");
  299. // const liuVideo = wx.createVideoContext('liuVideo')
  300. bannerVideo.pause();
  301. titleVideo.pause();
  302. this.setData(
  303. {
  304. liuControls: true,
  305. },
  306. () => {
  307. // liuVideo.play()
  308. }
  309. );
  310. },
  311. /**
  312. * 获取基础信息
  313. */
  314. async onInit() {
  315. const userType = this.data.userTypes;
  316. const requestId = ++purchaseDataRequestId;
  317. if (purchaseDataCache[userType]) {
  318. this.applyPurchaseData(purchaseDataCache[userType]);
  319. return
  320. }
  321. if (userType === PURCHASE_TYPE.TEACHER) {
  322. await this.onInitTeacherVip(requestId)
  323. return
  324. }
  325. try {
  326. const result = await api_shopInstruments({ appId: app.globalData.appId })
  327. const instrumentList = result.data.data || []
  328. instrumentList.forEach((item: any) => {
  329. item.showSalePrice = formatPrice(item.salePrice || 0, 'ALL')
  330. item.showOriginalPrice = formatPrice(item.originalPrice || 0, 'ALL')
  331. })
  332. const { data } = await api_shopProduct({ appId: app.globalData.appId });
  333. const list = data.data || [];
  334. let selected: any = {};
  335. let isOverSaled = true; // 是否销售完
  336. list.forEach((item: any) => {
  337. const salePrice = Number(item.salePrice || 0);
  338. const originalPrice = Number(item.originalPrice || salePrice);
  339. item.originalPrice = originalPrice;
  340. item.salePrice = salePrice;
  341. item.showSalePrice = formatPrice(salePrice, "ALL");
  342. item.showOriginalPrice = formatPrice(originalPrice, "ALL");
  343. item.typeName = this.formatPeriod(Number(item.num), item.period);
  344. item.discountPrice = formatPrice(
  345. originalPrice - salePrice,
  346. "ALL"
  347. );
  348. const prices: any = formatPrice(salePrice);
  349. item.integerPart = prices.integerPart;
  350. item.decimalPart = prices.decimalPart;
  351. // 格式化赠送内容
  352. item.giftLongTime = item.giftFlag
  353. ? this.formatGiftPeriod(item.giftVipDay, item.giftPeriod)
  354. : "";
  355. if (item.stockNum > 0) {
  356. isOverSaled = false;
  357. if (!selected.id) {
  358. selected = item;
  359. }
  360. }
  361. });
  362. if (isOverSaled) {
  363. // 没有可销售商品则默认选中第一个商品
  364. selected = list[0];
  365. }
  366. const purchaseData = {
  367. list,
  368. periodList: buildPeriodList(list),
  369. selectedPeriod: selected?.id ? String(selected.id) : '',
  370. instrumentList, // 乐器列表
  371. isOverSaled,
  372. selected,
  373. selectInstrumentId: '',
  374. selectedInstrument: {},
  375. showBonusGift: Boolean(formatGiftText(selected))
  376. };
  377. purchaseDataCache[userType] = purchaseData;
  378. if (requestId !== purchaseDataRequestId || this.data.userTypes !== userType) {
  379. return;
  380. }
  381. this.applyPurchaseData(purchaseData);
  382. } catch (e) {
  383. console.log(e, "e");
  384. }
  385. },
  386. // 格式化类型
  387. applyPurchaseData(purchaseData: any) {
  388. const periodList = markPeriodListActive(
  389. purchaseData.periodList,
  390. purchaseData.selectedPeriod
  391. );
  392. const periodScrollIntoView = getPeriodScrollIntoView(
  393. periodList,
  394. purchaseData.selectedPeriod
  395. );
  396. this.setData({
  397. list: purchaseData.list,
  398. periodList,
  399. selectedPeriod: purchaseData.selectedPeriod,
  400. periodScrollIntoView,
  401. instrumentList: purchaseData.instrumentList,
  402. isOverSaled: purchaseData.isOverSaled,
  403. selected: purchaseData.selected,
  404. selectInstrumentId: purchaseData.selectInstrumentId,
  405. selectedInstrument: purchaseData.selectedInstrument,
  406. showBonusGift: purchaseData.showBonusGift
  407. }, () => {
  408. this.onFormatGoods()
  409. });
  410. },
  411. async onInitTeacherVip(requestId: number) {
  412. const userType = PURCHASE_TYPE.TEACHER;
  413. try {
  414. const { data } = await api_queryByParamNameList({
  415. paramNames: TEACHER_VIP_PARAM_NAME
  416. });
  417. const configList = data.data || [];
  418. const config = Array.isArray(configList)
  419. ? configList.find((item: any) => item.paramName === TEACHER_VIP_PARAM_NAME) || configList[0]
  420. : configList;
  421. const list = parseTeacherVipList(config?.paramValue).map((item: any, index: number) => {
  422. const salePrice = Number(item.salePrice ?? item.currentPrice ?? item.price ?? item.paymentCashAmount ?? 0);
  423. const originalPrice = Number(item.originalPrice ?? item.marketPrice ?? item.originalAmount ?? salePrice);
  424. const period = item.period || item.unit;
  425. const num = item.num ?? item.number;
  426. const typeName = item.typeName || item.label || item.title || item.name || formatPeriodText(num, period);
  427. const prices: any = formatPrice(salePrice);
  428. return {
  429. ...item,
  430. id: item.id || item.goodsId || item.value || `${TEACHER_VIP_PARAM_NAME}_${index}`,
  431. name: item.name || item.title || typeName,
  432. pic: item.pic || item.coverImg || "",
  433. coverImg: item.coverImg || item.pic || "",
  434. shopId: item.shopId || "",
  435. stockNum: item.stockNum ?? 999999,
  436. originalPrice,
  437. salePrice,
  438. num,
  439. period,
  440. showSalePrice: formatPrice(salePrice, "ALL"),
  441. showOriginalPrice: formatPrice(originalPrice, "ALL"),
  442. discountPrice: formatPrice(originalPrice - salePrice, "ALL"),
  443. typeName,
  444. giftFlag: Boolean(item.free || item.giftFlag),
  445. giftVipDay: item.free?.number ?? item.giftVipDay,
  446. giftPeriod: item.free?.unit ?? item.giftPeriod,
  447. integerPart: prices.integerPart,
  448. decimalPart: prices.decimalPart,
  449. goodsType: item.goodsType || PURCHASE_TYPE.TEACHER,
  450. };
  451. });
  452. const selected = selectDefaultTeacherVip(list);
  453. const periodList = buildPeriodList(list);
  454. const purchaseData = {
  455. list,
  456. periodList,
  457. selectedPeriod: selected?.id ? String(selected.id) : '',
  458. instrumentList: [],
  459. isOverSaled: !list.some((item: any) => item.stockNum > 0),
  460. selected,
  461. selectInstrumentId: '',
  462. selectedInstrument: {},
  463. showBonusGift: Boolean(formatGiftText(selected))
  464. };
  465. purchaseDataCache[userType] = purchaseData;
  466. if (requestId !== purchaseDataRequestId || this.data.userTypes !== userType) {
  467. return;
  468. }
  469. this.applyPurchaseData(purchaseData);
  470. } catch (e) {
  471. console.log(e, "e");
  472. if (requestId !== purchaseDataRequestId || this.data.userTypes !== userType) {
  473. return;
  474. }
  475. this.setData({
  476. list: [],
  477. instrumentList: [],
  478. isOverSaled: true,
  479. selected: {},
  480. selectInstrumentId: '',
  481. selectedInstrument: {},
  482. showBonusGift: false
  483. }, () => {
  484. this.onFormatGoods()
  485. });
  486. }
  487. },
  488. formatPeriod(num: number, type: string) {
  489. const template: any = {
  490. DAY: "天卡",
  491. MONTH: "月卡",
  492. YEAR: "年卡",
  493. };
  494. if (type === "YEAR" && num >= 99) {
  495. return "永久卡";
  496. }
  497. return num + template[type];
  498. },
  499. formatGiftPeriod(num: number, type: string) {
  500. if (!num || !type) {
  501. return "";
  502. }
  503. const template: any = {
  504. DAY: "天",
  505. MONTH: "个月",
  506. YEAR: "年",
  507. };
  508. return num + template[type];
  509. },
  510. // 选择
  511. onSelectGoods(e: any) {
  512. const { dataset } = e.currentTarget;
  513. const item = this.data.list.find((item: any) => item.id === dataset.id);
  514. // 判断是否有库存
  515. if (item.stockNum <= 0) {
  516. return;
  517. }
  518. this.setData({
  519. selected: item || {}
  520. }, () => {
  521. this.onFormatGoods()
  522. });
  523. },
  524. /** 选中乐器 */
  525. onSelectInstrument(e: any) {
  526. if (this.data.userTypes === PURCHASE_TYPE.TEACHER) {
  527. return
  528. }
  529. const { dataset } = e.currentTarget;
  530. if (dataset.id === this.data.selectInstrumentId) {
  531. this.setData({
  532. selectInstrumentId: '',
  533. selectedInstrument: {}
  534. }, () => {
  535. this.onFormatGoods()
  536. })
  537. } else {
  538. const item = this.data.instrumentList.find((item: any) => item.id === dataset.id);
  539. this.setData({
  540. selectInstrumentId: dataset.id,
  541. selectedInstrument: item || {}
  542. }, () => {
  543. this.onFormatGoods()
  544. })
  545. }
  546. },
  547. /** 格式化选中的商品 */
  548. onFormatGoods() {
  549. const selected = this.data.selected;
  550. const selectedInstrument = this.data.selectedInstrument
  551. const params: any = {
  552. typeName: '',
  553. name: '',
  554. productImage: '',
  555. giftText: '',
  556. showSalePrice: '' as any, // 显示的现价
  557. originalPrice: 0, // 原价
  558. salePrice: 0, // 现价
  559. discountPrice: '' as any, // 已省
  560. integerPart: '',
  561. decimalPart: '',
  562. }
  563. // 选中期限
  564. if (selected.id) {
  565. params.typeName = selected.typeName
  566. params.name = selected.name
  567. params.productImage = getProductImage(selected, this.data.userTypes)
  568. params.giftText = formatGiftText(selected)
  569. params.showSalePrice = selected.showSalePrice
  570. params.originalPrice = selected.originalPrice
  571. params.salePrice = selected.salePrice
  572. params.discountPrice = selected.discountPrice
  573. const prices: any = formatPrice(params.salePrice);
  574. params.integerPart = prices.integerPart
  575. params.decimalPart = prices.decimalPart
  576. }
  577. // 选中乐器
  578. if (selectedInstrument.id) {
  579. params.typeName = selected.typeName ? selected.typeName + '+' + selectedInstrument.name : selectedInstrument.name
  580. params.name = selected.name ? selected.name + '+' + selectedInstrument.name : selectedInstrument.name
  581. params.originalPrice = Number(selected.originalPrice) + Number(selectedInstrument.originalPrice)
  582. params.salePrice = Number(selected.salePrice) + Number(selectedInstrument.salePrice)
  583. params.showSalePrice = formatPrice(params.salePrice, "ALL");
  584. params.discountPrice = formatPrice(
  585. params.originalPrice - params.salePrice,
  586. "ALL"
  587. );
  588. const prices: any = formatPrice(params.salePrice);
  589. params.integerPart = prices.integerPart
  590. params.decimalPart = prices.decimalPart
  591. }
  592. this.setData({
  593. formatSelectGood: params
  594. })
  595. },
  596. // 事件处理函数
  597. changeSwiper(e: any) {
  598. const detail = e.detail;
  599. if (detail.source === "touch" || detail.source == "autoplay") {
  600. this.setData({
  601. current: detail.current,
  602. });
  603. this.onTitlePlay();
  604. }
  605. },
  606. changeSwiperDetail(e: any) {
  607. const detail = e.detail;
  608. if (detail.source === "touch" || detail.source == "autoplay") {
  609. this.setData({
  610. detailCurrent: detail.current,
  611. });
  612. }
  613. },
  614. isLogin() {
  615. // 判断是否登录
  616. if (!app.globalData.isLogin) {
  617. wx.navigateTo({
  618. url: "../login/login",
  619. });
  620. return false;
  621. }
  622. return true;
  623. },
  624. /** 我的订单 */
  625. onOrder() {
  626. wx.navigateTo({
  627. url: "../orders/orders",
  628. });
  629. },
  630. onBuyShop() {
  631. this.setData({
  632. popupShow: true,
  633. // showSelectedProduct: true,
  634. });
  635. },
  636. /** 切换学生端/老师端 */
  637. onSwitchUserType(e: any) {
  638. const { dataset } = e.currentTarget;
  639. if (dataset.type === this.data.userTypes) {
  640. return
  641. }
  642. this.setData({
  643. userTypes: dataset.type,
  644. list: [],
  645. periodList: [],
  646. selectedPeriod: '',
  647. periodScrollIntoView: '',
  648. instrumentList: [],
  649. selected: {},
  650. selectInstrumentId: '',
  651. selectedInstrument: {},
  652. showBonusGift: false,
  653. formatSelectGood: {
  654. typeName: '',
  655. name: '',
  656. productImage: '',
  657. giftText: '',
  658. showSalePrice: '',
  659. originalPrice: 0,
  660. salePrice: 0,
  661. discountPrice: '',
  662. integerPart: '',
  663. decimalPart: '',
  664. }
  665. }, () => {
  666. // 这里可以根据用户类型重新加载商品数据
  667. // 目前先保持逻辑不变,后续可根据后端 API 扩展
  668. this.onInit()
  669. })
  670. },
  671. /** 选择期限 */
  672. onSelectPeriod(e: any) {
  673. const { value } = e.currentTarget.dataset
  674. const periodItem = this.data.periodList.find((item: any) => String(item.value) === String(value))
  675. if (periodItem?.disabled) {
  676. wx.showToast({
  677. title: '暂无库存',
  678. icon: 'none',
  679. });
  680. return
  681. }
  682. const selectedItem = this.data.list.find((item: any) => String(item.id) === String(value))
  683. if (!selectedItem) {
  684. return
  685. }
  686. const selectedPeriod = String(value);
  687. const periodList = markPeriodListActive(this.data.periodList, selectedPeriod);
  688. this.setData({
  689. periodList,
  690. selectedPeriod,
  691. selected: selectedItem,
  692. periodScrollIntoView: getPeriodScrollIntoView(periodList, selectedPeriod),
  693. showBonusGift: Boolean(formatGiftText(selectedItem))
  694. }, () => {
  695. // 根据选中的期限更新商品
  696. this.onFormatGoods()
  697. })
  698. syncPurchaseDataCache(this.data.userTypes, {
  699. periodList,
  700. selectedPeriod,
  701. selected: selectedItem,
  702. selectInstrumentId: this.data.selectInstrumentId,
  703. selectedInstrument: this.data.selectedInstrument,
  704. showBonusGift: Boolean(formatGiftText(selectedItem))
  705. });
  706. },
  707. /** 根据期限更新商品列表 */
  708. onUpdatePeriodList() {
  709. if (this.data.userTypes === PURCHASE_TYPE.TEACHER) {
  710. return
  711. }
  712. const { selectedPeriod, list } = this.data
  713. const selectedItem = list.find((item: any) => String(item.id) === String(selectedPeriod))
  714. if (!selectedItem || Number(selectedItem.stockNum ?? 1) <= 0) {
  715. return
  716. }
  717. this.setData({
  718. selected: selectedItem,
  719. showBonusGift: Boolean(formatGiftText(selectedItem))
  720. }, () => {
  721. this.onFormatGoods()
  722. })
  723. },
  724. // 进行埋点
  725. onTrackPoint(options: { openId: string, elementName: string }) {
  726. const traceId = wx.getStorageSync("traceId");
  727. const deviceInfo = wx.getDeviceInfo();
  728. api_trackPointLog({
  729. traceId,
  730. openId: options.openId,
  731. elementName: options.elementName,
  732. deviceInfo: deviceInfo.brand + '_' + deviceInfo.model + '_' + deviceInfo.system + '_' + deviceInfo.platform,
  733. appName: "音乐数字 AI",
  734. // extParams: '',
  735. clickTime: formatTime(new Date(), '-') // 点击时间
  736. })
  737. },
  738. onClose() {
  739. this.setData({
  740. popupShow: false,
  741. });
  742. },
  743. onSubmit() {
  744. // 判断是否登录
  745. const that = this;
  746. debounce(function () {
  747. // if (!that.isLogin()) {
  748. // return;
  749. // }
  750. const params = [] as any
  751. const selected = that.data.selected
  752. if (selected.id) {
  753. params.push({
  754. pic: selected.pic,
  755. name: selected.name,
  756. originalPrice: selected.originalPrice,
  757. salePrice: selected.salePrice,
  758. shopId: selected.shopId,
  759. id: selected.id,
  760. goodsType: selected.goodsType || 'ACTIVATION_CODE', // INSTRUMENTS
  761. })
  762. }
  763. const selectedInstrument = that.data.selectedInstrument
  764. if (selectedInstrument.id) {
  765. params.push({
  766. pic: selectedInstrument.pic,
  767. name: selectedInstrument.name,
  768. originalPrice: selectedInstrument.originalPrice,
  769. salePrice: selectedInstrument.salePrice,
  770. shopId: selectedInstrument.shopId,
  771. id: selectedInstrument.id,
  772. goodsType: 'INSTRUMENTS', // INSTRUMENTS
  773. })
  774. }
  775. // openId
  776. const openId = wx.getStorageSync("openId")
  777. that.onTrackPoint({
  778. openId,
  779. elementName: "立即购买"
  780. })
  781. let info = JSON.stringify({
  782. ...params
  783. });
  784. info = encodeURIComponent(info);
  785. wx.navigateTo({
  786. url: `../orders/order-detail?orderInfo=${info}&orderType=${that.data.userTypes}`,
  787. success: () => {
  788. that.setData({
  789. popupShow: false,
  790. });
  791. },
  792. });
  793. }, 200)();
  794. },
  795. onPreivewBannerImg(e: { currentTarget: { dataset: any } }) {
  796. wx.previewImage({
  797. current: e.currentTarget.dataset.src,
  798. urls: this.data.imgList,
  799. success: () => {
  800. this.setData({
  801. isFromPreviewImage: true,
  802. });
  803. },
  804. });
  805. },
  806. onPreivewDetailImg(e: { currentTarget: { dataset: any } }) {
  807. wx.previewImage({
  808. current: e.currentTarget.dataset.src,
  809. urls: [
  810. "https://oss.dayaedu.com/ktyq/1733403675345.png",
  811. "https://oss.dayaedu.com/ktyq/1733403707851.png",
  812. "https://oss.dayaedu.com/ktyq/1733403725644.png",
  813. ],
  814. success: () => {
  815. this.setData({
  816. isFromPreviewImage: true,
  817. });
  818. },
  819. });
  820. },
  821. onPreivewDetailImg2(e: { currentTarget: { dataset: any } }) {
  822. wx.previewImage({
  823. current: e.currentTarget.dataset.src,
  824. urls: [
  825. "https://oss.dayaedu.com/ktyq/03/1772461866051.png",
  826. ],
  827. success: () => {
  828. this.setData({
  829. isFromPreviewImage: true,
  830. });
  831. },
  832. });
  833. },
  834. onPreivewGoodsImg(e: { currentTarget: { dataset: any } }) {
  835. wx.previewImage({
  836. current: e.currentTarget.dataset.src,
  837. urls: this.data.goodsImgList,
  838. success: () => {
  839. this.setData({
  840. isFromPreviewImage: true,
  841. });
  842. },
  843. });
  844. },
  845. onPreivewGoods(e: { currentTarget: { dataset: any } }) {
  846. wx.previewImage({
  847. current: e.currentTarget.dataset.src,
  848. urls: [e.currentTarget.dataset.src],
  849. success: () => {
  850. this.setData({
  851. isFromPreviewImage: true,
  852. });
  853. },
  854. });
  855. },
  856. /**
  857. * 生命周期函数--监听页面显示
  858. */
  859. onShow() {
  860. if (!this.data.isFromPreviewImage) {
  861. this.onInit();
  862. } else {
  863. this.setData({
  864. isFromPreviewImage: false,
  865. });
  866. }
  867. this.setData({
  868. serviceShow: true,
  869. });
  870. },
  871. onHide() {
  872. this.setData({
  873. serviceShow: false,
  874. });
  875. },
  876. // 页面滚动时颜色变化
  877. onScrollView(e: { detail: any }) {
  878. const top = e.detail.scrollTop || 0;
  879. // const scrollHeight = e.detail.scrollHeight || 0;
  880. // 从 100 开始显示
  881. this.setData({
  882. // opacity: top < 100 ? 0 : (top - 100) > 150 ? 1 : (top - 100) / 150
  883. opacity: top < 100 ? 0 : top - 100 > 150 ? 1 : 1,
  884. });
  885. // if (top + this.data.initialScrollHeight >= scrollHeight - 80) {
  886. // // console.log('已经滑动到底部了');
  887. // // 相应业务逻辑处理
  888. // this.setData({
  889. // scrolIntoViewStr: "type2",
  890. // });
  891. // } else {
  892. // console.log(this.data.scrollDiscount, top, this.data.headerHeight, "top");
  893. if (this.data.scrollIntoViewType) {
  894. this.setData({
  895. scrollTop: this.data.scrollDiscount
  896. ? top - this.data.headerHeight
  897. : top,
  898. scrollIntoViewType: false,
  899. scrollDiscount: false,
  900. isScrollTT: true,
  901. });
  902. } else {
  903. if (!this.data.isScrollTT) {
  904. this.onChangeScroll();
  905. } else {
  906. this.setData({
  907. isScrollTT: false,
  908. });
  909. }
  910. }
  911. // }
  912. },
  913. onChangeScroll() {
  914. const that = this;
  915. debounce(function () {
  916. wx.createSelectorQuery()
  917. .select("#type3")
  918. .boundingClientRect(function (rect) {
  919. let check = false;
  920. if (rect.top > 0 && rect.top <= that.data.headerHeight) {
  921. that.setData({
  922. scrolIntoViewStr: "type3",
  923. });
  924. check = true;
  925. }
  926. if (rect.top > 0 && rect.top > that.data.headerHeight) {
  927. that.setData({
  928. scrolIntoViewStr: "type1",
  929. });
  930. check = true;
  931. }
  932. // console.log('checked', check)
  933. if (!check) {
  934. wx.createSelectorQuery()
  935. .select("#type2")
  936. .boundingClientRect(function (rect) {
  937. if (rect.top > 0 && rect.top <= that.data.headerHeight) {
  938. that.setData({
  939. scrolIntoViewStr: "type2",
  940. });
  941. }
  942. if (rect.top > 0 && rect.top > that.data.headerHeight) {
  943. that.setData({
  944. scrolIntoViewStr: "type3",
  945. });
  946. }
  947. })
  948. .exec();
  949. }
  950. })
  951. .exec();
  952. }, 100)();
  953. },
  954. onTapAnchor(e: { currentTarget: { dataset: any } }) {
  955. const type = e.currentTarget.dataset.type;
  956. this.setData({
  957. scrolIntoView: type,
  958. scrolIntoViewStr: type,
  959. scrollDiscount: true, // type !== 'type2' ? true : false,
  960. scrollIntoViewType: true,
  961. });
  962. },
  963. onShareAppMessage() {
  964. return {
  965. title: "音乐数字 AI",
  966. path: "/pages/index/index",
  967. imageUrl: "https://oss.dayaedu.com/ktyq/1739870592907.png",
  968. };
  969. },
  970. onShareTimeline() {
  971. return {
  972. title: "音乐数字 AI",
  973. path: "/pages/index/index",
  974. imageUrl: "https://oss.dayaedu.com/ktyq/1739870592907.png",
  975. };
  976. },
  977. });