Browse Source

开门操作

刘琳琳 1 month ago
parent
commit
4b68b289db

+ 11 - 7
src/api/old_api_pengwenbing.js

@@ -120,6 +120,14 @@ export function restart(sn) {
   })
 }
 
+// 设备开门
+export function openDevice(sn) {
+  return request({
+    url: `/admin/face/openDoor/${sn}`,
+    method: 'get'
+  })
+}
+
 /** *********************************zyh_加入_logo管理*************************************************/
 
 // 获得logo
@@ -206,15 +214,11 @@ export function getMachineCompanyListSearch() {
   })
 }
 
-// 获取第三方设备名称列表-搜索
-export function getFaceLogStatusEnumSearch() {
+// 获取无效原因
+export function getReasonTypeEnumSearch() {
   return request({
     url: '/admin/face/getFaceLogStatusEnum',
-    method: 'get',
-    headers: {
-      'Content-Type': 'application/x-www-form-urlencoded'
-    },
-    data: {}
+    method: 'get'
   })
 }
 

BIN
src/assets/action-area-fold.png


BIN
src/assets/action-area-unfold.png


+ 71 - 3
src/views/area/index.vue

@@ -103,8 +103,39 @@
             <div class="content-item-id">{{ itemS.sn }}</div>
             <div class="content-item-name">{{ itemS.name }}</div>
             <div class="content-item-status">
-              <el-tag v-if="itemS.online === 1" type="success">在线</el-tag>
-              <el-tag v-else type="info">离线</el-tag>
+              <div>
+                <el-tag
+                  v-if="itemS.online === 1"
+                  effect="dark"
+                  style="border: 1px solid rgba(194, 231, 176, 1);background: transparent;color: rgba(103, 194, 58, 1);"
+                >
+                  在线
+                </el-tag>
+                <el-tag
+                  v-else
+                  effect="dark"
+                  style="border: 1px solid #E9E9EB;background: #F4F4F5;color: #909399"
+                >
+                  离线
+                </el-tag>
+              </div>
+              <div style="margin-left: 10px">
+                <el-tag
+                  v-if="itemS.openDoorSwitch"
+                  effect="dark"
+                  style="border: 1px solid transparent;background: #E6F1FF;color: #399BFF;border-radius: 17px;cursor: pointer"
+                  @click="openDevice(itemS.sn)"
+                >
+                  开门
+                </el-tag>
+                <el-tag
+                  v-else
+                  effect="dark"
+                  style="border: 1px solid transparent;background: #E8EDF7;color: #FFFFFF;border-radius: 17px"
+                >
+                  开门
+                </el-tag>
+              </div>
               <el-button
                 type="danger"
                 icon="el-icon-close"
@@ -138,7 +169,7 @@ import {
   deleteDeviceOfArea,
   platformSnList
 } from '@/api/area'
-import { getFaceDeviceList } from '@/api/old_api_pengwenbing'
+import { getFaceDeviceList, openDevice } from '@/api/old_api_pengwenbing'
 import tableMixins from '@/mixins/tableMixins'
 import Pagination from '@/components/Pagination'
 import AddModal from './modal/AddModal.vue'
@@ -318,6 +349,42 @@ export default {
         .then(() => {})
         .catch(() => {})
     },
+    // 设备开门
+    openDevice(deviceId) {
+      this.$confirm('确定开门吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        center: true
+      })
+        .then(() => {
+          const loading = this.$loading({
+            lock: true,
+            text: '设备开门中...',
+            spinner: 'el-icon-loading',
+            background: 'rgba(0, 0, 0, 0.7)'
+          })
+          openDevice(deviceId)
+            .then((response) => {
+              loading.close()
+              this.fetchData()
+              this.$message({
+                type: 'success',
+                message: '已开门!'
+              })
+            })
+            .catch(() => {
+              loading.close()
+            })
+        })
+        .catch(() => {
+          loading.close()
+          this.$message({
+            type: 'info',
+            message: '已取消开门'
+          })
+        })
+    },
     goLargeScreeno(item) {
       const id = window.btoa(item.id)
       window.location.href =
@@ -430,6 +497,7 @@ export default {
         }
         .content-item-id {
           flex: none;
+          min-width: 160px;
         }
         .content-item-name {
           flex: auto;

+ 100 - 16
src/views/machine_list/components/ysgz_machine_list.vue

@@ -277,25 +277,40 @@
         prop=""
         label="操作区"
         fixed="right"
-        :width="checkRole([1, 2]) ? '370' : '300'"
+        :width="checkRole([1, 2]) ? (isFold?'260':'360') : '260'"
       >
+        <template slot="header">
+          <div
+            v-if="checkRole([1, 2])"
+            style="padding: 0 10px;cursor:pointer;display: flex;justify-content: center;align-items: center"
+            @click="isFold = !isFold"
+          >
+            <img
+              v-if="isFold"
+              src="@/assets/action-area-unfold.png"
+              style="width: 16px;height: 16px;margin-right: 10px;"
+            >
+            <img
+              v-else
+              src="@/assets/action-area-fold.png"
+              style="width: 16px;height: 16px;margin-right: 10px;"
+            >操作区
+          </div>
+          <span v-else>操作区</span>
+        </template>
         <template slot-scope="scope">
           <el-button
-            v-if="checkRole([1, 2]) || (checkRole([5]) && placeType === 2)"
+            v-if="(checkRole([1, 2]) || (checkRole([5]) && placeType === 2)) && !isFold"
             type="danger"
             size="small"
+            style="width: 48px;height:32px;box-sizing: border-box;padding: 0 0"
             @click="deleteUser(scope.row.deviceId)"
           >删除</el-button>
           <el-button
-            v-if="checkRole([1, 2, 5])"
-            type="primary"
-            size="small"
-            @click="update(scope.row)"
-          >编辑</el-button>
-          <el-button
-            v-if="checkRole([1, 2])"
+            v-if="checkRole([1, 2]) && !isFold"
             :type="scope.row.auth === 1 ? 'warning' : 'success'"
             size="small"
+            style="width: 48px;height:32px;box-sizing: border-box;padding: 0 0"
             @click="
               scope.row.auth === 1
                 ? doStopFaceDevice(scope.row.deviceId)
@@ -303,25 +318,33 @@
             "
           >
             {{ scope.row.auth === 1 ? "停用" : "授权" }}</el-button>
+          <el-button
+            v-if="checkRole([1, 2, 5])"
+            type="primary"
+            size="small"
+            style="width: 48px;height:32px;box-sizing: border-box;padding: 0 0"
+            @click="update(scope.row)"
+          >编辑</el-button>
           <!-- <el-button type="primary" size="small" @click="clickIssue(scope.row.deviceId)"
             >下发</el-button
           > -->
           <el-button
-            v-if="checkRole([1, 2, 5])"
+            v-if="checkRole([1, 2, 5]) && scope.row.downFaceSwitch"
             :type="
-              scope.row.enable === 1 && scope.row.auth === 1
+               scope.row.enable === 1 && scope.row.auth === 1
                 ? 'primary'
                 : 'info'
             "
             plain
             size="small"
+            style="width: 48px;height:32px;box-sizing: border-box;padding: 0 0"
             :disabled="!(scope.row.enable === 1 && scope.row.auth === 1)"
             @click="clickIssue(scope.row.deviceId)"
           >
             下发
           </el-button>
           <el-button
-            v-if="checkRole([1, 2, 5])"
+            v-if="checkRole([1, 2, 5]) && scope.row.restartSwitch"
             :type="
               scope.row.online === 1 &&
                 scope.row.enable === 1 &&
@@ -331,6 +354,7 @@
             "
             plain
             size="small"
+            style="width: 48px;height:32px;box-sizing: border-box;padding: 0 0"
             :disabled="
               !(
                 scope.row.online === 1 &&
@@ -342,6 +366,28 @@
           >
             重启
           </el-button>
+          <el-button
+            v-if="checkRole([1, 2, 5]) && scope.row.openDoorSwitch"
+            :type="
+              scope.row.online === 1 &&
+                scope.row.enable === 1 &&
+                scope.row.auth === 1
+                ? 'primary'
+                : 'info'
+            "
+            plain
+            size="small"
+            style="width: 48px;height:32px;box-sizing: border-box;padding: 0 0"
+            :disabled="
+              !(
+                scope.row.online === 1 &&
+                scope.row.enable === 1 &&
+                scope.row.auth === 1)
+            "
+            @click="openDevice(scope.row.sn)"
+          >
+            开门
+          </el-button>
         </template>
       </el-table-column>
       <el-table-column
@@ -364,6 +410,7 @@
             >下发</el-button
           > -->
           <el-button
+            v-if="scope.row.downFaceSwitch"
             :type="
               scope.row.enable === 1 && scope.row.auth === 1
                 ? 'primary'
@@ -374,7 +421,7 @@
             :disabled="!(scope.row.enable === 1 && scope.row.auth === 1)"
             @click="clickIssue(scope.row.deviceId)"
           >
-            全量下发
+            下发
           </el-button>
         </template>
       </el-table-column>
@@ -646,7 +693,7 @@ import {
   issueAll,
   restart,
   getMachineCompanyListSearch,
-  getMachineTypeListSearch
+  getMachineTypeListSearch, openDevice
 } from '@/api/old_api_pengwenbing'
 import { checkRole, checkVisitorType } from '@/utils/checkRole'
 import { defaultTime } from '@/utils/defaultTime'
@@ -670,6 +717,7 @@ export default {
   },
   data() {
     return {
+      isFold: true, // 是否需要折叠
       role: this.$store.getters.role, // 角色
       placeType: this.$store.getters.placeType,
       isOpenPrivateArea: this.$store.getters.isOpenPrivateArea, // 是否开启私有区域
@@ -791,7 +839,7 @@ export default {
         {
           label: '设备SN',
           field: 'sn',
-          width: 150
+          width: 160
         }, {
           label: '设备地点',
           field: 'name',
@@ -818,7 +866,7 @@ export default {
         }, {
           label: '省-市-区',
           field: 'stateCityDistrictStreet',
-          width: 120
+          width: 160
         }, {
           label: '设备IP',
           field: 'interIp',
@@ -1212,6 +1260,42 @@ export default {
           })
         })
     },
+    // 设备开门
+    openDevice(deviceId) {
+      this.$confirm('确定开门吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+        center: true
+      })
+        .then(() => {
+          const loading = this.$loading({
+            lock: true,
+            text: '设备开门中...',
+            spinner: 'el-icon-loading',
+            background: 'rgba(0, 0, 0, 0.7)'
+          })
+          openDevice(deviceId)
+            .then((response) => {
+              loading.close()
+              this.fetchData()
+              this.$message({
+                type: 'success',
+                message: '已开门!'
+              })
+            })
+            .catch(() => {
+              loading.close()
+            })
+        })
+        .catch(() => {
+          loading.close()
+          this.$message({
+            type: 'info',
+            message: '已取消开门'
+          })
+        })
+    },
     // 获得省市县列表_搜索
     getAddressListSearch(type, code) {
       switch (type) {

+ 2 - 1
src/views/pass_records/components/DetailModule.vue

@@ -348,7 +348,7 @@ export default {
   display: flex;
   align-items: center;
   flex-wrap: wrap;
-  margin-top: 10px;
+  //margin-top: 10px;
 
   &-item {
     width: calc(100% / 3);
@@ -368,6 +368,7 @@ export default {
       font-weight: 400;
       min-height: 28px;
       line-height: 28px;
+      margin-bottom: 5px;
     }
   }
 }

+ 2 - 2
src/views/pass_records/components/ysgz_pass_records.vue

@@ -294,7 +294,7 @@ import {
   doGetFaceServerLog,
   downloadFaceLog,
   getFaceDeviceList,
-  getFaceLogStatusEnumSearch,
+  getReasonTypeEnumSearch,
   getMachineTypeListSearch,
   getVerifyTypeEnumList
 } from '@/api/old_api_pengwenbing'
@@ -591,7 +591,7 @@ export default {
      */
     async initData() {
       const verifyTypeAxios = await getVerifyTypeEnumList()
-      const faceLogAxios = await getFaceLogStatusEnumSearch()
+      const faceLogAxios = await getReasonTypeEnumSearch()
       const machineTypeAxios = await getMachineTypeListSearch()
       const machineAxios = await getFaceDeviceList()
       const userAxios = await getUserListSearch()

+ 2 - 1
src/views/visitors_list/component/DetailModule.vue

@@ -279,7 +279,7 @@ export default {
   display: flex;
   //align-items: center;
   flex-wrap: wrap;
-  margin-top: 10px;
+  //margin-top: 10px;
 
   &-item {
     width: calc(100% / 3);
@@ -299,6 +299,7 @@ export default {
       font-weight: 400;
       min-height: 28px;
       line-height: 28px;
+      margin-bottom: 5px;
     }
   }
 }

+ 2 - 1
src/views/visitors_record/compoment/DetailModule.vue

@@ -439,7 +439,7 @@ export default {
   display: flex;
   align-items: center;
   flex-wrap: wrap;
-  margin-top: 10px;
+  //margin-top: 10px;
 
   &-item {
     width: calc(100% / 3);
@@ -459,6 +459,7 @@ export default {
       font-weight: 400;
       min-height: 28px;
       line-height: 28px;
+      margin-bottom: 5px;
     }
   }
 }

+ 2 - 2
src/views/visitors_record/index.vue

@@ -290,7 +290,7 @@ import {
 } from '@/api/user_manage'
 import {
   getFaceDeviceList,
-  getFaceLogStatusEnumSearch,
+  getReasonTypeEnumSearch,
   getMachineTypeListSearch,
   getVerifyTypeEnumList
 } from '@/api/old_api_pengwenbing'
@@ -710,7 +710,7 @@ export default {
      */
     async initData() {
       const verifyTypeAxios = await getVerifyTypeEnumList()
-      const faceLogAxios = await getFaceLogStatusEnumSearch()
+      const faceLogAxios = await getReasonTypeEnumSearch()
       const machineTypeAxios = await getMachineTypeListSearch()
       const machineAxios = await getFaceDeviceList()
       const userAxios = await getUserListSearch()

+ 5 - 0
src/views/white_list/component/AddModal.vue

@@ -737,6 +737,11 @@ export default {
               this.matchIdNumberOrPhone(this.form) &&
               this.combineValue()
             ) {
+              if (this.dialogType === 'add') {
+                this.form.inputType = 1
+              } else if (this.dialogType === 'artificial') {
+                this.form.inputType = 2
+              }
               if (this.form.inputType == 1) {
                 this.form.idNumberType = 1
               }

+ 652 - 0
src/views/white_list/component/BatchUpdateModal.vue

@@ -0,0 +1,652 @@
+<!--批量编辑-弹框-->
+<template>
+  <div>
+    <el-dialog
+      :title="dialogTitle"
+      width="1200px"
+      :visible.sync="dialogVisible"
+      :destroy-on-close="false"
+      :close-on-click-modal="false"
+      @close="closeBatch"
+    >
+      <p class="text-color">
+        在“比对唯一参数”里选择一项作为更新文件里的数据和后台数据进行寻找匹配的标准参数值。上传excel更新文件后,根据选择的比对唯一参数寻找匹配对应的后台数据,更新文件里填写的内容在匹配上对应的后台数据后将覆盖更新,没填写的内容将不进行覆盖更新。
+      </p>
+      <el-form
+        ref="form"
+        :rules="rules"
+        :model="form"
+        label-position="left"
+        label-width="120px"
+        enctype="multipart/form-data"
+      >
+        <el-form-item
+          label="对比唯一参数"
+          prop="uniqueCode"
+          class="form-item-style"
+        >
+          <el-radio-group v-model="form.uniqueCode">
+            <el-radio :label="1">身份证号</el-radio>
+            <el-radio :label="2">手机号</el-radio>
+            <el-radio :label="3">卡号</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="上传Excel文件" prop="file">
+          <a href="javascript:;" class="file">
+            上传文件
+            <input
+              ref="file"
+              type="file"
+              name="file"
+              @change="batchEditUpload($event)"
+            >
+          </a>
+          <span style="margin-left: 8px">
+            {{ form.file ? form.fileName : "" }}</span>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="closeBatch"> 取消 </el-button>
+        <el-button type="primary" @click="batchEditFun"> 确定 </el-button>
+      </div>
+    </el-dialog>
+    <!-- 批量注册人员-抽屉 -->
+    <el-drawer
+      :title="hasCompleted ? '导入已完成' : '正在处理中..'"
+      :visible.sync="drawerVisible"
+      :wrapper-closable="false"
+      size="50%"
+      direction="rtl"
+    >
+      <div style="padding: 50px">
+        <div>
+          已处理条数;{{ hasDealNumber }}; 待处理条数:{{ waitDealNumber }};
+          总共条数:{{ allNumber }}
+        </div>
+        <el-progress
+          :percentage="makePercent"
+          :format="formatProgress"
+          style="margin-top: 10px"
+        />
+        <el-table
+          ref="batch_upload_result"
+          v-loading="false"
+          :data="batchUploadResultList"
+          class="table"
+          element-loading-text="Loading"
+          border
+          fit
+          highlight-current-row
+          height="500"
+        >
+          <el-table-column label="错误序号" align="center" width="100px">
+            <template slot-scope="scope">
+              {{ scope.$index + 1 }}
+            </template>
+          </el-table-column>
+          <el-table-column label="错误描述" align="center">
+            <template slot-scope="scope">
+              {{ scope.row.err }}
+            </template>
+          </el-table-column>
+        </el-table>
+        <div style="text-align: center; margin: 20px 0">
+          <el-button type="primary" @click="drawerVisible = false">
+            我已知晓
+          </el-button>
+          <el-button type="warning" @click="downloadBatchUploadErrorList">
+            下载错误列表文件
+          </el-button>
+        </div>
+      </div>
+    </el-drawer>
+  </div>
+</template>
+
+<script>
+import BatchUpload from '@/components/BatchUpload'
+import { checkRole } from '@/utils/checkRole'
+import { readExcel } from '@/utils/getExcelList'
+import { batchEditUserWhitelist } from '@/api/user_manage'
+import { insert } from '@/api/ordinary_user'
+import { parseTime } from '@/utils'
+export default {
+  components: { BatchUpload },
+  props: {
+    contents: {
+      type: Array,
+      default: () => {
+
+      }
+    }
+  },
+  data() {
+    return {
+      buyList: [],
+      form: {
+        uniqueCode: null,
+        fileName: null,
+        file: null,
+        warningPersonCheckListDtoList: [
+          {
+            documentType: '',
+            idNumber: '',
+            name: '',
+            warningType: ''
+          }
+        ],
+        correctList: {
+          correct: [],
+          incorrect: []
+        }
+      },
+      rules: {
+        uniqueCode: [{ required: true, message: '请选择', trigger: 'blur' }],
+        file: [{ required: true, message: '请选择', trigger: 'blur' }]
+      },
+      dialogVisible: false,
+      // 批量注册-处理提示值
+      hasDealNumber: 0,
+      waitDealNumber: 0,
+      allNumber: 0,
+      hasCompleted: false,
+      // 批量注册-抽屉控制值
+      drawerVisible: false,
+      batchUploadResultList: [],
+      //
+      arr: [],
+      dialogTitle: '',
+      isEdit: false
+    }
+  },
+  computed: {
+    // 批量注册-返回向下取整,减少渲染次数
+    makePercent() {
+      if (this.allNumber === 0 || this.hasDealNumber === 0) {
+        return 0
+      }
+      return Math.floor((this.hasDealNumber / this.allNumber) * 100)
+    }
+  },
+  created() {
+    // console.log(this.option,7);
+  },
+  methods: {
+    checkRole,
+    upload(e) {
+      console.log(e)
+      // 处理excel
+      this.form.file = e.target.files[0]
+    },
+    open() {
+      this.dialogVisible = true
+      this.$nextTick(() => {
+        this.$refs.form.resetFields()
+        this.dialogTitle = '批量编辑'
+        this.isEdit = false
+      })
+    },
+    batchUploadResult(correctList) {
+      if (this.type === 'button') {
+        this.getFileList(correctList)
+      } else {
+        this.form.correctList = correctList
+      }
+    },
+    // 批量注册人员-操作
+    getFileList(correctList) {
+      this.hasCompleted = false
+      this.drawerVisible = true
+      this.hasDealNumber = correctList.incorrect.length
+      this.waitDealNumber = correctList.correct.length
+      this.allNumber =
+        correctList.incorrect.length + correctList.correct.length
+      this.batchUploadResultList = correctList.incorrect.map((item) => {
+        return { name: item.file.name, err: item.reason }
+      })
+      this.makeScrollDown()
+      this.arr = []
+      this.doSubmitUrl(correctList, 0)
+    },
+    // 批量注册人员-并提交至添加到接口
+    async doSubmitUrl(correctList, index) {
+      const that = this
+      if (index <= correctList.correct.length - 1) {
+        const item = correctList.correct[index]
+        // 组装数据上传
+        const data = JSON.parse(JSON.stringify(this.form))
+        const warningParams = {
+          name: item['人员姓名'],
+          documentType: item['证件类型'],
+          idNumber: item['证件号'],
+          warningType: item['布控人员类型']
+        }
+        if (
+          warningParams.name &&
+          warningParams.documentType &&
+          warningParams.idNumber &&
+          warningParams.warningType
+        ) {
+          let err = ''
+          if (warningParams.documentType == '身份证号') {
+            warningParams.documentType = 2
+          } else if (warningParams.documentType == '护照') {
+            warningParams.documentType = 1
+          }
+          if (warningParams.documentType === 2 && !/^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dxX]$/.test(warningParams.idNumber)
+          ) {
+            err = '身份证长度或格式有误'
+          }
+
+          if (err) {
+            this.batchUploadResultList.push({
+              index: '第' + index + '行',
+              err: err
+            })
+          } else {
+            try {
+              this.arr.push(warningParams)
+            } catch (err) {
+              // console.log(err);
+              this.batchUploadResultList.push({
+                index: '第' + index + '行',
+                err: err
+              })
+            }
+          }
+        } else {
+          if (!warningParams.name) {
+            this.batchUploadResultList.push({
+              index: '第' + index + '行',
+              err: '人员姓名不能为空'
+            })
+          }
+          if (!warningParams.documentType) {
+            this.batchUploadResultList.push({
+              index: '第' + index + '行',
+              err: '证件类型不能为空'
+            })
+          }
+          if (!warningParams.idNumber) {
+            this.batchUploadResultList.push({
+              index: '第' + index + '行',
+              err: '证件号不能为空'
+            })
+          }
+          if (!warningParams.warningType) {
+            this.batchUploadResultList.push({
+              index: '第' + index + '行',
+              err: '布控人员类型不能为空'
+            })
+          }
+        }
+        this.hasDealNumber += 1
+        this.waitDealNumber -= 1
+        this.makeScrollDown()
+        // 继续调用
+        this.doSubmitUrl(correctList, ++index)
+      } else {
+        if (this.batchUploadResultList.length == 0) {
+          const controlStartTime = this.form.time[0]
+          const controlEndTime = this.form.time[1]
+          const managePhone = this.form.phone.split(',').map((item) => item)
+          if (this.isEdit) {
+            /* await getwarningPersonRectify({
+              ...this.form,
+              controlStartTime,
+              controlEndTime,
+              managePhone,
+              warningPersonCheckListDtoList: this.arr
+            }) */
+          } else {
+            /* await getwarningPersonInsert({
+              ...this.form,
+              controlStartTime,
+              controlEndTime,
+              managePhone,
+              warningPersonCheckListDtoList: this.arr
+            }) */
+          }
+        }
+        this.hasCompleted = true
+        this.$emit('finish')
+      }
+    },
+    // 批量注册人员-保持滚动条在最底部
+    makeScrollDown() {
+      this.$nextTick(() => {
+        this.$refs.batch_upload_result.$refs.bodyWrapper.scrollTop =
+          this.$refs.batch_upload_result.$refs.bodyWrapper.scrollHeight
+      })
+    },
+    // 批量注册人员-返回进度条尾部显示值
+    formatProgress(percent) {
+      return percent === 100 ? '已完成' : ''
+    },
+    // 批量注册人员-导出错误名单
+    downloadBatchUploadErrorList() {
+      const list = this.batchUploadResultList
+      let string = '序号\t设备sn\t错误原因\n'
+      for (let i = 0; i < this.batchUploadResultList.length; i++) {
+        string +=
+          (i + 1).toString() +
+          '\t' +
+          list[i].sn +
+          '\t' +
+          list[i].err +
+          '\t' +
+          '\n'
+      }
+      const blob = new Blob([string], { type: 'text/plain;charset=utf-8' })
+      const excel_url = window.URL.createObjectURL(blob)
+      const link = document.createElement('a')
+      link.href = excel_url
+      link.download = '批量注册结果错误名单.xls'
+      document.body.appendChild(link)
+      link.click()
+      document.body.removeChild(link)
+    },
+    batchEditUpload(e) {
+      this.form.fileName = e.target.files[0].name
+      this.form.file = e.currentTarget.files
+    },
+    closeBatch() {
+      this.form = {
+        uniqueCode: null,
+        fileName: null,
+        file: null
+      }
+      this.dialogVisible = false
+    },
+    // 批量编辑
+    batchEditFun(e) {
+      e.preventDefault()
+      this.$refs.form.validate((valid) => {
+        console.log(valid)
+        if (valid) {
+          this.dialogVisible = false
+          this.uploadFun(
+            this.form.file,
+            'batchEdit',
+            this.form.uniqueCode
+          )
+        }
+      })
+    },
+    // 批量导入
+    async uploadFun(e, type, uniqueCode) {
+      console.log('uploadFun', e, type, uniqueCode)
+      this.loading = true
+      let files
+      if (type) {
+        files = e
+      } else {
+        files = e.currentTarget.files
+      }
+      if (!files.length) {
+        return
+      }
+      let data = await readExcel(files[0]) // file指的是获取的excel文件对象,如e.file
+      const newData = []
+      data.forEach((i) => {
+        for (const key in i) {
+          if (i[key]) {
+            newData.push(i)
+            return
+          }
+        }
+      })
+      data = newData
+      this.loading = false
+      this.allNumber = data.length
+      this.drawerVisible = true
+      this.doUploadAddUserInfo(0, data, type, uniqueCode)
+      e.target.value = ''
+    },
+    // 递归调用校验数据并请求
+    async doUploadAddUserInfo(i, data, type, uniqueCode) {
+      if (i > data.length - 1) {
+        this.hasCompleted = true
+        this.$emit('finish')
+        this.$message.success('操作已完成!')
+        return
+      }
+
+      const form = {}
+      if (this.contents && this.contents.length > 0) {
+        form.addCustomList = JSON.parse(
+          JSON.stringify(this.contents)
+        )
+        for (var k in form.addCustomList) {
+          form.addCustomList[k].customNameVal =
+            data[i][form.addCustomList[k].customName]
+        }
+      }
+      form.name = data[i]['姓名']
+      form.phone = data[i]['手机号']
+      form.idNumber = data[i]['身份证号']
+      form.personnelType1 = data[i]['人员类型']
+      if (form.personnelType1) {
+        switch (form.personnelType1) {
+          case '学生':
+            form.personnelType = 1
+            break
+          case '教职工':
+            form.personnelType = 2
+            break
+          default:
+            break
+        }
+      }
+      form.startTime = data[i]['开始有效期']
+      if (form.startTime) {
+        form.startTime = parseTime(form.startTime, '{y}-{m}-{d} {h}:{i}:{s}')
+      }
+      form.endTime = data[i]['结束有效期']
+      if (form.endTime) {
+        form.endTime = parseTime(form.endTime, '{y}-{m}-{d} {h}:{i}:{s}')
+      }
+      form.cardIdEx = data[i]['物理卡号']
+      form.adminName = data[i]['账号名称']
+      form.adminAreaTypeName = data[i]['通行区域权限']
+      if (data[i]['私有区域']) {
+        form.privateAreaName = data[i]['私有区域'].toString().split(',')
+      }
+      form.inputType = 1
+      form.pushType = 1
+      if (type) {
+        await this.isPassBatchEditFun(form, i, uniqueCode).then(async(res) => {
+          let timeout = 0
+          if (res.isOk) {
+            await this.batchEditUserWhitelist(data, form, i, uniqueCode)
+          } else {
+            this.getFileList1(data, i, res, form)
+            timeout = 0
+          }
+          this.hasDealNumber = i + 1
+          this.waitDealNumber = data.length - (i + 1)
+          setTimeout(() => {
+            this.doUploadAddUserInfo(++i, data, type, uniqueCode)
+          }, timeout)
+        })
+      } else {
+        await this.isPassFun(form, i).then(async(res) => {
+          let timeout = 0
+          if (res.isOk) {
+            await this.addUserInfo(data, form, i)
+          } else {
+            this.getFileList1(data, i, res, form)
+            timeout = 0
+          }
+          this.hasDealNumber = i + 1
+          this.waitDealNumber = data.length - (i + 1)
+          setTimeout(() => {
+            this.doUploadAddUserInfo(++i, data, type, uniqueCode)
+          }, timeout)
+        })
+      }
+    },
+    // 批量导入-推入错误信息
+    getFileList1(data, i, isPass) {
+      // this.initAddress(this.user_form.contents);
+      this.batchUploadResultList.push(isPass.incorrect)
+      this.makeScrollDown()
+    },
+    // 校验批量编辑模板数据内容
+    async isPassBatchEditFun(form, i) {
+      const isPass = {
+        isOk: true,
+        incorrect: {
+          name: `第${i + 1}行`,
+          err: ''
+        }
+      }
+      switch (this.form.uniqueCode) {
+        case 1:
+          if (!form.idNumber) {
+            isPass.isOk = false
+            isPass.incorrect.err = '身份证号为必填'
+            return isPass
+          }
+          // if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(form.idNumber)) {
+          //   isPass.isOk = false;
+          //   isPass.incorrect.err = "身份证长度或格式有误";
+          //   return isPass;
+          // }
+          break
+        case 2:
+          if (!form.phone) {
+            isPass.isOk = false
+            isPass.incorrect.err = '手机号为必填'
+            return isPass
+          }
+          if (form.phone && !/^[0-9]*$/.test(form.phone)) {
+            isPass.isOk = false
+            isPass.incorrect.err = '手机号只能由数字组成'
+            return isPass
+          }
+          break
+        case 3:
+          if (!form.cardIdEx) {
+            isPass.isOk = false
+            isPass.incorrect.err = '卡号为必填'
+            return isPass
+          }
+          break
+        default:
+          break
+      }
+      if (form.adminName) {
+        const index = this.enterprise_list.findIndex((item) => {
+          return item.username === form.adminName
+        })
+        if (index > -1) {
+          form.adminId = this.enterprise_list[index].adminId
+        } else {
+          isPass.isOk = false
+          isPass.incorrect.err = '账号名称有误'
+          return isPass
+        }
+      }
+      return new Promise((resolve) => {
+        resolve(isPass)
+      })
+    },
+    // 常客的批量编辑
+    async batchEditUserWhitelist(data, form, i, uniqueCode) {
+      form.uniqueCode = uniqueCode
+      await batchEditUserWhitelist(form)
+        .then((res) => {})
+        .catch((err) => {
+          this.batchUploadResultList.push({ name: `第${i + 1}行`, err: err })
+          this.makeScrollDown()
+        })
+    },
+    // 批量导入-调用添加员工接口
+    async addUserInfo(data, form, i) {
+      await insert(form)
+        .then((res) => {})
+        .catch((err) => {
+          this.batchUploadResultList.push({ name: `第${i + 1}行`, err: err })
+          this.makeScrollDown()
+        })
+    },
+    submit(e) {
+      e.preventDefault()
+      this.$refs.form.validate((valid) => {
+        if (!valid) {
+          return false
+        }
+        this.dialogVisible = false
+        this.getFileList(this.form.correctList)
+      })
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.batchVisible {
+  ::v-deep .el-dialog__body {
+    padding-top: 0;
+  }
+}
+.text-color {
+  color: #b9becb;
+  font-size: 13px;
+  line-height: 20px;
+}
+::v-deep .el-select {
+  width: 100%;
+}
+.table {
+  margin-top: 15px;
+}
+.flex {
+  width: 100%;
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+}
+.dialog-top {
+  padding: 16px;
+  background-color: #ff5c651a;
+  color: #ff4747;
+  font-size: 16px;
+  font-weight: 600;
+  border-radius: 10px;
+  margin-bottom: 10px;
+}
+/*批量导入按钮*/
+.file {
+  margin: 10px 10px 0 10px;
+  position: relative;
+  background: #d0eeff;
+  border: 1px solid #99d3f5;
+  border-radius: 4px;
+  padding: 12px 20px;
+  box-sizing: border-box;
+  overflow: hidden;
+  color: #1e88c7;
+  text-decoration: none;
+  text-indent: 0;
+  font-size: 14px;
+
+  input {
+    position: absolute;
+    font-size: 14px;
+    width: 106px;
+    height: 40px;
+    left: 0;
+    top: 0;
+    opacity: 0;
+    cursor: pointer;
+  }
+  &:hover {
+    background: #aadffd;
+    border-color: #78c3f3;
+    color: #004974;
+    text-decoration: none;
+  }
+}
+</style>

+ 2 - 1
src/views/white_list/component/DetailModal.vue

@@ -162,7 +162,7 @@ export default {
   display: flex;
   align-items: center;
   flex-wrap: wrap;
-  margin-top: 10px;
+  //margin-top: 10px;
 
   &-item {
     width: calc(100% / 3);
@@ -182,6 +182,7 @@ export default {
       font-weight: 400;
       min-height: 28px;
       line-height: 28px;
+      margin-bottom: 5px;
     }
   }
 }

+ 2 - 2
vue.config.js

@@ -36,9 +36,9 @@ module.exports = {
     // },
     proxy: {
       '/yx-fyzd': {
-        target: 'https://test.hz-hanghui.com:18890' // 测试
+        // target: 'https://test.hz-hanghui.com:18890' // 测试
         // target: 'https://tx.hz-hanghui.com:8088' // 线上
-        // target: 'http://192.168.77.253:9100' // 本地
+        target: 'http://192.168.77.253:9100' // 本地
       }
     }
     // 关闭mock