Browse Source

门禁日志

master
xuhuajiao 5 months ago
parent
commit
49cea0bef2
  1. 40
      src/api/system/zkt.js
  2. 2
      src/utils/request.js
  3. 45
      src/views/components/SecurityDoor.vue
  4. 251
      src/views/system/logManage/doorLog/index.vue

40
src/api/system/zkt.js

@ -0,0 +1,40 @@
import request from '@/utils/request'
// import qs from 'qs'
// 编辑skt设置
export function add(data) {
return request({
url: 'api/securitydoor/editZktParam',
method: 'post',
data
})
}
// 获取ZKT门禁信息
export function FetchZKTDoorList(params) {
return request({
url: 'api/securitydoor/getZKTDoorList',
method: 'get',
params
})
}
// 初始化skt
export function FetchInitZktParam(params) {
return request({
url: 'api/securitydoor/initZktParam',
method: 'get',
params
})
}
// 实时获取ZKT门禁日志
export function FetchRealTimeZKTLog(params) {
return request({
url: 'api/securitydoor/realTimeZKTLog',
method: 'get',
params
})
}
export default { add, FetchZKTDoorList, FetchInitZktParam, FetchRealTimeZKTLog }

2
src/utils/request.js

@ -39,6 +39,8 @@ service.interceptors.response.use(
if (response.data.code) { if (response.data.code) {
if (response.data.code === 200) { if (response.data.code === 200) {
return response.data.data return response.data.data
} else if (response.data.code === -1 || response.data.code === 0) {
return response.data
} else if (response.data instanceof Blob) { } else if (response.data instanceof Blob) {
return response.data return response.data
} else { } else {

45
src/views/components/SecurityDoor.vue

@ -8,28 +8,37 @@
</p> </p>
</h3> </h3>
<el-table ref="table" style="min-width: 100%;" :height="height" :data="tableData" class="warehose-el-table" stripe @row-click="toPage"> <el-table ref="table" style="min-width: 100%;" :height="height" :data="tableData" class="warehose-el-table" stripe @row-click="toPage">
<el-table-column prop="hisTime" label="时间" align="center" width="160">
<el-table-column prop="eventTime" label="时间" align="center" width="160" />
<el-table-column prop="eventPointName" label="事件点" align="center" width="140" />
<el-table-column prop="eventLevel" label="事件描述">
<template slot-scope="scope"> <template slot-scope="scope">
<div>{{ scope.row.hisTime | parseTime }}</div>
</template>
</el-table-column>
<el-table-column label="位置" align="center" width="120">
<template slot-scope="scope">
<div>{{ scope.row.doorName }}</div>
</template>
</el-table-column>
<el-table-column prop="inOrOut" label="说明" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.inOrOut===0">{{ scope.row.userName }}_进门_{{ scope.row.action }}</el-tag>
<el-tag v-if="scope.row.inOrOut===1" type="warning">{{ scope.row.userName }}_出门_{{ scope.row.action }}</el-tag>
<!-- eventLevel 0 -->
<el-tag v-if="scope.row.eventLevel===0">
<span v-if="scope.row.name">{{ scope.row.name }}</span>
<i v-if="scope.row.name">_</i>
<span v-if="scope.row.eventName">{{ scope.row.eventName }}</span>
</el-tag>
<!-- eventLevel 1 -->
<el-tag v-if="scope.row.eventLevel===1" type="warning">
<span v-if="scope.row.name">{{ scope.row.name }}</span>
<i v-if="scope.row.name">_</i>
<span v-if="scope.row.eventName">{{ scope.row.eventName }}</span>
</el-tag>
<!-- eventLevel 2 -->
<el-tag v-if="scope.row.eventLevel===2" type="danger">
<span v-if="scope.row.name">{{ scope.row.name }}</span>
<i v-if="scope.row.name">_</i>
<span v-if="scope.row.eventName">{{ scope.row.eventName }}</span>
</el-tag>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
</template> </template>
<script> <script>
import { securitydoor } from '@/api/home/securityDoor/securityDoor'
import { FetchRealTimeZKTLog } from '@/api/system/zkt'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
export default { export default {
name: 'SecurityDoor', name: 'SecurityDoor',
props: { props: {
@ -130,9 +139,11 @@ export default {
} }
}, },
getSecuritydoor() { getSecuritydoor() {
securitydoor({ page: 0, size: 30 }).then((data) => {
if (data.content && data.content.length > 0) {
this.tableData.splice(0, data.content.length, ...data.content)
FetchRealTimeZKTLog({ pageNo: 1, pageSize: 20 }).then((data) => {
const result = JSON.parse(data)
console.log(result)
if (result && result.length > 0) {
this.tableData.splice(0, result.length, ...result)
} }
}) })
} }

251
src/views/system/logManage/doorLog/index.vue

@ -1,20 +1,28 @@
<template> <template>
<div> <div>
<div class="head-container">
<!-- <crudOperation /> -->
<!-- <el-button v-permission="permission.download" :loading="crud.downloadLoading" :disabled="!selections.length" size="mini" icon="el-icon-download" @click="handleDownload">导出</el-button> -->
<div class="head-container" style="display: flex;justify-content: space-between; align-items: center">
<div>
<el-button :loading="crud.downloadLoading" size="mini" icon="el-icon-download" @click="handleDownload">导出</el-button> <el-button :loading="crud.downloadLoading" size="mini" icon="el-icon-download" @click="handleDownload">导出</el-button>
<!-- 事件等级 -->
<el-select v-model="eventLevel" clearable size="small" placeholder="事件等级" class="filter-item" style="width: 120px; margin-left: 10px; margin-right: 0;" @change="stateSelect">
<i slot="prefix" class="iconfont icon-zhuangtai-fanbai" />
<el-option v-for="item in levelOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<!-- 设备名称 -->
<el-select v-model="sn" clearable size="small" placeholder="设备名称" class="filter-item" style="width: 150px; margin-left: 10px; margin-right: 0;" @change="snSelect">
<el-option v-for="item in snOptions" :key="item.sn" :label="item.name" :value="item.sn" />
</el-select>
<el-input <el-input
v-model="keyWord" v-model="keyWord"
size="small" size="small"
clearable clearable
placeholder="请输入关键词" placeholder="请输入关键词"
style="width: 300px;margin-right:10px;padding-left:10px"
style="width: 320px;margin-right:10px;padding-left:10px"
class="input-prepend filter-item" class="input-prepend filter-item"
@clear="crud.toQuery"
@keyup.enter.native="crud.toQuery" @keyup.enter.native="crud.toQuery"
> >
<!-- <el-select slot="prepend" v-model="optionVal" style="width: 100px" @keyup.enter.native="crud.toQuery"> -->
<el-select slot="prepend" v-model="optionVal" style="width: 80px">
<el-select slot="prepend" v-model="optionVal" style="width: 100px">
<el-option <el-option
v-for="item in options" v-for="item in options"
:key="item.value" :key="item.value"
@ -26,6 +34,8 @@
<date-range-picker v-model="queryTime" class="date-item" /> <date-range-picker v-model="queryTime" class="date-item" />
<rrOperation /> <rrOperation />
</div> </div>
<el-button size="mini" icon="el-icon-setting" @click="setDevice">设置</el-button>
</div>
<el-table <el-table
ref="table" ref="table"
:data="crud.data" :data="crud.data"
@ -35,44 +45,71 @@
@row-click="clickRowHandler" @row-click="clickRowHandler"
@selection-change="selectionChangeHandler" @selection-change="selectionChangeHandler"
> >
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="lsh" label="流水号" min-width="100" align="center" />
<el-table-column prop="userName" label="姓名" min-width="100" align="center" />
<el-table-column prop="employeeId" label="工号" min-width="140" align="center" />
<el-table-column prop="cardNo" label="卡编号" min-width="140" align="center" />
<el-table-column prop="cardCode" label="卡内码" min-width="140" align="center" />
<el-table-column prop="departmentName" label="部门" min-width="140" align="center" />
<el-table-column prop="doorName" label="门区" min-width="100" align="center" />
<el-table-column prop="inOrOut" label="事件" align="center" min-width="150">
<template slot-scope="scope">
<el-tag v-if="scope.row.inOrOut===0">进门</el-tag>
<el-tag v-if="scope.row.inOrOut===1" type="warning">出门</el-tag>
</template>
</el-table-column>
<el-table-column prop="hisTime" label="记录时间" align="center" min-width="150">
<!-- <el-table-column type="selection" width="55" align="center" /> -->
<el-table-column prop="areaName" label="区域名称" min-width="120" align="center" />
<el-table-column prop="devName" label="设备名称" min-width="230" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<div>{{ scope.row.hisTime | parseTime }}</div>
{{ scope.row.devName + "("+ scope.row.devSn + ")" }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="action" label="动作类型" align="center" min-width="180" />
<el-table-column prop="createTime" label="创建时间" align="center" min-width="180">
<el-table-column prop="eventPointName" label="事件点" min-width="130" />
<el-table-column prop="eventName" label="事件描述" min-width="150" />
<el-table-column prop="eventLevel" label="事件级别" align="center" min-width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
<el-tag v-if="scope.row.eventLevel==='0'">正常</el-tag>
<el-tag v-if="scope.row.eventLevel==='1'" type="warning">异常</el-tag>
<el-tag v-if="scope.row.eventLevel==='2'" type="danger">报警</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<!-- <el-table-column prop="alarmEvent" label="事件" min-width="150" align="center">
<el-table-column prop="pin" label="人员编号" min-width="100" align="center" />
<el-table-column prop="name" label="姓名" min-width="100" align="center" />
<el-table-column prop="cardNo" label="卡号" min-width="100" align="center" />
<el-table-column prop="verifyModeName" label="验证方式" min-width="140" align="center" />
<el-table-column prop="eventTime" label="时间" align="center" min-width="150" />
<el-table-column prop="capturePhotoBase64" label="媒体文件" align="center" min-width="140">
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if="scope.row.alarmEvent===0"></span>
<span v-if="scope.row.alarmEvent===1"></span>
<div v-if="scope.row.capturePhotoBase64"><el-button @click="showCoverPreview(scope.row.capturePhotoBase64)">查看</el-button></div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="borrowerName" label="用户" align="center" min-width="150" /> -->
</el-table> </el-table>
<pagination /> <pagination />
<el-dialog class="params-dialog" :close-on-click-modal="false" :visible.sync="bindParamsVisible" title="参数设置" :before-close="handleClose">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog">
<el-form ref="form" :model="form" inline :rules="rules" size="small" label-width="90px">
<el-form-item label="接口地址" prop="zktUrl">
<el-input v-model="form.zktUrl" placeholder="例如:https://192.168.1.100" style="width: 370px;" />
</el-form-item>
<el-form-item label="端口" prop="zktPort">
<el-input v-model="form.zktPort" style="width: 370px;" />
</el-form-item>
<el-form-item label="Token" prop="zktApitoken">
<el-input v-model="form.zktApitoken" style="width: 370px;" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button class="filter-item" size="mini" type="primary" @click="saveData">保存</el-button>
</div>
</div>
</el-dialog>
<!-- 点击缩略图看大图 -->
<el-dialog class="preview-dialog" :append-to-body="true" :close-on-click-modal="false" :before-close="handlePreview" :visible="showCoverVisible" title="媒体文件">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog" style="max-height:calc(100vh - 230px); overflow:auto;">
<img style="display: block;max-width:100%; object-fit: contain; margin: 0 auto;" :src="previewSrc" :onerror="defaultImg">
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { add, FetchZKTDoorList, FetchInitZktParam } from '@/api/system/zkt'
import rrOperation from '@crud/RR.operation' import rrOperation from '@crud/RR.operation'
import CRUD, { presenter, crud } from '@crud/crud' import CRUD, { presenter, crud } from '@crud/crud'
import DateRangePicker from '@/components/DateRangePicker' import DateRangePicker from '@/components/DateRangePicker'
@ -86,7 +123,7 @@ export default {
mixins: [presenter(), crud()], mixins: [presenter(), crud()],
cruds() { cruds() {
return CRUD({ return CRUD({
url: 'api/securitydoor/initSecurityDoorLog1',
url: 'api/securitydoor/initZKTDoorLog',
optShow: { optShow: {
add: false, add: false,
edit: false, edit: false,
@ -98,15 +135,39 @@ export default {
}, },
data() { data() {
return { return {
bindParamsVisible: false,
showCoverVisible: false,
previewSrc: '',
defaultImg: 'this.src="' + require('@/assets/images/cover-bg.png') + '"',
form: { id: null, zktApitoken: '', zktPort: '', zktUrl: '' },
selections: [], selections: [],
keyWord: '', keyWord: '',
optionVal: 'userName',
optionVal: 'name',
options: [ options: [
{ value: 'userName', label: '姓名' },
{ value: 'employeeId', label: '工号' },
{ value: 'doorName', label: '门区' }
{ value: 'name', label: '姓名' },
{ value: 'pin', label: '人员编号' },
{ value: 'areaName', label: '区域名称' }
],
eventLevel: null,
levelOptions: [
{ value: '0', label: '正常' },
{ value: '1', label: '异常' },
{ value: '2', label: '报警' }
], ],
queryTime: []
sn: null,
snOptions: [],
queryTime: [],
rules: {
zktUrl: [
{ required: true, message: '接口地址不能为空', trigger: 'blur' }
],
zktPort: [
{ required: true, message: '端口不能为空', trigger: 'blur' }
],
zktApitoken: [
{ required: true, message: 'token不能为空', trigger: 'blur' }
]
}
} }
}, },
computed: { computed: {
@ -114,28 +175,97 @@ export default {
'baseApi' 'baseApi'
]) ])
}, },
created() {
this.getZKTDoorList(0)
},
methods: { methods: {
[CRUD.HOOK.beforeRefresh]() { [CRUD.HOOK.beforeRefresh]() {
this.crud.query.userName = null
this.crud.query.employeeId = null
this.crud.query.doorName = null
this.crud.query.areaName = null
this.crud.query.name = null
this.crud.query.pin = null
this.crud.query.startTime = null this.crud.query.startTime = null
if (this.optionVal === 'employeeId') {
this.crud.query.employeeId = this.keyWord
} else if (this.optionVal === 'userName') {
this.crud.query.userName = this.keyWord
} else if (this.optionVal === 'doorName') {
this.crud.query.doorName = this.keyWord
this.crud.query.endTime = null
if (this.optionVal === 'areaName') {
this.crud.query.areaName = this.keyWord
} else if (this.optionVal === 'name') {
this.crud.query.name = this.keyWord
} else if (this.optionVal === 'pin') {
this.crud.query.pin = this.keyWord
} }
if (this.queryTime.length > 0) {
this.crud.query.startTime = this.queryTime
if (this.queryTime && this.queryTime.length > 0) {
this.crud.query.startTime = this.queryTime[0]
this.crud.query.endTime = this.queryTime[1]
} else {
this.crud.query.startTime = null
this.crud.query.endTime = null
} }
}, },
stateSelect(val) {
this.crud.query.eventLevel = val
this.crud.toQuery()
},
snSelect(val) {
this.crud.query.sn = val
this.crud.toQuery()
},
getZKTDoorList(type) {
FetchZKTDoorList().then((res) => {
if (type !== 0) {
if (res.code === -1) {
this.$message.error('门禁服务器连接失败,请确保服务器正常运行及设置参数正确!')
} else {
this.$message.success('门禁服务器连接成功!')
}
this.snOptions = res.data
this.handleClose()
this.crud.toQuery()
} else {
this.snOptions = res.data
}
})
},
getInitZktParam() {
FetchInitZktParam().then((res) => {
console.log(res)
this.bindParamsVisible = true
this.form = {
'id': res.id ? res.id : null,
'zktApitoken': res.zktApitoken,
'zktPort': res.zktPort,
'zktUrl': res.zktUrl
}
})
},
setDevice() {
this.getInitZktParam()
},
saveData() {
this.$refs.form.validate((valid) => {
if (valid) {
add(this.form).then((res) => {
if (res === 'SUCCESS') {
this.getZKTDoorList(1)
}
})
} else {
return false
}
})
},
// //
handleDownload() { handleDownload() {
if (this.queryTime && this.queryTime.length !== 0) {
this.crud.query.startTime = this.queryTime[0]
this.crud.query.endTime = this.queryTime[1]
} else {
this.crud.query.startTime = null
this.crud.query.endTime = null
this.$message.warning('请先选择开始时间和结束时间!')
return false
}
this.crud.downloadLoading = true this.crud.downloadLoading = true
const fileName = parseTime(new Date()) + '-门禁日志.xlsx' const fileName = parseTime(new Date()) + '-门禁日志.xlsx'
getBlob(this.baseApi + '/api/securitydoor/exportSecurityDoorLog1List' + '?' + qs.stringify(this.crud.query, { indices: false }), function(blob) {
getBlob(this.baseApi + '/api/securitydoor/exportZKTDoorLogList' + '?' + qs.stringify(this.crud.query, { indices: false }), function(blob) {
saveAs(blob, fileName) saveAs(blob, fileName)
}) })
this.crud.downloadLoading = false this.crud.downloadLoading = false
@ -156,6 +286,24 @@ export default {
} else if (row.alarmLevel === 0 && columnIndex === 2) { } else if (row.alarmLevel === 0 && columnIndex === 2) {
return 'fail-clear' return 'fail-clear'
} }
},
//
showCoverPreview(row) {
this.showCoverVisible = true
this.previewSrc = 'data:image/png;base64,' + row
},
resetForm() {
this.form.zktApitoken = ''
this.form.zktPort = ''
this.form.zktUrl = ''
},
handleClose() {
this.resetForm()
this.$refs.form.clearValidate()
this.bindParamsVisible = false
},
handlePreview() {
this.showCoverVisible = false
} }
} }
} }
@ -164,5 +312,14 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import '~@/assets/styles/lend-manage.scss'; @import '~@/assets/styles/lend-manage.scss';
@import "~@/assets/styles/archives-manage.scss"; @import "~@/assets/styles/archives-manage.scss";
.params-dialog{
::v-deep .el-dialog{
width: 530px !important;
}
}
::v-deep .input-prepend .el-input__inner{
padding-left: 90px;
}
</style> </style>
Loading…
Cancel
Save