StudyTables.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. <template>
  2. <div class="studyRecordTable">
  3. <div style="height: 62px">
  4. <div
  5. class="studyStyle"
  6. :class="{ isFixed: headerFixed }"
  7. :style="{ left: left }"
  8. >
  9. <div class="a_style">
  10. <i></i>
  11. <span>视频审核进度</span>
  12. <div class="flex_style_study">
  13. <div class="num_style" style="color: #0047d0">
  14. 待审:{{ userData.pending }}节
  15. </div>
  16. <div class="num_style" style="color: #e53935">
  17. 作弊:{{ userData.cheat }}节
  18. </div>
  19. <div class="num_style" style="color: #43a047">
  20. 通过:{{ userData.pass }}节
  21. </div>
  22. <div style="clear: both"></div>
  23. </div>
  24. </div>
  25. <div class="a_style">
  26. <i></i>
  27. <span>做题审核进度</span>
  28. <div class="flex_style_study">
  29. <div class="num_style" style="color: #0047d0">
  30. 待审:{{ userData.examPending }}节
  31. </div>
  32. <div class="num_style" style="color: #e53935">
  33. 作弊:{{ userData.examCheat }}节
  34. </div>
  35. <div class="num_style" style="color: #43a047">
  36. 通过:{{ userData.examPass }}节
  37. </div>
  38. <div style="clear: both"></div>
  39. </div>
  40. </div>
  41. <div class="a_style" style="width: 280px">
  42. <i></i>
  43. <span>学时审批状态</span>
  44. <div class="flex_style_study">
  45. <div class="num_style" style="color: #0047d0">
  46. {{
  47. ["不可审核", "未通过", "通过审核", "待审核", "审核中"][
  48. periodStatus + 1
  49. ]
  50. }}
  51. </div>
  52. <div style="clear: both"></div>
  53. </div>
  54. </div>
  55. <div class="s_sd">
  56. <template v-if="periodStatus === 2">
  57. <el-checkbox
  58. :disabled="!allIds.length"
  59. :indeterminate="isIndeterminate"
  60. v-model="checkAll"
  61. @change="handleCheckAllChange"
  62. >待审全选</el-checkbox
  63. >
  64. <el-button
  65. style="margin-left: 10px"
  66. size="mini"
  67. type="success"
  68. @click="getChangeStatus(1)"
  69. >勾选通过</el-button
  70. >
  71. <el-button size="mini" type="danger" @click="getChangeStatus(2)"
  72. >勾选作弊</el-button
  73. >
  74. </template>
  75. <template v-if="periodStatus === 3">
  76. <el-button style="margin-left: 10px" size="mini" @click="checkBack"
  77. >勾选数据,打回待审核状态</el-button
  78. >
  79. <el-button size="mini" type="warning" @click="approvedOK = true"
  80. >确认审核通过结果</el-button
  81. >
  82. </template>
  83. <!-- <el-button
  84. v-if="periodStatus === 1"
  85. style="margin-left: 10px"
  86. size="mini"
  87. @click="backToAudit"
  88. >打回待审核状态</el-button
  89. > -->
  90. </div>
  91. </div>
  92. </div>
  93. <el-checkbox-group v-model="checkList" @change="handleCheckedCitiesChange">
  94. <component
  95. :is="keys[key]"
  96. v-for="key in Object.keys(tablesData)"
  97. :key="key"
  98. :tabledata="tablesData[key]"
  99. :label="key == 5 ? '卷' : '章'"
  100. :userImg="userImg"
  101. :setData="setData"
  102. ></component>
  103. </el-checkbox-group>
  104. <Cheat-dialog
  105. :disabledBtn="disabledBtn"
  106. :vidBoxHours.sync="vidBoxHours"
  107. @close="loadingClose"
  108. @submit="
  109. (reason) => {
  110. submitOK(2, reason);
  111. }
  112. "
  113. ></Cheat-dialog>
  114. <Base-dialog
  115. title="操作提示:"
  116. :disabledBtn="disabledBtn"
  117. :isShow.sync="through"
  118. @close="loadingClose"
  119. @submit="
  120. () => {
  121. submitOK(1);
  122. }
  123. "
  124. >
  125. <div>
  126. 确定所勾选的内容,审核结果为【通过】?<br />
  127. 确认后,初审不可再修改,请检查清楚再操作!
  128. </div>
  129. </Base-dialog>
  130. <Base-dialog
  131. title="操作提示:"
  132. :disabledBtn="disabledBtn"
  133. :isShow.sync="popback"
  134. @close="loadingClose"
  135. @submit="uploadForm"
  136. >
  137. <div>
  138. <div style="color: red">
  139. <h4 style="margin: 0px">当前勾选了{{ checkList.length }}条数据:</h4>
  140. <ul style="margin: 0px 0px 6px; max-height: 500px; overflow: auto">
  141. <li v-for="(item, index) in checkList" :key="index">
  142. {{ index + 1 }}.{{ getSecName(item) }}
  143. </li>
  144. </ul>
  145. </div>
  146. <div style="text-align: center; font-weight: bold">
  147. 所选数据,确定要打回待审核状态吗?<br />
  148. 打回后,重新走审核流程,请慎重操作。
  149. </div>
  150. </div>
  151. </Base-dialog>
  152. <Base-dialog
  153. title="操作提示:"
  154. :disabledBtn="disabledBtn"
  155. :isShow.sync="approvedOK"
  156. @close="loadingClose"
  157. @submit="approvedOKFunc"
  158. >
  159. <div>
  160. <div style="color: red">
  161. <h4 style="margin: 0px">确认审核通过结果后:</h4>
  162. <ul style="margin: 0px 0px 6px">
  163. <li>
  164. (1)有做官方接口的,自动触发【学时官方推送】<br />
  165. (2)公开【学习学时记录-学时记录】按钮,权限人可查看【审核结果】<br />
  166. (3)有匹配的预约考试,可走预约流程
  167. </li>
  168. </ul>
  169. </div>
  170. <div style="font-weight: bold; margin-top: 20px">
  171. 确认提交审核通过结果?<br />
  172. 确认后,不能再修改,请慎重操作。
  173. </div>
  174. </div>
  175. </Base-dialog>
  176. </div>
  177. </template>
  178. <script>
  179. import ModulTable from "./ModulTable.vue";
  180. import ChapterTable from "./ChapterTable.vue";
  181. import LessonTable from "./LessonTable.vue";
  182. import CheatDialog from "./CheatDialog.vue";
  183. import { rollBackPeriod } from "@/api/education/classManageMent";
  184. import { debounce } from "@/utils";
  185. import { mapGetters } from "vuex";
  186. export default {
  187. props: {
  188. tablesData: {
  189. type: Object,
  190. default: () => {
  191. return {};
  192. },
  193. },
  194. userData: {
  195. type: Object,
  196. default: () => {
  197. return {};
  198. },
  199. },
  200. setData: {
  201. type: Object,
  202. default: () => {
  203. return {};
  204. },
  205. },
  206. getUserInfo: {
  207. type: Function,
  208. default: () => {},
  209. },
  210. },
  211. provide() {
  212. return {
  213. getPeriodStatus: () => this.periodStatus,
  214. getUserInfo: this.getUserInfo,
  215. getAllIds: () => this.allIds,
  216. getUserImgPhoto: () => this.userData.oneInchPhotos,
  217. };
  218. },
  219. data() {
  220. return {
  221. checkList: [],
  222. allIds: [],
  223. checkAll: false,
  224. isIndeterminate: false,
  225. vidBoxHours: false,
  226. through: false,
  227. popback: false,
  228. approvedOK: false,
  229. disabledBtn: false,
  230. formData: {
  231. cheating_reason: "",
  232. },
  233. statusPop: "", //1单个2批量
  234. rules: {
  235. cheating_reason: [
  236. {
  237. required: true,
  238. message: "请填写作弊原因",
  239. trigger: ["blur", "change"],
  240. },
  241. ],
  242. },
  243. msgTitle: [
  244. { label: "学习拍照异常", value: 1 },
  245. {
  246. label: "学习拍照太黑无法识别人像,请确保拍照光线充足并拍到全脸",
  247. value: 2,
  248. },
  249. {
  250. label: "学习拍照太模糊无法识别人像,请确保拍照光线充足并拍到全脸",
  251. value: 3,
  252. },
  253. {
  254. label: "学习拍照人像不全无法识别,请确保拍照光线充足并拍到全脸",
  255. value: 4,
  256. },
  257. ],
  258. allType3List: [],
  259. offsetTop: 0,
  260. offsetHeight: 0,
  261. headerFixed: false,
  262. userImg: "",
  263. };
  264. },
  265. methods: {
  266. handleScroll() {
  267. // 得到页面滚动的距离
  268. let scrollTop =
  269. window.pageYOffset ||
  270. document.documentElement.scrollTop ||
  271. document.body.scrollTop;
  272. // 判断页面滚动的距离是否大于吸顶元素的位置
  273. this.headerFixed = scrollTop > this.offsetTop + this.offsetHeight;
  274. },
  275. submitAllSlect(reason) {
  276. this.submitOK(2, reason);
  277. },
  278. handleCheckedCitiesChange(value) {
  279. let checkedCount = value.length;
  280. if (checkedCount) {
  281. this.checkAll = checkedCount === this.allIds.length;
  282. } else {
  283. this.checkAll = false;
  284. }
  285. this.isIndeterminate =
  286. checkedCount > 0 && checkedCount < this.allIds.length;
  287. },
  288. handleCheckAllChange(val) {
  289. this.checkList = val ? this.allIds : [];
  290. this.isIndeterminate = false;
  291. },
  292. getAllId(data) {
  293. if (!data || !data.length) {
  294. return;
  295. }
  296. data.forEach((ele) => {
  297. if (ele.type == 3 || ele.type == 4) {
  298. this.allType3List.push(ele);
  299. ele.status === 2 && this.allIds.push(ele.periodStatusId);
  300. } else {
  301. if (ele.type == 1 && ele.arr) {
  302. let item = ele.arr[0];
  303. this.allType3List.push(item);
  304. item.status === 2 && this.allIds.push(item.periodStatusId);
  305. }
  306. this.getAllId(
  307. ele.type == 1 ? ele.classPeriods : ele.classPeriodSectionList
  308. );
  309. }
  310. });
  311. },
  312. getChangeStatus(int) {
  313. if (!this.checkList.length) {
  314. this.$message.warning("请勾选需要操作的待审核数据");
  315. return;
  316. }
  317. var data = {
  318. gradeId: Number(this.setData.id),
  319. userId: Number(this.setData.userId),
  320. goodsId: Number(this.setData.goodsId),
  321. };
  322. if (int === 1) {
  323. data.status = 1;
  324. this.through = true;
  325. }
  326. if (int === 2) {
  327. data.status = 0;
  328. this.statusPop = 2;
  329. this.formData.cheating_reason = "";
  330. this.vidBoxHours = true;
  331. }
  332. },
  333. loadingClose() {
  334. this.disabledBtn = false;
  335. },
  336. submitOK(int, msg) {
  337. this.disabledBtn = true;
  338. var data = {
  339. gradeId: Number(this.setData.id),
  340. userId: Number(this.setData.userId),
  341. goodsId: Number(this.setData.goodsId),
  342. ids: this.checkList,
  343. };
  344. if (int === 1) {
  345. data.status = 1;
  346. }
  347. if (int === 2) {
  348. data.auditReason = msg;
  349. data.status = 0;
  350. }
  351. this.$api
  352. .editGradeUsereditPeriodeAll(data)
  353. .then((res) => {
  354. if (int === 1) {
  355. this.$message.success("状态全部通过修改成功");
  356. this.through = false;
  357. this.checkAll && this.goReview();
  358. }
  359. if (int === 2) {
  360. this.$message.success("状态全部作弊修改成功");
  361. this.vidBoxHours = false;
  362. }
  363. this.checkList = [];
  364. this.isIndeterminate = false;
  365. this.checkAll = false;
  366. this.getUserInfo(true);
  367. })
  368. .catch(() => {
  369. this.disabledBtn = false;
  370. });
  371. },
  372. getSecName(id) {
  373. try {
  374. return this.allType3List.find((e) => e.periodStatusId == id).typeName;
  375. } catch (error) {
  376. return "";
  377. }
  378. },
  379. uploadText(msg) {
  380. this.formData.cheating_reason = msg;
  381. },
  382. checkBack() {
  383. if (!this.checkList.length) {
  384. this.$message.warning("请勾选数据");
  385. return;
  386. }
  387. this.popback = true;
  388. },
  389. // 打回审核状态
  390. uploadForm() {
  391. this.disabledBtn = true;
  392. let data = {
  393. gradeId: Number(this.setData.id),
  394. userId: Number(this.setData.userId),
  395. goodsId: Number(this.setData.goodsId),
  396. orderGoodsId: Number(this.setData.orderGoodsId),
  397. ids: this.checkList,
  398. };
  399. this.$api
  400. .editGradeUsereditrollbackPeriod(data)
  401. .then((res) => {
  402. this.checkList = []; //勾选列表
  403. this.isIndeterminate = false; //待审半选
  404. this.checkAll = false; //全选状态
  405. this.getUserInfo(true);
  406. this.$message.success("已打回待审核状态");
  407. this.popback = false;
  408. this.goReview();
  409. })
  410. .catch(() => {
  411. this.disabledBtn = false;
  412. });
  413. },
  414. // 确认审核结果
  415. approvedOKFunc() {
  416. this.disabledBtn = true;
  417. let data = {
  418. gradeId: Number(this.setData.id),
  419. userId: Number(this.setData.userId),
  420. goodsId: Number(this.setData.goodsId),
  421. orderGoodsId: Number(this.setData.orderGoodsId),
  422. };
  423. this.$api
  424. .editGradeUsereditrollconfirmPeriod(data)
  425. .then((res) => {
  426. this.getUserInfo(true);
  427. this.$message.success("审核通过");
  428. this.approvedOK = false;
  429. this.goReview();
  430. })
  431. .catch(() => {
  432. this.disabledBtn = false;
  433. });
  434. },
  435. backToAudit() {
  436. this.$confirm("此操作将打回审核状态, 是否继续?", "提示", {
  437. confirmButtonText: "确定",
  438. cancelButtonText: "取消",
  439. type: "warning",
  440. })
  441. .then(() => {
  442. rollBackPeriod({ orderGoodsId: this.userData.orderGoodsId }).then(
  443. (res) => {
  444. this.getUserInfo(true);
  445. this.$message.success("已打回待审核状态");
  446. }
  447. );
  448. })
  449. .catch(() => {
  450. this.$message({
  451. type: "info",
  452. message: "已取消删除",
  453. });
  454. });
  455. },
  456. goReview() {
  457. this.$router.push({
  458. name: "ListOfhoursToBeReviewed",
  459. });
  460. },
  461. },
  462. created() {
  463. this.keys = {
  464. 1: "ModulTable",
  465. 2: "ChapterTable",
  466. 5: "ChapterTable",
  467. 6: "LessonTable",
  468. };
  469. },
  470. components: { ModulTable, LessonTable, ChapterTable, CheatDialog },
  471. watch: {
  472. tablesData: {
  473. handler() {
  474. this.allIds = [];
  475. for (const key in this.tablesData) {
  476. this.getAllId(this.tablesData[key]);
  477. }
  478. },
  479. immediate: true,
  480. deep: true,
  481. },
  482. userData: {
  483. handler(val) {
  484. this.userImg = val.oneInchPhotos;
  485. },
  486. immediate: true,
  487. deep: true,
  488. },
  489. },
  490. computed: {
  491. periodStatus() {
  492. return this.userData.periodStatus;
  493. },
  494. ...mapGetters(["sidebar"]),
  495. left() {
  496. return this.sidebar.opened ? "206px" : "60px";
  497. },
  498. },
  499. mounted() {
  500. this.$nextTick(function () {
  501. let header = document.getElementsByClassName("studyStyle")[0];
  502. this.offsetTop = header.offsetTop;
  503. this.offsetHeight = header.offsetHeight;
  504. });
  505. window.addEventListener("scroll", debounce(this.handleScroll, 50));
  506. },
  507. };
  508. </script>
  509. <style lang="scss" scoped>
  510. .studyRecordTable {
  511. .studyStyle {
  512. margin: 16px 0;
  513. display: flex;
  514. align-items: center;
  515. & > .a_style {
  516. display: flex;
  517. align-items: center;
  518. margin-right: 16px;
  519. padding: 11px 16px;
  520. box-shadow: 0px 0px 8px 0px rgba(217, 217, 217, 0.8);
  521. border-radius: 4px;
  522. height: 40px;
  523. width: 440px;
  524. user-select: none;
  525. i {
  526. width: 2px;
  527. height: 18px;
  528. display: inline-block;
  529. background-color: #0047d0;
  530. margin-right: 8px;
  531. }
  532. span {
  533. color: #666;
  534. font-weight: bold;
  535. }
  536. .flex_style_study {
  537. flex: 1;
  538. }
  539. .num_style {
  540. float: right;
  541. font-size: 16px;
  542. margin-left: 14px;
  543. }
  544. }
  545. .s_sd {
  546. flex: 1;
  547. justify-content: flex-end;
  548. display: flex;
  549. align-items: center;
  550. flex-shrink: 0;
  551. .dis_colu {
  552. height: 55px;
  553. margin-right: 14px;
  554. display: flex;
  555. flex-direction: column;
  556. justify-content: space-around;
  557. font-size: 14px;
  558. }
  559. }
  560. }
  561. .isFixed {
  562. position: fixed;
  563. top: 84px;
  564. right: 0;
  565. z-index: 10;
  566. background: #fff;
  567. padding: 0 20px;
  568. margin: 0;
  569. }
  570. }
  571. </style>