index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <template>
  2. <div v-loading="loading" class="task-detail">
  3. <TaskTop :item-info="itemInfo" type="student" @viewFile="viewFile" />
  4. <div class="task-detail-main">
  5. <div class="time-type">{{ $t(timeType) }} {{ name }}</div>
  6. <div class="time-interval">
  7. {{ time_space_view_txt }}
  8. </div>
  9. <div class="task-require">
  10. <span class="label">{{ $t('Key326') }}</span>
  11. <span v-html="contentUrl"></span>
  12. </div>
  13. <div class="task-courseware">
  14. <span class="label">{{ $t('Key312') }}</span>
  15. <div>
  16. <el-tag
  17. v-for="{ courseware_id, courseware_name, is_finished, group_id_selected_info } in courseware_list"
  18. :key="courseware_id"
  19. color="#fff"
  20. :title="courseware_name"
  21. @click="finishTask(courseware_id, is_finished, group_id_selected_info)"
  22. >
  23. <svg-icon icon-class="courseware" /> <span>{{ courseware_name }}</span>
  24. <svg-icon v-if="is_finished === 'true'" class="check-mark" icon-class="check-mark" />
  25. </el-tag>
  26. </div>
  27. </div>
  28. <div class="accessory-list">
  29. <span class="label">{{ $t('Key313') }}</span>
  30. <div>
  31. <el-tag v-for="item in accessory_list" :key="item.file_id" color="#fff" :title="item.file_name">
  32. <span @click="viewFile(item.file_name, item.file_id)">{{ item.file_name }}</span>
  33. </el-tag>
  34. </div>
  35. </div>
  36. <!-- 完成评价 -->
  37. <template v-if="my_execute_info.is_finished === 'true'">
  38. <div class="teacher-commenting">
  39. <div v-if="is_enable_homework" class="single-line">
  40. <span class="label">{{ $t('Key327') }}</span>
  41. <div>
  42. <el-tag
  43. v-for="item in my_execute_info.homework_list"
  44. :key="item.file_id"
  45. color="#fff"
  46. :title="item.file_name"
  47. >
  48. <span @click="viewFile(item.file_name, item.file_id)">{{ item.file_name }}</span>
  49. </el-tag>
  50. </div>
  51. </div>
  52. <template v-if="teaching_type === 10 && is_enable_KHPJ">
  53. <div class="single-line">
  54. <span class="label">{{ $t('Key316') }}</span>
  55. <el-input
  56. v-model="my_execute_info.student_remark"
  57. maxlength="3000"
  58. disabled
  59. type="textarea"
  60. resize="none"
  61. :rows="6"
  62. />
  63. </div>
  64. <div class="single-line">
  65. <span class="label">{{ $t('Key317') }}</span>
  66. <el-rate v-model="my_execute_info.student_score" disabled />
  67. </div>
  68. </template>
  69. <div v-if="is_enable_message" class="single-line">
  70. <span class="label">{{ $t('Key328') }}</span>
  71. <el-input
  72. v-model="my_execute_info.student_message"
  73. maxlength="3000"
  74. disabled
  75. type="textarea"
  76. resize="none"
  77. :rows="6"
  78. />
  79. </div>
  80. <div class="single-line">
  81. <span class="label">{{ $t('Key318') }}</span>
  82. <el-rate v-model="my_execute_info.teacher_score" disabled />
  83. <span class="teacher_remark">{{ my_execute_info.teacher_remark }}</span>
  84. </div>
  85. </div>
  86. </template>
  87. <!-- 直播评价 -->
  88. <template v-else-if="teaching_type === 10">
  89. <div class="live-info">
  90. <div class="single-line">
  91. <span class="enter-live" @click="enterLive"><svg-icon icon-class="video-red" /> {{ $t('Key329') }}</span>
  92. </div>
  93. <template v-if="is_enable_KHPJ">
  94. <div class="single-line">
  95. <span class="label">{{ $t('Key316') }}</span>
  96. <el-input v-model="student_remark" maxlength="3000" type="textarea" resize="none" :rows="6" />
  97. </div>
  98. <div class="single-line">
  99. <span class="label">{{ $t('Key317') }}</span>
  100. <el-rate v-model="student_score" />
  101. </div>
  102. <div class="confirm single-line">
  103. <el-button type="primary" @click="fillTaskExecuteInfo_Student_live">
  104. {{ $t('Key319') }}
  105. </el-button>
  106. </div>
  107. </template>
  108. </div>
  109. </template>
  110. <template v-else>
  111. <div v-if="is_enable_homework" class="submit-homework">
  112. <span class="label">{{ $t('Key330') }}</span>
  113. <el-upload action="no" :http-request="upload" multiple :show-file-list="false">
  114. <el-button><svg-icon icon-class="upload" /> {{ $t('Key152') }}</el-button>
  115. </el-upload>
  116. </div>
  117. <div class="file-list">
  118. <el-tag
  119. v-for="(item, i) in file_list"
  120. :key="item.file_id"
  121. color="#fff"
  122. closable
  123. :title="item.file_name"
  124. @close="deleteFile(i)"
  125. >
  126. <span>{{ item.file_name }}</span>
  127. </el-tag>
  128. </div>
  129. <div v-if="is_enable_message" class="leave-message">
  130. <span class="label">{{ $t('Key328') }}</span>
  131. <el-input v-model="student_message" maxlength="3000" type="textarea" resize="none" :rows="6" />
  132. </div>
  133. <div v-if="is_enable_homework || is_enable_message" class="submit-button">
  134. <el-button type="primary" @click="fillTaskExecuteInfo_Student">
  135. {{ $t('Key331') }}
  136. </el-button>
  137. </div>
  138. </template>
  139. </div>
  140. <CompletionView
  141. :task-id="id"
  142. :cur-student-id="$store.state.user.user_code"
  143. :cur-courseware-id="curCoursewareId"
  144. :dialog-visible="dialogVisible_completion"
  145. :preview-group-id="previewGroupId"
  146. @dialogClose="dialogClose_completion"
  147. />
  148. <FinishCourseware
  149. :id="id"
  150. :courseware-id="coursewareId"
  151. :preview-group-id="previewGroupId"
  152. :dialog-visible="dialogVisible"
  153. @dialogClose="dialogClose"
  154. />
  155. <ShowFile :visible="visible" :file-name="showCurFileName" :file-id="showCurFileId" @close="dialogShowFileClose" />
  156. </div>
  157. </template>
  158. <script>
  159. export default {
  160. name: 'TaskDetailsStudent'
  161. };
  162. </script>
  163. <script setup>
  164. import { ref, computed, inject } from 'vue';
  165. import { fileUpload, FileDownload } from '@/api/app';
  166. import { CreateEnterLiveRoomSession } from '@/api/live';
  167. import { GetTaskInfo, FillMyTaskExecuteInfo_Student } from '@/api/course';
  168. import { isAllowFileType, fileTypeSizeLimit } from '@/utils/validate';
  169. import { useRoute, useRouter } from 'vue-router/composables';
  170. import { Message } from 'element-ui';
  171. import TaskTop from '../TaskTop.vue';
  172. import FinishCourseware from '@/components/course/FinishCourseware.vue';
  173. import CompletionView from '@/components/course/CompletionView.vue';
  174. import ShowFile from '@/common/show_file/index.vue';
  175. const $t = inject('$t');
  176. const route = useRoute();
  177. const router = useRouter();
  178. // 任务 ID
  179. const id = route.params.id;
  180. let itemInfo = ref({
  181. course_name: '',
  182. cs_item_name: '',
  183. cs_item_learning_material_list: [],
  184. time_space_view_txt: ''
  185. });
  186. let student_message = ref('');
  187. let name = ref('');
  188. let teaching_type = ref('');
  189. let time_type = ref('');
  190. let content = ref('');
  191. let time_space_view_txt = ref('');
  192. let courseware_list = ref([]);
  193. let accessory_list = ref([]);
  194. let file_list = ref([]);
  195. let dialogVisible = ref(false);
  196. let previewGroupId = ref('[]');
  197. let coursewareId = ref('');
  198. let curCoursewareId = ref('');
  199. let dialogVisible_completion = ref(false);
  200. let my_execute_info = ref({});
  201. let student_remark = ref('');
  202. let student_score = ref(0);
  203. let loading = ref(true);
  204. let visible = ref(false);
  205. let showCurFileName = ref('');
  206. let showCurFileId = ref('');
  207. // 开启课后评价
  208. let is_enable_KHPJ = ref(false);
  209. let is_enable_homework = ref(false);
  210. let is_enable_message = ref(false);
  211. let timeType = computed(() => {
  212. let val = '';
  213. switch (time_type.value) {
  214. case 0:
  215. val = 'Key353';
  216. break;
  217. case 1:
  218. val = 'Key354';
  219. break;
  220. case 2:
  221. val = 'Key355';
  222. break;
  223. default:
  224. break;
  225. }
  226. return val;
  227. });
  228. let contentUrl = computed(() => {
  229. const con = content.value;
  230. if (!con) return '';
  231. return con.replace(
  232. new RegExp(/((https?:\/\/)?[\w-]+\.[\w-]+\.[\w-,@?^=%&:/~\\+#]+)/, 'g'),
  233. '<a href="$1" target="_blank">$1</a>'
  234. );
  235. });
  236. GetTaskInfo({
  237. id,
  238. is_contain_cs_item_learning_material: true,
  239. is_contain_my_execute_info: true
  240. })
  241. .then(
  242. ({
  243. name: na,
  244. teaching_type: teachingType,
  245. time_type: timeType,
  246. course_name,
  247. cs_item_name,
  248. courseware_list: courseList,
  249. accessory_list: accList,
  250. cs_item_learning_material_list,
  251. content: con,
  252. time_space_view_txt: view_txt,
  253. my_execute_info: executeInfo,
  254. is_enable_KHPJ: isKHPJ,
  255. is_enable_homework: isHomework,
  256. is_enable_message: isMessage,
  257. cs_item_begin_time,
  258. cs_item_end_time
  259. }) => {
  260. itemInfo.value = {
  261. name,
  262. time_space_view_txt: view_txt,
  263. course_name,
  264. cs_item_name,
  265. cs_item_learning_material_list,
  266. content,
  267. cs_item_time: `${cs_item_begin_time} ~ ${cs_item_end_time}`
  268. };
  269. name.value = na;
  270. content.value = con;
  271. teaching_type.value = teachingType;
  272. time_type.value = timeType;
  273. courseware_list.value = courseList;
  274. accessory_list.value = accList;
  275. time_space_view_txt.value = view_txt;
  276. my_execute_info.value = executeInfo;
  277. is_enable_KHPJ.value = isKHPJ === 'true';
  278. is_enable_homework.value = isHomework === 'true';
  279. is_enable_message.value = isMessage === 'true';
  280. }
  281. )
  282. .finally(() => {
  283. loading.value = false;
  284. });
  285. function upload(file) {
  286. const fileName = file.file.name;
  287. if (!isAllowFileType(fileName)) {
  288. Message.error(`【${fileName}】${$t('Key335')}`);
  289. return;
  290. }
  291. if (fileTypeSizeLimit(file.file.name, file.file.size)) {
  292. return Message.error(`${fileName}文件大小超出限制`);
  293. }
  294. fileUpload('Open', file).then(({ file_info_list }) => {
  295. if (file_info_list.length > 0) {
  296. const { file_id, file_name, file_url } = file_info_list[0];
  297. file_list.value.push({ file_id, file_name, file_url });
  298. }
  299. });
  300. }
  301. function deleteFile(i) {
  302. file_list.value.splice(i, 1);
  303. }
  304. function download(FileID) {
  305. FileDownload(FileID).then((data) => {
  306. console.log(data);
  307. });
  308. }
  309. function viewFile(fileName, fileId) {
  310. showCurFileName.value = fileName;
  311. showCurFileId.value = fileId;
  312. visible.value = true;
  313. }
  314. function dialogShowFileClose() {
  315. visible.value = false;
  316. showCurFileName.value = '';
  317. showCurFileId.value = '';
  318. }
  319. function fillTaskExecuteInfo_Student() {
  320. // 基础任务,必须提交作业
  321. if (my_execute_info.value.is_finished === 'false' && teaching_type.value === 12 && file_list.value.length <= 0) {
  322. return Message.error('请先提交作业');
  323. }
  324. const homework_file_id_list = [];
  325. file_list.value.forEach((item) => {
  326. homework_file_id_list.push(item.file_id);
  327. });
  328. FillMyTaskExecuteInfo_Student({
  329. task_id: id,
  330. homework_file_id_list,
  331. student_message: student_message.value,
  332. is_finished: true
  333. }).then(() => {
  334. Message.success($t('Key337'));
  335. router.go(0);
  336. });
  337. }
  338. function fillTaskExecuteInfo_Student_live() {
  339. FillMyTaskExecuteInfo_Student({
  340. task_id: id,
  341. is_finished: true,
  342. student_remark: student_remark.value,
  343. student_score: student_score.value
  344. }).then(() => {
  345. Message.success($t('Key336'));
  346. router.go(0);
  347. });
  348. }
  349. function enterLive() {
  350. CreateEnterLiveRoomSession({
  351. task_id: id
  352. }).then(({ live_room_sys_user_id, room_id, session_id, room_user_id }) => {
  353. router.push({
  354. path: `/live/student`,
  355. query: { live_room_sys_user_id, room_id, session_id, task_id: id, room_user_id }
  356. });
  357. });
  358. }
  359. // 完成任务
  360. function finishTask(id, is_finished, group_id_selected_info) {
  361. if (my_execute_info.value.is_finished === 'true' && is_finished === 'false') {
  362. return Message.error($t('Key338'));
  363. }
  364. previewGroupId.value = group_id_selected_info ?? '[]';
  365. if (is_finished === 'true') {
  366. dialogVisible_completion.value = true;
  367. curCoursewareId.value = id;
  368. } else {
  369. dialogVisible.value = true;
  370. coursewareId.value = id;
  371. }
  372. }
  373. function dialogClose() {
  374. dialogVisible.value = false;
  375. coursewareId.value = '';
  376. }
  377. function dialogClose_completion() {
  378. dialogVisible_completion.value = false;
  379. curCoursewareId.value = '';
  380. }
  381. </script>
  382. <style lang="scss" scoped>
  383. @import '~@/styles/mixin';
  384. $bor-color: #d9d9d9;
  385. .task-detail {
  386. @include container;
  387. min-height: calc(100vh - 130px);
  388. .el-tag {
  389. @include el-tag;
  390. margin: 0 8px 6px 0;
  391. border-color: $bor-color;
  392. border-radius: 4px;
  393. > span {
  394. cursor: pointer;
  395. }
  396. }
  397. &-main {
  398. padding: 24px 32px;
  399. margin-top: 16px;
  400. background-color: #fff;
  401. border-radius: 8px;
  402. .time-type {
  403. font-size: 20px;
  404. font-weight: 500;
  405. }
  406. .time-interval {
  407. padding: 16px 0;
  408. color: #737373;
  409. }
  410. %submit-homework,
  411. .submit-homework {
  412. display: flex;
  413. align-items: center;
  414. padding-top: 24px;
  415. border-top: 1px solid $bor-color;
  416. }
  417. %teacher-commenting,
  418. .teacher-commenting {
  419. @extend %submit-homework;
  420. flex-direction: column;
  421. > .single-line {
  422. display: flex;
  423. width: 100%;
  424. + div {
  425. margin-top: 24px;
  426. }
  427. .teacher_remark {
  428. margin-left: 24px;
  429. }
  430. }
  431. }
  432. .live-info {
  433. @extend %teacher-commenting;
  434. .enter-live {
  435. padding: 8px 26px;
  436. color: #ff6868;
  437. cursor: pointer;
  438. border: 1px solid #ff6868;
  439. border-radius: 20px;
  440. }
  441. .confirm {
  442. padding-left: 120px;
  443. }
  444. }
  445. .file-list {
  446. padding-left: 120px;
  447. margin-bottom: 16px;
  448. > .el-tag {
  449. padding: 0 10px;
  450. color: #409eff;
  451. border-color: #d9ecff;
  452. }
  453. }
  454. .leave-message {
  455. display: flex;
  456. align-items: flex-start;
  457. .label {
  458. margin-top: 8px;
  459. }
  460. }
  461. .task-courseware .el-tag {
  462. cursor: pointer;
  463. .svg-icon {
  464. margin-right: 8px;
  465. font-size: 18px;
  466. }
  467. .check-mark {
  468. position: relative;
  469. top: 2px;
  470. right: -20px;
  471. margin-left: 12px;
  472. }
  473. }
  474. .task-require,
  475. .task-courseware,
  476. .accessory-list,
  477. .submit-homework,
  478. .leave-message,
  479. .live-info,
  480. .teacher-commenting {
  481. display: flex;
  482. margin-bottom: 16px;
  483. .label {
  484. display: inline-block;
  485. width: 120px;
  486. min-width: 120px;
  487. }
  488. }
  489. .task-require {
  490. white-space: pre-wrap;
  491. :deep a {
  492. color: #18a0fb;
  493. }
  494. }
  495. .submit-button {
  496. padding-left: 120px;
  497. }
  498. }
  499. }
  500. </style>