teacherRecord.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. <template >
  2. <div>
  3. <!-- 头部展示 -->
  4. <statistic>
  5. <statistic-item>
  6. <span>未上课时</span>
  7. <span>{{ totalClassTimes }}</span>
  8. </statistic-item>
  9. <statistic-item>
  10. <span>已上课时</span>
  11. <span>{{ currentClassTimes }}</span>
  12. </statistic-item>
  13. <statistic-item>
  14. <span>已结算</span>
  15. <span>{{ isSalaryNum }}</span>
  16. </statistic-item>
  17. <statistic-item>
  18. <span>被投诉</span>
  19. <span>{{ complaintsNum }}</span>
  20. </statistic-item>
  21. </statistic>
  22. <!-- 搜索标题 -->
  23. <save-form
  24. save-key='vipDetail-record'
  25. :inline="true"
  26. label-position="right"
  27. label-width="120px"
  28. class="searchForm"
  29. @submit="search"
  30. :model="searchForm"
  31. >
  32. <el-form-item>
  33. <el-select
  34. v-model.trim="searchForm.type"
  35. clearable
  36. placeholder="课程类型"
  37. >
  38. <el-option label="线上课" value="ONLINE"></el-option>
  39. <el-option label="线下课" value="OFFLINE"></el-option>
  40. </el-select>
  41. </el-form-item>
  42. <el-form-item>
  43. <el-select
  44. v-model.trim="searchForm.status"
  45. clearable
  46. placeholder="课程状态"
  47. >
  48. <el-option label="未开始" value="NOT_START"></el-option>
  49. <el-option label="进行中" value="UNDERWAY"></el-option>
  50. <el-option label="已结束" value="OVER"></el-option>
  51. </el-select>
  52. </el-form-item>
  53. <el-form-item>
  54. <el-date-picker
  55. v-model.trim="searchForm.time"
  56. style="width: 400px"
  57. type="daterange"
  58. value-format="yyyy-MM-dd"
  59. range-separator="至"
  60. start-placeholder="课程开始日期"
  61. end-placeholder="课程结束日期"
  62. :picker-options="{
  63. firstDayOfWeek: 1,
  64. }"
  65. >
  66. </el-date-picker>
  67. </el-form-item>
  68. <el-form-item>
  69. <el-button native-type="submit" type="primary">搜索</el-button>
  70. </el-form-item>
  71. </save-form>
  72. <!-- 列表 -->
  73. <div class="tableWrap">
  74. <el-table :data="tableList" :header-cell-style="{background:'#EDEEF0',color:'#444'}">
  75. <el-table-column align="center" label="课程编号" prop="id">
  76. </el-table-column>
  77. <el-table-column
  78. align="center"
  79. label="上课时间"
  80. width="250px"
  81. prop="startClassTime"
  82. >
  83. <template slot-scope="scope">
  84. <!-- {{ scope.row.classDate }} {{ scope.row.startClassTime ? scope.row.startClassTime.substr(0, 5) : '' }}-{{ scope.row.endClassTime ? scope.row.endClassTime.substr(0, 5) : '' }} -->
  85. <div>
  86. <p>
  87. {{ scope.row.startClassTime | dateForMinFormat }}-{{
  88. scope.row.endClassTime | endTime
  89. }}
  90. </p>
  91. </div>
  92. </template>
  93. </el-table-column>
  94. <el-table-column align="center" label="课程类型" prop="teachMode">
  95. <template slot-scope="scope">
  96. <div>
  97. <p>{{ scope.row.teachMode | fitterTeachMode }}</p>
  98. </div>
  99. </template>
  100. </el-table-column>
  101. <el-table-column align="center" label="教学点" prop="schoolName">
  102. <template slot-scope="scope">
  103. <div>
  104. {{ scope.row.schoolName ? scope.row.schoolName : "网络教室" }}
  105. </div>
  106. </template>
  107. </el-table-column>
  108. <el-table-column align="center" label="上课学员数" prop="attendanceNum">
  109. </el-table-column>
  110. <el-table-column align="center" prop="status" label="签到状态">
  111. <template slot-scope="scope">
  112. <div>
  113. <p>{{ scope.row.signInStatus | attendanceType }}</p>
  114. </div>
  115. </template>
  116. </el-table-column>
  117. <el-table-column align="center" prop="status" label="签退状态">
  118. <template slot-scope="scope">
  119. <div>
  120. <p>{{ scope.row.signOutStatus | attendanceOutType }}</p>
  121. </div>
  122. </template>
  123. </el-table-column>
  124. <el-table-column align="center" prop="status" label="课程状态">
  125. <template slot-scope="scope">
  126. <div>
  127. <p>{{ scope.row.status | fitterStatus }}</p>
  128. </div>
  129. </template>
  130. </el-table-column>
  131. <el-table-column align="center" prop="isSalary" label="结算状态">
  132. <template slot-scope="scope">
  133. <div>
  134. <p>{{ scope.row.isSalary | fitterisSalary }}</p>
  135. </div>
  136. </template>
  137. </el-table-column>
  138. <el-table-column align="center" label="操作" width="200">
  139. <template slot-scope="scope">
  140. <div>
  141. <el-button
  142. type="text"
  143. v-if="scope.row.attendanceNum"
  144. permission="'vipGroupManage/findVipGroupAttendanceStudents'"
  145. @click="lookStudents(scope.row)"
  146. >查看学员</el-button
  147. >
  148. <!-- 未结算没有点击功能 -->
  149. <el-button
  150. v-if="
  151. scope.row.status == 'OVER' &&
  152. !scope.row.isSalary &&
  153. permission('teacherAttendance/updateTeacherAttendance')
  154. "
  155. type="text"
  156. @click="onMarkAttendance(scope.row)"
  157. >补考勤</el-button
  158. >
  159. <el-button
  160. v-if="
  161. scope.row.status == 'OVER' &&
  162. permission('studentAttendance/updateStudentAttendances')
  163. "
  164. type="text"
  165. @click="onCallName(scope.row)"
  166. >点名表</el-button
  167. >
  168. <!-- <el-button type="text" v-permission="'vipGroupManage/classStartDateAdjust'"
  169. @click="resetClass(scope.row)">课程调整</el-button> -->
  170. </div>
  171. </template>
  172. </el-table-column>
  173. </el-table>
  174. </div>
  175. <pagination
  176. save-key='vipDetail-record'
  177. sync
  178. :total.sync="rules.total"
  179. :page.sync="rules.page"
  180. :limit.sync="rules.limit"
  181. :page-sizes="rules.page_size"
  182. @pagination="getList"
  183. />
  184. <el-dialog
  185. title="上课学员"
  186. :visible.sync="studentVisible"
  187. width="30%"
  188. :before-close="handleClose"
  189. >
  190. <span
  191. v-for="(item, index) in studentList"
  192. :key="index"
  193. style="margin-left: 10px"
  194. >{{ item }}</span
  195. >
  196. <span slot="footer" class="dialog-footer">
  197. <el-button type="primary" @click="studentVisible = false"
  198. >确 定</el-button
  199. >
  200. </span>
  201. </el-dialog>
  202. <!-- <el-dialog title="课程调整"
  203. :visible.sync="courseVisible"
  204. width="420px">
  205. <el-form :model="maskForm"
  206. :rules="maskrules"
  207. label-width="120px"
  208. label-position="right"
  209. ref='maskForm'>
  210. <el-form-item label="选择上课日期"
  211. prop="date">
  212. <el-date-picker type="date"
  213. value-format="yyyy-MM-dd"
  214. :picker-options="{
  215. firstDayOfWeek:1
  216. }"
  217. v-model.trim="maskForm.date"
  218. placeholder="选择日期"></el-date-picker>
  219. </el-form-item>
  220. <el-form-item label="开始时间"
  221. prop="startTime">
  222. <el-time-picker v-model.trim="maskForm.startTime"
  223. format='HH:mm'
  224. value-format='HH:mm'
  225. :picker-options="{
  226. selectableRange: '04:00:00 - 23:59:00'
  227. }"
  228. placeholder="选择时间">
  229. </el-time-picker>
  230. </el-form-item>
  231. <el-form-item label="结束时间"
  232. prop="endTime">
  233. <el-time-picker v-model.trim="maskForm.endTime"
  234. format='HH:mm'
  235. value-format='HH:mm'
  236. :picker-options="{
  237. selectableRange:`${maskForm.startTime ? maskForm.startTime+':00' : '04:00:00'}-23:59:00`
  238. }"
  239. placeholder="选择时间">
  240. </el-time-picker>
  241. </el-form-item>
  242. <el-form-item label="教学点"
  243. prop="cooperation"
  244. v-if='activeRow&&activeRow.teachMode == "OFFLINE"'>
  245. <el-select v-model.trim="maskForm.cooperation"
  246. clearable
  247. filterable>
  248. <el-option v-for='(item,index) in cooperationList'
  249. :key="index"
  250. :value="item.id"
  251. :label="item.name"></el-option>
  252. </el-select>
  253. </el-form-item>
  254. </el-form>
  255. <span slot="footer"
  256. class="dialog-footer">
  257. <el-button type="primary"
  258. @click="resetCourse">确 定</el-button>
  259. </span>
  260. </el-dialog> -->
  261. <el-dialog
  262. title="补考勤"
  263. width="400px"
  264. :visible.sync="markAttendance.status"
  265. >
  266. <el-form>
  267. <el-form-item label="签到状态"
  268. >{{ markAttendance.dataInfo.signInStatus | attendanceType }}
  269. </el-form-item>
  270. <el-form-item label="签到时间">{{
  271. markAttendance.dataInfo.signInTime
  272. }}</el-form-item>
  273. <el-form-item label="签退状态"
  274. >{{ markAttendance.dataInfo.signOutStatus | attendanceOutType }}
  275. </el-form-item>
  276. <el-form-item label="签退时间">{{
  277. markAttendance.dataInfo.signOutTime
  278. }}</el-form-item>
  279. </el-form>
  280. <div slot="footer" class="dialog-footer">
  281. <el-button @click="markAttendance.status = false">取 消</el-button>
  282. <el-button
  283. type="primary"
  284. :disabled="
  285. markAttendance.dataInfo.signOutStatus == 1 &&
  286. markAttendance.dataInfo.signInStatus == 1
  287. ? true
  288. : false
  289. "
  290. @click="batchAdjustmentTime"
  291. >确定补卡</el-button
  292. >
  293. </div>
  294. </el-dialog>
  295. <el-dialog title="点名表" width="800px" :visible.sync="rollCall.status">
  296. <el-table :data="rollCall.gridData" :header-cell-style="{background:'#EDEEF0',color:'#444'}">
  297. <el-table-column
  298. align="center"
  299. property="userName"
  300. label="学员姓名"
  301. ></el-table-column>
  302. <el-table-column
  303. align="center"
  304. property="phone"
  305. label="手机号"
  306. ></el-table-column>
  307. <el-table-column
  308. align="center"
  309. property="subjectName"
  310. label="学员声部"
  311. ></el-table-column>
  312. <el-table-column align="center" label="到课状态">
  313. <template slot-scope="scope">
  314. {{ scope.row.status | studentCallName }}
  315. </template>
  316. </el-table-column>
  317. <el-table-column
  318. align="center"
  319. v-if="!rollCall.selectItem.isSalary"
  320. label="操作"
  321. width="240px"
  322. >
  323. <template slot-scope="scope">
  324. <el-button
  325. size="small"
  326. @click="onChangeRollCall('TRUANT', scope.row)"
  327. type="primary"
  328. round
  329. >未到</el-button
  330. >
  331. <el-button
  332. size="small"
  333. @click="onChangeRollCall('LEAVE', scope.row)"
  334. type="warning"
  335. round
  336. >请假</el-button
  337. >
  338. <el-button
  339. size="small"
  340. @click="onChangeRollCall('NORMAL', scope.row)"
  341. type="success"
  342. round
  343. >到课</el-button
  344. >
  345. </template>
  346. </el-table-column>
  347. </el-table>
  348. <pagination
  349. :total="rollCall.total"
  350. :page.sync="rollCall.page"
  351. :limit.sync="rollCall.limit"
  352. :page-sizes="rollCall.page_size"
  353. @pagination="getCallName"
  354. />
  355. </el-dialog>
  356. </div>
  357. </template>
  358. <script>
  359. import pagination from "@/components/Pagination/index";
  360. import { getSchool } from "@/api/systemManage";
  361. import {
  362. findVipGroupTeachingRecord,
  363. getStudyStudents,
  364. resetVipClass,
  365. } from "@/api/vipSeting";
  366. import {
  367. findAttendanceStudentByCourseWithPage,
  368. updateStudentAttendances,
  369. updateTeacherAttendance,
  370. } from "@/api/buildTeam";
  371. import { permission } from "@/utils/directivePage";
  372. export default {
  373. components: { pagination },
  374. name: "teacherRecord",
  375. data() {
  376. return {
  377. searchForm: {
  378. type: "",
  379. status: "",
  380. time: [],
  381. },
  382. searchLsit: [],
  383. tableList: [],
  384. id: "",
  385. complaintsNum: "", //投诉数
  386. currentClassTimes: "", //当前课数
  387. isSalaryNum: "", // 已结算
  388. totalClassTimes: "", // 未上课数
  389. studentVisible: false, // 查看上课学员数的弹窗
  390. courseVisible: false, // 课时调整弹窗
  391. studentList: [],
  392. cooperationList: [],
  393. maskForm: {
  394. data: "",
  395. startTime: "",
  396. endTime: "",
  397. status: "",
  398. type: "",
  399. cooperation: "",
  400. },
  401. markAttendance: {
  402. // 考勤状态
  403. status: false,
  404. dataInfo: {},
  405. },
  406. activeId: "",
  407. activeRow: null, //
  408. maskrules: {
  409. date: [{ required: true, message: "请选择修改日期", trigger: "blur" }],
  410. startTime: [{ required: true, message: "请选择开始", trigger: "blur" }],
  411. endTime: [{ required: true, message: "请选择结束", trigger: "blur" }],
  412. },
  413. rules: {
  414. // 分页规则
  415. limit: 10, // 限制显示条数
  416. page: 1, // 当前页
  417. total: 0, // 总条数
  418. page_size: [10, 20, 40, 50], // 选择限制显示条数
  419. },
  420. rollCall: {
  421. // 点名表
  422. status: false,
  423. gridData: [],
  424. selectItem: {}, // 选中状态
  425. limit: 10, // 限制显示条数
  426. page: 1, // 当前页
  427. total: 0, // 总条数
  428. page_size: [10, 20, 40, 50], // 选择限制显示条数
  429. },
  430. };
  431. },
  432. mounted() {
  433. this.__init();
  434. },
  435. activated() {
  436. this.__init();
  437. },
  438. methods: {
  439. __init() {
  440. let id = this.$route.query.id;
  441. this.id = id;
  442. this.rules.page = 1;
  443. // 获取vip教学记录
  444. this.getList();
  445. // 获取分部教学点
  446. getSchool({ organId: null }).then((res) => {
  447. if (res.code == 200) {
  448. this.cooperationList = res.data;
  449. }
  450. });
  451. },
  452. search() {
  453. this.rules.page = 1;
  454. this.getList();
  455. },
  456. getList() {
  457. let startTime;
  458. let endTime;
  459. if (this.searchForm.time) {
  460. startTime = this.searchForm.time[0];
  461. endTime = this.searchForm.time[1];
  462. } else {
  463. startTime = "";
  464. endTime = "";
  465. }
  466. let obj = {
  467. vipGroupId: this.id,
  468. page: this.rules.page,
  469. rows: this.rules.limit,
  470. status: this.searchForm.status || null,
  471. teachMode: this.searchForm.type || null,
  472. startTime,
  473. endTime,
  474. };
  475. findVipGroupTeachingRecord(obj).then((res) => {
  476. if (res.code == 200) {
  477. this.complaintsNum = res.data.baseInfo.complaintsNum;
  478. // 当前课数
  479. this.currentClassTimes = res.data.baseInfo.courseEndNum;
  480. this.isSalaryNum = res.data.baseInfo.isSalaryNum;
  481. // 未上课数
  482. this.totalClassTimes = res.data.baseInfo.courseNoStartNum;
  483. // this.totalClassTimes = res.data.baseInfo.totalClassTimes - this.currentClassTimes;
  484. this.tableList = res.data.pageInfo.rows;
  485. this.rules.total = res.data.pageInfo.total;
  486. }
  487. });
  488. },
  489. batchAdjustmentTime() {
  490. let tempData = this.markAttendance.dataInfo;
  491. let params = {
  492. courseScheduleId: tempData.id,
  493. signInStatus: 1,
  494. signOutStatus: 1,
  495. };
  496. updateTeacherAttendance(params).then((res) => {
  497. if (res.code == 200) {
  498. this.$message.success("补卡成功");
  499. this.markAttendance.status = false;
  500. this.getList();
  501. } else {
  502. this.$message.error(res.msg);
  503. }
  504. });
  505. },
  506. onMarkAttendance(item) {
  507. // 补考勤
  508. this.markAttendance = {
  509. status: true,
  510. dataInfo: item,
  511. };
  512. },
  513. onCallName(item) {
  514. // 点名表
  515. this.rollCall.page = 1;
  516. this.rollCall.selectItem = item;
  517. this.getCallName();
  518. },
  519. getCallName() {
  520. let rollCall = this.rollCall;
  521. let params = {
  522. page: rollCall.page,
  523. rows: rollCall.limit,
  524. courseScheduleId: rollCall.selectItem.id,
  525. };
  526. findAttendanceStudentByCourseWithPage(params).then((res) => {
  527. let result = res.data;
  528. rollCall.status = true;
  529. if (res.code == 200) {
  530. rollCall.gridData = result.rows;
  531. rollCall.total = result.total;
  532. }
  533. });
  534. },
  535. onChangeRollCall(type, row) {
  536. let rollCall = this.rollCall;
  537. let params = {
  538. courseScheduleId: rollCall.selectItem.id,
  539. studentAttendances: [
  540. {
  541. userId: row.studentId,
  542. status: type,
  543. },
  544. ],
  545. };
  546. updateStudentAttendances(params).then((res) => {
  547. if (res.code == 200) {
  548. this.$message.success("修改成功");
  549. row.status = type;
  550. this.getList();
  551. } else {
  552. this.$message.error(res.msg);
  553. }
  554. });
  555. },
  556. lookStudents(row) {
  557. let id = row.id;
  558. getStudyStudents({ courseScheduleId: id }).then((res) => {
  559. if (res.code == 200) {
  560. this.studentList = res.data;
  561. this.studentVisible = true;
  562. }
  563. });
  564. },
  565. permission(str) {
  566. return permission(str);
  567. },
  568. handleClose() {
  569. this.studentList = [];
  570. this.studentVisible = false;
  571. },
  572. resetClass(row) {
  573. this.courseVisible = true;
  574. // 弹出弹窗
  575. this.activeId = row.id;
  576. this.activeRow = row;
  577. // resetVipClass().then()
  578. },
  579. resetCourse() {
  580. // 点击弹窗效验
  581. this.$refs["maskForm"].validate((valid) => {
  582. if (valid) {
  583. // 效验成功
  584. resetVipClass({
  585. id: this.activeId,
  586. classDate: this.maskForm.date,
  587. startClassTime: this.maskForm.date + " " + this.maskForm.startTime,
  588. endClassTime: this.maskForm.date + " " + this.maskForm.endTime,
  589. schoolId: this.maskForm.cooperation,
  590. }).then((res) => {
  591. if (res.code == 200) {
  592. this.$message.success("调整成功");
  593. this.getList();
  594. this.courseVisible = false;
  595. this.$refs["maskForm"].resetFields();
  596. } else {
  597. this.$message.error(res.msg);
  598. }
  599. });
  600. }
  601. });
  602. },
  603. },
  604. filters: {
  605. fitterisSalary(val) {
  606. let arr = ["未结算", "已结算"];
  607. return arr[val];
  608. },
  609. fitterTeachMode(val) {
  610. if (val == "ONLINE") {
  611. return "线上课";
  612. } else if (val == "OFFLINE") {
  613. return "线下课";
  614. }
  615. },
  616. fitterStatus(val) {
  617. if (val == "NOT_START") {
  618. return "未开始";
  619. } else if (val == "UNDERWAY") {
  620. return "进行中";
  621. } else if (val == "OVER") {
  622. return "已结束";
  623. }
  624. },
  625. endTime(val) {
  626. if (val) {
  627. return val.split(" ")[1].substring(0, 5);
  628. } else {
  629. return val;
  630. }
  631. },
  632. studentCallName: (value) => {
  633. let template = {
  634. NORMAL: "到课",
  635. TRUANT: "未到",
  636. LEAVE: "请假",
  637. DROP_OUT: "退学",
  638. "": "未到",
  639. };
  640. return template[value];
  641. },
  642. },
  643. };
  644. </script>
  645. <style lang="scss" scope>
  646. </style>