Browse Source

设备管理

master
xuhuajiao 3 weeks ago
parent
commit
bd901ab45d
  1. 11
      src/api/deviceVI/index.js
  2. 52
      src/views/deviceManage/accessControlLog/logList.vue
  3. 186
      src/views/deviceManage/map3d/index.vue
  4. 10
      src/views/deviceManage/safetyDoorLog/alarmLog/index.vue
  5. 39
      src/views/deviceManage/safetyDoorLog/search.vue
  6. 23
      src/views/deviceManage/safetyDoorLog/visitorLog/index.vue
  7. 267
      src/views/deviceManage/shelfManage/codeRules copy.vue
  8. 441
      src/views/deviceManage/shelfManage/shelf.vue

11
src/api/deviceVI/index.js

@ -87,4 +87,13 @@ export function FetchPingIP(params) {
})
}
export default { add, edit, del, FetchRegionTree, FetchinitDeviceInfoList, FetchDeviceById, FetchDeviceShelfGridBinding, FetchBoundGridByDevice, FetchUnboundGrid, FetchPingIP }
// 根据设备类别获取设备树
export function FetchDeviceTreeByType(params) {
return request({
url: 'api/device/getDeviceTreeByType',
method: 'get',
params
})
}
export default { add, edit, del, FetchRegionTree, FetchinitDeviceInfoList, FetchDeviceById, FetchDeviceShelfGridBinding, FetchBoundGridByDevice, FetchUnboundGrid, FetchPingIP, FetchDeviceTreeByType }

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

@ -2,9 +2,9 @@
<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">
<el-select v-model="query.doorCodes" 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-option v-for="item in doorOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select>
<date-range-picker v-model="blurryTime" class="date-item" />
<rrOperation>
@ -27,12 +27,22 @@
<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="操作时间">
<el-table-column prop="dev_sn" label="门禁设备" />
<el-table-column prop="person_name" label="通行人员" />
<el-table-column prop="pass_direction" label="进出方向">
<template slot-scope="scope">
<div>{{ scope.row.snapshotTime | parseTime }}</div>
<div>{{ scope.row.pass_direction === 1?'进':'出' }}</div>
</template>
</el-table-column>
<el-table-column prop="pass_type" label="进出凭证类型">
<template slot-scope="scope">
<div>{{ scope.row.pass_type === 1 ? '证号':'身份证/一卡通/读者证' }}</div>
</template>
</el-table-column>
<el-table-column prop="pass_card" label="卡号" />
<el-table-column prop="pass_time" label="时间">
<template slot-scope="scope">
<div>{{ scope.row.pass_time | parseTime }}</div>
</template>
</el-table-column>
</el-table>
@ -44,6 +54,7 @@
<script>
import crudFace from '@/api/faceRecognition/index'
import { FetchDeviceTreeByType } from '@/api/deviceVI/index'
import CRUD, { presenter, header, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
@ -57,7 +68,7 @@ export default {
name: 'PersonInfoManage',
components: { pagination, crudOperation, rrOperation, DateRangePicker },
cruds() {
return CRUD({ title: '门禁日志', url: 'api/person/initFaceRecognizeLog', crudMethod: { ...crudFace }, optShow: {
return CRUD({ title: '门禁日志', url: 'api/accessLog/initAccessControlLog', crudMethod: { ...crudFace }, optShow: {
add: false,
edit: false,
del: false,
@ -74,10 +85,7 @@ export default {
edit: ['admin', 'column:edit'],
del: ['admin', 'column:del']
},
userTypeOptions: [
{ key: 0, display_name: '普通用户' },
{ key: 1, display_name: 'VIP用户' },
{ key: 2, display_name: '黑名单用户' }
doorOptions: [
],
blurryTime: []
}
@ -89,10 +97,21 @@ export default {
])
},
created() {
this.getDeviceTreeByType()
},
mounted() {
},
methods: {
getDeviceTreeByType() {
const params = {
'libcode': this.user.fonds.fondsNo,
'deviceType': 3
}
FetchDeviceTreeByType(params).then(res => {
this.doorOptions = res
}).catch(() => {
})
},
[CRUD.HOOK.beforeRefresh]() {
this.crud.query.libcode = this.user.fonds.fondsNo
if (this.blurryTime) {
@ -109,12 +128,12 @@ export default {
this.blurryTime = null
this.crud.query.startTime = null
this.crud.query.endTime = null
this.crud.query.personType = null
this.crud.query.doorCodes = null
this.crud.toQuery()
},
doExport() {
console.log('doExport', this.crud.page.total)
if (this.crud.page.total > 10000) {
if (this.crud.page.total >= 10000) {
this.handleExport('导出数据大于10000条,时间可能较长')
} else {
this.handleExport('此操作将导出所有数据')
@ -130,15 +149,16 @@ export default {
}).then(() => {
const params = {
'libcode': this.user.fonds.fondsNo,
'personType': this.crud.query.personType,
'doorCodes': this.crud.query.doorCodes,
'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 }))
exportFile(this.baseApi + '/api/accessLog/downloadAccessControlLog?' + qs.stringify(params, { indices: false, allowDots: true, skipNulls: false }))
this.crud.downloadLoading = false
}).catch(() => {
console.log('取消')
this.crud.downloadLoading = false
})
}
}

186
src/views/deviceManage/map3d/index.vue

@ -0,0 +1,186 @@
<template>
<div class="app-container row-container">
<div class="venue-header" style="margin-bottom: 20px;">
<h4><i class="iconfont icon-duolouceng" />3D地图管理</h4>
<p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p>
</div>
<div class="head-container">
<div class="head-search" style="align-items: center;">
<el-input v-model="query.title" size="small" clearable placeholder="输入appName关键字搜索" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @keyup.enter.native="crud.toQuery" />
<rrOperation />
</div>
<crudOperation :permission="permission">
<template v-slot:middle>
<el-button slot="reference" size="mini" :loading="crud.delAllLoading" :disabled="crud.selections.length === 0" @click="toDelete(crud.selections)">
<i class="iconfont icon-shanchu" />
删除
</el-button>
</template>
</crudOperation>
</div>
<div class="container-wrap" style="min-height: calc(100vh - 306px);">
<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 - 400px)" :data="crud.data" @selection-change="crud.selectionChangeHandler">
<el-table-column type="selection" align="center" width="55" />
<el-table-column prop="appName" label="appName" />
<el-table-column prop="appID" label="appID" />
<el-table-column prop="key" label="Key" />
<el-table-column prop="seqencing" label="访问方式" align="center" />
<el-table-column prop="status" label="离线地图包" align="center" />
<el-table-column prop="createTime" label="操作">
<!-- slot-scope="scope" -->
<template>
<!-- @click="handlePosition(scope.row)" -->
<el-button size="mini">
<i class="iconfont icon-yulan" />
地图预览
</el-button>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination v-if="crud.data.length !== 0" />
</div>
<el-dialog :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog">
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="110px">
<el-row>
<el-form-item label="appName" prop="appName">
<el-input v-model="form.appName" style="width: 486px;" placeholder="请输入,注意:输入错误将无法正常解析" />
</el-form-item>
</el-row>
<el-form-item label="appId" prop="appId">
<el-input v-model="form.appId" style="width: 486px;" placeholder="请输入,注意:输入错误将无法正常解析" />
</el-form-item>
<el-form-item label="Key" prop="key">
<el-input v-model="form.key" style="width: 486px;" placeholder="请输入,注意:输入错误将无法正常解析" />
</el-form-item>
<el-form-item label="访问方式" prop="type">
<el-radio-group v-model="form.type">
<el-radio :label="1">在线</el-radio>
<el-radio :label="0">离线</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确定</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import crudColumn from '@/api/inquiryMachine/column'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
import { mapGetters } from 'vuex'
const defaultForm = { id: null, appName: null, appId: null, type: 1, key: null }
export default {
name: 'Column',
components: { pagination, crudOperation, rrOperation },
cruds() {
return CRUD({ title: '3D地图配置', url: 'api/queryMachine/initQueryTopic', crudMethod: { ...crudColumn }, optShow: {
add: true,
edit: true,
del: false,
reset: true,
download: false,
group: false
}})
},
mixins: [presenter(), header(), form(function() {
return Object.assign({ libcode: this.user.fonds.fondsNo }, defaultForm)
}), crud()],
data() {
return {
permission: {
add: ['admin'],
edit: ['admin'],
del: ['admin']
},
rules: {
appName: [
{ required: true, message: '请输入AppName', trigger: 'blur' }
],
appId: [
{ required: true, message: '请输入AppID', trigger: 'blur' }
],
key: [
{ required: true, message: '请输入Key', trigger: 'blur' }
],
type: [
{ required: true, message: '请选择访问方式', trigger: 'change' }
]
}
}
},
computed: {
...mapGetters([
'baseApi',
'user'
])
},
created() {
},
mounted() {
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.crud.query.libcode = this.user.fonds.fondsNo
},
[CRUD.HOOK.afterRefresh]() {
},
//
[CRUD.HOOK.beforeToAdd](crud, form) {
},
//
[CRUD.HOOK.beforeToEdit](crud, form) {
},
//
[CRUD.HOOK.afterValidateCU](crud) {
console.log(crud.form)
return true
},
toDelete(datas) {
this.$confirm('此操作将删除当前所选' + this.crud.title + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
this.crud.delAllLoading = true
const ids = []
datas.forEach(val => {
ids.push(val.id)
})
crudColumn.del(ids).then((res) => {
if (res.code !== 500) {
this.$message({ message: '删除成功', type: 'success', offset: 8 })
this.crud.refresh()
} else {
this.$message({ message: '删除失败', type: 'error', offset: 8 })
}
this.crud.delAllLoading = false
}).catch(err => {
this.crud.delAllLoading = false
console.log(err)
})
}).catch(() => {
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

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

@ -36,7 +36,7 @@ export default {
mixins: [presenter(), crud()],
cruds() {
return CRUD({
url: 'api/log/initLog',
url: 'api/accessLog/initSafetyDoorLog',
title: '操作日志',
optShow: {
add: false,
@ -48,13 +48,6 @@ export default {
}
})
},
props: {
isCenter: {
type: Boolean,
default: false
}
},
data() {
return {
isLogType: 'alarm',
@ -70,6 +63,7 @@ export default {
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.crud.query.libcode = this.user.fonds.fondsNo
}
}
}

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

@ -5,9 +5,9 @@
<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">
<el-select v-model="query.doorCodes" 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-option v-for="item in doorOptions" :key="item.deviveCode" :label="item.deviceName" :value="item.deviveCode" />
</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>
@ -15,7 +15,7 @@
</div>
<crudOperation>
<template v-slot:right>
<el-button :loading="crud.downloadLoading" size="mini" :disabled="crud.selections.length === 0" @click="doExport">
<el-button :loading="crud.downloadLoading" size="mini" @click="doExport">
<i class="iconfont icon-daochu" />
导出
</el-button>
@ -25,6 +25,7 @@
</template>
<script>
import { FetchDeviceTreeByType } from '@/api/deviceVI/index'
import CRUD, { header, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import DateRangePicker from '@/components/DateRangePicker'
@ -44,12 +45,7 @@ export default {
return {
blurryTime: [],
delVisible: false,
options: [
{ value: 'username', label: '用户名' },
{ value: 'account', label: '登录账号' },
{ value: 'method', label: '请求方法' },
{ value: 'params', label: '请求参数' }
],
doorOptions: [],
alarmOptions: []
}
},
@ -60,8 +56,20 @@ export default {
])
},
created() {
this.getDeviceTreeByType()
},
methods: {
getDeviceTreeByType() {
const params = {
'libcode': this.user.fonds.fondsNo,
'deviceType': 4
}
FetchDeviceTreeByType(params).then(res => {
console.log('res', res)
this.doorOptions = res
}).catch(() => {
})
},
[CRUD.HOOK.beforeRefresh]() {
if (this.blurryTime) {
this.crud.query.startTime = this.blurryTime[0]
@ -72,15 +80,16 @@ export default {
}
},
resetQuery() {
this.blurryTime = []
this.crud.query.startTime = null
this.crud.query.endTime = null
this.crud.query.personType = null
this.crud.query.doorCodes = null
this.crud.query.snapshotOperation = null
this.crud.toQuery()
},
doExport() {
console.log('doExport', this.crud.page.total)
if (this.crud.page.total > 10000) {
if (this.crud.page.total >= 10000) {
this.handleExport('导出数据大于10000条,时间可能较长')
} else {
this.handleExport('此操作将导出所有数据')
@ -95,16 +104,18 @@ export default {
dangerouslyUseHTMLString: true
}).then(() => {
const params = {
'personType': this.crud.query.personType,
'snapshotOperation': this.crud.query.snapshotOperation,
'libcode': this.user.fonds.fondsNo,
'doorCodes': this.crud.query.doorCodes ? this.crud.query.doorCodes : null,
// 'snapshotOperation': this.isLogType === 'alarm' ? this.crud.query.snapshotOperation : null,
'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 }))
exportFile(this.baseApi + '/api/accessLog/downloadSafetyDoorLog?' + qs.stringify(params, { indices: false, allowDots: true, skipNulls: false }))
this.crud.downloadLoading = false
}).catch(() => {
console.log('取消')
this.crud.downloadLoading = false
})
}

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

@ -8,12 +8,12 @@
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="时间">
<el-table-column prop="cdoorCode" label="安全门设备" />
<el-table-column prop="inCount" label="进馆人次" />
<el-table-column prop="outCount" label="出馆人次" />
<el-table-column prop="LastTime" label="时间">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
<div>{{ scope.row.LastTime | parseTime }}</div>
</template>
</el-table-column>
</el-table>
@ -25,13 +25,15 @@
import CRUD, { presenter, crud, header } from '@crud/crud'
import pagination from '@crud/Pagination'
import Search from '../search.vue'
import { mapGetters } from 'vuex'
export default {
name: 'LoginLog',
components: { pagination, Search },
mixins: [presenter(), crud(), header()],
cruds() {
return CRUD({
url: 'api/log/initLoginLog',
url: 'api/accessLog/initSafetyDoorLog',
sort: [],
optShow: {
add: false,
@ -43,13 +45,22 @@ export default {
}
})
},
data() {
return {
isLogType: 'visitor',
selections: []
}
},
computed: {
...mapGetters([
'user'
])
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.crud.query.libcode = this.user.fonds.fondsNo
}
}
}
</script>

267
src/views/deviceManage/shelfManage/codeRules copy.vue

@ -1,267 +0,0 @@
<template>
<div class="app-container" style=" padding: 20px; height: calc(100vh - 140px); background-color: #fff;">
<div style="display: flex; justify-content: flex-start;">
<div class="code-rules-left">
<div class="code-rules-content">
<div
v-for="(item,index) in field"
:key="`position-${index}`"
class="rules-item"
:class="{ active: hoverIndex === index }"
@mouseenter="handleItemHover(index)"
@mouseleave="handleItemLeave"
>
<p>{{ index+1 }}</p>
<span v-if="index < field.length - 1" />
</div>
</div>
<div class="code-rules-content code-rules-field">
<div
v-for="(item, index) in field"
:key="`field-${index}`"
class="rules-item"
:class="{ active: hoverIndex === index }"
@mouseenter="handleItemHover(index)"
@mouseleave="handleItemLeave"
>
<p>{{ item.name }}</p>
<span v-if="index < field.length - 1">-</span>
</div>
</div>
</div>
<div class="code-rules-right">
<div class="code-rules-tip">
<span style="display: block; padding-bottom: 6px; font-weight: bold;">说明</span>
书架的层架位编码规则可根据图书馆现行方案进行设置本系统默认的规则为----<br>
显示时可根据设置决定是否需要在编号第1位加入机构编号
</div>
<div
v-for="(item, index) in [...field].reverse()"
:key="`field-${index}`"
:class="['rules-item-remark', `remark-${index+1}`, { 'remark-active': hoverIndex === (field.length - 1 - index) }]"
@mouseenter="handleRemarkHover(field.length - 1 - index)"
@mouseleave="handleRemarkLeave"
>
<span>{{ item.name }}</span>
<p v-html="item.remark" />
</div>
</div>
</div>
<div class="code-rules-setting" />
</div>
</template>
<script>
export default {
name: 'CodeRules',
data() {
return {
field: [
{ name: '机构', remark: '可在本系统的“系统设置-机构管理”中进行设置。注意:一般因机构名称较长,中文显示时会省略。<br/> 例如:中文显示【智慧图书馆或不显示】、编号显示【FTZN】' },
{ name: '区域', remark: '可在本系统的“场馆设备管理-区域管理”中进行设置。注意:区域编号不可重复!<br/>例如:中文显示【成人阅览室】、编号显示【01】' },
{ name: '排', remark: '根据书架的实际位置设置。通常情况用3位数字进行标识,不足3位的在前面补“0”。 <br/>例如:中文显示【001排】、编号显示【001】' },
{ name: '面', remark: ' 根据书架的实际情况设置。通常书架有两面(靠墙则为单面)。用字母A、B或数字1、2标识。 <br/>例如:中文显示【A面】、编号显示【A或1】' },
{ name: '架/列', remark: '根据书架的实际情况设置。通常情况用2位数字进行标识,不足2位的在前面补“0”。<br/> 例如:中文显示【01架】、编号显示【01】' },
{ name: '层', remark: '根据书架的实际情况设置。通常情况下书架为6层,用1位数字进行标识。 <br/>例如:中文显示【6层】、编号显示【6】' }
],
hoverIndex: -1 //
}
},
methods: {
//
handleRemarkHover(index) {
this.hoverIndex = index
},
//
handleRemarkLeave() {
this.hoverIndex = -1
},
//
handleItemHover(index) {
this.hoverIndex = index
},
//
handleItemLeave() {
this.hoverIndex = -1
}
}
}
</script>
<style lang="scss" scoped>
.code-rules-left{
width: 520px;
}
.code-rules-right{
flex: 1;
margin-left: 30px;
}
.code-rules-content{
display: flex;
justify-content: flex-start;
align-items: center;
text-align: center;
height: 36px;
line-height: 36px;
margin-bottom: 20px;
font-size: 14px;
.rules-item{
display: flex;
justify-content: flex-start;
align-items: center;
text-align: center;
p{
width: 70px;
background-color: #909399;
border:1px solid #909399;
color: #fff;
border-radius: 4px;
transition: all 0.3s ease;
}
span{
display: block;
width: 20px;
}
&.active {
p {
border-color: #0348f3;
background-color: #0348f3;
}
}
&:hover {
cursor: pointer;
}
}
}
.code-rules-field{
.rules-item{
p{
background-color: transparent;
border-color: #545b65;
color: #545b65;
font-weight: bold;
}
&.active{
p{
border-color: #0348f3;
color: #fff;
}
}
}
}
.code-rules-tip{
height: 93px;
padding: 6px 10px;
background-color: #eef5fe;
color: #545b65;
line-height: 24px;
border-left: 3px solid #0348f3;
font-size: 14px;
}
.rules-item-remark{
position: relative;
display: flex;
justify-content: flex-start;
margin-top: 15px;
padding: 8px;
background-color: #eef5fe;
font-size: 14px;
line-height: 22px;
border-radius: 4px;
transition: all 0.3s ease;
&::before{
content: '';
position: absolute;
bottom: 30px;
width: 2px;
border-left: 1px dashed #9098a4;
}
&::after{
content: '';
position: absolute;
bottom: 30px;
height: 2px;
border-bottom: 1px dashed #9098a4;
}
span{
display: block;
width: 46px;
}
&:hover, &.remark-active{
cursor: pointer;
color: #fff;
background-color: #0348f3;
&::before{
content: '';
border-left: 1px dashed #0348f3;
}
&::after{
content: '';
border-bottom: 1px dashed #0348f3;
}
}
&.remark-1{
&::before{
height: 45px;
left: -65px;
}
&::after{
width: 65px;
left: -65px;
}
}
&.remark-2{
&::before{
height: 120px;
left: -155px;
}
&::after{
width: 155px;
left: -155px;
}
}
&.remark-3{
&::before{
height: 195px;
left: -245px;
}
&::after{
width: 245px;
left: -245px;
}
}
&.remark-4{
&::before{
height: 270px;
left: -336px;
}
&::after{
width: 336px;
left: -336px;
}
}
&.remark-5{
&::before{
height: 345px;
left: -425px;
}
&::after{
width: 425px;
left: -425px;
}
}
&.remark-6{
&::before{
height: 420px;
left: -514px;
}
&::after{
width: 514px;
left: -514px;
}
}
}
</style>

441
src/views/deviceManage/shelfManage/shelf.vue

@ -0,0 +1,441 @@
<template>
<div class="app-container row-container">
<div class="head-container">
<div class="head-search" style="align-items: center; ">
<el-select v-model="selectFloorVal" size="small" placeholder="楼层" class="filter-item" style="width: 80px" value-key="id" @change="changeBeforeFloor">
<el-option v-for="(item,index) in floorOptions" :key="index" :label="item.floorName" :value="item" />
</el-select>
<el-select v-model="selectRegionVal" size="small" placeholder="区域" class="filter-item" style="width: 140px" value-key="id" @change="changeBeforeRegion">
<el-option v-for="(item,index) in regionOptions" :key="index" :label="item.regionName" :value="item" />
</el-select>
<el-input v-model="query.search" size="small" clearable placeholder="输入检索条件检索" prefix-icon="el-icon-search" class="filter-item" style="width: 260px;" @keyup.enter.native="crud.toQuery" />
<rrOperation />
</div>
<crudOperation :permission="permission">
<template v-slot:middle>
<el-button slot="reference" size="mini" :loading="crud.delAllLoading" :disabled="crud.selections.length === 0" @click="toDelete(crud.selections)">
<i class="iconfont icon-shanchu" />
删除
</el-button>
<el-button :loading="crud.downloadLoading" size="mini" :disabled="crud.selections.length === 0" @click="doExport">
<i class="iconfont icon-daochu" />
导出
</el-button>
</template>
<template v-slot:right>
<el-button size="mini" @click="handleBatchImport">
<i class="iconfont icon-piliangchengjian" />
批量导入
</el-button>
</template>
</crudOperation>
</div>
<div class="container-wrap">
<span class="right-top-line" />
<span class="left-bottom-line" />
<el-dialog :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog">
<div style="display: flex; justify-content: flex-start;">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="110px">
<!-- <el-form-item label="馆代码" prop="libcode">
<el-input v-model="form.libcode" disabled placeholder="系统自动输入" />
</el-form-item>
<el-form-item label="读者证号" prop="barcode">
<el-input v-model="form.barcode" placeholder="请输入" />
</el-form-item>
<el-form-item label="姓名" prop="personName">
<el-input v-model="form.personName" placeholder="请输入" />
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="form.idCard" placeholder="请输入" />
</el-form-item>
<el-form-item label="联系方式" prop="phone">
<el-input v-model="form.phone" placeholder="请输入" />
</el-form-item>
<el-form-item label="性别" prop="personSex">
<el-radio-group v-model="form.personSex">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="用户类型" prop="personType">
<el-select v-model="form.personType" placeholder="请选择">
<el-option
v-for="(item,index) in userTypeOptions"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item> -->
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确定</el-button>
</div>
</div>
</el-dialog>
<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" @row-click="clickRowHandler">
<el-table-column type="selection" align="center" width="55" />
<el-table-column prop="gridName" label="层位名称">
<template slot-scope="scope">
{{ scope.row.gridName | removeQUPrefix }}
</template>
</el-table-column>
<el-table-column prop="personSex" label="层位编码" />
<el-table-column prop="barcode" label="所属机构" />
<el-table-column prop="floorName" label="所属楼层" />
<el-table-column prop="regionName" label="所属区域" />
<el-table-column prop="createTime" label="操作">
<!-- slot-scope="scope" -->
<template>
<!-- @click="handlePosition(scope.row)" -->
<el-button>定位</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-if="crud.data.length !== 0" />
</div>
<el-dialog class="positionDialog" append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :before-close="handleCloseDialog" :visible="positionVisible" title="层位定位">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<!-- <div class="setting-dialog">
<ul class="book-detail">
<li><span>所属机构</span>{{ user.fonds.fondsName }}</li>
<li><span>所属楼层</span>{{ positionContent.floorName }}</li>
<li><span>所属区域</span>{{ positionContent.regionName }}</li>
<li><span>所属书架</span>{{ positionTitle }}</li>
</ul>
<div class="position-content">
<div class="position-left">
<h5>平面图</h5>
<div class="venue-preview">
<div v-show="currentMarkData && currentMarkData.signPoint ">
<canvas :id="`canvasPreview${currentMarkData && currentMarkData.id}`" :width="width" :height="height" />
</div>
<img v-if="currentMarkData && !currentMarkData.signPoint" :src="imageUrl" :onerror="defaultImg" alt="">
<img v-if="!currentMarkData" :src="imageUrl" :onerror="defaultImg" alt="">
</div>
</div>
<div class="position-right">
<h5>书架图</h5>
<div class="shelf-top" :style="rowStyle">
<p v-for="(item,index) in reversedRackNum" :key="index" :style="{width: `calc(${'100%/' + rackNum} - 4px )`}"><span>{{ item + '架' }}</span></p>
</div>
<ul class="data-shelf-row" :style="rowStyle">
<li
v-for="(cell,i) in booShelfGrid"
:key="i"
:class="{ active: i === cellIndex }"
class="data-shelf-cell"
:style="cellStyle"
>
<span class="cell-name">{{ cell.gridName | removeMianBeforeRefix }}</span>
</li>
</ul>
</div>
</div>
</div> -->
</el-dialog>
</div>
</template>
<script>
import { FetchLibraryFloorListAll } from '@/api/floor/index'
import { FetchInitLibraryRegionList } from '@/api/area/index'
import crudShelf from '@/api/shelf/index'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
// import { exportFile } from '@/utils/index'
// import qs from 'qs'
import { mapGetters } from 'vuex'
const defaultForm = { personId: null, libcode: null, barcode: null, personName: null, personPhotoUrl: null, idCard: null, phone: null, personSex: 1, personType: 0, personPhotoBase64: null }
export default {
name: 'PersonInfoManage',
components: { pagination, crudOperation, rrOperation },
cruds() {
return CRUD({ title: '架位管理', url: 'api/bookShelf/initShelfGridSearch', crudMethod: { ...crudShelf }, sort: [], optShow: {
add: true,
edit: true,
del: false,
reset: true,
download: false,
group: false
}})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
return {
floorOptions: [],
regionOptions: [],
selectFloorVal: null,
selectRegionVal: null,
positionVisible: false,
permission: {
add: ['admin', 'face:add'],
edit: ['admin', 'face:edit'],
del: ['admin', 'face:del']
},
userTypeOptions: [
{ value: 0, label: '普通用户' },
{ value: 1, label: 'VIP用户' },
{ value: 2, label: '黑名单用户' }
],
rules: {
libcode: [
{ required: true, message: '馆代码不可为空', trigger: 'blur' }
],
barcode: [
{ required: true, message: '读者证号不可为空', trigger: 'blur' }
],
personName: [
{ required: true, message: '姓名不可为空', trigger: 'blur' }
],
personType: [
{ required: true, message: '请选择用户类型', trigger: 'change' }
]
},
file: null,
fileNames: '',
filePath: '',
imageUrl: null,
selfRegisterVisible: false,
faceSearchVisible: false,
cameraVisible: false
}
},
computed: {
...mapGetters([
'baseApi',
'user'
])
},
created() {
this.getLibraryFloorListAll()
},
methods: {
//
getLibraryFloorListAll() {
FetchLibraryFloorListAll().then(res => {
this.floorOptions = res
if (this.floorOptions.length > 0) {
this.selectFloorVal = this.floorOptions[0]
this.crud.query.floorId = this.selectFloorVal.id
if (this.crud.query.floorId) {
this.getInitLibraryRegionList(this.crud.query.floorId)
}
}
}).catch(() => {
})
},
getInitLibraryRegionList(val) {
const params = {
'floorId': val
}
FetchInitLibraryRegionList(params).then(res => {
this.regionOptions = res.content
if (this.regionOptions.length > 0) {
this.selectRegionVal = this.regionOptions[0]
this.crud.query.regionId = this.selectRegionVal.id
} else {
this.selectRegionVal = null
this.crud.query.regionId = null
}
this.crud.toQuery()
}).catch(() => {
})
},
changeBeforeFloor(val) {
if (this.$route.query.formArea) {
localStorage.removeItem('formArea')
}
if (val) {
this.selectFloorVal = val
this.crud.query.floorId = val.id
this.getInitLibraryRegionList(val.id)
}
},
changeBeforeRegion(val) {
if (this.$route.query.formArea) {
localStorage.removeItem('formArea')
}
if (val) {
this.selectRegionVal = val
this.crud.query.regionId = val.id
this.crud.toQuery()
}
},
updatePerson() {
this.crud.refresh()
},
[CRUD.HOOK.beforeRefresh]() {
this.crud.query.libcode = this.user.fonds.fondsNo
},
[CRUD.HOOK.afterRefresh]() {
},
//
[CRUD.HOOK.afterToCU](crud, form) {
form.libcode = this.user.fonds.fondsNo
},
//
[CRUD.HOOK.beforeToAdd](crud, form) {
this.imageUrl = null
Object.keys(crud.form).forEach(key => {
this.$set(crud.form, key, null)
})
this.crud.form.personSex = 1
this.crud.form.personType = 0
},
//
[CRUD.HOOK.beforeToEdit](crud, form) {
},
//
[CRUD.HOOK.afterValidateCU](crud) {
if (crud.form.personPhotoUrl === '' || crud.form.personPhotoUrl === null) {
this.$message({ message: '请选择上传照片', type: 'error', offset: 8 })
return false
}
console.log(crud.form)
return true
},
handleBatchImport() {
// this.$refs.batchImportRefs.batchImportVisible = true
},
toDelete(datas) {
this.$confirm('此操作将删除当前所选' + this.crud.title + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
this.crud.delAllLoading = true
const ids = []
datas.forEach(val => {
ids.push(val.personId)
})
// crudFace.del(ids).then(() => {
// this.$message({ message: '', type: 'success', offset: 8 })
// this.crud.delAllLoading = false
// this.crud.refresh()
// }).catch(err => {
// this.crud.delAllLoading = false
// console.log(err)
// })
}).catch(() => {
})
},
clickRowHandler(row) {
this.$refs.table.clearSelection()
this.$refs.table.toggleRowSelection(row)
},
handleCloseDialog() {
this.positionVisible = false
this.detailVisible = false
},
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>
.face-search.el-button:hover,
.face-search.el-button:focus,
.face-search.el-button--info.is-plain:hover,
.face-search.el-button--info.is-plain:focus{
background: #E8F2FF !important;
}
.right-user-img{
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
margin-left: 30px;
border-left: 1px solid #E8E8E8;
img{
display: block;
width: 150px;
height: 200px;
margin: 20px 0;
}
}
::v-deep .el-tag{
&.el-tag--small{
color: #0348f3 !important;
background-color: #eef5fe !important;
border-color: #eef5fe !important;
}
&.el-tag--success {
background-color: #e7faf0 !important;
border-color: #d0f5e0!important;
color: #13ce66!important;
}
&.el-tag--info {
background-color: #f4f4f5 !important;
border-color: #f4f4f5!important;
color: #909399!important;
}
}
.remove-black-btn,
.remove-vip-btn{
border-color: #909399;
color: #909399;
}
.upload-btn{
display: flex;
flex-direction: column;
align-items: center;
#upFile{
position: static;
left: 0;
top: 0;
opacity: 0;
height: 34px;
}
.el-button{
position: static;
margin-top: -34px;
z-index: 99;
}
}
</style>
Loading…
Cancel
Save