Browse Source

楼层/区域api调试

master
xuhuajiao 7 months ago
parent
commit
0f66d6d4c8
  1. 1
      package.json
  2. 43
      src/api/area/index.js
  3. 9
      src/api/floor/index.js
  4. BIN
      src/assets/images/closed.png
  5. 667
      src/views/components/mark.vue
  6. 165
      src/views/visualCheck/venueDevice/area/index.vue
  7. 188
      src/views/visualCheck/venueDevice/device/index.vue
  8. 19
      src/views/visualCheck/venueDevice/floor/index.vue

1
package.json

@ -48,6 +48,7 @@
"element-resize-detector": "^1.2.4",
"element-ui": "^2.15.6",
"exceljs": "^4.4.0",
"fabric": "2.5",
"file-saver": "^1.3.8",
"fuse.js": "3.4.4",
"handsontable": "^14.1.0",

43
src/api/area/index.js

@ -0,0 +1,43 @@
import request from '@/utils/request'
export function add(data) {
return request({
url: 'api/libraryRegion/editLibraryRegion',
method: 'post',
data
})
}
export function edit(data) {
return request({
url: 'api/libraryRegion/editLibraryRegion',
method: 'post',
data
})
}
export function del(ids) {
return request({
url: 'api/libraryRegion/delLibraryRegion',
method: 'post',
data: ids
})
}
export function sort(parameter) {
return request({
url: 'api/libraryRegion/libraryRegionSort',
method: 'post',
data: parameter
})
}
export function saveLibraryRegionSignPoint(parameter) {
return request({
url: 'api/libraryRegion/saveLibraryRegionSignPoint',
method: 'post',
data: parameter
})
}
export default { add, edit, del, sort, saveLibraryRegionSignPoint }

9
src/api/floor/index.js

@ -1,5 +1,12 @@
import request from '@/utils/request'
export function FetchLibraryFloorListAll() {
return request({
url: 'api/libraryFloor/getLibraryFloorListAll',
method: 'get'
})
}
export function add(data) {
return request({
url: 'api/libraryFloor/editLibraryFloor',
@ -32,4 +39,4 @@ export function sort(parameter) {
})
}
export default { add, edit, del, sort }
export default { add, edit, del, sort, FetchLibraryFloorListAll }

BIN
src/assets/images/closed.png

After

Width: 30  |  Height: 30  |  Size: 1.5 KiB

667
src/views/components/mark.vue

@ -0,0 +1,667 @@
<template>
<div class="mark-handle">
<div class="mark-img">
<!-- <img :src="imageFloorUrl" :onerror="defaultImg" alt=""> -->
<canvas id="canvas" :width="width" :height="height" />
</div>
<div class="mark-right">
<ul class="mark-info">
<li>
<p>所属机构</p>
<span>{{ user.fonds.fondsName }}</span>
</li>
<li>
<p>所属楼层</p>
<span>{{ currentMarkData && currentMarkData.floorName }}</span>
</li>
<li>
<p>书架</p>
<span>{{ currentMarkData && currentMarkData.booksheflCount }}</span>
</li>
<li><span :class="['row-state', currentMarkData && currentMarkData.signPoint ? 'end-state' : 'cancel-state' ]">{{ currentMarkData && currentMarkData.signPoint ? '已标注': '未标注' }}</span></li>
</ul>
<div class="mark-button">
<el-button type="primary" :disabled="!isDrawing" @click="clean"><i class="iconfont icon-shanchu" />清空</el-button>
<el-button type="primary" :disabled="isDrawing" @click="drawPolygon"><i class="el-icon-edit" style="font-weight: bold; padding-right: 4px; font-size: 16px;" />标注</el-button>
<el-button type="primary" :disabled="!isDrawing" @click="submitDraw"><i class="el-icon-folder-checked" style="font-weight: bold; padding-right: 4px; font-size: 16px;" />保存</el-button>
</div>
</div>
<img id="expImg" :src="imageFloorUrl">
</div>
</template>
<script>
import { saveLibraryRegionSignPoint } from '@/api/area/index'
import { fabric } from 'fabric'
import { mapGetters } from 'vuex'
export default {
name: 'Mark',
props: {
currentMarkData: {
type: Object,
require: true,
default: function() {
return {}
}
},
imageFloorUrl: {
type: String,
default: ''
}
},
data() {
return {
bgImgFlag: true,
bgImgSrc: this.imageFloorUrl,
width: 900,
height: 600,
canvas: {},
mouseFrom: {},
mouseTo: {},
drawWidth: 2, //
drawingObject: null, //
moveCount: 1, //
doDrawing: false, //
// polygon
polygonMode: false,
pointArray: [],
lineArray: [],
savePointsGroup: [],
activeShape: false,
activeLine: '',
line: {},
deleteIconURL: require('@/assets/images/closed.png'),
drawinfo: null,
isDrawing: false
}
},
computed: {
...mapGetters([
'user',
'baseApi'
])
},
watch: {
width() {
this.canvas.setWidth(this.width)
},
height() {
this.canvas.setHeight(this.height)
},
currentMarkData(newVal) {
if (newVal) {
// console.log(newVal.signPoint)
// if (newVal.signPoint !== null) {
// this.drawinfo = JSON.parse(newVal.signPoint)
// } else {
// this.drawinfo = null
// }
this.initCanvas()
}
},
imageFloorUrl(newVal) {
if (newVal) {
console.log('newVal', newVal)
this.isDrawing = false
this.bgImgFlag = true
const imgElement = document.getElementById('expImg')
imgElement.src = this.imageFloorUrl
}
}
},
created() {
},
mounted() {
this.initCanvas()
},
methods: {
initCanvas() {
if (this.currentMarkData && (this.currentMarkData.signPoint !== '' || this.currentMarkData.signPoint !== null)) {
this.drawinfo = JSON.parse(this.currentMarkData.signPoint)
} else {
this.drawinfo = null
}
this.canvas = new fabric.Canvas('canvas', {
skipTargetFind: false, //
selectable: false, // false
selection: false //
})
this.canvas.selectionColor = 'rgba(0,0,0,0.05)'
this.canvas.on('mouse:down', this.mousedown)
this.canvas.on('mouse:move', this.mousemove)
this.canvas.on('object:moving', this.objectMoving)
// this.canvas.on('mouse:wheel', this.mouse)
// this.$nextTick(() => {
// console.log(this.drawinfo)
if (this.drawinfo) {
this.loadDraw()
this.canvas.on('mouse:wheel', this.mouse)
} else {
this.loadExpImg()
}
// })
},
// DOMcanvas
loadExpImg() {
const imgElement = document.getElementById('expImg')
const newWidth = this.canvas.width
imgElement.onload = () => {
const newHeight = newWidth / (imgElement.width / imgElement.height)
new fabric.Image.fromURL(
imgElement.src,
(img) => {
img.set(
{
originX: 'center',
originY: 'center',
scaleX: newWidth / imgElement.width,
scaleY: newHeight / imgElement.height
},
{ crossOrigin: 'anonymous' }
)
img.on('scaling', (e) => {
//
const h = img.scaleY
const w = img.scaleX
if (h !== w || w === h) {
//
if (e.e.movementY === -1 || e.e.movementY === 1) {
img.scale(h) //
} else {
img.scale(w)
}
}
})
img.setCoords()
img.centeredScaling = true
img.centerTransform = true
this.canvas.add(img)
this.canvas.centerObject(img)
this.canvas.renderAll()
},
{
selectable: true,
hasControls: true,
lockRotation: true, //
centeredScaling: true,
zIndex: -99,
isBgImg: true
}
)
}
},
//
objectMoving(e) {
const target = e.target
if (target.type === 'polygon') {
target.setCoords()
// params.pointInfo
// const points = target.points.map(p => ({
// x: p.x + target.left,
// y: p.y + target.top
// }));
// const index = params.pointInfo.findIndex(info => info.pointInfo[0].x === target.points[0].x && info.pointInfo[0].y === target.points[0].y);
// if (index !== -1) {
// params.pointInfo[index] = { pointInfo: points };
// } else {
// params.pointInfo.push({ pointInfo: points });
// }
}
},
submitDraw() {
const saveCanvasData = {
pointInfo: [],
imgInfo: ''
// img: ''
}
this.canvas
.toJSON(['isBgImg'])
.objects.forEach((item) => {
const element = {
pointInfo: ''
}
if (item?.points) {
element.pointInfo = item.points
saveCanvasData.pointInfo.push(element)
}
if (item.isBgImg) {
saveCanvasData.imgInfo = item
// params.img = item.src
delete saveCanvasData.imgInfo.src
}
})
console.log('saveCanvasData', saveCanvasData)
const params = {
'id': this.currentMarkData.id,
'signPoint': JSON.stringify(saveCanvasData)
}
console.log('params', params)
saveLibraryRegionSignPoint(params).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
},
//
mousedown(e) {
if (e === undefined) return
//
const xy =
e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY)
this.mouseFrom.x = xy.x
this.mouseFrom.y = xy.y
this.doDrawing = true
this.canvas.skipTargetFind = false
try {
//
if (this.pointArray.length > 1) {
// e.target.id == this.pointArray[0].id
if (e.target && e.target.id === this.pointArray[0].id) {
this.generatePolygon()
console.log('画完')
console.log('this.pointArray', this.pointArray)
this.isDrawing = true
return
} else {
console.log('未画完')
this.isDrawing = false
}
}
//
if (this.polygonMode) {
console.log('作画')
this.addPoint(e)
}
} catch (error) {
console.log(error)
}
},
//
mouseup(e) {
if (e === undefined) return
const xy =
e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY)
this.mouseTo.x = xy.x
this.mouseTo.y = xy.y
this.drawingObject = null
this.moveCount = 1
//
if (this.activeShape && this.activeShape.type === 'polygon') {
this.activeShape.setCoords()
}
},
//
mouse(e) {
if (undefined === e) return
let zoom = (e.e.deltaY > 0 ? -0.1 : 0.1) + this.canvas.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.canvas.zoomToPoint(zoomPoint, zoom)
},
//
mousemove(e) {
if (e === undefined) return
if (this.moveCount % 2 === 0 && !this.doDrawing) {
//
return
}
this.moveCount++
const xy =
e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY)
this.mouseTo.x = xy.x
this.mouseTo.y = xy.y
if (this.activeLine && this.activeLine.class === 'line') {
const pointer = this.canvas.getPointer(e.e)
this.activeLine.set({
x2: pointer.x,
y2: pointer.y
})
const points = this.activeShape.get('points')
points.push({
x: pointer.x,
y: pointer.y,
zIndex: 1
})
this.activeShape.set({
points: points
})
this.canvas.renderAll()
}
},
//
deleteObj() {
const activeObjects = this.canvas.getActiveObjects()
if (activeObjects.length > 0) {
activeObjects.forEach((item) => {
this.canvas.remove(item)
})
this.canvas.renderAll()
}
},
//
transformMouse(mouseX, mouseY) {
return {
x: mouseX,
y: mouseY
}
},
//
drawPolygon() {
if (this.bgImgFlag) {
this.canvas.getObjects().forEach((obj) => {
if (obj.isBgImg) {
obj.hasControls = false
obj.selectable = false
obj.evented = false
}
})
this.bgImgFlag = false
this.canvas.renderAll()
}
this.polygonMode = true
this.pointArray = [] //
this.lineArray = [] // 线
this.canvas.isDrawingMode = false
},
addPoint(e) {
const random = Math.floor(Math.random() * 10000)
const id = new Date().getTime() + random
const circle = new fabric.Circle({
radius: 5,
fill: '#ffffff',
stroke: '#333333',
strokeWidth: 0.5,
left: (e.pointer?.x || e.e.layerX) / this.canvas.getZoom(),
top: (e.pointer?.y || e.e.layerY) / this.canvas.getZoom(),
selectable: false,
hasBorders: false,
hasControls: false,
originX: 'center',
originY: 'center',
id,
objectCaching: false
})
if (this.pointArray.length === 0) {
circle.set({ fill: 'rgba(196,43, 1, 1)' })
}
const points = [
(e.pointer?.x || e.e.layerX) / this.canvas.getZoom(),
(e.pointer?.y || e.e.layerY) / this.canvas.getZoom(),
(e.pointer?.x || e.e.layerX) / this.canvas.getZoom(),
(e.pointer?.y || e.e.layerY) / this.canvas.getZoom()
]
const line = new fabric.Line(points, {
strokeWidth: 2,
fill: 'rgba(196,43, 1, 1)',
stroke: 'rgba(196,43, 1, 1)',
class: 'line',
originX: 'center',
originY: 'center',
selectable: false,
hasBorders: false,
hasControls: false,
evented: false,
objectCaching: false
})
if (this.activeShape) {
const pos = this.canvas.getPointer(e.e)
const points = this.activeShape.get('points')
points.push({ x: pos.x, y: pos.y })
const polygon = new fabric.Polygon(points, {
stroke: '#333333',
strokeWidth: 1,
fill: 'rgba(196,43, 1, 0.3)',
opacity: 0.3,
selectable: false,
hasBorders: false,
hasControls: false,
evented: false,
objectCaching: false
})
this.canvas.remove(this.activeShape)
this.canvas.add(polygon)
this.activeShape = polygon
this.canvas.renderAll()
} else {
const polyPoint = [
{
x: (e.pointer?.x || e.e.layerX) / this.canvas.getZoom(),
y: (e.pointer?.y || e.e.layerY) / this.canvas.getZoom()
}
]
const polygon = new fabric.Polygon(polyPoint, {
stroke: '#333333',
strokeWidth: 1,
fill: '#cccccc',
opacity: 0.3,
selectable: false,
hasBorders: false,
hasControls: false,
evented: false,
objectCaching: false
})
this.activeShape = polygon
this.canvas.add(polygon)
}
this.activeLine = line
this.pointArray.push(circle)
this.lineArray.push(line)
this.canvas.add(line)
this.canvas.add(circle)
},
generatePolygon() {
const points = []
this.pointArray.forEach((point) => {
points.push({ x: point.left, y: point.top })
this.canvas.remove(point)
})
this.lineArray.forEach((line) => {
this.canvas.remove(line)
})
if (this.activeShape) {
this.canvas.remove(this.activeShape)
}
if (this.activeLine) {
this.canvas.remove(this.activeLine)
}
const polygon = new fabric.Polygon(points, {
stroke: 'rgba(196,43, 1, 1)',
strokeWidth: this.drawWidth,
fill: 'rgba(196,43, 1, 0.3)',
opacity: 1,
selectable: false,
hasBorders: false,
hasControls: false,
name: '测试架号name1'
})
let maxIndex = 0
this.canvas._objects.forEach((obj) => {
if (obj.index > maxIndex) maxIndex = obj.index
})
polygon.index = maxIndex + 1
this.canvas.add(polygon)
this.activeLine = null
this.activeShape = null
this.polygonMode = false
this.doDrawing = false
fabric.Image.fromURL(this.deleteIconURL, this.deletecallback)
},
//
deleteObject() {
const activeObject = this.canvas.getActiveObject()
if (activeObject) {
this.canvas._objects.forEach(item => {
if (item.index === activeObject.index) {
this.canvas.remove(item)
}
})
const onlyBgImgItems = this.canvas._objects.filter(item => item.isBgImg)
const allItemsAreBgImg = this.canvas._objects.length / 2 === onlyBgImgItems.length
console.log('allItemsAreBgImg', allItemsAreBgImg)
if (allItemsAreBgImg) {
this.canvas.clear()
this.bgImgFlag = true
const imgElement = document.getElementById('expImg')
imgElement.src = this.imageFloorUrl
this.loadExpImg()
}
this.canvas.remove(activeObject)
this.canvas.renderAll()
} else {
console.log('this.canvas._objects.length', this.canvas._objects.length)
}
},
//
async deletecallback(img) {
const self = this
let max = 0
for (let i = 1; i < this.canvas._objects.length; i++) {
if (this.canvas._objects[i].index > max) max = this.canvas._objects[i].index
}
img.index = max
const oImg = await img.set({
name: 'delete-btn',
left: this.pointArray[0].left - 20,
top: this.pointArray[0].top - 20,
width: 40,
height: 40,
angle: 0
}).scale(0.8)
this.canvas.add(oImg).renderAll()
this.canvas.setActiveObject(oImg)
oImg.on('mousedown', function() {
self.deleteObject()
})
},
//
loadDraw() {
const self = this
if (this.drawinfo.id === '') return
// const pointGroup = JSON.parse(self.drawinfo.pointInfo);
// const imgInfo = JSON.parse(self.drawinfo.imgInfo);
const pointGroup = self.drawinfo.pointInfo
const imgInfo = self.drawinfo.imgInfo
// self.imageFloorUrl = self.drawinfo.img
imgInfo.src = self.imageFloorUrl
//
fabric.util.enlivenObjects([imgInfo], objects => {
objects.forEach(o => {
o.selectable = false
o.hasControls = false
o.centeredScaling = false
this.canvas.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, 0.3)',
opacity: 1,
selectable: false,
hasBorders: false,
hasControls: false,
originX: 'left', //
originY: 'top' //
})
polygon.index = index
self.canvas.add(polygon)
self.activeLine = null
self.activeShape = null
self.polygonMode = false
self.doDrawing = false
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)
// var delta = new fabric.Point(e.e.movementX, e.e.movementY)
// if(e.target&&e.target.name){
// // that.showDialog(e.target.name)
// }
this.set({ opacity: 0.3, hoverCursor: 'pointer' })
this.canvas.renderAll()
})
//
polygon.on('mouseout', function() {
this.set({ opacity: 1 })
this.canvas.renderAll()
})
// if (!self.readstate) {
// fabric.Image.fromURL(self.deleteIconURL, async img => {
// const _self = this;
// img.index = index;
// const oImg = await img.set({
// name: 'delete-btn',
// left: item.pointInfo[0].x - 20,
// top: item.pointInfo[0].y - 20,
// width: 40,
// height: 40,
// angle: 0
// }).scale(0.8);
// this.canvas.add(oImg);
// oImg.on('mousedown', function() {
// _self.deleteObject();
// });
// });
// }
}
})
})
self.canvas.renderAll()
},
//
clean() {
this.$confirm('确认清空标注吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.canvas.clear()
//
// this.canvas._objects = this.canvas._objects.filter((item) => {
// return item.isBgImg;
// });
//
// this.canvas.renderAll();
this.isDrawing = false
this.bgImgFlag = true
const imgElement = document.getElementById('expImg')
imgElement.src = this.imageFloorUrl
this.loadExpImg()
}).catch(() => {
console.log('取消清空标注')
})
}
}
}
</script>
<style lang="scss" scoped>
#expImg{
display: none;
}
</style>

165
src/views/visualCheck/venueDevice/area/index.vue

@ -10,7 +10,7 @@
<div class="head-search">
<!-- 搜索 -->
<el-select v-model="query.floorId" clearable size="small" placeholder="楼层" class="filter-item" style="width: 80px" @change="crud.toQuery">
<el-option v-for="item in floorOptions" :key="item.key" :label="item.floorName" :value="item.key" />
<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 />
@ -42,25 +42,15 @@
>
<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="collectionFloor" label="区域编码" />
<el-table-column prop="regionName" label="区域名称" />
<el-table-column prop="regionCode" label="区域编码" />
<el-table-column prop="floorName" label="所在楼层" />
<el-table-column prop="floorName" label="书架" />
<el-table-column prop="floorMap" label="标注">
<el-table-column prop="booksheflCount" label="书架" />
<el-table-column prop="signPoint" label="标注">
<template slot-scope="scope">
<span :class="['row-state', scope.row.floorMap ? 'end-state' : 'cancel-state' ]">{{ scope.row.floorMap ? '已标注': '未标注' }}</span>
<span :class="['row-state', scope.row.signPoint ? 'end-state' : 'cancel-state' ]">{{ scope.row.signPoint ? '已标注': '未标注' }}</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" />
@ -75,15 +65,17 @@
<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 === 0" @click="markVisible = true">
<el-button size="mini" class="venue-mark" :disabled="crud.selections.length !== 1" @click="handleMark">
<i class="el-icon-edit" />
区域标注
</el-button>
</ul>
<div v-if="activeIndex == 0" class="venue-preview">
<img :src="imageUrl" :onerror="defaultImg" alt="">
<img :src="imageFloorUrl" :onerror="defaultImg" alt="">
</div>
<div v-if="activeIndex == 1" class="venue-preview">
<img :src="imageRegionUrl" :onerror="defaultImg" alt="">
</div>
<div v-if="activeIndex == 1">区域预览</div>
</div>
</div>
</div>
@ -104,14 +96,14 @@
/>
</el-select>
</el-form-item>
<el-form-item label="区域名称" prop="areaName">
<el-input v-model="form.floorName" style="width: 580px;" />
<el-form-item label="区域名称" prop="regionName">
<el-input v-model="form.regionName" style="width: 580px;" />
</el-form-item>
<el-form-item label="区域编码" prop="areaCode">
<el-input v-model="form.floorName" style="width: 580px;" />
<el-form-item label="区域编码" prop="regionCode">
<el-input v-model="form.regionCode" 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 label="描述信息" prop="regionDescription">
<el-input v-model="form.regionDescription" placeholder="请输入" type="textarea" rows="3" style="width: 580px;" />
</el-form-item>
<UploadCover :label-name="labelName" :form="form" @childCover="handleCover" />
</el-form>
@ -130,65 +122,48 @@
<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="areaName" label="区域名称" />
<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="区域A-区域标注" :visible.sync="markVisible">
<el-dialog class="mark-dialog" :close-on-click-modal="false" :append-to-body="true" :title="titleMark" :visible.sync="markVisible">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog mark-handle">
<div class="mark-img">
<img :src="imageUrl" :onerror="defaultImg" alt="">
</div>
<div class="mark-right">
<ul class="mark-info">
<li>
<p>所属机构</p>
<span>机构A</span>
</li>
<li>
<p>所属楼层</p>
<span>五楼</span>
</li>
<li>
<p>书架</p>
<span>4</span>
</li>
<li><span :class="['row-state', true ? 'end-state' : 'cancel-state' ]">{{ true ? '已标注': '未标注' }}</span></li>
</ul>
<div class="mark-button">
<el-button type="primary" disabled><i class="iconfont icon-shanchu" />清空</el-button>
<el-button type="primary"><i class="el-icon-edit" style="font-weight: bold; padding-right: 4px; font-size: 16px;" />标注</el-button>
<el-button type="primary" disabled><i class="el-icon-folder-checked" style="font-weight: bold; padding-right: 4px; font-size: 16px;" />保存</el-button>
</div>
</div>
<div class="setting-dialog">
<MarkCover :current-mark-data="currentMarkData" :image-floor-url="imageFloorUrl" />
</div>
</el-dialog>
</div>
</template>
<script>
import crudFloor from '@/api/floor/index'
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'
const defaultForm = { id: null, floorId: null, areaName: null, areaCode: null, floorDescription: null, floorMap: null }
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 },
components: { crudOperation, rrOperation, pagination, UploadCover, MarkCover },
cruds() {
return CRUD({ title: '区域', url: 'api/libraryFloor/initLibraryFloorList', crudMethod: { ...crudFloor }, sort: [], optShow: {
return CRUD({ title: '区域', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: {
add: true,
edit: true,
del: false,
@ -200,10 +175,7 @@ export default {
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
return {
floorOptions: [
{ key: '1', floorName: '一楼' },
{ key: '0', floorName: '二楼' }
],
floorOptions: [],
labelName: '区域地图',
permission: {
add: ['admin', 'floor:add'],
@ -214,19 +186,22 @@ export default {
floorId: [
{ required: true, message: '请选择所属楼层', trigger: 'change' }
],
areaName: [
regionName: [
{ required: true, message: '区域名称不可为空', trigger: 'blur' }
],
areaCode: [
regionCode: [
{ required: true, message: '区域编码不可为空', trigger: 'blur' }
]
},
activeIndex: 0,
defaultImg: defaultImg,
imageUrl: defaultImg,
imageFloorUrl: defaultImg,
imageRegionUrl: defaultImg,
sortTableData: [], // data
sortVisible: false, // dialog
markVisible: false //
markVisible: false, //
titleMark: '区域标注',
currentMarkData: null
}
},
computed: {
@ -237,24 +212,24 @@ export default {
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.getLibraryFloorListAll()
},
[CRUD.HOOK.afterRefresh](crud) {
console.log(crud.data)
if (crud.data.length !== 0) {
// this.$nextTick(() => {
// this.$refs.table.toggleRowSelection(crud.data[0], true)
// })
}
},
//
[CRUD.HOOK.afterValidateCU](crud) {
console.log(crud.form)
return true
},
//
getLibraryFloorListAll() {
FetchLibraryFloorListAll().then(res => {
this.floorOptions = res
}).catch(() => {
})
},
handleCover(value) {
console.log(value)
this.form.floorMap = value
this.crud.form.regionMap = value
},
changeFloorValue(value) {
console.log(value)
@ -262,15 +237,47 @@ export default {
clickRowHandler(row) {
this.$refs.table.clearSelection()
this.$refs.table.toggleRowSelection(row)
// http://192.168.99.67:12010/api/fileRelevant/getImg?imgId=f6d3ecea-0456-4429-ba77-1a4921d5c806
if (row.floorMap) {
this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgId=' + row.floorMap
if (this.activeIndex === 0) {
if (row.floorMap) {
this.imageFloorUrl = this.baseApi + '/api/fileRelevant/getImg?imgId=' + row.floorMap
} else {
this.imageFloorUrl = this.defaultImg
}
} else {
this.imageUrl = this.defaultImg
if (row.regionMap) {
this.imageRegionUrl = this.baseApi + '/api/fileRelevant/getImg?imgId=' + row.regionMap
} else {
this.imageRegionUrl = this.defaultImg
}
}
},
changeActiveTab(data) {
this.activeIndex = data
console.log(this.crud.selections)
if (this.crud.selections.length === 1) {
if (this.crud.selections[0].floorMap) {
this.imageFloorUrl = this.baseApi + '/api/fileRelevant/getImg?imgId=' + this.crud.selections[0].floorMap
} else {
this.imageFloorUrl = this.defaultImg
}
if (this.crud.selections[0].regionMap) {
this.imageRegionUrl = this.baseApi + '/api/fileRelevant/getImg?imgId=' + this.crud.selections[0].regionMap
} else {
this.imageRegionUrl = this.defaultImg
}
}
},
async handleMark() {
if (this.crud.selections[0].floorMap) {
this.markVisible = true
this.currentMarkData = this.crud.selections[0]
this.titleMark = this.currentMarkData.regionName + ' - 区域标注'
} else {
this.$message({ message: '请先上传当前楼层图', type: 'error', offset: 8 })
}
},
toDelete(datas) {
this.$confirm('此操作将删除当前所选区域<span>你是否还要继续?</span>', '提示', {
@ -285,7 +292,7 @@ export default {
ids.push(val.id)
})
console.log(ids)
crudFloor.del(ids).then(res => {
crudRegion.del(ids).then(res => {
console.log(res)
this.$message({ message: res, type: 'success', offset: 8 })
this.crud.delAllLoading = false
@ -327,7 +334,7 @@ export default {
this.sortTableData.forEach((item, index) => {
item.isSequence = index + 1
})
crudFloor.sort(data).then(() => {
crudRegion.sort(data).then(() => {
this.sortVisible = false
this.$message({ message: '保存成功', type: 'success', offset: 8 })
this.crud.refresh()

188
src/views/visualCheck/venueDevice/device/index.vue

@ -44,8 +44,7 @@
</el-button>
</template>
<template v-slot:right>
<!-- :disabled="selections.length !== 1 || selections[0].bindState" -->
<el-button type="primary" size="mini" :disabled="crud.selections.length !== 1"><i class="iconfont icon-bangding" />书架绑定</el-button>
<el-button type="primary" size="mini" :disabled="crud.selections.length !== 1" @click="openBindShelf"><i class="iconfont icon-bangding" />书架绑定</el-button>
</template>
</crudOperation>
</div>
@ -91,6 +90,7 @@
<pagination />
</div>
<!-- 设备管理1 -->
<el-dialog
:close-on-click-modal="false"
:modal-append-to-body="false"
@ -113,7 +113,7 @@
</div>
</div>
</el-dialog>
<!-- 设备管理2 -->
<el-dialog
:close-on-click-modal="false"
:modal-append-to-body="false"
@ -160,6 +160,57 @@
</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">
<!-- @input="changePid" -->
<treeselect
v-model="floorTreeValue"
:options="menus"
:load-options="loadMenus"
style="width: 320px; margin-bottom: 20px;"
placeholder="请选择楼层区域"
/>
<div class="transfer-bookshelf">
<!-- :filter-method="filterMethod" -->
<el-transfer
v-model="value4"
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="data"
@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="value4.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>
@ -167,6 +218,10 @@
</template>
<script>
import crudMenu from '@/api/system/menu'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect'
import crudDevice from '@/api/device/index'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
@ -202,7 +257,7 @@ const defaultForm = {
}
export default {
name: 'Device',
components: { crudOperation, pagination },
components: { Treeselect, crudOperation, pagination },
cruds() {
return CRUD({ title: '设备', url: 'api/device/list', sort: [], crudMethod: { ...crudDevice }, optShow: {
add: false,
@ -215,7 +270,19 @@ export default {
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
const generateData = _ => {
// disabled: i % 4 === 0
const data = []
for (let i = 1; i <= 20; i++) {
data.push({
key: i,
label: `001排A面01架${i}`
})
}
return data
}
return {
bindBookShelfVisible: false,
fondsDatas: [],
deviceType: null,
deviceTypeOptions: [],
@ -233,6 +300,15 @@ export default {
add: ['admin', 'device:add'],
edit: ['admin', 'device:edit'],
del: ['admin', 'device:del']
},
floorTreeValue: null,
menus: [],
data: generateData(),
value4: [],
leftDefaultChecked: [],
rightDefaultChecked: [],
filterMethod(query, item) {
// return item.pinyin.indexOf(query) > -1
}
}
},
@ -291,6 +367,58 @@ export default {
mounted: () => {
},
methods: {
openBindShelf() {
this.value4 = []
this.bindBookShelfVisible = true
},
handleChange(value, direction, movedKeys) {
console.log(value, direction, movedKeys)
},
dialogSaveSeting() {
// https://www.cnblogs.com/liujiajiablog/p/15818056.html
this.bindBookShelfVisible = false
console.log(this.value4)
},
rightCheckedClear() {
this.value4 = []
},
changePid() {
// this.$refs.form.validateField('pid')
},
getMenus(tree, treeNode, resolve) {
const params = { pid: tree.id }
setTimeout(() => {
crudMenu.getMenus(params).then(res => {
resolve(res.content)
})
}, 100)
},
getSupDepts(id) {
crudMenu.getMenuSuperior(id).then(res => {
const children = res.map(function(obj) {
if (!obj.leaf && !obj.children) {
obj.children = null
}
return obj
})
this.menus = [{ id: 0, label: '顶级类目', children: children }]
})
},
loadMenus({ action, parentNode, callback }) {
if (action === LOAD_CHILDREN_OPTIONS) {
crudMenu.getMenusTree(parentNode.id).then(res => {
parentNode.children = res.map(function(obj) {
if (!obj.leaf) {
obj.children = null
}
return obj
})
setTimeout(() => {
callback()
}, 100)
})
}
},
resetQuery() {
this.crud.query.blurry = ''
this.crud.toQuery()
@ -386,6 +514,7 @@ export default {
})
},
handleCloseDialog(done) {
this.bindBookShelfVisible = false
//
if (this.$refs.deviceForm) {
this.deviceSelectVisible = false
@ -426,4 +555,55 @@ export default {
}
}
}
.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>

19
src/views/visualCheck/venueDevice/floor/index.vue

@ -10,7 +10,7 @@
<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 /> -->
<rrOperation />
</div>
<crudOperation :permission="permission">
<template v-slot:middle>
@ -40,7 +40,7 @@
<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="collectionFloor" 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>
@ -70,6 +70,7 @@
<!-- 最右侧装饰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="">
@ -121,7 +122,7 @@
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 rrOperation from '@crud/RR.operation'
import pagination from '@crud/Pagination'
import UploadCover from '@/views/components/upload.vue'
import Sortable from 'sortablejs'
@ -131,7 +132,7 @@ 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, pagination, UploadCover },
components: { crudOperation, rrOperation, pagination, UploadCover },
cruds() {
return CRUD({ title: '楼层', url: 'api/libraryFloor/initLibraryFloorList', crudMethod: { ...crudFloor }, sort: [], optShow: {
add: true,
@ -139,12 +140,13 @@ export default {
del: false,
download: false,
group: false,
reset: true
reset: false
}})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
return {
imgLoading: false,
labelName: '楼层地图',
permission: {
add: ['admin', 'floor:add'],
@ -175,10 +177,7 @@ export default {
[CRUD.HOOK.afterRefresh](crud) {
console.log(crud.data)
if (crud.data.length !== 0) {
// this.clickRowHandler(crud.data[0])
this.$nextTick(() => {
this.$refs.table.toggleRowSelection(crud.data[0], true)
})
this.clickRowHandler(crud.data[0])
}
},
//
@ -188,7 +187,7 @@ export default {
},
handleCover(value) {
console.log(value)
this.form.floorMap = value
this.crud.form.floorMap = value
},
clickRowHandler(row) {
this.$refs.table.clearSelection()

Loading…
Cancel
Save