chanpin4.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <template>
  2. <view class="ezy-page-body xuexi-page-body">
  3. <!-- 滚动区域 -->
  4. <scroll-view v-if="existData" :scroll-with-animation="true" scroll-y :scroll-top="scrollTop"
  5. @scroll="handleScroll">
  6. <view class="xxjl-card-box-padding">
  7. <view class="xxjl-card-box">
  8. <!-- 显示内容 -->
  9. <view class="card-body-box">
  10. <img :src="neirongInfo.cover" />
  11. <view class="body-right">
  12. <view class="right-name">{{ neirongInfo.chanpinName }}</view>
  13. <view class="right-item right-item-mini">等级:{{neirongInfo.dengjiName}}</view>
  14. <view class="right-item">版本:{{neirongInfo.name}}</view>
  15. <view>课程:{{neirongInfo.curKechengName}}</view>
  16. </view>
  17. </view>
  18. <view class="card-progress-box">
  19. <view class="xx-progress-box">
  20. <view class="progress-title">学习进度</view>
  21. <progress :percent="curProcess" class="xx-progress" stroke-width="20"
  22. backgroundColor="#3c7dfd" activeColor="#ffd11c" />
  23. </view>
  24. <ezyActiveVue class="ezy-btn-active jxxx-btn" @aclick="handlePlay(neirongInfo,'jixu')">
  25. </ezyActiveVue>
  26. </view>
  27. </view>
  28. </view>
  29. <view class="xx-item-list">
  30. <view class="xx-item-title">— 以下为当前等级课程目录 —</view>
  31. <view v-for="(item, index) in dagangList" :key="item.jieId">
  32. <!-- 节列表 -->
  33. <ezyActiveVue class="ezy-list-item-active xx-item-box" :class="item.lock?'xx-disabled-item-box':''"
  34. @aclick="handlePlay(item,'play')">
  35. <view class="xx-item-status"
  36. :class="item.wanchengFlag == 1 ? 'completed-status' : 'uncompleted-status'"></view>
  37. <img :src="item.cover" />
  38. <view class="xx-text-box">
  39. <view>{{ item.jieName }}</view>
  40. <view>{{ item.jieIntro }}</view>
  41. </view>
  42. <view v-if="item.lock" class="xx-item-lock-btn"></view>
  43. <view v-else class="xx-item-btn"></view>
  44. </ezyActiveVue>
  45. </view>
  46. <view class="xx-item-title">本级别最后一单元啦~</view>
  47. <view class="xx-more-btn" @click="moreBtn"></view>
  48. </view>
  49. </scroll-view>
  50. <!-- 回到顶部 -->
  51. <view v-show="showGoTop" class="go-top-btn" @click="goTopBtn"></view>
  52. <!-- 无数据占位 -->
  53. <view v-if="!existData" class="ezy-page-body">
  54. <view class="ezy-no-sj">
  55. <icon></icon>
  56. <text>暂无数据</text>
  57. </view>
  58. </view>
  59. <!-- 弹窗组件 -->
  60. <danyuanInfoVue ref="dyRef" v-if="isShow" @close="isShow = false"></danyuanInfoVue>
  61. <!-- 购买提示窗 -->
  62. <tipSmallDialog ref="gmtRef" content="需要购买当前课程才能学习" @confirm-btn="handleConfirmBtn" qrBtnName="前往购买">
  63. </tipSmallDialog>
  64. </view>
  65. </template>
  66. <script>
  67. import ezyActiveVue from "@/components/ezyActive/ezyActive.vue";
  68. import CustomTabBar from '@/components/custom-tabbar/index.vue';
  69. import cacheManager from "@/utils/cacheManager.js";
  70. import {
  71. yingyuPinduInfo,
  72. shuxueSave2
  73. } from "@/api/chanpinneirong.js"
  74. import {
  75. onLoad,
  76. onShow,
  77. onHide,
  78. onUnload
  79. } from "@dcloudio/uni-app"
  80. import danyuanInfoVue from '@/pages/xinshuxue/components/danyuanInfo.vue';
  81. import {
  82. toast
  83. } from '../../utils/common';
  84. import {
  85. updateChanpin4Process
  86. } from "./useNeirongChanpin4"
  87. import tipSmallDialog from "@/components/dialog/tipSmallDialog.vue";
  88. // 产品2 计算特训
  89. export default {
  90. data() {
  91. return {
  92. canExitApp: false,
  93. dagangList: [],
  94. neirongInfo: {},
  95. banbenId: '',
  96. jieId: '',
  97. chanpinId: '',
  98. dengjiId: '',
  99. curProcess: '',
  100. existData: false,
  101. isShow: false,
  102. danyuanId: '',
  103. stickyHeight: 0, // 吸顶栏高度(px)
  104. currentStickyTitle: '', // 初始为空,不显示吸顶
  105. currentStickyIntro: '',
  106. currentDanyuanId: '',
  107. currentStickyDengjiId: '',
  108. titlePositions: [],
  109. scrollTop: 0,
  110. showGoTop: false,
  111. scrollThreshold: 300,
  112. }
  113. },
  114. components: {
  115. CustomTabBar,
  116. danyuanInfoVue,
  117. ezyActiveVue,
  118. tipSmallDialog
  119. },
  120. onHide() {
  121. console.log('学习页面隐藏')
  122. },
  123. onUnload() {
  124. // 页面卸载无需特殊处理
  125. },
  126. methods: {
  127. handleConfirmBtn() {
  128. // 加锁视频需要购买
  129. uni.navigateTo({
  130. url: "/pages/chanpinShop/cp2/dingdan"
  131. })
  132. },
  133. initData(data) {
  134. console.log('4444444');
  135. const cacheData = cacheManager.get('contentInfo');
  136. if (cacheData) {
  137. console.log('使用缓存数据');
  138. this.updateFromCache();
  139. } else {
  140. console.log('重新请求数据');
  141. this.initFromOptions(data);
  142. }
  143. },
  144. goTopBtn() {
  145. // 替换原来的 uni.pageScrollTo
  146. this.scrollTop = Math.random(); // 先设置一个随机值
  147. this.$nextTick(() => {
  148. this.scrollTop = 0; // 再设置回0
  149. });
  150. this.showGoTop = false;
  151. },
  152. moreBtn() {
  153. uni.switchTab({
  154. url: '/pages/chanpinXuanze/index'
  155. })
  156. },
  157. initFromOptions(data) {
  158. this.loadDataFromApi(data);
  159. },
  160. // 从缓存更新数据方法
  161. updateFromCache() {
  162. console.log('12311');
  163. updateChanpin4Process()
  164. const cacheData = cacheManager.get('contentInfo');
  165. console.log('cacheData 从缓存更新数据方法', cacheData);
  166. if (cacheData) {
  167. this.neirongInfo = {
  168. ...cacheData
  169. };
  170. this.curProcess = cacheData.curProcess;
  171. this.dagangList = [...(cacheData.dagangList || [])];
  172. console.log('dagangListdagangList', this.dagangList);
  173. this.dengjiId = cacheData.dengjiId
  174. this.danyuanId = cacheData.danyuanId
  175. this.chanpinId = cacheData.chanpinId
  176. if (this.dagangList.length == 0) {
  177. this.existData = false
  178. } else {
  179. this.existData = true
  180. }
  181. // this.$nextTick(() => {
  182. // this.updateTitlePositions();
  183. // });
  184. } else {
  185. this.existData = false;
  186. }
  187. },
  188. loadDataFromApi(data) {
  189. console.log('data', data);
  190. uni.showLoading({
  191. title: '加载中'
  192. });
  193. this.dengjiId = data.dengjiId
  194. this.danyuanId = data.danyuanId
  195. this.chanpinId = data.chanpinId
  196. this.neirongInfo = {}
  197. this.curProcess = ''
  198. this.dagangList = []
  199. const req = {
  200. dengjiId: this.dengjiId,
  201. danyuanId: this.danyuanId,
  202. }
  203. yingyuPinduInfo(req).then(res => {
  204. if (res.code === 0) {
  205. this.neirongInfo = res.data;
  206. this.neirongInfo.jieId = res.data.curJieId;
  207. this.curProcess = res.data.curProcess * 100;
  208. this.dagangList = res.data.dagangList || [];
  209. if (this.dagangList.length == 0) {
  210. this.existData = false
  211. } else {
  212. this.existData = true
  213. }
  214. const cacheData = {
  215. ...res.data,
  216. dengjiId: this.dengjiId,
  217. chanpinId: this.chanpinId
  218. };
  219. cacheManager.set('contentInfo', cacheData);
  220. uni.hideLoading();
  221. }
  222. }).catch(res => {
  223. cacheManager.remove("contentInfo");
  224. toast("加载失败,请重试");
  225. uni.hideLoading();
  226. });
  227. },
  228. handleScroll(e) {
  229. const scrollTop = e.detail.scrollTop;
  230. console.log('scrollTop', scrollTop);
  231. this.showGoTop = scrollTop > this.scrollThreshold;
  232. },
  233. getJieAndDanyuan(data, jieId) {
  234. for (let jie of data.dagangList) {
  235. if (jie.jieId == jieId) {
  236. return {
  237. jie
  238. }
  239. }
  240. }
  241. return null;
  242. },
  243. async saveAndNavigate(jieId, da, code) {
  244. if (code == 'jixu') {
  245. if (!da.jieId) {
  246. toast("jieId 丢失")
  247. return false
  248. }
  249. }
  250. let req = {
  251. "dengjiId": da.dengjiId,
  252. "jieId": da.jieId
  253. }
  254. console.log('req', req);
  255. const res = await shuxueSave2(req);
  256. if (res.code == 0) {
  257. let curJieAndDanyuan = this.getJieAndDanyuan(this.neirongInfo, jieId);
  258. console.log('curJieAndDanyuan', curJieAndDanyuan);
  259. if (!curJieAndDanyuan) {
  260. toast("未找到课程信息");
  261. return false;
  262. }
  263. const cacheData = cacheManager.get('contentInfo') || {};
  264. cacheData.curKechengName = curJieAndDanyuan.jie.jieIntro;
  265. cacheData.jieId = curJieAndDanyuan.jie.jieId;
  266. cacheData.curJieId = jieId;
  267. cacheData.type = curJieAndDanyuan.jie.type;
  268. cacheManager.set('contentInfo', cacheData);
  269. uni.navigateTo({
  270. url: `/pages/jisuantexun/lookShipin?jieId=${jieId}`
  271. })
  272. } else {
  273. return false;
  274. }
  275. },
  276. handlePlay(da, code) {
  277. console.log('ddd', da)
  278. if (da.lock && code == 'play') {
  279. this.$refs.gmtRef.handleShow();
  280. // 加锁视频需要购买
  281. // uni.navigateTo({
  282. // url: "/pages/chanpinShop/cp1/dingdan"
  283. // })
  284. return;
  285. }
  286. let jieId = code === 'jixu' ? da.curJieId : da.jieId;
  287. if (!jieId) {
  288. toast("无课程ID");
  289. return;
  290. }
  291. this.saveAndNavigate(jieId, da, code);
  292. },
  293. handleClickDanyuan(jieId) {
  294. if (!jieId) {
  295. toast("jieId丢失")
  296. return false
  297. }
  298. this.isShow = true;
  299. setTimeout(() => {
  300. // 更新为点击的动态单元Id [临时]
  301. this.$refs.dyRef.handleShow(jieId)
  302. }, 100)
  303. },
  304. handleBack() {
  305. uni.navigateTo({
  306. url: `/pages/chanpinXuanze/banben?dengjiId=` + this.dengjiId
  307. })
  308. },
  309. },
  310. // 计算吸顶栏下方的偏移(确保内容不被遮挡)
  311. computed: {
  312. }
  313. }
  314. </script>