Files
apt15e/src/pages/modules/building2.vue
2025-07-15 13:59:05 +08:00

356 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="page_container">
<el-row type="flex" justify="space-between">
<el-col :span="10"><button class="button_control" :disabled="disabled" @click="addPoint"><p>打点</p></button></el-col>
<el-col :span="14">
<el-row type="flex" justify="end">
<el-button type="primary" icon="el-icon-zoom-in" size="mini" @click="zoomIn">放大</el-button>
<el-button type="primary" icon="el-icon-zoom-out" size="mini" @click="zoomOut">缩小</el-button>
</el-row>
</el-col>
</el-row>
<div class="canvas-container">
<canvas id="canvas" ref="canvas" width="1920" height="1080"></canvas>
</div>
<el-row type="flex" justify="end"><button class="button_control" :disabled="disabled" @click="_stopMapping"><p>结束建图</p></button></el-row>
<el-dialog
title="设置站点"
:visible.sync="dialogVisible"
width="50%">
<el-form :model="dataForm" ref="dataForm" :label-width="$i18n.locale === 'en-us' ? '' : '1.1rem'" size="mini">
<el-form-item label="站点名称" prop="point">
<el-input v-model="dataForm.point" id="point" @focus="show" data-layout="normal"></el-input>
</el-form-item>
</el-form>
<el-row type="flex" justify="space-around" style="margin-top: .3rem">
<el-col :span="7"><button class="button_control button_control_disabled" @click="dialogVisible = false"><p>{{$t('Cancel')}}</p></button></el-col>
<el-col :span="7"><button class="button_control" @click="_setStation"><p>{{$t('Save')}}</p></button></el-col>
</el-row>
<vue-touch-keyboard id="keyboard" :options="options" v-if="visible" :layout="layout" :cancel="hide" :accept="accept" :input="input" :next="next" />
</el-dialog>
<p v-if="message">{{ message }}</p>
</div>
</template>
<script>
import { startMapping, setStation, stopMapping, getLocalMaps, oneClickDeployment } from '@config/getData.js'
export default {
data () {
return {
mapName: '',
dialogVisible: false,
dataForm: {
point: ''
},
keyPoints: [],
disabled: false,
message: '', // 用于显示消息
intervalId: null, // 用于存储定时器ID
startTime: null, // 用于记录开始时间
visible: false,
layout: 'normal',
input: null,
options: {
useKbEvents: false,
preventClickEvent: false
},
points: [], // 存储所有点位坐标
intervalId: null, // 用于存储定时器的 ID
drawingPoints: true, // 是否继续绘制点位
scale: 1, // 缩放比例
gridColor: '#FFFFFF', // 线条颜色
gridLineWidth: 1, // 线条宽度
gridCellSize: 200, // 格子大小
dotColor: '#000000', // 圆点颜色
dotRadius: 5 // 圆点半径直径为5px半径为2.5px
}
},
beforeDestroy () {
if (this.intervalId) {
clearInterval(this.intervalId)
}
},
mounted () {
// this.drawGrid()
this._startMapping()
},
methods: {
show (e) {
// 关闭中文keyboard
let arr = document.querySelectorAll('.hg-theme-default')
arr.forEach((ele) => {
ele.style.visibility = 'hidden'
})
this.input = e.target
this.layout = e.target.dataset.layout
if (!this.visible) {
this.visible = true
}
},
hide () {
this.visible = false
},
accept () {
this.hide()
},
next () {
let inputs = document.querySelectorAll('input')
let found = false;
[].forEach.call(inputs, (item, i) => {
if (!found && item === this.input && i < inputs.length - 1 && this.input.dataset.next === '1') {
found = true
this.$nextTick(() => {
inputs[i + 1].focus()
})
}
})
if (!found) {
this.input.blur()
this.hide()
}
},
// 开始建图
async _startMapping () {
try {
const getTimestamp = new Date().getTime()
this.mapName = `apt_map_${getTimestamp}`
let res = await startMapping(this.mapName)
if (res) {
if (res.code !== 200) {
this.$message.error(res.message)
}
}
} catch (e) {
this.$message.error(e)
}
},
// 打点
addPoint () {
this.dialogVisible = true
this.dataForm.point = 'B' + (this.keyPoints.length + 1)
},
// 打点->保存
async _setStation () {
this.disabled = true
try {
let res = await setStation(this.dataForm.point)
if (res) {
if (res.code === 200) {
this.$message({
type: 'success',
message: res.message
})
this.keyPoints.push(this.dataForm.point)
} else {
this.$message.error(res.message)
}
}
this.dialogVisible = false
this.visible = false
this.disabled = false
} catch (e) {
this.$message.error(e)
this.dialogVisible = false
this.visible = false
this.disabled = false
}
},
// 结束建图
async _stopMapping () {
this.disabled = true
try {
let res = await stopMapping()
if (res) {
if (res.code === 200) {
this.$message({
type: 'success',
message: res.message
})
this.message = ''
this.startTime = Date.now() // 记录开始时间
this.intervalId = setInterval(this._getLocalMaps, 5000) // 每5秒检查一次
// this._oneClickDeployment()
} else {
this.$message.error(res.message)
}
}
this.disabled = false
} catch (e) {
this.$message.error(e)
this.disabled = false
}
},
async _getLocalMaps () {
try {
let res = await getLocalMaps()
if (res && res.code === 200) {
res.data(el => {
if (el.id === this.mapName) {
clearInterval(this.intervalId) // 停止定时器
await this._oneClickDeployment()
}
})
} else {
const elapsedTime = Date.now() - this.startTime
if (elapsedTime >= 60000) { // 超过1分钟
clearInterval(this.intervalId) // 停止定时器
this.message = '建图失败,请重新建图'
}
}
} catch (e) {
clearInterval(this.intervalId) // 出错时停止定时器
this.$message.error(e)
}
},
async _oneClickDeployment () {
try {
let res = await oneClickDeployment(this.mapName)
if (res) {
if (res.code === 200) {
this.$message({
type: 'success',
message: res.message
})
} else {
this.$message.error(res.message)
}
}
} catch (e) {
this.$message.error(e)
}
},
drawGrid () {
const canvas = this.$refs.canvas
const ctx = canvas.getContext('2d')
const width = canvas.width
const height = canvas.height
// 清空画布
ctx.clearRect(0, 0, width, height)
// 绘制格子
for (let x = 0; x <= width; x += this.gridCellSize * this.scale) {
ctx.beginPath()
ctx.moveTo(x, 0)
ctx.lineTo(x, height)
ctx.strokeStyle = this.gridColor
ctx.lineWidth = this.gridLineWidth
ctx.stroke()
}
for (let y = 0; y <= height; y += this.gridCellSize * this.scale) {
ctx.beginPath()
ctx.moveTo(0, y)
ctx.lineTo(width, y)
ctx.strokeStyle = this.gridColor
ctx.lineWidth = this.gridLineWidth
ctx.stroke()
}
// 绘制圆点
for (let x = 0; x < width; x += this.gridCellSize * this.scale) {
for (let y = 0; y < height; y += this.gridCellSize * this.scale) {
if (x > 0 && y > 0) {
ctx.beginPath()
ctx.arc(x, y, this.dotRadius, 0, Math.PI * 2)
ctx.fillStyle = this.dotColor
ctx.fill()
}
}
}
},
addPoint2 () {
this.points = [] // 清空白色点位数组
this.drawingPoints = true // 重新开始绘制点位
this.drawPoints() // 重新绘制画布
this.updatePoint()
this.intervalId = setInterval(this.updatePoint, 5000)
},
// 模拟后端提供的点位坐标
getNewPoint () {
// 随机生成新的坐标
const newX = Math.random() * 1920 // 假设 x 坐标范围是 0 到 1920
const newY = Math.random() * 1080 // 假设 y 坐标范围是 0 到 1080
return { x: newX, y: newY } // 返回坐标
},
// 更新点位坐标
updatePoint () {
if (!this.drawingPoints) return
const newPoint = this.getNewPoint() // 获取新的坐标
this.points.push(newPoint) // 将新坐标添加到数组中
this.drawPoints() // 重新绘制点位
},
// 绘制点位
drawPoints () {
const canvas = this.$refs.canvas
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height) // 清除画布
// 绘制每个点位
ctx.fillStyle = 'white'
ctx.beginPath()
this.points.forEach(point => {
ctx.moveTo(point.x, point.y)
ctx.arc(point.x, point.y, 10, 0, Math.PI * 2) // 绘制半径为10px的圆点
})
ctx.fill()
},
// 连接点位成一条直线
connectPoints () {
this.drawingPoints = false // 停止绘制点位
clearInterval(this.intervalId) // 关闭定时器
this.drawLine() // 绘制直线
},
drawLine () {
const canvas = this.$refs.canvas
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height) // 清除画布
// 绘制路径
ctx.strokeStyle = 'white'
ctx.lineWidth = 1
ctx.beginPath()
if (this.points.length > 0) {
ctx.moveTo(this.points[0].x, this.points[0].y) // 移动到第一个点
for (let i = 1; i < this.points.length; i++) {
ctx.lineTo(this.points[i].x, this.points[i].y) // 依次连接到其他点
}
ctx.stroke() // 绘制路径
}
},
// 放大
zoomIn () {
this.scale += 0.1
this.redrawCanvas()
},
// 缩小
zoomOut () {
this.scale -= 0.1
if (this.scale < 0.1) this.scale = 0.1 // 防止缩放到 0 或负值
this.redrawCanvas()
},
// 重新绘制画布
redrawCanvas () {
const canvas = this.$refs.canvas
canvas.style.transform = `scale(${this.scale})`
if (this.drawingPoints) {
this.drawPoints()
} else {
this.drawLine()
}
}
}
}
</script>
<style lang="stylus" scoped>
.canvas-container
height calc(100% - 1rem)
margin .14rem 0
background-color rgba(0, 19, 48, 70%)
box-shadow inset 1px 1px 7px 2px #4d9bcd
overflow hidden
#canvas
width 100%
height 100%
</style>