This commit is contained in:
2025-04-11 14:55:10 +08:00
parent 342ef26549
commit d4e0ff0fc2

View File

@@ -67,6 +67,7 @@
</div>
<!-- 中间编辑框 -->
<div class="center-box">
<div class="editor-container" @scroll="handleScroll">
<!-- 标尺部分 -->
<div class="ruler-horizontal" :style="horizontalRulerStyle">
@@ -93,6 +94,7 @@
<!-- 编辑画布 -->
<div
ref="editorCanvas"
class="editor-canvas"
:style="{
width: canvasWidth + 'px',
@@ -101,22 +103,23 @@
}"
@drop="onDrop"
@dragover.prevent
ref="editorCanvas"
>
<div
v-for="(component, index) in canvasComponents"
:key="index"
ref="targetDiv"
:style="getComponentStyle(component)"
class="canvas-component"
ref="targetDiv"
:class="{ 'highlight-border': isActive && currentIndex == index}"
@mousedown="startDrag(component, $event)"
@click="selectComponent(component, index)"
>
<!-- <div class="pbox" :style="{background: '#fc0 url('+ component.imageUrl +') no-repeat center;'}"> -->
<div class="pbox" :style="{backgroundImage: 'url(' + component.imageUrl + ')'}">
<!-- <div class="pbox" :style="{backgroundImage: 'url(' + component.imageUrl + ')'}">
<div style="line-height: 100%; font-size:12px; color: #000;">{{ component.name}}</div>
</div>
</div> -->
{{ component.name }}
<!-- <div style="width: 100%; height: 100%; font-size: 14px; line-height: 100%;">{{ component.name }}</div> -->
<!-- <img
v-if="component.imageUrl"
:src="component.imageUrl"
@@ -127,6 +130,17 @@
</div>
</div>
</div>
<div class="sbox">
<!-- <div class="sbox-t">点位状态配置</div> -->
<h3>点位状态配置</h3>
<div class="s-container">
<div v-for="(e, i) in statusList" :key="i" class="sbox-l">
<span class="s-txt">{{ e.name }}</span>
<span class="s-btn"><el-button type="primary" @click="toDialog(e)">编辑</el-button></span>
</div>
</div>
</div>
</div>
<!-- 右侧属性编辑面板 -->
<div class="right-panel">
@@ -167,24 +181,56 @@
>
<el-button type="primary">点击上传</el-button>
</el-upload> -->
<label></label>
<label />
</div>
<div v-else>
请选择一个点位
</div>
</div>
<!-- 图标配置 -->
<el-dialog
title="图标"
:visible.sync="dialogVisible"
width="50%"
>
<!-- <span>这是一段信息</span> -->
<div class="icon-container">
<div v-for="(e, i) in iconList" :key="i" class="iconbox" :class="{ 'highlight-border': e.id === pkId}" @click="toSelectIcon(e)">
<img :src="e.iconUrl">
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="toSureBind()"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import draggable from 'vuedraggable';
import draggable from 'vuedraggable'
export default {
components: {
draggable,
draggable
},
data() {
return {
pkId: '',
pkIconObj: '',
selStatusObj: '',
statusList: [
{ id: 1, code: 'c001', name: '状态1' },
{ id: 2, code: 'c002', name: '状态2' },
{ id: 3, code: 'c003', name: '状态3' },
{ id: 4, code: 'c004', name: '状态4' }
],
iconList: [
{ id: 1, iconUrl: 'https://img2.baidu.com/it/u=2914671817,628443499&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=889' },
{ id: 2, iconUrl: 'https://img0.baidu.com/it/u=3613398591,98570664&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500' },
{ id: 3, iconUrl: 'https://img0.baidu.com/it/u=1796365119,3995265789&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=667' }
],
dialogVisible: false,
// 新增分辨率设置
canvasWidth: 1920,
canvasHeight: 1080,
@@ -199,7 +245,7 @@ export default {
components: [ // 左侧可拖拽点位
{ id: 1, name: '点位1', type: 'component1' },
{ id: 2, name: '点位2', type: 'component2' },
{ id: 3, name: '点位3', type: 'component3' },
{ id: 3, name: '点位3', type: 'component3' }
],
pointSetOptions: [
{ id: 1, name: '点位1', code: '029-01', pointImg: 'https://img2.baidu.com/it/u=2914671817,628443499&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=889' },
@@ -225,52 +271,24 @@ export default {
scrollLeft: 0,
scrollTop: 0,
currentIndex: '',
currentObject: {},
};
},
watch: {
// 监听分辨率变化
canvasWidth(newVal) {
this.updateRulerTicks();
this.adjustComponentsPosition();
},
canvasHeight(newVal) {
this.updateRulerTicks();
this.adjustComponentsPosition();
currentObject: {}
}
},
mounted() {
// 添加全局点击监听
document.addEventListener('click', this.handleDocumentClick);
this.updateRulerTicks();
// const box = document.querySelector('.ruler-horizontal')
// const vox = document.querySelector('.ruler-vertical')
// window.addEventListener('scroll', () => {
// const scrollX = window.scrollX; // 获取水平滚动值
// box.style.left = `${30 + scrollX}px`; // 更新left值
// const scrollY = window.scrollY; // 获取垂直滚动值
// vox.style.top = `${20 + scrollY}px`; // 更新top值
// })
},
beforeDestroy() {
// 移除监听,防止内存泄漏
document.removeEventListener('click', this.handleDocumentClick);
},
computed: {
// 顶部标尺样式
horizontalRulerStyle() {
return {
top: this.scrollTop + 'px',
width: this.canvasWidth + 'px',
width: this.canvasWidth + 'px'
}
},
// 左侧标尺样式
verticalRulerStyle() {
return {
left: this.scrollLeft + 'px',
height: this.canvasHeight + 'px',
height: this.canvasHeight + 'px'
}
}
},
// // 左侧标尺样式
// verticalRulerStyle() {
// return {
@@ -287,26 +305,78 @@ export default {
// }
// }
},
watch: {
// 监听分辨率变化
canvasWidth(newVal) {
this.updateRulerTicks()
this.adjustComponentsPosition()
},
canvasHeight(newVal) {
this.updateRulerTicks()
this.adjustComponentsPosition()
}
},
mounted() {
// 添加全局点击监听
document.addEventListener('click', this.handleDocumentClick)
this.updateRulerTicks()
// const box = document.querySelector('.ruler-horizontal')
// const vox = document.querySelector('.ruler-vertical')
// window.addEventListener('scroll', () => {
// const scrollX = window.scrollX; // 获取水平滚动值
// box.style.left = `${30 + scrollX}px`; // 更新left值
// const scrollY = window.scrollY; // 获取垂直滚动值
// vox.style.top = `${20 + scrollY}px`; // 更新top值
// })
},
beforeDestroy() {
// 移除监听,防止内存泄漏
document.removeEventListener('click', this.handleDocumentClick)
},
methods: {
toSureBind() {
this.statusList.map(item => {
if (item === this.selStatusObj) {
item.bindIcon = this.pkIconObj.iconUrl
}
})
console.log(this.statusList, '2222222')
this.dialogVisible = false
},
toDialog(e) {
this.pkId = ''
this.iconList.map(item => {
if (item.iconUrl === e.bindIcon) {
this.pkId = item.id
}
})
// this.pkId = this.pkId === e.id ? '' : e.id
this.dialogVisible = !this.dialogVisible
this.selStatusObj = e
},
toSelectIcon(e) {
this.pkId = this.pkId === e.id ? '' : e.id
this.pkIconObj = e
},
handleDocumentClick(event) {
// 判断点击是否发生在目标 div 外部
if (this.$refs.targetDiv && !this.$refs.targetDiv[this.currentIndex].contains(event.target)) {
this.isActive = false;
this.isActive = false
}
},
handleFileChange(file) {
// 验证文件类型
if (!file.raw.type.startsWith('image/')) {
this.$message.error('只能上传图片文件!');
return;
this.$message.error('只能上传图片文件!')
return
}
// 读取文件生成预览
const reader = new FileReader();
const reader = new FileReader()
reader.onload = (e) => {
this.bgUrl = e.target.result;
};
reader.readAsDataURL(file.raw);
this.bgUrl = e.target.result
}
reader.readAsDataURL(file.raw)
console.log(this.bgUrl, 'bgimg')
// 切换背景图片,重置
// this.canvasComponents = [];
@@ -314,10 +384,10 @@ export default {
},
// 分辨率变更处理
handleResolutionChange() {
if (this.canvasWidth < 100) this.canvasWidth = 100;
if (this.canvasHeight < 100) this.canvasHeight = 100;
this.updateRulerTicks();
this.adjustComponentsPosition();
if (this.canvasWidth < 100) this.canvasWidth = 100
if (this.canvasHeight < 100) this.canvasHeight = 100
this.updateRulerTicks()
this.adjustComponentsPosition()
},
// 更新标尺刻度
@@ -325,48 +395,48 @@ export default {
this.horizontalRulerTicks = Array.from(
{ length: Math.ceil(this.canvasWidth / this.rulerUnit) },
(_, i) => i
);
)
this.verticalRulerTicks = Array.from(
{ length: Math.ceil(this.canvasHeight / this.rulerUnit) },
(_, i) => i
);
)
},
// 调整组件位置
adjustComponentsPosition() {
this.canvasComponents.forEach(component => {
// 限制X坐标
const maxX = this.canvasWidth - component.width;
const maxX = this.canvasWidth - component.width
if (component.x > maxX) {
component.x = Math.max(0, maxX);
component.x = Math.max(0, maxX)
}
// 限制Y坐标
const maxY = this.canvasHeight - component.height;
const maxY = this.canvasHeight - component.height
if (component.y > maxY) {
component.y = Math.max(0, maxY);
component.y = Math.max(0, maxY)
}
});
})
},
// 新增厂区变更处理方法
handleFactoryChange(factoryId) {
console.log(`切换到厂区: ${factoryId}`);
console.log(`切换到厂区: ${factoryId}`)
console.log('selectedFactory', this.selectedFactory)
this.factoryOptions.map(el => {
if (el.id == factoryId) {
this.selFacName = el.name;
if (el.id === factoryId) {
this.selFacName = el.name
}
})
// 这里可以添加加载厂区配置的逻辑
// 例如:清空当前画布或加载对应厂区配置
this.canvasComponents = [];
this.selectedComponent = null;
this.canvasComponents = []
this.selectedComponent = null
},
handlePointImgChange(PointSetId) {
// console.log(`切换到点位图片: ${PointSetId}`);
this.pointSetOptions.map(el => {
if (el.id == PointSetId) {
this.selectedComponent.imageUrl = el.pointImg;
if (el.id === PointSetId) {
this.selectedComponent.imageUrl = el.pointImg
}
})
},
@@ -377,8 +447,8 @@ export default {
},
onDragStart(event) {
// console.log('eeee', event)
event.item.dataset.type = this.components[event.oldIndex].type;
event.item.dataset.id = this.components[event.oldIndex].id; // 新加
event.item.dataset.type = this.components[event.oldIndex].type
event.item.dataset.id = this.components[event.oldIndex].id // 新加
this.currentObject = this.components[event.oldIndex]
if (this.canvasComponents.some(item => {
return item.id === this.currentObject.id
@@ -393,8 +463,8 @@ export default {
// console.log('11222', event.dataTransfer.getData('id'))
// console.log('22333', event.dataTransfer.getData('type'))
// const type = event.dataTransfer.getData('type');
const type = this.currentObject.type;
const id = this.currentObject.id;
const type = this.currentObject.type
const id = this.currentObject.id
const newComponent = {
id,
type,
@@ -403,14 +473,14 @@ export default {
y: event.offsetY - this.dragOffset.y,
width: 100,
height: 50,
imageUrl: '',
};
imageUrl: ''
}
if (this.canvasComponents.some(item => {
return item.id === this.currentObject.id
})) {
console.log('已存在')
} else {
this.canvasComponents.push(newComponent);
this.canvasComponents.push(newComponent)
}
},
getComponentStyle(component) {
@@ -421,68 +491,68 @@ export default {
width: `${component.width}px`,
height: `${component.height}px`,
border: '1px solid #ccc',
cursor: this.isDragging ? 'grabbing' : 'move',
};
cursor: this.isDragging ? 'grabbing' : 'move'
}
},
// 开始拖拽
startDrag(component, event) {
this.selectedComponent = component;
this.isDragging = true;
this.selectedComponent = component
this.isDragging = true
// 计算鼠标在组件内部的偏移量
const rect = event.target.getBoundingClientRect();
const rect = event.target.getBoundingClientRect()
this.dragOffset = {
x: event.clientX - rect.left,
y: event.clientY - rect.top,
};
y: event.clientY - rect.top
}
// 绑定全局事件
document.addEventListener('mousemove', this.onDrag);
document.addEventListener('mouseup', this.stopDrag);
document.addEventListener('mousemove', this.onDrag)
document.addEventListener('mouseup', this.stopDrag)
},
// 拖拽中
onDrag(event) {
if (!this.isDragging || !this.selectedComponent) return;
if (!this.isDragging || !this.selectedComponent) return
// 计算组件的新位置(相对于画布)
const canvasRect = this.$refs.editorCanvas.getBoundingClientRect();
const newX = event.clientX - canvasRect.left - this.dragOffset.x;
const newY = event.clientY - canvasRect.top - this.dragOffset.y;
const canvasRect = this.$refs.editorCanvas.getBoundingClientRect()
const newX = event.clientX - canvasRect.left - this.dragOffset.x
const newY = event.clientY - canvasRect.top - this.dragOffset.y
// 更新组件位置
this.selectedComponent.x = Math.max(0, newX);
this.selectedComponent.y = Math.max(0, newY);
this.selectedComponent.x = Math.max(0, newX)
this.selectedComponent.y = Math.max(0, newY)
},
// 停止拖拽
stopDrag() {
this.isDragging = false;
document.removeEventListener('mousemove', this.onDrag);
document.removeEventListener('mouseup', this.stopDrag);
this.isDragging = false
document.removeEventListener('mousemove', this.onDrag)
document.removeEventListener('mouseup', this.stopDrag)
},
selectComponent(component, index) {
this.selectedComponent = component;
this.isActive = true;
this.selectedPointImg = '';
this.currentIndex = index;
this.selectedComponent = component
this.isActive = true
this.selectedPointImg = ''
this.currentIndex = index
},
handleUploadSuccess(response, file) {
if (this.selectedComponent) {
this.selectedComponent.imageUrl = URL.createObjectURL(file.raw);
this.selectedComponent.imageUrl = URL.createObjectURL(file.raw)
}
},
beforeUpload(file) {
const isImage = file.type.startsWith('image/');
const isImage = file.type.startsWith('image/')
if (!isImage) {
this.$message.error('只能上传图片文件!');
this.$message.error('只能上传图片文件!')
}
return isImage;
return isImage
},
handleScroll(e) {
this.scrollLeft = e.target.scrollLeft;
this.scrollTop = e.target.scrollTop;
},
},
};
this.scrollLeft = e.target.scrollLeft
this.scrollTop = e.target.scrollTop
}
}
}
</script>
<style scoped>
@@ -514,7 +584,6 @@ export default {
color: #666;
}
/* 新增厂区选择器样式 */
.factory-selector {
margin-bottom: 20px;
@@ -549,14 +618,46 @@ export default {
border: 1px solid #c0c4cc;
cursor: move;
}
.editor-container {
.center-box {
flex: 1;
position: relative;
overflow: auto;
}
.sbox {
margin: 0 20px;
}
.s-container {
display: flex;
/* justify-content: space-between; */
}
.sbox-t {
font-size: 20px;
}
.sbox-l {
display: flex;
justify-content: space-between;
border: 1px solid #ccc;
width: 150px;
height: 40px;
padding: 5px 4px;
margin: 2px 6px;
}
.s-txt {
display: inline-block;
font-size: 14px;
line-height: 26px;
margin-right: 5px;
}
.s-btn {
display: inline-block;
}
.editor-container {
/* flex: 1; */
position: relative;
margin: 0 20px;
/* min-height: 600px;
max-height: 1080px; */
height: 650px;
height: 600px;
overflow: auto;
}
@@ -629,7 +730,7 @@ export default {
text-align: center;
/* box-sizing: border-box;
border: 1px solid #0073e1 !important; */
/* line-height: 50px; */
line-height: 50px;
box-sizing: border-box;
/* border: 2px dashed rgb(77 187 249); */
}
@@ -668,12 +769,30 @@ input {
width: 100%;
height: 100%;
text-align: center;
line-height: 100%;
background-size: 100% 100%;
}
.highlight-border {
/* border: 3px solid #2196f3; */
/* box-shadow: 0 0 8px rgba(33, 150, 243, 0.5); */
border: 3px solid #ff0;
box-shadow: 0 0 20px rgb(255, 255, 0);
box-shadow: 0 0 5px rgb(255, 255, 0);
}
.icon-container{
display: flex;
width: 100%;
justify-content: flex-start;
}
.iconbox {
display: inline-block;
box-sizing: border-box;
width: 60px;
height: 40px;
margin: 5px;
/* border: 1px solid #ccc; */
}
.iconbox img{
width: 100%;
height: 100%;
}
</style>