CourseTree.vue 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412
  1. <template>
  2. <div class="course_tree">
  3. <div v-for="(courseItem, courseIndex) in treeList" :key="courseIndex">
  4. <div v-if="courseItem.courseList" class="teacherList_name">
  5. <div
  6. v-for="tea in courseItem.courseList"
  7. :key="tea.courseId"
  8. class="names"
  9. :class="{ nactive: tea.courseId == courseItem.courseId }"
  10. @click="activeFunc(tea.courseId, courseIndex)"
  11. >
  12. {{ tea.aliasName }}
  13. </div>
  14. </div>
  15. <div
  16. class="item__title"
  17. @click="getMenuList(courseItem)"
  18. v-if="treeList.length != 1"
  19. >
  20. <i
  21. :class="{
  22. 'el-icon-caret-right': !courseItem.showList,
  23. 'el-icon-caret-bottom': courseItem.showList,
  24. }"
  25. ></i>
  26. {{ courseItem.courseName }}
  27. </div>
  28. <div
  29. v-if="courseItem.showList"
  30. :style="{ paddingLeft: treeList.length != 1 ? '12px' : '0' }"
  31. >
  32. <div class="item" v-for="(menu, index) in courseItem.list" :key="index">
  33. <template v-if="menu.type == 1">
  34. <div class="item__title" @click="openModule(menu)">
  35. <i
  36. :class="{
  37. 'el-icon-caret-right': !menu.showList,
  38. 'el-icon-caret-bottom': menu.showList,
  39. }"
  40. ></i>
  41. {{ menu.menuName }}
  42. </div>
  43. <div class="item__content">
  44. <div class="bank-chapter" v-if="menu.showList">
  45. <div
  46. class="bank-chapter__item"
  47. v-for="chapter in menu.list"
  48. :key="chapter.id"
  49. >
  50. <div
  51. v-if="chapter.type == 1"
  52. class="bank-chapter__item__text"
  53. @click="openChapter(chapter)"
  54. >
  55. <i
  56. :class="{
  57. 'el-icon-caret-right': !chapter.showList,
  58. 'el-icon-caret-bottom': chapter.showList,
  59. }"
  60. ></i
  61. >{{ chapter.name }}
  62. </div>
  63. <div
  64. class="bank-section"
  65. v-if="chapter.showList && chapter.type == 1"
  66. >
  67. <div
  68. class="bank-section__item"
  69. :class="{
  70. active: isActive(section),
  71. }"
  72. v-for="(section, sectionIndex) in chapter.list"
  73. :key="sectionIndex"
  74. @click="getResource(section, 1, courseIndex)"
  75. >
  76. <template v-if="section.type != 2">
  77. <template>
  78. <div
  79. class="note note--blue"
  80. v-if="section.sectionType == 1"
  81. >
  82. 视频
  83. </div>
  84. <div class="note" v-if="section.sectionType == 2">
  85. 直播
  86. </div>
  87. <div
  88. class="note note--yellow"
  89. v-if="section.sectionType == 3"
  90. >
  91. 回放
  92. </div>
  93. <div class="bank-section__item__text">
  94. {{ section.name }}
  95. <div
  96. style="font-size: 12px"
  97. v-if="section.liveStartTime > nowTime"
  98. >
  99. <span>{{
  100. $tools.timestampToTime(
  101. section.liveStartTime,
  102. (isDay = false)
  103. )
  104. }}</span
  105. >-
  106. <span>{{
  107. $tools.timestampToTime(
  108. section.liveEndTime,
  109. (isDay = false)
  110. )
  111. }}</span>
  112. </div>
  113. </div>
  114. </template>
  115. <div class="lear-state" v-if="isActive(section)">
  116. <img src="../../assets/learing.gif" alt="" />
  117. </div>
  118. <template v-if="section.durationTime > 0">
  119. <div class="during">
  120. {{ $tools.secondToDate(section.durationTime) }}
  121. </div>
  122. </template>
  123. <template>
  124. <div class="btn" v-if="section.rebuild > 0">
  125. 待重修
  126. </div>
  127. <template v-else>
  128. <div
  129. class="btn btn--green"
  130. v-if="section.learning == 1"
  131. >
  132. 已学完
  133. </div>
  134. </template>
  135. </template>
  136. <template
  137. v-if="
  138. section.liveStartTime && section.sectionType == 2
  139. "
  140. >
  141. <div
  142. class="live-btn live-btn--blue"
  143. v-if="section.liveStartTime > nowTime"
  144. >
  145. 待开播
  146. </div>
  147. <div
  148. class="live-btn live-btn--yellow"
  149. v-if="
  150. section.liveStartTime <= nowTime &&
  151. section.liveEndTime > nowTime
  152. "
  153. >
  154. 直播中
  155. </div>
  156. <div
  157. class="live-btn"
  158. v-if="section.liveEndTime < nowTime"
  159. >
  160. 已结束
  161. </div>
  162. </template>
  163. <template
  164. v-if="checkSection(section.sectionId, 'sectionExam')"
  165. >
  166. <div
  167. class="exercises"
  168. @click.stop="
  169. handelPracticeOrRxam(
  170. section,
  171. 2,
  172. courseItem.courseId
  173. )
  174. "
  175. >
  176. 习题
  177. <i class="el-icon-arrow-right icons"></i>
  178. </div>
  179. </template>
  180. </template>
  181. <template v-if="section.type == 2">
  182. <template>
  183. <div class="test-btn" v-if="section.doType == 1">
  184. 练习
  185. </div>
  186. <div class="test-btn" v-if="section.doType != 1">
  187. 考试
  188. </div>
  189. </template>
  190. <div class="bank-section__item__text">
  191. {{ section.name }}
  192. </div>
  193. <template>
  194. <div class="btn" v-if="section.rebuild > 0">
  195. 待重修
  196. </div>
  197. <template v-else>
  198. <div
  199. class="btn btn--green"
  200. v-if="section.learning == 1"
  201. >
  202. 合格
  203. </div>
  204. <div
  205. class="btn btn--red"
  206. v-if="section.learning == 0"
  207. >
  208. 不及格(需重考)
  209. </div>
  210. <div
  211. class="btn btn--green"
  212. v-if="section.rebuild > 0"
  213. >
  214. 待重测
  215. </div>
  216. </template>
  217. </template>
  218. </template>
  219. </div>
  220. </div>
  221. <div
  222. v-if="chapter.type == 2"
  223. class="bank-section__item"
  224. @click="getResource(chapter, 3, courseIndex)"
  225. >
  226. <template>
  227. <template>
  228. <div class="test-btn" v-if="chapter.doType == 1">
  229. 练习
  230. </div>
  231. <div class="test-btn" v-if="chapter.doType != 1">
  232. 考试
  233. </div>
  234. </template>
  235. <div class="bank-section__item__text">
  236. {{ chapter.name }}
  237. </div>
  238. <template>
  239. <div class="btn" v-if="chapter.rebuild > 0">待重修</div>
  240. <template v-else>
  241. <div
  242. class="btn btn--green"
  243. v-if="chapter.learning == 1"
  244. >
  245. 合格
  246. </div>
  247. <div
  248. class="btn btn--red"
  249. v-if="chapter.learning == 0"
  250. >
  251. 不及格(需重考)
  252. </div></template
  253. >
  254. </template>
  255. </template>
  256. </div>
  257. </div>
  258. </div>
  259. </div>
  260. </template>
  261. <template v-if="menu.type == 2">
  262. <div class="item__content">
  263. <div class="bank-chapter">
  264. <div class="bank-chapter__item">
  265. <div
  266. class="bank-chapter__item__text"
  267. @click="openChapter(menu)"
  268. >
  269. <i
  270. :class="{
  271. 'el-icon-caret-right': !menu.showList,
  272. 'el-icon-caret-bottom': menu.showList,
  273. }"
  274. ></i
  275. >{{ menu.menuName }}
  276. </div>
  277. <div class="bank-section" v-if="menu.showList">
  278. <div
  279. class="bank-section__item"
  280. :class="{
  281. active: isActive(section),
  282. }"
  283. v-for="(section, sectionIndex) in menu.list"
  284. :key="sectionIndex"
  285. @click="getResource(section, 1, courseIndex)"
  286. >
  287. <template v-if="section.type != 2">
  288. <template>
  289. <div
  290. class="note note--blue"
  291. v-if="section.sectionType == 1"
  292. >
  293. 视频
  294. </div>
  295. <div class="note" v-if="section.sectionType == 2">
  296. 直播
  297. </div>
  298. <div
  299. class="note note--yellow"
  300. v-if="section.sectionType == 3"
  301. >
  302. 回放
  303. </div>
  304. </template>
  305. <div class="bank-section__item__text">
  306. {{ section.name }}
  307. <div
  308. style="font-size: 12px"
  309. v-if="section.liveStartTime > nowTime"
  310. >
  311. <span>{{
  312. $tools.timestampToTime(
  313. section.liveStartTime,
  314. (isDay = false)
  315. )
  316. }}</span
  317. >-
  318. <span>{{
  319. $tools.timestampToTime(
  320. section.liveEndTime,
  321. (isDay = false)
  322. )
  323. }}</span>
  324. </div>
  325. </div>
  326. <div class="lear-state" v-if="isActive(section)">
  327. <img src="../../assets/learing.gif" alt="" />
  328. </div>
  329. <template v-if="section.durationTime > 0">
  330. <div class="during">
  331. {{ $tools.secondToDate(section.durationTime) }}
  332. </div>
  333. </template>
  334. <template>
  335. <div class="btn" v-if="section.rebuild > 0">
  336. 待重修
  337. </div>
  338. <template v-else>
  339. <div
  340. class="btn btn--green"
  341. v-if="section.learning == 1"
  342. >
  343. 已学完
  344. </div>
  345. </template>
  346. </template>
  347. <template
  348. v-if="
  349. section.liveStartTime && section.sectionType == 2
  350. "
  351. >
  352. <div
  353. class="live-btn live-btn--blue"
  354. v-if="section.liveStartTime > nowTime"
  355. >
  356. 待开播
  357. </div>
  358. <div
  359. class="live-btn live-btn--yellow"
  360. v-if="
  361. section.liveStartTime <= nowTime &&
  362. section.liveEndTime > nowTime
  363. "
  364. >
  365. 直播中
  366. </div>
  367. <div
  368. class="live-btn"
  369. v-if="section.liveEndTime < nowTime"
  370. >
  371. 已结束
  372. </div>
  373. </template>
  374. <template
  375. v-if="checkSection(section.sectionId, 'sectionExam')"
  376. >
  377. <div
  378. class="exercises"
  379. @click.stop="
  380. handelPracticeOrRxam(
  381. section,
  382. 2,
  383. courseItem.courseId
  384. )
  385. "
  386. >
  387. 习题
  388. <i class="el-icon-arrow-right icons"></i>
  389. </div>
  390. </template>
  391. </template>
  392. <template v-if="section.type == 2">
  393. <template>
  394. <div class="test-btn" v-if="section.doType == 1">
  395. 练习
  396. </div>
  397. <div class="test-btn" v-if="section.doType != 1">
  398. 考试
  399. </div>
  400. </template>
  401. <div class="bank-section__item__text">
  402. {{ section.name }}
  403. </div>
  404. <template>
  405. <div class="btn" v-if="section.rebuild > 0">
  406. 待重修
  407. </div>
  408. <template v-else>
  409. <div
  410. class="btn btn--green"
  411. v-if="section.learning == 1"
  412. >
  413. 合格
  414. </div>
  415. <div
  416. class="btn btn--red"
  417. v-if="section.learning == 0"
  418. >
  419. 不及格(需重考)
  420. </div>
  421. <div
  422. class="btn btn--green"
  423. v-if="section.rebuild > 0"
  424. >
  425. 待重测
  426. </div>
  427. </template>
  428. </template>
  429. </template>
  430. </div>
  431. </div>
  432. </div>
  433. </div>
  434. </div>
  435. </template>
  436. <template v-if="menu.type == 3">
  437. <div class="item__content">
  438. <div class="bank-section">
  439. <div
  440. class="bank-section__item"
  441. :class="{
  442. active: isActive(menu),
  443. }"
  444. @click="getResource(menu, 1, courseIndex)"
  445. >
  446. <template>
  447. <div class="note note--blue" v-if="menu.sectionType == 1">
  448. 视频
  449. </div>
  450. <div class="note" v-if="menu.sectionType == 2">直播</div>
  451. <div class="note note--yellow" v-if="menu.sectionType == 3">
  452. 回放
  453. </div>
  454. <div class="bank-section__item__text">
  455. {{ menu.name }}
  456. <div
  457. style="font-size: 12px"
  458. v-if="menu.liveStartTime > nowTime"
  459. >
  460. <span>{{
  461. $tools.timestampToTime(
  462. menu.liveStartTime,
  463. (isDay = false)
  464. )
  465. }}</span
  466. >-
  467. <span>{{
  468. $tools.timestampToTime(
  469. menu.liveEndTime,
  470. (isDay = false)
  471. )
  472. }}</span>
  473. </div>
  474. </div>
  475. </template>
  476. <div class="lear-state" v-if="isActive(menu)">
  477. <img src="../../assets/learing.gif" alt="" />
  478. </div>
  479. <template v-if="menu.durationTime > 0">
  480. <div class="during">
  481. {{ $tools.secondToDate(menu.durationTime) }}
  482. </div>
  483. </template>
  484. <template>
  485. <div class="btn" v-if="menu.rebuild > 0">待重修</div>
  486. <template v-else>
  487. <div class="btn btn--green" v-if="menu.learning == 1">
  488. 已学完
  489. </div>
  490. </template>
  491. </template>
  492. <template v-if="menu.liveStartTime && menu.sectionType == 2">
  493. <div
  494. class="live-btn live-btn--blue"
  495. v-if="menu.liveStartTime > nowTime"
  496. >
  497. 待开播
  498. </div>
  499. <div
  500. class="live-btn live-btn--yellow"
  501. v-if="
  502. menu.liveStartTime <= nowTime &&
  503. menu.liveEndTime > nowTime
  504. "
  505. >
  506. 直播中
  507. </div>
  508. <div class="live-btn" v-if="menu.liveEndTime < nowTime">
  509. 已结束
  510. </div>
  511. </template>
  512. <template v-if="checkSection(menu.menuId, 'sectionExamList')">
  513. <div
  514. class="exercises"
  515. @click.stop="
  516. handelPracticeOrRxam(menu, 3, courseItem.courseId)
  517. "
  518. >
  519. 习题
  520. <i class="el-icon-arrow-right icons"></i>
  521. </div>
  522. </template>
  523. </div>
  524. </div>
  525. </div>
  526. </template>
  527. </div>
  528. </div>
  529. </div>
  530. <el-dialog
  531. title="温馨提示"
  532. width="380px"
  533. center
  534. class="tip-dialog"
  535. :visible.sync="dialogPalyVisible"
  536. :close-on-click-modal="false"
  537. :close-on-press-escape="false"
  538. :show-close="false"
  539. >
  540. <template v-if="!isLastVideo">
  541. <p>当前视频已学完,继续学习下一个视频?</p>
  542. <div class="btn1">
  543. <el-button type="info" plain round @click="dialogPalyVisible = false"
  544. >取 消</el-button
  545. >
  546. <el-button type="primary" @click="comfirm" round>确定</el-button>
  547. </div>
  548. </template>
  549. <template v-else>
  550. <p>
  551. 当前是最后一个视频并已学习完,请检查所有章节的视频是否已学习完成。
  552. </p>
  553. <div class="btn2">
  554. <el-button type="primary" round @click="dialogPalyVisible = false"
  555. >确定</el-button
  556. >
  557. </div>
  558. </template>
  559. </el-dialog>
  560. </div>
  561. </template>
  562. <script>
  563. export default {
  564. props: {
  565. courseList: {
  566. type: Array,
  567. default: () => {
  568. return [];
  569. },
  570. },
  571. goodsLearningOrder: {
  572. type: Number,
  573. },
  574. sectionMaxNum: {
  575. type: Number,
  576. },
  577. sectionItem: {
  578. type: Object,
  579. default: () => {
  580. return {};
  581. },
  582. },
  583. rebuild: {
  584. type: Number,
  585. default: 0,
  586. },
  587. },
  588. data() {
  589. return {
  590. teaIndex: 0,
  591. nowTime: 0,
  592. treeList: [],
  593. sectionExam: [],
  594. sectionExamList: [],
  595. dialogPalyVisible: false,
  596. allSectionList: [],
  597. };
  598. },
  599. created() {
  600. this.init();
  601. },
  602. methods: {
  603. async init() {
  604. this.nowTime = Number(new Date().getTime() / 1000).toFixed(0);
  605. await this.getAllSectionList();
  606. this.treeList = await this.getDoubleTeacherList();
  607. let sectionItem = await this.backNextItem(
  608. this.treeList.find((e) => e.courseId == this.activeCourseId),
  609. 0,
  610. false
  611. );
  612. if (this.query.sectionType == 1 && !!this.query.rebuild == this.rebuild) {
  613. this.toPlay(sectionItem);
  614. }
  615. },
  616. activeFunc(courseId, index) {
  617. let { courseId: nowCourseId, courseList } = this.treeList[index];
  618. if (courseId == nowCourseId) {
  619. return;
  620. }
  621. let course = this.courseList.find((e) => e.courseId == courseId);
  622. if (course) {
  623. course.courseList = courseList;
  624. course.list = [];
  625. course.showList = false;
  626. }
  627. this.treeList.splice(index, 1, JSON.parse(JSON.stringify(course)));
  628. this.getMenuList(this.treeList[index]);
  629. },
  630. getMenuList(course, isFresh = false) {
  631. let { showList, courseId, list } = course;
  632. if (!isFresh) {
  633. course.showList = !showList;
  634. if (list.length) return;
  635. }
  636. this.$request
  637. .reSectionExamList({
  638. chapterId: 0,
  639. courseId,
  640. gradeId: this.gradeId,
  641. })
  642. .then((res) => {
  643. this.sectionExamList = res.data;
  644. });
  645. return this.$request
  646. .reMenuList({ courseId, gradeId: this.gradeId })
  647. .then((res) => {
  648. for (let i = 0; i < res.rows.length; i++) {
  649. let item = res.rows[i];
  650. item.id = item.menuId;
  651. item.name = item.menuName;
  652. item.menuType = item.type;
  653. item.showList = false;
  654. item.list = [];
  655. item.parent = course;
  656. }
  657. course.list = res.rows;
  658. return Promise.resolve(res.rows);
  659. });
  660. },
  661. openModule(module, isFresh = false) {
  662. console.log("openModule");
  663. let { list, isRebuild, id, courseId, showList } = module;
  664. if (!isFresh) {
  665. module.showList = !showList;
  666. if (list.length) return;
  667. }
  668. return this.$request
  669. .reChapterList({
  670. moduleId: id,
  671. gradeId: this.gradeId,
  672. courseId: courseId,
  673. rebuild: isRebuild ? 1 : undefined,
  674. })
  675. .then((res) => {
  676. for (let i = 0; i < res.data.length; i++) {
  677. let item = res.data[i];
  678. item.id = item.chapterId;
  679. item.showList = false;
  680. item.list = [];
  681. item.parent = module;
  682. isRebuild ? (item.isRebuild = 1) : (item.menuType = 2);
  683. }
  684. module.list = res.data;
  685. return Promise.resolve(res.data);
  686. });
  687. },
  688. openChapter(chapter, isFresh = false) {
  689. let {
  690. chapterId,
  691. menuId,
  692. list,
  693. moduleId,
  694. id,
  695. isRebuild,
  696. courseId,
  697. showList,
  698. } = chapter;
  699. if (!isFresh) {
  700. chapter.showList = !showList;
  701. if (list.length) return;
  702. }
  703. this.$request
  704. .reSectionExamList({
  705. chapterId: chapterId || menuId,
  706. courseId,
  707. gradeId: this.gradeId,
  708. })
  709. .then((res) => {
  710. this.sectionExam = [...this.sectionExam, ...res.data];
  711. });
  712. return this.$request
  713. .reSectionList({
  714. chapterId: id,
  715. gradeId: this.gradeId,
  716. courseId,
  717. rebuild: isRebuild ? 1 : undefined,
  718. moduleId: moduleId || 0,
  719. })
  720. .then((res) => {
  721. chapter.canLearn = res.data
  722. .filter((item) => item.type != 2)
  723. .every((item) => item.learning == 1);
  724. res.data.forEach((section) => {
  725. section.parent = chapter;
  726. section.courseId = courseId;
  727. });
  728. chapter.list = res.data;
  729. return Promise.resolve(chapter.list);
  730. });
  731. },
  732. getAllSectionList() {
  733. return this.$request
  734. .getAllSectionList({
  735. gradeId: this.gradeId,
  736. goodsId: this.goodsId,
  737. rebuild: this.rebuild,
  738. })
  739. .then((res) => {
  740. let { skipPort } = this.query;
  741. if (skipPort) {
  742. let { moduleId, chapterId, sectionId } = res.data[0];
  743. const query = JSON.parse(JSON.stringify(this.$route.query));
  744. query.moduleId = moduleId;
  745. query.chapterId = chapterId;
  746. query.sectionId = sectionId;
  747. query.skipPort = undefined;
  748. this.$router.push({ path: this.$route.path, query });
  749. }
  750. this.allSectionList = res.data;
  751. return Promise.resolve(res.data);
  752. });
  753. },
  754. /**
  755. * 判断是否是当前播放的节
  756. */
  757. isActive(section) {
  758. let moduleId = section.moduleId || 0;
  759. let chapterId = section.chapterId || 0;
  760. let sectionId = section.sectionId || section.menuId;
  761. let moduleId1 = this.sectionItem.moduleId || 0;
  762. let chapterId1 = this.sectionItem.chapterId || 0;
  763. let sectionId1 = this.sectionItem.sectionId || this.sectionItem.menuId;
  764. return (
  765. moduleId == moduleId1 &&
  766. chapterId == chapterId1 &&
  767. sectionId == sectionId1
  768. );
  769. },
  770. comfirm() {
  771. this.dialogPalyVisible = false;
  772. this.playNextVideo();
  773. },
  774. // 自动播放下一个视频
  775. async playNextVideo(sectionItem = this.sectionItem) {
  776. let { menuId, parent, courseId, projectId } = sectionItem;
  777. let list = (
  778. menuId
  779. ? this.treeList.find((e) => e.courseId == courseId).list
  780. : projectId
  781. ? this.treeList
  782. : parent.list
  783. ).filter((e) => !e.doType);
  784. let index = list.findIndex((e) => e.id == sectionItem.id);
  785. let nextItem = {};
  786. if (list.length - 1 > index) {
  787. nextItem = list[index + 1];
  788. this.toPlay(
  789. await this.backNextItem(nextItem, projectId ? 0 : nextItem.menuType)
  790. );
  791. } else {
  792. this.playNextVideo(parent);
  793. }
  794. },
  795. // 获取模块/章/节
  796. async backNextItem(nextItem, type, isNext = true) {
  797. if (type == undefined || type == 3) return nextItem;
  798. let key = ["getMenuList", "openModule", "openChapter"][type];
  799. let list = nextItem.list.length
  800. ? nextItem.list
  801. : await this[key](nextItem);
  802. if (isNext) {
  803. nextItem = type == 2 ? list.find((e) => e.type == 1) : list[0];
  804. } else {
  805. // 初始化 获取播放位置
  806. let { moduleId, chapterId, sectionId } = this.query;
  807. nextItem = list.find((e) => {
  808. if (moduleId * 1 && type == 0) {
  809. return e.menuId == moduleId;
  810. }
  811. if (chapterId * 1 && type < 2) {
  812. return e[moduleId * 1 ? "chapterId" : "menuId"] == chapterId;
  813. }
  814. return (
  815. e[moduleId * 1 || chapterId * 1 ? "sectionId" : "id"] == sectionId
  816. );
  817. });
  818. }
  819. return this.backNextItem(nextItem, nextItem.menuType, isNext);
  820. },
  821. async getResource(section, type, courseIndex) {
  822. if (
  823. section.type != 2 &&
  824. this.isActive(section) &&
  825. section.sectionType != 3
  826. ) {
  827. return;
  828. }
  829. if (!(await this.orderTopTobottom(section, type, courseIndex))) {
  830. this.clickLock = false;
  831. this.$message({
  832. type: "warning",
  833. message:
  834. section.type == 2
  835. ? "请学完视频课程再进行练习和测试"
  836. : "请按顺序学习视频课程",
  837. });
  838. return false;
  839. }
  840. //视频 回放
  841. if (section.sectionType == 1 || section.sectionType == 3) {
  842. if (!section.recordingUrl) {
  843. this.$message({
  844. type: "warning",
  845. message: `暂无播放地址数据`,
  846. });
  847. return false;
  848. }
  849. }
  850. // 直播
  851. if (section.sectionType == 2) {
  852. if (!section.liveUrl) {
  853. this.$message({
  854. type: "warning",
  855. message: `暂无直播地址数据`,
  856. });
  857. return false;
  858. }
  859. let data = await this.studyRecordGetChannelBasicInfo(section.liveUrl);
  860. if (data.watchStatus == "end" || data.watchStatus == "playback") {
  861. this.$message({
  862. type: "warning",
  863. message: `直播已结束`,
  864. });
  865. return false;
  866. }
  867. if (data.watchStatus == "waiting") {
  868. this.$message({
  869. type: "warning",
  870. message: `直播未开始`,
  871. });
  872. return false;
  873. }
  874. }
  875. // 学习次数
  876. if (!(await this.exceedLearnNum(section))) {
  877. return false;
  878. }
  879. section.type == 2
  880. ? this.toCourseExam(section, type, courseIndex)
  881. : this.toPlay(section);
  882. },
  883. async toCourseExam(section, type, courseIndex) {
  884. //试卷
  885. // 学习次数
  886. let num =
  887. this.goodsLearningOrder != 2 || section.rebuild
  888. ? await this.bankRecordDoNum(section.typeId)
  889. : section.doNum;
  890. if (
  891. (section.answerNum - num > 0 && section.answerNum > 0) ||
  892. section.answerNum == 0
  893. ) {
  894. this.$router.push({
  895. path: "/course-exam/" + this.goodsId,
  896. query: {
  897. courseId: this.treeList[courseIndex].courseId,
  898. gradeId: this.gradeId,
  899. moduleId: section.moduleId || 0,
  900. sectionId: section.sectionId || 0,
  901. examId: section.typeId,
  902. learning: section.learning,
  903. type: type,
  904. chapterId: section.chapterId || 0,
  905. orderGoodsId: this.orderGoodsId,
  906. },
  907. });
  908. } else {
  909. this.$message({
  910. type: "warning",
  911. message: "该试卷只能答题" + section.answerNum + "次",
  912. });
  913. return;
  914. }
  915. },
  916. // 节卷不需要控制
  917. handelPracticeOrRxam(section, type, courseId) {
  918. if (type == 3) {
  919. //节卷
  920. let data = this.sectionExamList.filter(
  921. (x) => x.sectionId == section.menuId
  922. );
  923. if (data && data.length > 0) {
  924. section = data[0];
  925. }
  926. } else if (type == 2) {
  927. //节卷
  928. let data = this.sectionExam.filter(
  929. (x) => x.sectionId == section.sectionId
  930. );
  931. if (data && data.length > 0) {
  932. section = data[0];
  933. }
  934. }
  935. this.$router.push({
  936. path: "/course-exam/" + this.goodsId,
  937. query: {
  938. courseId,
  939. gradeId: this.gradeId,
  940. moduleId: section.moduleId || 0,
  941. sectionId: section.sectionId || 0,
  942. examId: section.typeId,
  943. learning: section.learning,
  944. type: type,
  945. chapterId: section.chapterId || 0,
  946. orderGoodsId: this.orderGoodsId,
  947. },
  948. });
  949. },
  950. async exceedLearnNum(section) {
  951. let learnNum = await this.goodsTodayStudySectionNum();
  952. let hasLearn = await this.gradeCheckGoodsStudy(
  953. section.type == 2 ? section.typeId : section
  954. );
  955. if (this.sectionMaxNum > 0) {
  956. if (learnNum >= this.sectionMaxNum && !hasLearn) {
  957. this.$message({
  958. type: "warning",
  959. message: `每天最多学习${this.sectionMaxNum}节`,
  960. });
  961. return false;
  962. }
  963. }
  964. return true;
  965. },
  966. goodsTodayStudySectionNum() {
  967. return new Promise((resolve) => {
  968. this.$request
  969. .goodsTodayStudySectionNum({
  970. goodsId: this.goodsId,
  971. gradeId: this.gradeId,
  972. })
  973. .then((res) => {
  974. resolve(res.data);
  975. });
  976. });
  977. },
  978. gradeCheckGoodsStudy(option) {
  979. return new Promise((resolve) => {
  980. this.$request
  981. .gradeCheckGoodsStudy({
  982. goodsId: this.goodsId,
  983. gradeId: this.gradeId,
  984. moduleId: option.moduleId || 0,
  985. chapterId: option.chapterId || 0,
  986. sectionId: option.sectionId || option.menuId,
  987. })
  988. .then((res) => {
  989. resolve(res.data);
  990. });
  991. });
  992. },
  993. bankRecordDoNum(section) {
  994. return new Promise((resolve) => {
  995. this.$request
  996. .bankRecordDoNum({
  997. goodsId: this.goodsId,
  998. gradeId: this.gradeId,
  999. chapterId: section.chapterId,
  1000. courseId: this.courseId,
  1001. moduleId: 0,
  1002. examId: section.typeId,
  1003. })
  1004. .then((res) => {
  1005. resolve(res.data);
  1006. });
  1007. });
  1008. },
  1009. toPlay(section) {
  1010. this.$emit("getResource", section, this.rebuild);
  1011. },
  1012. //获取商品双师资模板
  1013. getDoubleTeacherList() {
  1014. let rows = JSON.parse(JSON.stringify(this.courseList));
  1015. rows.forEach((e) => {
  1016. e.list = [];
  1017. e.showList = false;
  1018. e.id = e.courseId;
  1019. });
  1020. return this.$request
  1021. .courseTeacherList({
  1022. goodsId: this.$route.params.goodsId,
  1023. })
  1024. .then(({ data }) => {
  1025. data.forEach((ele) => {
  1026. rows.forEach((e, i) => {
  1027. let actvieIndex = ele.courseIds.indexOf(this.activeCourseId);
  1028. let index = ele.courseIds.indexOf(e.courseId);
  1029. if (actvieIndex != -1 && index != -1) {
  1030. if (e.courseId == this.activeCourseId) {
  1031. e.courseList = ele.courseList;
  1032. } else {
  1033. delete rows[i];
  1034. }
  1035. } else {
  1036. if (index == 0) {
  1037. e.courseList = ele.courseList;
  1038. }
  1039. if (index > 0) {
  1040. delete rows[i];
  1041. }
  1042. }
  1043. });
  1044. });
  1045. return Promise.resolve(rows.filter((e) => e));
  1046. });
  1047. },
  1048. async orderTopTobottom(section, type, courseIndex) {
  1049. let { rebuild, moduleId, chapterId } = section;
  1050. if (this.goodsLearningOrder != 2 || rebuild) {
  1051. return true;
  1052. }
  1053. if (this.treeList.length > 1 && courseIndex > 0) {
  1054. let isAllLear = this.treeList
  1055. .filter((e, i) => i < courseIndex)
  1056. .every((ele) => ele.stuAllNum == ele.secAllNum);
  1057. if (!isAllLear) return false;
  1058. }
  1059. let list = await this.studyRecordMenuAllList(
  1060. this.treeList[courseIndex].courseId
  1061. );
  1062. type = type == 1 && section.type == 2 ? 2 : type;
  1063. if (type == 1) {
  1064. let index = list.findIndex(
  1065. (e) =>
  1066. e.moduleId == moduleId &&
  1067. e.chapterId == chapterId &&
  1068. e.id == section.sectionId
  1069. );
  1070. list = list.slice(0, index);
  1071. } else if (type != 3) {
  1072. list = list.filter(
  1073. (e) => e.moduleId == moduleId && e.chapterId == chapterId
  1074. );
  1075. }
  1076. return list.every((item) => item.studyStatus == 1);
  1077. },
  1078. studyRecordMenuAllList(courseId) {
  1079. return new Promise((resolve) => {
  1080. this.$request
  1081. .studyRecordMenuAllList({
  1082. courseId,
  1083. gradeId: this.gradeId,
  1084. goodsId: this.goodsId,
  1085. })
  1086. .then((res) => {
  1087. resolve(res.data);
  1088. });
  1089. });
  1090. },
  1091. //校验节是否有试卷
  1092. checkSection(sectionId, key) {
  1093. let _data = this[key];
  1094. if (_data.length == 0) {
  1095. return false;
  1096. }
  1097. return _data.some((section) => section.sectionId == sectionId);
  1098. },
  1099. // 刷新数据
  1100. refreshList() {
  1101. let { parent, menuId } = this.sectionItem;
  1102. if (menuId) {
  1103. this.getMenuList(playCourse, true);
  1104. } else {
  1105. this.openChapter(parent, true);
  1106. }
  1107. },
  1108. studyRecordGetChannelBasicInfo(channelId) {
  1109. return new Promise((resolve) => {
  1110. this.$request
  1111. .studyRecordGetChannelBasicInfo({
  1112. channelId,
  1113. })
  1114. .then((res) => {
  1115. resolve(res.data);
  1116. })
  1117. .catch((err) => {});
  1118. });
  1119. },
  1120. },
  1121. computed: {
  1122. query() {
  1123. return this.$route.query;
  1124. },
  1125. gradeId() {
  1126. return this.query.gradeId;
  1127. },
  1128. activeCourseId() {
  1129. let courseId = this.query.courseId;
  1130. if (!courseId&&this.treeList.length) {
  1131. courseId = this.treeList[0].courseId;
  1132. }
  1133. return courseId;
  1134. },
  1135. goodsId() {
  1136. return this.$route.params.goodsId;
  1137. },
  1138. playCourseId() {
  1139. return this.sectionItem.courseId;
  1140. },
  1141. playCourse() {
  1142. return this.treeList.find((e) => e.courseId == this.playCourseId);
  1143. },
  1144. isLastVideo() {
  1145. try {
  1146. let { sectionId, chapterId, courseId } = this.sectionItem;
  1147. let lastVideo = this.allSectionList.slice(-1)[0];
  1148. return (
  1149. sectionId == lastVideo.sectionId &&
  1150. chapterId == lastVideo.chapterId &&
  1151. courseId == lastVideo.courseId
  1152. );
  1153. } catch (error) {
  1154. return false;
  1155. }
  1156. },
  1157. orderGoodsId() {
  1158. return this.query.orderGoodsId;
  1159. },
  1160. },
  1161. };
  1162. </script>
  1163. <style scoped lang="scss">
  1164. .course_tree {
  1165. height: 380px;
  1166. overflow-y: scroll;
  1167. &::-webkit-scrollbar {
  1168. display: none;
  1169. }
  1170. .item {
  1171. &__title {
  1172. padding-left: 12px;
  1173. height: 40px;
  1174. line-height: 40px;
  1175. cursor: pointer;
  1176. font-size: 14px;
  1177. font-family: Microsoft YaHei;
  1178. font-weight: bold;
  1179. color: #fff;
  1180. .el-icon-caret-right,
  1181. .el-icon-caret-bottom {
  1182. color: #999;
  1183. }
  1184. }
  1185. &__content {
  1186. .bank-chapter {
  1187. &__item {
  1188. color: #fff;
  1189. font-size: 14px;
  1190. &__text {
  1191. padding: 8px 8px 8px 24px;
  1192. cursor: pointer;
  1193. flex: 1;
  1194. .el-icon-caret-right,
  1195. .el-icon-caret-bottom {
  1196. color: #999;
  1197. }
  1198. }
  1199. }
  1200. }
  1201. .bank-section {
  1202. &__item {
  1203. user-select: none;
  1204. color: #fff;
  1205. font-size: 14px;
  1206. display: flex;
  1207. align-items: center;
  1208. .lear-state {
  1209. height: 20px;
  1210. padding-right: 8px;
  1211. img {
  1212. width: 20px;
  1213. height: 20px;
  1214. // margin-right: 4px;
  1215. }
  1216. }
  1217. &.active {
  1218. background: #132b4d;
  1219. font-size: 14px;
  1220. font-family: Microsoft YaHei;
  1221. font-weight: bold;
  1222. color: #3f8dfd;
  1223. }
  1224. &__text {
  1225. flex: 1;
  1226. padding: 8px 8px 8px 12px;
  1227. height: 40px;
  1228. display: flex;
  1229. flex-direction: column;
  1230. justify-content: center;
  1231. cursor: pointer;
  1232. .el-icon-caret-right,
  1233. .el-icon-caret-bottom {
  1234. color: #999;
  1235. }
  1236. }
  1237. .test-btn {
  1238. margin-left: 10px;
  1239. width: 32px;
  1240. height: 20px;
  1241. background: #007aff;
  1242. border-radius: 4px;
  1243. line-height: 18px;
  1244. color: #fff;
  1245. text-align: center;
  1246. }
  1247. .note {
  1248. margin-left: 10px;
  1249. width: 32px;
  1250. height: 20px;
  1251. border: 1px solid #ff3b30;
  1252. border-radius: 4px;
  1253. line-height: 18px;
  1254. color: #ff3b30;
  1255. text-align: center;
  1256. &--yellow {
  1257. border-color: #ff9500;
  1258. color: #ff9500;
  1259. }
  1260. &--blue {
  1261. border-color: #3f8dfd;
  1262. color: #3f8dfd;
  1263. }
  1264. }
  1265. .during {
  1266. color: #999;
  1267. margin-right: 10px;
  1268. }
  1269. .btn {
  1270. margin-right: 12px;
  1271. padding: 0 2px;
  1272. height: 20px;
  1273. border: 1px solid #ff3b30;
  1274. background: #ff3b30;
  1275. border-radius: 4px;
  1276. line-height: 18px;
  1277. color: #fff;
  1278. text-align: center;
  1279. &--green {
  1280. border: 1px solid #34c759;
  1281. background: #34c759;
  1282. }
  1283. }
  1284. .live-btn {
  1285. margin-left: 20px;
  1286. width: 60px;
  1287. height: 20px;
  1288. border-radius: 4px;
  1289. background: #eeeeee;
  1290. line-height: 18px;
  1291. color: #666666;
  1292. text-align: center;
  1293. &--yellow {
  1294. background: #fff7eb;
  1295. color: #ff9500;
  1296. }
  1297. &--blue {
  1298. border-color: #ebf4ff;
  1299. color: #007aff;
  1300. }
  1301. }
  1302. .exercises {
  1303. cursor: pointer;
  1304. font-size: 14px;
  1305. color: #498afe;
  1306. }
  1307. }
  1308. }
  1309. }
  1310. }
  1311. .teacherList_name {
  1312. display: flex;
  1313. margin-left: 20px;
  1314. margin-top: 10px;
  1315. .names {
  1316. font-size: 13px;
  1317. color: #383838;
  1318. margin-right: 8px;
  1319. cursor: pointer;
  1320. background: #818181;
  1321. border-radius: 4px;
  1322. padding: 3px 6px;
  1323. &.nactive {
  1324. background: #cccccc;
  1325. }
  1326. }
  1327. }
  1328. .tip-dialog {
  1329. /deep/ {
  1330. .el-dialog__body {
  1331. padding: 6px 40px 44px;
  1332. }
  1333. .el-dialog__header {
  1334. padding-top: 36px;
  1335. }
  1336. .el-dialog__title {
  1337. font-weight: bold;
  1338. color: #222222;
  1339. }
  1340. }
  1341. p {
  1342. color: #666666;
  1343. font-size: 16px;
  1344. text-align: center;
  1345. }
  1346. .btn1 {
  1347. display: flex;
  1348. justify-content: space-between;
  1349. margin-top: 50px;
  1350. .el-button {
  1351. width: 140px;
  1352. }
  1353. }
  1354. .btn2 {
  1355. width: 200px;
  1356. margin: 32px auto 0;
  1357. .el-button {
  1358. width: 200px;
  1359. }
  1360. }
  1361. }
  1362. }
  1363. </style>