index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. <!-- <filter-search @reload="reloadSearch" searchKey="ids" /> -->
  2. <template>
  3. <div class="m-container">
  4. <h2>
  5. <div class="squrt"></div>
  6. 学生考勤管理
  7. </h2>
  8. <div class="m-core">
  9. <save-form
  10. :inline="true"
  11. ref="searchForm"
  12. :model="searchForm"
  13. @submit="search"
  14. @reset="onReSet"
  15. >
  16. <el-form-item prop="studentID">
  17. <el-input
  18. v-model.trim="searchForm.studentID"
  19. clearable
  20. @keyup.enter.native="
  21. (e) => {
  22. e.target.blur();
  23. $refs.searchForm.save();
  24. search();
  25. }
  26. "
  27. placeholder="学生编号"
  28. ></el-input>
  29. </el-form-item>
  30. <el-form-item prop="teacherId">
  31. <remote-search
  32. :commit="'setTeachers'"
  33. v-model="searchForm.teacherId"
  34. />
  35. </el-form-item>
  36. <el-form-item prop="organId">
  37. <el-select
  38. class="multiple"
  39. filterable
  40. style="width: 180px !important"
  41. v-model.trim="searchForm.organId"
  42. clearable
  43. placeholder="请选择分部"
  44. >
  45. <el-option
  46. v-for="(item, index) in selects.branchs"
  47. :key="index"
  48. :label="item.name"
  49. :value="item.id"
  50. ></el-option>
  51. </el-select>
  52. </el-form-item>
  53. <el-form-item prop="musicGroupId">
  54. <el-input
  55. v-model.trim="searchForm.musicGroupId"
  56. clearable
  57. @keyup.enter.native="
  58. (e) => {
  59. e.target.blur();
  60. $refs.searchForm.save();
  61. search();
  62. }
  63. "
  64. placeholder="乐团编号"
  65. ></el-input>
  66. </el-form-item>
  67. <el-form-item prop="courseScheduleId">
  68. <el-input
  69. v-model.trim="searchForm.courseScheduleId"
  70. clearable
  71. @keyup.enter.native="
  72. (e) => {
  73. e.target.blur();
  74. $refs.searchForm.save();
  75. search();
  76. }
  77. "
  78. placeholder="课程编号"
  79. ></el-input>
  80. </el-form-item>
  81. <el-form-item prop="groupType">
  82. <el-select
  83. v-model.trim="searchForm.groupType"
  84. placeholder="请选择课程组类型"
  85. >
  86. <el-option
  87. v-for="(item, index) in courseListType"
  88. :key="index"
  89. :value="item.value"
  90. :label="item.label"
  91. ></el-option>
  92. </el-select>
  93. </el-form-item>
  94. <el-form-item prop="courseScheduleType">
  95. <el-select
  96. v-model.trim="searchForm.courseScheduleType"
  97. clearable
  98. placeholder="请选择课程类型"
  99. >
  100. <el-option
  101. v-for="(item, index) in courseType"
  102. :key="index"
  103. :value="item.value"
  104. :label="item.label"
  105. ></el-option>
  106. </el-select>
  107. </el-form-item>
  108. <el-form-item prop="visitFlag">
  109. <el-select
  110. v-model.trim="searchForm.visitFlag"
  111. placeholder="请选择是否回访"
  112. clearable
  113. >
  114. <el-option label="否" value="0"></el-option>
  115. <el-option label="是" value="1"></el-option>
  116. </el-select>
  117. </el-form-item>
  118. <el-form-item prop="status">
  119. <el-select
  120. v-model.trim="searchForm.status"
  121. placeholder="请选择考勤状态"
  122. clearable
  123. >
  124. <el-option
  125. v-for="(item, index) in attendanceStatus"
  126. :key="index"
  127. :value="item.value"
  128. :label="item.label"
  129. ></el-option>
  130. </el-select>
  131. </el-form-item>
  132. <el-form-item prop="dates">
  133. <el-date-picker
  134. v-model="searchForm.dates"
  135. type="daterange"
  136. style="width: 405px"
  137. range-separator="至"
  138. start-placeholder="课程开始日期"
  139. end-placeholder="课程结束日期"
  140. >
  141. </el-date-picker>
  142. </el-form-item>
  143. <el-form-item>
  144. <el-button native-type="submit" type="danger">搜索</el-button>
  145. <el-button native-type="reset" type="primary">重置</el-button>
  146. <!-- <el-button
  147. @click="onExport"
  148. type="primary"
  149. v-permission="'export/queryTeacherAttendances'"
  150. >导出</el-button> -->
  151. </el-form-item>
  152. </save-form>
  153. <div class="tableWrap">
  154. <el-table
  155. style="width: 100%"
  156. :header-cell-style="{ background: '#EDEEF0', color: '#444' }"
  157. :data="tableList"
  158. >
  159. <el-table-column
  160. align="center"
  161. prop="courseSchedule.organization.name"
  162. label="分部"
  163. ></el-table-column>
  164. <el-table-column
  165. align="center"
  166. prop="username"
  167. label="学生姓名"
  168. width="110px"
  169. >
  170. <template slot-scope="scope">
  171. <div>
  172. {{ scope.row.username }}
  173. <p style="color: #f56c6c">
  174. (<copy-text>{{ scope.row.userId }}</copy-text>)
  175. </p>
  176. </div>
  177. </template>
  178. </el-table-column>
  179. <el-table-column
  180. align="center"
  181. prop="courseSchedule.teacherName"
  182. width="120px"
  183. label="老师姓名"
  184. >
  185. <template slot-scope="scope">
  186. {{ scope.row.courseSchedule.teacherName }}
  187. <p style="color: #f56c6c" v-if="scope.row.teacherId">
  188. (<copy-text>{{ scope.row.teacherId }}</copy-text
  189. >)
  190. </p>
  191. </template>
  192. </el-table-column>
  193. <el-table-column align="center" prop="musicGroupId" label="乐团编号">
  194. <template slot-scope="scope">
  195. <div>
  196. <copy-text>{{ scope.row.musicGroupId }}</copy-text>
  197. </div>
  198. </template>
  199. </el-table-column>
  200. <el-table-column
  201. align="center"
  202. prop="courseScheduleId"
  203. label="课程编号"
  204. >
  205. <template slot-scope="scope">
  206. <div>
  207. <copy-text>{{ scope.row.courseScheduleId }}</copy-text>
  208. </div>
  209. </template>
  210. </el-table-column>
  211. <el-table-column
  212. align="center"
  213. prop="courseSchedule.name"
  214. label="课程名称"
  215. ></el-table-column>
  216. <!-- <el-table-column
  217. align="center"
  218. prop="courseSchedule.classDate"
  219. label="上课日期"
  220. >
  221. <template slot-scope="scope">
  222. <div>
  223. </div>
  224. </template>
  225. </el-table-column> -->
  226. <el-table-column
  227. align="center"
  228. prop="startClassTime"
  229. label="课程组类型"
  230. >
  231. <template slot-scope="scope">
  232. <div>
  233. {{ scope.row.groupType | coursesType }}
  234. </div>
  235. </template>
  236. </el-table-column>
  237. <el-table-column
  238. align="center"
  239. prop="startClassTime"
  240. label="课程类型"
  241. >
  242. <template slot-scope="scope">
  243. <div>
  244. {{ scope.row.courseSchedule.type | coursesType }}
  245. </div>
  246. </template>
  247. </el-table-column>
  248. <el-table-column align="center" label="合并类型">
  249. <template slot-scope="scope">
  250. <div>
  251. <!-- {{ scope.row.courseSchedule.newCourseId > 0 ? "是" : "否" }} -->
  252. {{
  253. scope.row.courseSchedule.newCourseId > 0 &&
  254. scope.row.courseSchedule.newCourseId ==
  255. scope.row.courseScheduleId
  256. ? "合并课"
  257. : null
  258. }}
  259. {{
  260. scope.row.courseSchedule.newCourseId > 0 &&
  261. scope.row.courseSchedule.newCourseId !=
  262. scope.row.courseScheduleId
  263. ? "被合并课"
  264. : null
  265. }}
  266. </div>
  267. </template>
  268. </el-table-column>
  269. <el-table-column
  270. width="180px"
  271. align="center"
  272. prop="startClassTime"
  273. label="上课时间"
  274. >
  275. <template slot-scope="scope">
  276. <div>
  277. {{ scope.row.courseSchedule.classDate | dayjsFormat }}
  278. {{
  279. scope.row.courseSchedule.startClassTime | dayjsFormatMinute
  280. }}-{{
  281. scope.row.courseSchedule.endClassTime | dayjsFormatMinute
  282. }}
  283. </div>
  284. </template>
  285. </el-table-column>
  286. <el-table-column align="center" label="签到时间" width="180px">
  287. <template slot-scope="scope">
  288. <div>
  289. {{ scope.row.signInTime }}
  290. </div>
  291. </template>
  292. </el-table-column>
  293. <el-table-column
  294. align="center"
  295. prop="startClassTime"
  296. width="180px"
  297. label="签退时间"
  298. >
  299. <template slot-scope="scope">
  300. <div>
  301. {{ scope.row.signOutTime }}
  302. </div>
  303. </template>
  304. </el-table-column>
  305. <el-table-column align="center" label="考勤回访">
  306. <template slot-scope="scope">
  307. <div>{{ scope.row.visitFlag | yesOrNo }}</div>
  308. </template>
  309. </el-table-column>
  310. <el-table-column align="center" label="考勤状态">
  311. <template slot-scope="scope">
  312. <div
  313. v-if="
  314. scope.row.courseSchedule &&
  315. scope.row.courseSchedule.status != 'NOT_START'
  316. "
  317. >
  318. {{ scope.row.status | clockingIn }}
  319. </div>
  320. </template>
  321. </el-table-column>
  322. <el-table-column
  323. align="center"
  324. fixed="right"
  325. label="操作"
  326. v-if="permission(getFullPermission('visit/add'))"
  327. >
  328. <template slot-scope="scope">
  329. <div>
  330. <el-button
  331. type="text"
  332. v-if="
  333. permission(getFullPermission('visit/add')) &&
  334. !scope.row.visitFlag
  335. "
  336. @click="addVisit(scope.row)"
  337. >新增回访</el-button
  338. >
  339. <el-button
  340. type="text"
  341. @click="lookVisit(scope.row)"
  342. v-if="
  343. scope.row.visitFlag &&
  344. permission(getFullPermission('visit/queryPage'))
  345. "
  346. >查看回访</el-button
  347. >
  348. </div>
  349. </template>
  350. </el-table-column>
  351. </el-table>
  352. <pagination
  353. sync
  354. :total.sync="rules.total"
  355. :page.sync="rules.page"
  356. :limit.sync="rules.limit"
  357. :page-sizes="rules.page_size"
  358. @pagination="getList"
  359. />
  360. <el-dialog title="新增回访" width="500px" :visible.sync="visitVisible">
  361. <visit
  362. v-if="visitVisible && detail"
  363. :detail="detail"
  364. :username="detail.username"
  365. @close="visitVisible = false"
  366. @submited="getList"
  367. :isMainGo="true"
  368. />
  369. </el-dialog>
  370. </div>
  371. </div>
  372. </div>
  373. </template>
  374. <script>
  375. import axios from "axios";
  376. import { getToken } from "@/utils/auth";
  377. import pagination from "@/components/Pagination/index";
  378. import load from "@/utils/loading";
  379. import { getTimes } from "@/utils";
  380. import qs from "qs";
  381. import { permission } from "@/utils/directivePage";
  382. import { findStudentAttendance } from "@/api/buildTeam";
  383. import { Export } from "@/utils/downLoadFile";
  384. import cleanDeep from "clean-deep";
  385. // import { queryTeacherAttendances } from "@/api/recodeManager";
  386. import { courseType, courseListType, stuAttendance } from "@/utils/searchArray";
  387. import visit from "@/views/withdrawal-application/modals/visit";
  388. export default {
  389. components: { pagination, visit },
  390. data() {
  391. return {
  392. visitVisible: false,
  393. detail: null,
  394. searchForm: {
  395. studentID: "",
  396. groupType: "MUSIC",
  397. musicGroupId: "",
  398. courseScheduleId: "",
  399. status: "",
  400. teacherId: "",
  401. courseScheduleType: "",
  402. organId: "",
  403. visitFlag: "",
  404. dates: [],
  405. },
  406. courseType,
  407. courseListType,
  408. attendanceStatus: stuAttendance,
  409. // teacherList: [],
  410. tableList: [],
  411. organList: [],
  412. rules: {
  413. // 分页规则
  414. limit: 10, // 限制显示条数
  415. page: 1, // 当前页
  416. total: 0, // 总条数
  417. page_size: [10, 20, 40, 50], // 选择限制显示条数
  418. },
  419. };
  420. },
  421. //生命周期 - 创建完成(可以访问当前this实例)
  422. created() {
  423. const { query } = this.$route;
  424. if (this.searchForm.dates?.length < 1) {
  425. const start = query.start || new Date();
  426. const end = query.end || new Date();
  427. this.searchForm.dates = [start, end];
  428. }
  429. },
  430. //生命周期 - 挂载完成(可以访问DOM元素)
  431. mounted() {
  432. const { query } = this.$route;
  433. if (query.visitFlag == 1 || query.visitFlag == 0) {
  434. this.searchForm.visitFlag = String(query.visitFlag);
  435. }
  436. if (query.status) {
  437. this.searchForm.status = query.status;
  438. }
  439. this.init();
  440. },
  441. methods: {
  442. permission,
  443. reloadSearch() {
  444. this.rules.page = 1;
  445. this.getList();
  446. },
  447. async init() {
  448. await this.$store.dispatch("setBranchs");
  449. this.getList();
  450. },
  451. addVisit(row) {
  452. this.visitVisible = true;
  453. this.detail = row;
  454. },
  455. // 导出
  456. async onExport() {
  457. const { dates, ...rest } = this.searchForm;
  458. let obj = {
  459. ...rest,
  460. page: this.rules.page,
  461. rows: this.rules.limit,
  462. ids: this.$route.query.ids,
  463. ...getTimes(dates, ["classStartDate", "classEndDate"], "YYYY-MM-DD"),
  464. };
  465. await Export(
  466. this,
  467. {
  468. url: "/api-web/export/exportStudentAttendances",
  469. fileName: "考勤列表.xls",
  470. method: "post",
  471. params: qs.stringify(cleanDeep(obj)),
  472. },
  473. "您确定考勤列表?"
  474. );
  475. },
  476. getList() {
  477. const { dates, ...rest } = this.searchForm;
  478. let obj = {
  479. ...rest,
  480. page: this.rules.page,
  481. rows: this.rules.limit,
  482. ...getTimes(
  483. dates,
  484. ["startDateOfCourse", "endDateOfCourse"],
  485. "YYYY-MM-DD"
  486. ),
  487. };
  488. // let obj = {
  489. // page: this.rules.page,
  490. // rows: this.rules.limit,
  491. // ...this.searchForm,
  492. // ...getTimes(
  493. // this.dates,
  494. // ["startDateOfCourse", "endDateOfCourse"],
  495. // "YYYY-MM-DD"
  496. // ),
  497. // };
  498. findStudentAttendance(obj, {
  499. ids: this.$route.query.ids,
  500. }).then((res) => {
  501. if (res.code == 200) {
  502. this.tableList = res.data.rows;
  503. this.rules.total = res.data.total;
  504. }
  505. });
  506. },
  507. clearSearchUrl() {
  508. const { query } = this.$route;
  509. if (
  510. query.status ||
  511. query.visitFlag == 0 ||
  512. query.visitFlag == 1 ||
  513. query.start ||
  514. query.end
  515. ) {
  516. this.$router.replace({
  517. status: undefined,
  518. visitFlag: undefined,
  519. start: undefined,
  520. end: undefined,
  521. });
  522. }
  523. },
  524. search() {
  525. this.rules.page = 1;
  526. this.clearSearchUrl();
  527. this.getList();
  528. },
  529. onReSet() {
  530. this.$refs["searchForm"].resetFields();
  531. this.clearSearchUrl();
  532. this.search();
  533. },
  534. lookVisit(row) {
  535. this.$router.push({
  536. path: "/studentManager/returnVisitList",
  537. query: { search: row.id },
  538. });
  539. },
  540. },
  541. };
  542. </script>
  543. <style lang='scss' scoped>
  544. </style>