Browse Source

设备管理/蜂鸟云

master
xuhuajiao 1 month ago
parent
commit
7d567a58c4
  1. 2
      src/assets/fengmap/fengmap.analyser.min.js
  2. 2
      src/assets/fengmap/fengmap.effect.min.js
  3. 8649
      src/assets/fengmap/fengmap.map.min.js
  4. 35
      src/assets/fengmap/fengmap.plugin.ui.min.js
  5. 1
      src/assets/fengmap/toolBarStyle.css
  6. 46
      src/views/deviceManage/accessControlLog/index.vue
  7. 152
      src/views/deviceManage/accessControlLog/logList.vue
  8. 136
      src/views/deviceManage/map/index copy.vue
  9. 428
      src/views/deviceManage/map/index.vue
  10. 82
      src/views/deviceManage/safetyDoorLog/alarmLog/index.vue
  11. 52
      src/views/deviceManage/safetyDoorLog/index.vue
  12. 116
      src/views/deviceManage/safetyDoorLog/search.vue
  13. 61
      src/views/deviceManage/safetyDoorLog/visitorLog/index.vue
  14. 5
      vue.config.js

2
src/assets/fengmap/fengmap.analyser.min.js
File diff suppressed because it is too large
View File

2
src/assets/fengmap/fengmap.effect.min.js
File diff suppressed because it is too large
View File

8649
src/assets/fengmap/fengmap.map.min.js
File diff suppressed because it is too large
View File

35
src/assets/fengmap/fengmap.plugin.ui.min.js
File diff suppressed because it is too large
View File

1
src/assets/fengmap/toolBarStyle.css
File diff suppressed because it is too large
View File

46
src/views/deviceManage/accessControlLog/index.vue

@ -0,0 +1,46 @@
<template>
<div class="app-container tab-container">
<div class="tab-content">
<span class="right-top-line" />
<span class="left-bottom-line" />
<span class="right-bottom-line" />
<ul class="tab-nav">
<li :class="{ 'active-tab-nav': activeIndex == 0 }" @click="changeActiveTab(0)">人流日志<i /></li>
<span class="tab-right-img" />
</ul>
<component :is="comName" />
</div>
</div>
</template>
<script>
import logList from './logList'
export default {
name: 'LogManage',
components: {
logList
},
data() {
return {
activeIndex: 0
}
},
computed: {
comName: function() {
if (this.activeIndex === 0) {
return 'logList'
}
return 'logList'
}
},
methods: {
changeActiveTab(data) {
this.activeIndex = data
}
}
}
</script>
<style lang="scss" scoped>
</style>

152
src/views/deviceManage/accessControlLog/logList.vue

@ -0,0 +1,152 @@
<template>
<div style="height: calc(100vh - 232px);">
<div class="head-container">
<div class="head-search">
<el-select v-model="query.personType" clearable size="small" placeholder="门禁列表选择" class="filter-item" style="width: 140px;" @change="crud.toQuery">
<i slot="prefix" class="iconfont icon-zhuangtai" />
<el-option v-for="item in userTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select>
<date-range-picker v-model="blurryTime" class="date-item" />
<rrOperation>
<template v-slot:right>
<el-button class="filter-item filter-refresh" size="mini" type="warning" icon="el-icon-refresh-left" @click="resetQuery()">重置</el-button>
</template>
</rrOperation>
</div>
<crudOperation :permission="permission">
<template v-slot:right>
<el-button :loading="crud.downloadLoading" size="mini" @click="doExport">
<i class="iconfont icon-daochu" />
导出
</el-button>
</template>
</crudOperation>
</div>
<div class="container-wrap">
<span class="right-top-line" />
<span class="left-bottom-line" />
<el-table ref="table" v-loading="crud.loading" highlight-current-row style="width: 100%;" height="calc(100vh - 330px)" :data="crud.data" @selection-change="crud.selectionChangeHandler">
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column prop="personName" label="门禁设备" />
<el-table-column prop="personType" label="进馆人次" />
<el-table-column prop="deviceName" label="出馆人次" />
<el-table-column :show-overflow-tooltip="true" prop="snapshotTime" label="操作时间">
<template slot-scope="scope">
<div>{{ scope.row.snapshotTime | parseTime }}</div>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination v-if="crud.data.length !== 0" />
</div>
</div>
</template>
<script>
import crudFace from '@/api/faceRecognition/index'
import CRUD, { presenter, header, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
import DateRangePicker from '@/components/DateRangePicker'
import { exportFile } from '@/utils/index'
import qs from 'qs'
import { mapGetters } from 'vuex'
export default {
name: 'PersonInfoManage',
components: { pagination, crudOperation, rrOperation, DateRangePicker },
cruds() {
return CRUD({ title: '门禁日志', url: 'api/person/initFaceRecognizeLog', crudMethod: { ...crudFace }, optShow: {
add: false,
edit: false,
del: false,
reset: false,
download: false,
group: false
}})
},
mixins: [presenter(), header(), crud()],
data() {
return {
permission: {
add: ['admin', 'column:add'],
edit: ['admin', 'column:edit'],
del: ['admin', 'column:del']
},
userTypeOptions: [
{ key: 0, display_name: '普通用户' },
{ key: 1, display_name: 'VIP用户' },
{ key: 2, display_name: '黑名单用户' }
],
blurryTime: []
}
},
computed: {
...mapGetters([
'baseApi',
'user'
])
},
created() {
},
mounted() {
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.crud.query.libcode = this.user.fonds.fondsNo
if (this.blurryTime) {
this.crud.query.startTime = this.blurryTime[0]
this.crud.query.endTime = this.blurryTime[1]
} else {
this.crud.query.startTime = null
this.crud.query.endTime = null
}
},
[CRUD.HOOK.afterRefresh]() {
},
resetQuery() {
this.blurryTime = null
this.crud.query.startTime = null
this.crud.query.endTime = null
this.crud.query.personType = null
this.crud.toQuery()
},
doExport() {
console.log('doExport', this.crud.page.total)
if (this.crud.page.total > 10000) {
this.handleExport('导出数据大于10000条,时间可能较长')
} else {
this.handleExport('此操作将导出所有数据')
}
},
handleExport(message) {
this.crud.downloadLoading = true
this.$confirm(message + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
const params = {
'libcode': this.user.fonds.fondsNo,
'personType': this.crud.query.personType,
'startTime': this.blurryTime.length !== 0 ? this.blurryTime[0].split(' ')[0] : null,
'endTime': this.blurryTime.length !== 0 ? this.blurryTime[1].split(' ')[0] : null
}
console.log('exportFile', params)
exportFile(this.baseApi + '/api/person/downloadFaceRecognizeLog?' + qs.stringify(params, { indices: false, allowDots: true, skipNulls: false }))
this.crud.downloadLoading = false
}).catch(() => {
console.log('取消')
})
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .el-pagination{
margin: 24px 0 10px 0 !important
}
</style>

136
src/views/deviceManage/map/index copy.vue

@ -0,0 +1,136 @@
<template>
<div class="map-container">
<div class="toolBarDiv" />
<div id="fengmap" />
</div>
</template>
<script>
// import fengmap from '@/assets/fengmapSDK/fengmap.map.min.js'
import { FMMap } from '@/assets/fengmap/fengmap.map.min.js'
import {
FMControlPosition,
FMCompass,
FMZoomBar,
FMToolbar,
FMScaleBar
} from '@/assets/fengmap/fengmap.plugin.ui.min.js'
// import '@/assets/fengmap/fengmap.plugin.ui.min' // UI
// import '@/assets/fengmap/fengmap.analyser.min' //
// import '@/assets/fengmapSDK/fengmap.plugin.navi.min' //
// import '@/assets/fengmapSDK/fengmap.effect.min' //
// import '@/assets/fengmapSDK/fengmap.plugin.markers.min' //
// import '@/assets/fengmapSDK/fengmap.plugin.draw.min' //
// import '@/assets/fengmapSDK/fengmap.plugin.location.min' //
// import '@/assets/fengmapSDK/fengmap.plugin.export.min' // /
// import '@/assets/fengmapSDK/fengmap.plugin.layers.min' //
// import '@/assets/fengmapSDK/fengmap.plugin.debug.min' //
// import '@/assets/fengmapSDK/fengmap.plugin.fusion.min' //
// import '@/assets/fengmapSDK/fengmap.plugin.loader.min' // JS/FBX
export default {
name: 'FengmapComponent',
data() {
return {
map: null, //
marker: null //
}
},
mounted() {
this.initMap()
},
beforeDestroy() {
if (this.map) {
this.map.destroy()
this.map = null
}
},
methods: {
//
initMap() {
const mapOptions = {
container: document.getElementById('fengmap'),
appName: '武汉东西湖图书馆',
key: 'd0ebc0507c72e6fb8598a3e58517f9d3',
mapID: '1572162706543931393',
level: 3,
mapZoom: 19.5
}
//
this.map = new FMMap(mapOptions)
this.map.on('loaded', function() {
//
const scrollCompassCtlOpt = {
position: FMControlPosition.RIGHT_TOP,
offset: {
x: -20,
y: 80
}
}
const compass = new FMCompass(scrollCompassCtlOpt)
compass.addTo(this.map)
compass.on('click', function() {
this.map.setRotation({
rotation: 0,
animate: true,
duration: 0.3,
finish: function() { console.log('setRotation') }
})
})
//
const scrollZoomCtlOpt = {
position: FMControlPosition.RIGHT_TOP,
offset: {
x: -20,
y: 600
}
}
const toolbar = new FMZoomBar(scrollZoomCtlOpt)
toolbar.addTo(this.map)
//
const scrollFloorCtlOpt = {
position: FMControlPosition.RIGHT_TOP,
floorButtonCount: 5,
offset: {
x: -20,
y: 150
},
viewModeControl: true,
floorModeControl: true,
needAllLayerBtn: true
}
const scrollFloorControl = new FMToolbar(scrollFloorCtlOpt)
scrollFloorControl.addTo(this.map)
//
const scrollScaleBarCtlOpt = {
fontSize: 18,
height: 30,
position: FMControlPosition.LEFT_BOTTOM,
offset: {
x: 20,
y: -20
}
}
const scaleBar = new FMScaleBar(scrollScaleBarCtlOpt)
scaleBar.addTo(this.map)
})
}
}
}
</script>
<style scoped>
</style>

428
src/views/deviceManage/map/index.vue

@ -0,0 +1,428 @@
<template>
<div class="app-container">
<div id="fengmap" />
<div class="toolBarDiv" />
<div class="rightMask" />
<!-- <div v-if="debugInfo" class="debug-info">
<pre>{{ debugInfo }}</pre>
</div> -->
<!-- <div class="control-panel">
<div class="button-group">
<el-button type="primary" @click="startTracking(0)">定位点1</el-button>
<el-button type="success" @click="startTracking(1)">定位点2</el-button>
<el-button type="warning" @click="startTracking(2)">定位点3</el-button>
<el-button type="danger" @click="stopAllTracking">停止所有</el-button>
</div>
<div class="tracking-info">
<div v-for="(marker, index) in markers" :key="index" class="marker-status">
<span :style="{ color: getMarkerColor(index) }">
定位点{{ index + 1 }}: {{ marker.active ? '追踪中' : '已停止' }}
<template v-if="marker.remainTime > 0">({{ marker.remainTime }}s)</template>
</span>
</div>
</div>
</div> -->
</div>
</template>
<script>
import fengmap from '@/assets/fengmap/fengmap.map.min'
import {
FMControlPosition,
FMCompass,
FMZoomBar,
FMToolbar,
FMScaleBar
} from '@/assets/fengmap/fengmap.plugin.ui.min.js'
import '@/assets/fengmap/fengmap.analyser.min'
import '@/assets/fengmap/fengmap.effect.min'
export default {
name: 'FengNiaoYun',
data() {
return {
map: null,
markers: [
{ marker: null, timer: null, remainTimer: null, remainTime: 0, active: false, positions: [] },
{ marker: null, timer: null, remainTimer: null, remainTime: 0, active: false, positions: [] },
{ marker: null, timer: null, remainTimer: null, remainTime: 0, active: false, positions: [] }
],
level: null,
levels: null,
floorObj: {},
activeFloor: null,
debugInfo: null,
markerColors: ['#409EFF', '#67C23A', '#E6A23C'] //
}
},
mounted() {
console.log('组件已挂载')
const container = document.getElementById('fengmap')
console.log('容器尺寸:', container.offsetWidth, container.offsetHeight)
this.$nextTick(() => {
this.initMap()
})
},
methods: {
initMap() {
try {
console.log('开始初始化地图')
const options = {
container: document.getElementById('fengmap'),
appName: '武汉东西湖图书馆',
key: 'd0ebc0507c72e6fb8598a3e58517f9d3',
mapID: '1572162706543931393',
// themeID: '1572162706543931393',
// level: 3,
mapZoom: 19
// defaultViewMode: fengmap.FMViewMode.MODE_3D,
// defaultControlsPose: 0,
// defaultTiltAngle: 60,
// defaultMapScaleLevel: 18,
// defaultFocusGroup: 1,
// forceWebGL: true
}
console.log('地图配置:', options)
this.map = new fengmap.FMMap(options)
console.log('地图实例已创建')
this.map.on('loadingProcess', (event) => {
console.log('加载进度:', event.progress)
this.debugInfo = `加载进度: ${event.progress}%`
})
this.map.on('loaded', () => {
console.log('地图加载完成')
this.debugInfo = '地图加载完成'
this.map.setViewMode(fengmap.FMViewMode.MODE_3D)
//
const scrollCompassCtlOpt = {
position: FMControlPosition.RIGHT_TOP,
offset: {
x: -20,
y: 80
}
}
const compass = new FMCompass(scrollCompassCtlOpt)
compass.addTo(this.map)
compass.on('click', function() {
this.map.setRotation({
rotation: 0,
animate: true,
duration: 0.3,
finish: function() { console.log('setRotation') }
})
})
//
const scrollZoomCtlOpt = {
position: FMControlPosition.RIGHT_TOP,
offset: {
x: -20,
y: 600
}
}
const toolbar = new FMZoomBar(scrollZoomCtlOpt)
toolbar.addTo(this.map)
//
const scrollFloorCtlOpt = {
position: FMControlPosition.RIGHT_TOP,
floorButtonCount: 5,
offset: {
x: -20,
y: 150
},
viewModeControl: true,
floorModeControl: true,
needAllLayerBtn: true
}
const scrollFloorControl = new FMToolbar(scrollFloorCtlOpt)
console.log('scrollFloorControl', scrollFloorControl.p)
scrollFloorControl.addTo(this.map)
//
const scrollScaleBarCtlOpt = {
fontSize: 18,
height: 30,
position: FMControlPosition.LEFT_BOTTOM,
offset: {
x: 20,
y: -20
}
}
const scaleBar = new FMScaleBar(scrollScaleBarCtlOpt)
scaleBar.addTo(this.map)
console.log('当前楼层', this.map.getLevel())
console.log('所有楼层', this.map.getLevels())
//
this.level = this.map.getLevel()
this.levels = this.map.getLevels()
// console.log('', this.map.getVisibleLevels())
const floorInfos = this.map.getFloorInfos().reverse()
console.log(floorInfos)
//
// this.map.setLevel({
// level: item
// })
// this.addFloorsDom()
}, { passive: true })
this.map.on('click', (e) => {
console.log('地图点击事件:', e)
this.debugInfo = `点击坐标: x=${e.x}, y=${e.y}`
}, { passive: true })
this.map.on('mapInitError', (err) => {
console.error('地图初始化错误:', err)
this.debugInfo = `地图初始化错误: ${err.message}`
})
} catch (error) {
console.error('初始化地图失败:', error)
this.debugInfo = `初始化失败: ${error.message}`
}
},
addFloorsDom() {
//
const floorInfos = this.map.getFloorInfos().reverse()
console.log(floorInfos)
floorInfos.forEach(item => {
this.floorObj[item.level] = item.name
})
const dom = document.getElementsByClassName('fm-floor-list')[0]
this.levels.reverse().forEach((item) => {
const labelEle = document.createElement('label')
const textEle = document.createTextNode(this.floorObj[item])
// Dom
labelEle.onclick = function setLevelClick() {
console.log(item, this.floorObj)
this.level = item
//
this.map.setLevel({
level: item
})
//
if (this.activeFloor) {
const activeDom = document.getElementById(this.activeFloor)
activeDom.classList.remove('fm-floor-name-active')
activeDom.classList.add('fm-floor-name-normal')
}
const dom = document.getElementById(this.floorObj[item])
dom.classList.remove('fm-floor-name-normal')
dom.classList.add('fm-floor-name-active')
this.activeFloor = this.floorObj[item]
}
labelEle.id = this.floorObj[item]
labelEle.classList.add('fm-floor-name')
labelEle.classList.add('fm-floor-name-normal')
labelEle.appendChild(textEle)
dom.appendChild(labelEle)
const hrEle = document.createElement('hr')
hrEle.classList.add('fm-floor-line')
dom.appendChild(hrEle)
})
dom.removeChild(dom.childNodes[dom.childNodes.length - 1])
},
getMarkerColor(index) {
return this.markerColors[index]
},
async addLocationMarker(index, ops = {}) {
try {
if (this.markers[index].marker) {
this.markers[index].marker.remove()
this.markers[index].marker = null
}
const markerConfig = {
height: 0.2,
size: 23,
level: 5,
url: 'https://developer.fengmap.com/fmAPI/images/location.png',
x: 11791504,
y: 3418833.5,
color: this.markerColors[index], //
...ops
}
this.markers[index].marker = new fengmap.FMLocationMarker(markerConfig)
this.markers[index].marker.addTo(this.map)
} catch (error) {
console.error(`添加定位标记${index + 1}失败:`, error)
this.debugInfo = `添加标记${index + 1}失败: ${error.message}`
}
},
async getRealtimePosition(index) {
//
const baseX = 11791504 + (index * 50) // 50
const baseY = 3418833.5 + (index * 50)
return {
x: baseX + Math.random() * 20 - 10,
y: baseY + Math.random() * 20 - 10,
level: 5
}
},
async updateMarkerPosition(index) {
try {
const position = await this.getRealtimePosition(index)
if (this.markers[index].marker) {
this.markers[index].marker.moveTo({
x: position.x,
y: position.y,
level: position.level,
animate: true,
duration: 0.5
})
} else {
this.addLocationMarker(index, position)
}
//
this.markers[index].positions.push({
x: position.x,
y: position.y,
timestamp: new Date().toLocaleString()
})
this.debugInfo = `定位点${index + 1}更新: x=${position.x.toFixed(2)}, y=${position.y.toFixed(2)}`
} catch (error) {
console.error(`更新位置${index + 1}失败:`, error)
this.debugInfo = `更新位置${index + 1}失败: ${error.message}`
}
},
startTracking(index) {
if (this.markers[index].timer) {
this.$message.warning(`定位点${index + 1}已在追踪中`)
return
}
this.markers[index].active = true
this.markers[index].remainTime = 60
this.markers[index].positions = [] //
//
this.markers[index].remainTimer = setInterval(() => {
this.markers[index].remainTime--
if (this.markers[index].remainTime <= 0) {
this.stopTracking(index)
}
}, 1000)
//
this.updateMarkerPosition(index)
this.markers[index].timer = setInterval(() => {
this.updateMarkerPosition(index)
}, 3000)
this.$message.success(`定位点${index + 1}开始追踪`)
},
stopTracking(index) {
if (this.markers[index].timer) {
clearInterval(this.markers[index].timer)
clearInterval(this.markers[index].remainTimer)
this.markers[index].timer = null
this.markers[index].remainTimer = null
this.markers[index].remainTime = 0
this.markers[index].active = false
//
console.log(`定位点${index + 1}位置记录:`, this.markers[index].positions)
this.$message.info(`定位点${index + 1}追踪已停止`)
}
},
stopAllTracking() {
this.markers.forEach((_, index) => {
this.stopTracking(index)
})
this.$message.info('所有定位点追踪已停止')
},
beforeDestroy() {
this.stopAllTracking()
this.markers.forEach(markerInfo => {
if (markerInfo.marker) {
markerInfo.marker.remove()
}
})
if (this.map) {
this.map.dispose()
this.map = null
}
}
}
}
</script>
<style scoped lang="scss">
@import "~@/assets/fengmap/toolBarStyle.css";
#fengmap {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #f5f5f5;
}
.rightMask{
width: 162px;
height: 42px;
position: absolute;
bottom: 0;
right: 0;
background: #fff;
}
.debug-info {
position: absolute;
top: 10px;
left: 10px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 10px;
border-radius: 4px;
font-size: 12px;
max-width: 80%;
z-index: 99999999;
}
/*.control-panel {
position: fixed;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.9);
padding: 15px;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.button-group {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
.tracking-info {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid #eee;
}
.marker-status {
margin: 5px 0;
font-size: 14px;
} */
</style>

82
src/views/deviceManage/safetyDoorLog/alarmLog/index.vue

@ -0,0 +1,82 @@
<template>
<div style="height: calc(100vh - 236px);">
<Search :is-log-type="isLogType" />
<el-table
ref="table"
:data="crud.data"
style="width: 100%;"
height="calc(100vh - 330px)"
>
<el-table-column type="index" label="序号" align="center" width="55" />
<el-table-column prop="username" label="书名" />
<el-table-column prop="nickName" label="ISBN" />
<el-table-column prop="fondsName" label="索书号" />
<el-table-column prop="deptsName" label="UID" />
<el-table-column prop="requestIp" label="安全门设备" />
<el-table-column prop="address" label="报警类型" />
<el-table-column prop="createTime" label="时间">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
</template>
</el-table-column>
</el-table>
<pagination v-if="crud.data.length !== 0" />
</div>
</template>
<script>
import Search from '../search.vue'
import CRUD, { presenter, crud } from '@crud/crud'
import { mapGetters } from 'vuex'
import pagination from '@crud/Pagination'
export default {
name: 'OperateLog',
components: { pagination, Search },
mixins: [presenter(), crud()],
cruds() {
return CRUD({
url: 'api/log/initLog',
title: '操作日志',
optShow: {
add: false,
edit: false,
del: false,
download: false,
reset: false,
group: false
}
})
},
props: {
isCenter: {
type: Boolean,
default: false
}
},
data() {
return {
isLogType: 'alarm',
selections: []
}
},
computed: {
...mapGetters([
'user'
])
},
mounted() {
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .el-pagination{
margin: 24px 0 10px 0 !important
}
</style>

52
src/views/deviceManage/safetyDoorLog/index.vue

@ -0,0 +1,52 @@
<template>
<div class="app-container tab-container">
<div class="tab-content">
<span class="right-top-line" />
<span class="left-bottom-line" />
<span class="right-bottom-line" />
<ul class="tab-nav">
<li :class="{ 'active-tab-nav': activeIndex == 0 }" @click="changeActiveTab(0)">人流日志<i /></li>
<li :class="{ 'active-tab-nav': activeIndex == 1 }" @click="changeActiveTab(1)">报警日志<i /></li>
<!-- 最右侧装饰img -->
<span class="tab-right-img" />
</ul>
<component :is="comName" />
</div>
</div>
</template>
<script>
import visitorLog from './visitorLog/index'
import alarmLog from './alarmLog/index'
export default {
name: 'LogManage',
components: {
visitorLog,
alarmLog
},
data() {
return {
activeIndex: 0
}
},
computed: {
comName: function() {
if (this.activeIndex === 0) {
return 'visitorLog'
} else if (this.activeIndex === 1) {
return 'alarmLog'
}
return 'visitorLog'
}
},
methods: {
changeActiveTab(data) {
this.activeIndex = data
}
}
}
</script>
<style lang="scss" scoped>
</style>

116
src/views/deviceManage/safetyDoorLog/search.vue

@ -0,0 +1,116 @@
<template>
<div class="head-container">
<div class="head-search">
<el-select v-if="isLogType === 'alarm'" v-model="query.snapshotOperation" clearable size="small" placeholder="报警类型" class="filter-item" style="width: 150px;" @change="crud.toQuery">
<i slot="prefix" class="iconfont icon-zhuangtai" />
<el-option v-for="item in alarmOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select>
<el-select v-model="query.personType" clearable size="small" placeholder="安全门列表选择" class="filter-item" style="width: 140px;" @change="crud.toQuery">
<i slot="prefix" class="iconfont icon-zhuangtai" />
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<date-range-picker v-model="blurryTime" class="date-item" />
<el-button class="filter-item filter-search" size="mini" type="success" icon="el-icon-search" @click="crud.toQuery">搜索</el-button>
<el-button class="filter-item filter-refresh" size="mini" type="warning" icon="el-icon-refresh-left" @click="resetQuery()">重置</el-button>
</div>
<crudOperation>
<template v-slot:right>
<el-button :loading="crud.downloadLoading" size="mini" :disabled="crud.selections.length === 0" @click="doExport">
<i class="iconfont icon-daochu" />
导出
</el-button>
</template>
</crudOperation>
</div>
</template>
<script>
import CRUD, { header, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import DateRangePicker from '@/components/DateRangePicker'
import { mapGetters } from 'vuex'
import { exportFile } from '@/utils/index'
import qs from 'qs'
export default {
components: { DateRangePicker, crudOperation },
mixins: [header(), crud()],
props: {
isLogType: {
type: String,
default: ''
}
},
data() {
return {
blurryTime: [],
delVisible: false,
options: [
{ value: 'username', label: '用户名' },
{ value: 'account', label: '登录账号' },
{ value: 'method', label: '请求方法' },
{ value: 'params', label: '请求参数' }
],
alarmOptions: []
}
},
computed: {
...mapGetters([
'baseApi',
'user'
])
},
created() {
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
if (this.blurryTime) {
this.crud.query.startTime = this.blurryTime[0]
this.crud.query.endTime = this.blurryTime[1]
} else {
this.crud.query.startTime = null
this.crud.query.endTime = null
}
},
resetQuery() {
this.crud.query.startTime = null
this.crud.query.endTime = null
this.crud.query.personType = null
this.crud.query.snapshotOperation = null
this.crud.toQuery()
},
doExport() {
console.log('doExport', this.crud.page.total)
if (this.crud.page.total > 10000) {
this.handleExport('导出数据大于10000条,时间可能较长')
} else {
this.handleExport('此操作将导出所有数据')
}
},
handleExport(message) {
this.crud.downloadLoading = true
this.$confirm(message + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
const params = {
'personType': this.crud.query.personType,
'snapshotOperation': this.crud.query.snapshotOperation,
'startTime': this.blurryTime.length !== 0 ? this.blurryTime[0].split(' ')[0] : null,
'endTime': this.blurryTime.length !== 0 ? this.blurryTime[1].split(' ')[0] : null
}
console.log('exportFile', params)
exportFile(this.baseApi + '/api/person/downloadFaceRecognizeLog?' + qs.stringify(params, { indices: false, allowDots: true, skipNulls: false }))
this.crud.downloadLoading = false
}).catch(() => {
console.log('取消')
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

61
src/views/deviceManage/safetyDoorLog/visitorLog/index.vue

@ -0,0 +1,61 @@
<template>
<div style="height: calc(100vh - 232px);">
<Search :is-log-type="isLogType" />
<el-table
ref="table"
:data="crud.data"
style="width: 100%;"
height="calc(100vh - 330px)"
>
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column prop="account" label="安全门设备" />
<el-table-column prop="username" label="进馆人次" />
<el-table-column prop="fondsName" label="出馆人次" />
<el-table-column prop="createTime" label="时间">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
</template>
</el-table-column>
</el-table>
<pagination v-if="crud.data.length !== 0" />
</div>
</template>
<script>
import CRUD, { presenter, crud, header } from '@crud/crud'
import pagination from '@crud/Pagination'
import Search from '../search.vue'
export default {
name: 'LoginLog',
components: { pagination, Search },
mixins: [presenter(), crud(), header()],
cruds() {
return CRUD({
url: 'api/log/initLoginLog',
sort: [],
optShow: {
add: false,
edit: false,
del: false,
download: false,
reset: false,
group: false
}
})
},
data() {
return {
isLogType: 'visitor',
selections: []
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
::v-deep .el-pagination{
margin: 24px 0 10px 0 !important
}
</style>

5
vue.config.js

@ -53,6 +53,11 @@ module.exports = {
pathRewrite: {
'^/auth': 'auth'
}
},
'/fengmap': {
target: 'https://map.fengmap.com',
changeOrigin: true,
pathRewrite: { '^/fengmap': '' }
}
}
},

Loading…
Cancel
Save