新功能

This commit is contained in:
2025-07-04 17:52:10 +08:00
parent 8defc28022
commit beb227f6b1
17 changed files with 475 additions and 178 deletions

View File

@@ -0,0 +1,128 @@
<template>
<div class="page_container">
<el-row type="flex" justify="space-between">
<el-col :span="10"><button class="button_control" @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" @click="connectPoints"><p>建图</p></button></el-row>
</div>
</template>
<script>
export default {
data () {
return {
points: [], // 存储所有点位坐标
intervalId: null, // 用于存储定时器的 ID
drawingPoints: true, // 是否继续绘制点位
scale: 1 // 缩放比例
}
},
beforeDestroy () {
if (this.intervalId) {
clearInterval(this.intervalId)
}
},
methods: {
addPoint () {
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>

View File

@@ -1,126 +1,174 @@
<template>
<el-row type="flex" class="page_container" align="top">
<el-col :span="20" class="l_box_w">
<el-row type="flex" class="l_box" justify="start" align="top">
<el-col class="point_item" v-for="e in dataList" :key="e.point_code">
<div class="zbox point_item_i" @click="handleCheck(e)"><p>{{ e.point_code }}</p></div>
</el-col>
</el-row>
<el-row type="flex" class="result_w" justify="space-between" align="middle">
<el-col :span="19" class="result_items_w">
<el-row type="flex" class="result_items" justify="start" align="top">
<el-col class="pp_item" v-for="(e, i) in newData" :key="e.point_code">
<el-row type="flex">
<div class="point_item point_checked point_item_s"><div class="point_item_i"><p>{{ e.point_code }}</p></div></div>
<i class="el-icon-caret-right icon-caret-right" :style="i === newData.length - 1 ? 'visibility: hidden' : ''"></i>
</el-row>
<div class="page_container">
<div class="t_box">
<el-tabs tab-position="left" @tab-click="tabClick">
<el-tab-pane label="自定义">
<el-row type="flex" class="r_box">
<el-col class="point_item" v-for="e in dataList" :key="e.point_code">
<el-popover
placement="bottom"
trigger="click"
:value="popId === e.point_code"
@show="popId = e.point_code"
@hide="popId = null">
<el-row type="flex">
<el-button class="task_button" v-for="e in radioOption" :key="e.value" @click="radioInput(e.value)">{{ e.label }}</el-button>
</el-row>
<div slot="reference" class="zbox point_item_i"><p>{{ e.point_code }}</p></div>
</el-popover>
</el-col>
</el-row>
</el-col>
<el-col :span="4">
<button class="button_control button_control_disabled" style="margin-bottom: .08rem" @click="newData = []"><p>{{$t('Empty')}}</p></button>
<button class="button_control"><p :style="$i18n.locale === 'en-us' ? 'font-size: 0.19rem;' : 'font-size: 0.22rem;'">{{$t('SendTask')}}</p></button>
</el-col>
</el-row>
</el-col>
<el-col :span="4" class="r_box_w">
<div class="tip" :style="$i18n.locale === 'en-us' ? 'font-size: 0.15rem;' : 'font-size: 0.16rem;'">{{$t('HistoricalTasks')}}</div>
<div class="ls_w">
<div class="ls_item">
<span v-for="(e, i) in historyData" :key="e.point_code">
<span>{{ e.point_code }}</span><i v-if="i < historyData.length - 1" class="el-icon-right"></i>
</span>
</div>
</div>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane label="任务链">
<el-row type="flex" class="r_box">
<el-col class="point_item" v-for="e in linkData" :key="e.point_code">
<div class="zbox point_item_i" @click="handleLinkCheck(e)"><p>{{ e.point_code }}</p></div>
</el-col>
</el-row>
</el-tab-pane>
<el-tab-pane label="标准任务">
<el-row type="flex" class="r_box">
<el-col class="point_item" v-for="(e, i) in dataList" :key="i">
<div class="zbox point_item_i" @click="handleCheck(e)"><p>{{ e.point_code }}</p></div>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
</div>
<el-row type="flex" class="result_w" justify="space-between" align="middle">
<el-col :span="15" class="result_items_w">
<el-row type="flex" class="result_items" justify="start" align="top">
<el-col class="pp_item" v-for="(e, i) in newData" :key="e.point_code">
<el-row type="flex" align="middle">
<div class="point_item point_checked">
<el-row type="flex" align="middle" class="zbox">
<el-col :span="18">
<p style="padding-left: 0.02rem;">{{ e.point_code }}</p>
</el-col>
<el-col :span="6" style="border-left: 1px solid #fff;"><p style="font-size: .12rem;font-weight: 700;text-align: center;padding-right: 0.02rem;">{{ e.radio }}</p></el-col>
</el-row>
</div>
<i class="el-icon-caret-right icon-caret-right" :style="i === newData.length - 1 ? 'visibility: hidden' : ''"></i>
</el-row>
</el-col>
</el-row>
</el-col>
<el-col :span="8">
<el-row type="flex" justify="space-between" style="flex-wrap: wrap" >
<el-col :span="11" style="margin-bottom: .08rem"><button class="button_control button_control_disabled" @click="newData = []"><p>删除任务链</p></button></el-col>
<el-col :span="11" style="margin-bottom: .08rem"><button class="button_control button_control_disabled"><p>取消任务</p></button></el-col>
<el-col :span="11"><button class="button_control"><p>保存任务</p></button></el-col>
<el-col :span="11"><button class="button_control"><p>发送任务</p></button></el-col>
</el-row>
<!-- <button class="button_control button_control_disabled" style="margin-bottom: .08rem" @click="newData = []"><p>{{$t('Empty')}}</p></button>
<button class="button_control"><p :style="$i18n.locale === 'en-us' ? 'font-size: 0.19rem;' : 'font-size: 0.22rem;'">{{$t('SendTask')}}</p></button> -->
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data () {
return {
dataList: [{point_code: 'A'}, {point_code: 'B'}, {point_code: 'C'}, {point_code: 'D'}, {point_code: 'E'}, {point_code: 'F'}, {point_code: 'G'}, {point_code: 'H'}],
popId: null,
radioOption: [{label: '取货', value: '取'}, {label: '放货', value: '放'}, {label: '移动', value: '移'}, {label: '返回点', value: '返'}],
dataList: [{point_code: 'A', radio: ''}, {point_code: 'B', radio: ''}, {point_code: 'C', radio: ''}, {point_code: 'D', radio: ''}, {point_code: 'E', radio: ''}, {point_code: 'F', radio: ''}],
newData: [],
historyData: [{point_code: 'A'}, {point_code: 'B'}, {point_code: 'C'}, {point_code: 'D'}, {point_code: 'E'}]
linkData: [{point_code: 'A-B-C', radio: '取-放-移'}]
}
},
methods: {
tabClick () {
this.newData = []
},
radioInput (e) {
const lastItem = this.newData.length > 0 ? this.newData[this.newData.length - 1].point_code : null
if (lastItem === this.popId) {
this.$message('相邻的两个站点不能相同')
this.popId = ''
return
}
if (this.newData.length > 4) {
this.$message('最多选取5个站点')
this.popId = ''
return
}
this.newData.push({point_code: this.popId, radio: e})
this.popId = ''
},
handleCheck (e) {
this.newData.push(e)
if (this.newData.length > 3) {
return
}
if (this.newData.length === 0) {
this.newData.push({point_code: e.point_code, radio: '起'})
} else if (this.newData.length === 1) {
this.newData.push({point_code: e.point_code, radio: '终'})
} else if (this.newData.length === 2) {
this.newData.push({point_code: e.point_code, radio: '停'})
}
},
handleLinkCheck (e) {
const data = e.point_code.split('-')
const radio = e.radio.split('-')
data.map((e, i) => {
this.newData.push({point_code: e, radio: radio[i]})
})
}
}
}
</script>
<style lang="stylus" scoped>
.l_box_w
height 100%
overflow hidden
.l_box
.t_box
height calc(100% - 1.1rem)
margin-bottom 0.1rem
background-color rgba(0, 19, 48, 70%)
box-shadow inset 1px 1px 7px 2px #4d9bcd
padding .1rem
overflow hidden
.r_box
height 100%
overflow-y auto
flex-wrap wrap
align-content flex-start
margin-bottom .1rem
.pp_item
width 19.6%
width 33%
.point_item
width 19.6%
height 0.6rem
padding 0.1rem
margin-bottom 0.02rem
background center / 100% 100% url(../../images/new/bg2.png) no-repeat
.point_item_i
display flex
align-items center
justify-content center
p
font-size .2rem
font-family 'SourceHanSansCN-Bold'
line-height .2rem
color #B4C1D8
text-align center
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* 定义显示的行数 */
overflow: hidden;
text-overflow: ellipsis;
.point_item_i
display flex
align-items center
justify-content center
.point_checked
width calc(100% - .17rem)
height .4rem
padding 0
background-image url(../../images/new/bg1.png)
p
color #3CC1FF
.r_box_w
margin-left: .1rem
background-color #001330
box-shadow inset 1px 1px 7px 2px #4d9bcd
padding .1rem
overflow hidden
.tip
font-size .16rem
color #fff
font-family 'YouSheBiaoTiHei'
line-height .16rem
margin-bottom .2rem
.ls_w
height calc(100% - .36rem)
overflow-y auto
.ls_item
font-size .15rem
line-height .16rem
color #3CC1FF
padding-bottom .1rem
margin-top .1rem
border-bottom 1px dashed #457C9B
font-size .16rem
.result_w
height 1rem
border 1px solid #1E9FE7
padding .1rem
background-color rgba(10, 73, 164, 80%)
.point_item_s
width calc(100% - .17rem)
height .4rem
p
font-size .17rem
.icon-caret-right
width .3rem
font-size .2rem
@@ -133,5 +181,30 @@ export default {
flex-wrap wrap
align-content flex-start
overflow-y auto
max-height: 100%;
max-height 100%
.task_button
line-height 1
white-space nowrap
vertical-align middle
border 1px solid #233553
border-left 0
-webkit-appearance none
text-align center
box-sizing border-box
margin 0
color #9ff0fc
background center / 100% 100% url(../../images/new/tab_bg.png) no-repeat
padding 0.1rem
font-size 0.14rem
&:first-child
border-left 1px solid #233553
&:active, &:hover
border-color #146fd0
border-left 1px solid #146fd0
.task_checked
color #FFF
background-color #409EFF
border-color #409EFF
&:first-child
border-left-color #409EFF
</style>

View File

@@ -16,7 +16,7 @@ export default {
return {
nav: [
{title: '操作', zh_title: '操作', en_title: 'Operation', router: '/index/device'},
{title: '建图', zh_title: '建图', en_title: 'Map building', router: ''},
{title: '建图', zh_title: '建图', en_title: 'Map building', router: '/index/building'},
{title: '取消任务', zh_title: '取消任务', en_title: 'Cancel task', router: ''},
{title: '地图', zh_title: '地图', en_title: 'Map', router: ''}
],

View File

@@ -0,0 +1,67 @@
<template>
<el-dialog
class="warn_modal"
:title="$t('Configuration')"
:visible.sync="dialogVisible"
width="70%"
:before-close="handleClose">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="图文说明" name="1">
<p class="tip">障碍物告警</p>
<p class="p1">处理方法</p>
<p class="p2">1.查看避障传感器</p>
<img src="../../images/new/bg1.png" alt="">
</el-tab-pane>
<el-tab-pane label="视频说明" name="2">
<video src=""></video>
</el-tab-pane>
</el-tabs>
</el-dialog>
</template>
<script>
export default {
data () {
return {
dialogVisible: false,
activeName: '1'
}
},
methods: {
init () {
this.dialogVisible = true
},
handleClick (tab, event) {
console.log(tab, event)
},
handleClose (done) {
this.visible = false
done()
}
}
}
</script>
<style lang="stylus" scoped>
.el-dialog__header
padding 0.2rem 0.2rem 0.3rem
.tip
font-size .2rem
font-weight 700
font-family 'SourceHanSansCN-Bold'
line-height .2rem
color #E54F29
text-align center
border-bottom 1px dashed #85DFFF
padding .2rem
margin-bottom .2rem
.p1
font-size .18rem
line-height .2rem
color #fff
margin-bottom .2rem
.p2
font-size .16rem
line-height .2rem
color #fff
</style>

View File

@@ -3,37 +3,64 @@
<el-table
:data="tableData"
style="width: 100%">
<el-table-column
prop="time"
:label="$t('Time')">
</el-table-column>
<el-table-column
prop="date"
:label="$t('Name')"
width="180">
:label="$t('Name')">
</el-table-column>
<el-table-column
prop="name"
:label="$t('Category')"
width="180">
width="100">
</el-table-column>
<el-table-column
prop="address"
:label="$t('Description')">
:label="$t('Description')"
width="400">
</el-table-column>
<el-table-column
label="操作"
width="90">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
</template>
</el-table-column>
</el-table>
<warn-modal v-if="warnVisible" ref="warnModal"/>
</div>
</template>
<script>
import WarnModal from './warn-modal.vue'
export default {
components: {
WarnModal
},
data () {
return {
tableData: [{
time: '2025-6-30 14:37:24',
date: '障碍物告警',
name: '一级',
address: '车辆避障传感器检测到障碍物,请检查周围环境,移除障碍物。'
}, {
time: '2025-6-30 14:31:20',
date: '定位丢失',
name: '二级',
address: '当前位置定位丢失,恢复定位请拉动车辆到点位上重新上线。'
}]
}],
warnVisible: false
}
},
methods: {
handleClick () {
this.warnVisible = true
this.$nextTick(() => {
this.$refs.warnModal.init()
})
}
}
}