courseModule.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <template>
  2. <!-- style="margin: 20rpx 0;" -->
  3. <view>
  4. <view class="title" @click="openModule(menuItem)">
  5. <text class="title_name" style="margin-left: 10rpx"
  6. >{{ menuItem.name }}
  7. </text>
  8. <view class="fl">
  9. <view
  10. class="title_status"
  11. :class="['grey', 'blue', 'gre'][learnStatus + 1]"
  12. style="margin-right: 20rpx"
  13. >
  14. {{ ["待学习", "学习中", "已学完"][learnStatus + 1] }}
  15. </view>
  16. <image src="/static/icon/up.png" class="icon_up" v-if="down"></image>
  17. <image src="/static/icon/down.png" class="icon_up" v-if="!down"></image>
  18. </view>
  19. </view>
  20. <view v-show="!down">
  21. <view v-for="(itemM, indexM) in list" :key="indexM">
  22. <courseChapter
  23. v-if="itemM.type != 2"
  24. :orderGoodsId="orderGoodsId"
  25. :isLive="isLive"
  26. :preItem="list[indexM - 1] || preItem"
  27. :sectionMaxNum="sectionMaxNum"
  28. :needOpen="itemM.needOpen"
  29. @toDo="toDo($event)"
  30. :courseId="courseId"
  31. :learningOrder="learningOrder"
  32. :goodsId="goodsId"
  33. :isBuy="isBuy"
  34. :gradeId="gradeId"
  35. :isRebuild="isRebuild"
  36. :menuItem="itemM"
  37. :levelId="levelId + '-' + itemM.chapterId"
  38. :menuAllList="menuAllList"
  39. :sectionItem="sectionItem"
  40. >
  41. </courseChapter>
  42. <u-line v-if="indexM < list.length - 1"></u-line>
  43. <!-- 模块卷 -->
  44. <view v-if="itemM.type == 2">
  45. <view
  46. class="examBox"
  47. @click="
  48. toDoModuleExam(
  49. itemM.typeId,
  50. goodsId,
  51. itemM.moduleId,
  52. itemM.chapterId,
  53. itemM,
  54. indexM
  55. )
  56. "
  57. >
  58. <view class="exam">
  59. <view class="eTag">
  60. {{ itemM.doType == 1 ? "练习" : "考试" }}
  61. </view>
  62. <view style="margin-left: 15rpx; flex: 1">{{ itemM.name }}</view>
  63. </view>
  64. <view v-if="isRebuild || itemM.rebuild > 0" class="tagRe"
  65. >待重修</view
  66. >
  67. <view v-else>
  68. <view
  69. :class="{
  70. tagGreen: itemM.learning == 1,
  71. tagRe: itemM.learning == 0 || itemM.rebuild > 0,
  72. }"
  73. >
  74. <text v-if="itemM.learning == 1">合格</text>
  75. <text v-else-if="itemM.learning == 0">不及格(需重考)</text>
  76. <!-- <text v-else>不合格</text> -->
  77. </view>
  78. </view>
  79. </view>
  80. </view>
  81. </view>
  82. </view>
  83. </view>
  84. </template>
  85. <script>
  86. import courseChapter from "@/components/course/courseChapter.vue";
  87. export default {
  88. name: "courseModule",
  89. props: {
  90. isLive: false,
  91. orderGoodsId: {
  92. default: 0,
  93. },
  94. preItem: {
  95. default: undefined,
  96. },
  97. learningOrder: {
  98. //是否设置学习顺序 1 章节顺序 0不设置 2从头学到尾顺序
  99. type: Number,
  100. defaule: 0,
  101. },
  102. needOpen: {
  103. //是否默认展开
  104. type: Boolean,
  105. default: false,
  106. },
  107. menuItem: {
  108. type: Object,
  109. default: {},
  110. },
  111. goodsId: {
  112. type: Number,
  113. default: 0,
  114. },
  115. courseId: {
  116. type: [Number, String],
  117. default: 0,
  118. },
  119. isBuy: {
  120. //是否是已购买商品
  121. type: Boolean,
  122. default: false,
  123. },
  124. levelId: {
  125. type: [Number, String],
  126. default: "",
  127. },
  128. isRebuild: {
  129. //是否重修目录
  130. type: Boolean,
  131. default: false,
  132. },
  133. gradeId: {
  134. //重修需要班级ID
  135. type: Number,
  136. default: 0,
  137. },
  138. sectionMaxNum: {
  139. default: undefined,
  140. },
  141. // 商品类型 1视频2题库 3补考 4前培 5虚拟赠送题库 6直播
  142. goodsType: {
  143. type: [Number, String],
  144. default: 0,
  145. },
  146. menuAllList: {
  147. // 课程所有子目录结构列表
  148. type: Array,
  149. default: () => [],
  150. },
  151. sectionItem: {
  152. type: Object,
  153. default: () => {},
  154. },
  155. },
  156. components: {
  157. courseChapter,
  158. },
  159. data() {
  160. return {
  161. down: true,
  162. list: [],
  163. };
  164. },
  165. methods: {
  166. toDo(item) {
  167. this.$emit("toDo", item);
  168. },
  169. openModule(item) {
  170. this.down = !this.down;
  171. console.log(this.down, 789);
  172. if (!this.down && this.list.length == 0) {
  173. if (this.isBuy) {
  174. if (this.isRebuild) {
  175. this.getReChapterList(item.id, item.courseId);
  176. } else {
  177. this.getBuyChapterList(item.id, item.courseId); //已购买目录
  178. }
  179. } else {
  180. this.getChapterList(item.id); //未购买目录
  181. }
  182. }
  183. },
  184. getChapterList(moduleId) {
  185. // url: '/app/common/course/chapterList/'+data,
  186. this.$api.chapterList(moduleId).then((res) => {
  187. if (res.data.code == 200) {
  188. for (let i = 0; i < res.data.data.length; i++) {
  189. let item = res.data.data[i];
  190. item.id = item.chapterId;
  191. item.menuType = 2;
  192. }
  193. this.list = res.data.data;
  194. }
  195. });
  196. },
  197. getReChapterList(moduleId, courseId) {
  198. this.$api
  199. .reChapterList({
  200. moduleId: moduleId,
  201. gradeId: this.gradeId,
  202. courseId: courseId,
  203. rebuild: 1,
  204. orderGoodsId: this.orderGoodsId,
  205. })
  206. .then((res) => {
  207. if (res.data.code == 200) {
  208. for (let i = 0; i < res.data.data.length; i++) {
  209. let item = res.data.data[i];
  210. item.id = item.chapterId;
  211. }
  212. this.list = res.data.data;
  213. }
  214. });
  215. },
  216. getBuyChapterList(moduleId, courseId) {
  217. console.log(moduleId, courseId, "moduleId, courseId");
  218. // course/chapterList
  219. this.$api
  220. .reChapterList({
  221. moduleId: moduleId,
  222. gradeId: this.gradeId,
  223. courseId: courseId,
  224. orderGoodsId: this.orderGoodsId,
  225. })
  226. .then((res) => {
  227. if (res.data.code == 200) {
  228. for (let i = 0; i < res.data.data.length; i++) {
  229. let item = res.data.data[i];
  230. item.id = item.chapterId;
  231. item.menuType = 2;
  232. if (Object.keys(this.sectionItem).length) {
  233. item["needOpen"] =
  234. item.chapterId == this.sectionItem.chapterId ? true : false;
  235. } else {
  236. item["needOpen"] = i == 0 ? true : false;
  237. }
  238. }
  239. this.list = res.data.data;
  240. // console.log('章的列表:', this.list);
  241. }
  242. });
  243. },
  244. /**
  245. * 去做题
  246. */
  247. async toDoModuleExam(
  248. id,
  249. goodsId = 0,
  250. moduleId = 0,
  251. chapterId = 0,
  252. item,
  253. index
  254. ) {
  255. if (item.doType === 2 && item.learning == 1) {
  256. return;
  257. }
  258. if (this.learningOrder == 2) {
  259. let newRows = [];
  260. newRows = this.menuAllList.filter((e) => e.moduleId == moduleId);
  261. let isAllLearn = newRows.every((item) => {
  262. return item.studyStatus == 1;
  263. });
  264. if (isAllLearn) {
  265. uni.navigateTo({
  266. url:
  267. "/pages2/class/questionBank?courseId=" +
  268. this.courseId +
  269. "&gradeId=" +
  270. this.gradeId +
  271. "&isFromVideo=1&id=" +
  272. id +
  273. "&goodsid=" +
  274. goodsId +
  275. "&moduleId=" +
  276. moduleId +
  277. "&chapterId=" +
  278. chapterId +
  279. "&orderGoodsId=" +
  280. this.orderGoodsId +
  281. "&type=3" +
  282. "&learning=" +
  283. item.learning +
  284. "&isBackVideo=" +
  285. 1,
  286. });
  287. } else {
  288. uni.showToast({
  289. icon: "none",
  290. title: "请学完视频课程再进行练习和测试",
  291. });
  292. }
  293. } else {
  294. uni.navigateTo({
  295. url:
  296. "/pages2/class/questionBank?courseId=" +
  297. this.courseId +
  298. "&gradeId=" +
  299. this.gradeId +
  300. "&isFromVideo=1&id=" +
  301. id +
  302. "&goodsid=" +
  303. goodsId +
  304. "&moduleId=" +
  305. moduleId +
  306. "&chapterId=" +
  307. chapterId +
  308. "&orderGoodsId=" +
  309. this.orderGoodsId +
  310. "&type=3" +
  311. "&learning=" +
  312. item.learning +
  313. "&isBackVideo=" +
  314. 1,
  315. });
  316. }
  317. },
  318. },
  319. computed: {
  320. learnStatus() {
  321. let { id, courseId } = this.menuItem;
  322. if (
  323. this.sectionItem.courseId == courseId &&
  324. this.sectionItem.moduleId == id
  325. ) {
  326. return 0;
  327. }
  328. const list = this.menuAllList.filter(
  329. (e) => e.courseId == courseId && e.moduleId == id
  330. );
  331. const isAllLearn = list.every((item) => {
  332. return item.studyStatus == 1;
  333. });
  334. return isAllLearn ? 1 : -1;
  335. },
  336. },
  337. watch: {
  338. courseId: {
  339. handler(val) {
  340. console.log(
  341. "🚀 ~ file: courseModule.vue:346 ~ handler ~ val:",
  342. this.sectionItem,
  343. this.menuItem
  344. );
  345. if (this.sectionItem.moduleId == this.menuItem.menuId) {
  346. this.down = true;
  347. this.list = [];
  348. this.openModule(this.menuItem);
  349. }
  350. },
  351. immediate: true,
  352. },
  353. },
  354. };
  355. </script>
  356. <style lang="scss" scoped>
  357. .title {
  358. height: 70rpx;
  359. display: flex;
  360. justify-content: space-between;
  361. align-items: center;
  362. border-bottom: 1rpx solid #eeeeee;
  363. .title_name {
  364. font-size: 24rpx;
  365. font-weight: 500;
  366. color: #333333;
  367. white-space: nowrap;
  368. overflow: hidden;
  369. text-overflow: ellipsis;
  370. }
  371. .icon_up {
  372. width: 24rpx;
  373. height: 24rpx;
  374. }
  375. .title_status {
  376. width: 80rpx;
  377. height: 28rpx;
  378. border-radius: 8rpx;
  379. font-size: 20rpx;
  380. color: #ffffff;
  381. text-align: center;
  382. }
  383. .gre {
  384. background: #34c759;
  385. }
  386. .blue {
  387. background: #409eff;
  388. }
  389. .grey {
  390. background: #909399;
  391. }
  392. }
  393. .examBox {
  394. display: flex;
  395. align-items: center;
  396. justify-content: space-between;
  397. .exam {
  398. font-size: 30rpx;
  399. display: flex;
  400. align-items: center;
  401. margin: 20rpx 0;
  402. }
  403. .eTag {
  404. width: 64rpx;
  405. height: 36rpx;
  406. text-align: center;
  407. line-height: 36rpx;
  408. font-size: 20rpx;
  409. background: #007aff;
  410. border-radius: 8rpx;
  411. color: #ffffff;
  412. }
  413. }
  414. .tagRe {
  415. // width: 80rpx;
  416. line-height: 28rpx;
  417. padding: 0 8rpx;
  418. height: 28rpx;
  419. background: #ff3b30;
  420. border-radius: 8rpx;
  421. font-size: 20rpx;
  422. color: #ffffff;
  423. text-align: center;
  424. }
  425. .tagGreen {
  426. width: 80rpx;
  427. height: 28rpx;
  428. background: #34c759;
  429. border-radius: 8rpx;
  430. font-size: 20rpx;
  431. color: #ffffff;
  432. text-align: center;
  433. }
  434. </style>