workAttendance-list.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. <template>
  2. <div
  3. v-loading="downloadLoading"
  4. element-loading-text="加载中"
  5. element-loading-spinner="el-icon-loading"
  6. >
  7. <el-breadcrumb separator=">">
  8. <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
  9. <el-breadcrumb-item>
  10. <a href="#">门禁管理</a>
  11. </el-breadcrumb-item>
  12. <el-breadcrumb-item>
  13. <a href="/workAttendance">考勤统计</a>
  14. </el-breadcrumb-item>
  15. </el-breadcrumb>
  16. <el-divider></el-divider>
  17. <!--
  18. 要resetFields起作用,必须配置:model和prop
  19. -->
  20. <el-form
  21. ref="queryForm"
  22. :model="queryModel"
  23. :rules="ruleValidate"
  24. inline
  25. class="demo-form-inline"
  26. >
  27. <div>
  28. <el-row>
  29. <el-form-item label="单位" prop="companyId">
  30. <!-- <el-select
  31. v-model="queryModel.companyId"
  32. size="mini"
  33. filterable
  34. placeholder="请选择"
  35. style="width:220px"
  36. >
  37. <el-option
  38. v-for="company in companyResult"
  39. :key="company.id"
  40. :label="company.name"
  41. :value="company.id"
  42. ></el-option>
  43. </el-select>-->
  44. <el-select-tree
  45. :props="props"
  46. :options="companyResult"
  47. :value="queryModel.companyId"
  48. @getValue="getSelectedValue($event)"
  49. height="200"
  50. ></el-select-tree>
  51. </el-form-item>
  52. <el-form-item label="统计区间" prop="timeRanges">
  53. <el-date-picker
  54. v-model="queryModel.timeRanges"
  55. type="daterange"
  56. range-separator="至"
  57. start-placeholder="开始日期"
  58. end-placeholder="结束日期"
  59. value-format="yyyy-MM-dd"
  60. :default-time="timeRangesDefaultTime"
  61. size="mini"
  62. ></el-date-picker>
  63. </el-form-item>
  64. </el-row>
  65. <el-row>
  66. <el-form-item label="姓名" prop="name">
  67. <el-input type="text" size="mini" v-model="queryModel.name"></el-input>
  68. </el-form-item>
  69. <el-form-item v-if="position1Show" :label="position1" prop="position1">
  70. <el-input type="text" size="mini" v-model="queryModel.position1"></el-input>
  71. </el-form-item>
  72. <el-form-item v-if="position2Show" :label="position2" prop="position2">
  73. <el-input type="text" size="mini" v-model="queryModel.position2"></el-input>
  74. </el-form-item>
  75. <el-form-item v-if="position3Show" :label="position3" prop="position3">
  76. <el-input type="text" size="mini" v-model="queryModel.position3"></el-input>
  77. </el-form-item>
  78. <el-form-item>
  79. <el-button
  80. type="primary"
  81. size="mini"
  82. style="margin-left: 8px"
  83. @click="handleQuery('queryForm')"
  84. >查询</el-button>&nbsp;
  85. <el-button
  86. type="info"
  87. size="mini"
  88. style="margin-left: 8px"
  89. @click="handleReset('queryForm')"
  90. >重置</el-button>
  91. </el-form-item>
  92. </el-row>
  93. </div>
  94. <div>
  95. <el-form-item v-if="position4Show" :label="position4" prop="position4">
  96. <el-input type="text" size="mini" v-model="queryModel.position4"></el-input>
  97. </el-form-item>
  98. <el-form-item v-if="position5Show" :label="position5" prop="position5">
  99. <el-input type="text" size="mini" v-model="queryModel.position5"></el-input>
  100. </el-form-item>
  101. </div>
  102. </el-form>
  103. <el-divider></el-divider>
  104. <el-row class="button-group">
  105. <el-button
  106. type="primary"
  107. size="small"
  108. plain
  109. icon="el-icon-download"
  110. :loading="downloadLoading"
  111. @click="exportXls"
  112. >导出数据</el-button>
  113. </el-row>
  114. <el-table ref="table" stripe :data="tableData" :height="tableHeight" style="width: 100%">
  115. <el-table-column label="序号" fixed="left" type="index" :index="indexMethod"></el-table-column>
  116. <el-table-column label="姓名" fixed="left" prop="name"></el-table-column>
  117. <el-table-column prop="position1" :label="position1" v-if="position1Show"></el-table-column>
  118. <el-table-column prop="position2" :label="position2" v-if="position2Show"></el-table-column>
  119. <el-table-column prop="position3" :label="position3" v-if="position3Show"></el-table-column>
  120. <el-table-column prop="position4" :label="position4" v-if="position4Show"></el-table-column>
  121. <el-table-column prop="position5" :label="position5" v-if="position5Show"></el-table-column>
  122. <el-table-column label="出勤天数" prop="workDays"></el-table-column>
  123. <el-table-column label="休息天数" prop="restDays"></el-table-column>
  124. <el-table-column label="迟到次数" prop="lateNum"></el-table-column>
  125. <el-table-column label="早退次数" prop="leaveNum"></el-table-column>
  126. <el-table-column label="上班缺卡次数" prop="missCardOnWorkCount"></el-table-column>
  127. <el-table-column label="下班缺卡次数" prop="missCardOffWorkCount"></el-table-column>
  128. <el-table-column label="旷工天数" prop="missCardAllDayCount"></el-table-column>
  129. <template v-for="col in dayColumns">
  130. <el-table-column :label="col.label" :prop="col.name" :key="col.name" width="200px">
  131. <template slot-scope="{row}">
  132. <div style="display:flex;flex-direction:column;">
  133. <template v-for="(item,index) in row.workAttendanceMap[col.name]">
  134. <div v-html="showItem(item)" :key="index"></div>
  135. </template>
  136. </div>
  137. </template>
  138. </el-table-column>
  139. </template>
  140. </el-table>
  141. <el-pagination
  142. :current-page.sync="pageIndex"
  143. :total="totalElements"
  144. :page-sizes="pageSizeList"
  145. @current-change="changePage"
  146. @size-change="pageSizeChange"
  147. layout="total, sizes, prev, pager, next, jumper"
  148. ></el-pagination>
  149. </div>
  150. </template>
  151. <script>
  152. import Constant from "@/constant";
  153. import workAttendanceApi from "@/api/business/workAttendance";
  154. import companyPositionApi from "@/api/base/companyPosition";
  155. import companyInfoApi from "@/api/base/companyInfo";
  156. import SelectTree from "@/components/SelectTree";
  157. import NProgress from "nprogress"; // progress bar
  158. import "nprogress/nprogress.css"; // progress bar style
  159. export default {
  160. data() {
  161. var self = this;
  162. return {
  163. ruleValidate: {
  164. companyId: [{ required: true, message: "不能为空", trigger: "blur" }],
  165. timeRanges: [
  166. { required: true, message: "请选择事件范围", trigger: "blur" }
  167. ]
  168. },
  169. queryModel: {
  170. companyId: "",
  171. timeRanges: "",
  172. name: "",
  173. jobNumber: "",
  174. position1: "",
  175. position2: "",
  176. position3: "",
  177. position4: "",
  178. position5: ""
  179. },
  180. loading: false,
  181. tableData: [],
  182. pageIndex: 1,
  183. pageSize: 20,
  184. totalPages: 0,
  185. totalElements: 0,
  186. field: "",
  187. direction: "",
  188. pageSizeList: [20, 30, 50],
  189. multipleSelection: [],
  190. showModal: false,
  191. modalTitle: "",
  192. businessKey: "",
  193. downloadLoading: false,
  194. tableHeight: "",
  195. timeRangesDefaultTime: [],
  196. companyResult: [],
  197. editorOption: {
  198. modules: {
  199. toolbar: "title" // 设置文本编辑器的头部是否展示
  200. },
  201. placeholder: "", // 文本框为空时 , 占位文本
  202. theme: "snow" // 或者为 `bubble`
  203. },
  204. downloadUrl: "",
  205. dayColumns: [],
  206. tmplKey: "",
  207. position1: "",
  208. position2: "",
  209. position3: "",
  210. position4: "",
  211. position5: "",
  212. position1Show: false,
  213. position2Show: false,
  214. position3Show: false,
  215. position4Show: false,
  216. position5Show: false,
  217. treeData: [],
  218. props: {
  219. // 配置项(必选)
  220. value: "id",
  221. label: "name",
  222. children: "children"
  223. }
  224. };
  225. },
  226. created() {
  227. var self = this;
  228. companyInfoApi.list().then(function(response) {
  229. var jsonData = response.data;
  230. if (jsonData.result) {
  231. if (jsonData.data != null && jsonData.data != "") {
  232. self.companyResult = jsonData.data;
  233. }
  234. }
  235. });
  236. companyPositionApi.detailForCompany().then(function(response) {
  237. var jsonData = response.data.data;
  238. if (jsonData.position1Name != null && jsonData.position1Name != "") {
  239. self.position1 = jsonData.position1Name;
  240. self.position1Show = true;
  241. }
  242. if (jsonData.position2Name != null && jsonData.position2Name != "") {
  243. self.position2 = jsonData.position2Name;
  244. self.position2Show = true;
  245. }
  246. if (jsonData.position3Name != null && jsonData.position3Name != "") {
  247. self.position3 = jsonData.position3Name;
  248. self.position3Show = true;
  249. }
  250. if (jsonData.position4Name != null && jsonData.position4Name != "") {
  251. self.position4 = jsonData.position4Name;
  252. self.position4Show = true;
  253. }
  254. if (jsonData.position5Name != null && jsonData.position5Name != "") {
  255. self.position5 = jsonData.position5Name;
  256. self.position5Show = true;
  257. }
  258. });
  259. this.getCurrentMonthFirst();
  260. this.loadTree();
  261. },
  262. methods: {
  263. getSelectedValue(value) {
  264. this.queryModel.companyId = value;
  265. },
  266. loadTree() {
  267. var formData = new FormData();
  268. companyInfoApi.loadChildren(formData).then(resp => {
  269. var jsonData = resp.data;
  270. if (jsonData.result) {
  271. this.treeData = jsonData.data;
  272. } else {
  273. this.$message.error(jsonData.message + "");
  274. }
  275. });
  276. },
  277. loadChildren(tree, treeNode, resolve) {
  278. console.log(tree);
  279. var formData = new FormData();
  280. formData.append("parentId", tree.id);
  281. companyInfoApi.loadChildren(formData).then(resp => {
  282. var jsonData = resp.data;
  283. if (jsonData.result) {
  284. resolve(jsonData.data);
  285. } else {
  286. this.$message.error(jsonData.message + "");
  287. }
  288. });
  289. },
  290. indexMethod(index) {
  291. return (this.pageIndex - 1) * this.pageSize + (index + 1);
  292. },
  293. changePage(pageIndex) {
  294. var self = this;
  295. self.pageIndex = pageIndex;
  296. var formData = new FormData();
  297. formData.append("pageIndex", self.pageIndex);
  298. formData.append("pageSize", self.pageSize);
  299. if (self.queryModel.companyId == null) {
  300. self.queryModel.companyId = "";
  301. }
  302. formData.append("companyId", self.queryModel.companyId);
  303. formData.append("name", self.queryModel.name);
  304. var startDate = "";
  305. var endDate = "";
  306. var timeRanges = self.queryModel.timeRanges + "";
  307. if (timeRanges != "" && timeRanges != null) {
  308. timeRanges = timeRanges.split(",");
  309. startDate = timeRanges[0];
  310. endDate = timeRanges[1];
  311. }
  312. formData.append("startDate", startDate);
  313. formData.append("endDate", endDate);
  314. formData.append("position1", self.queryModel.position1);
  315. formData.append("position2", self.queryModel.position2);
  316. formData.append("position3", self.queryModel.position3);
  317. formData.append("position4", self.queryModel.position4);
  318. formData.append("position5", self.queryModel.position5);
  319. self.downloadLoading = true;
  320. workAttendanceApi.statList(formData).then(function(response) {
  321. var jsonData = response.data;
  322. self.downloadLoading = false;
  323. if (jsonData.result) {
  324. self.tableData = jsonData.data.data;
  325. self.totalPages = jsonData.data.totalPage;
  326. self.totalElements = jsonData.data.totalElements;
  327. self.tableHeight = window.innerHeight - 280;
  328. self.dayColumns = jsonData.data.dayColumns;
  329. self.tmplKey = jsonData.data.tmplKey;
  330. } else {
  331. self.$message({
  332. type: "warning",
  333. message: jsonData.message
  334. });
  335. }
  336. });
  337. },
  338. pageSizeChange(pageSize) {
  339. this.pageSize = pageSize;
  340. this.changePage(1);
  341. },
  342. showItem(item) {
  343. var content = [];
  344. var arr = item.recordTime.split(" ");
  345. if (arr.length > 1) {
  346. content.push(arr[1]);
  347. } else {
  348. content.push(arr[0]);
  349. }
  350. content.push(" ");
  351. if (item.classifier == 1) {
  352. content.push("上班");
  353. } else {
  354. content.push("下班");
  355. }
  356. var fontColor = "";
  357. if (item.result == "0") {
  358. content.push("缺卡");
  359. fontColor = "red";
  360. } else if (item.result == "1") {
  361. content.push("打卡");
  362. fontColor = "green";
  363. } else if (item.result == "2") {
  364. content.push("迟到");
  365. } else if (item.result == "3") {
  366. content.push("早退");
  367. }
  368. return `<font color='${fontColor}'>` + content.join("") + "</font>";
  369. },
  370. handleQuery() {
  371. var self = this;
  372. this.$refs["queryForm"].validate(valid => {
  373. if (valid) {
  374. self.changePage(1);
  375. }
  376. });
  377. },
  378. handleReset(name) {
  379. this.$refs[name].resetFields();
  380. },
  381. exportXls() {
  382. var self = this;
  383. //导出
  384. this.$refs["queryForm"].validate(valid => {
  385. if (valid) {
  386. self.downloadLoading = true;
  387. var formData = new FormData();
  388. if (self.queryModel.companyId == null) {
  389. self.queryModel.companyId = "";
  390. }
  391. formData.append("companyId", self.queryModel.companyId);
  392. formData.append("name", self.queryModel.name);
  393. var startDate = "";
  394. var endDate = "";
  395. var timeRanges = self.queryModel.timeRanges + "";
  396. if (timeRanges != "" && timeRanges != null) {
  397. timeRanges = timeRanges.split(",");
  398. startDate = timeRanges[0];
  399. endDate = timeRanges[1];
  400. }
  401. formData.append("startDate", startDate);
  402. formData.append("endDate", endDate);
  403. formData.append("position1", self.queryModel.position1);
  404. formData.append("position2", self.queryModel.position2);
  405. formData.append("position3", self.queryModel.position3);
  406. formData.append("position4", self.queryModel.position4);
  407. formData.append("position5", self.queryModel.position5);
  408. workAttendanceApi.exportXls(formData).then(function(response) {
  409. var jsonData = response.data;
  410. self.downloadLoading = false;
  411. if (jsonData.result) {
  412. self.$message({
  413. type: "success",
  414. message: `报表已生成,<a href="${jsonData.data}">请点击链接下载</a>`,
  415. dangerouslyUseHTMLString: true,
  416. duration: 30000
  417. });
  418. } else {
  419. self.$message({
  420. type: "warning",
  421. message: jsonData.message
  422. });
  423. }
  424. });
  425. }
  426. });
  427. },
  428. //初始化日期
  429. getCurrentMonthFirst() {
  430. var self = this;
  431. var date = new Date();
  432. date.setDate(1);
  433. var month = parseInt(date.getMonth() + 1);
  434. var startTime = date.getFullYear() + "-" + month + "-" + date.getDate();
  435. var lastDate = new Date();
  436. //设置为第一天
  437. lastDate.setDate(1);
  438. var lastMonth = parseInt(lastDate.getMonth() + 2);
  439. var endTime =
  440. lastDate.getFullYear() + "-" + lastMonth + "-" + lastDate.getDate();
  441. self.queryModel.timeRanges = [startTime, endTime];
  442. }
  443. },
  444. mounted: function() {},
  445. components: {
  446. "el-select-tree": SelectTree
  447. }
  448. };
  449. </script>
  450. <style lang="scss" scoped>
  451. .el-breadcrumb {
  452. margin: 10px;
  453. line-height: 20px;
  454. }
  455. .el-divider {
  456. margin: 5px 0;
  457. }
  458. .demo-form-inline {
  459. margin-left: 10px;
  460. text-align: left;
  461. }
  462. .button-group {
  463. margin-left: 10px;
  464. text-align: left;
  465. }
  466. </style>