yanliming 4 年 前
コミット
e8fbe0f8fd

+ 46 - 0
src/api/base/approvalConfig.js

@@ -0,0 +1,46 @@
+import request from '@/utils/request'
+import constant from '@/constant'
+
+function pageList(formData){
+  return request.post(constant.serverUrl + "/base/approvalConfig/pageList", formData);
+}
+
+function create(){
+  return request.get(constant.serverUrl + "/base/approvalConfig/create");
+}
+
+function edit(id){
+  return request.get(constant.serverUrl + "/base/approvalConfig/edit/" + id);
+}
+
+function add(formModel){
+  return request.post(constant.serverUrl + "/base/approvalConfig/add", formModel,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function update(formModel){  
+  return request.post(constant.serverUrl + "/base/approvalConfig/update", formModel,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function remove(id){
+  return request.post(constant.serverUrl + "/base/approvalConfig/delete/" + id);
+}
+
+function batchRemove(idList){
+  return request.post(constant.serverUrl + "/base/approvalConfig/batchDelete",idList,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+export default {
+  pageList,create,edit,add,update,remove,batchRemove
+}

+ 7 - 1
src/api/base/personDeviceRelation.js

@@ -97,9 +97,15 @@ function devicesPersonSync(formData) {
 }
 
 
+function unbindSelectDevice(formData) {
+  //解除选择的设备绑定
+  return request.post(constant.serverUrl + "/personDeviceRelation/unbindSelectDevice", formData);
+}
+
+
 export default {
   create, edit, add, update, remove, batchRemove, pageList,
   isUnbindDeviceList, batchBindDevice, unbindDevice, batchBindPerson, batchUnBindPerson,
   devicePersonList, devicePersonSync, devicePersonsSync, updateIsWrite, updatePersonIsWrite,
-  devicesPersonSync
+  devicesPersonSync,unbindSelectDevice
 }

+ 63 - 0
src/api/base/personHealthLedger.js

@@ -0,0 +1,63 @@
+import request from '@/utils/request'
+import constant from '@/constant'
+
+function pageList(formData) {
+  return request.post(constant.serverUrl + "/base/personHealthLedger/pageList", formData);
+}
+
+function create() {
+  return request.get(constant.serverUrl + "/base/personHealthLedger/create");
+}
+
+function edit(id) {
+  return request.get(constant.serverUrl + "/base/personHealthLedger/edit/" + id);
+}
+
+function add(formModel) {
+  return request.post(constant.serverUrl + "/base/personHealthLedger/add", formModel, {
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function update(formModel) {
+  return request.post(constant.serverUrl + "/base/personHealthLedger/update", formModel, {
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function remove(id) {
+  return request.post(constant.serverUrl + "/base/personHealthLedger/delete/" + id);
+}
+
+function batchRemove(idList) {
+  return request.post(constant.serverUrl + "/base/personHealthLedger/batchDelete", idList, {
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function exportXls(formData) {
+  return request.post(constant.serverUrl + "/base/personHealthLedger/exportXls", formData);
+}
+
+function pageListAll(formData) {
+  //包含测温和健康上报
+  return request.post(constant.serverUrl + "/base/personHealthLedger/pageListAll", formData);
+}
+
+function exportXlsAll(formData) {
+  return request.post(constant.serverUrl + "/base/personHealthLedger/exportXlsAll", formData);
+}
+
+function gpsHistoryList(formData) {
+  return request.post(constant.serverUrl + "/base/personHealthLedger/gpsHistoryList", formData);
+}
+
+export default {
+  pageList, create, edit, add, update, remove, batchRemove, exportXls, pageListAll,exportXlsAll,gpsHistoryList
+}

+ 46 - 0
src/api/base/workOver.js

@@ -0,0 +1,46 @@
+import request from '@/utils/request'
+import constant from '@/constant'
+
+function pageList(formData){
+  return request.post(constant.serverUrl + "/base/workOver/pageList", formData);
+}
+
+function create(){
+  return request.get(constant.serverUrl + "/base/workOver/create");
+}
+
+function edit(id){
+  return request.get(constant.serverUrl + "/base/workOver/edit/" + id);
+}
+
+function add(formModel){
+  return request.post(constant.serverUrl + "/base/workOver/add", formModel,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function update(formModel){  
+  return request.post(constant.serverUrl + "/base/workOver/update", formModel,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function remove(id){
+  return request.post(constant.serverUrl + "/base/workOver/delete/" + id);
+}
+
+function batchRemove(idList){
+  return request.post(constant.serverUrl + "/base/workOver/batchDelete",idList,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+export default {
+  pageList,create,edit,add,update,remove,batchRemove
+}

+ 54 - 0
src/api/base/workSchedule.js

@@ -0,0 +1,54 @@
+import request from '@/utils/request'
+import constant from '@/constant'
+
+function pageList(formData){
+  return request.post(constant.serverUrl + "/base/workSchedule/pageList", formData);
+}
+
+function create(){
+  return request.get(constant.serverUrl + "/base/workSchedule/create");
+}
+
+function edit(id){
+  return request.get(constant.serverUrl + "/base/workSchedule/edit/" + id);
+}
+
+function add(formModel){
+  return request.post(constant.serverUrl + "/base/workSchedule/add", formModel,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function update(formModel){  
+  return request.post(constant.serverUrl + "/base/workSchedule/update", formModel,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function updateCompany(formModel){  
+  return request.post(constant.serverUrl + "/base/workSchedule/updateCompany", formModel,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+function remove(id){
+  return request.post(constant.serverUrl + "/base/workSchedule/delete/" + id);
+}
+
+function batchRemove(idList){
+  return request.post(constant.serverUrl + "/base/workSchedule/batchDelete",idList,{
+    headers: {
+      "Content-Type": "application/json"
+    }
+  });
+}
+
+export default {
+  pageList,create,edit,add,update,remove,batchRemove,updateCompany
+}

+ 18 - 0
src/api/business/workScheduleReport.js

@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+import constant from '@/constant'
+
+function statList(formData){
+  return request.post(constant.serverUrl + "/business/workScheduleReport/statList", formData);
+}
+
+function exportXls(formData){
+  return request.post(constant.serverUrl + "/business/workScheduleReport/exportXls", formData);
+}
+
+function batchUpdate(formData){
+  return request.post(constant.serverUrl + "/business/workScheduleReport/batchUpdate", formData);
+}
+
+export default {
+  statList,exportXls,batchUpdate
+}

+ 40 - 0
src/routers/modules/base.js

@@ -578,6 +578,46 @@ var routers = [
                         title: '返乡人员管理'
                 }
         }, 
+        {
+                path: '/base/approvalConfig/list',
+                name: 'baseApprovalConfigList',
+                component: () => import('@/views/base/approvalConfig-list.vue'),
+                meta: {
+                        roles: ["admin"],
+                        title: '审核层级管理'
+                }
+        },  
+        {
+                path: '/base/workOver/list',
+                name: 'baseWorkOverList',
+                component: () => import('@/views/base/workOver-list.vue'),
+                meta: {
+                        roles: ["admin"],
+                        title: '加班申请记录'
+                }
+        }, 
+        {
+                path: '/base/workSchedule/list',
+                name: 'baseWorkScheduleList',
+                component: () => import('@/views/base/workSchedule-list.vue'),
+                meta: {
+                        roles: ["admin"],
+                        title: '班次考勤设置'
+                }
+        },
+        {
+                //学生每日健康情况-包含健康打卡和上报
+                path: '/base/personHealthLedger/list',
+                name: 'basePersonHealthLedgerList',
+                // route level code-splitting
+                // this generates a separate chunk (about.[hash].js) for this route
+                // which is lazy-loaded when the route is visited.
+                component: () => import('@/views/base/personHealthLedger-list.vue'),
+                meta: {
+                        roles: ["admin"],
+                        title: '健康打卡情况'
+                }
+        },
 ]
 
 export default routers;

+ 13 - 0
src/routers/modules/business.js

@@ -77,6 +77,19 @@ var routers = [
                         title: '租户账单管理'
                 }
         },
+        {
+                //班次考勤表
+                path: '/business/workScheduleReport/list',
+                name: 'BusinessWorkScheduleReport',
+                // route level code-splitting
+                // this generates a separate chunk (about.[hash].js) for this route
+                // which is lazy-loaded when the route is visited.
+                component: () => import('@/views/business/workScheduleReport.vue'),
+                meta: {
+                        roles: ["admin"],
+                        title: '班次考勤表'
+                }
+        },
 ]
 
 export default routers;

+ 29 - 13
src/views/base/alarmConfig-detail.vue

@@ -29,7 +29,8 @@
             :props="props"
             :options="companyResult"
             v-model="formModel.companyId"
-            height="200"
+            width="300px"
+            size="mediumn"
           ></el-select-tree>
         </el-form-item>
         <el-form-item label="是否包含下级单位" prop="subordinate">
@@ -66,7 +67,7 @@
                 }"
           ></el-time-picker>
         </el-form-item>
-        <el-form-item label="考勤时间" prop="endTime">
+        <el-form-item label="考勤时间" prop="attendanceTime">
           <el-time-picker
             v-model="formModel.attendanceTime"
             class="date-box"
@@ -93,10 +94,14 @@
           <el-radio v-model="formModel.classifier" :label="1">上班时间</el-radio>
           <el-radio v-model="formModel.classifier" :label="2">下班时间</el-radio>
         </el-form-item>
-        <el-form-item label="要求测温" prop="needMeasureTemperature">
+        <el-form-item label="需要提醒" prop="needMeasureTemperature">
           <el-radio v-model="formModel.needMeasureTemperature" :label="true">是</el-radio>
           <el-radio v-model="formModel.needMeasureTemperature" :label="false">否</el-radio>
         </el-form-item>
+        <el-form-item label="实时统计" prop="realTimeStat">
+          <el-radio v-model="formModel.realTimeStat" :label="true">是</el-radio>
+          <el-radio v-model="formModel.realTimeStat" :label="false">否</el-radio>
+        </el-form-item>
       </el-form>
     </div>
     <span slot="footer" class="dialog-footer">
@@ -117,7 +122,15 @@ export default {
   data() {
     return {
       ruleValidate: {
-        companyId: [{ required: true, message: "不能为空", trigger: "blur" }]
+        companyId: [{ required: true, message: "不能为空", trigger: "blur" }],
+        weekdays: [{ required: true, message: "不能为空", trigger: "blur" }],
+        startTime: [{ required: true, message: "不能为空", trigger: "blur" }],
+        attendanceTime: [{ required: true, message: "不能为空", trigger: "blur" }],
+        endTime: [{ required: true, message: "不能为空", trigger: "blur" }],
+        classifier: [{ required: true, message: "不能为空", trigger: "blur" }],
+        attendanceType: [{ required: true, message: "不能为空", trigger: "blur" }],
+        needMeasureTemperature: [{ required: true, message: "不能为空", trigger: "blur" }],
+        realTimeStat: [{ required: true, message: "不能为空", trigger: "blur" }]
       },
       showDialog: true,
       loading: false,
@@ -210,23 +223,26 @@ export default {
         if (valid) {
           (function() {
             var id = self.formModel.id;
-            self.loading = true;
-            if (self.formModel.weekdays != null) {
-                var weekdays = self.formModel.weekdays.join(",");
-                self.formModel.weekdays = weekdays;
+            self.submitting = true;
+
+            var requestModel = JSON.parse(JSON.stringify(self.formModel));
+
+            if (requestModel.weekdays != null) {
+              var weekdays = requestModel.weekdays.join(",");
+              requestModel.weekdays = weekdays;
             }
 
-            if (self.formModel.companyId == null) {
-              self.formModel.companyId = "";
+            if (requestModel.companyId == null) {
+              requestModel.companyId = "";
             }
 
             if (id == null || id.length == 0) {
-              return alarmConfigApi.add(self.formModel);
+              return alarmConfigApi.add(requestModel);
             } else {
-              return alarmConfigApi.update(self.formModel);
+              return alarmConfigApi.update(requestModel);
             }
           })().then(function(response) {
-            self.loading = false;
+            self.submitting = false;
 
             var jsonData = response.data;
 

+ 8 - 8
src/views/base/alarmConfig-list.vue

@@ -117,6 +117,12 @@
         show-overflow-tooltip
         width="150"
       ></el-table-column>
+      <el-table-column prop="classifier" label="考勤分类" width="120">
+        <template slot-scope="{ row }">
+          <span v-html="row.classifier == 1 ? '上班时间' : ''"></span>
+          <span v-html="row.classifier == 2 ? '下班时间' : ''"></span>
+        </template>
+      </el-table-column>
       <el-table-column
         prop="startTime"
         label="开始时间"
@@ -138,15 +144,9 @@
           <span v-html="row.attendanceType == 2 ? '外勤' : ''"></span>
         </template>
       </el-table-column>
-      <el-table-column prop="classifier" label="考勤分类" width="120">
-        <template slot-scope="{ row }">
-          <span v-html="row.classifier == 1 ? '上班时间' : ''"></span>
-          <span v-html="row.classifier == 2 ? '下班时间' : ''"></span>
-        </template>
-      </el-table-column>
       <el-table-column
         prop="needMeasureTemperature"
-        label="是否要求测温"
+        label="是否需要提醒"
         width="120"
       >
         <template slot-scope="{ row }">
@@ -190,7 +190,7 @@
       <el-form label-width="150px">
         <el-form-item label="模板下载">
           <el-link
-            href="http://rccs.oss-cn-hangzhou.aliyuncs.com/smart/personInfo/2020/10/%E8%80%83%E5%8B%A4%E6%97%B6%E9%97%B4%E8%AE%BE%E7%BD%AE%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xls"
+            href="http://rccs.oss-cn-hangzhou.aliyuncs.com/smart/alarmConfig/2020/12/%E8%80%83%E5%8B%A4%E6%97%B6%E9%97%B4%E8%AE%BE%E7%BD%AE%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xls"
             type="primary"
             target="_blank"
             >点击下载模板</el-link

+ 224 - 0
src/views/base/approvalConfig-detail.vue

@@ -0,0 +1,224 @@
+
+<style scoped>
+.user-panel {
+  margin: 10px auto;
+}
+</style>
+<template>
+  <el-dialog
+    :visible.sync="showDialog"
+    :title="title"
+    :modal-append-to-body="false"
+    style="text-align: left"
+    @close="closeDialog"
+    :close-on-click-modal="false"
+  >
+    <div class="user-panel" v-loading="loading">
+      <el-form
+        ref="form"
+        :model="formModel"
+        :rules="ruleValidate"
+        :label-width="'150px'"
+      >
+        <el-form-item label="公司" prop="companyId">
+          <el-select-tree
+          :props="props"
+          :options="companyResult"
+          v-model="formModel.companyId"
+          size=""
+          height="200"
+        ></el-select-tree>
+        </el-form-item>
+        <el-form-item
+          label="类型"
+          prop="type"
+        >
+          <el-select
+          v-model="formModel.type"
+          filterable
+          placeholder="请选择"
+          style="width: 200px"
+        >
+          <el-option
+            v-for="type in typeResult"
+            :key="type.value"
+            :label="type.name"
+            :value="type.value"
+          ></el-option>
+        </el-select>
+        </el-form-item>
+        <el-form-item label="审批层级" prop="level">
+          <el-input-number
+            v-model="formModel.level"
+            placeholder="请输入审批需要的层级"
+            style="width: 200px"
+            :min="0" :max="99"
+          ></el-input-number>
+        </el-form-item>
+        <el-form-item label="申请对应天数" prop="days">
+          <el-input-number
+            v-model="formModel.days"
+            placeholder="请输入申请时对应的天数"
+            style="width: 200px"
+            :min="0" :max="99"
+          ></el-input-number>
+        </el-form-item>
+        <el-form-item label="备注信息" prop="remark">
+          <el-input
+            v-model="formModel.remark"
+            placeholder="请输入备注信息"
+            style="width: 400px"
+          ></el-input>
+        </el-form-item>
+      </el-form>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="closeDialog">取 消</el-button>
+      <el-button type="primary" @click="handleSubmit" :loading="submitting"
+        >确 定</el-button
+      >
+    </span>
+  </el-dialog>
+</template>
+<script>
+import Constant from "@/constant";
+import approvalConfigApi from "@/api/base/approvalConfig";
+import companyInfoApi from "@/api/base/companyInfo";
+import dataDictionaryApi from "@/api/sys/dataDictionary";
+import SelectTree from "@/components/SelectTree";
+
+export default {
+  props: ["businessKey", "title"],
+  components: {
+    "el-select-tree": SelectTree
+  },
+  data() {
+    return {
+      formModel: {},
+      ruleValidate: {
+        companyId: [
+          { required: true, message: "请选择单位", trigger: "blur" },
+        ],
+        type: [
+          {
+            required: true,
+            message:
+              "请选择类型",
+            trigger: "blur",
+          },
+        ],
+        level: [
+          {
+            required: true,
+            message: "审批需要的层级不能为空",
+            trigger: "blur",
+          },
+        ],
+        days: [
+          {
+            required: true,
+            message: "申请时对应的天数不能为空",
+            trigger: "blur",
+          },
+        ],
+      },
+      showDialog: true,
+      loading: false,
+      submitting: false,
+      companyResult: [],
+      treeData: [],
+      props: {
+        // 配置项(必选)
+        value: "id",
+        label: "name",
+        children: "children",
+      },
+      typeResult: [],
+    };
+  },
+  created() {
+    var self = this;
+    companyInfoApi.list().then(function (response) {
+      var jsonData = response.data;
+      if (jsonData.result) {
+        if (jsonData.data != null && jsonData.data != "") {
+          self.companyResult = jsonData.data;
+        }
+      }
+    });
+
+    dataDictionaryApi
+      .findByCatalogName({
+        catalogName: "审批层级类型",
+      })
+      .then((response) => {
+        var jsonData = response.data;
+        this.typeResult = jsonData.data;
+      });
+  },
+  methods: {
+    closeDialog() {
+      this.$emit("close", false);
+    },
+    handleSubmit() {
+      var self = this;
+
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          (function () {
+            var id = self.formModel.id;
+
+            if (id == null || id.length == 0) {
+              return approvalConfigApi.add(self.formModel);
+            } else {
+              return approvalConfigApi.update(self.formModel);
+            }
+          })().then(function (response) {
+            var jsonData = response.data;
+
+            if (jsonData.result) {
+              self.$message({
+                message: "保存成功!",
+                type: "success",
+              });
+
+              self.$emit("close", true);
+            } else {
+              self.$message({
+                message: jsonData.message + "",
+                type: "warning",
+              });
+
+              self.$emit("close", false);
+            }
+          });
+        }
+      });
+    },
+  },
+  mounted: function () {
+    var self = this;
+
+    (function () {
+      if (self.businessKey.length == 0) {
+        return approvalConfigApi.create();
+      } else {
+        return approvalConfigApi.edit(self.businessKey);
+      }
+    })()
+      .then((response) => {
+        var jsonData = response.data;
+        self.loading = false;
+
+        if (jsonData.result) {
+          self.formModel = jsonData.data;
+        } else {
+          self.$message.error(jsonData.message + "");
+        }
+      })
+      .catch((error) => {
+        self.$message.error(error + "");
+      });
+  },
+};
+</script>

+ 373 - 0
src/views/base/approvalConfig-list.vue

@@ -0,0 +1,373 @@
+<template>
+  <div>
+    <el-breadcrumb separator=">">
+      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="#">系统管理</a>
+      </el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="/approvalConfig">审批层级管理</a>
+      </el-breadcrumb-item>
+    </el-breadcrumb>
+    <el-divider></el-divider>
+    <!--
+      要resetFields起作用,必须配置:model和prop
+    -->
+    <el-form
+      ref="queryForm"
+      :model="queryModel"
+      inline
+      class="demo-form-inline"
+    >
+      <el-form-item label="单位" prop="companyId">
+        <el-select-tree
+          :props="props"
+          :options="companyResult"
+          v-model="queryModel.companyId"
+          height="200"
+          size="mini"
+        ></el-select-tree>
+        &nbsp;
+        <el-checkbox v-model="queryModel.subordinate"
+          >是否包含下级单位</el-checkbox
+        >
+      </el-form-item>
+      <el-form-item label="类型" prop="type">
+        <el-select
+          v-model="queryModel.type"
+          filterable
+          size="mini"
+          placeholder="请选择"
+          style="width: 180px"
+        >
+          <el-option
+            v-for="type in typeResult"
+            :key="type.value"
+            :label="type.name"
+            :value="type.value"
+          ></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="primary"
+          size="mini"
+          icon="ios-search"
+          @click="changePage(1)"
+          :loading="loading"
+          >查询</el-button
+        >&nbsp;
+        <el-button
+          type="info"
+          size="mini"
+          style="margin-left: 8px"
+          @click="handleReset('queryForm')"
+          >重置</el-button
+        >&nbsp;
+      </el-form-item>
+    </el-form>
+    <el-divider></el-divider>
+    <el-row class="button-group">
+      <el-button
+        type="primary"
+        size="small"
+        plain
+        icon="el-icon-circle-plus"
+        @click="handleAdd"
+        >新增</el-button
+      >
+      <el-button
+        type="primary"
+        size="small"
+        plain
+        icon="el-icon-circle-plus"
+        :disabled="multipleSelection.length == 0"
+        @click="handleBatchDelete"
+        >删除选中项</el-button
+      >
+    </el-row>
+    <el-table
+      :data="tableData"
+      style="min-height: 400px"
+      v-loading="loading"
+      stripe
+      @sort-change="sortChange"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55"></el-table-column>
+      <el-table-column label="序号" fixed="left" type="index" :index="indexMethod"></el-table-column>
+      <el-table-column
+        prop="companyName"
+        label="公司"
+        width="220"
+      ></el-table-column>
+      <el-table-column prop="typeN" label="类型" width="150"></el-table-column>
+      <el-table-column
+        prop="level"
+        label="审批需要的层级"
+        width="150"
+      ></el-table-column>
+      <el-table-column
+        prop="days"
+        label="申请时对应的天数"
+        width="150"
+      ></el-table-column>
+      <el-table-column
+        prop="remark"
+        label="备注信息"
+        show-overflow-tooltip
+        width="180"
+      ></el-table-column>
+      <el-table-column label="操作">
+        <template slot-scope="{ row }">
+          <el-button size="mini" type="warning" @click="handleEdit(row)"
+            >编辑</el-button
+          >
+          <el-button size="mini" type="danger" @click="handleDelete(row)"
+            >删除</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      :current-page.sync="pageIndex"
+      :total="totalElements"
+      :page-sizes="pageSizeList"
+      @current-change="changePage"
+      @size-change="pageSizeChange"
+      layout="total, sizes, prev, pager, next, jumper"
+    ></el-pagination>
+    <approvalConfig-detail
+      v-if="showModal"
+      :businessKey="businessKey"
+      :title="modalTitle"
+      @close="onDetailModalClose"
+    ></approvalConfig-detail>
+  </div>
+</template>
+<script>
+import Constant from "@/constant";
+import ApprovalConfigDetail from "./approvalConfig-detail";
+import approvalConfigApi from "@/api/base/approvalConfig";
+import companyInfoApi from "@/api/base/companyInfo";
+import dataDictionaryApi from "@/api/sys/dataDictionary";
+import SelectTree from "@/components/SelectTree";
+import NProgress from "nprogress"; // progress bar
+import "nprogress/nprogress.css"; // progress bar style
+
+export default {
+  name: "baseApprovalConfigList",
+  data() {
+    var self = this;
+    return {
+      queryModel: {
+        companyId: "",
+        type: "",
+        subordinate:false,
+      },
+      loading: false,
+      tableData: [],
+      pageIndex: 1,
+      pageSize: 10,
+      totalPages: 0,
+      totalElements: 0,
+      field: "",
+      direction: "",
+      pageSizeList: [10, 20, 30],
+      multipleSelection: [],
+      showModal: false,
+      modalTitle: "",
+      businessKey: "",
+      companyResult: [],
+      treeData: [],
+      props: {
+        // 配置项(必选)
+        value: "id",
+        label: "name",
+        children: "children",
+      },
+      typeResult: [],
+    };
+  },
+  created() {
+    var self = this;
+    companyInfoApi.list().then(function (response) {
+      var jsonData = response.data;
+      if (jsonData.result) {
+        if (jsonData.data != null && jsonData.data != "") {
+          self.companyResult = jsonData.data;
+        }
+      }
+    });
+
+    dataDictionaryApi
+      .findByCatalogName({
+        catalogName: "审批层级类型",
+      })
+      .then((response) => {
+        var jsonData = response.data;
+        this.typeResult = jsonData.data;
+      });
+  },
+  methods: {
+    indexMethod(index) {
+      return (this.pageIndex - 1) * this.pageSize + (index + 1);
+    },
+    changePage(pageIndex) {
+      var self = this;
+
+      self.loading = true;
+
+      self.pageIndex = pageIndex;
+      var formData = new FormData();
+
+      formData.append("pageIndex", self.pageIndex);
+      formData.append("pageSize", self.pageSize);
+
+      formData.append("companyId", self.queryModel.companyId);
+      formData.append("type", self.queryModel.type);
+      formData.append("subordinate", self.queryModel.subordinate);
+
+      if (this.field != null) {
+        formData.append("field", this.field);
+      }
+
+      if (this.direction != null) {
+        formData.append("direction", this.direction);
+      }
+
+      approvalConfigApi
+        .pageList(formData)
+        .then(function (response) {
+          self.loading = false;
+
+          var jsonData = response.data.data;
+
+          self.tableData = jsonData.data;
+          self.totalPages = jsonData.totalPages;
+          self.totalElements = jsonData.recordsTotal;
+        })
+        .catch((error) => {
+          self.loading = false;
+          // self.$message.error(error + "");
+        });
+    },
+    pageSizeChange(pageSize) {
+      this.pageSize = pageSize;
+
+      this.$nextTick(() => {
+        this.changePage(this.pageIndex);
+      });
+    },
+    sortChange(data) {
+      this.field = data.column.field;
+      this.direction = data.order;
+
+      this.changePage(this.pageIndex);
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+    handleReset(name) {
+      this.$refs[name].resetFields();
+    },
+    handleAdd() {
+      this.modalTitle = "新增";
+      this.businessKey = "";
+      this.showModal = true;
+    },
+    handleEdit(record) {
+      this.modalTitle = "编辑";
+      this.businessKey = record.id;
+      this.showModal = true;
+    },
+    handleDelete(record) {
+      var self = this;
+
+      self
+        .$confirm("是否确认删除?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        })
+        .then(() => {
+          approvalConfigApi.remove(record.id).then(function (response) {
+            var jsonData = response.data;
+
+            if (jsonData.result) {
+              // var index = self.tableData.indexOf(record);
+              // self.tableData.splice(index, 1);
+              self.changePage(self.pageIndex);
+
+              self.$message({
+                type: "success",
+                message: "删除成功!",
+              });
+            }
+          });
+        });
+    },
+    handleBatchDelete() {
+      var self = this;
+
+      var idList = this.multipleSelection.map((record) => {
+        return record.id;
+      });
+
+      this.$confirm("是否确认删除选中项?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      }).then(() => {
+        approvalConfigApi.batchRemove(idList).then(function (response) {
+          var jsonData = response.data;
+
+          if (jsonData.result) {
+            self.changePage(self.pageIndex);
+
+            self.$message({
+              type: "success",
+              message: "删除成功!",
+            });
+          }
+        });
+      });
+    },
+    onDetailModalClose(refreshed) {
+      //保存成功后回调
+      this.showModal = false;
+
+      if (refreshed) {
+        this.changePage(this.pageIndex);
+      }
+    },
+  },
+  mounted: function () {
+    this.changePage(1);
+  },
+  components: {
+    "approvalConfig-detail": ApprovalConfigDetail,
+    "el-select-tree": SelectTree
+  },
+};
+</script>
+<style lang="scss" scoped>
+.el-breadcrumb {
+  margin: 10px;
+  line-height: 20px;
+}
+
+.el-divider {
+  margin: 5px 0;
+}
+
+.demo-form-inline {
+  margin-left: 10px;
+  text-align: left;
+}
+
+.button-group {
+  margin-left: 10px;
+  text-align: left;
+}
+</style>

+ 2 - 2
src/views/base/companyInfo-detail.vue

@@ -54,9 +54,9 @@
             </el-form-item>
           </el-col>
           <el-col :span="12">
-            <el-form-item label="全称" prop="shortName">
+            <el-form-item label="全称" prop="fullName">
               <el-input
-                v-model="formModel.shortName"
+                v-model="formModel.fullName"
                 placeholder="请输入单位全称"
                 style="width: 400px"
               ></el-input>

+ 1 - 1
src/views/base/companyInfo-list.vue

@@ -146,7 +146,7 @@
         width="200"
       ></el-table-column>
       <el-table-column
-        prop="shortName"
+        prop="fullName"
         label="全称"
         width="120"
       ></el-table-column>

+ 27 - 14
src/views/base/deviceInfo-detail.vue

@@ -325,22 +325,27 @@ export default {
 
             self.loading = true;
 
-            if (self.formModel.companyId == null) {
-              self.formModel.companyId = "";
-            }
+            // if (self.formModel.companyId == null) {
+            //   self.formModel.companyId = "";
+            // }
 
-            if(self.formModel.remoteOpenRangeTime!=null&&self.formModel.remoteOpenRangeTime!=""){
-              var remoteOpenRangeTime = self.formModel.remoteOpenRangeTime.toString();
-              self.formModel.remoteOpenRangeTime = remoteOpenRangeTime;
-            }
-            else{
-              self.formModel.remoteOpenRangeTime = "";
+            // if(self.formModel.remoteOpenRangeTime!=null&&self.formModel.remoteOpenRangeTime!=""){
+            //   var remoteOpenRangeTime = self.formModel.remoteOpenRangeTime.toString();
+            //   self.formModel.remoteOpenRangeTime = remoteOpenRangeTime;
+            // }
+            // else{
+            //   self.formModel.remoteOpenRangeTime = "";
+            // }
+            var requestModel = JSON.parse(JSON.stringify(self.formModel));
+
+            if(self.formModel.remoteOpenRangeTime!=null){
+              requestModel.remoteOpenRangeTime = self.formModel.remoteOpenRangeTime.join(",");
             }
 
             if (id == null || id.length == 0) {
-              return deviceInfoApi.add(self.formModel);
+              return deviceInfoApi.add(requestModel);
             } else {
-              return deviceInfoApi.update(self.formModel);
+              return deviceInfoApi.update(requestModel);
             }
           })().then(function(response) {
             self.loading = false;
@@ -407,10 +412,18 @@ export default {
           self.formModel = jsonData.data;
 
           var rangeTime = [];
-          rangeTime.push(self.formModel.remoteOpenStartTime);
-          rangeTime.push(self.formModel.remoteOpenEndTime);
 
-          self.formModel.remoteOpenRangeTime = rangeTime;
+          if(self.formModel.remoteOpenStartTime!=null){
+            rangeTime.push(self.formModel.remoteOpenStartTime);
+          }
+          
+          if(self.formModel.remoteOpenEndTime!=null){
+            rangeTime.push(self.formModel.remoteOpenEndTime);
+          }
+
+          if(rangeTime.length>0){
+            self.formModel.remoteOpenRangeTime = rangeTime;
+          }
 
           if (self.businessKey.length == 0){
             self.formModel.columnColor="1";

+ 83 - 16
src/views/base/deviceInfo-ehome.vue

@@ -121,6 +121,28 @@
                 ></el-switch>
             </el-form-item>
           </el-col>
+        </el-row>        
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="是否开启口罩检测">
+                <el-switch
+                    v-model="maskDetection.enable"
+                    active-color="#13ce66"
+                    active-text="是"
+                    inactive-color="#ff4949"
+                    inactive-text="否"
+                ></el-switch>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="检测未带口罩策略">
+              <el-select v-model="maskDetection.noMaskStrategy">
+                <el-option label="提示且开门" value="tipsAndOpenDoor"></el-option>
+                <el-option label="不提示且开门" value="noTipsAndOpenDoor"></el-option>
+                <el-option label="提示且不开门" value="tipsAndNotOpenDoor"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
         </el-row>
       </el-form>
     </div>
@@ -139,11 +161,16 @@ export default {
   data() {
     return {
       formModel: {},
+      maskDetection: {
+        "enable": true,          
+        "noMaskStrategy": ""
+      },
       ruleValidate: {},
       showDialog: true,
       loading: false,
       submitting: false,
-      cfgUrl: "/ISAPI/AccessControl/AcsCfg?format=json"
+      cfgUrl: "/ISAPI/AccessControl/AcsCfg?format=json",
+      maskDetectionUrl: "/ISAPI/AccessControl/maskDetection?format=json"
     }
   },
   methods: {
@@ -154,29 +181,50 @@ export default {
       var self = this;
 
       this.$refs["form"].validate(valid => {
+        self.loading = true;
+
+        //保存测温策略
         ehomeApi.putXMLConfig(
             self.deviceNo,self.cfgUrl,{
                 "AcsCfg": self.formModel
             },
-        ).then(function(response) {
-            self.loading = false;
-            var jsonData = response.data;
+        ).then(response=>{
+          var jsonData = response.data;
 
-            if (jsonData.success) {
-              self.$message({
-                message: "保存成功!",
-                type: "success"
-              });
+          if(!jsonData.success){
+            self.$message({
+              message: jsonData.message + "",
+              type: "warning"
+            });
+          }
 
-              self.$emit("close", true);
-            } else {
-              self.$message({
-                message: jsonData.message + "",
-                type: "warning"
-              });
+          //保存口罩设置
+          return  ehomeApi.putXMLConfig(
+            self.deviceNo,
+            self.maskDetectionUrl,
+            {
+                "MaskDetection": self.maskDetection
             }
-          });
+          )
+        }).then(response=>{
+          self.loading = false;
+          var jsonData = response.data;
+
+          if (jsonData.success) {
+            self.$message({
+              message: "保存成功!",
+              type: "success"
+            });
+
+            self.$emit("close", true);
+          } else {
+            self.$message({
+              message: jsonData.message + "",
+              type: "warning"
+            });
+          }
         });
+      });
     },
   },
   mounted: function() {
@@ -184,6 +232,7 @@ export default {
     
     self.loading = true;
 
+    //获取测温策略
     ehomeApi.getXMLConfig(self.deviceNo,self.cfgUrl)
     .then(response => {
         var jsonData = response.data;
@@ -200,6 +249,24 @@ export default {
     .catch(error => {
         self.$message.error(error + "");
     });
+
+    //获取口罩设置
+    ehomeApi.getXMLConfig(self.deviceNo,self.maskDetectionUrl)
+    .then(response => {
+        var jsonData = response.data;
+        self.loading = false;
+
+        if (jsonData.success) {
+            var data = eval('(' + jsonData.data + ')');
+
+            self.maskDetection = data.MaskDetection;
+        } else {
+            self.$message.error(jsonData.message + "");
+        }
+    })
+    .catch(error => {
+        self.$message.error(error + "");
+    });
   }
 };
 </script>

+ 2 - 2
src/views/base/deviceInfo-list.vue

@@ -187,9 +187,9 @@
             </el-col> -->
           </el-row>
           <el-row>
-            <!-- <el-col :span="8">
+            <el-col :span="8">
               <el-link type="primary" @click="handleBindPerson(row)">用户关联</el-link>
-            </el-col> -->
+            </el-col>
             <el-col :span="8" v-if="row.manufacturer=='1'">
               <el-link type="primary" @click="handleEditRule(row)">验证规则</el-link>
             </el-col>

+ 1 - 2
src/views/base/devicePhoto-list.vue

@@ -45,8 +45,7 @@
                 </el-table-column>
                 <el-table-column
                     prop="Remarks"
-                    label="备注"
-                    width="150">
+                    label="备注">
                 </el-table-column>
                 <el-table-column label="操作" width="100" fixed="right">
                     <template slot-scope="{row}">

+ 1 - 0
src/views/base/personDeviceLog-list.vue

@@ -390,6 +390,7 @@ export default {
       formData.append("faceImage", self.queryModel.faceImage);
       formData.append("timeRanges", self.queryModel.timeRanges);
       formData.append("matchStatus", self.queryModel.matchStatus);
+      formData.append("personId", self.queryModel.personId);
       formData.append("personName", self.queryModel.personName);
       formData.append("deviceNo", self.queryModel.deviceNo);
       formData.append("aliasName", self.queryModel.aliasName);

+ 53 - 0
src/views/base/personDeviceRelation-BoundList.vue

@@ -24,6 +24,15 @@
           @click="handleRemoveAll"
           >解绑所有设备</el-button
         >
+        <el-button
+          type="primary"
+          size="small"
+          plain
+          icon="el-icon-remove"
+          @click="handleRemoveSelect"
+          >解绑选择的设备</el-button
+        >
+        
         <el-button
           type="primary"
           size="small"
@@ -286,6 +295,50 @@ export default {
           // self.$message.error(error + "");
         });
     },
+    handleRemoveSelect() {
+      var self = this;
+
+      var deviceIdList = this.multipleSelection.map((record) => {
+        return record.deviceId;
+      });
+
+      this.$confirm("是否解除关联?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+        distinguishCancelAndClose: true,
+      })
+        .then(() => {
+          self.loading = true;
+          var formData = new FormData();
+          formData.append("personId", self.personId);
+          formData.append("deviceIds", deviceIdList);
+
+          personDeviceRelationApi
+            .unbindSelectDevice(formData)
+            .then(function (response) {
+              var jsonData = response.data;
+              self.loading = false;
+              if (jsonData.result) {
+                self.changePage(self.pageIndex);
+
+                self.$message({
+                  type: "success",
+                  message: "解绑成功!",
+                });
+              } else {
+                self.$message({
+                  type: "warning",
+                  message: jsonData.message,
+                });
+              }
+            });
+        })
+        .catch((error) => {
+          self.loading = false;
+          // self.$message.error(error + "");
+        });
+    },
     handleRemoveAll() {
       var self = this;
 

+ 503 - 0
src/views/base/personHealthLedger-list.vue

@@ -0,0 +1,503 @@
+<template>
+  <div>
+    <el-breadcrumb separator=">">
+      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="#">系统管理</a>
+      </el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="/personHealthLedger">健康打卡情况</a>
+        <!-- 包含测温和健康上报 -->
+      </el-breadcrumb-item>
+    </el-breadcrumb>
+    <el-divider></el-divider>
+    <!--
+      要resetFields起作用,必须配置:model和prop
+    -->
+    <el-form
+      ref="queryForm"
+      :model="queryModel"
+      :rules="ruleValidate"
+      inline
+      class="demo-form-inline"
+    >
+      <el-row>
+        <el-form-item label="日期" prop="queryTime">
+          <el-date-picker
+            size="mini"
+            v-model="queryModel.queryTime"
+            type="date"
+            placeholder="选择日期"
+            style="width:100%"
+            value-format="yyyy-MM-dd"
+          ></el-date-picker>
+        </el-form-item>
+        <el-form-item label="单位" prop="companyId">
+          <el-select-tree
+            :props="props"
+            :options="companyResult"
+            v-model="queryModel.companyId"
+            height="200"
+          ></el-select-tree>&nbsp;&nbsp;
+          <el-checkbox v-model="queryModel.subordinate">是否包含下级单位</el-checkbox>
+        </el-form-item>
+      </el-row>
+      <el-row>
+        <el-form-item label="姓名" prop="personName">
+          <el-input type="text" size="mini" v-model="queryModel.personName"></el-input>
+        </el-form-item>
+        <!-- <el-form-item label="健康情况" prop="healthStatus">
+          <el-select
+            v-model="queryModel.healthStatus"
+            filterable
+            placeholder="请选择"
+            style="width:50%"
+          >
+            <el-option
+              size="mini"
+              v-for="result in healthData"
+              :key="result.id"
+              :label="result.name"
+              :value="result.value"
+            ></el-option>
+          </el-select>
+        </el-form-item> -->
+        <el-form-item>
+          <el-button
+            type="primary"
+            size="mini"
+            icon="ios-search"
+            @click="handleQuery"
+            :loading="loading"
+          >查询</el-button>&nbsp;
+          <el-button
+            type="info"
+            size="mini"
+            style="margin-left: 8px"
+            @click="handleReset('queryForm')"
+          >重置</el-button>&nbsp;
+        </el-form-item>
+      </el-row>
+    </el-form>
+    <el-divider></el-divider>
+    <el-row class="button-group">
+      <el-button
+        type="primary"
+        size="small"
+        plain
+        icon="el-icon-download"
+        :loading="downloadLoading"
+        @click="exportXls"
+      >导出健康打卡情况</el-button>
+    </el-row>
+    <el-table
+      ref="formTable"
+      :data="tableData"
+      style="min-height:400px;" 
+      :height="tableHeight"
+      v-loading="loading"
+      stripe
+      @sort-change="sortChange"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55"></el-table-column>
+      <el-table-column type="index" label="序号" :index="indexMethod" width="100"></el-table-column>
+      <el-table-column prop="name" label="姓名" width="150"></el-table-column>
+      <el-table-column prop="personHealthLedger.temperature" label="记录温度" width="150"></el-table-column>
+      <el-table-column prop="companyName" label="单位" width="220"></el-table-column>
+      <el-table-column prop="healthStatusN" label="健康情况" width="120">
+        <template slot-scope="{row}">
+          <span v-if="row.isUpHealth">{{row.personHealthLedger.healthStatusN}}</span>
+          <span v-else>未提交</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="familyStatusN" label="家庭健康情况" width="120">
+        <template slot-scope="{row}">
+          <span v-if="row.isUpHealth">{{row.personHealthLedger.familyStatusN}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="isGoto" sort-by="is_goto" label="是否前往疫区" width="150">
+        <template slot-scope="{row}">
+          <span v-if="row.isUpHealth">{{row.personHealthLedger.isGoto == 1 ? "是" : "否"}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="isTouch" label="是否接触高危人员" width="150">
+        <template slot-scope="{row}">
+          <span v-if="row.isUpHealth">{{row.personHealthLedger.isTouch == 1 ? "是" : "否"}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="address" label="打卡地址" width="150" show-overflow-tooltip>
+        <template slot-scope="{row}">
+          <span v-if="row.isUpHealth">{{row.personHealthLedger.address}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="remark" label="备注" width="180" show-overflow-tooltip>
+        <template slot-scope="{row}">
+          <span v-if="row.isUpHealth">{{row.personHealthLedger.remark}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="createTime" label="上传日期" width="180">
+        <template slot-scope="{row}">
+          <span v-if="row.isUpHealth">{{row.personHealthLedger.createTime}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" fixed="right" width="100">
+          <template slot-scope="{row}">
+              <el-button size="mini" type="success" @click="showHistoryList(row)">历史轨迹</el-button>
+          </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      :current-page.sync="pageIndex"
+      :total="totalElements"
+      :page-sizes="pageSizeList"
+      @current-change="changePage"
+      @size-change="pageSizeChange"
+      layout="total, sizes, prev, pager, next, jumper"
+    ></el-pagination>
+    <personHealthLedger-detail
+      v-if="showModal"
+      :businessKey="businessKey"
+      :title="modalTitle"
+      @close="onDetailModalClose"
+    ></personHealthLedger-detail>
+    <el-dialog
+        :visible.sync="showMapDialog"
+        title="历史位置"
+        :modal-append-to-body="true"
+        :append-to-body="true"
+        style="text-align:left;"
+        :close-on-click-modal="false"
+    >
+        <el-amap
+            ref="map"
+            vid="vehicleMap"
+            :center="pointPosition"
+            :zoom="15"
+            style="width:100%;height:400px;"
+        >
+            <el-amap-marker :position="pointPosition" :title="selectedRow.licensePlateNumber"></el-amap-marker>
+        </el-amap>
+        <el-input :value="pointPosition[0] + ',' + pointPosition[1]" :readonly="true"/>
+        <span slot="footer" class="dialog-footer">
+            <el-button @click="showMapDialog=false;">关闭</el-button>
+        </span>
+    </el-dialog>
+    <el-dialog
+        :visible.sync="showHistoryDialog"
+        title="历史轨迹"
+        :modal-append-to-body="true"
+        :append-to-body="true"
+        width="1000px"
+        style="text-align:left;"
+        :close-on-click-modal="false"
+    >
+        <vehicle-history-list
+            ref="vehicleHistoryList"
+            :personId="selectedRow.id"
+        ></vehicle-history-list>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import Constant from "@/constant";
+import personHealthLedgerApi from "@/api/base/personHealthLedger";
+import dataDictionaryApi from "@/api/sys/dataDictionary";
+import companyInfoApi from "@/api/base/companyInfo";
+import SelectTree from "@/components/SelectTree";
+import NProgress from "nprogress"; // progress bar
+import "nprogress/nprogress.css"; // progress bar style
+import pageUtil from "@/utils/page";
+import VehicleHistoryList from './vehicleHistory-list';
+
+export default {
+  name: 'basePersonHealthLedgerListAll',
+  data() {
+    var self = this;
+
+    return {
+      ruleValidate: {
+        companyId: [{ required: true, message: "不能为空", trigger: "blur" }],
+        queryTime: [{ required: true, message: "请选择时间", trigger: "blur" }]
+      },
+      queryModel: {
+        personName: "",
+        healthStatus: "",
+        companyId: "",
+        subordinate: true,
+        queryTime: "",
+        popedom:"1"
+      },
+      loading: false,
+      tableData: [],
+      pageIndex: 1,
+      pageSize: 10,
+      totalPages: 0,
+      totalElements: 0,
+      field: "",
+      direction: "",
+      pageSizeList: [10, 20, 30],
+      multipleSelection: [],
+      showModal: false,
+      modalTitle: "",
+      businessKey: "",
+      healthData: [],
+      companyResult: [],
+      treeData: [],
+      tableHeight: 400,
+      props: {
+        // 配置项(必选)
+        value: "id",
+        label: "name",
+        children: "children"
+      },
+      downloadLoading: false,
+      showMapDialog: false,
+      pointPosition: [112.240222, 30.337053],
+      selectedRow: {
+          licensePlateNumber : "",
+          deviceNo: ""
+      },
+      showHistoryDialog: false,
+    };
+  },
+  created() {
+    var self = this;
+    var formData = new FormData();
+    formData.append("catalogName", "健康情况");
+    dataDictionaryApi.findByCatalogName(formData).then(response => {
+      var jsonData = response.data;
+      this.healthData = jsonData.data;
+    });
+
+    companyInfoApi.list().then(function(response) {
+      var jsonData = response.data;
+      if (jsonData.result) {
+        self.companyResult = jsonData.data;
+      }
+    });
+
+    this.loadTree();
+    this.setDefaultTime();
+
+    setTimeout(()=>{
+      //45为分页栏的高度
+      //页面高度-列表上面的高度-分页栏高度
+      self.tableHeight = pageUtil.autoAdjustHeight(self.$refs.formTable.$el);
+    },1000);
+  },
+  methods: {
+    showMap(row) {
+        this.pointPosition = [parseFloat(row.longitude),parseFloat(row.latitude)];
+        this.selectedRow = row;
+        this.showMapDialog = true;
+    },
+    showHistoryList(row) {
+        this.selectedRow = row;
+        this.showHistoryDialog = true;
+        
+        this.$nextTick(()=>{
+            this.$refs.vehicleHistoryList.getCurrentMonthFirst();
+            this.$refs.vehicleHistoryList.changePage(1);
+        });            
+    },
+    indexMethod(index) {
+      return (this.pageIndex - 1) * this.pageSize + (index + 1);
+    },
+    loadTree() {
+      var formData = new FormData();
+
+      companyInfoApi.loadChildren(formData).then(resp => {
+        var jsonData = resp.data;
+
+        if (jsonData.result) {
+          this.treeData = jsonData.data;
+        } else {
+          this.$message.error(jsonData.message + "");
+        }
+      });
+    },
+    loadChildren(tree, treeNode, resolve) {
+      console.log(tree);
+
+      var formData = new FormData();
+      formData.append("parentId", tree.id);
+
+      companyInfoApi.loadChildren(formData).then(resp => {
+        var jsonData = resp.data;
+
+        if (jsonData.result) {
+          resolve(jsonData.data);
+        } else {
+          this.$message.error(jsonData.message + "");
+        }
+      });
+    },
+    changePage(pageIndex) {
+      var self = this;
+
+      self.loading = true;
+
+      self.pageIndex = pageIndex;
+      var formData = new FormData();
+
+      formData.append("pageIndex", self.pageIndex);
+      formData.append("pageSize", self.pageSize);
+
+      formData.append("personName", self.queryModel.personName);
+      formData.append("healthStatus", self.queryModel.healthStatus);
+      if (self.queryModel.companyId == null) {
+        self.queryModel.companyId = "";
+      }
+      formData.append("companyId", self.queryModel.companyId);
+      formData.append("subordinate", self.queryModel.subordinate);
+      formData.append("queryTime", self.queryModel.queryTime);
+      formData.append("popedom", self.queryModel.popedom);
+
+      if (this.field != null) {
+        formData.append("field", this.field);
+      }
+
+      if (this.direction != null) {
+        formData.append("direction", this.direction);
+      }
+
+      personHealthLedgerApi
+        .pageList(formData)
+        .then(function(response) {
+          self.loading = false;
+
+          var jsonData = response.data.data;
+
+          self.tableData = jsonData.data;
+          self.totalPages = jsonData.totalPages;
+          self.totalElements = jsonData.recordsTotal;
+        })
+        .catch(error => {
+          self.loading = false;
+          // self.$message.error(error + "");
+        });
+    },
+    pageSizeChange(pageSize) {
+      this.pageSize = pageSize;
+
+      this.$nextTick(() => {
+        this.changePage(this.pageIndex);
+      });
+    },
+    sortChange(data) {
+      this.field = data.column.field;
+       this.direction = data.order == "ascending" ? "asc" : "desc";
+
+      this.changePage(this.pageIndex);
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+    handleQuery() {
+      var self = this;
+      this.$refs["queryForm"].validate(valid => {
+        if (valid) {
+          self.changePage(1);
+        }
+      });
+    },
+    handleReset(name) {
+      this.$refs[name].resetFields();
+      //this.queryModel.companyId = "";
+      this.queryModel.queryTime = "";
+      this.queryModel.subordinate = false;
+    },
+    onDetailModalClose(refreshed) {
+      //保存成功后回调
+      this.showModal = false;
+
+      if (refreshed) {
+        this.changePage(this.pageIndex);
+      }
+    },
+    setDefaultTime() {
+      var self = this;
+      var date = new Date();
+      var month = parseInt(date.getMonth() + 1);
+      var nowTime = date.getFullYear() + "-" + month + "-" + date.getDate();
+
+      self.queryModel.queryTime = nowTime;
+    },
+    exportXls() {
+      var self = this;
+
+      //导出
+      this.$refs["queryForm"].validate(valid => {
+        if (valid) {
+          self.downloadLoading = true;
+          self.loading = true;
+
+          var formData = new FormData();
+          formData.append("pageIndex", self.pageIndex);
+          formData.append("pageSize", self.pageSize);
+
+          formData.append("personName", self.queryModel.personName);
+          formData.append("healthStatus", self.queryModel.healthStatus);
+          if (self.queryModel.companyId == null) {
+            self.queryModel.companyId = "";
+          }
+          formData.append("companyId", self.queryModel.companyId);
+          formData.append("subordinate", self.queryModel.subordinate);
+          formData.append("queryTime", self.queryModel.queryTime);
+          formData.append("popedom", self.queryModel.popedom);
+
+          personHealthLedgerApi.exportXls(formData).then(function(response) {
+            var jsonData = response.data;
+
+            self.downloadLoading = false;
+            self.loading = false;
+
+            if (jsonData.result) {
+              self.$message({
+                type: "success",
+                showClose: true,
+                message: `报表已生成,<a href="${jsonData.data}">请点击链接下载</a>`,
+                dangerouslyUseHTMLString: true,
+                duration: 30000
+              });
+            } else {
+              self.$message({
+                type: "warning",
+                message: jsonData.message
+              });
+            }
+          });
+        }
+      });
+    }
+  },
+  mounted: function() {
+    //this.changePage(1);
+  },
+  components: {
+    "el-select-tree": SelectTree,
+    "vehicle-history-list" : VehicleHistoryList
+  }
+};
+</script>
+<style lang="scss" scoped>
+.el-breadcrumb {
+  margin: 10px;
+  line-height: 20px;
+}
+
+.el-divider {
+  margin: 5px 0;
+}
+
+.demo-form-inline {
+  margin-left: 10px;
+  text-align: left;
+}
+
+.button-group {
+  margin-left: 10px;
+  text-align: left;
+}
+</style>

+ 248 - 0
src/views/base/vehicleHistory-list.vue

@@ -0,0 +1,248 @@
+<template>
+    <div>
+        <el-form ref="queryForm" :model="queryModel" inline class="demo-form-inline">
+            <el-form-item label="查询时间段" prop="timeRange">
+                <el-date-picker
+                    type="datetimerange"
+                    v-model="queryModel.timeRange"
+                    start-placeholder="开始时间"
+                    end-placeholder="结束时间"
+                    placeholder="选择时间范围"
+                    format='yyyy-MM-dd HH:mm:ss'
+                    value-format="yyyy-MM-dd HH:mm:ss"           
+                    >
+                </el-date-picker>
+            </el-form-item>
+            <el-form-item>
+                <el-button
+                type="primary"
+                size="mini"
+                icon="ios-search"
+                @click="changePage(1)"
+                :loading="loading"
+                >查询</el-button>&nbsp;
+                <el-button
+                    type="info"
+                    size="mini"
+                    style="margin-left: 8px"
+                    @click="handleReset('queryForm')"
+                >重置</el-button>
+            </el-form-item>
+        </el-form>
+        <el-divider></el-divider>
+        <div class="custom-layout">
+            <div class="custom-center">                
+                <el-amap
+                    ref="vehicleHistoryMap"
+                    vid="vehicleHistoryMap"
+                    :center="pointPosition"
+                    :zoom="15"
+                    style="width:100%;height:400px;"
+                >
+                    <!--数据点-->
+                    <el-amap-marker :zIndex="1"
+                        v-for="(item,index) in itemList"
+                        :key="index"
+                        :position="item.position"
+                        :title="item.title"
+                        >
+                    </el-amap-marker>
+                    <!--轨迹-->
+                    <el-amap-polyline :path="mapPath"
+                                    :zIndex="2"
+                                    :isOutline="true"
+                                    :outlineColor="'#ffeeff'"
+                                    :borderWeight="3"
+                                    :strokeColor="'#3366FF'"
+                                    :strokeOpacity="1"
+                                    :strokeWeight="6"
+                                    :strokeStyle="'solid'"
+                                    :strokeDasharray="[10, 5]"
+                                    :lineJoin="'round'"
+                                    :lineCap="'round'"
+                    ></el-amap-polyline>
+                </el-amap>                
+            </div>
+            <div class="custom-right">
+                <el-table
+                    ref="formTable"
+                    :data="tableData"
+                    v-loading="loading"
+                    element-loading-text="拼命加载中"
+                    stripe
+                    height="400"
+                    @row-click="rowClick"
+                >
+                    <el-table-column label="经纬度" width="200px">
+                        <template slot-scope="{row}">
+                            <span style="cursor:pointer;">{{row.longitude}},{{row.latitude}}</span>
+                        </template>
+                    </el-table-column>
+                    <el-table-column prop="createTime" width="160px" label="记录时间"></el-table-column>
+                </el-table>
+            </div>
+        </div>
+        <div style="text-align:right;">
+            <el-pagination
+                :current-page.sync="pageIndex"
+                :total="totalElements"
+                :page-sizes="pageSizeList"
+                @current-change="changePage"
+                @size-change="pageSizeChange"
+                layout="total, sizes, prev, pager, next"
+            ></el-pagination>
+        </div>
+    </div>
+</template>
+<script>
+import vehicleApi from '@/api/base/personHealthLedger';
+
+export default {
+    name:"busVehicleList",
+    props: ["personId"],
+    data(){
+        return{
+            queryModel: {
+                timeRange: null
+            },
+            loading: false,
+            tableData: [],
+            statusData:[],
+            multipleSelection: [],
+            pageIndex: 1,
+            pageSize: 20,
+            totalElements: 0,
+            pageSizeList: [20,50,100],
+            pointPosition: [112.240222, 30.337053],
+            mapPath: [],
+            itemList: []
+        }
+    },
+    methods: {
+        handleReset(name) {
+            this.$refs[name].resetFields();
+        },
+        changePage(pageIndex) {
+            this.loading = true;
+            var formData = new FormData();
+
+            formData.append("pageIndex", this.pageIndex);
+            formData.append("pageSize", this.pageSize);
+            formData.append("personId", this.personId);
+
+            if(this.queryModel.timeRange!=null){
+                formData.append("startTime", this.queryModel.timeRange[0]);
+                formData.append("endTime", this.queryModel.timeRange[1]);
+            }
+
+            vehicleApi.gpsHistoryList(formData).then((response)=>{
+                this.loading = false;
+                var jsonData = response.data;
+
+                this.tableData = jsonData.data.data;
+                this.totalElements = jsonData.data.recordsTotal;
+                this.mapPath = [];
+
+                if(this.tableData.length>0){
+                    var lngSum = this.tableData.reduce((acc,cur)=>{
+                        return acc + parseFloat(cur.longitude);
+                    },0);
+                    
+                    var lngAvg = lngSum / this.tableData.length;
+
+                    console.log(lngAvg);
+
+                    this.tableData.forEach(item=>{
+                        var pos = [parseFloat(item.longitude),parseFloat(item.latitude)];
+                        
+                        //如果有数据点精度与平均值偏差0.5,则不显示该点
+                        if(Math.abs(lngAvg - pos[0])<0.5){
+                            this.mapPath.push(pos);
+                        }
+                    });
+
+                    var firstRow = this.tableData[0];
+                    this.rowClick(firstRow);
+                }
+
+                this.pageIndex = pageIndex;
+            })
+        },
+        pageSizeChange(pageSize) {
+            this.pageSize = pageSize;
+            this.changePage(1);
+        },
+        rowClick(row, column, event) {
+            this.itemList = [];
+            
+            this.pointPosition = [parseFloat(row.longitude),parseFloat(row.latitude)];
+
+            this.itemList.push({
+                position: [row.longitude,row.latitude],
+                title: row.createTime
+            });
+        },
+        //初始化日期
+        getCurrentMonthFirst() {
+            var self = this;
+            var date = new Date();
+            var startDate = new Date();
+            var month = parseInt(date.getMonth() + 1);
+
+            //当前测温记录
+
+            var startMonth = month;
+            // if (startDate.getDate() < 7) {
+            //   startMonth = startDate.getMonth();
+            //   startDate.setDate(0);
+            // }
+
+            // startDate = startDate.getDate() - 7;
+
+            var startTime =
+                date.getFullYear() + "-" + startMonth + "-" + startDate.getDate() + " 00:00:00";
+
+            var endTime =
+                date.getFullYear() + "-" + month + "-" + date.getDate() + " 23:59:59";
+
+            self.queryModel.timeRange = [startTime, endTime];
+        }
+    },
+    components: {
+
+    },
+    mounted() {
+        //this.changePage(1);
+    },
+    created() {
+
+    }
+}
+</script>
+<style lang="scss" scoped>
+.el-divider {
+  margin: 5px 0;
+}
+
+.route-list{
+    text-align: left;
+}
+
+.demo-form-inline {
+  margin-left: 10px;
+  text-align: left;
+}
+
+.custom-layout{
+    display: flex;
+    flex-direction: row;
+}
+
+.custom-center{
+    flex:1;
+}
+
+.custom-right{
+    width: 400px;
+}
+</style>

+ 435 - 0
src/views/base/workOver-list.vue

@@ -0,0 +1,435 @@
+<template>
+  <div>
+    <el-breadcrumb separator=">">
+      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="#">系统管理</a>
+      </el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="/workOver">加班申请记录</a>
+      </el-breadcrumb-item>
+    </el-breadcrumb>
+    <el-divider></el-divider>
+    <!--
+      要resetFields起作用,必须配置:model和prop
+    -->
+    <el-form
+      ref="queryForm"
+      :model="queryModel"
+      inline
+      class="demo-form-inline"
+    >
+    <el-form-item label="所属单位" prop="companyId">
+        <el-select-tree
+          size="mini"
+          :props="props"
+          :options="treeData"
+          v-model="queryModel.companyId"
+          height="200"
+        ></el-select-tree>&nbsp;
+          <el-checkbox v-model="queryModel.subordinate"
+            >是否包含下级单位</el-checkbox
+          >
+      </el-form-item>
+      <el-form-item label="申请人姓名" prop="personName">
+        <el-input type="text" size="mini" v-model="queryModel.personName"></el-input>
+      </el-form-item>
+      <el-form-item label="审批状态" prop="status">
+        <el-select
+          v-model="queryModel.status"
+          size="mini"
+          filterable
+          placeholder="请选择"
+          style="width:100px"
+        >
+          <el-option v-for="item in statusList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="申请时间" prop="requestTimeRange">
+        <el-date-picker
+            v-model="queryModel.requestTimeRange"
+            type="daterange"
+            size="mini"
+            range-separator="至"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            placeholder="选择时间范围"
+            value-format="yyyy-MM-dd"
+            >
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="审核时间" prop="auditTimeRange">
+        <el-date-picker
+            v-model="queryModel.auditTimeRange"
+            type="daterange"
+            size="mini"
+            range-separator="至"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            placeholder="选择时间范围"
+            value-format="yyyy-MM-dd"
+            >
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="primary"
+          size="mini"
+          icon="ios-search"
+          @click="changePage(1)"
+          :loading="loading"
+          >查询</el-button
+        >&nbsp;
+        <el-button
+          type="info"
+          size="mini"
+          style="margin-left: 8px"
+          @click="handleReset('queryForm')"
+          >重置</el-button
+        >&nbsp;
+      </el-form-item>
+    </el-form>
+    <el-divider></el-divider>
+    <el-row class="button-group">
+      <!-- <el-button type="success" size="small" plain icon="el-icon-download" @click="exportXls()">批量导出</el-button> -->
+    </el-row>
+    <el-table
+      :data="tableData"
+      style="min-height: 400px"
+      v-loading="loading"
+      stripe
+      @sort-change="sortChange"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="expand">
+        <template slot-scope="{row}">
+          <el-form label-position="left" class="demo-table-expand">
+            <el-form-item label="开始时间:">
+              <span>{{row.startTime }}</span>
+            </el-form-item>
+            <el-form-item label="结束时间:">
+              <span>{{row.endTime }}</span>
+            </el-form-item>
+            <el-form-item label="加班时长:">
+              <span>{{row.hours }}</span>
+            </el-form-item>
+            <el-form-item label="加班原因:">
+              <span>{{row.reason }}</span>
+            </el-form-item>
+            <el-form-item label="审核意见:">
+              <span>{{row.approvalContent }}</span>
+            </el-form-item>
+            <el-form-item label="审核时间:">
+              <span>{{row.approvalTime }}</span>
+            </el-form-item>
+          </el-form>
+        </template>
+      </el-table-column>
+      <el-table-column prop="createTime" label="申请时间" :sortable="false" width="180"></el-table-column>
+      <el-table-column
+        prop="personName"
+        label="申请人"
+        width="180"
+      ></el-table-column>
+      <el-table-column
+        prop="companyName"
+        label="单位"
+        width="180"
+      ></el-table-column>
+      
+      <el-table-column
+        prop="approvalPersonName"
+        label="审批人"
+        width="180"
+      ></el-table-column>
+      <el-table-column
+        prop="statusN"
+        label="状态"
+        width="180"
+      ></el-table-column>
+      <el-table-column
+        prop="approvalTime"
+        label="审核时间"
+        width="180"
+      ></el-table-column>
+      <el-table-column prop="remark" label="备注" width="180"></el-table-column>
+    </el-table>
+    <el-pagination
+      :current-page.sync="pageIndex"
+      :total="totalElements"
+      :page-sizes="pageSizeList"
+      @current-change="changePage"
+      @size-change="pageSizeChange"
+      layout="total, sizes, prev, pager, next, jumper"
+    ></el-pagination>
+    <workOver-detail
+      v-if="showModal"
+      :businessKey="businessKey"
+      :title="modalTitle"
+      @close="onDetailModalClose"
+    ></workOver-detail>
+  </div>
+</template>
+<script>
+import Constant from "@/constant";
+import workOverApi from "@/api/base/workOver";
+import companyInfoApi from "@/api/base/companyInfo";
+import SelectTree from "@/components/SelectTree";
+import NProgress from "nprogress"; // progress bar
+import "nprogress/nprogress.css"; // progress bar style
+
+export default {
+  name: "baseWorkOverList",
+  data() {
+    var self = this;
+
+    return {
+      queryModel: {
+        companyId: "",
+        personName: "",
+        status:"",
+        requestTimeRange: ['',''],
+        auditTimeRange: ['',''],
+        subordinate:false
+      },
+      loading: false,
+      tableData: [],
+      pageIndex: 1,
+      pageSize: 10,
+      totalPages: 0,
+      totalElements: 0,
+      field: "",
+      direction: "",
+      pageSizeList: [10, 20, 30],
+      multipleSelection: [],
+      showModal: false,
+      modalTitle: "",
+      businessKey: "",
+      statusList: [
+        {id: 0, name: "待处理"},
+        {id: 1, name: "已同意"},
+        {id: 2, name: "已拒绝"}
+      ],
+      treeData: [],
+      props: {
+        // 配置项(必选)
+        value: "id",
+        label: "name",
+        children: "children"
+      },
+      
+    };
+  },
+  created() {
+    this.loadTree();
+    this.changePage(1);
+  },
+  methods: {
+    showStatusName(status) {
+      var list = this.statusList.filter(item=>item.id == status);
+
+      if(list.length>0){
+        return list[0].name;
+      }
+      else{
+        return "";
+      }
+    },
+    loadTree() {
+      companyInfoApi.list().then(resp => {
+        var jsonData = resp.data;
+
+        if (jsonData.result) {
+          this.treeData = jsonData.data;
+        } else {
+          this.$message.error(jsonData.message + "");
+        }
+      });
+    },
+    changePage(pageIndex,exportFlag) {
+      var self = this;
+
+      self.loading = true;
+
+      self.pageIndex = pageIndex;
+      var formData = new FormData();
+
+      formData.append("pageIndex", self.pageIndex);
+
+      if(exportFlag!=null){
+        formData.append("exportFlag", exportFlag);
+        formData.append("pageSize", 10000);
+      }
+      else{
+        formData.append("pageSize", self.pageSize);
+      }
+
+      if(self.queryModel.companyId != null){
+        formData.append("companyId", self.queryModel.companyId);
+      }
+
+      formData.append("subordinate", self.queryModel.subordinate);
+      
+      formData.append("personName", self.queryModel.personName);
+      formData.append("status", self.queryModel.status);
+      if(self.queryModel.requestTimeRange[0] != null){
+        formData.append("startTime", self.queryModel.requestTimeRange[0]);
+      }
+
+      if(self.queryModel.requestTimeRange[1] != null){
+        formData.append("endTime", self.queryModel.requestTimeRange[1]);
+      }
+
+      if(self.queryModel.auditTimeRange[0] != null){
+        formData.append("auditStartTime", self.queryModel.auditTimeRange[0]);
+      }
+
+      if(self.queryModel.auditTimeRange[1] != null){
+        formData.append("auditEndTime", self.queryModel.auditTimeRange[1]);
+      }
+
+      if (this.field != null) {
+        formData.append("field", this.field);
+      }
+
+      if (this.direction != null) {
+        formData.append("direction", this.direction);
+      }
+
+      workOverApi
+        .pageList(formData)
+        .then(function (response) {
+          self.loading = false;
+
+          var jsonData = response.data.data;
+
+          self.tableData = jsonData.data;
+          self.totalPages = jsonData.totalPages;
+          self.totalElements = jsonData.recordsTotal;
+        })
+        .catch((error) => {
+          self.loading = false;
+          // self.$message.error(error + "");
+        });
+    },
+    pageSizeChange(pageSize) {
+      this.pageSize = pageSize;
+
+      this.$nextTick(() => {
+        this.changePage(this.pageIndex);
+      });
+    },
+    sortChange(data) {
+      this.field = data.column.field;
+      this.direction = data.order;
+
+      this.changePage(this.pageIndex);
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+    handleReset(name) {
+      this.$refs[name].resetFields();
+    },
+    handleAdd() {
+      this.modalTitle = "新增";
+      this.businessKey = "";
+      this.showModal = true;
+    },
+    handleEdit(record) {
+      this.modalTitle = "编辑";
+      this.businessKey = record.id;
+      this.showModal = true;
+    },
+    handleDelete(record) {
+      var self = this;
+
+      self
+        .$confirm("是否确认删除?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        })
+        .then(() => {
+          workOverApi.remove(record.id).then(function (response) {
+            var jsonData = response.data;
+
+            if (jsonData.result) {
+              // var index = self.tableData.indexOf(record);
+              // self.tableData.splice(index, 1);
+              self.changePage(self.pageIndex);
+
+              self.$message({
+                type: "success",
+                message: "删除成功!",
+              });
+            }
+          });
+        });
+    },
+    handleBatchDelete() {
+      var self = this;
+
+      var idList = this.multipleSelection.map((record) => {
+        return record.id;
+      });
+
+      this.$confirm("是否确认删除选中项?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      }).then(() => {
+        workOverApi.batchRemove(idList).then(function (response) {
+          var jsonData = response.data;
+
+          if (jsonData.result) {
+            self.changePage(self.pageIndex);
+
+            self.$message({
+              type: "success",
+              message: "删除成功!",
+            });
+          }
+        });
+      });
+    },
+    onDetailModalClose(refreshed) {
+      //保存成功后回调
+      this.showModal = false;
+
+      if (refreshed) {
+        this.changePage(this.pageIndex);
+      }
+    },
+    exportXls() {
+      this.changePage(1,true);
+    }
+  },
+  mounted: function () {
+    this.changePage(1);
+  },
+  components: {
+    "el-select-tree": SelectTree
+  },
+};
+</script>
+<style lang="scss" scoped>
+.el-breadcrumb {
+  margin: 10px;
+  line-height: 20px;
+}
+
+.el-divider {
+  margin: 5px 0;
+}
+
+.demo-form-inline {
+  margin-left: 10px;
+  text-align: left;
+}
+
+.button-group {
+  margin-left: 10px;
+  text-align: left;
+}
+</style>

+ 235 - 0
src/views/base/workSchedule-company.vue

@@ -0,0 +1,235 @@
+
+<style scoped>
+.user-panel {
+  margin: 10px auto;
+}
+</style>
+<template>
+  <el-dialog
+    :visible.sync="showDialog"
+    :title="title"
+    :modal-append-to-body="false"
+    style="text-align: left"
+    @close="closeDialog"
+    :close-on-click-modal="false"
+  >
+    <div class="user-panel" v-loading="loading">
+      <el-form
+        ref="form"
+        :model="formModel"
+        :rules="ruleValidate"
+        :label-width="'120px'"
+      >
+        <el-form-item label="考勤部门" prop="clockIn">
+          <el-tree
+           v-model="formModel.clockIn"
+            :data="companyResultData"
+            show-checkbox
+            node-key="id"
+            ref="tree"
+            highlight-current
+            :props="companyProps">
+          </el-tree>
+        </el-form-item>
+      </el-form>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="closeDialog">取 消</el-button>
+      <el-button type="primary" @click="handleSubmit" :loading="submitting"
+        >确 定</el-button
+      >
+    </span>
+  </el-dialog>
+</template>
+<script>
+import Constant from "@/constant";
+import workScheduleApi from "@/api/base/workSchedule";
+import companyInfoApi from "@/api/base/companyInfo";
+
+export default {
+  props: ["businessKey", "title"],
+  data() {
+    return {
+      formModel: {},
+      ruleValidate: {
+        name: [
+          { required: true, message: "班次名称不能为空", trigger: "blur" },
+        ],
+        weekdays: [
+          { required: true, message: "周工作日不能为空", trigger: "blur" },
+        ],
+        startTime: [
+          { required: true, message: "上班时间不能为空", trigger: "blur" },
+        ],
+        startAdvanceMinutes: [
+          { required: true, message: "上班提前分钟不能为空", trigger: "blur" },
+        ],
+        startDelayMinutes: [
+          { required: true, message: "上班延迟分钟不能为空", trigger: "blur" },
+        ],
+        endTime: [
+          { required: true, message: "下班时间不能为空", trigger: "blur" },
+        ],
+        endAdvanceMinutes: [
+          { required: true, message: "下班提前分钟不能为空", trigger: "blur" },
+        ],
+        endDelayMinutes: [
+          { required: true, message: "下班延迟分钟不能为空", trigger: "blur" },
+        ],
+      },
+      showDialog: true,
+      loading: false,
+      submitting: false,
+      options: [
+        {
+          value: "1",
+          label: "周一"
+        },
+        {
+          value: "2",
+          label: "周二"
+        },
+        {
+          value: "3",
+          label: "周三"
+        },
+        {
+          value: "4",
+          label: "周四"
+        },
+        {
+          value: "5",
+          label: "周五"
+        },
+        {
+          value: "6",
+          label: "周六"
+        },
+        {
+          value: "7",
+          label: "星期天"
+        }
+      ],
+      companyResult: [],
+      companyProps: {
+        value: "id",
+        label: "name",
+        children: "children"
+      },
+    };
+  },
+  computed: {
+    /* 转树形数据 */
+    companyResultData() {
+      //第一个节点为根节点
+      if (this.companyResult.length > 0) {
+        var rootId = this.companyResult[0].id;
+
+        let cloneData = JSON.parse(JSON.stringify(this.companyResult)); // 对源数据深度克隆
+        return cloneData.filter(father => {
+          // 循环所有项,并添加children属性
+          let branchArr = cloneData.filter(
+            child => father.id == child.parentId
+          ); // 返回每一项的子级数组
+          branchArr.length > 0 ? (father.children = branchArr) : ""; //给父级添加一个children属性,并赋值
+          return father.id == rootId || father.parentId == null; //返回第一层
+        });
+      } else {
+        return [];
+      }
+    }
+  },
+  created() {
+    var self = this;
+
+    companyInfoApi.list().then(function(response) {
+      var jsonData = response.data;
+      if (jsonData.result) {
+        self.companyResult = jsonData.data;
+      }
+    });
+  },
+  methods: {
+    closeDialog() {
+      this.$emit("close", false);
+    },
+    handleSubmit() {
+      var self = this;
+      self.formModel.clockIn = this.$refs.tree.getCheckedKeys();
+      
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          (function () {
+            var id = self.formModel.id;
+
+            if (self.formModel.weekdays != null) {
+                var weekdays = self.formModel.weekdays.join(",");
+                self.formModel.weekdays = weekdays;
+            }
+
+            
+            if (self.formModel.clockIn != null) {
+                var clockIn = self.formModel.clockIn.join(",");
+                self.formModel.clockIn = clockIn;
+            }
+
+            return workScheduleApi.updateCompany(self.formModel);
+          })().then(function (response) {
+            var jsonData = response.data;
+
+            if (jsonData.result) {
+              self.$message({
+                message: "保存成功!",
+                type: "success",
+              });
+
+              self.$emit("close", true);
+            } else {
+              self.$message({
+                message: jsonData.message + "",
+                type: "warning",
+              });
+
+              self.$emit("close", false);
+            }
+          });
+        }
+      });
+    },
+  },
+  mounted: function () {
+    var self = this;
+
+    (function () {
+      if (self.businessKey.length == 0) {
+        return workScheduleApi.create();
+      } else {
+        return workScheduleApi.edit(self.businessKey);
+      }
+    })()
+      .then((response) => {
+        var jsonData = response.data;
+        self.loading = false;
+
+        if (jsonData.result) {
+          self.formModel = jsonData.data;
+
+          var weekdays = self.formModel.weekdays;
+          if (weekdays != null) {
+            self.formModel.weekdays = weekdays.split(",");
+          }
+
+          var clockIn = self.formModel.clockIn;
+          if (clockIn != null) {
+            this.$refs.tree.setCheckedKeys(clockIn.split(","));
+          }
+        } else {
+          self.$message.error(jsonData.message + "");
+        }
+      })
+      .catch((error) => {
+        self.$message.error(error + "");
+      });
+  },
+};
+</script>

+ 288 - 0
src/views/base/workSchedule-detail.vue

@@ -0,0 +1,288 @@
+
+<style scoped>
+.user-panel {
+  margin: 10px auto;
+}
+</style>
+<template>
+  <el-dialog
+    :visible.sync="showDialog"
+    :title="title"
+    :modal-append-to-body="false"
+    style="text-align: left"
+    @close="closeDialog"
+    :close-on-click-modal="false"
+  >
+    <div class="user-panel" v-loading="loading">
+      <el-form
+        ref="form"
+        :model="formModel"
+        :rules="ruleValidate"
+        :label-width="'120px'"
+      >
+        <el-form-item label="企业名称" prop="companyId">
+          <el-select-tree
+            :props="companyProps"
+            :options="companyResult"
+            v-model="formModel.companyId"
+            style="width: 300px"
+            size="mediumn"
+          ></el-select-tree>
+        </el-form-item>
+        <el-form-item label="班次名称" prop="name">
+          <el-input
+            v-model="formModel.name"
+            placeholder="请输入班次名称"
+            style="width: 300px"
+          ></el-input>
+        </el-form-item>
+        <el-form-item label="周工作日" prop="weekdays">
+          <el-select
+            v-model="formModel.weekdays"
+            filterable
+            multiple
+            placeholder="请选择"
+            style="width:100% "
+          >
+            <el-option
+              v-for="item in options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="上班时间" prop="startTime">
+          <el-time-picker
+            v-model="formModel.startTime"
+            class="date-box"
+            format="HH:mm"
+            value-format="HH:mm"
+          ></el-time-picker>
+        </el-form-item>
+        <el-form-item label="上班提前" prop="startAdvanceMinutes">
+          <el-input
+            v-model="formModel.startAdvanceMinutes"
+            placeholder="请输入上班提前分钟"
+            style="width: 200px"
+          >
+            <template slot="append">分钟</template>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="上班延迟" prop="startDelayMinutes">
+          <el-input
+            v-model="formModel.startDelayMinutes"
+            placeholder="请输入上班延迟分钟"
+            style="width: 200px"
+          >
+            <template slot="append">分钟算迟到</template>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="下班时间" prop="endTime">
+          <el-time-picker
+            v-model="formModel.endTime"
+            class="date-box"
+            format="HH:mm"
+            value-format="HH:mm"
+          ></el-time-picker>
+        </el-form-item>
+        <el-form-item label="下班提前" prop="endAdvanceMinutes">
+          <el-input
+            v-model="formModel.endAdvanceMinutes"
+            placeholder="请输入下班提前分钟"
+            style="width: 200px"
+          >
+            <template slot="append">分钟算早退</template>
+          </el-input>
+        </el-form-item>
+        <el-form-item label="下班延迟" prop="endDelayMinutes">
+          <el-input
+            v-model="formModel.endDelayMinutes"
+            placeholder="请输入下班延迟分钟"
+            style="width: 200px"
+          >
+            <template slot="append">分钟</template>
+          </el-input>
+        </el-form-item>
+      </el-form>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="closeDialog">取 消</el-button>
+      <el-button type="primary" @click="handleSubmit" :loading="submitting"
+        >确 定</el-button
+      >
+    </span>
+  </el-dialog>
+</template>
+<script>
+import Constant from "@/constant";
+import workScheduleApi from "@/api/base/workSchedule";
+import companyInfoApi from "@/api/base/companyInfo";
+import SelectTree from "@/components/SelectTree";
+
+export default {
+  props: ["businessKey", "title"],
+  data() {
+    return {
+      formModel: {},
+      ruleValidate: {
+        name: [
+          { required: true, message: "班次名称不能为空", trigger: "blur" },
+        ],
+        weekdays: [
+          { required: true, message: "周工作日不能为空", trigger: "blur" },
+        ],
+        startTime: [
+          { required: true, message: "上班时间不能为空", trigger: "blur" },
+        ],
+        startAdvanceMinutes: [
+          { required: true, message: "上班提前分钟不能为空", trigger: "blur" },
+        ],
+        startDelayMinutes: [
+          { required: true, message: "上班延迟分钟不能为空", trigger: "blur" },
+        ],
+        endTime: [
+          { required: true, message: "下班时间不能为空", trigger: "blur" },
+        ],
+        endAdvanceMinutes: [
+          { required: true, message: "下班提前分钟不能为空", trigger: "blur" },
+        ],
+        endDelayMinutes: [
+          { required: true, message: "下班延迟分钟不能为空", trigger: "blur" },
+        ],
+      },
+      showDialog: true,
+      loading: false,
+      submitting: false,
+      options: [
+        {
+          value: "1",
+          label: "周一"
+        },
+        {
+          value: "2",
+          label: "周二"
+        },
+        {
+          value: "3",
+          label: "周三"
+        },
+        {
+          value: "4",
+          label: "周四"
+        },
+        {
+          value: "5",
+          label: "周五"
+        },
+        {
+          value: "6",
+          label: "周六"
+        },
+        {
+          value: "7",
+          label: "星期天"
+        }
+      ],
+      companyResult: [],
+      companyProps: {
+        value: "id",
+        label: "name",
+        children: "children"
+      },
+    };
+  },
+  created() {
+    var self = this;
+
+    companyInfoApi.list({scope:"all"}).then(function(response) {
+      var jsonData = response.data;
+      if (jsonData.result) {
+        self.companyResult = jsonData.data;
+      }
+    });
+  },
+  methods: {
+    closeDialog() {
+      this.$emit("close", false);
+    },
+    handleSubmit() {
+      var self = this;
+      
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          (function () {
+            var id = self.formModel.id;
+            self.submitting = true;
+
+            var requestModel = JSON.parse(JSON.stringify(self.formModel));
+
+            if (requestModel.weekdays != null) {
+                var weekdays = requestModel.weekdays.join(",");
+                requestModel.weekdays = weekdays;
+            }
+
+            if (id == null || id.length == 0) {
+              return workScheduleApi.add(requestModel);
+            } else {
+              return workScheduleApi.update(requestModel);
+            }
+          })().then(function (response) {
+            self.submitting = false;
+
+            var jsonData = response.data;
+
+            if (jsonData.result) {
+              self.$message({
+                message: "保存成功!",
+                type: "success",
+              });
+
+              self.$emit("close", true);
+            } else {
+              self.$message({
+                message: jsonData.message + "",
+                type: "warning",
+              });
+
+              self.$emit("close", false);
+            }
+          });
+        }
+      });
+    },
+  },
+  mounted: function () {
+    var self = this;
+
+    (function () {
+      if (self.businessKey.length == 0) {
+        return workScheduleApi.create();
+      } else {
+        return workScheduleApi.edit(self.businessKey);
+      }
+    })()
+      .then((response) => {
+        var jsonData = response.data;
+        self.loading = false;
+
+        if (jsonData.result) {
+          self.formModel = jsonData.data;
+
+          var weekdays = self.formModel.weekdays;
+          if (weekdays != null) {
+            self.formModel.weekdays = weekdays.split(",");
+          }
+        } else {
+          self.$message.error(jsonData.message + "");
+        }
+      })
+      .catch((error) => {
+        self.$message.error(error + "");
+      });
+  },
+  components: {
+    "el-select-tree": SelectTree
+  },
+};
+</script>

+ 428 - 0
src/views/base/workSchedule-list.vue

@@ -0,0 +1,428 @@
+<template>
+  <div>
+    <el-breadcrumb separator=">">
+      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="#">考勤管理</a>
+      </el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="/base/workSchedule">班次考勤设置</a>
+      </el-breadcrumb-item>
+    </el-breadcrumb>
+    <el-divider></el-divider>
+    <!--
+      要resetFields起作用,必须配置:model和prop
+    -->
+    <el-form
+      ref="queryForm"
+      :model="queryModel"
+      inline
+      class="demo-form-inline"
+    >
+    <el-form-item label="单位名称" prop="companyId">
+        <el-select-tree
+          size="mini"
+          :props="companyProps"
+          :options="companyResult"
+          v-model="queryModel.companyId"
+          height="200"
+        ></el-select-tree>
+      </el-form-item>
+      <el-form-item label="班次名称" prop="name">
+        <el-input type="text" size="mini" v-model="queryModel.name"></el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="primary"
+          size="mini"
+          icon="ios-search"
+          @click="changePage(1)"
+          :loading="loading"
+          >查询</el-button
+        >&nbsp;
+        <el-button
+          type="info"
+          size="mini"
+          style="margin-left: 8px"
+          @click="handleReset('queryForm')"
+          >重置</el-button
+        >&nbsp;
+      </el-form-item>
+    </el-form>
+    <el-divider></el-divider>
+    <el-row class="button-group">
+      <el-button
+        type="primary"
+        size="small"
+        plain
+        icon="el-icon-circle-plus"
+        @click="handleAdd"
+        >新增</el-button
+      >
+      <el-button
+        type="primary"
+        size="small"
+        plain
+        icon="el-icon-circle-plus"
+        :disabled="multipleSelection.length == 0"
+        @click="handleBatchDelete"
+        >删除选中项</el-button
+      >
+      <el-button
+        type="primary"
+        size="small"
+        plain
+        icon="el-icon-edit"
+        :loading="loading"
+        @click="handleBatchUpdate"
+        v-show="batchUpdateVisible"
+      >重新生成考勤数据</el-button>
+    </el-row>
+    <el-table
+      :data="tableData"
+      style="min-height: 400px"
+      v-loading="loading"
+      stripe
+      @sort-change="sortChange"
+      @selection-change="handleSelectionChange"
+    >
+      <el-table-column type="selection" width="55"></el-table-column>
+      <el-table-column
+        prop="companyName"
+        label="单位名称"
+        width="220"
+      ></el-table-column>
+      <el-table-column
+        prop="name"
+        label="班次名称"
+        width="180"
+      ></el-table-column>
+      <el-table-column
+        prop="weekdays"
+        label="周工作日"
+        width="180"
+      ></el-table-column>
+      <el-table-column
+        prop="startTime"
+        label="上班时间"
+        width="120"
+      ></el-table-column>
+      <el-table-column
+        prop="startAdvanceMinutes"
+        label="上班提前分钟"
+        width="120"
+      ></el-table-column>
+      <el-table-column
+        prop="startDelayMinutes"
+        label="上班延迟分钟"
+        width="120"
+      ></el-table-column>
+      <el-table-column
+        prop="endTime"
+        label="下班时间"
+        width="120"
+      ></el-table-column>
+      <el-table-column
+        prop="endAdvanceMinutes"
+        label="下班提前分钟"
+        width="120"
+      ></el-table-column>
+      <el-table-column
+        prop="endDelayMinutes"
+        label="下班延迟分钟"
+        width="120"
+      ></el-table-column>
+      <el-table-column label="操作" width="250" fixed="right">
+        <template slot-scope="{ row }">
+          <el-button size="mini" type="warning" @click="handleEdit(row)"
+            >编辑</el-button
+          >
+          <el-button size="mini" type="primary" @click="handleCompany(row)"
+            >关联部门</el-button
+          >
+          <el-button size="mini" type="danger" @click="handleDelete(row)"
+            >删除</el-button
+          >
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-pagination
+      :current-page.sync="pageIndex"
+      :total="totalElements"
+      :page-sizes="pageSizeList"
+      @current-change="changePage"
+      @size-change="pageSizeChange"
+      layout="total, sizes, prev, pager, next, jumper"
+    ></el-pagination>
+    <workSchedule-detail
+      v-if="showModal"
+      :businessKey="businessKey"
+      :title="modalTitle"
+      @close="onDetailModalClose"
+    ></workSchedule-detail>
+    <workSchedule-company
+      v-if="showModal1"
+      :businessKey="businessKey"
+      :title="modalTitle"
+      @close="onDetailModalClose"
+    ></workSchedule-company>
+    <workSchedule-update
+      v-if="showModal2"
+      title="更新考勤记录"
+      :multipleSelection="multipleSelection"
+      @close="showModal2=false"
+    ></workSchedule-update>
+  </div>
+</template>
+<script>
+import Constant from "@/constant";
+import WorkScheduleDetail from "./workSchedule-detail";
+import WorkScheduleCompany from "./workSchedule-company";
+import WorkScheduleUpdate from "./workSchedule-update";
+import workScheduleApi from "@/api/base/workSchedule";
+import NProgress from "nprogress"; // progress bar
+import "nprogress/nprogress.css"; // progress bar style
+import companyInfoApi from "@/api/base/companyInfo";
+import SelectTree from "@/components/SelectTree";
+import permissionApi from "@/api/sys/permission";
+
+export default {
+  name: "baseWorkScheduleList",
+  data() {
+    var self = this;
+
+    return {
+      queryModel: {
+        id: "",
+        name: "",
+        weekdays: "",
+        startType: "",
+        startTime: "",
+        startAdvanceMinutes: "",
+        startDelayMinutes: "",
+        endType: "",
+        endTime: "",
+        endAdvanceMinutes: "",
+        endDelayMinutes: "",
+        companyId: "",
+        createBy: "",
+        createTime: "",
+        updateBy: "",
+        updateTime: "",
+        delFlag: "",
+      },
+      loading: false,
+      tableData: [],
+      pageIndex: 1,
+      pageSize: 10,
+      totalPages: 0,
+      totalElements: 0,
+      field: "",
+      direction: "",
+      pageSizeList: [10, 20, 30],
+      multipleSelection: [],
+      showModal: false,
+      showModal1: false,
+      modalTitle: "",
+      businessKey: "",
+      companyResult: [],
+      companyProps: {
+        value: "id",
+        label: "name",
+        children: "children"
+      },
+      batchUpdateVisible: false,
+      showModal2: false
+    };
+  },
+  created() {
+    var self = this;
+
+    companyInfoApi.list().then(function(response) {
+      var jsonData = response.data;
+      if (jsonData.result) {
+        self.companyResult = jsonData.data;
+      }
+    });
+
+    permissionApi.hasPermission("post","/business/workScheduleReport/batchUpdate")
+    .then(response=>{
+      this.batchUpdateVisible = response.data.result;
+    });
+  },
+  methods: {
+    changePage(pageIndex) {
+      var self = this;
+
+      self.loading = true;
+
+      self.pageIndex = pageIndex;
+      var formData = new FormData();
+
+      formData.append("pageIndex", self.pageIndex);
+      formData.append("pageSize", self.pageSize);
+
+      formData.append("name", self.queryModel.name);
+      formData.append("companyId", self.queryModel.companyId);
+
+      if (this.field != null) {
+        formData.append("field", this.field);
+      }
+
+      if (this.direction != null) {
+        formData.append("direction", this.direction);
+      }
+
+      workScheduleApi
+        .pageList(formData)
+        .then(function (response) {
+          self.loading = false;
+
+          var jsonData = response.data.data;
+
+          self.tableData = jsonData.data;
+          self.totalPages = jsonData.totalPages;
+          self.totalElements = jsonData.recordsTotal;
+        })
+        .catch((error) => {
+          self.loading = false;
+          // self.$message.error(error + "");
+        });
+    },
+    pageSizeChange(pageSize) {
+      this.pageSize = pageSize;
+
+      this.$nextTick(() => {
+        this.changePage(this.pageIndex);
+      });
+    },
+    sortChange(data) {
+      this.field = data.column.field;
+      this.direction = data.order;
+
+      this.changePage(this.pageIndex);
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val;
+    },
+    handleReset(name) {
+      this.$refs[name].resetFields();
+    },
+    handleAdd() {
+      this.modalTitle = "新增";
+      this.businessKey = "";
+      this.showModal = true;
+    },
+    handleEdit(record) {
+      this.modalTitle = "编辑";
+      this.businessKey = record.id;
+      this.showModal = true;
+    },
+    handleCompany(record) {
+      this.modalTitle = "部门";
+      this.businessKey = record.id;
+      this.showModal1 = true;
+    },
+    handleDelete(record) {
+      var self = this;
+
+      self
+        .$confirm("是否确认删除?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        })
+        .then(() => {
+          workScheduleApi.remove(record.id).then(function (response) {
+            var jsonData = response.data;
+
+            if (jsonData.result) {
+              // var index = self.tableData.indexOf(record);
+              // self.tableData.splice(index, 1);
+              self.changePage(self.pageIndex);
+
+              self.$message({
+                type: "success",
+                message: "删除成功!",
+              });
+            }
+          });
+        });
+    },
+    handleBatchDelete() {
+      var self = this;
+
+      var idList = this.multipleSelection.map((record) => {
+        return record.id;
+      });
+
+      this.$confirm("是否确认删除选中项?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      }).then(() => {
+        workScheduleApi.batchRemove(idList).then(function (response) {
+          var jsonData = response.data;
+
+          if (jsonData.result) {
+            self.changePage(self.pageIndex);
+
+            self.$message({
+              type: "success",
+              message: "删除成功!",
+            });
+          }
+        });
+      });
+    },
+    onDetailModalClose(refreshed) {
+      //保存成功后回调
+      this.showModal = false;
+      this.showModal1 = false;
+
+      if (refreshed) {
+        this.changePage(this.pageIndex);
+      }
+    },    
+    handleBatchUpdate() {
+      var self = this;
+
+      if(this.multipleSelection.length==0){
+        self.$message.warning("请先选择考勤班次!");
+        return;
+      }
+
+      this.showModal2 = true;
+    }
+  },
+  mounted: function () {
+    this.changePage(1);
+  },
+  components: {
+    "workSchedule-detail": WorkScheduleDetail,
+    "workSchedule-company": WorkScheduleCompany,
+    "workSchedule-update": WorkScheduleUpdate,
+    "el-select-tree": SelectTree
+  },
+};
+</script>
+<style lang="scss" scoped>
+.el-breadcrumb {
+  margin: 10px;
+  line-height: 20px;
+}
+
+.el-divider {
+  margin: 5px 0;
+}
+
+.demo-form-inline {
+  margin-left: 10px;
+  text-align: left;
+}
+
+.button-group {
+  margin-left: 10px;
+  text-align: left;
+}
+</style>

+ 160 - 0
src/views/base/workSchedule-update.vue

@@ -0,0 +1,160 @@
+<style scoped>
+.user-panel {
+  margin: 10px auto;
+}
+</style>
+<template>
+  <el-dialog
+    :visible.sync="showDialog"
+    :title="title"
+    :modal-append-to-body="false"
+    style="text-align: left"
+    @close="closeDialog"
+    :close-on-click-modal="false"
+  >
+    <div class="user-panel"
+    v-loading="loading"
+    :element-loading-text="loadingText">
+      <el-form
+        ref="form"
+        :model="formModel"
+        :rules="ruleValidate"
+        :label-width="'120px'"
+      >
+        <el-form-item label="更新班次">
+          <el-input :value="scheduleName" readonly></el-input>
+        </el-form-item>
+        <el-form-item label="考勤时段" prop="companyId">
+          <el-date-picker
+            v-model="formModel.timeRanges"
+            type="daterange"
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="yyyy-MM-dd"
+            size="mini"
+          ></el-date-picker>
+        </el-form-item>
+      </el-form>
+    </div>
+    <span slot="footer" class="dialog-footer">
+      <el-button @click="closeDialog">取 消</el-button>
+      <el-button type="primary" @click="handleSubmit" :loading="loading">更新</el-button>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import Constant from "@/constant";
+import workScheduleApi from "@/api/base/workSchedule";
+import companyInfoApi from "@/api/base/companyInfo";
+import workScheduleReportApi from "@/api/business/workScheduleReport";
+import SelectTree from "@/components/SelectTree";
+
+export default {
+  props: ["multipleSelection", "title"],
+  computed: {
+    scheduleName() {
+      return this.multipleSelection
+        .map((record) => {
+          return record.name;
+        })
+        .join(",");
+    },
+  },
+  data() {
+    return {
+      formModel: {
+        timeRanges: null,
+      },
+      ruleValidate: {
+        timeRanges: [
+          { required: true, message: "考勤时段不能为空", trigger: "blur" },
+        ],
+      },
+      showDialog: true,
+      loading: false,
+      loadingText: ""
+    };
+  },
+  created() {
+    var self = this;
+  },
+  methods: {
+    //初始化日期
+    getCurrentMonthFirst() {
+      var self = this;
+      var date = new Date();
+      date.setDate(1);
+      var month = parseInt(date.getMonth() + 1);
+      var startTime = date.getFullYear() + "-" + month + "-" + date.getDate();
+
+      date.setMonth(date.getMonth() + 1);
+      var lastDate = new Date(date.getTime() - 1000 * 60 * 60 * 24);
+
+      var endTime =
+        lastDate.getFullYear() + "-" + month + "-" + lastDate.getDate();
+
+      self.formModel.timeRanges = [startTime, endTime];
+    },
+    closeDialog() {
+      this.$emit("close", false);
+    },
+    handleSubmit() {
+      var self = this;
+
+      this.$refs["form"].validate((valid) => {
+        if (valid) {
+          // self
+          //   .$confirm("是否确认更新考勤数据?", "提示", {
+          //     confirmButtonText: "确定",
+          //     cancelButtonText: "取消",
+          //     type: "warning",
+          //   })
+          //   .then(() => {
+              var formData = new FormData();
+
+              var workScheduleIds = this.multipleSelection
+                .map((record) => {
+                  return record.id;
+                })
+                .join(",");
+
+              formData.append("workScheduleIds", workScheduleIds);
+              formData.append("startDate", this.formModel.timeRanges[0]);
+              formData.append("endDate", this.formModel.timeRanges[1]);
+
+              self.loading = true;
+              self.loadingText = "考勤数据生成中...";
+
+              workScheduleReportApi
+                .batchUpdate(formData)
+                .then(function (response) {
+                  var jsonData = response.data;
+
+                  self.loading = false;
+
+                  if (jsonData.result) {
+                    self.$message({
+                      type: "success",
+                      message: jsonData.data + "",
+                    });
+
+                    self.closeDialog();
+                  } else {
+                    self.$message({
+                      type: "warning",
+                      message: jsonData.message + "",
+                    });
+                  }
+                });
+            // });
+        }
+      });
+    },
+  },
+  mounted: function () {
+    var self = this;
+    this.getCurrentMonthFirst();
+  },
+};
+</script>

+ 8 - 0
src/views/business/requestForLeave-list.vue

@@ -14,6 +14,9 @@
       要resetFields起作用,必须配置:model和prop
     -->
     <el-form ref="queryForm" :model="queryModel" inline class="demo-form-inline">
+      <el-form-item label="请假人" prop="name">
+        <el-input type="text" size="mini" v-model="queryModel.name"></el-input>
+      </el-form-item>
       <el-form-item label="所属单位" prop="classId">
         <el-select-tree
           size="mini"
@@ -156,6 +159,7 @@ export default {
 
     return {
       queryModel: {
+        name: "",
         classId: "",
         leaveType: "",
         status:"",
@@ -238,6 +242,10 @@ export default {
 
       formData.append("pageIndex", self.pageIndex);
 
+      if(self.queryModel.name!=null){
+        formData.append("name", self.queryModel.name);
+      }
+
       if(self.queryModel.classId!=null){
         formData.append("classId", self.queryModel.classId);
       }

+ 1 - 1
src/views/business/workAttendance-list.vue

@@ -10,7 +10,7 @@
         <a href="#">门禁管理</a>
       </el-breadcrumb-item>
       <el-breadcrumb-item>
-        <a href="/workAttendance">考勤统计</a>
+        <a href="/business/workAttendance">考勤统计</a>
       </el-breadcrumb-item>
     </el-breadcrumb>
     <el-divider></el-divider>

+ 499 - 0
src/views/business/workScheduleReport.vue

@@ -0,0 +1,499 @@
+<template>
+  <div
+    v-loading="downloadLoading"
+    element-loading-text="导出中"
+    element-loading-spinner="el-icon-loading"
+  >
+    <el-breadcrumb separator=">">
+      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="#">考勤管理</a>
+      </el-breadcrumb-item>
+      <el-breadcrumb-item>
+        <a href="/business/workScheduleReport">班次考勤表</a>
+      </el-breadcrumb-item>
+    </el-breadcrumb>
+    <el-divider></el-divider>
+    <!--
+      要resetFields起作用,必须配置:model和prop
+    -->
+    <el-form
+      ref="queryForm"
+      :model="queryModel"
+      :rules="ruleValidate"
+      inline
+      class="demo-form-inline"
+    >
+      <div>
+        <el-row>
+          <el-form-item label="单位" prop="companyId">
+            <!-- <el-select
+              v-model="queryModel.companyId"
+              size="mini"
+              filterable
+              placeholder="请选择"
+              style="width:220px"
+            >
+              <el-option
+                v-for="company in companyResult"
+                :key="company.id"
+                :label="company.name"
+                :value="company.id"
+              ></el-option>
+            </el-select>-->
+            <el-select-tree
+              :props="props"
+              :options="companyResult"
+              v-model="queryModel.companyId"
+              height="200"
+            ></el-select-tree>
+            &nbsp;
+            <el-checkbox v-model="queryModel.subordinate">是否包含下级单位</el-checkbox>
+          </el-form-item>
+          <el-form-item label="统计区间" prop="timeRanges">
+            <el-date-picker
+              v-model="queryModel.timeRanges"
+              type="daterange"
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              value-format="yyyy-MM-dd"
+              :default-time="timeRangesDefaultTime"
+              size="mini"
+            ></el-date-picker>
+          </el-form-item>
+          <el-form-item label="姓名" prop="name">
+            <el-input type="text" size="mini" v-model="queryModel.name" style="width:100px;"></el-input>
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              type="primary"
+              size="mini"
+              style="margin-left: 8px"
+              @click="handleQuery('queryForm')"
+            >查询</el-button>&nbsp;
+            <el-button
+              type="info"
+              size="mini"
+              style="margin-left: 8px"
+              @click="handleReset('queryForm')"
+            >重置</el-button>
+          </el-form-item>
+        </el-row>
+      </div>
+    </el-form>
+    <el-divider></el-divider>
+    <el-row class="button-group">
+      <el-button
+        type="primary"
+        size="small"
+        plain
+        icon="el-icon-download"
+        :loading="downloadLoading"
+        @click="exportXls"
+      >导出数据</el-button>
+      <el-button
+        type="primary"
+        size="small"
+        plain
+        icon="el-icon-edit"
+        :loading="loading"
+        @click="handleBatchUpdate"
+        v-show="batchUpdateVisible"
+      >重新生成考勤数据</el-button>
+    </el-row>
+    <el-table 
+    ref="formTable" 
+    stripe 
+    :data="tableData" 
+    :height="tableHeight" 
+    style="width: 100%" 
+    v-loading="loading"
+    :element-loading-text="loadingText">
+      <el-table-column label="序号" fixed="left" type="index" :index="indexMethod"></el-table-column>
+      <el-table-column label="姓名" fixed="left" prop="name" width="100"></el-table-column>
+      <el-table-column label="编号" prop="personId" width="100"></el-table-column>
+      <el-table-column label="公司" prop="companyName" width="200"></el-table-column>
+      <el-table-column label="上级部门" prop="parentDepartmentName" width="200"></el-table-column>
+      <el-table-column label="部门" prop="departmentName" width="200"></el-table-column>
+      <el-table-column label="出勤天数" prop="workDays"></el-table-column>
+      <el-table-column label="休息天数" prop="restDays"></el-table-column>
+      <el-table-column label="迟到次数" prop="lateNum"></el-table-column>
+      <el-table-column label="早退次数" prop="leaveNum"></el-table-column>
+      <template v-for="col in dayColumns">
+        <el-table-column :label="col.label" :prop="col.name" :key="col.name" width="200">
+          <template slot-scope="{row}">
+            <div style="display:flex;flex-direction:column;">
+              <template v-for="(item,index) in row.workAttendanceMap[col.name]">
+                <div v-html="showItem(item)" :key="index"></div>
+              </template>
+            </div>
+          </template>
+        </el-table-column>
+      </template>
+    </el-table>
+    <el-pagination
+      :current-page.sync="pageIndex"
+      :total="totalElements"
+      :page-sizes="pageSizeList"
+      @current-change="changePage"
+      @size-change="pageSizeChange"
+      layout="total, sizes, prev, pager, next, jumper"
+    ></el-pagination>
+  </div>
+</template>
+<script>
+import Constant from "@/constant";
+import workScheduleReportApi from "@/api/business/workScheduleReport";
+import companyInfoApi from "@/api/base/companyInfo";
+import permissionApi from "@/api/sys/permission";
+import SelectTree from "@/components/SelectTree";
+
+import NProgress from "nprogress"; // progress bar
+import "nprogress/nprogress.css"; // progress bar style
+
+export default {
+  name: "BusinessWorkScheduleReport",
+  data() {
+    var self = this;
+
+    return {
+      ruleValidate: {
+        companyId: [{ required: true, message: "不能为空", trigger: "blur" }],
+        timeRanges: [
+          { required: true, message: "请选择时间范围", trigger: "blur" }
+        ]
+      },
+      queryModel: {
+        companyId: "",
+        timeRanges: "",
+        subordinate: false,
+        name: ""
+      },
+      loading: false,
+      loadingText: "加载中",
+      tableData: [],
+      pageIndex: 1,
+      pageSize: 20,
+      totalPages: 0,
+      totalElements: 0,
+      field: "",
+      direction: "",
+      pageSizeList: [20, 30, 50],
+      multipleSelection: [],
+      showModal: false,
+      modalTitle: "",
+      businessKey: "",
+      downloadLoading: false,
+      tableHeight: 400,
+      timeRangesDefaultTime: [],
+      companyResult: [],
+      editorOption: {
+        modules: {
+          toolbar: "title" // 设置文本编辑器的头部是否展示
+        },
+        placeholder: "", // 文本框为空时 , 占位文本
+        theme: "snow" // 或者为 `bubble`
+      },
+      downloadUrl: "",
+      dayColumns: [],
+      tmplKey: "",
+      treeData: [],
+      props: {
+        // 配置项(必选)
+        value: "id",
+        label: "name",
+        children: "children"
+      },
+      batchUpdateVisible: false
+    };
+  },
+  created() {
+    var self = this;
+    companyInfoApi.list().then(function(response) {
+      var jsonData = response.data;
+      if (jsonData.result) {
+        if (jsonData.data != null && jsonData.data != "") {
+          self.companyResult = jsonData.data;
+        }
+      }
+    });
+
+    permissionApi.hasPermission("post","/business/workScheduleReport/batchUpdate")
+    .then(response=>{
+      this.batchUpdateVisible = response.data.result;
+    });
+
+    this.getCurrentMonthFirst();
+    this.loadTree();
+  },
+  methods: {
+    getSelectedValue(value) {
+      this.queryModel.companyId = value;
+    },
+    loadTree() {
+      var formData = new FormData();
+
+      companyInfoApi.loadChildren(formData).then(resp => {
+        var jsonData = resp.data;
+
+        if (jsonData.result) {
+          this.treeData = jsonData.data;
+        } else {
+          this.$message.error(jsonData.message + "");
+        }
+      });
+    },
+    loadChildren(tree, treeNode, resolve) {
+      console.log(tree);
+
+      var formData = new FormData();
+      formData.append("parentId", tree.id);
+
+      companyInfoApi.loadChildren(formData).then(resp => {
+        var jsonData = resp.data;
+
+        if (jsonData.result) {
+          resolve(jsonData.data);
+        } else {
+          this.$message.error(jsonData.message + "");
+        }
+      });
+    },
+    indexMethod(index) {
+      return (this.pageIndex - 1) * this.pageSize + (index + 1);
+    },
+    changePage(pageIndex) {
+      var self = this;
+      self.pageIndex = pageIndex;
+
+      var formData = new FormData();
+
+      formData.append("pageIndex", self.pageIndex);
+      formData.append("pageSize", self.pageSize);
+
+      if (self.queryModel.companyId == null) {
+        self.queryModel.companyId = "";
+      }
+      
+      formData.append("companyId", self.queryModel.companyId);
+      formData.append("subordinate", self.queryModel.subordinate);
+
+      formData.append("name", self.queryModel.name);
+
+      var startDate = "";
+      var endDate = "";
+      var timeRanges = self.queryModel.timeRanges + "";
+
+      if (timeRanges != "" && timeRanges != null) {
+        timeRanges = timeRanges.split(",");
+        startDate = timeRanges[0];
+        endDate = timeRanges[1];
+      }
+
+      formData.append("startDate", startDate);
+      formData.append("endDate", endDate);
+
+      self.loading = true;
+      self.loadingText = "加载中";
+
+      workScheduleReportApi.statList(formData).then(function(response) {
+        var jsonData = response.data;
+
+        self.loading = false;
+
+        if (jsonData.result) {
+          self.tableData = jsonData.data.data;
+          self.totalPages = jsonData.data.totalPage;
+          self.totalElements = jsonData.data.totalElements;
+
+          self.dayColumns = jsonData.data.dayColumns;
+          self.tmplKey = jsonData.data.tmplKey;
+
+          //45为分页栏的高度
+          //页面高度-列表上面的高度-分页栏高度
+          self.tableHeight =
+            window.innerHeight - self.$refs.formTable.$el.offsetTop - 100;
+        } else {
+          self.$message({
+            type: "warning",
+            message: jsonData.message
+          });
+        }
+      });
+    },
+    pageSizeChange(pageSize) {
+      this.pageSize = pageSize;
+      this.changePage(1);
+    },
+    showItem(item) {
+      var content = [];
+
+      content.push(item.remark);
+
+      var fontColor = "";
+
+      if (item.result == "0") {
+        fontColor = "red";
+      } else if (item.result == "1") {
+        fontColor = "green";
+      } else if (item.result == "2") {
+        fontColor = "gray";
+      } else if (item.result == "3") {
+        fontColor = "gray";
+      }else if(item.result == "4"){
+        fontColor = "#11A8CD";
+      }
+
+      return `<font color='${fontColor}'>` + content.join("") + "</font>";
+    },
+    handleQuery() {
+      var self = this;
+
+      this.$refs["queryForm"].validate(valid => {
+        if (valid) {
+          self.changePage(1);
+        }
+      });
+    },
+    handleReset(name) {
+      this.$refs[name].resetFields();
+    },
+    exportXls() {
+      var self = this;
+
+      //导出
+      this.$refs["queryForm"].validate(valid => {
+        if (valid) {
+          self.downloadLoading = true;
+
+          var formData = new FormData();
+
+          if (self.queryModel.companyId == null) {
+            self.queryModel.companyId = "";
+          }
+          
+          formData.append("companyId", self.queryModel.companyId);
+          formData.append("subordinate", self.queryModel.subordinate);
+          formData.append("name", self.queryModel.name);
+
+          var startDate = "";
+          var endDate = "";
+          var timeRanges = self.queryModel.timeRanges + "";
+
+          if (timeRanges != "" && timeRanges != null) {
+            timeRanges = timeRanges.split(",");
+            startDate = timeRanges[0];
+            endDate = timeRanges[1];
+          }
+
+          formData.append("startDate", startDate);
+          formData.append("endDate", endDate);
+
+          workScheduleReportApi.exportXls(formData).then(function(response) {
+            var jsonData = response.data;
+
+            self.downloadLoading = false;
+
+            if (jsonData.result) {
+              if(document.location.href.startsWith("https://")){
+                  jsonData.data = jsonData.data.replace("http://","https://");
+              }
+
+              self.$message({
+                type: "success",
+                message: `报表已生成,<a href="${jsonData.data}">请点击链接下载</a>`,
+                dangerouslyUseHTMLString: true,
+                duration: 30000
+              });
+            } else {
+              self.$message({
+                type: "warning",
+                message: jsonData.message
+              });
+            }
+          });
+        }
+      });
+    },
+    //初始化日期
+    getCurrentMonthFirst() {
+      var self = this;
+      var date = new Date();
+      date.setDate(1);
+      var month = parseInt(date.getMonth() + 1);
+      var startTime = date.getFullYear() + "-" + month + "-" + date.getDate();
+
+      date.setMonth(date.getMonth()+1);
+      var lastDate = new Date(date.getTime()-1000*60*60*24);
+      
+      var endTime = lastDate.getFullYear() + "-" + month + "-" + lastDate.getDate();
+      
+      self.queryModel.timeRanges = [startTime, endTime];
+    },
+    handleBatchUpdate() {
+      var self = this;
+
+      self.$confirm("是否确认更新考勤数据?", "提示", {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+      }).then(() => {
+        var formData = new FormData();
+
+        formData.append("companyId", this.queryModel.companyId);
+        formData.append("startDate", this.queryModel.timeRanges[0]);
+        formData.append("endDate", this.queryModel.timeRanges[1]);
+
+        self.loading = true;
+        self.loadingText = "考勤数据生成中...";
+
+        workScheduleReportApi.batchUpdate(formData).then(function(response) {
+          var jsonData = response.data;
+
+          self.loading = false;
+
+          if (jsonData.result) {
+            self.$message({
+              type: "success",
+              message: jsonData.data + ""
+            });
+
+            self.handleQuery();
+          } else {
+            self.$message({
+              type: "warning",
+              message: jsonData.message + ""
+            });
+          }
+        });
+      });
+    }
+  },
+  mounted: function() {},
+
+  components: {
+    "el-select-tree": SelectTree
+  }
+};
+</script>
+<style lang="scss" scoped>
+.el-breadcrumb {
+  margin: 10px;
+  line-height: 20px;
+}
+
+.el-divider {
+  margin: 5px 0;
+}
+
+.demo-form-inline {
+  margin-left: 10px;
+  text-align: left;
+}
+
+.button-group {
+  margin-left: 10px;
+  text-align: left;
+}
+</style>