video.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. // pages/video/video.js
  2. import { getVideoList, getTemplateConfig, getUuid } from "../../api/api";
  3. import {
  4. rnd,
  5. deepCopy,
  6. goToBookDetail,
  7. goToVideoDetail,
  8. SendEvent,
  9. rndone,
  10. } from "../../utils/util";
  11. import { apple } from "../../config/config";
  12. const app = getApp();
  13. let interstitialAd = null;
  14. Page({
  15. data: {
  16. videoList: [],
  17. originVideoList: [],
  18. loading: false,
  19. hasMore: true,
  20. page: 1,
  21. size: 10,
  22. // 状态栏高度
  23. statusBarHeight: 20,
  24. navHeight: 64, // 导航栏高度 = 状态栏 + 44
  25. navStyle: "",
  26. listStyle: "",
  27. // 添加防抖时间戳
  28. lastLoadTime: 0,
  29. ads: null,
  30. globalConfig: null,
  31. // 视频分类列表
  32. categoryList: [],
  33. // 当前选中的分类ID
  34. currentCategoryId: null,
  35. share_count: 1,
  36. hasLoadAdConfig: false,
  37. templateAdId: "",
  38. adErrorField: {
  39. videoError: false,
  40. bannerError: false,
  41. templateError: false,
  42. },
  43. },
  44. onLoad(options) {
  45. console.log("打开视频列表页面--------------------------");
  46. wx.setStorageSync("jump", parseInt(options.jump)); // 是否跳转阅读器
  47. this.autoLogin(options.promotionid);
  48. if (!app.globalData.uuid) {
  49. this.getUUID().then((uuid) => {
  50. // getApp().globalData.uuid = uuid
  51. console.log("登录成功");
  52. });
  53. }
  54. this.handleEntrace(options);
  55. this.setData({
  56. templateAdId: apple.ads.templateAdId,
  57. hasLoadAdConfig: true,
  58. });
  59. this.interstitalLoad();
  60. getTemplateConfig({
  61. box_type: 67,
  62. uuid: app.globalData.uuid,
  63. }).then((res) => {
  64. this.setData({
  65. globalConfig: res.globalConfig,
  66. });
  67. app.globalData.ads_config = res.globalConfig;
  68. // 获取视频分类
  69. this.getVideoCategories();
  70. });
  71. // 获取状态栏高度
  72. this.getSystemInfo();
  73. // this.handleEntrace(options);
  74. },
  75. // 自动登录
  76. async autoLogin(promotionid) {
  77. try {
  78. await getApp().login(promotionid);
  79. } catch (error) {
  80. console.error("登录失败:", error);
  81. }
  82. },
  83. onShow() {
  84. console.log("页面显示--------------------------");
  85. this.rewardVideoLoad();
  86. // 每次显示页面时刷新列表
  87. if (this.data.videoList.length === 0) {
  88. this.setData({
  89. page: 1,
  90. });
  91. }
  92. },
  93. handleEntrace(options) {
  94. console.log("点击入口按钮");
  95. if (!options || Object.keys(options).length === 0) {
  96. return;
  97. }
  98. console.log("入口:", options);
  99. try {
  100. let { type, jump, shared_video_id, tag_id, collectId, tid } = options;
  101. const scene = wx.getStorageSync("scene");
  102. console.log("入口:", type, jump, scene, shared_video_id);
  103. if ((type === "share" || type === "tuiguang") && shared_video_id) {
  104. SendEvent("enter_wxwork_material", {
  105. materialId: shared_video_id,
  106. type: "video",
  107. tag_id: tag_id,
  108. task_id: tid,
  109. });
  110. if (jump === "1") {
  111. console.log("jump为1直接跳转到视频详情页");
  112. // 延迟跳转,确保列表页已经加载完成
  113. setTimeout(() => {
  114. this.goToVideoDetail(shared_video_id, tag_id);
  115. }, 500);
  116. } else {
  117. if (scene === 1007 || scene === 1008) {
  118. console.log("scene为1007或1008且jump不为1,跳转到书详情页");
  119. // 延迟跳转,确保列表页已经加载完成
  120. setTimeout(() => {
  121. this.goToBookDetail(
  122. `&shared_video_id=${shared_video_id}&tag_id=${tag_id}`,
  123. );
  124. }, 500);
  125. } else {
  126. console.log("scene不为1007,1008且jump不为1,跳转到视频详情页");
  127. // 延迟跳转,确保列表页已经加载完成
  128. setTimeout(() => {
  129. this.goToVideoDetail(shared_video_id, tag_id);
  130. }, 500);
  131. }
  132. }
  133. }
  134. if ((type === "share" || type === "tuiguang") && collectId) {
  135. if (scene === 1007 || scene === 1008) {
  136. console.log("scene为1007或1008,跳转到书详情页");
  137. // 延迟跳转,确保列表页已经加载完成
  138. //跳转合集视频
  139. setTimeout(() => {
  140. this.goToBookDetail(`&collectId=${collectId}`);
  141. }, 500);
  142. } else {
  143. wx.navigateTo({
  144. url: "/pages/collect-video/video?collectId=" + collectId,
  145. });
  146. }
  147. }
  148. } catch (e) {
  149. console.log("处理不同场景进入小程序出错", error);
  150. }
  151. },
  152. onTabItemTap(item) {
  153. console.log(item.index);
  154. setTimeout(() => {
  155. this.interstitalPlayFn();
  156. }, 1000);
  157. },
  158. // 插屏广告加载
  159. interstitalLoad() {
  160. let adId = apple.ads.insertAdId;
  161. interstitialAd = wx.createInterstitialAd({
  162. adUnitId: adId,
  163. });
  164. interstitialAd.onLoad(() => {
  165. console.log("视频列表页插屏广告onLoad");
  166. });
  167. interstitialAd.onError((err) => {
  168. console.log("视频列表页插屏广告onError", err);
  169. });
  170. interstitialAd.onClose(() => {
  171. console.log("视频列表页插屏广告onClose");
  172. });
  173. },
  174. // 插屏广告展示
  175. interstitalPlayFn() {
  176. if (interstitialAd) {
  177. interstitialAd.show().catch((err) => {
  178. console.error("视频列表页插屏显示错误", err);
  179. });
  180. }
  181. },
  182. /**
  183. * 获取uuid
  184. */
  185. getUUID() {
  186. return new Promise((resolve, reject) => {
  187. wx.login({
  188. success: (res) => {
  189. console.log("wxlogin:", res);
  190. let body = {
  191. code: res.code,
  192. source_type: 1,
  193. source_id: "",
  194. };
  195. getUuid(body)
  196. .then(async (uuidres) => {
  197. console.log("登录成功:", uuidres);
  198. app.globalData.uuid = uuidres.uuid;
  199. app.globalData.openId = uuidres.open_id;
  200. // 直接从视频链接进入,同时登录IAA小说用户
  201. // userLogin({
  202. // "appid": apple.appid,
  203. // "channel": 1,
  204. // "srcType": "0",
  205. // "srcAppId": "",
  206. // "srcId": "",
  207. // "cusId": "",
  208. // "inviter": "",
  209. // "promotionId": "",
  210. // "inviterPromotionId": "",
  211. // "system": "pc",
  212. // "type": "inner",
  213. // "inner": 1,
  214. // code: res.code,
  215. // }).then(logres => {
  216. // console.log('userLogin', logres);
  217. // wx.setStorageSync('accessToken', logres.accessToken);
  218. // app.globalData.isLogin = true;
  219. // app.globalData.userCode = logres.userCode;
  220. // app.globalData.openId = logres.openId;
  221. // app.globalData.unionId = logres.unionId;
  222. // console.log('登录成功', app.globalData)
  223. // resolve(logres);
  224. // }).catch(err => {
  225. // app.globalData.isLogin = false;
  226. // reject(err);
  227. // })
  228. console.log("登录后的openid:", uuidres.open_id);
  229. console.log("登录成功:", app.globalData);
  230. SendEvent("login_shanhu", { uuid: uuidres.uuid });
  231. resolve(res.uuid);
  232. })
  233. .catch((err) => {
  234. reject(err);
  235. });
  236. },
  237. });
  238. });
  239. },
  240. // 获取系统信息
  241. getSystemInfo() {
  242. const systemInfo = wx.getSystemInfoSync();
  243. const statusBarHeight = systemInfo.statusBarHeight;
  244. const navHeight = statusBarHeight + 44;
  245. this.setData({
  246. statusBarHeight: statusBarHeight,
  247. navHeight: navHeight,
  248. navStyle: `height:${navHeight}px`,
  249. listStyle: `top:${navHeight}px`,
  250. });
  251. },
  252. // 获取视频分类
  253. getVideoCategories() {
  254. console.log("getVideoCategories", this.data.globalConfig);
  255. // 筛选出type=1的视频分类
  256. const videoCategories = this.data.globalConfig.categoryList.filter(
  257. (item) => item.type === 1,
  258. );
  259. console.log("videoCategories", videoCategories);
  260. if (videoCategories.length > 0) {
  261. // 设置分类列表和默认选中的分类
  262. this.setData({
  263. categoryList: videoCategories,
  264. currentCategoryId: videoCategories[0].id,
  265. });
  266. // 加载第一个分类的视频列表
  267. this.loadVideoList();
  268. } else {
  269. console.error("未找到视频分类");
  270. wx.showToast({
  271. title: "未找到视频分类",
  272. icon: "none",
  273. });
  274. }
  275. },
  276. // 切换分类
  277. switchCategory(e) {
  278. const categoryId = e.currentTarget.dataset.id;
  279. if (categoryId === this.data.currentCategoryId) return;
  280. this.setData({
  281. currentCategoryId: categoryId,
  282. page: 1,
  283. videoList: [],
  284. originVideoList: [],
  285. hasMore: true,
  286. });
  287. this.loadVideoList();
  288. },
  289. // 加载视频列表
  290. async loadVideoList() {
  291. if (this.data.loading) return;
  292. this.setData({
  293. loading: true,
  294. });
  295. try {
  296. const params = {
  297. page: this.data.page,
  298. size: this.data.size,
  299. tag_id: this.data.currentCategoryId,
  300. // 如果不是第一页,传递最后一个视频的ID作为next_id
  301. next_id:
  302. this.data.page > 1 && this.data.videoList.length > 0
  303. ? this.data.videoList[this.data.videoList.length - 1].id
  304. : "",
  305. };
  306. let videoList = [];
  307. try {
  308. videoList = await getVideoList(params);
  309. if (!Array.isArray(videoList)) {
  310. throw new Error("返回数据格式错误");
  311. }
  312. videoList = videoList.map((item) => ({
  313. ...item,
  314. views: rnd(1, 10),
  315. favors: rnd(5000, 10000),
  316. adType: "video",
  317. lock: false,
  318. }));
  319. this.data.originVideoList = this.data.originVideoList.concat(videoList);
  320. this.data.videoList = this.formatVideoAdList(
  321. deepCopy(this.data.originVideoList),
  322. );
  323. } catch (apiError) {
  324. console.error("API调用失败:", apiError);
  325. throw apiError;
  326. }
  327. // 如果是第一页,直接替换数据
  328. if (this.data.page === 1) {
  329. this.setData({
  330. videoList: this.data.videoList,
  331. originVideoList: this.data.originVideoList,
  332. loading: false,
  333. hasMore: videoList.length >= this.data.size,
  334. });
  335. } else {
  336. // 否则追加数据
  337. this.setData({
  338. videoList: this.data.videoList,
  339. originVideoList: this.data.originVideoList,
  340. loading: false,
  341. hasMore: videoList.length >= this.data.size,
  342. });
  343. }
  344. } catch (error) {
  345. console.error("加载视频列表失败:", error);
  346. }
  347. },
  348. /* ------------------ 广告相关 ----------------- */
  349. /**
  350. * 标记广告位置
  351. * @param {} arr
  352. * @returns
  353. */
  354. formatVideoAdList(arr) {
  355. // 原生广告间隔,激励广告间隔
  356. let templateGap = 0,
  357. rewardGap = 0;
  358. console.log(this.data.globalConfig);
  359. if (this.data.globalConfig.isHomeTemplateAd === 1) {
  360. templateGap = this.data.globalConfig.homeTemplateAdInterval;
  361. } else {
  362. templateGap = 0;
  363. }
  364. if (this.data.globalConfig.isHomeRewardAd) {
  365. rewardGap = this.data.globalConfig.homeRewardAdInterval;
  366. } else {
  367. rewardGap = 0;
  368. }
  369. console.log(
  370. "原生间隔templateGap",
  371. templateGap,
  372. "激励间隔rewardGap",
  373. rewardGap,
  374. );
  375. // 第二个固定是原生广告
  376. let result = [
  377. arr.shift(),
  378. {
  379. adType: "templateAd",
  380. },
  381. ];
  382. // 辅助计算间隔变量
  383. let markIndex = 0;
  384. let templateAdFlag = true;
  385. let rewardAdFlag = true;
  386. do {
  387. markIndex += 1;
  388. if (templateGap > 0) {
  389. if (templateAdFlag && markIndex - 1 === templateGap) {
  390. markIndex = 0;
  391. result.push({
  392. adType: "templateAd",
  393. });
  394. templateAdFlag = false;
  395. rewardAdFlag = true;
  396. continue;
  397. }
  398. } else {
  399. rewardAdFlag = true;
  400. }
  401. if (rewardGap > 0) {
  402. if (rewardAdFlag && markIndex - 1 === rewardGap) {
  403. markIndex = 0;
  404. templateAdFlag = true;
  405. rewardAdFlag = false;
  406. let rewardItem = arr.shift();
  407. rewardItem.lock = true;
  408. result.push(rewardItem);
  409. console.log("标记激励项:", rewardItem);
  410. continue;
  411. }
  412. } else {
  413. templateAdFlag = true;
  414. }
  415. result.push(arr.shift());
  416. } while (arr.length > 0);
  417. return result;
  418. },
  419. // 加载更多
  420. loadMore() {
  421. console.log("触发loadMore");
  422. console.log("当前状态:", {
  423. loading: this.data.loading,
  424. hasMore: this.data.hasMore,
  425. page: this.data.page,
  426. videoListLength: this.data.videoList.length,
  427. });
  428. // 添加防抖,避免频繁触发
  429. const now = Date.now();
  430. if (now - this.data.lastLoadTime < 500) {
  431. console.log("防抖触发,跳过本次加载");
  432. return;
  433. }
  434. if (this.data.hasMore && !this.data.loading) {
  435. console.log("开始加载更多数据");
  436. this.setData({
  437. page: this.data.page + 1,
  438. lastLoadTime: now,
  439. });
  440. this.loadVideoList();
  441. } else {
  442. console.log("不满足加载条件:", {
  443. hasMore: this.data.hasMore,
  444. loading: this.data.loading,
  445. });
  446. }
  447. },
  448. // 刷新列表
  449. refreshList() {
  450. wx.showLoading({
  451. title: "刷新中...",
  452. });
  453. this.setData({
  454. page: 1,
  455. videoList: [],
  456. hasMore: true,
  457. });
  458. this.loadVideoList()
  459. .then(() => {
  460. wx.hideLoading();
  461. wx.showToast({
  462. title: "刷新成功",
  463. icon: "success",
  464. duration: 1500,
  465. });
  466. })
  467. .catch(() => {
  468. wx.hideLoading();
  469. });
  470. },
  471. // 点击视频
  472. onVideoTap(e) {
  473. const { id, info, index } = e.currentTarget.dataset;
  474. console.log(id, info, index, "视频详情");
  475. if (!info) {
  476. wx.hideLoading();
  477. wx.showToast({
  478. title: "视频数据错误",
  479. icon: "none",
  480. });
  481. return;
  482. }
  483. SendEvent("click_video_tab_video", {
  484. video_id: id,
  485. tag_id: info.tag_ids[0],
  486. uuid: app.globalData.uuid,
  487. });
  488. const encodedTitle = encodeURIComponent(info.title || "");
  489. this.unlockUrl = `/pages/video/detail?id=${id}&title=${encodedTitle}&tag_id=${info.tag_ids[0]}`;
  490. if (!info.lock) {
  491. // 显示加载中提示
  492. wx.showLoading({
  493. title: "加载中...",
  494. mask: true,
  495. });
  496. // 跳转到视频详情页
  497. wx.navigateTo({
  498. url: this.unlockUrl,
  499. success: () => {
  500. wx.hideLoading();
  501. },
  502. fail: (err) => {
  503. console.error("跳转失败:", err);
  504. wx.hideLoading();
  505. wx.showToast({
  506. title: "跳转失败",
  507. icon: "none",
  508. });
  509. },
  510. });
  511. } else {
  512. this.reawrdVideoIndex = index;
  513. this.rewardVideo = info;
  514. this.rewardVideoPlayFn();
  515. }
  516. },
  517. // 下拉刷新
  518. onPullDownRefresh() {
  519. this.setData({
  520. page: 1,
  521. videoList: [],
  522. });
  523. this.loadVideoList().then(() => {
  524. wx.stopPullDownRefresh();
  525. });
  526. },
  527. // 分享按钮点击事件
  528. onShareTap(e) {
  529. // 阻止事件冒泡
  530. e.stopPropagation();
  531. // SendEvent('click_list_share', {"video_id": video.id, "tag_id": video.tag_ids[0]});
  532. },
  533. // 分享给朋友
  534. onShareAppMessage(e) {
  535. const video = e.target.dataset.video;
  536. if (!video) return {};
  537. const jump = wx.getStorageSync("jump"); // 是否跳转阅读器
  538. let url = "";
  539. url = `/pages/video/video?shared_video_id=${video.id}&title=${encodeURIComponent(video.title)}&tag_id=${video.tag_ids[0]}&share_count=1`;
  540. if (jump === 1) {
  541. url += "&jump=1";
  542. }
  543. SendEvent("click_list_share", {
  544. video_id: video.id,
  545. tag_id: video.tag_ids[0],
  546. uuid: app.globalData.uuid,
  547. });
  548. return {
  549. title: video.title,
  550. path: url,
  551. imageUrl: video.cover_image,
  552. success: function (res) {
  553. wx.showToast({
  554. title: "分享成功",
  555. icon: "success",
  556. duration: 1500,
  557. });
  558. },
  559. fail: function (res) {
  560. wx.showToast({
  561. title: "分享失败",
  562. icon: "none",
  563. duration: 1500,
  564. });
  565. },
  566. };
  567. },
  568. // 分享到朋友圈
  569. onShareTimeline(e) {
  570. const video = e.target.dataset.video;
  571. if (!video) return {};
  572. const jump = wx.getStorageSync("jump"); // 是否跳转阅读器
  573. let url = "";
  574. url = `shared_video_id=${video.id}&title=${encodeURIComponent(video.title)}&tag_id=${video.tag_ids[0]}&share_count=1`;
  575. SendEvent("click_list_share", {
  576. video_id: video.id,
  577. tag_id: video.tag_ids[0],
  578. uuid: app.globalData.uuid,
  579. });
  580. if (jump === 1) {
  581. url += "&jump=1";
  582. }
  583. return {
  584. title: video.title,
  585. query: url,
  586. imageUrl: video.cover_image,
  587. };
  588. },
  589. // 跳转到书籍详情
  590. goToBookDetail(query) {
  591. getApp().globalData.isShowDialog = true;
  592. // 使用公共的goToBookDetail函数
  593. const rndBook = rndone(apple.bookList);
  594. goToBookDetail(
  595. {
  596. bookId: rndBook.bookId,
  597. wxBookId: rndBook.wxBookId,
  598. chapterId: rndBook.chapterId,
  599. },
  600. query,
  601. );
  602. },
  603. // 跳转视频详情
  604. goToVideoDetail(videoId, tagId) {
  605. // 使用公共的goToVideoDetail函数
  606. goToVideoDetail({
  607. videoId: videoId,
  608. tagId: tagId,
  609. });
  610. },
  611. // 激励视频加载
  612. rewardVideoLoad() {
  613. if (wx.createRewardedVideoAd) {
  614. let adId = apple.ads.rewardAdId;
  615. let that = this;
  616. this.videoAd = wx.createRewardedVideoAd({
  617. adUnitId: adId,
  618. });
  619. this.videoAd.onLoad(() => {
  620. console.log("首页激励加载成功");
  621. });
  622. this.videoAd.onError((err) => {
  623. console.log("首页激励失败", err);
  624. });
  625. this.videoAd.onClose((res) => {
  626. // 用户点击了【关闭广告】按钮
  627. this.setData({
  628. isLoadingVideo: false,
  629. });
  630. if (res && res.isEnded) {
  631. // 发放奖励
  632. that.setData({
  633. [`videoList[${that.reawrdVideoIndex}].lock`]: false,
  634. });
  635. SendEvent("rewardad_finish", {
  636. video_id: that.rewardVideo.id,
  637. tag_id: that.rewardVideo.tag_ids[0],
  638. });
  639. console.log("发放奖励跳转");
  640. wx.navigateTo({
  641. url: `${that.unlockUrl}`,
  642. });
  643. }
  644. });
  645. }
  646. },
  647. // 激励视频展示
  648. rewardVideoPlayFn() {
  649. wx.showLoading({
  650. title: "解锁视频中",
  651. });
  652. this.videoAd
  653. .show()
  654. .then(() => {
  655. console.log("激励视频播放成功");
  656. })
  657. .catch((err) => {
  658. console.log("激励视频播放失败", err);
  659. this.setData({
  660. [`videoList[${that.reawrdVideoIndex}].lock`]: false,
  661. });
  662. wx.navigateTo({
  663. url: `${this.unlockUrl}`,
  664. });
  665. })
  666. .then(() => {
  667. wx.hideLoading();
  668. });
  669. },
  670. // 统一小程序广告加载成功
  671. appletsAdLoad(e) {
  672. let _target = e.currentTarget.dataset;
  673. this.setData({
  674. [`adErrorField.${_target.field}`]: false,
  675. });
  676. },
  677. // 统一小程序广告加载失败
  678. appletsAdError(e) {
  679. let _target = e.currentTarget.dataset;
  680. this.setData({
  681. [`adErrorField.${_target.field}`]: true,
  682. });
  683. console.error(_target.name, "错误", e);
  684. },
  685. // 统一小程序广告关闭
  686. appletsAdClose(e) {
  687. let _target = e.currentTarget.dataset;
  688. },
  689. // 统一小程序广告点击
  690. appletsAdClick(e) {
  691. let _target = e.currentTarget.dataset;
  692. },
  693. });