最近做的一个项目,需要拖动配置,网上找了一圈 没找到合适的轮子,没办法自己写吧,代码中有能优化的地方,没时间优化了(其实就是懒得),希望能帮到需要的人。

效果图如下:

  1. 可以充设备组件拖动到右侧容器中,设备组件栏中对应删除拖出去的数据,右侧容器则添加对应数据,反之亦然(从右侧拖动设备组件放回左侧设备组件栏时也是删除右侧拖出数据,设备栏添加相关数据)
  2. 环境组件栏:拖动组件到右侧容器,组件栏数据保持原样,右侧容器添加对应拖动数据。从右侧容器拖动环境组件放回组件栏,容器删除对应数据,环境组件栏保持原样
  3. 右侧容器中的任何组件都可以随意拖动位置

数据结构

"data": {"orgOuterId": "13","orgName": "星座设备健康管理有限公司","bigScreenTitle": "工业设备监测云平台","workshop": [{"workshopId": "1000047","name": "上海一区","position": "东方一角","manager": "张阳阳","bgPic": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/199e4f0fcd76710c487f8e8e5c5a11b4.jpg","envLayout": [{"envComponentId": "3","name": "墙类","iconId": "10005","iconSubId": "10006","subIcons": [{"iconId": "10005","name": "墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "0"},{"iconId": "10006","name": "左墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771432169_m8kxa0lwu2.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"},{"iconId": "10007","name": "右墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771442722_j7g6ko6xg3.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"}],"icon": {"iconId": "10006","name": "左墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771432169_m8kxa0lwu2.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"},"randomId": "162978737079900","type": "env","position": {"l": 161,"left": 0,"z": 54,"t": 121}},{"envComponentId": "4","name": "测试2","iconId": "10022","iconSubId": "10022","subIcons": [{"iconId": "10022","name": "父图","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686574303_uq3ehbd2q.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "0"},{"iconId": "10024","name": "子","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686634420_6eqq6rpitk.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "10022"}],"icon": {"iconId": "10022","name": "父图","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686574303_uq3ehbd2q.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "0"},"randomId": "162978737079901","type": "env","position": {"l": 380,"left": 0,"z": 54,"t": 233}},{"envComponentId": "4","name": "测试2","iconId": "10022","iconSubId": "10024","subIcons": [{"iconId": "10022","name": "父图","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686574303_uq3ehbd2q.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "0"},{"iconId": "10024","name": "子","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686634420_6eqq6rpitk.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "10022"}],"icon": {"iconId": "10024","name": "子","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686634420_6eqq6rpitk.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "10022"},"randomId": "162978737079902","type": "env","position": {"l": 548,"left": 0,"z": 54,"t": 93}},{"envComponentId": "4","name": "测试2","iconId": "10022","iconSubId": "10022","subIcons": [{"iconId": "10022","name": "父图","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686574303_uq3ehbd2q.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "0"},{"iconId": "10024","name": "子","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686634420_6eqq6rpitk.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "10022"}],"icon": {"iconId": "10022","name": "父图","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686574303_uq3ehbd2q.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "0"},"randomId": "162978737079903","type": "env","position": {"l": 70,"left": 0,"z": 55,"t": 237}}],"devices": [{"deviceUUID": "581248563706978304","deviceName": "四轴机器人","workshopId": "1000047","position": {"iconSubId": "10","l": 347,"t": 135,"z": 54},"iconId": "10","iconSubId": "10","icon": {"iconId": "10","name": "机床","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629252429605_g7650z9j6o.png","width": "135","height": "131","type": "2","extra": {"x": 0,"y": 0},"pid": "0"}}]},{"workshopId": "1000121","name": "海淀","position": "万柳","manager": "李丰台","bgPic": "","envLayout": [],"devices": []},{"workshopId": "1000135","name": "上海2区","position": "东方2角","manager": "张2阳","bgPic": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/199e4f0fcd76710c487f8e8e5c5a11b4.jpg","envLayout": [{"envComponentId": 3,"iconId": 10005,"iconSubId": "10007","position": {"w": 0,"t": 17,"z": 32,"l": 499},"icon": {"iconId": "10007","name": "右墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771442722_j7g6ko6xg3.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"},"subIcons": [{"iconId": "10005","name": "墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "0"},{"iconId": "10006","name": "左墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771432169_m8kxa0lwu2.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"},{"iconId": "10007","name": "右墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771442722_j7g6ko6xg3.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"}],"randomId": 1629775200460,"type": "env"},{"envComponentId": 3,"iconId": 10005,"iconSubId": "10007","position": {"w": 0,"t": 22,"z": 33,"l": 257},"icon": {"iconId": "10007","name": "右墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771442722_j7g6ko6xg3.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"},"subIcons": [{"iconId": "10005","name": "墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "0"},{"iconId": "10006","name": "左墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771432169_m8kxa0lwu2.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"},{"iconId": "10007","name": "右墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771442722_j7g6ko6xg3.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"}],"randomId": 1629775200461,"type": "env"}],"devices": [{"deviceUUID": "577988705557798912","deviceName": "六轴机器人","workshopId": "1000135","position": {"iconSubId": "10","l": 86.10189573459715,"t": 74.08767772511848,"z": 25},"iconId": "10","iconSubId": "10","icon": {"iconId": "10","name": "机床","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629252429605_g7650z9j6o.png","width": "135","height": "131","type": "2","extra": {"x": 0,"y": 0},"pid": "0"}}]},{"workshopId": "1000136","name": "阿萨的","position": "啊","manager": "啊","bgPic": "","envLayout": [{"envComponentId": "4","name": "测试2","iconId": "10022","iconSubId": "10022","subIcons": [{"iconId": "10022","name": "父图","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686574303_uq3ehbd2q.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "0"},{"iconId": "10024","name": "子","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686634420_6eqq6rpitk.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "10022"}],"icon": {"iconId": "10022","name": "父图","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686574303_uq3ehbd2q.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "0"},"randomId": "162977737390130","type": "env","position": {"l": 149,"left": 0,"z": 55,"t": 141}},{"envComponentId": "3","name": "墙类","iconId": "10005","iconSubId": "10005","subIcons": [{"iconId": "10005","name": "墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "0"},{"iconId": "10006","name": "左墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771432169_m8kxa0lwu2.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"},{"iconId": "10007","name": "右墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771442722_j7g6ko6xg3.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"}],"icon": {"iconId": "10005","name": "墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "0"},"randomId": 1629777377747,"type": "env","position": {"l": 393,"left": 0,"z": 54,"t": 264}}],"devices": []}],"otherDevices": [],"envComponents": [{"envComponentId": "3","name": "墙类","iconId": "10005","iconSubId": "10005"},{"envComponentId": "4","name": "测试2","iconId": "10022","iconSubId": "10022"},{"envComponentId": "5","name": "轨道","iconId": "11","iconSubId": "11"}],"iconsGroup": {"10": {"10": {"iconId": "10","name": "机床","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629252429605_g7650z9j6o.png","width": "135","height": "131","type": "2","extra": {"x": 0,"y": 0},"pid": "0"}},"11": {"11": {"iconId": "11","name": "传感器","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629252414513_fe4coz4kf.png","width": "135","height": "131","type": "2","extra": {"x": 0,"y": 0},"pid": "0"}},"10000": {"10000": {"iconId": "10000","name": "设备默认图标","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "0"},"10001": {"iconId": "10001","name": "左设备默认图标","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "10000"},"10002": {"iconId": "10002","name": "右设备默认图标","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "10000"}},"10005": {"10005": {"iconId": "10005","name": "墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1628841770502_3fz6umsn53.png","width": "252","height": "188","type": "2","extra": {"x": 0,"y": 0},"pid": "0"},"10006": {"iconId": "10006","name": "左墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771432169_m8kxa0lwu2.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"},"10007": {"iconId": "10007","name": "右墙","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629771442722_j7g6ko6xg3.png","width": "126","height": "94","type": "2","extra": {"x": 0,"y": 0},"pid": "10005"}},"10022": {"10022": {"iconId": "10022","name": "父图","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686574303_uq3ehbd2q.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "0"},"10024": {"iconId": "10024","name": "子","img": "https://tsd-test.oss-cn-shenzhen.aliyuncs.com/iot/device-model/1629686634420_6eqq6rpitk.png","width": "126","height": "94","type": "1","extra": {"x": 0,"y": 0},"pid": "10022"}}}
},
"code": 200,
"message": "OK",
"requestId": "b0fe622fa9ac21f7e3339ef2ef77a56e",
"takeTime": "47.622 ms",
"serverTime": "2021-08-24 14:46:35"

页面代码

<template><div class="my-container"><div class="top"><div><span class="icon-back" @click="goBack"><i class="el-icon-arrow-left back" /></span><span class="name">{{ orgName }}</span></div><div><el-button size="small" @click="look">预览</el-button><el-button type="primary" size="small" :loading="loading" @click="publush">{{ loading ? '发布中...' : '发布' }}</el-button></div></div><div class="content"><div><div class="right"><div class="title">设备组件(共{{ otherDevices.length }}台)</div><div v-loading="loading" class="cont" @drop="dropCur($event)" @dragover="allowDropCur($event)" @dragleave="ondragleave"><div v-for="item in otherDevices" :id="item.deviceUUID" :key="item.deviceUUID" class="item" draggable="true" @dragstart="drag($event, item.deviceUUID, item, true)"><img class="img" :src="item.icon.img"><span>{{ item.deviceName }}</span></div></div></div><div class="env-cont"><div class="title">环境组件</div><div v-loading="loading" class="cont" @drop="dropEnv($event)" @dragover="allowDropEnv($event)" @dragleave="ondragleave"><div v-for="(item, index) in envComponents" :id="item.randomId + index" :key="item.randomId" class="item" draggable="true" @dragstart="dragEnvOrigin($event, item.randomId + index, item, true)"><img class="img" :src="item.icon.img"><span>{{ item.icon.name }}</span></div></div></div></div><div class="drag-cont"><div class="screen-cont"><span>大屏标题:</span><el-input v-model="bigScreenTitle" maxlength="9" style="width: 180px" /><el-button :loading="inputLoading" type="primary" size="small" style="margin-left: 10px" @click="changeName">保存</el-button></div><el-tabs id="tabs" v-model="activeName" type="border-card" addable @tab-add="add"><template v-for="(item, index) in workshop"><el-tab-pane v-if="item.action !== 'delete'" :key="index" :name="index.toString()"><span slot="label">{{ item.name }}<span class="tab-action-cont" @click="editCj(item.name, item.isNew || false, index)"><i class="el-icon-edit" /></span></span><div :ref="activeName" v-loading="loading" class="bg-cont" :style="{ height: divHeight + 'px' }" @drop="drop($event)" @dragover="allowDrop($event)" @dragleave="ondragleave"><divv-for="(child, idx) in item.devices":id="child.deviceUUID":key="child.deviceUUID"draggable="true"class="right-img-cont":style="{width: child.icon.width / child.icon.type + 'px',height: child.icon.height / child.icon.type + 'px',left: child.position.l + 'px',top: child.position.t + 'px','z-index': child.position.z,background: `url('${child.icon.img}') 100% 100%`}"@dragstart="drag($event, child.deviceUUID, child, false, idx)"><!-- <img:src="child.icon.img"class="imgcur"> --><div v-if="child.subIcons && child.subIcons.length > 1" class="refresh-cont"><i class="el-icon-refresh" @click="changeImg(child, child.iconSubId, idx)" /></div></div><divv-for="(child, idx) in item.envLayout":id="child.randomId":key="child.randomId"draggable="true"class="right-img-cont":style="{width: child.icon.width / child.icon.type + 'px',height: child.icon.height / child.icon.type + 'px',left: child.position.l + 'px',top: child.position.t + 'px','z-index': child.position.z,background: `url('${child.icon.img}') 100% 100%`}"@dragstart="dragEnv($event, child.randomId, child, false, idx)"><div v-if="child.subIcons && child.subIcons.length > 1" class="refresh-cont"><i class="el-icon-refresh" @click="changeEnvImg(child, child.iconSubId, idx)" /></div></div></div></el-tab-pane></template></el-tabs></div></div><!-- 效果预览 --><el-dialogtitle="查看效果图"width="845px"custom-class="pt-preview":visible.sync="dialogVisible"><div v-loading="dialogLoading" class="preview"><el-tabs type="border-card"><template v-for="(item, index) in previewWorkshop"><el-tab-pane v-if="item.action !== 'delete'" :key="index" :name="index.toString()"><span slot="label">{{ item.name }}</span><div class="bg-cont" :style="{ height: divHeight + 'px' }"><imgv-for="child in item.devices":key="child.deviceUUID":src="child.icon.img"class="imgcur"draggable="true":style="{width: child.icon.width / child.icon.type + 'px',height: child.icon.height / child.icon.type + 'px',left: child.position.l + 'px',top: child.position.t + 'px','z-index': child.position.z}"><imgv-for="child in item.envLayout":key="child.randomId":src="child.icon.img"class="imgcur"draggable="true":style="{width: child.icon.width / child.icon.type + 'px',height: child.icon.height / child.icon.type + 'px',left: child.position.l + 'px',top: child.position.t + 'px','z-index': child.position.z}"></div></el-tab-pane></template></el-tabs></div></el-dialog><!-- 编辑/新建 车间 --><el-dialog:title="isAdd ? '新建车间' : '编辑车间'":visible.sync="addEditVisible"width="420px"@close="infoClose"><el-formref="infoForm"label-position="left":model="infoForm"label-width="110px":rules="infoRules"class="add-cont"><el-form-item label="所属公司:"><span>{{ orgName }}</span></el-form-item><el-form-item label="车间名称:" prop="name"><el-inputv-model.trim="infoForm.name"placeholder="请输入车间名称"style="width: 100%;"/></el-form-item><el-form-item label="车间位置:" prop="position"><el-inputv-model.trim="infoForm.position"placeholder="请输入车间位置"style="width: 100%;"/></el-form-item><el-form-item label="负责人:" prop="manager"><el-inputv-model.trim="infoForm.manager"placeholder="请输入负责人"style="width: 100%;"/></el-form-item></el-form><span slot="footer" class="dialog-footer"><el-button v-if="!isAdd && canDelete" type="danger" plain @click="delCj">删除车间</el-button><el-button type="primary" :loading="btnLoading" @click="addSubmit">{{ btnLoading ? '保存中' : '保 存' }}</el-button></span></el-dialog></div>
</template><script>
import { workshopLayout, workshopInfo, orgEdit } from '@/api/iot'
export default {name: 'Peitu',data() {return {halfWidth: '',halfHeight: '',basicWidth: 845,basicHeight: 468,basicPerW: '',basicPerH: '',percent: 845 / 468,orgName: '',orgOuterId: '',zIndex: 0,tagIndex: '',first: true,activeName: '0',isEnv: false,inputLoading: false,dialogVisible: false,dialogLoading: false,loading: false,bigScreenTitle: '工业设备监测云平台',// 新建、编辑canDelete: false,infoForm: {name: '',position: '',manager: ''},infoRules: {name: [{ required: true, message: '请输入车间名称', trigger: 'blur' }],},workshopIndex: 0,addEditVisible: false,btnLoading: false,isAdd: true,timeOut: '',moveX: '',moveY: '',offsetLeft: '',offsetTop: '',imgUrl: '',dragId: '',tempObj: {},// 边界处理tagWidth: '',tagHeight: '',divWidth: '',divHeight: '',workshop: [{workshopId: 'new_0',name: '车间1',action: 'create',devices: []}],otherDevices: [],// 预览效果图previewWorkshop: [],// 环境组件envComponents: [],iconsGroup: {},addEnv: true,}},watch: {workshop: {handler(val, oldVal) {let num = 0this.workshop.forEach(item => {if (item.action !== 'delete') {num++}})this.canDelete = num > 1},// immediate: true,deep: true}},created() {this.orgOuterId = this.$route.query.idthis.getList()},mounted() {// 处理边界const elm = document.getElementById('tabs')this.divWidth = elm.clientWidththis.divHeight = this.divWidth / this.percentthis.basicPerW = this.divWidth / this.basicWidththis.basicPerH = this.divHeight / this.basicHeight// 重新计算window.onresize = () => {this.workshop.forEach(item => {item.devices.forEach(child => {child.position.l = child.position.l / this.basicPerWchild.position.t = child.position.t / this.basicPerH})})this.$nextTick(() => {this.divWidth = elm.clientWidththis.divHeight = this.divWidth / this.percentthis.basicPerW = this.divWidth / this.basicWidththis.basicPerH = this.divHeight / this.basicHeightthis.workshop.forEach(item => {item.devices.forEach(child => {child.position.l = child.position.l * this.basicPerWchild.position.t = child.position.t * this.basicPerH})})})}},methods: {changeImg(item, iconSubId, index) {this.workshop[this.activeName].action = 'update'const num = item.subIcons.lengthlet idx = 0item.subIcons.map((c, i) => {if (c.iconId * 1 === iconSubId * 1) {idx = i + 1}})if (idx === num) {idx = 0}this.workshop[this.activeName].devices[index].icon = item.subIcons[idx]this.workshop[this.activeName].devices[index].iconSubId = item.subIcons[idx].iconId},changeEnvImg(item, iconSubId, index) {this.workshop[this.activeName].action = 'update'const num = item.subIcons.lengthlet idx = 0item.subIcons.map((c, i) => {this.isRefresh = trueif (c.iconId * 1 === iconSubId * 1) {idx = i + 1}})if (idx === num) {idx = 0}this.workshop[this.activeName].envLayout[index].icon = item.subIcons[idx]this.workshop[this.activeName].envLayout[index].iconSubId = item.subIcons[idx].iconId},changeName() {this.inputLoading = trueorgEdit({outerId: this.orgOuterId,bigScreenTitle: this.bigScreenTitle}).then(res => {this.$message({type: 'success',message: '修改成功'})}).finally(_ => {this.inputLoading = false})},goBack() {this.$router.back()},publush() {// const hasEmpty = this.workshop.some(item => {//   if (item.action !== 'delete') {//     return item.devices.length === 0//   }// })// if (hasEmpty) {//   this.$message({//     message: '车间不能为空,请为车间配置设备',//     type: 'warning'//   })//   return false// }const tempArry = JSON.parse(JSON.stringify(this.workshop))tempArry.forEach(item => {item.devices.forEach(child => {child.position.l = child.position.l / this.basicPerWchild.position.t = child.position.t / this.basicPerH})item.envLayout.forEach(child => {child.position.l = child.position.l / this.basicPerWchild.position.t = child.position.t / this.basicPerH})})const obj = {orgOuterId: this.orgOuterId,orgName: this.orgName,workshop: tempArry,otherDevices: this.otherDevices,}this.loading = trueworkshopLayout({...obj}).then(res => {this.$message({message: '发布成功',type: 'success'})this.getList()}).finally(_ => {this.loading = false})},getList() {this.loading = trueworkshopInfo({orgOuterId: this.orgOuterId}).then(res => {this.bigScreenTitle = res.data.bigScreenTitlethis.orgName = res.data.orgNamethis.workshop = res.data.workshopthis.otherDevices = res.data.otherDevicesthis.iconsGroup = res.data.iconsGroupthis.envComponents = res.data.envComponents// 环境组件this.workshop.map((item, index) => {item.envLayout.map((child, idx) => {const tempObj = this.iconsGroup[child.iconId]const tempArr = Object.values(tempObj)child.subIcons = tempArrchild.randomId = new Date().getTime() + '' + index + idxchild.type = 'env'})item.devices.map(child => {const tempObj = this.iconsGroup[child.iconId]const tempArr = Object.values(tempObj)child.subIcons = tempArr})})this.envComponents.map((item, index) => {const tempObj = this.iconsGroup[item.iconId]const tempArr = Object.values(tempObj)item.subIcons = tempArritem.icon = tempObj[item.iconId]item.randomId = new Date().getTime() + indexitem.type = 'env'item.position = {l: 0,left: 0,z: this.zIndex++}})// // 获取图片宽高// const _this = this// this.otherDevices.map((item, index) => {//   ((index) => {//     const img = new Image()//     img.src = item.icon.img//     img.onload = function() {//       _this.otherDevices[index].icon.width = img.width / 2//       _this.otherDevices[index].icon.height = img.height / 2//     }//   })(index)// })this.workshop.forEach(item => {item.action = 'none'})if (!this.workshop.length) {this.workshop = [{workshopId: 'new_1',isNew: true,name: '车间1',action: 'create',devices: []}]} else {const arr = []this.workshop.forEach(item => {item.devices.forEach(child => {arr.push(child.position.z)child.position.l = child.position.l * this.basicPerWchild.position.t = child.position.t * this.basicPerH})})this.zIndex = arr.length ? Math.max(...arr) : 0}this.activeName = '0'}).finally(_ => {this.loading = false})},look() {this.dialogVisible = truethis.previewWorkshop = JSON.parse(JSON.stringify(this.workshop))},add() {this.addEditVisible = truethis.isAdd = true},editCj(name, isNew, index) {this.infoForm.name = this.workshop[this.activeName].namethis.infoForm.position = this.workshop[this.activeName].positionthis.infoForm.manager = this.workshop[this.activeName].managerthis.addEditVisible = truethis.isAdd = falsethis.isNew = isNewthis.activeName = index + ''},infoClose() {this.infoForm = {name: '',position: '',manager: ''}this.$refs.infoForm.clearValidate()this.btnLoading = false},addSubmit() {this.$refs.infoForm.validate((valid) => {if (valid && this.isAdd) {// 新增车间const obj = {workshopId: 'new_' + (this.activeName * 0 + 1),isNew: true,// name: this.infoForm.name,orgOuterId: this.orgOuterId,...this.infoForm,action: 'create',devices: [],envLayout: []}this.workshop.push(obj)this.activeName = (this.workshop.length - 1).toString()this.addEditVisible = false} else if (valid && !this.isAdd) {// 编辑车间this.workshop[this.activeName].name = this.infoForm.namethis.workshop[this.activeName].position = this.infoForm.positionthis.workshop[this.activeName].manager = this.infoForm.managerif (!this.isNew) {this.workshop[this.activeName].action = 'update'}this.addEditVisible = false}})},delCj() {// if (this.workshop[val].devices.length) {//   this.$alert('该车间下存在已配置设备,删除车间前请先移除相关设备', '删除车间', {//     type: 'warning',//     confirmButtonText: '确定'//   });// } else {this.$confirm('此操作将永久删除该车间, 是否继续?', '删除车间', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.otherDevices = [...this.workshop[this.activeName].devices, ...this.otherDevices]if (this.isNew) {this.workshop.splice(this.activeName, 1)} else {this.workshop[this.activeName].action = 'delete'this.workshop[this.activeName].devices = []}this.addEditVisible = falsethis.$message({type: 'success',message: '删除成功!'});this.workshop.some((item, index) => {if (item.action !== 'delete') {this.activeName = index + ''}})// this.activeName = (this.workshop.length - 1).toString()})// }},// 抓取要拖动的元素drag(ev, id, item, f, idx) {this.isEnv = falsethis.halfWidth = item.icon.width / item.icon.type / 2this.halfHeight = item.icon.height / item.icon.type / 2if (f) {this.first = true} else {this.first = falsethis.clientX = ev.clientXthis.clientY = ev.clientYthis.offsetLeft = ev.target.offsetLeftthis.offsetTop = ev.target.offsetTop}this.dragId = idev.dataTransfer.setData('Text', id)this.tempObj = item// 边界处理this.tagIndex = idxthis.tagWidth = item.icon.width / item.icon.typethis.tagHeight = item.icon.height / item.icon.type// this.tagWidth = ev.target.clientWidth// this.tagHeight = ev.target.clientWidth},allowDrop(ev) {ev.preventDefault()var elm = document.getElementById(this.dragId)if (!this.first) {this.moveX = ev.clientX - this.clientXthis.moveY = ev.clientY - this.clientY}elm.style.opacity = 0this.timeOut && clearTimeout(this.timeOut)// 处理拖动边界问题if (!this.first) {if (this.offsetLeft + this.moveX < 0) {elm.style.left = 0elm.style.top = this.offsetTop + this.moveY + 'px'this.tempObj.position.l = 0this.tempObj.position.t = this.offsetTop + this.moveYelm.style.opacity = 1}if (this.offsetTop + this.moveY < 0) {elm.style.top = 0elm.style.left = this.offsetLeft + this.moveX + 'px'this.tempObj.position.l = this.offsetLeft + this.moveXthis.tempObj.position.t = 0elm.style.opacity = 1}if (this.offsetLeft + this.moveX + this.tagWidth > this.divWidth) {elm.style.left = this.divWidth - this.tagWidth + 'px'elm.style.top = this.offsetTop + this.moveY + 'px'this.tempObj.position.l = this.divWidth - this.tagWidththis.tempObj.position.t = this.offsetTop + this.moveYelm.style.opacity = 1}if (this.offsetTop + this.moveY + this.tagHeight > this.divHeight) {elm.style.top = this.divHeight - this.tagHeight + 'px'elm.style.left = this.offsetLeft + this.moveX + 'px'this.tempObj.position.l = this.offsetLeft + this.moveXthis.tempObj.position.t = this.divHeight - this.tagHeightelm.style.opacity = 1}if (this.offsetLeft + this.moveX < 0 && this.offsetTop + this.moveY < 0) {elm.style.left = 0elm.style.top = 0this.tempObj.position.l = 0this.tempObj.position.t = 0elm.style.opacity = 1}if (this.offsetLeft + this.moveX + this.tagWidth > this.divWidth && this.offsetTop + this.moveY < 0) {elm.style.left = this.divWidth - this.tagWidth + 'px'elm.style.top = 0this.tempObj.position.l = this.divWidth - this.tagWidththis.tempObj.position.t = 0elm.style.opacity = 1}if (this.offsetLeft + this.moveX + this.tagWidth > this.divWidth && this.offsetTop + this.moveY + this.tagHeight > this.divHeight) {elm.style.left = this.divWidth - this.tagWidth + 'px'elm.style.top = this.divHeight - this.tagHeight + 'px'this.tempObj.position.l = this.divWidth - this.tagWidththis.tempObj.position.t = this.divHeight - this.tagHeightelm.style.opacity = 1}if (this.offsetLeft + this.moveX < 0 && this.offsetTop + this.moveY + this.tagHeight > this.divHeight) {elm.style.left = 0elm.style.top = this.divHeight - this.tagHeight + 'px'this.tempObj.position.l = 0this.tempObj.position.t = this.divHeight - this.tagHeightelm.style.opacity = 1}}// 变更actionif (!this.workshop[this.activeName].isNew) {this.workshop[this.activeName].action = 'update'}},// 把元素放到容器中drop(ev) {ev.preventDefault();const data = ev.dataTransfer.getData('Text')const elm = document.getElementById(data)const odiv = ev.targetelm.style.position = 'absolute'elm.style.opacity = 1if (odiv.id !== '') {if (this.first) {elm.style.left = ev.target.offsetLeft + 'px'elm.style.top = ev.target.offsetTop + 'px'this.tempObj.position.l = ev.target.offsetLeftthis.tempObj.position.t = ev.target.offsetTop} else {elm.style.left = this.offsetLeft + this.moveX + 'px'elm.style.top = this.offsetTop + this.moveY + 'px'this.tempObj.position.l = this.offsetLeft + this.moveXthis.tempObj.position.t = this.offsetTop + this.moveY}} else {if (this.first) {elm.style.left = ev.layerX - this.halfWidth + 'px'elm.style.top = ev.layerY - this.halfHeight + 'px'this.tempObj.position.l = ev.layerX - this.halfWidththis.tempObj.position.t = ev.layerY - this.halfHeight} else {elm.style.left = this.offsetLeft + this.moveX + 'px'elm.style.top = this.offsetTop + this.moveY + 'px'this.tempObj.position.l = this.offsetLeft + this.moveXthis.tempObj.position.t = this.offsetTop + this.moveY}}// 处理边界if (!this.first) {if (this.offsetLeft + this.moveX < 0) {elm.style.left = 0this.tempObj.position.l = 0}if (this.offsetTop + this.moveY < 0) {elm.style.top = 0this.tempObj.position.t = 0}if (this.offsetLeft + this.moveX + this.tagWidth > this.divWidth) {elm.style.left = this.divWidth - this.tagWidth + 'px'this.tempObj.position.l = this.divWidth - this.tagWidth}if (this.offsetTop + this.moveY + this.tagHeight > this.divHeight) {elm.style.top = this.divHeight - this.tagHeight + 'px'this.tempObj.position.t = this.divHeight - this.tagHeight}}// 操作数据this.tempObj.position.z = this.zIndex++if (!this.isEnv) {if (!this.workshop[this.activeName].devices.length) {// 左侧添加数据this.workshop[this.activeName].devices.push(this.tempObj)// 右侧删除数据this.otherDevices = this.otherDevices.filter(item => {return item.deviceUUID !== this.dragId})} else {const isHas = this.workshop[this.activeName].devices.some(item => {return item.deviceUUID === this.dragId})if (!isHas) {// 左侧添加数据this.workshop[this.activeName].devices.push(this.tempObj)// 右侧删除数据this.otherDevices = this.otherDevices.filter(item => {return item.deviceUUID !== this.dragId})}}} else {if (!this.workshop[this.activeName].envLayout.length) {// 左侧添加数据this.workshop[this.activeName].envLayout.push(this.tempObj)} else {if (this.addEnv) {// 左侧添加数据this.workshop[this.activeName].envLayout.push(this.tempObj)}}}},allowDropCur(ev) {ev.preventDefault()this.timeOut && clearTimeout(this.timeOut)},ondragleave(ev) {var elm = document.getElementById(this.dragId)// elm.style.opacity = 1this.timeOut = setTimeout(() => {elm.style.opacity = 1}, 1000)},dropCur(ev) {ev.preventDefault()const elm = document.getElementById(this.dragId)if (!this.tempObj.type) {// 非环境组件才可以放入设备组件容器elm.style.opacity = 1const isHas = this.otherDevices.some(item => {return item.deviceUUID === this.dragId})if (!isHas) {this.otherDevices.push(this.tempObj)this.workshop[this.activeName].devices = this.workshop[this.activeName].devices.filter(item => {return item.deviceUUID !== this.dragId})}} else {this.$message({message: '环境组件不能归类到设备组件,请重新操作',type: 'warning'});}},// envdragEnvOrigin(ev, id, item, f, idx) {this.addEnv = fconst tempItem = JSON.parse(JSON.stringify(item))tempItem.randomId = new Date().getTime()this.isEnv = truethis.halfWidth = tempItem.icon.width / tempItem.icon.type / 2this.halfHeight = tempItem.icon.height / tempItem.icon.type / 2if (f) {this.first = true} else {this.first = falsethis.clientX = ev.clientXthis.clientY = ev.clientYthis.offsetLeft = ev.target.offsetLeftthis.offsetTop = ev.target.offsetTop}this.dragId = idev.dataTransfer.setData('Text', id)this.tempObj = tempItem// 边界处理this.tagIndex = idxthis.tagWidth = tempItem.icon.width / tempItem.icon.typethis.tagHeight = tempItem.icon.height / tempItem.icon.type// this.tagWidth = ev.target.clientWidth// this.tagHeight = ev.target.clientWidth},dragEnv(ev, id, item, f, idx) {this.addEnv = fitem.randomId = idthis.isEnv = truethis.halfWidth = item.icon.width / item.icon.type / 2this.halfHeight = item.icon.height / item.icon.type / 2if (f) {this.first = true} else {this.first = falsethis.clientX = ev.clientXthis.clientY = ev.clientYthis.offsetLeft = ev.target.offsetLeftthis.offsetTop = ev.target.offsetTop}this.dragId = item.randomIdev.dataTransfer.setData('Text', item.randomId)this.tempObj = item// 边界处理this.tagIndex = idxthis.tagWidth = item.icon.width / item.icon.typethis.tagHeight = item.icon.height / item.icon.type// this.tagWidth = ev.target.clientWidth// this.tagHeight = ev.target.clientWidth},dropEnv(ev) {ev.preventDefault()const elm = document.getElementById(this.dragId)if (this.tempObj.type) {// 非环境组件才可以放入设备组件容器elm.style.opacity = 1this.workshop[this.activeName].envLayout.splice(this.tagIndex, 1)} else {this.$message({message: '设备组件不能归类到环境组件,请重新操作',type: 'warning'});}},allowDropEnv(ev) {ev.preventDefault()this.timeOut && clearTimeout(this.timeOut)},}
}
</script><style lang="scss" scoped>
.drag-cont {flex-grow: 1;min-height: calc(100vh - 68px);.screen-cont {width: 100%;height: 57px;display: flex;align-items: center;justify-content: center;background: #fff;margin-bottom: 20px;border-top: 1px solid #E9E9E9;padding: 6px 0;box-shadow: 0px 1px 4px 0px rgba(0, 21, 41, 0.12);}
}
.add-cont {width: 100%;padding: 20px;box-sizing: border-box;background: #fff;;
}
.my-container {width: 100%;min-width: 1200px;/deep/ .el-dialog__body {padding: 0;background: #F0F2F5;}.content {width: 100%;display: flex;}.top {width: 100%;height: 68px;padding: 0 24px;box-sizing: border-box;background: #FFFFFF;box-shadow: 0px 1px 4px 0px rgba(0, 21, 41, 0.12);display: flex;justify-content: space-between;align-items: center;.icon-back {display: inline-block;width: 34px;height: 34px;line-height: 34px;text-align: center;border-radius: 50%;border: 1px solid #D9D9D9;cursor: pointer;margin-right: 20px;}.name {color: #000;font-size: 20px;font-weight: bold;}}
}
/deep/ .el-tabs--border-card {width: 845px;margin: 0 auto;background: none;border: 0;box-shadow: none;.el-tabs__header {display: flex;justify-content: space-between;align-items: center;flex-direction: row-reverse;height: 68px;line-height: 68px;background: #fff;border: 0;margin-bottom: 20px;.el-tabs__nav-prev {line-height: 68px;}.el-tabs__nav-next {line-height: 68px;}.el-tabs__nav {padding: 0 10px;}.el-tabs__item {color: #262626;font-size: 18px;font-weight: bold;border: 0;padding: 0 10px;padding-right: 0 !important;margin: 0 10px;&:nth-child(2) {padding-left: 10px;}span {display: flex;justify-content: center;align-items: center;width: 100%;height: 30px;}.tab-action-cont {width: 38px;height: 30px;background: #F4F5F9;border-radius: 0px 2px 2px 0px;display: none;margin-left: 16px;}&.is-active {height: 32px;border-radius: 4px;border: 1px solid #D9D9D9;color: #409EFF;.tab-action-cont {display: flex;}}}.el-tabs__new-tab {width: 65px;height: 32px;line-height: 32px;margin: 0px 15px;&::after {content: '新增';color: #262626;font-size: 14px;}.el-icon-plus {display: none;}}}.el-tabs__content {padding: 0px;background: #fff;}
}.preview {/deep/ .el-tabs--border-card {width: 845px;margin: 0 auto;background: none;border: 0;box-shadow: none;.imgcur {cursor: auto !important;position: absolute;}.el-tabs__header {display: flex;justify-content: space-between;align-items: center;flex-direction: row;height: 68px;line-height: 68px;background: #fff;border: 0;margin-bottom: 20px;}.el-tabs__item {padding-right: 10px !important;}}
}.tab-action-cont {display: inline-flex;width: 16px;height: 16px;text-align: center;margin-left: 5px;font-size: 12px;.el-icon-edit {-webkit-transition: all .3s cubic-bezier(.645,.045,.355,1);transition: all .3s cubic-bezier(.645,.045,.355,1);&:hover {color: red;}}
}
.bg-cont {width: 100%;/* height: 468px; */background: url('../../../assets/imgs/pt-bg.png') no-repeat;background-size: cover;position: relative;.right-img-cont {background-size: cover !important;position: absolute;cursor: move;border: 1px dashed #e4e4e4;border-radius: 3px;&:hover {border-color: #409eff;}.refresh-cont {width: 20px;height: 20px;position: absolute;top: 0;right: 0;cursor: pointer;background: #f1f1f1;border-radius: 3px;&:hover {background: #409eff;color: #fff;}.el-icon-refresh {font-size: 16px;padding: 2px;}}.imgcur {width: 100%;height: 100%;}}
}
.env-cont {width: 360px;height: 356px;background: #fff;border: 1px solid #E9E9E9;.title {text-align: center;border-bottom: 1px solid #E9E9E9;line-height: 56px;font-size: 16px;color: #262626;font-weight: bold;}.cont {width: 100%;height: 300px;overflow-y: auto;display: flex;flex-wrap: wrap;justify-content: space-between;align-content: flex-start;/* align-items: center; */padding: 24px;box-sizing: border-box;overflow-x: hidden;.item {width: 140px;height: 134px;border-radius: 4px;border: 1px solid #E4E4E4;display: flex;flex-direction: column;align-items: center;justify-content: space-between;padding: 8px 10px;box-sizing: border-box;cursor: pointer;margin-bottom: 20px;position: inherit !important;opacity: 1 !important;.img {width: 80px;/* height: 80px; */}span {display: inline-block;width: 100%;word-break: break-all;text-align: center;font-size: 12px;margin-top: 10px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;}}}
}
.right {width: 360px;background: #fff;border: 1px solid #E9E9E9;.title {text-align: center;border-bottom: 1px solid #E9E9E9;line-height: 56px;font-size: 16px;color: #262626;font-weight: bold;}.cont {width: 100%;height: calc(100vh - 481px);overflow-y: auto;display: flex;flex-wrap: wrap;justify-content: space-between;align-content: flex-start;/* align-items: center; */padding: 24px;box-sizing: border-box;position: relative;.item {width: 140px;height: 134px;border-radius: 4px;border: 1px solid #E4E4E4;display: flex;flex-direction: column;align-items: center;justify-content: space-between;padding: 8px 10px;box-sizing: border-box;cursor: pointer;margin-bottom: 20px;.img {width: 80px;/* height: 80px; */}span {display: inline-block;width: 100%;word-break: break-all;text-align: center;font-size: 12px;margin-top: 10px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;}}}
}
.btn-cont {width: 100%;display: flex;flex-direction: row-reverse;margin: 20px 0;
}
</style>

vue中使用html5的drag实现任意位置拖动相关推荐

  1. vue中is属性搭配vuedraggable插件实现可拖动可视化大屏展示组件的自定义配置功能

    最近有这样一个需求,将大屏上展示的东西都封装成独立的组件让用户自己可以自定义配置自己的组件位置及想要展示的组件,第一个我就想到通过is来实现,分享下我的思路及部分代码供大家参考. 先看下大概布局: 如 ...

  2. div在屏幕任意位置拖动

    div在屏幕任意位置拖动 主要就是三点: 1,获取鼠标按下时的位置: 2,获取鼠标移动后的位置: 3,两者相减就是div的位置: js代码如下: // 获取屏幕的高宽度 let cw = $(wind ...

  3. php 拖拽 上传文件 进度,在Vue中如何实现带进度条的文件拖动上传功能

    这篇文章主要介绍了Vue实现带进度条的文件拖动上传功能,本文通过实例代码给大家介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下 1. 基本界面 content="width=devic ...

  4. vue 中基于html5 drag drap的拖放

    事情是这样的,右边有各种控件,可以拖动到右边自由区,在自由区内可以随意拖动. 案例一: 开始的我,so easy! 通过绑定元素的mousedown 事件,监听鼠标的mousemove,和mouseu ...

  5. vue中使用拖拽drag

    被拖拽的节点 dragable="true" @dragstart="drag" 拖入的节点 @drop="drop" @dragover= ...

  6. vue中进入详情页记住列表滚动位置keep-alive解决

    一.配置路由 keepactice:true {path: '/index',name: 'index',component: index,meta: {keepalive: true // 组件是否 ...

  7. vue项目中-上传图片头像并裁剪成任意大小的实现

    vue项目中-上传图片头像并裁剪成任意大小的实现 先看效果图: 放大缩小-翻转-查看都有的哦! 直接上代码 <el-dialog title="图片剪裁" :visible. ...

  8. mui html5 vue,VUE中使用MUI方法

    VUE中如何使用MUI 1.第一步:下载MUI 百度搜索MUI进入其官网点击右上角github地址,下载MUI文件 2.第二步:拷贝文件 拷贝下载文件的dist目录中的三个文件复制到自己项目中创建的m ...

  9. html5 语音包,在vue中使用vue-i18n按需加载语言包

    1.新建目录结构如下: . ├── App.vue ├── assets │   └── langs │ ├── en │ │ └── index.js │   ├── zh │ │ └── inde ...

最新文章

  1. [Nginx优化]分享nginx配置文件及优化说明
  2. Lync Server外部访问系列PART3:准备反向代理
  3. 机器人流程自动化(RPA)系统原理及特点
  4. xml tools属性详解
  5. a标签中href=javacript:; href=javacript:void(0); href=#区别
  6. 重做实验七 寻址方式在结构化数据访问中的应用
  7. ubuntu memcached php,如何在 Ubuntu 18.04 上安装 Memcached
  8. 四川方言说唱《管我锤子事》
  9. 计算机网络概述的功能 组成,计算机网络的概述
  10. Java面试题-Java中的锁
  11. Nagios中NSClient++监控Windows主机
  12. html 5个人博客代码模板,5套漂亮的个人博客html模板分享
  13. 仙剑奇侠传脚本制作教程
  14. Android百度地图API使用教程
  15. Smart Contract Vulnerabilities:Vulnerable Does Not Imply Exploited总结
  16. java 中 webcam类_如何在Java的Swing应用程序中集成Webcam?
  17. 30天自制操作系统:第十天 叠加处理
  18. 大华视频服务器系统日志怎么看,日常工作中查看工控机Windows日志的方法
  19. 二维码简介_二维码基本概念_二维码基本原理
  20. 5G入门到精通-5G专业词汇中英文对照[持续更新]

热门文章

  1. 八皇后问题python实现
  2. Effective C++ 条款11_不止于此
  3. 切换上下首音乐功能的实现(消息订阅与发布的使用)
  4. (汇总篇)语义SLAM相关开源方案| 全球优秀作者与实验室 | SLAM学习资料整理
  5. 【白皮书分享】2020脱发治疗白皮书.pdf(附下载链接)
  6. 目睹鸿蒙开创四大至高位面,第二十三章 鸿蒙四大至高规则
  7. React最佳实践系列 —— 循序渐进理解 Dva中的model概念
  8. linux设备编号,linux设备号详解
  9. Insight.Numerics.inFlux.v1.0通风和气体扩散CFD软件
  10. 在android上模拟ios阴影效果