CourseTree.vue 45 KB

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