8 changed files with 2912 additions and 1 deletions
-
528src/views/deviceManage/area/index.vue
-
682src/views/deviceManage/bookshelf/index.vue
-
594src/views/deviceManage/bookshelfPosition/index.vue
-
769src/views/deviceManage/device/index.vue
-
282src/views/deviceManage/floor/index.vue
-
16src/views/deviceManage/index.vue
-
24src/views/faceRecognition/personInfoManage.vue
-
18src/views/faceRecognition/personRegister.vue
@ -0,0 +1,528 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="venue-header"> |
|||
<h4><i class="iconfont icon-hangzhengquyuguanli" />区域列表</h4> |
|||
<p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p> |
|||
</div> |
|||
<div class="venue-content"> |
|||
<div class="venue-left"> |
|||
<div class="head-container"> |
|||
<div class="head-search"> |
|||
<!-- 搜索 --> |
|||
<el-select v-model="query.floorId" clearable size="small" placeholder="楼层" class="filter-item" style="width: 80px" @change="changeInitFloorValue($event)"> |
|||
<el-option v-for="item in floorOptions" :key="item.id" :label="item.floorName" :value="item.id" /> |
|||
</el-select> |
|||
<el-input v-model="query.search" clearable size="small" placeholder="输入关键字搜索" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @clear="crud.toQuery" @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> |
|||
<template v-slot:right> |
|||
<el-button :loading="crud.downloadLoading" size="mini" :disabled="crud.selections.length <= 1" @click="showSort"> |
|||
<i class="iconfont icon-paixu" /> |
|||
排序 |
|||
</el-button> |
|||
</template> |
|||
</crudOperation> |
|||
</div> |
|||
<div> |
|||
<!-- <div class="double-click-btn"><i class="iconfont icon-zhuyi-lan" /><span>双击列表数据查看对应书架</span></div> --> |
|||
<el-table |
|||
ref="table" |
|||
v-loading="crud.loading" |
|||
:data="crud.data" |
|||
style="width: 100%;" |
|||
height="506" |
|||
@selection-change="crud.selectionChangeHandler" |
|||
@row-click="clickRowHandler" |
|||
@row-dblclick="onRowDblclick" |
|||
> |
|||
<el-table-column type="selection" align="center" width="55" /> |
|||
<el-table-column type="index" label="排序" /> |
|||
<el-table-column prop="regionName" label="区域名称" /> |
|||
<el-table-column prop="regionCode" label="区域编码" /> |
|||
<el-table-column prop="floorName" label="所在楼层" /> |
|||
<el-table-column prop="booksheflCount" label="书架" /> |
|||
<el-table-column prop="signPoint" label="标注"> |
|||
<template slot-scope="scope"> |
|||
<span :class="['row-state', scope.row.signPoint ? 'end-state' : 'cancel-state' ]">{{ scope.row.signPoint ? '已标注': '未标注' }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<!--分页组件--> |
|||
<pagination v-if="crud.data.length!==0" /> |
|||
</div> |
|||
</div> |
|||
<div class="venue-right"> |
|||
<div class="container-right tab-content"> |
|||
<span class="right-top-line" /> |
|||
<span class="left-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" /> |
|||
<el-button size="mini" class="venue-mark" :disabled="crud.selections.length !== 1" @click="handleMark"> |
|||
<i class="el-icon-edit" /> |
|||
区域标注 |
|||
</el-button> |
|||
</ul> |
|||
<div v-show="activeIndex == 0" class="venue-preview"> |
|||
<!-- <MarkCover v-if="currentMarkData && currentMarkData.signPoint" ref="markRefs2" :is-canvas-show="true" :current-mark-data="currentMarkData" :image-floor-url="imageUrl" /> --> |
|||
<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 v-if="activeIndex == 1" class="venue-preview"> |
|||
<img :src="imageRegionUrl" :onerror="defaultImg" alt=""> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- form --> |
|||
<el-dialog append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :before-close="crud.cancelCU" :visible="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" :rules="rules" :model="form" size="small" label-width="100px"> |
|||
<el-form-item label="所属楼层" prop="floorId"> |
|||
<el-select v-model="form.floorId" placeholder="请选择" style="width: 225px;" @change="changeFloorValue($event)"> |
|||
<el-option |
|||
v-for="(item,index) in floorOptions" |
|||
:key="index" |
|||
:label="item.floorName" |
|||
:value="item.id" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="区域名称" prop="regionName"> |
|||
<el-input v-model="form.regionName" style="width: 580px;" /> |
|||
</el-form-item> |
|||
<el-form-item label="区域编码" prop="regionCode"> |
|||
<el-input v-model="form.regionCode" style="width: 580px;" /> |
|||
</el-form-item> |
|||
<el-form-item label="描述信息" prop="regionDescription"> |
|||
<el-input v-model="form.regionDescription" placeholder="请输入" type="textarea" rows="3" style="width: 580px;" /> |
|||
</el-form-item> |
|||
<UploadCover ref="uploadCoverRefs" :label-name="labelName" :form="form" @childCover="handleCover" /> |
|||
</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> |
|||
|
|||
<!-- 排序 --> |
|||
<el-dialog :close-on-click-modal="false" :append-to-body="true" title="排序" :visible.sync="sortVisible" @opened="opened"> |
|||
<span class="dialog-right-top" /> |
|||
<span class="dialog-left-bottom" /> |
|||
<div class="setting-dialog"> |
|||
<i class="drag-tip">提示:请通过拖动鼠标来调整当前顺序</i> |
|||
<el-table :data="sortTableData" class="file-sort" style="width: 100%;max-height: 70vh;" row-key="id"> |
|||
<el-table-column type="index" label="序号" width="100" align="center" /> |
|||
<el-table-column prop="regionName" label="区域名称"> |
|||
<template slot-scope="scope"> |
|||
<span>{{ scope.row.regionName +' [ '+ scope.row.floorName+' ] ' }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" @click.native="handleSort">保存</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
<!-- 标注 --> |
|||
<el-dialog class="mark-dialog" :close-on-click-modal="false" :append-to-body="true" :title="titleMark" :visible.sync="markVisible" :before-close="handleCloseDialog"> |
|||
<span class="dialog-right-top" /> |
|||
<span class="dialog-left-bottom" /> |
|||
<div class="setting-dialog"> |
|||
<MarkCover ref="markRefs" :is-book-shelf="false" :current-mark-data="currentMarkData" :image-url="imageUrl" @handleCloseDialog="handleCloseDialog" /> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { FetchLibraryFloorListAll } from '@/api/floor/index' |
|||
import crudRegion from '@/api/area/index' |
|||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|||
import crudOperation from '@crud/CRUD.operation' |
|||
import rrOperation from '@crud/RR.operation' |
|||
import pagination from '@crud/Pagination' |
|||
import UploadCover from '@/views/components/upload.vue' |
|||
import MarkCover from '@/views/components/mark.vue' |
|||
import Sortable from 'sortablejs' |
|||
import { mapGetters } from 'vuex' |
|||
import defaultImg from '@/assets/images/system/default-img.jpg' |
|||
import { fabric } from 'fabric' |
|||
|
|||
const defaultForm = { id: null, floorId: null, regionName: null, regionCode: null, regionDescription: null, regionMap: null, signPoint: null } |
|||
export default { |
|||
name: 'Bookshelf', |
|||
components: { crudOperation, rrOperation, pagination, UploadCover, MarkCover }, |
|||
cruds() { |
|||
return CRUD({ title: '区域', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: { |
|||
add: true, |
|||
edit: true, |
|||
del: false, |
|||
download: false, |
|||
group: false, |
|||
reset: false |
|||
}}) |
|||
}, |
|||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|||
data() { |
|||
return { |
|||
setfloorId: null, |
|||
floorOptions: [], |
|||
labelName: '区域地图', |
|||
permission: { |
|||
add: ['admin', 'floor:add'], |
|||
edit: ['admin', 'floor:edit'], |
|||
del: ['admin', 'floor:del'] |
|||
}, |
|||
rules: { |
|||
floorId: [ |
|||
{ required: true, message: '请选择所属楼层', trigger: 'change' } |
|||
], |
|||
regionName: [ |
|||
{ required: true, message: '区域名称不可为空', trigger: 'blur' } |
|||
], |
|||
regionCode: [ |
|||
{ required: true, message: '区域编码不可为空', trigger: 'blur' } |
|||
] |
|||
}, |
|||
activeIndex: 0, |
|||
defaultImg: defaultImg, |
|||
imageUrl: defaultImg, |
|||
imageRegionUrl: defaultImg, |
|||
sortTableData: [], // 排序data |
|||
sortVisible: false, // 排序dialog |
|||
markVisible: false, // 区域标注 |
|||
titleMark: '区域标注', |
|||
currentMarkData: null, |
|||
|
|||
canvasPreview: {}, |
|||
width: 900, |
|||
height: 600, |
|||
drawWidth: 2 // 笔触宽度 |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'user', |
|||
'baseApi' |
|||
]) |
|||
}, |
|||
watch: { |
|||
width() { |
|||
this.canvasPreview.setWidth(this.width) |
|||
}, |
|||
height() { |
|||
this.canvasPreview.setHeight(this.height) |
|||
} |
|||
}, |
|||
beforeDestroy() { |
|||
window.removeEventListener('beforeunload', this.clearLocalStorage) |
|||
}, |
|||
methods: { |
|||
clearLocalStorage() { |
|||
const key = 'formFloor' |
|||
if (localStorage.getItem(key)) { |
|||
localStorage.removeItem(key) |
|||
} |
|||
}, |
|||
[CRUD.HOOK.beforeRefresh]() { |
|||
this.getLibraryFloorListAll() |
|||
console.log(this.$route.query) |
|||
if (this.$route.query.formFloor) { |
|||
const formFloor = JSON.parse(localStorage.getItem('formFloor')) |
|||
if (formFloor) { |
|||
this.crud.query.floorId = formFloor.id |
|||
} |
|||
} |
|||
}, |
|||
[CRUD.HOOK.afterRefresh](crud) { |
|||
console.log('crud.data', crud.data) |
|||
if (crud.data.length !== 0) { |
|||
this.clickRowHandler(crud.data[0]) |
|||
this.activeIndex = 0 |
|||
} else { |
|||
this.currentMarkData = null |
|||
this.imageUrl = this.defaultImg |
|||
this.imageRegionUrl = this.defaultImg |
|||
} |
|||
}, |
|||
|
|||
// 提交前的验证 |
|||
[CRUD.HOOK.afterValidateCU](crud) { |
|||
this.$refs.uploadCoverRefs.fileNames = '' |
|||
return true |
|||
}, |
|||
// 获取楼层数据 |
|||
getLibraryFloorListAll() { |
|||
FetchLibraryFloorListAll().then(res => { |
|||
this.floorOptions = res |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
handleCover(value) { |
|||
console.log(value) |
|||
this.crud.form.regionMap = value |
|||
}, |
|||
changeInitFloorValue(value) { |
|||
if (this.$route.query.formFloor) { |
|||
localStorage.removeItem('formFloor') |
|||
} |
|||
|
|||
this.crud.query.floorId = value |
|||
this.crud.toQuery() |
|||
console.log('value', value) |
|||
}, |
|||
changeFloorValue(value) { |
|||
}, |
|||
clickRowHandler(row) { |
|||
this.$refs.table.clearSelection() |
|||
this.$refs.table.toggleRowSelection(row) |
|||
// http://192.168.99.67:12010/api/fileRelevant/getImg?imgType=1&imgId=f6d3ecea-0456-4429-ba77-1a4921d5c806 |
|||
this.currentMarkData = row |
|||
if (this.canvasPreview.lowerCanvasEl) { |
|||
this.canvasPreview.clear() |
|||
this.canvasPreview.dispose() |
|||
} |
|||
if (this.activeIndex === 0) { |
|||
if (row.floorMap) { |
|||
this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=1&imgId=' + row.floorMap |
|||
if (row.signPoint) { |
|||
this.$nextTick(() => { |
|||
const drawinfo = JSON.parse(row.signPoint) |
|||
this.initCanvasPreview(drawinfo) |
|||
}) |
|||
} |
|||
} else { |
|||
this.imageUrl = this.defaultImg |
|||
} |
|||
} else { |
|||
if (row.regionMap) { |
|||
this.imageRegionUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=1&imgId=' + row.regionMap |
|||
} else { |
|||
this.imageRegionUrl = this.defaultImg |
|||
} |
|||
} |
|||
}, |
|||
onRowDblclick(row) { |
|||
localStorage.setItem('formArea', JSON.stringify(row)) |
|||
// this.$router.push({ path: '/check/venueDevice/bookshelf', query: { 'formArea': true }}) |
|||
}, |
|||
changeActiveTab(data) { |
|||
this.activeIndex = data |
|||
if (this.crud.selections.length === 1) { |
|||
if (this.crud.selections[0].floorMap) { |
|||
this.currentMarkData = this.crud.selections[0] |
|||
this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=1&imgId=' + this.crud.selections[0].floorMap |
|||
} else { |
|||
this.imageUrl = this.defaultImg |
|||
} |
|||
if (this.crud.selections[0].regionMap) { |
|||
this.imageRegionUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=1&imgId=' + this.crud.selections[0].regionMap |
|||
} else { |
|||
this.imageRegionUrl = this.defaultImg |
|||
} |
|||
|
|||
if (this.activeIndex === 0) { |
|||
if (this.crud.selections[0].signPoint) { |
|||
console.log('1111') |
|||
this.$nextTick(() => { |
|||
const drawinfo = JSON.parse(this.crud.selections[0].signPoint) |
|||
this.initCanvasPreview(drawinfo) |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
async handleMark() { |
|||
if (this.crud.selections[0].floorMap) { |
|||
this.markVisible = true |
|||
this.currentMarkData = this.crud.selections[0] |
|||
this.titleMark = this.currentMarkData.regionName + ' - 区域标注' |
|||
this.$nextTick(() => { |
|||
this.$refs.markRefs.drawinfo = this.currentMarkData && this.currentMarkData.signPoint ? JSON.parse(this.currentMarkData.signPoint) : null |
|||
this.$refs.markRefs.initCanvas() |
|||
}) |
|||
} else { |
|||
this.$message({ message: '请先上传当前楼层图', type: 'error', offset: 8 }) |
|||
} |
|||
}, |
|||
toDelete(datas) { |
|||
this.$confirm('此操作将删除当前所选区域<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
this.crud.delAllLoading = true |
|||
const ids = [] |
|||
datas.forEach(val => { |
|||
ids.push(val.id) |
|||
}) |
|||
console.log(ids) |
|||
crudRegion.del(ids).then(res => { |
|||
console.log(res) |
|||
this.$message({ message: res, type: 'success', offset: 8 }) |
|||
this.crud.delAllLoading = false |
|||
this.crud.refresh() |
|||
}).catch(err => { |
|||
this.crud.delAllLoading = false |
|||
console.log(err) |
|||
}) |
|||
}).catch(() => { |
|||
this.crud.delAllLoading = false |
|||
}) |
|||
}, |
|||
// 排序 - 行拖拽 |
|||
rowDrop(className, targetName) { |
|||
// 此时找到的元素是要拖拽元素的父容器 |
|||
const tbody = document.querySelector('.' + className + ' .el-table__body-wrapper tbody') |
|||
const that = this |
|||
Sortable.create(tbody, { |
|||
// 指定父元素下可被拖拽的子元素 |
|||
draggable: '.el-table__row', |
|||
onEnd({ newIndex, oldIndex }) { |
|||
if (newIndex === oldIndex) return |
|||
that[targetName].splice(newIndex, 0, that[targetName].splice(oldIndex, 1)[0]) |
|||
} |
|||
}) |
|||
}, |
|||
// 排序 |
|||
opened() { |
|||
this.rowDrop('file-sort', 'sortTableData') |
|||
}, |
|||
showSort() { |
|||
this.sortVisible = true |
|||
this.sortTableData = JSON.parse(JSON.stringify(this.crud.selections)) |
|||
}, |
|||
handleSort() { |
|||
const data = this.sortTableData.map((value, index) => { |
|||
return { id: value.id, isSequence: index + 1 } |
|||
}) |
|||
this.sortTableData.forEach((item, index) => { |
|||
item.isSequence = index + 1 |
|||
}) |
|||
crudRegion.sort(data).then(() => { |
|||
this.sortVisible = false |
|||
this.$message({ message: '保存成功', type: 'success', offset: 8 }) |
|||
this.crud.refresh() |
|||
}) |
|||
}, |
|||
handleCloseDialog() { |
|||
// if (this.$refs.markRefs.canvas) { |
|||
// this.$refs.markRefs.canvas.clear() |
|||
// this.$refs.markRefs.canvas.dispose() |
|||
// } |
|||
this.markVisible = false |
|||
this.crud.refresh() |
|||
}, |
|||
initCanvasPreview(drawinfo) { |
|||
if (!this.currentMarkData) { |
|||
console.error('currentMarkData is null or undefined') |
|||
return |
|||
} |
|||
|
|||
const canvasId = `canvasPreview${this.currentMarkData.id}` |
|||
this.canvasPreview = new fabric.Canvas(canvasId, { |
|||
skipTargetFind: false, |
|||
selectable: false, |
|||
selection: false |
|||
}) |
|||
|
|||
this.$nextTick(() => { |
|||
this.canvasPreview.selectionColor = 'rgba(0,0,0,0.05)' |
|||
this.loadDrawPreview(drawinfo) |
|||
this.canvasPreview.on('mouse:wheel', this.mouse) |
|||
}) |
|||
}, |
|||
// 鼠标滚轮放大缩小 |
|||
mouse(e) { |
|||
if (undefined === e) return |
|||
let zoom = (e.e.deltaY > 0 ? -0.1 : 0.1) + this.canvasPreview.getZoom() |
|||
zoom = Math.max(0.8, zoom) |
|||
// 最小为原来的1/10 |
|||
zoom = Math.min(3, zoom) |
|||
// 最大是原来的3倍 |
|||
const zoomPoint = new fabric.Point(e.e.pageX, e.e.pageY) |
|||
this.canvasPreview.zoomToPoint(zoomPoint, zoom) |
|||
}, |
|||
// 回显详情信息 |
|||
loadDrawPreview(drawinfo) { |
|||
const self = this |
|||
const pointGroup = drawinfo.pointInfo |
|||
const imgInfo = drawinfo.imgInfo |
|||
imgInfo.src = self.imageUrl |
|||
// 加载底图 |
|||
fabric.util.enlivenObjects([imgInfo], objects => { |
|||
objects.forEach(o => { |
|||
o.selectable = false |
|||
o.hasControls = false |
|||
o.centeredScaling = false |
|||
self.canvasPreview.add(o) |
|||
}) |
|||
// 处理多边形绘制回显操作 |
|||
pointGroup.forEach(async(item, index) => { |
|||
if (item.pointInfo !== '') { |
|||
const polygon = new fabric.Polygon(item.pointInfo, { |
|||
name: item.name, |
|||
stroke: 'rgba(196,43, 1, 1)', |
|||
strokeWidth: self.drawWidth, |
|||
fill: 'rgba(196,43, 1, 1)', |
|||
opacity: 0.5, |
|||
selectable: false, |
|||
hasBorders: false, |
|||
hasControls: false, |
|||
originX: 'left', // 设置原点为左上角 |
|||
originY: 'top' // 设置原点为左上角 |
|||
}) |
|||
// polygon.index = index |
|||
self.canvasPreview.add(polygon) |
|||
|
|||
polygon.on('mousedown', function(e) { |
|||
console.log('Rect ' + (index + 1) + ' clicked', e) |
|||
console.log('e.target.name', e.target.name) |
|||
}) |
|||
|
|||
polygon.on('mouseover', function(e) { |
|||
console.log('e', e) |
|||
console.log('e.target', e.target) |
|||
console.log('e.target.name', e.target.name) |
|||
this.set({ opacity: 0.8, hoverCursor: 'pointer' }) |
|||
self.canvasPreview.renderAll() |
|||
}) |
|||
|
|||
// 监听鼠标移出事件 |
|||
polygon.on('mouseout', function() { |
|||
this.set({ opacity: 0.5 }) |
|||
self.canvasPreview.renderAll() |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
self.canvasPreview.renderAll() |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.tab-content{ |
|||
min-height: calc(100vh - 232px) !important; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,682 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="venue-header"> |
|||
<h4><i class="iconfont icon-shujia" />书架列表</h4> |
|||
<p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p> |
|||
</div> |
|||
<div class="venue-content"> |
|||
<div class="venue-left"> |
|||
<div class="head-container"> |
|||
<div class="head-search"> |
|||
<!-- 搜索 --> |
|||
<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" clearable size="small" placeholder="输入关键字搜索" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @clear="crud.toQuery" @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> |
|||
<div class="double-click-btn"><i class="iconfont icon-zhuyi-lan" /><span>双击列表数据查看对应架位</span></div> |
|||
<el-table |
|||
ref="table" |
|||
v-loading="crud.loading" |
|||
:data="crud.data" |
|||
style="width: 100%;" |
|||
height="507" |
|||
@selection-change="selectionChangeHandler" |
|||
@row-dblclick="onRowDblclick" |
|||
@row-click="clickRowHandler" |
|||
> |
|||
<el-table-column type="selection" align="center" width="55" /> |
|||
<!-- <el-table-column type="index" label="排序" /> --> |
|||
<el-table-column prop="shelfName" label="书架名称" /> |
|||
<el-table-column prop="shelfShelf" label="书架规格"> |
|||
<template slot-scope="scope"> |
|||
<span>{{ scope.row.shelfFloor + ' X ' + scope.row.shelfShelf }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="rowType" label="单/双面"> |
|||
<template slot-scope="scope"> |
|||
<span>{{ scope.row.rowType === 1 ? '单面' :'双面' }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="floorName" label="所属楼层" /> |
|||
<el-table-column prop="regionName" label="所属区域" min-width="100" /> |
|||
<el-table-column prop="signPoint" label="标注"> |
|||
<template slot-scope="scope"> |
|||
<span :class="['row-state', scope.row.signPoint ? 'end-state' : 'cancel-state' ]">{{ scope.row.signPoint ? '已标注': '未标注' }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<!--分页组件--> |
|||
<pagination v-if="crud.data.length!==0" /> |
|||
</div> |
|||
</div> |
|||
<div class="venue-right"> |
|||
<div class="container-right tab-content"> |
|||
<span class="right-top-line" /> |
|||
<span class="left-bottom-line" /> |
|||
<ul class="tab-nav"> |
|||
<li class="active-tab-nav">区域书架<i /></li> |
|||
<!-- 最右侧装饰img --> |
|||
<span class="tab-right-img" /> |
|||
<el-button size="mini" class="venue-mark" :disabled="crud.selections.length !== 1" @click="handleMark"> |
|||
<i class="el-icon-edit" /> |
|||
书架标注 |
|||
</el-button> |
|||
</ul> |
|||
<div class="venue-preview"> |
|||
<!-- <img :src="imageUrl" :onerror="defaultImg" alt=""> --> |
|||
<div v-show="currentMarkData && currentMarkData.signPoint"> |
|||
<canvas id="canvasPreview" :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> |
|||
</div> |
|||
|
|||
<!-- form --> |
|||
<el-dialog append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :before-close="crud.cancelCU" :visible="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" :rules="rules" :model="form" inline size="small" label-width="90px"> |
|||
<el-form-item label="所属楼层" prop="floorName"> |
|||
<el-input v-model="form.floorName" disabled /> |
|||
</el-form-item> |
|||
<el-form-item label="所属区域" prop="regionName"> |
|||
<el-input v-model="form.regionName" disabled /> |
|||
</el-form-item> |
|||
<el-row> |
|||
<el-form-item label="单/双排" prop="rowType"> |
|||
<el-radio-group v-model="form.rowType" v-removeAriaHidden size="mini"> |
|||
<el-radio :label="1">单排</el-radio> |
|||
<el-radio :label="2">双排</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-form-item v-if="form.rowType===1" label="A/B面" prop="toward"> |
|||
<el-select v-model="form.toward" placeholder="请选择" style="width: 225px;"> |
|||
<el-option |
|||
v-for="(item,index) in abOptions" |
|||
:key="index" |
|||
:label="item.name" |
|||
:value="item.value" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-row> |
|||
<el-row> |
|||
<el-form-item label="书架排号" prop="shelfRow"> |
|||
<el-input v-model="form.shelfRow" @blur="formatShelfRow" /> |
|||
</el-form-item> |
|||
<el-form-item label="书架名称" prop="shelfName"> |
|||
<el-input v-model="computedShelfName" disabled /> |
|||
</el-form-item> |
|||
</el-row> |
|||
<el-form-item label="书架规格" prop="rackSpecs"> |
|||
<el-input-number v-model.number="form.shelfFloor" :min="1" :max="999" controls-position="right" style="width:80px;" /> |
|||
<span style="font-size: 12px;">层</span> |
|||
<span style="padding:0 2px;">✕</span> |
|||
<el-input-number v-model.number="form.shelfShelf" :min="1" :max="999" controls-position="right" style="width: 80px;" /> |
|||
<span style="font-size: 12px;">架</span> |
|||
</el-form-item> |
|||
<el-form-item label="架起始标" prop="startShelf"> |
|||
<el-input-number v-model.number="form.startShelf" :min="1" :max="999" controls-position="right" /> |
|||
</el-form-item> |
|||
<el-row> |
|||
<el-form-item label="架号顺序" prop="shelfType"> |
|||
<el-select v-model="form.shelfType" placeholder="请选择" style="width: 586px;"> |
|||
<el-option |
|||
v-for="(item,index) in rackOrderOptions" |
|||
:key="index" |
|||
:label="item.name" |
|||
:value="item.key" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-row> |
|||
<el-row> |
|||
<el-form-item label="层号顺序" prop="floorType"> |
|||
<el-select v-model="form.floorType" placeholder="请选择" style="width: 586px;"> |
|||
<el-option |
|||
v-for="(item,index) in layerSeqOptions" |
|||
:key="index" |
|||
:label="item.name" |
|||
:value="item.key" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-row> |
|||
<el-form-item label="倒架规则" prop="shelfRule"> |
|||
<el-radio-group v-model="form.shelfRule" v-removeAriaHidden size="mini"> |
|||
<el-radio :label="1">有序</el-radio> |
|||
<el-radio :label="2">无序</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-form-item label="错架判断" prop="shelfErrorJudge"> |
|||
<el-radio-group v-model="form.shelfErrorJudge" v-removeAriaHidden size="mini"> |
|||
<el-radio :label="2">格子</el-radio> |
|||
<el-radio :label="1">书架</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> |
|||
|
|||
<!-- 标注 --> |
|||
<el-dialog class="mark-dialog" :close-on-click-modal="false" :append-to-body="true" :title="titleMark" :visible.sync="markVisible" :before-close="handleCloseDialog"> |
|||
<span class="dialog-right-top" /> |
|||
<span class="dialog-left-bottom" /> |
|||
<div class="setting-dialog"> |
|||
<MarkCover ref="markRefs" :is-book-shelf="true" :current-mark-data="currentMarkData" :image-url="imageUrl" @handleCloseDialog="handleCloseDialog" /> |
|||
</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 crudOperation from '@crud/CRUD.operation' |
|||
import pagination from '@crud/Pagination' |
|||
import { mapGetters } from 'vuex' |
|||
import defaultImg from '@/assets/images/system/default-img.jpg' |
|||
import MarkCover from '@/views/components/mark.vue' |
|||
import { fabric } from 'fabric' |
|||
|
|||
const defaultForm = { id: null, floorName: null, floorId: null, regionName: null, rowType: 1, toward: 1, shelfRow: '', shelfName: '', shelfShelf: null, shelfFloor: null, startShelf: null, shelfType: 1, floorType: 1, shelfRule: 1, shelfErrorJudge: 2, signPoint: '' } |
|||
export default { |
|||
name: 'Bookshelf', |
|||
components: { crudOperation, pagination, MarkCover }, |
|||
cruds() { |
|||
return CRUD({ title: '书架', idField: 'shelfId', url: 'api/bookShelf/initBookShelfList', crudMethod: { ...crudShelf }, sort: [], optShow: { |
|||
add: true, |
|||
edit: true, |
|||
del: false, |
|||
download: false, |
|||
group: false, |
|||
reset: false |
|||
}, |
|||
queryOnPresenterCreated: false |
|||
}) |
|||
}, |
|||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|||
data() { |
|||
return { |
|||
permission: { |
|||
add: ['admin', 'floor:add'], |
|||
edit: ['admin', 'floor:edit'], |
|||
del: ['admin', 'floor:del'] |
|||
}, |
|||
floorOptions: [], |
|||
regionOptions: [], |
|||
selectFloorVal: null, |
|||
selectRegionVal: null, |
|||
abOptions: [ |
|||
{ value: 1, name: 'A面' }, |
|||
{ value: 2, name: 'B面' } |
|||
], |
|||
rackOrderOptions: [ |
|||
{ key: 1, name: '始终最左边为第1架(S型排架)' }, |
|||
{ key: 2, name: 'A面最左为第1架(B面最左为最后1架)' }, |
|||
{ key: 3, name: 'B面最左为第1架(A面最左为最后1架)' } |
|||
], |
|||
layerSeqOptions: [ |
|||
{ key: 1, name: '最顶层为第一层(从上至下)' }, |
|||
{ key: 2, name: '最底层为第一层(从下至上)' } |
|||
], |
|||
rules: { |
|||
floorName: [ |
|||
{ required: true, message: '所属楼层不可为空', trigger: 'blur' } |
|||
], |
|||
regionName: [ |
|||
{ required: true, message: '所属区域不可为空', trigger: 'blur' } |
|||
], |
|||
rowType: [ |
|||
{ required: true, message: '请选择单双排', trigger: 'change' } |
|||
], |
|||
shelfRow: [ |
|||
{ required: true, message: '书架排号不可为空', trigger: 'blur' } |
|||
], |
|||
shelfName: [ |
|||
{ validator: this.validateShelfName, trigger: 'blur' } |
|||
], |
|||
rackSpecs: [ |
|||
{ validator: this.validateRackSpecs, trigger: 'blur' } |
|||
], |
|||
startShelf: [ |
|||
{ required: true, message: '架起始标不可为空', trigger: 'blur' } |
|||
], |
|||
shelfType: [ |
|||
{ required: true, message: '请选择架号顺序', trigger: 'change' } |
|||
], |
|||
floorType: [ |
|||
{ required: true, message: '请选择层号顺序', trigger: 'change' } |
|||
], |
|||
shelfRule: [ |
|||
{ required: true, message: '请选择倒架规则', trigger: 'change' } |
|||
], |
|||
shelfErrorJudge: [ |
|||
{ required: true, message: '请选择错架判断', trigger: 'change' } |
|||
] |
|||
}, |
|||
defaultImg: defaultImg, |
|||
imageUrl: defaultImg, |
|||
markVisible: false, // 区域标注 |
|||
titleMark: '书架标注', |
|||
currentMarkData: null, |
|||
|
|||
canvasPreview: {}, |
|||
width: 900, |
|||
height: 600, |
|||
drawWidth: 2 // 笔触宽度 |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'user', |
|||
'baseApi' |
|||
]), |
|||
computedShelfName() { |
|||
const { shelfRow, rowType, toward } = this.form |
|||
if (!shelfRow) { |
|||
return '' |
|||
} |
|||
const baseName = `${shelfRow}排` |
|||
if (rowType === 1 && toward !== null) { |
|||
return `${baseName}${this.abOptions.find(option => option.value === toward).name}` |
|||
} else if (rowType === 2) { |
|||
return baseName |
|||
} |
|||
return '' |
|||
} |
|||
}, |
|||
watch: { |
|||
computedShelfName(newVal) { |
|||
this.form.shelfName = newVal |
|||
}, |
|||
width() { |
|||
this.canvasPreview.setWidth(this.width) |
|||
}, |
|||
height() { |
|||
this.canvasPreview.setHeight(this.height) |
|||
} |
|||
}, |
|||
beforeDestroy() { |
|||
window.removeEventListener('beforeunload', this.clearLocalStorage) |
|||
}, |
|||
created() { |
|||
this.getLibraryFloorListAll() |
|||
}, |
|||
mounted() { |
|||
|
|||
}, |
|||
methods: { |
|||
clearLocalStorage() { |
|||
const key = 'formArea' |
|||
if (localStorage.getItem(key)) { |
|||
localStorage.removeItem(key) |
|||
} |
|||
}, |
|||
formatShelfRow() { |
|||
let value = this.form.shelfRow |
|||
value = value.toString() |
|||
if (value.length < 3) { |
|||
value = value.padStart(3, '0') |
|||
} else if (value.length > 3) { |
|||
value = value.slice(0, 3) |
|||
} |
|||
this.form.shelfRow = value |
|||
}, |
|||
validateShelfName(rule, value, callback) { |
|||
if (this.form.shelfRow) { |
|||
if (!value) { |
|||
callback(new Error('书架名称不能为空')) |
|||
} else { |
|||
callback() |
|||
} |
|||
} else { |
|||
callback() |
|||
} |
|||
}, |
|||
validateRackSpecs(rule, value, callback) { |
|||
// 检查 shelfShelf 和 shelfFloor 是否为空 |
|||
if (!this.form.shelfShelf) { |
|||
callback(new Error('请输入书架规格中书架架数')) |
|||
} else if (!this.form.shelfFloor) { |
|||
callback(new Error('请输入书架规格中书架层数')) |
|||
} else { |
|||
callback() |
|||
} |
|||
}, |
|||
[CRUD.HOOK.beforeRefresh]() { |
|||
console.log(this.$route.query) |
|||
if (this.$route.query.formArea) { |
|||
const formArea = JSON.parse(localStorage.getItem('formArea')) |
|||
if (formArea) { |
|||
this.selectFloorVal = { |
|||
id: formArea.floorId, |
|||
floorMap: formArea.floorMap, |
|||
floorName: formArea.floorName |
|||
} |
|||
this.selectRegionVal = formArea |
|||
this.crud.query.floorId = this.selectFloorVal.id |
|||
this.crud.query.regionId = this.selectRegionVal.id |
|||
|
|||
FetchInitLibraryRegionList({ 'floorId': this.selectFloorVal.id }).then(res => { |
|||
this.regionOptions = res.content |
|||
}).catch(() => { |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
[CRUD.HOOK.afterRefresh](crud) { |
|||
console.log(crud.data) |
|||
if (this.selectRegionVal && this.selectRegionVal.regionMap) { |
|||
this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=1&imgId=' + this.selectRegionVal.regionMap |
|||
} else { |
|||
this.imageUrl = defaultImg |
|||
} |
|||
}, |
|||
// 新增与编辑前做的操作 |
|||
[CRUD.HOOK.afterToCU](crud, form) { |
|||
console.log(form) |
|||
console.log('crud.query.floorId', crud.query.floorId) |
|||
console.log('selectFloorVal', this.selectFloorVal) |
|||
console.log('crud.query.regionId', crud.query.regionId) |
|||
console.log('selectRegionVal', this.selectRegionVal) |
|||
form.floorId = this.selectFloorVal.id |
|||
form.floorName = this.selectFloorVal.floorName |
|||
form.regionId = this.selectRegionVal.id |
|||
form.regionName = this.selectRegionVal.regionName |
|||
}, |
|||
// 编辑前 |
|||
[CRUD.HOOK.beforeToEdit](crud, form) { |
|||
const params = { |
|||
'shelfId': this.crud.selections[0].shelfId |
|||
} |
|||
crudShelf.FetchBookShelfDetails(params).then(res => { |
|||
form.id = res.id |
|||
// 单/双排 1 单 2 双 |
|||
form.rowType = res.rowType |
|||
// A/B面 1 A 2 B |
|||
form.toward = res.toward |
|||
// 书架排号 |
|||
form.shelfRow = res.shelfRow |
|||
// 书架名称 |
|||
form.shelfName = res.shelfName |
|||
// 书架规格 架 |
|||
form.shelfShelf = res.shelfShelf |
|||
// 书架规格 层 |
|||
form.shelfFloor = res.shelfFloor |
|||
// 架起始标 |
|||
form.startShelf = res.startShelf |
|||
// 架号顺序 |
|||
form.shelfType = res.shelfType |
|||
// 层号顺序 |
|||
form.floorType = res.floorType |
|||
// 倒架规则 1 无序 2 有序 |
|||
form.shelfRule = res.shelfRule |
|||
// 错架判断 1 书架 2 格子 |
|||
form.shelfErrorJudge = res.shelfErrorJudge |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
// 提交前的验证 |
|||
[CRUD.HOOK.afterValidateCU](crud) { |
|||
console.log(crud.form) |
|||
delete crud.form.floorName |
|||
delete crud.form.regionName |
|||
return true |
|||
}, |
|||
// 获取楼层数据 |
|||
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() |
|||
} |
|||
}, |
|||
selectionChangeHandler(val) { |
|||
this.crud.selections = val |
|||
// 处理选择项为1且有签名点的情况 |
|||
if (this.crud.selections.length === 1 && this.crud.selections[0].signPoint) { |
|||
this.currentMarkData = val[0] |
|||
if (this.canvasPreview.lowerCanvasEl) { |
|||
this.canvasPreview.clear() |
|||
this.canvasPreview.dispose() |
|||
} |
|||
|
|||
try { |
|||
const drawinfo = JSON.parse(this.crud.selections[0].signPoint) |
|||
this.initCanvasPreview(drawinfo) |
|||
} catch (error) { |
|||
console.error(error) |
|||
this.resetImageUrl() |
|||
} |
|||
} else { |
|||
// 处理选择项大于1或选择项为0的情况 |
|||
this.currentMarkData = null |
|||
this.setImageUrlBasedOnRegionMap() |
|||
} |
|||
}, |
|||
setImageUrlBasedOnRegionMap() { |
|||
if (this.selectRegionVal && this.selectRegionVal.regionMap) { |
|||
this.imageUrl = `${this.baseApi}/api/fileRelevant/getImg?imgType=1&imgId=${this.selectRegionVal.regionMap}` |
|||
} else { |
|||
this.resetImageUrl() |
|||
} |
|||
}, |
|||
resetImageUrl() { |
|||
this.imageUrl = this.defaultImg |
|||
}, |
|||
async handleMark() { |
|||
if (this.crud.selections.length === 1) { |
|||
const selection = this.crud.selections[0] |
|||
if (selection && this.selectRegionVal.regionMap) { |
|||
this.markVisible = true |
|||
this.currentMarkData = selection |
|||
this.titleMark = this.currentMarkData.shelfName + ' - 书架标注' |
|||
this.$nextTick(() => { |
|||
this.$refs.markRefs.drawinfo = this.currentMarkData && this.currentMarkData.signPoint ? JSON.parse(this.currentMarkData.signPoint) : null |
|||
this.$refs.markRefs.initCanvas() |
|||
}) |
|||
} else { |
|||
this.$message({ message: '请先上传当前区域图', type: 'error', offset: 8 }) |
|||
} |
|||
} else { |
|||
console.error('666') |
|||
} |
|||
}, |
|||
clickRowHandler(row) { |
|||
this.$refs.table.clearSelection() |
|||
this.$refs.table.toggleRowSelection(row) |
|||
}, |
|||
onRowDblclick(row) { |
|||
crudShelf.FetchBookShelfDetails({ 'shelfId': row.shelfId }).then(res => { |
|||
this.$router.push({ path: '/bookshelf/bookshelfPosition', query: { 'floorName': row.floorName, 'regionName': row.regionName }}) |
|||
localStorage.setItem('bookShelfDetails', JSON.stringify(res)) |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
toDelete(datas) { |
|||
this.$confirm('此操作将删除当前所选书架<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
this.crud.delAllLoading = true |
|||
const ids = [] |
|||
datas.forEach(val => { |
|||
ids.push(val.shelfId) |
|||
}) |
|||
console.log(ids) |
|||
crudShelf.del(ids).then(res => { |
|||
console.log(res) |
|||
this.$message({ message: res, type: 'success', offset: 8 }) |
|||
this.crud.delAllLoading = false |
|||
this.crud.refresh() |
|||
}).catch(err => { |
|||
this.crud.delAllLoading = false |
|||
console.log(err) |
|||
}) |
|||
}).catch(() => { |
|||
this.crud.delAllLoading = false |
|||
}) |
|||
}, |
|||
handleCloseDialog() { |
|||
this.markVisible = false |
|||
this.crud.refresh() |
|||
}, |
|||
initCanvasPreview(drawinfo) { |
|||
this.canvasPreview = new fabric.Canvas('canvasPreview', { |
|||
skipTargetFind: false, |
|||
selectable: false, |
|||
selection: false |
|||
}) |
|||
|
|||
this.canvasPreview.selectionColor = 'rgba(0,0,0,0.05)' |
|||
this.loadDrawPreview(drawinfo) |
|||
this.canvasPreview.on('mouse:wheel', this.mouse) |
|||
}, |
|||
// 鼠标滚轮放大缩小 |
|||
mouse(e) { |
|||
if (undefined === e) return |
|||
let zoom = (e.e.deltaY > 0 ? -0.1 : 0.1) + this.canvasPreview.getZoom() |
|||
zoom = Math.max(0.8, zoom) |
|||
// 最小为原来的1/10 |
|||
zoom = Math.min(3, zoom) |
|||
// 最大是原来的3倍 |
|||
const zoomPoint = new fabric.Point(e.e.pageX, e.e.pageY) |
|||
this.canvasPreview.zoomToPoint(zoomPoint, zoom) |
|||
}, |
|||
// 回显详情信息 |
|||
loadDrawPreview(drawinfo) { |
|||
const self = this |
|||
const pointGroup = drawinfo.pointInfo |
|||
const imgInfo = drawinfo.imgInfo |
|||
imgInfo.src = self.imageUrl |
|||
// 加载底图 |
|||
fabric.util.enlivenObjects([imgInfo], objects => { |
|||
objects.forEach(o => { |
|||
o.selectable = false |
|||
o.hasControls = false |
|||
o.centeredScaling = false |
|||
self.canvasPreview.add(o) |
|||
}) |
|||
// 处理多边形绘制回显操作 |
|||
pointGroup.forEach(async(item, index) => { |
|||
if (item.pointInfo !== '') { |
|||
const polygon = new fabric.Polygon(item.pointInfo, { |
|||
name: item.name, |
|||
stroke: 'rgba(196,43, 1, 1)', |
|||
strokeWidth: self.drawWidth, |
|||
fill: 'rgba(196,43, 1, 1)', |
|||
opacity: 0.5, |
|||
selectable: false, |
|||
hasBorders: false, |
|||
hasControls: false, |
|||
originX: 'left', // 设置原点为左上角 |
|||
originY: 'top' // 设置原点为左上角 |
|||
}) |
|||
// polygon.index = index |
|||
self.canvasPreview.add(polygon) |
|||
|
|||
polygon.on('mousedown', function(e) { |
|||
console.log('Rect ' + (index + 1) + ' clicked', e) |
|||
console.log('e.target.name', e.target.name) |
|||
}) |
|||
|
|||
polygon.on('mouseover', function(e) { |
|||
console.log('e', e) |
|||
console.log('e.target', e.target) |
|||
console.log('e.target.name', e.target.name) |
|||
this.set({ opacity: 0.8, hoverCursor: 'pointer' }) |
|||
self.canvasPreview.renderAll() |
|||
}) |
|||
|
|||
// 监听鼠标移出事件 |
|||
polygon.on('mouseout', function() { |
|||
this.set({ opacity: 0.5 }) |
|||
self.canvasPreview.renderAll() |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
self.canvasPreview.renderAll() |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.tab-content{ |
|||
min-height: calc(100vh - 232px) !important; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,594 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="venue-header"> |
|||
<h4><i class="iconfont icon-shujia" />架位列表</h4> |
|||
<span class="bookshelf-area">{{ floorName }} - {{ regionName }}</span> |
|||
<p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p> |
|||
</div> |
|||
<div class="bookshelf-main"> |
|||
<div class="bookshelf-top"> |
|||
<ul class="bookshelf-info"> |
|||
<li><p>书架名称:</p><span>{{ bookShelfDetails && bookShelfDetails.shelfName }}</span></li> |
|||
<li><p>书架规格:</p><span>{{ bookShelfDetails && bookShelfDetails.shelfFloor + ' X ' + bookShelfDetails.shelfShelf }}</span></li> |
|||
<li><p>单/双面:</p><span>{{ bookShelfDetails && bookShelfDetails.rowType === 1 ? '单面' :'双面' }}</span></li> |
|||
<li><p>倒架规则:</p><span>{{ bookShelfDetails && bookShelfDetails.shelfRule === 1 ? '无序' :'有序' }}</span></li> |
|||
<li><p>错架判断:</p><span>{{ bookShelfDetails && bookShelfDetails.shelfErrorJudge === 1 ? '书架' :'格子' }}</span></li> |
|||
<!-- <li><p>前端测试用-架号顺序:</p><span>{{ bookShelfDetails && bookShelfDetails.shelfType === 1 ? '始终最左边为第1架(S型排架)' : (bookShelfDetails.shelfType === 2 ? 'A面最左为第1架(B面最左为最后1架)' : 'B面最左为第1架(A面最左为最后1架)') }}</span></li> |
|||
<li><p>前端测试用-层号顺序:</p><span>{{ bookShelfDetails && bookShelfDetails.floorType === 1 ? '最顶层为第一层(从上至下)' :'最底层为第一层(从下至上)' }}</span></li> --> |
|||
</ul> |
|||
<div class="bookshelf-button"> |
|||
<el-button size="mini" @click="doExport"> |
|||
<i class="iconfont icon-daochu" /> |
|||
导出层位编码 |
|||
</el-button> |
|||
<el-button size="mini" :disabled="!cellInfo.cameraId" @click="handleViewVideo(cellInfo.cameraId)"> |
|||
<i class="iconfont icon-yulan" /> |
|||
{{ cellInfo.cameraId ? '摄像头预览' : '未绑定摄像头' }} |
|||
</el-button> |
|||
</div> |
|||
</div> |
|||
<div class="bookshelf-layer-info"> |
|||
<div class="bookshelf-left"> |
|||
<swiper |
|||
ref="swiperTitle" |
|||
class="swiper-title" |
|||
:options="swiperOptionTitle" |
|||
:auto-update="true" |
|||
:auto-destroy="true" |
|||
:delete-instance-on-destroy="true" |
|||
:cleanup-styles-on-destroy="true" |
|||
> |
|||
<swiper-slide |
|||
v-for="(item, index) of tabListData" |
|||
ref="swiperSlideItem" |
|||
:key="'name' + index" |
|||
:iname="item.name" |
|||
class="swiper-slide-title" |
|||
> |
|||
<div |
|||
class="tab-name" |
|||
:class="{ active: index === swiperActiveIndex }" |
|||
@click="handleSlidClickFun(index)" |
|||
> |
|||
{{ item.name }} |
|||
</div> |
|||
</swiper-slide> |
|||
</swiper> |
|||
<swiper |
|||
ref="swiperContent" |
|||
class="swiper-content" |
|||
:style="rowStyle" |
|||
:options="swiperOptionContent" |
|||
:auto-update="true" |
|||
:auto-destroy="true" |
|||
:delete-instance-on-destroy="true" |
|||
:cleanup-styles-on-destroy="true" |
|||
> |
|||
<swiper-slide |
|||
v-for="(item, index) of tabListData" |
|||
:key="'content' + index" |
|||
class="swiper-slide-content" |
|||
> |
|||
<ul class="cabinet-row" :style="rowStyle"> |
|||
<li v-for="(shelf,i) in booShelfGrid" :key="i" class="cabinet-cell" :style="cellStyle" :class="{ active: i === cellIndex }" @click="handleCellCurrent(shelf,i)"> |
|||
<span>{{ shelf.gridName | removeQUPrefix }}</span> |
|||
</li> |
|||
</ul> |
|||
</swiper-slide> |
|||
</swiper> |
|||
</div> |
|||
<div class="bookshelf-right-info"> |
|||
<div class="layer-status"> |
|||
<span v-if="cellInfo.startSortmark && cellInfo.endSortmark && checkValue === 'true'" class="row-state end-state">正常盘点</span> |
|||
<span v-if="!cellInfo.startSortmark && !cellInfo.endSortmark && checkValue === 'true'" class="row-state soon-state">待初始化</span> |
|||
<span v-if="checkValue === 'false'" class="row-state cancel-state">停止盘点</span> |
|||
<span v-if="bookSortValue === 'false'" class="row-state other-state">无序倒架</span> |
|||
<span v-else class="row-state ing-state">有序倒架</span> |
|||
</div> |
|||
<h5 class="layer-name">{{ cellInfo.gridName | removeQUPrefix }}</h5> |
|||
<div class="layer-code-sort"> |
|||
<ul> |
|||
<!-- I247.58/586 --> |
|||
<li><p>起始索书号</p><span>{{ cellInfo.startSortmark ? cellInfo.startSortmark : '-' }}</span></li> |
|||
<li><p>结束索书号</p><span>{{ cellInfo.endSortmark? cellInfo.endSortmark : '-' }}</span></li> |
|||
</ul> |
|||
<el-button size="mini" class="edit-callNumber" @click="handleEditGridNum"> |
|||
<!-- <i class="iconfont icon-yulan" /> --> |
|||
<!-- <i>编 辑</i> |
|||
<i>索书号</i> --> |
|||
编辑索书号 |
|||
</el-button> |
|||
</div> |
|||
<ul class="layer-handle"> |
|||
<li> |
|||
<p>层位盘点开关</p> |
|||
<el-switch |
|||
v-model="checkValue" |
|||
active-color="#13ce66" |
|||
inactive-color="#ff4949" |
|||
active-value="true" |
|||
inactive-value="false" |
|||
@change="changeCheckSwitch" |
|||
/> |
|||
</li> |
|||
<li> |
|||
<p>图书有序检查</p> |
|||
<el-switch |
|||
v-model="bookSortValue" |
|||
active-color="#13ce66" |
|||
inactive-color="#ff4949" |
|||
active-value="true" |
|||
inactive-value="false" |
|||
@change="changeBookSortSwitch" |
|||
/> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 编辑索书号 --> |
|||
<el-dialog append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :visible="callNumVisible" title="编辑索书号范围" :before-close="handleClose"> |
|||
<span class="dialog-right-top" /> |
|||
<span class="dialog-left-bottom" /> |
|||
<div class="setting-dialog"> |
|||
<el-form ref="form" :rules="rules" :model="form" size="small" label-width="100px"> |
|||
<el-form-item label="所属架位" prop="gridName"> |
|||
<el-input v-model="form.gridName" disabled style="width: 580px;" /> |
|||
</el-form-item> |
|||
<el-form-item label="起始索书号" prop="startSortmark"> |
|||
<el-input v-model="form.startSortmark" style="width: 580px;" /> |
|||
</el-form-item> |
|||
<el-form-item label="结束索书号" prop="endSortmark"> |
|||
<el-input v-model="form.endSortmark" style="width: 580px;" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="text" @click.native="handleClose">取消</el-button> |
|||
<el-button type="primary" @click.native="handleSaveCallNum">保存</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
<!-- 查看监控视频 --> |
|||
<el-dialog class="view-video" append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :visible="hkVideoVisible" title="查看监控视频" :before-close="handleClose"> |
|||
<span class="dialog-right-top" /> |
|||
<span class="dialog-left-bottom" /> |
|||
<div class="setting-dialog"> |
|||
<hkVideo ref="hkVideoRef" :hk-config="hkConfig" /> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
// https://blog.csdn.net/qq_37236395/article/details/119737898 |
|||
import { FetchInitShelfGridByShelfId, FetcheEditSortmarkByGrid, FetchChangeOrderByGrid, FetchChangeCheckByGrid } from '@/api/shelf/index' |
|||
import { FetchDeviceById } from '@/api/deviceVI/index' |
|||
import { mapGetters } from 'vuex' |
|||
import { swiper, swiperSlide } from 'vue-awesome-swiper' |
|||
import 'swiper/dist/css/swiper.css' |
|||
import { parseTime, saveAs, getBlob } from '@/utils/index' |
|||
import qs from 'qs' |
|||
import hkVideo from '@/views/components/hkVideo.vue' |
|||
|
|||
export default { |
|||
name: 'BookshelfPosition', |
|||
components: { swiper, swiperSlide, hkVideo }, |
|||
data() { |
|||
const _this = this |
|||
return { |
|||
floorName: null, |
|||
regionName: null, |
|||
bookShelfDetails: null, |
|||
booShelfGrid: null, |
|||
cellInfo: { |
|||
gridName: null, |
|||
startSortmark: null, |
|||
endSortmark: null, |
|||
cameraId: null |
|||
}, |
|||
callNumVisible: false, |
|||
layerNum: 0, |
|||
rackNum: 0, |
|||
checkValue: 'true', |
|||
bookSortValue: 'true', |
|||
swiperActiveIndex: 0, |
|||
cellIndex: null, |
|||
swiperOptionContent: { |
|||
slidesPerView: 'auto', |
|||
on: { |
|||
slideChangeTransitionStart: function() { |
|||
_this.cellIndex = null |
|||
_this.swiperActiveIndex = this.activeIndex |
|||
console.log('activeIndexffff', this.swiperActiveIndex) |
|||
_this.swiperTitle.slideTo(this.activeIndex, 500, false) |
|||
} |
|||
} |
|||
}, |
|||
swiperOptionTitle: { |
|||
slidesPerView: 'auto', |
|||
freeMode: true |
|||
}, |
|||
tabListData: [], |
|||
form: { |
|||
id: null, |
|||
gridName: null, |
|||
startSortmark: null, |
|||
endSortmark: null, |
|||
check: null, |
|||
order: null, |
|||
cameraId: null |
|||
}, |
|||
rules: { |
|||
gridName: [ |
|||
{ required: true, message: '所属架位不可为空', trigger: 'blur' } |
|||
], |
|||
startSortmark: [ |
|||
{ required: true, message: '起始索书号不可为空', trigger: 'blur' } |
|||
], |
|||
endSortmark: [ |
|||
{ required: true, message: '结束索书号不可为空', trigger: 'blur' } |
|||
] |
|||
}, |
|||
hkVideoVisible: false, |
|||
hkConfig: { |
|||
'username': null, |
|||
'password': null, |
|||
'ip': null, |
|||
'port': null |
|||
} |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'user', |
|||
'baseApi' |
|||
]), |
|||
swiperContent() { |
|||
return this.$refs.swiperContent.$el.swiper |
|||
}, |
|||
swiperTitle() { |
|||
return this.$refs.swiperTitle.$el.swiper |
|||
}, |
|||
cellStyle: function() { |
|||
// const h = '100%/' + this.layerNum |
|||
// const w = '100%/' + this.rackNum |
|||
const h = '60px' |
|||
const w = '146px' |
|||
return { width: `calc(${w} - 4px )`, height: `calc(${h} - 2px)` } |
|||
}, |
|||
rowStyle: function() { |
|||
const w = 146 * this.rackNum + 'px' |
|||
return { width: `calc(${w})` } |
|||
} |
|||
}, |
|||
watch: { |
|||
'$route'(val, from) { // 监听到路由(参数)改变 |
|||
if (this.$route.query) { |
|||
this.floorName = this.$route.query.floorName |
|||
this.regionName = this.$route.query.regionName |
|||
} |
|||
} |
|||
}, |
|||
async created() { |
|||
if (this.$route.query) { |
|||
this.floorName = this.$route.query.floorName |
|||
this.regionName = this.$route.query.regionName |
|||
} |
|||
if (localStorage.getItem('bookShelfDetails')) { |
|||
this.bookShelfDetails = JSON.parse(localStorage.getItem('bookShelfDetails')) |
|||
this.layerNum = this.bookShelfDetails.shelfFloor |
|||
this.rackNum = this.bookShelfDetails.shelfShelf |
|||
|
|||
// 单面/双面 |
|||
this.tabListData = this.bookShelfDetails.rowType === 1 |
|||
? this.bookShelfDetails.toward === 1 |
|||
? [{ name: 'A面' }] |
|||
: [{ name: 'B面' }] |
|||
: [{ name: 'A面' }, { name: 'B面' }] |
|||
|
|||
// 层数据 |
|||
this.getInitShelfGridByShelfId(this.bookShelfDetails.toward) |
|||
} |
|||
}, |
|||
mounted() { |
|||
}, |
|||
methods: { |
|||
removeAreaPrefix(gridNames) { |
|||
const index = gridNames.indexOf('区') |
|||
if (index !== -1) { |
|||
return gridNames.substring(index + 1) |
|||
} |
|||
return gridNames |
|||
}, |
|||
getInitShelfGridByShelfId(toward) { |
|||
// rowType 1 单 2 双 |
|||
// toward 1 A面 2 B面 |
|||
// shelfType 1 '始终最左边为第1架(S型排架)' |
|||
// shelfType 2 'A面最左为第1架(B面最左为最后1架)' |
|||
// shelfType 3 'B面最左为第1架(A面最左为最后1架)' |
|||
// floorType 1 '最顶层为第一层(从上至下)' |
|||
// floorType 2 '最底层为第一层(从下至上)' |
|||
FetchInitShelfGridByShelfId({ 'shelfId': this.bookShelfDetails.id, 'toward': toward }).then(res => { |
|||
const sortFunction = toward === 1 ? { |
|||
1: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' }, |
|||
2: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' }, |
|||
3: { 1: 'sortBookshelvesRightTop', 2: 'sortBookshelvesRightBottom' } |
|||
} : { |
|||
1: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' }, |
|||
2: { 1: 'sortBookshelvesRightTop', 2: 'sortBookshelvesRightBottom' }, |
|||
3: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' } |
|||
} |
|||
const shelfType = this.bookShelfDetails.shelfType |
|||
const floorType = this.bookShelfDetails.floorType |
|||
const sortMethod = sortFunction[shelfType][floorType] |
|||
this.booShelfGrid = this[sortMethod](res) |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
// 最左为第一架, 最顶层为第一层 从上往下 |
|||
sortBookshelvesLeftTop(data) { |
|||
const sortedData = [] |
|||
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor))) |
|||
const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.slice(-1)))) |
|||
|
|||
for (let i = 1; i <= maxFloor; i++) { |
|||
for (let j = 1; j <= maxShelf; j++) { |
|||
const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.slice(-1)) === j) |
|||
if (currentShelf) { |
|||
sortedData.push(currentShelf) |
|||
} |
|||
} |
|||
} |
|||
return sortedData |
|||
}, |
|||
// 最右为第一架,最左为最后一架, 最顶层为第一层 从上往下 |
|||
sortBookshelvesRightTop(data) { |
|||
const sortedData = [] |
|||
// 获取最大的楼层数 |
|||
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor))) |
|||
const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.match(/\d+$/)[0]))) |
|||
for (let i = 1; i <= maxFloor; i++) { |
|||
// 从最大的书架层数开始,向下排序 |
|||
for (let j = maxShelf; j >= 1; j--) { |
|||
const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.match(/\d+$/)[0]) === j) |
|||
if (currentShelf) { |
|||
sortedData.push(currentShelf) |
|||
} |
|||
} |
|||
} |
|||
return sortedData |
|||
}, |
|||
// 最左为第一架, 最底层为第一层 从下往上 |
|||
sortBookshelvesLeftBottom(data) { |
|||
const sortedData = [] |
|||
// 获取最大的楼层数 |
|||
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor))) |
|||
// 获取最大的书架层数 |
|||
const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.slice(-1)))) |
|||
for (let i = maxFloor; i >= 1; i--) { |
|||
for (let j = 1; j <= maxShelf; j++) { |
|||
const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.slice(-1)) === j) |
|||
if (currentShelf) { |
|||
sortedData.push(currentShelf) |
|||
} |
|||
} |
|||
} |
|||
return sortedData |
|||
}, |
|||
// 最左为最后一架, 最底层为第一层 从下往上 |
|||
sortBookshelvesRightBottom(data) { |
|||
const sortedData = [] |
|||
// 获取最大的楼层数 |
|||
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor))) |
|||
const maxShelfPerFloor = data.map(item => parseInt(item.gridShelf.match(/\d+$/)[0])) |
|||
.reduce((acc, curr, index, arr) => { |
|||
const floor = parseInt(data[index].gridFloor) |
|||
if (!acc[floor]) acc[floor] = 1 |
|||
if (acc[floor] < curr) acc[floor] = curr |
|||
return acc |
|||
}, {}) |
|||
// 从最大的楼层开始向下遍历 |
|||
for (let i = maxFloor; i >= 1; i--) { |
|||
// 从最大的书架编号开始向左遍历 |
|||
for (let j = maxShelfPerFloor[i] || 1; j >= 1; j--) { |
|||
const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.match(/\d+$/)[0]) === j) |
|||
if (currentShelf) { |
|||
sortedData.push(currentShelf) |
|||
} |
|||
} |
|||
} |
|||
return sortedData |
|||
}, |
|||
handleSlidClickFun(index) { |
|||
this.cellIndex = null |
|||
this.handleSlideToFun(index) |
|||
if (localStorage.getItem('bookShelfDetails')) { |
|||
this.getInitShelfGridByShelfId(index + 1) |
|||
} |
|||
}, |
|||
handleSlideToFun(index) { |
|||
this.swiperActiveIndex = index |
|||
this.swiperContent.slideTo(index, 500, false) |
|||
this.swiperTitle.slideTo(index, 500, false) |
|||
}, |
|||
handleCellCurrent(item, index) { |
|||
this.cellIndex = index |
|||
this.cellInfo = { |
|||
id: item.id, |
|||
gridName: item.gridName, |
|||
startSortmark: item.startSortmark, |
|||
endSortmark: item.endSortmark, |
|||
cameraId: item.cameraId, |
|||
check: item.isCheck, |
|||
order: item.isOrder |
|||
} |
|||
this.checkValue = `${item.isCheck}` |
|||
this.bookSortValue = `${item.isOrder}` |
|||
}, |
|||
handleEditGridNum() { |
|||
console.log(this.cellIndex) |
|||
if (this.cellIndex !== null) { |
|||
this.callNumVisible = true |
|||
this.form = this.cellInfo |
|||
console.log(this.cellInfo) |
|||
} else { |
|||
this.$message({ message: '请选择需要操作得层位', type: 'error', offset: 8 }) |
|||
} |
|||
}, |
|||
handleSaveCallNum() { |
|||
if (this.$refs['form']) { |
|||
this.$refs['form'].validate((valid) => { |
|||
if (valid) { |
|||
console.log(this.form) |
|||
FetcheEditSortmarkByGrid(this.form).then(res => { |
|||
console.log(res) |
|||
if (res) { |
|||
this.$message({ message: '编辑索书号范围成功', type: 'success', offset: 8 }) |
|||
this.callNumVisible = false |
|||
} |
|||
}).catch(() => { |
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
}, |
|||
handleClose() { |
|||
if (this.callNumVisible) { |
|||
this.$refs['form'].resetFields() |
|||
this.callNumVisible = false |
|||
} |
|||
this.hkVideoVisible = false |
|||
}, |
|||
handleViewVideo(data) { |
|||
console.log('data', data) |
|||
FetchDeviceById({ 'deviceId': data }).then(res => { |
|||
if (res) { |
|||
console.log(res) |
|||
this.hkConfig = { |
|||
'username': res.account, |
|||
'password': res.password, |
|||
'ip': res.ipv4, |
|||
'port': res.rtsp |
|||
} |
|||
this.hkVideoVisible = true |
|||
this.$nextTick(() => { |
|||
this.$refs.hkVideoRef.initVideo() |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
// 盘点 |
|||
changeCheckSwitch(data) { |
|||
console.log(data) |
|||
if (this.cellIndex !== null) { |
|||
this.$confirm('此操作将开启/关闭该层位的盘点功能' + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
this.cellInfo.check = JSON.parse(data) |
|||
console.log(this.cellInfo) |
|||
FetchChangeCheckByGrid(this.cellInfo).then(res => { |
|||
this.$message({ message: '修改层位盘点状态成功', type: 'success', offset: 8 }) |
|||
if (localStorage.getItem('bookShelfDetails')) { |
|||
this.getInitShelfGridByShelfId(this.swiperActiveIndex + 1) |
|||
} |
|||
}).catch(() => { |
|||
this.checkValue = data === 'true' ? 'false' : 'true' |
|||
}) |
|||
}).catch(() => { |
|||
this.checkValue = data === 'true' ? 'false' : 'true' |
|||
}) |
|||
} else { |
|||
this.$message({ message: '请选择需要操作得层位', type: 'error', offset: 8 }) |
|||
this.checkValue = data === 'true' ? 'false' : 'true' |
|||
return false |
|||
} |
|||
}, |
|||
changeBookSortSwitch(data) { |
|||
console.log(data) |
|||
if (this.cellIndex !== null) { |
|||
this.$confirm('此操作将开启/关闭该层位的图书顺序检查' + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
this.cellInfo.order = JSON.parse(data) |
|||
FetchChangeOrderByGrid(this.cellInfo).then(res => { |
|||
this.$message({ message: '修改图书有序检查状态成功', type: 'success', offset: 8 }) |
|||
if (localStorage.getItem('bookShelfDetails')) { |
|||
this.getInitShelfGridByShelfId(this.swiperActiveIndex + 1) |
|||
} |
|||
}).catch(() => { |
|||
this.bookSortValue = data === 'true' ? 'false' : 'true' |
|||
}) |
|||
}).catch(() => { |
|||
this.bookSortValue = data === 'true' ? 'false' : 'true' |
|||
}) |
|||
} else { |
|||
this.$message({ message: '请选择需要操作得层位', type: 'error', offset: 8 }) |
|||
this.bookSortValue = data === 'true' ? 'false' : 'true' |
|||
return false |
|||
} |
|||
}, |
|||
doExport() { |
|||
console.log(this.bookShelfDetails) |
|||
this.$confirm('此操作将导出所选数据' + '<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
const params = { |
|||
'shelfId': this.bookShelfDetails.id, |
|||
'toward': this.bookShelfDetails.toward |
|||
} |
|||
console.log(params) |
|||
const fileName = '层位编码-' + parseTime(new Date()) + '.xlsx' |
|||
getBlob(this.baseApi + '/api/bookShelf/exportShelfGridLabel' + '?' + qs.stringify(params, { indices: false }), function(blob) { |
|||
saveAs(blob, fileName) |
|||
}) |
|||
}).catch(() => { |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.swiper-title{ |
|||
::v-deep .swiper-wrapper{ |
|||
margin: 10px 0; |
|||
border-bottom: 1px solid #EDEFF3; |
|||
} |
|||
} |
|||
.swiper-slide-title { |
|||
width: auto !important; |
|||
margin-right: 20px; |
|||
cursor: pointer; |
|||
.tab-name { |
|||
padding: 10px; |
|||
&.active { |
|||
color: #0348F3; |
|||
border-bottom: 3px solid #0348F3; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.swiper-content{ |
|||
height: 544px; |
|||
} |
|||
.view-video{ |
|||
::v-deep .el-dialog{ |
|||
width: 1000px !important; |
|||
} |
|||
} |
|||
.swiper-container{ |
|||
margin: 0 !important; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,769 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="container-main" style="justify-content: flex-start;"> |
|||
<div class="elect-cont-left"> |
|||
<el-tree |
|||
ref="tree" |
|||
:data="regionTreeData" |
|||
:props="defaultProps" |
|||
node-key="id" |
|||
default-expand-all |
|||
:default-checked-keys="defaultCheckedKeys" |
|||
:expand-on-click-node="false" |
|||
:highlight-current="true" |
|||
:render-content="renderContent" |
|||
@node-click="handleNodeClick" |
|||
/> |
|||
</div> |
|||
<!--用户数据--> |
|||
<div class="elect-cont-right"> |
|||
<!--工具栏--> |
|||
<div class="head-container"> |
|||
<div class="head-search"> |
|||
<!-- 搜索 --> |
|||
<el-input |
|||
v-model="search" |
|||
size="small" |
|||
clearable |
|||
placeholder="输入设备编号或名称搜索" |
|||
style="width: 320px;" |
|||
class="input-prepend filter-item" |
|||
@clear="crud.toQuery" |
|||
@keyup.enter.native="crud.toQuery" |
|||
> |
|||
<el-select slot="prepend" v-model="optionVal" style="width: 120px" @change="searchChange"> |
|||
<el-option |
|||
v-for="item in options" |
|||
:key="item.id" |
|||
:label="item.name" |
|||
:value="item.id" |
|||
/> |
|||
</el-select> |
|||
</el-input> |
|||
<!-- <el-input v-model="query.blurry" clearable size="small" placeholder="输入设备编号或名称搜索" prefix-icon="el-icon-search" style="width: 225px;" class="filter-item" @keyup.enter.native="crud.toQuery" /> --> |
|||
<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 :permission="permission"> |
|||
<template v-slot:left> |
|||
<el-button v-permission="permission.add" size="mini" :disabled="activeRightBtn" @click="deviceSelectVisible = true"> |
|||
<i class="iconfont icon-xinzeng" /> |
|||
新增 |
|||
</el-button> |
|||
<el-button v-permission="permission.edit" size="mini" :disabled="crud.selections.length !== 1" @click="toEdit(crud.selections)"> |
|||
<i class="iconfont icon-bianji" /> |
|||
编辑 |
|||
</el-button> |
|||
</template> |
|||
<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> |
|||
<template v-slot:right> |
|||
<!-- :disabled="activeRightBtn" --> |
|||
<el-button :disabled="crud.selections.length !== 1 || (crud.selections.length === 1 && crud.selections[0].deviceType !== 1) " type="primary" size="mini" @click="openBindShelf('')"><i class="iconfont icon-bangding" />书架绑定</el-button> |
|||
</template> |
|||
</crudOperation> |
|||
</div> |
|||
<div class="container-right"> |
|||
<span class="right-top-line" /> |
|||
<span class="left-bottom-line" /> |
|||
|
|||
<!--表格渲染--> |
|||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;" height="calc(100vh - 330px)" @row-click="clickRowHandler" @selection-change="crud.selectionChangeHandler"> |
|||
<el-table-column type="selection" align="center" width="55" /> |
|||
<el-table-column prop="deviceType" label="设备类型"> |
|||
<template slot-scope="scope"> |
|||
<span v-if="scope.row.deviceType === 1">球型摄像机</span> |
|||
<span v-else-if="scope.row.deviceType === 2">盘点机器人</span> |
|||
<span v-else-if="scope.row.deviceType === 3">闸机</span> |
|||
<span v-else>安全门</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="deviceName" label="设备名称" /> |
|||
<el-table-column prop="deviveCode" label="设备编号" /> |
|||
<!-- <el-table-column prop="ipv4" label="接口IP" /> --> |
|||
<el-table-column prop="ipv4" label="接口IP" min-width="120"> |
|||
<template slot-scope="scope"> |
|||
<span v-if="scope.row.ipv4"> {{ scope.row.ipv4 }} </span> |
|||
<span v-else>——</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="端口" prop="rtsp" width="50"> |
|||
<template slot-scope="scope"> |
|||
<span v-if="scope.row.rtsp"> {{ scope.row.rtsp }} </span> |
|||
<span v-else>——</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="状态" prop="deviceState" align="center"> |
|||
<template slot-scope="scope"> |
|||
<span v-if="scope.row.deviceState === null" class="el-icon-loading" /> |
|||
<span v-else :class="{ 'spk-a': scope.row.deviceState === 1, 'off-line': scope.row.deviceState !== 1 }" /> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="shelfCount" label="已绑架位" /> |
|||
<el-table-column prop="fondsName" label="所属机构" /> |
|||
<el-table-column prop="floorName" label="所属楼层" /> |
|||
<el-table-column prop="regionName" label="所属区域" min-width="120" /> |
|||
<el-table-column :show-overflow-tooltip="true" prop="createTime" label="创建日期" width="140"> |
|||
<template slot-scope="scope"> |
|||
<div>{{ scope.row.createTime | parseTime }}</div> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<!--分页组件--> |
|||
<pagination /> |
|||
</div> |
|||
|
|||
<!-- 设备管理1 --> |
|||
<el-dialog |
|||
:close-on-click-modal="false" |
|||
:modal-append-to-body="false" |
|||
append-to-body |
|||
:before-close="handleCloseDialog" |
|||
:visible.sync="deviceSelectVisible" |
|||
title="新增设备-选择设备类型" |
|||
> |
|||
<div class="setting-dialog"> |
|||
<el-form ref="deviceForm" inline :model="deviceForm" size="small" label-width="90px"> |
|||
<el-form-item label="设备类型" prop="deviceType" :rules="[{ required:true, message:'请选择设备类型', trigger:'change'}]"> |
|||
<el-select v-model="deviceForm.deviceType" class="filter-item" value-key="id" placeholder="设备类型" style="width: 550px;"> |
|||
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="text" @click="handleCloseDialog">取消</el-button> |
|||
<el-button :loading="crud.status.cu === 2" type="primary" @click="handleComfirmDevice">确定</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
<!-- 设备管理2 --> |
|||
<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="addDeviceTitle" |
|||
> |
|||
<div class="setting-dialog"> |
|||
<el-form ref="form" inline :model="form" :rules="rules" size="small" label-width="90px"> |
|||
<el-form-item label="设备名称" prop="deviceName"> |
|||
<el-input v-model="form.deviceName" /> |
|||
</el-form-item> |
|||
<el-form-item label="设备编号" prop="deviveCode"> |
|||
<el-input v-model="form.deviveCode" /> |
|||
</el-form-item> |
|||
<el-row> |
|||
<el-form-item label="品牌厂商" prop="deviceBrand"> |
|||
<el-select v-model="form.deviceBrand" class="filter-item" placeholder="请选择" style="width: 225px;"> |
|||
<el-option v-for="(item,index) in supplierOptions" :key="index" :label="item.name" :value="item.name" /> |
|||
</el-select> |
|||
</el-form-item> |
|||
</el-row> |
|||
<el-form-item v-if="selectedDeviceType===1" label="IPv4地址" prop="ipv4"> |
|||
<el-input v-model="form.ipv4" /> |
|||
</el-form-item> |
|||
<el-form-item v-if="selectedDeviceType===1" label="RTSP端口" prop="rtsp" style="margin-right: 0; margin-left: 30px;"> |
|||
<el-input v-model="form.rtsp" placeholder="RTSP端口一般均为554" /> |
|||
</el-form-item> |
|||
<el-form-item v-if="selectedDeviceType===1" label="账号" prop="account"> |
|||
<el-input v-model="form.account" /> |
|||
</el-form-item> |
|||
<el-form-item v-if="selectedDeviceType===1" label="密码" prop="password" style="margin-right: 0; margin-left: 30px;"> |
|||
<el-input v-model="form.password" /> |
|||
</el-form-item> |
|||
<el-form-item label="备注" prop="remarks"> |
|||
<el-input v-model="form.remarks" type="textarea" :rows="4" style="width: 585px;" /> |
|||
</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> |
|||
|
|||
<!-- 书架绑定 --> |
|||
<el-dialog |
|||
class="bind-bookShelf-dialog" |
|||
:close-on-click-modal="false" |
|||
:modal-append-to-body="false" |
|||
append-to-body |
|||
:before-close="handleCloseDialog" |
|||
:visible.sync="bindBookShelfVisible" |
|||
title="书架绑定" |
|||
> |
|||
<div class="setting-dialog"> |
|||
<el-select v-model="selectShelf" class="filter-item" placeholder="请选择指定架" style="width: 320px; margin-bottom: 20px;" @change="changeShelfBind"> |
|||
<el-option v-for="(item,index) in bindReigonsTree" :key="index" :label="item.shelfName" :value="item.shelfId" /> |
|||
</el-select> |
|||
|
|||
<div class="transfer-bookshelf"> |
|||
<el-transfer |
|||
v-model="bindGirdData" |
|||
style="text-align: left; display: inline-block" |
|||
filterable |
|||
filter-placeholder="请输入关键字检索" |
|||
:titles="['未绑定 - 层位架', '已绑定 - 层位架']" |
|||
:button-texts="['移除', '加入']" |
|||
:left-default-checked="leftDefaultChecked" |
|||
:right-default-checked="rightDefaultChecked" |
|||
:format="{ |
|||
noChecked: '${total}', |
|||
hasChecked: '${checked}/${total}' |
|||
}" |
|||
:data="unBindGirdData" |
|||
@change="handleChange" |
|||
> |
|||
<div slot-scope="{ option }" style="display: flex;"> |
|||
<!-- <span style="display:block; width: 50px; text-align: center;">{{ option.key }}</span> --> |
|||
<span style="display:block; width: 150px;">{{ option.label }}</span> |
|||
</div> |
|||
</el-transfer> |
|||
<el-button class="transfer-footer" :disabled="bindGirdData.length===0" size="small" @click="rightCheckedClear"><i class="iconfont icon-shanchu" />清空</el-button> |
|||
</div> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="text" @click="handleCloseDialog">取消</el-button> |
|||
<el-button :loading="crud.status.cu === 2" type="primary" @click="dialogSaveSeting">确定</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import crudDevice from '@/api/deviceVI/index' |
|||
import { FetchInitBookShelfList } from '@/api/shelf/index' |
|||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|||
import crudOperation from '@crud/CRUD.operation' |
|||
import pagination from '@crud/Pagination' |
|||
|
|||
const defaultForm = { |
|||
'account': null, |
|||
'deviceBrand': null, |
|||
'deviceName': null, |
|||
'deviceType': null, |
|||
'deviveCode': null, |
|||
'floorId': null, |
|||
'fondsId': null, |
|||
'id': null, |
|||
'ipv4': null, |
|||
'password': null, |
|||
'regionId': null, |
|||
'remarks': null, |
|||
'rtsp': null |
|||
|
|||
} |
|||
export default { |
|||
name: 'Device', |
|||
components: { crudOperation, pagination }, |
|||
cruds() { |
|||
return CRUD({ title: '设备', url: 'api/device/initDeviceInfoList', idField: 'id || deviceId', sort: [], crudMethod: { ...crudDevice }, optShow: { |
|||
add: false, |
|||
edit: false, |
|||
del: false, |
|||
reset: true, |
|||
download: false, |
|||
group: false |
|||
}, |
|||
queryOnPresenterCreated: false |
|||
}) |
|||
}, |
|||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|||
data() { |
|||
return { |
|||
regionTreeData: null, |
|||
defaultProps: { |
|||
children: 'children', |
|||
label: 'label' |
|||
}, |
|||
defaultCheckedKeys: [], |
|||
selectedTreeKey: null, |
|||
search: null, |
|||
optionVal: 1, |
|||
options: [ |
|||
{ |
|||
'id': 1, |
|||
'name': '球型摄像机' |
|||
}, |
|||
{ |
|||
'id': 2, |
|||
'name': '盘点机器人' |
|||
}, |
|||
{ |
|||
'id': 3, |
|||
'name': '闸机' |
|||
}, |
|||
{ |
|||
'id': 4, |
|||
'name': '安全门' |
|||
} |
|||
], |
|||
activeRightBtn: false, |
|||
bindBookShelfVisible: false, |
|||
fondsDatas: [], |
|||
deviceSelectVisible: false, |
|||
deviceForm: { |
|||
deviceType: null |
|||
}, |
|||
addDeviceTitle: '', |
|||
supplierOptions: [ |
|||
{ 'name': '海康威视' }, |
|||
{ 'name': '大华' }, |
|||
{ 'name': '天地伟业' }, |
|||
{ 'name': '其他' } |
|||
], |
|||
selectedDeviceType: '球型摄像机', |
|||
levelNumber: 0, |
|||
btn: 'add', |
|||
unBindGirdData: [], |
|||
bindGirdData: [], |
|||
leftDefaultChecked: [], |
|||
rightDefaultChecked: [], |
|||
permission: { |
|||
add: ['admin', 'device:add'], |
|||
edit: ['admin', 'device:edit'], |
|||
del: ['admin', 'device:del'] |
|||
}, |
|||
floorTreeValue: null, |
|||
bindReigonsTree: [], |
|||
selectShelf: null |
|||
} |
|||
}, |
|||
computed: { |
|||
rules() { |
|||
const checkDevicePort = (rule, value, callback) => { |
|||
const reg = /^([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-4]\d{4}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/ |
|||
if (reg.test(value)) { |
|||
callback() |
|||
} else { |
|||
callback(new Error('端口号输入错误')) |
|||
} |
|||
} |
|||
const validateRule = { |
|||
deviveCode: [{ required: true, message: '设备编号不可为空', trigger: 'blur' }], |
|||
deviceName: [{ required: true, message: '设备名称不可为空', trigger: 'blur' }] |
|||
} |
|||
this.$set(validateRule, 'ipv4', [ |
|||
{ required: true, message: '请输入接口IP', trigger: 'blur' } |
|||
]) |
|||
this.$set(validateRule, 'rtsp', [ |
|||
{ required: true, message: '请输入端口号', trigger: 'blur' }, |
|||
{ validator: checkDevicePort, trigger: 'blur' } |
|||
]) |
|||
this.$set(validateRule, 'account', [ |
|||
{ required: true, message: '请输入账号', trigger: 'blur' } |
|||
]) |
|||
this.$set(validateRule, 'password', [ |
|||
{ required: true, message: '请输入密码', trigger: 'blur' } |
|||
]) |
|||
return validateRule |
|||
} |
|||
}, |
|||
watch: { |
|||
}, |
|||
created() { |
|||
this.deviceTypeOptions = this.options |
|||
crudDevice.FetchRegionTree().then(res => { |
|||
this.regionTreeData = [this.transformData(res)] |
|||
this.expandDefault() |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
mounted() { |
|||
}, |
|||
methods: { |
|||
normalizer(node) { |
|||
return { |
|||
id: node.id, |
|||
label: node.label, |
|||
children: node.children, |
|||
isDisabled: !node.regionId |
|||
} |
|||
}, |
|||
// tree 数据转换 |
|||
transformData(data) { |
|||
return { |
|||
id: data.fondsId, |
|||
fondsId: data.fondsId, |
|||
label: data.fondsName, |
|||
children: data.floors.map(floor => ({ |
|||
id: floor.id, |
|||
floorId: floor.id, |
|||
label: floor.floorName, |
|||
children: floor.regions.map(region => ({ |
|||
id: region.id, |
|||
regionId: region.id, |
|||
label: region.regionName, |
|||
parentFloorId: floor.id |
|||
})) |
|||
})) |
|||
} |
|||
}, |
|||
treeSelectInput(value) { |
|||
console.log('treeSelectInput', value) |
|||
}, |
|||
renderContent(h, { node, data, store }) { |
|||
return h('span', [ |
|||
h('el-tooltip', { |
|||
props: { |
|||
content: data.label || '', |
|||
placement: 'top' |
|||
} |
|||
}, [ |
|||
h('span', node.label) |
|||
]) |
|||
]) |
|||
}, |
|||
expandDefault() { |
|||
// https://blog.csdn.net/weixin_47218354/article/details/135261449 |
|||
this.defaultCheckedKeys.push(this.regionTreeData[0].id) |
|||
this.$nextTick(() => { |
|||
this.$refs.tree.setCurrentKey(this.regionTreeData[0].id) // 默认选中节点第一个(高亮效果) |
|||
this.handleNodeClick(this.regionTreeData[0]) |
|||
}) |
|||
}, |
|||
// 获取数据前设置默认参数 |
|||
[CRUD.HOOK.beforeRefresh]() { |
|||
this.crud.query.search = this.search |
|||
this.crud.query.deviceType = this.optionVal |
|||
}, |
|||
[CRUD.HOOK.afterRefresh](crud) { |
|||
crud.data.forEach(element => { |
|||
element.deviceState = null |
|||
this.getDeviceState(element) |
|||
}) |
|||
}, |
|||
getDeviceState(element) { |
|||
crudDevice.FetchPingIP({ ip: element.ipv4 }).then((data) => { |
|||
element.deviceState = data === true ? 1 : 0 |
|||
}).catch((error) => { |
|||
console.error(error) |
|||
}) |
|||
}, |
|||
handleNodeClick(data) { |
|||
this.$nextTick(() => { |
|||
if (this.$refs.tree) { |
|||
this.selectedTreeKey = this.$refs.tree.getCurrentNode() |
|||
this.crud.query.fondsId = this.regionTreeData[0].id |
|||
if (this.selectedTreeKey.hasOwnProperty('floorId')) { |
|||
this.crud.query.floorId = this.selectedTreeKey.id |
|||
} else if (this.selectedTreeKey.hasOwnProperty('regionId')) { |
|||
this.crud.query.floorId = this.selectedTreeKey.parentFloorId |
|||
} else { |
|||
this.crud.query.floorId = null |
|||
} |
|||
this.crud.query.deviceType = this.optionVal |
|||
this.search = '' |
|||
this.crud.query.regionId = this.selectedTreeKey.hasOwnProperty('regionId') ? this.selectedTreeKey.id : null |
|||
|
|||
if (!this.selectedTreeKey.hasOwnProperty('regionId')) { |
|||
this.activeRightBtn = true |
|||
} else { |
|||
this.activeRightBtn = false |
|||
} |
|||
|
|||
this.crud.toQuery() |
|||
|
|||
const params = { |
|||
'floorId': this.crud.query.floorId, |
|||
'regionId': this.crud.query.regionId |
|||
} |
|||
FetchInitBookShelfList(params).then(res => { |
|||
this.bindReigonsTree = res.content |
|||
}).catch(() => { |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
searchChange(val) { |
|||
if (val) { |
|||
this.search = '' |
|||
} |
|||
}, |
|||
resetQuery() { |
|||
this.search = null |
|||
this.optionVal = 1 |
|||
this.crud.query.deviceType = this.optionVal |
|||
this.crud.query.search = this.search |
|||
this.crud.toQuery() |
|||
}, |
|||
// 新增前初始化部门信息 |
|||
[CRUD.HOOK.beforeToAdd](crud, form) { |
|||
this.crud.form.fondsId = this.regionTreeData[0].id |
|||
this.crud.form.deviceType = this.selectedDeviceType |
|||
if (this.selectedTreeKey.hasOwnProperty('floorId')) { |
|||
this.crud.query.floorId = this.selectedTreeKey.id |
|||
} else if (this.selectedTreeKey.hasOwnProperty('regionId')) { |
|||
this.crud.query.floorId = this.selectedTreeKey.parentFloorId |
|||
} else { |
|||
this.crud.query.floorId = null |
|||
} |
|||
this.crud.form.regionId = this.selectedTreeKey.hasOwnProperty('regionId') ? this.selectedTreeKey.id : null |
|||
}, |
|||
toEdit(row) { |
|||
crudDevice.FetchDeviceById({ 'deviceId': row[0].deviceId }).then(res => { |
|||
if (res) { |
|||
crud.form = res |
|||
this.crud.toEdit(crud.form) |
|||
} |
|||
}) |
|||
}, |
|||
[CRUD.HOOK.beforeToEdit](crud, form, btn) { |
|||
this.selectedDeviceType = this.form.deviceType |
|||
this.btn = 'edit' |
|||
let deviceName = '' |
|||
console.log('form', this.form.deviceType) |
|||
if (this.form.deviceType === 1) { |
|||
deviceName = '球形摄像机' |
|||
} else if (this.form.deviceType === 2) { |
|||
deviceName = '盘点机器人' |
|||
} else if (this.form.deviceType === 3) { |
|||
deviceName = '闸机' |
|||
} else if (this.form.deviceType === 4) { |
|||
deviceName = '安全门' |
|||
} else { |
|||
deviceName = '' |
|||
} |
|||
this.addDeviceTitle = '编辑设备 - ' + deviceName |
|||
}, |
|||
// 提交前做的操作 |
|||
[CRUD.HOOK.afterValidateCU](crud) { |
|||
if (this.btn === 'add') { |
|||
this.crud.form.deviceType = this.selectedDeviceType |
|||
this.crud.form.floorId = this.selectedTreeKey.parentFloorId |
|||
this.crud.form.fondsId = this.regionTreeData[0].id |
|||
this.crud.form.regionId = this.selectedTreeKey.id |
|||
} |
|||
delete crud.form.fondsName |
|||
delete crud.form.floorName |
|||
delete crud.form.deviceState |
|||
delete crud.form.shelfCount |
|||
delete crud.form.regionName |
|||
return true |
|||
}, |
|||
clickRowHandler(row) { |
|||
this.$refs.table.clearSelection() |
|||
this.$refs.table.toggleRowSelection(row) |
|||
}, |
|||
// 删除 |
|||
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.deviceId) |
|||
}) |
|||
crudDevice.del(ids).then(() => { |
|||
this.crud.notify('删除成功', CRUD.NOTIFICATION_TYPE.SUCCESS) |
|||
this.crud.delAllLoading = false |
|||
this.crud.refresh() |
|||
}).catch(err => { |
|||
this.crud.delAllLoading = false |
|||
console.log(err) |
|||
}) |
|||
}).catch(() => { |
|||
}) |
|||
}, |
|||
handleComfirmDevice() { |
|||
this.$refs.deviceForm.validate((valid) => { |
|||
if (valid) { |
|||
this.btn = 'add' |
|||
this.deviceSelectVisible = false |
|||
this.selectedDeviceType = this.deviceForm.deviceType.id |
|||
this.addDeviceTitle = '新增设备 - ' + this.deviceForm.deviceType.name |
|||
this.crud.toAdd() |
|||
} else { |
|||
console.log('error submit!!') |
|||
return false |
|||
} |
|||
}) |
|||
}, |
|||
handleCloseDialog(done) { |
|||
this.bindBookShelfVisible = false |
|||
|
|||
// 重置表单数据 |
|||
if (this.$refs.deviceForm) { |
|||
this.deviceSelectVisible = false |
|||
this.$refs.deviceForm.resetFields() |
|||
this.deviceForm.deviceType = null |
|||
} |
|||
if (this.$refs.form) { |
|||
this.crud.cancelCU() |
|||
this.$refs.form.resetFields() |
|||
} |
|||
// 关闭弹框 |
|||
// done() |
|||
}, |
|||
changeShelfBind(val) { |
|||
this.openBindShelf(val) |
|||
}, |
|||
openBindShelf(shelfId) { |
|||
crudDevice.FetchDeviceById({ 'deviceId': this.crud.selections[0].deviceId }).then(res => { |
|||
this.bindBookShelfVisible = true |
|||
const params = { |
|||
'fondsId': res.fondsId, |
|||
'floorId': res.floorId, |
|||
'regionId': res.regionId, |
|||
'shelfId': shelfId |
|||
} |
|||
const params2 = { |
|||
'deviceId': res.id |
|||
} |
|||
Promise.all([ |
|||
crudDevice.FetchUnboundGrid(params), |
|||
crudDevice.FetchBoundGridByDevice(params2) |
|||
]).then(results => { |
|||
console.log('FetchUnboundGrid result:', results[0]) |
|||
console.log('FetchBoundGridByDevice result:', results[1]) |
|||
this.unBindGirdData = results[0].map((item, index) => { |
|||
return { |
|||
id: item.gridId, |
|||
label: item.gridName, |
|||
key: item.gridId, |
|||
shelfId: item.shelfId |
|||
} |
|||
}) |
|||
if (results[1].length !== 0) { |
|||
this.unBindGirdData = [ |
|||
...this.unBindGirdData, |
|||
...results[1].map((item, index) => { |
|||
return { |
|||
id: item.gridId, |
|||
label: item.gridName, |
|||
key: item.gridId, |
|||
shelfId: item.shelfId |
|||
} |
|||
}) |
|||
] |
|||
const movedKeys = results[1].map(item => item.gridId) |
|||
this.bindGirdData = movedKeys |
|||
} else { |
|||
this.bindGirdData = [] |
|||
} |
|||
}).catch(error => { |
|||
console.error('Error fetching grids:', error) |
|||
}) |
|||
}) |
|||
}, |
|||
handleChange(value, direction, movedKeys) { |
|||
console.log(value + direction + movedKeys) |
|||
}, |
|||
dialogSaveSeting() { |
|||
// https://www.cnblogs.com/liujiajiablog/p/15818056.html |
|||
const movedIds = this.bindGirdData.map(key => { |
|||
const item = this.unBindGirdData.find(item => item.key === key) |
|||
return item ? item.id : null |
|||
}) |
|||
const params = { |
|||
'deviceId': this.crud.selections[0].deviceId, |
|||
'shelfGridIds': movedIds |
|||
} |
|||
crudDevice.FetchDeviceShelfGridBinding(params).then(res => { |
|||
if (res) { |
|||
this.$message({ message: res, type: 'success', offset: 8 }) |
|||
this.crud.refresh() |
|||
} |
|||
this.bindBookShelfVisible = false |
|||
}) |
|||
}, |
|||
rightCheckedClear() { |
|||
this.bindGirdData = [] |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
::v-deep .input-prepend .el-input__inner{ |
|||
padding-left: 130px; |
|||
} |
|||
|
|||
::v-deep .el-tree{ |
|||
.el-tree-node__content{ |
|||
font-size: 14px; |
|||
color: #545B65; |
|||
.tree-text{ |
|||
font-size: 16px; |
|||
font-weight: 600; |
|||
color: #0C0E1E; |
|||
} |
|||
} |
|||
.el-tree-node__children{ |
|||
.tree-text { |
|||
font-size: 14px !important; |
|||
font-weight: normal; |
|||
text-overflow: ellipsis; |
|||
overflow: hidden; |
|||
white-space: nowrap; |
|||
display: inline-block; |
|||
min-width: 170px; |
|||
color: #545B65; |
|||
} |
|||
} |
|||
} |
|||
.bind-bookShelf-dialog{ |
|||
::v-deep .el-dialog{ |
|||
width: 820px; |
|||
} |
|||
} |
|||
.transfer-bookshelf{ |
|||
position: relative; |
|||
::v-deep .el-transfer{ |
|||
display: flex !important; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
.el-transfer-panel{ |
|||
width: 400px !important; |
|||
.el-transfer-panel__body{ |
|||
height: 480px; |
|||
.el-transfer-panel__list.is-filterable{ |
|||
height: 420px; |
|||
} |
|||
.el-transfer-panel__filter .el-input__inner{ |
|||
border-radius: 4px; |
|||
} |
|||
.el-transfer-panel__filter .el-input__icon{ |
|||
margin-left: 0; |
|||
} |
|||
} |
|||
|
|||
} |
|||
.el-transfer__buttons{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
.el-button:last-child{ |
|||
margin-left: 0; |
|||
.el-icon-arrow-right:before{ |
|||
color: #0348f3; |
|||
} |
|||
} |
|||
.el-button.is-disabled{ |
|||
.el-icon-arrow-right:before{ |
|||
color: #b4c8fb; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.transfer-footer{ |
|||
position: absolute; |
|||
left: 50%; |
|||
bottom: 185px; |
|||
transform: translateX(-50%); |
|||
} |
|||
} |
|||
|
|||
</style> |
|||
@ -0,0 +1,282 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="venue-header"> |
|||
<h4><i class="iconfont icon-duolouceng" />楼层列表</h4> |
|||
<p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p> |
|||
</div> |
|||
<div class="venue-content"> |
|||
<div class="venue-left"> |
|||
<div class="head-container"> |
|||
<div class="head-search"> |
|||
<!-- 搜索 --> |
|||
<el-input v-model="query.search" clearable size="small" placeholder="输入关键字搜索" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @clear="crud.toQuery" @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> |
|||
<template v-slot:right> |
|||
<el-button :loading="crud.downloadLoading" size="mini" :disabled="crud.selections.length <= 1" @click="showSort"> |
|||
<i class="iconfont icon-paixu" /> |
|||
排序 |
|||
</el-button> |
|||
</template> |
|||
</crudOperation> |
|||
</div> |
|||
<div style="position: relative;"> |
|||
<div class="double-click-btn"><i class="iconfont icon-zhuyi-lan" /><span>双击列表数据查看对应区域</span></div> |
|||
<el-table |
|||
ref="table" |
|||
v-loading="crud.loading" |
|||
:data="crud.data" |
|||
style="width: 100%;" |
|||
height="506" |
|||
@selection-change="crud.selectionChangeHandler" |
|||
@row-click="clickRowHandler" |
|||
@row-dblclick="onRowDblclick" |
|||
> |
|||
<el-table-column type="selection" align="center" width="55" /> |
|||
<el-table-column type="index" label="排序" /> |
|||
<el-table-column prop="floorName" label="楼层名称" /> |
|||
<el-table-column prop="regionCount" label="区域" /> |
|||
<el-table-column prop="floorMap" label="地图"> |
|||
<template slot-scope="scope"> |
|||
<span :class="['row-state', scope.row.floorMap ? 'end-state' : 'cancel-state' ]">{{ scope.row.floorMap ? '已上传': '未上传' }}</span> |
|||
</template> |
|||
</el-table-column> |
|||
<!-- <el-table-column prop="floorDescription" label="说明"> |
|||
<template slot-scope="scope"> |
|||
<div>{{ scope.row.floorDescription ? scope.row.floorDescription : '-' }}</div> |
|||
</template> |
|||
</el-table-column> --> |
|||
<!-- <el-table-column prop="createTime" label="创建时间" min-width="180"> |
|||
<template slot-scope="scope"> |
|||
<div>{{ scope.row.createTime | parseTime }}</div> |
|||
</template> |
|||
</el-table-column> --> |
|||
</el-table> |
|||
<!--分页组件--> |
|||
<pagination v-if="crud.data.length!==0" /> |
|||
</div> |
|||
</div> |
|||
<div class="venue-right"> |
|||
<div class="container-right tab-content"> |
|||
<span class="right-top-line" /> |
|||
<span class="left-bottom-line" /> |
|||
<ul class="tab-nav"> |
|||
<li class="active-tab-nav">楼层预览<i /></li> |
|||
<!-- 最右侧装饰img --> |
|||
<span class="tab-right-img" /> |
|||
</ul> |
|||
<!-- v-loading="imgLoading" --> |
|||
<div class="venue-preview"> |
|||
<!-- <img src="~@/assets/images/system/default-img.jpg" alt=""> --> |
|||
<img :src="imageUrl" :onerror="defaultImg" alt=""> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- form --> |
|||
<el-dialog append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :before-close="crud.cancelCU" :visible="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" :rules="rules" :model="form" size="small" label-width="100px"> |
|||
<el-form-item label="楼层名称" prop="floorName"> |
|||
<el-input v-model="form.floorName" style="width: 580px;" /> |
|||
</el-form-item> |
|||
<el-form-item label="描述信息" prop="floorDescription"> |
|||
<el-input v-model="form.floorDescription" placeholder="请输入" type="textarea" rows="3" style="width: 580px;" /> |
|||
</el-form-item> |
|||
<UploadCover :label-name="labelName" :form="form" upload-type="other" @childCover="handleCover" /> |
|||
</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> |
|||
|
|||
<!-- 排序 --> |
|||
<el-dialog :close-on-click-modal="false" :append-to-body="true" title="排序" :visible.sync="sortVisible" @opened="opened"> |
|||
<span class="dialog-right-top" /> |
|||
<span class="dialog-left-bottom" /> |
|||
<div class="setting-dialog"> |
|||
<i class="drag-tip">提示:请通过拖动鼠标来调整当前顺序</i> |
|||
<el-table :data="sortTableData" class="file-sort" style="width: 100%;max-height: 70vh;" row-key="id"> |
|||
<el-table-column type="index" label="序号" width="100" align="center" /> |
|||
<el-table-column prop="floorName" label="楼层名称" /> |
|||
</el-table> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button type="primary" @click.native="handleSort">保存</el-button> |
|||
</div> |
|||
</div> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import crudFloor from '@/api/floor/index' |
|||
import CRUD, { presenter, header, form, crud } from '@crud/crud' |
|||
import crudOperation from '@crud/CRUD.operation' |
|||
import rrOperation from '@crud/RR.operation' |
|||
import pagination from '@crud/Pagination' |
|||
import UploadCover from '@/views/components/upload.vue' |
|||
import Sortable from 'sortablejs' |
|||
import { mapGetters } from 'vuex' |
|||
import defaultImg from '@/assets/images/system/default-img.jpg' |
|||
|
|||
const defaultForm = { id: null, floorName: null, floorDescription: null, floorMap: null } |
|||
export default { |
|||
name: 'Floor', |
|||
components: { crudOperation, rrOperation, pagination, UploadCover }, |
|||
cruds() { |
|||
return CRUD({ title: '楼层', url: 'api/libraryFloor/initLibraryFloorList', crudMethod: { ...crudFloor }, sort: [], optShow: { |
|||
add: true, |
|||
edit: true, |
|||
del: false, |
|||
download: false, |
|||
group: false, |
|||
reset: false |
|||
}}) |
|||
}, |
|||
mixins: [presenter(), header(), form(defaultForm), crud()], |
|||
data() { |
|||
return { |
|||
imgLoading: false, |
|||
labelName: '楼层地图', |
|||
permission: { |
|||
add: ['admin', 'floor:add'], |
|||
edit: ['admin', 'floor:edit'], |
|||
del: ['admin', 'floor:del'] |
|||
}, |
|||
rules: { |
|||
floorName: [ |
|||
{ required: true, message: '所在楼层不可为空', trigger: 'blur' } |
|||
] |
|||
}, |
|||
defaultImg: defaultImg, |
|||
imageUrl: defaultImg, |
|||
sortTableData: [], // 排序data |
|||
sortVisible: false // 排序dialog |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'user', |
|||
'baseApi' |
|||
]) |
|||
}, |
|||
methods: { |
|||
[CRUD.HOOK.beforeRefresh]() { |
|||
|
|||
}, |
|||
[CRUD.HOOK.afterRefresh](crud) { |
|||
console.log(crud.data) |
|||
if (crud.data.length !== 0) { |
|||
this.clickRowHandler(crud.data[0]) |
|||
} |
|||
}, |
|||
// 提交前的验证 |
|||
[CRUD.HOOK.afterValidateCU](crud) { |
|||
console.log(crud.form) |
|||
return true |
|||
}, |
|||
handleCover(value) { |
|||
console.log('value', value) |
|||
this.crud.form.floorMap = value |
|||
}, |
|||
clickRowHandler(row) { |
|||
this.$refs.table.clearSelection() |
|||
this.$refs.table.toggleRowSelection(row) |
|||
// http://192.168.99.67:12010/api/fileRelevant/getImg?imgType=1&imgId=f6d3ecea-0456-4429-ba77-1a4921d5c806 |
|||
if (row.floorMap) { |
|||
this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=1&imgId=' + row.floorMap |
|||
} else { |
|||
this.imageUrl = this.defaultImg |
|||
} |
|||
}, |
|||
onRowDblclick(row) { |
|||
// crudShelf.FetchBookShelfDetails({ 'shelfId': row.shelfId }).then(res => { |
|||
// this.$router.push({ path: '/bookshelf/bookshelfPosition', query: { 'floorName': row.floorName, 'regionName': row.regionName }}) |
|||
// localStorage.setItem('bookShelfDetails', JSON.stringify(res)) |
|||
// }).catch(() => { |
|||
// }) |
|||
localStorage.setItem('formFloor', JSON.stringify(row)) |
|||
this.$router.push({ path: '/deviceManage/area', query: { 'formFloor': true }}) |
|||
}, |
|||
toDelete(datas) { |
|||
this.$confirm('此操作将删除当前所选楼层<span>你是否还要继续?</span>', '提示', { |
|||
confirmButtonText: '继续', |
|||
cancelButtonText: '取消', |
|||
type: 'warning', |
|||
dangerouslyUseHTMLString: true |
|||
}).then(() => { |
|||
this.crud.delAllLoading = true |
|||
const ids = [] |
|||
datas.forEach(val => { |
|||
ids.push(val.id) |
|||
}) |
|||
console.log(ids) |
|||
crudFloor.del(ids).then(res => { |
|||
console.log(res) |
|||
this.$message({ message: res, type: 'success', offset: 8 }) |
|||
this.crud.delAllLoading = false |
|||
this.crud.refresh() |
|||
}).catch(err => { |
|||
this.crud.delAllLoading = false |
|||
console.log(err) |
|||
}) |
|||
}).catch(() => { |
|||
this.crud.delAllLoading = false |
|||
}) |
|||
}, |
|||
// 排序 - 行拖拽 |
|||
rowDrop(className, targetName) { |
|||
// 此时找到的元素是要拖拽元素的父容器 |
|||
const tbody = document.querySelector('.' + className + ' .el-table__body-wrapper tbody') |
|||
const that = this |
|||
Sortable.create(tbody, { |
|||
// 指定父元素下可被拖拽的子元素 |
|||
draggable: '.el-table__row', |
|||
onEnd({ newIndex, oldIndex }) { |
|||
if (newIndex === oldIndex) return |
|||
that[targetName].splice(newIndex, 0, that[targetName].splice(oldIndex, 1)[0]) |
|||
} |
|||
}) |
|||
}, |
|||
// 排序 |
|||
opened() { |
|||
this.rowDrop('file-sort', 'sortTableData') |
|||
}, |
|||
showSort() { |
|||
this.sortVisible = true |
|||
this.sortTableData = JSON.parse(JSON.stringify(this.crud.selections)) |
|||
}, |
|||
handleSort() { |
|||
const data = this.sortTableData.map((value, index) => { |
|||
return { id: value.id, isSequence: index + 1 } |
|||
}) |
|||
this.sortTableData.forEach((item, index) => { |
|||
item.isSequence = index + 1 |
|||
}) |
|||
crudFloor.sort(data).then(() => { |
|||
this.sortVisible = false |
|||
this.$message({ message: '保存成功', type: 'success', offset: 8 }) |
|||
this.crud.refresh() |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.tab-content{ |
|||
min-height: calc(100vh - 232px) !important; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,16 @@ |
|||
<template> |
|||
<div> |
|||
<router-view /> |
|||
</div> |
|||
</template> |
|||
<script> |
|||
export default { |
|||
name: 'VenueDevice', |
|||
data() { |
|||
return { |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
<style scoped> |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue