feat(tunnel): 添加图片热区功能
- 在 App.vue 中添加新的视口配置 - 在 router/index.js 中添加新的路由路径- 修改 tunnel/index.vue,为图片添加热区 - 新增 test
This commit is contained in:
@@ -27,6 +27,11 @@ onMounted(() => {
|
||||
height: "100vh",
|
||||
width: "100vw",
|
||||
},
|
||||
{
|
||||
el: "#imghot",
|
||||
height: "100vh",
|
||||
width: "100vw",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
234
src/components/PolygonSelector.vue
Normal file
234
src/components/PolygonSelector.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<div class="polygon-selector">
|
||||
<!--用来和鼠标进行交互操作的canvas-->
|
||||
<canvas
|
||||
id="canvas"
|
||||
ref="canvasRef"
|
||||
:width="width + 'px'"
|
||||
:height="height + 'px'"
|
||||
:style="{ backgroundImage: 'url(' + backgroundImg + ')', cursor: 'crosshair' }"
|
||||
></canvas>
|
||||
<!--存储已生成的点线,避免被清空-->
|
||||
<canvas
|
||||
id="canvasSave"
|
||||
ref="canvasSaveRef"
|
||||
:width="width + 'px'"
|
||||
:height="height + 'px'"
|
||||
class="canvas-save"
|
||||
></canvas>
|
||||
<div class="controls">
|
||||
<el-button @click="clearSelection" type="primary">清空选区</el-button>
|
||||
<slot name="controls"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'PolygonSelector',
|
||||
props: {
|
||||
width: {
|
||||
type: [Number, String],
|
||||
default: 1222
|
||||
},
|
||||
height: {
|
||||
type: [Number, String],
|
||||
default: 789
|
||||
},
|
||||
backgroundImg: {
|
||||
type: String,
|
||||
default: '/images/img.png'
|
||||
}
|
||||
},
|
||||
emits: ['selection-complete', 'points-change'],
|
||||
setup(props, { emit }) {
|
||||
const canvasRef = ref(null)
|
||||
const canvasSaveRef = ref(null)
|
||||
|
||||
let ctx = null
|
||||
let ctxSave = null
|
||||
let pointArr = [] // 存放坐标的数组
|
||||
let oIndex = -1 // 判断鼠标是否移动到起始点处,-1为否,1为是
|
||||
|
||||
onMounted(() => {
|
||||
initCanvas()
|
||||
})
|
||||
|
||||
const initCanvas = () => {
|
||||
const canvas = canvasRef.value
|
||||
const canvasSave = canvasSaveRef.value
|
||||
|
||||
if (!canvas || !canvasSave) return
|
||||
|
||||
ctx = canvas.getContext('2d')
|
||||
ctxSave = canvasSave.getContext('2d')
|
||||
|
||||
// 设置样式
|
||||
ctx.strokeStyle = 'rgba(102,168,255,1)' // 线条颜色
|
||||
ctx.lineWidth = 4 // 线条粗细
|
||||
ctxSave.strokeStyle = 'rgba(102,168,255,1)' // 线条颜色
|
||||
ctxSave.lineWidth = 4 // 线条粗细
|
||||
|
||||
// 绑定事件
|
||||
canvas.addEventListener('click', handleClick)
|
||||
canvas.addEventListener('mousemove', handleMouseMove)
|
||||
}
|
||||
|
||||
const handleClick = (e) => {
|
||||
const canvas = canvasRef.value
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
const pointX = e.clientX - rect.left
|
||||
const pointY = e.clientY - rect.top
|
||||
let piX, piY
|
||||
|
||||
if (oIndex > 0 && pointArr.length > 0) {
|
||||
piX = pointArr[0].x
|
||||
piY = pointArr[0].y
|
||||
// 画点
|
||||
makearc(ctx, piX, piY, getRandomNum(2, 2), 0, 180, 'rgba(102,168,255,0.5)')
|
||||
pointArr.push({x: piX, y: piY})
|
||||
canvasSave(pointArr) // 保存点线同步到另一个canvas
|
||||
saveCanvas() // 生成画布
|
||||
} else {
|
||||
piX = pointX
|
||||
piY = pointY
|
||||
makearc(ctx, piX, piY, getRandomNum(2, 2), 0, 180, 'rgba(102,168,255,0.5)')
|
||||
pointArr.push({x: piX, y: piY})
|
||||
canvasSave(pointArr) // 保存点线同步到另一个canvas
|
||||
}
|
||||
}
|
||||
|
||||
const handleMouseMove = (e) => {
|
||||
const canvas = canvasRef.value
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
const pointX = e.clientX - rect.left
|
||||
const pointY = e.clientY - rect.top
|
||||
let piX, piY
|
||||
|
||||
// 清空画布
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
// 鼠标下跟随的圆点
|
||||
makearc(ctx, pointX, pointY, getRandomNum(4, 4), 0, 180, 'rgba(102,168,255,1)')
|
||||
|
||||
if (pointArr.length > 0) {
|
||||
if ((pointX > pointArr[0].x-15 && pointX < pointArr[0].x+15) &&
|
||||
(pointY > pointArr[0].y-15 && pointY < pointArr[0].y+15)) {
|
||||
if (pointArr.length > 1) {
|
||||
piX = pointArr[0].x
|
||||
piY = pointArr[0].y
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
makearc(ctx, piX, piY, getRandomNum(4, 4), 0, 180, 'rgba(102,168,255,0.5)')
|
||||
oIndex = 1
|
||||
}
|
||||
} else {
|
||||
piX = pointX
|
||||
piY = pointY
|
||||
oIndex = -1
|
||||
}
|
||||
|
||||
// 开始绘制
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(pointArr[0].x, pointArr[0].y)
|
||||
if (pointArr.length > 1) {
|
||||
for (let i = 1; i < pointArr.length; i++) {
|
||||
ctx.lineTo(pointArr[i].x, pointArr[i].y)
|
||||
}
|
||||
}
|
||||
ctx.lineTo(piX, piY)
|
||||
ctx.fillStyle = 'rgba(161,195,255,0.5)' // 填充颜色
|
||||
ctx.fill() // 填充
|
||||
ctx.stroke() // 绘制
|
||||
}
|
||||
}
|
||||
|
||||
// 存储已生成的点线
|
||||
const canvasSave = (points) => {
|
||||
ctxSave.clearRect(0, 0, ctxSave.canvas.width, ctxSave.canvas.height)
|
||||
ctxSave.beginPath()
|
||||
if (points.length > 1) {
|
||||
ctxSave.moveTo(points[0].x, points[0].y)
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
ctxSave.lineTo(points[i].x, points[i].y)
|
||||
ctxSave.fillStyle = 'rgba(161,195,255,0.5)' // 填充颜色
|
||||
// ctxSave.fill()
|
||||
ctxSave.stroke() // 绘制
|
||||
}
|
||||
ctxSave.closePath()
|
||||
emit('points-change', [...points])
|
||||
}
|
||||
}
|
||||
|
||||
// 生成画布 结束绘画
|
||||
const saveCanvas = () => {
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
|
||||
ctxSave.closePath() // 结束路径状态,结束当前路径,如果是一个未封闭的图形,会自动将首尾相连封闭起来
|
||||
ctxSave.fill() // 填充
|
||||
ctxSave.stroke() // 绘制
|
||||
emit('selection-complete', [...pointArr])
|
||||
pointArr = []
|
||||
oIndex = -1
|
||||
}
|
||||
|
||||
// 清空选区
|
||||
const clearSelection = () => {
|
||||
const canvas = canvasRef.value
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctxSave.clearRect(0, 0, ctxSave.canvas.width, ctxSave.canvas.height)
|
||||
pointArr = []
|
||||
oIndex = -1
|
||||
emit('points-change', [])
|
||||
}
|
||||
|
||||
// canvas生成圆点
|
||||
const getRandomNum = (min, max) => {
|
||||
const range = max - min
|
||||
const rand = Math.random()
|
||||
return (min + Math.round(rand * range))
|
||||
}
|
||||
|
||||
const makearc = (ctx, x, y, r, s, e, color) => {
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height) // 清空画布
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = color
|
||||
ctx.arc(x, y, r, s, e)
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
return {
|
||||
canvasRef,
|
||||
canvasSaveRef,
|
||||
clearSelection
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.polygon-selector {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.canvas-save {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.controls {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
||||
260
src/components/content/tunnelScene/PolygonSelector.vue
Normal file
260
src/components/content/tunnelScene/PolygonSelector.vue
Normal file
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<div class="polygon-selector" :style="{ width: '100%', height: '100%' }">
|
||||
<!--用来和鼠标进行交互操作的canvas-->
|
||||
<canvas
|
||||
id="canvas"
|
||||
ref="canvasRef"
|
||||
:width="canvasWidth + 'px'"
|
||||
:height="canvasHeight + 'px'"
|
||||
:style="{ backgroundImage: 'url(' + backgroundImg + ')', cursor: 'crosshair' }"
|
||||
></canvas>
|
||||
<!--存储已生成的点线,避免被清空-->
|
||||
<canvas
|
||||
id="canvasSave"
|
||||
ref="canvasSaveRef"
|
||||
:width="canvasWidth + 'px'"
|
||||
:height="canvasHeight + 'px'"
|
||||
class="canvas-save"
|
||||
></canvas>
|
||||
<div class="controls">
|
||||
<el-button @click="clearSelection" type="primary">清空选区</el-button>
|
||||
<slot name="controls"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, onUpdated } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'PolygonSelector',
|
||||
props: {
|
||||
width: {
|
||||
type: [Number, String],
|
||||
default: 1222
|
||||
},
|
||||
height: {
|
||||
type: [Number, String],
|
||||
default: 789
|
||||
},
|
||||
backgroundImg: {
|
||||
type: String,
|
||||
default: '/images/img.png'
|
||||
}
|
||||
},
|
||||
emits: ['selection-complete', 'points-change'],
|
||||
setup(props, { emit }) {
|
||||
const canvasRef = ref(null)
|
||||
const canvasSaveRef = ref(null)
|
||||
|
||||
let ctx = null
|
||||
let ctxSave = null
|
||||
let pointArr = [] // 存放坐标的数组
|
||||
let oIndex = -1 // 判断鼠标是否移动到起始点处,-1为否,1为是
|
||||
|
||||
// 响应式canvas尺寸
|
||||
const canvasWidth = ref(1222)
|
||||
const canvasHeight = ref(789)
|
||||
|
||||
onMounted(() => {
|
||||
initCanvas()
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onUpdated(() => {
|
||||
// 当组件更新时重新初始化canvas
|
||||
if (canvasRef.value) {
|
||||
canvasRef.value.width = canvasWidth.value
|
||||
canvasRef.value.height = canvasHeight.value
|
||||
}
|
||||
})
|
||||
|
||||
const handleResize = () => {
|
||||
// 根据窗口尺寸调整canvas大小
|
||||
const container = canvasRef.value?.parentElement
|
||||
if (container) {
|
||||
canvasWidth.value = container.clientWidth
|
||||
canvasHeight.value = container.clientHeight
|
||||
}
|
||||
}
|
||||
|
||||
const initCanvas = () => {
|
||||
const canvas = canvasRef.value
|
||||
const canvasSave = canvasSaveRef.value
|
||||
|
||||
if (!canvas || !canvasSave) return
|
||||
|
||||
ctx = canvas.getContext('2d')
|
||||
ctxSave = canvasSave.getContext('2d')
|
||||
|
||||
// 设置样式
|
||||
ctx.strokeStyle = 'rgba(102,168,255,1)' // 线条颜色
|
||||
ctx.lineWidth = 4 // 线条粗细
|
||||
ctxSave.strokeStyle = 'rgba(102,168,255,1)' // 线条颜色
|
||||
ctxSave.lineWidth = 4 // 线条粗细
|
||||
|
||||
// 绑定事件
|
||||
canvas.addEventListener('click', handleClick)
|
||||
canvas.addEventListener('mousemove', handleMouseMove)
|
||||
}
|
||||
|
||||
const handleClick = (e) => {
|
||||
const canvas = canvasRef.value
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
const pointX = e.clientX - rect.left
|
||||
const pointY = e.clientY - rect.top
|
||||
let piX, piY
|
||||
|
||||
if (oIndex > 0 && pointArr.length > 0) {
|
||||
piX = pointArr[0].x
|
||||
piY = pointArr[0].y
|
||||
// 画点
|
||||
makearc(ctx, piX, piY, getRandomNum(2, 2), 0, 180, 'rgba(102,168,255,0.5)')
|
||||
pointArr.push({x: piX, y: piY})
|
||||
canvasSave(pointArr) // 保存点线同步到另一个canvas
|
||||
saveCanvas() // 生成画布
|
||||
} else {
|
||||
piX = pointX
|
||||
piY = pointY
|
||||
makearc(ctx, piX, piY, getRandomNum(2, 2), 0, 180, 'rgba(102,168,255,0.5)')
|
||||
pointArr.push({x: piX, y: piY})
|
||||
canvasSave(pointArr) // 保存点线同步到另一个canvas
|
||||
}
|
||||
}
|
||||
|
||||
const handleMouseMove = (e) => {
|
||||
const canvas = canvasRef.value
|
||||
const rect = canvas.getBoundingClientRect()
|
||||
const pointX = e.clientX - rect.left
|
||||
const pointY = e.clientY - rect.top
|
||||
let piX, piY
|
||||
|
||||
// 清空画布
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
// 鼠标下跟随的圆点
|
||||
makearc(ctx, pointX, pointY, getRandomNum(4, 4), 0, 180, 'rgba(102,168,255,1)')
|
||||
|
||||
if (pointArr.length > 0) {
|
||||
if ((pointX > pointArr[0].x-15 && pointX < pointArr[0].x+15) &&
|
||||
(pointY > pointArr[0].y-15 && pointY < pointArr[0].y+15)) {
|
||||
if (pointArr.length > 1) {
|
||||
piX = pointArr[0].x
|
||||
piY = pointArr[0].y
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
makearc(ctx, piX, piY, getRandomNum(4, 4), 0, 180, 'rgba(102,168,255,0.5)')
|
||||
oIndex = 1
|
||||
}
|
||||
} else {
|
||||
piX = pointX
|
||||
piY = pointY
|
||||
oIndex = -1
|
||||
}
|
||||
|
||||
// 开始绘制
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(pointArr[0].x, pointArr[0].y)
|
||||
if (pointArr.length > 1) {
|
||||
for (let i = 1; i < pointArr.length; i++) {
|
||||
ctx.lineTo(pointArr[i].x, pointArr[i].y)
|
||||
}
|
||||
}
|
||||
ctx.lineTo(piX, piY)
|
||||
ctx.fillStyle = 'rgba(161,195,255,0.5)' // 填充颜色
|
||||
ctx.fill() // 填充
|
||||
ctx.stroke() // 绘制
|
||||
}
|
||||
}
|
||||
|
||||
// 存储已生成的点线
|
||||
const canvasSave = (points) => {
|
||||
ctxSave.clearRect(0, 0, ctxSave.canvas.width, ctxSave.canvas.height)
|
||||
ctxSave.beginPath()
|
||||
if (points.length > 1) {
|
||||
ctxSave.moveTo(points[0].x, points[0].y)
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
ctxSave.lineTo(points[i].x, points[i].y)
|
||||
ctxSave.fillStyle = 'rgba(161,195,255,0.5)' // 填充颜色
|
||||
// ctxSave.fill()
|
||||
ctxSave.stroke() // 绘制
|
||||
}
|
||||
ctxSave.closePath()
|
||||
emit('points-change', [...points])
|
||||
}
|
||||
}
|
||||
|
||||
// 生成画布 结束绘画
|
||||
const saveCanvas = () => {
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
|
||||
ctxSave.closePath() // 结束路径状态,结束当前路径,如果是一个未封闭的图形,会自动将首尾相连封闭起来
|
||||
ctxSave.fill() // 填充
|
||||
ctxSave.stroke() // 绘制
|
||||
emit('selection-complete', [...pointArr])
|
||||
pointArr = []
|
||||
oIndex = -1
|
||||
}
|
||||
|
||||
// 清空选区
|
||||
const clearSelection = () => {
|
||||
const canvas = canvasRef.value
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctxSave.clearRect(0, 0, ctxSave.canvas.width, ctxSave.canvas.height)
|
||||
pointArr = []
|
||||
oIndex = -1
|
||||
emit('points-change', [])
|
||||
}
|
||||
|
||||
// canvas生成圆点
|
||||
const getRandomNum = (min, max) => {
|
||||
const range = max - min
|
||||
const rand = Math.random()
|
||||
return (min + Math.round(rand * range))
|
||||
}
|
||||
|
||||
const makearc = (ctx, x, y, r, s, e, color) => {
|
||||
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height) // 清空画布
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = color
|
||||
ctx.arc(x, y, r, s, e)
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
return {
|
||||
canvasRef,
|
||||
canvasSaveRef,
|
||||
clearSelection,
|
||||
canvasWidth,
|
||||
canvasHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.polygon-selector {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.canvas-save {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.controls {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
||||
@@ -23,6 +23,15 @@ const routes = [
|
||||
breadcrumb: true
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/polygon-demo',
|
||||
name: 'polygon-demo',
|
||||
component: () => import('@/views/tunnel/polygon-demo.vue'),
|
||||
meta: {
|
||||
title: '图片热区',
|
||||
breadcrumb: true
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/:tunnelId/:siteId',
|
||||
name: 'changeSitePreview',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div id="main">
|
||||
|
||||
<div class="img-box">
|
||||
<div class="img-box" id="imghot">
|
||||
<!-- @/assets/images/tunnel/img.png-->
|
||||
<!-- <img :src="'data:image/png;base64,'+siteImage" style="width:3500px;height:1789px" id="imgModel" usemap="#image"-->
|
||||
<!-- alt="" @click="clickHandler">-->
|
||||
|
||||
95
src/views/tunnel/polygon-demo.vue
Normal file
95
src/views/tunnel/polygon-demo.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div class="polygon-demo">
|
||||
<h2>多边形选择演示</h2>
|
||||
|
||||
<div class="img-box">
|
||||
<div style="display: flex;justify-content: center;align-items: center;">
|
||||
<PolygonSelector
|
||||
:width="1222"
|
||||
:height="789"
|
||||
background-img="/images/img.png"
|
||||
@selection-complete="handleSelectionComplete"
|
||||
@points-change="handlePointsChange"
|
||||
>
|
||||
<template #controls>
|
||||
<el-button @click="exportPoints" type="success">导出坐标</el-button>
|
||||
</template>
|
||||
</PolygonSelector>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="points-info" v-if="points.length > 0">
|
||||
<h3>当前选区坐标:</h3>
|
||||
<el-table :data="points" style="width: 100%">
|
||||
<el-table-column prop="x" label="X坐标" width="180"></el-table-column>
|
||||
<el-table-column prop="y" label="Y坐标" width="180"></el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue'
|
||||
import PolygonSelector from '@/components/content/tunnelScene/PolygonSelector.vue'
|
||||
|
||||
export default {
|
||||
name: 'PolygonDemo',
|
||||
components: {
|
||||
PolygonSelector
|
||||
},
|
||||
setup() {
|
||||
const points = ref([])
|
||||
|
||||
const handleSelectionComplete = (selectionPoints) => {
|
||||
console.log('选区完成:', selectionPoints)
|
||||
}
|
||||
|
||||
const handlePointsChange = (currentPoints) => {
|
||||
points.value = currentPoints
|
||||
}
|
||||
|
||||
const exportPoints = () => {
|
||||
if (points.value.length === 0) {
|
||||
ElMessage.warning('当前没有选区')
|
||||
return
|
||||
}
|
||||
|
||||
const dataStr = JSON.stringify(points.value, null, 2)
|
||||
const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr)
|
||||
|
||||
const exportFileDefaultName = 'polygon-points.json'
|
||||
|
||||
const linkElement = document.createElement('a')
|
||||
linkElement.setAttribute('href', dataUri)
|
||||
linkElement.setAttribute('download', exportFileDefaultName)
|
||||
linkElement.click()
|
||||
|
||||
ElMessage.success('坐标已导出')
|
||||
}
|
||||
|
||||
return {
|
||||
points,
|
||||
handleSelectionComplete,
|
||||
handlePointsChange,
|
||||
exportPoints
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.polygon-demo {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.img-box {
|
||||
position: relative;
|
||||
margin: 20px 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.points-info {
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
1193
src/views/tunnel/test.vue
Normal file
1193
src/views/tunnel/test.vue
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user