| App.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| api/request.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| api/vehicle.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| manifest.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/index/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/login/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/map/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/map/infos/scene-create.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/map/js/ctx.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/map/scene.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/map/task.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/my/help-feedback.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| pages/my/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
App.vue
@@ -15,7 +15,8 @@ min_y: 0, img_x: 1, img_y: 1, } }, withLog:false }, onLaunch: function() { console.log('App Launch') api/request.js
@@ -11,24 +11,71 @@ dataType: "json", }, apiCount: { agv_state: 0, laser_data: 0, }, addLog(item) { const list = session.getValue("request_log") || [] if (!getApp().globalData.withLog) { return } if (item.statusCode == 200) { const ret = JSON.parse(item.data) if (ret.code == 0) { if (item.url.indexOf("get_agv_state") > 0) { const res = typeof item.data == 'string' ? item.data : JSON.stringify(item.data) if (res.length > 64 * 1024) { if (this.apiCount.agv_state % 20 != 0) { this.apiCount.agv_state++; return } this.apiCount.agv_state = 1; } if (item.url.indexOf("laser_data") > 0) { if (ret.data?.base_map?.image_base64) { this.apiCount.laser_data++; } else { if (this.apiCount.laser_data % 20 != 0) { this.apiCount.laser_data++; return } this.apiCount.laser_data = 1; } } const res = ret.data if (res) { if (item.url.indexOf("getMapUrl") > 0) { if (res.filedata) { res.data_length = res.filedata.length res.filedata = "..." item.data = JSON.stringify(ret) } } else if (item.url.indexOf("laser_data") > 0) { if (res?.base_map?.image_base64) { res.base_map.image_length = res.base_map.image_base64.length res.base_map.image_base64 = "..." item.data = JSON.stringify(ret) } } if (JSON.stringify(res).length > 100 * 1024) { // const maxData = session.getValue("request_log_max_data") || {} // const key = `data${new Date().getTime()}` // maxData[key] = item.data // item.data_key = key // delete item.data // session.setValue("request_log_max_data", maxData) item.data = res.length ret.data = "..." ret.data_length = JSON.stringify(res).length item.data = JSON.stringify(ret) } if(item.url.indexOf("get_agv_state") > 0) { return } } } const list = session.getValue("request_log") || [] list.unshift(item) if (list.length > 512) { const oldItem = list.pop() if (oldItem.data_key) { @@ -48,8 +95,8 @@ options.method = options.method || this.common.method; options.dataType = options.dataType || this.common.dataType; if(options.url.indexOf("get_agv_state") < 0 && options.url.indexOf("laser_data") < 0) { if (options.url.indexOf("get_agv_state") < 0 && options.url.indexOf("laser_data") < 0 && options.url.indexOf( "taskGroupStatus") < 0) { console.log("url", options.url, options.data) } return new Promise((resolve, reject) => { @@ -61,8 +108,8 @@ method: options.method, dataType: options.dataType, success: (result) => { if(options.url.indexOf("get_agv_state") < 0 && options.url.indexOf("laser_data") < 0) { if (options.url.indexOf("get_agv_state") < 0 && options.url.indexOf( "laser_data") < 0) { // console.log("result", result) } @@ -87,14 +134,7 @@ msg: "访问失败,状态码:" + result.statusCode }) } this.addLog({ date, method: `${options.method || ""}`, url: options.url, param: options.data, statusCode: result.statusCode, data: result.data }) var ret = result.data if (typeof ret == 'string') { try { @@ -116,6 +156,14 @@ }) } } this.addLog({ date, method: `${options.method || ""}`, url: options.url, param: options.data, statusCode: result.statusCode, data: JSON.stringify(ret) }) if (ret.code == 0) { resolve(ret.data); api/vehicle.js
@@ -894,3 +894,84 @@ }) } /** * GET 5000/api/check_mapserver_is_start * 判断构图程序是否启动 * @param * @returns */ export const checkMapServerIsStart = (ip) => { var header = { "Content-Type": "application/json;charset=UTF-8" }; var url = `http://${ip}:5000/api/check_mapserver_is_start/`; return http.request({ method: "GET", url, header, }) } /** * POST 5000/api/start_or_stop_mapserver * 开启或者关闭构图程序: 1开启2关闭 * @param status 1开启2关闭 * @returns */ export const startOrStopMapServer = (ip, status) => { var header = { "Content-Type": "application/json;charset=UTF-8" }; var url = `http://${ip}:5000/api/start_or_stop_mapserver/`; return http.request({ method: "POST", url, header, data: {status} }) } /** * GET 5000/api/check_mapserver_is_ok * 构图程序是否准备到位 * @param * @returns */ export const checkMapServerIsOk = (ip) => { var header = { "Content-Type": "application/json;charset=UTF-8" }; var url = `http://${ip}:5000/api/check_mapserver_is_ok/`; return http.request({ method: "GET", url, header, }) } /** * GET 5000/api/check_save_map_is_ok * 结束构图是否保存完成 * @param * @returns */ export const checkSaveMapIsOk = (ip) => { var header = { "Content-Type": "application/json;charset=UTF-8" }; var url = `http://${ip}:5000/api/check_save_map_is_ok/`; return http.request({ method: "GET", url, header, }) } manifest.json
@@ -2,8 +2,8 @@ "name" : "ES-GO", "appid" : "__UNI__C988375", "description" : "", "versionName" : "1.2.9", "versionCode" : 129, "versionName" : "1.3.2", "versionCode" : 132, "transformPx" : false, /* 5+App特有相关 */ "app-plus" : { pages/index/index.vue
@@ -877,6 +877,8 @@ margin-top: 150rpx; margin-left: calc(750rpx - 330rpx); width: 320rpx; max-height: 50vh; overflow: auto; align-items: center; justify-content: center; flex-direction: column; pages/login/index.vue
@@ -188,7 +188,7 @@ password: "" }) } getApp().globalData.withLog = session.getValue("write_log") ? true:false uni.reLaunch({ url: "/pages/index/index" }) pages/map/index.vue
@@ -33,7 +33,9 @@ v-model:opSceneType="opSceneType" @create-ok="onCreateSceneOk"></SceneCreateInfo> --> <view class="map-content" v-show="mapOperationType !='scene_create'"> <view class="content"> <view class="fabric" :message="ctxDataStr" :change:message="ctx.receiveMsg" id="canvasMap"></view> <view ref="canvasCtx" class="fabric" id="canvasMap" :message="ctxDataStr" :change:message="ctx.receiveMsg"> </view> <view class="loading-overlay" v-if="bgLoading"> <view class="loading-content"> <view class="loading-spinner"></view> @@ -386,9 +388,10 @@ </view> </template> <script src="./js/ctx.js" module="ctx" lang="renderjs"></script> <script> import { ref } from "vue"; import { showToast, showModal, @@ -440,6 +443,7 @@ list: [] }, sceneList: [], ctxDataStr: "[]", mapOperationType: "", mapOperationStatus: "", @@ -482,7 +486,9 @@ img_x: 1, img_y: 1 }, positioningAgv: false positioningAgv: false, isPageVisible: true, destroyFlag: false, } }, computed: { @@ -539,10 +545,29 @@ }, onHide() { this.isPageVisible = false }, onUnload() { async onUnload() { this.isPageVisible = false console.log("onUnload") }, onBackPress() { this.isPageVisible = false if (this.destroyFlag) return false else { this.ctxDataStr = JSON.stringify([{ method: "destroy", }]) return true } }, methods: { setData(obj) { let that = this; @@ -583,6 +608,10 @@ }, clickShowMenu() { // const list = [...this.sceneList] // for(let i =0; i < 20;i++){ // list.push("test" + i) // } this.menuPopup = { type: "scene", list: this.sceneList, @@ -786,7 +815,7 @@ // this.mapOperationType = 'scene_create' // this.opSceneType = 'add_name' uni.navigateTo({ url: `/pages/map/scene?ip=${this.vehicleIp}`, url: `/pages/map/scene?ip=${_this.vehicleIp}`, events: { // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据 create_finish: function(data) { @@ -910,12 +939,18 @@ }, { method: "public_teaching_path", param: this.teachingMode.Public || [] param: { list: this.teachingMode.Public || [], show: this.showTeachingPathFlag } }, { method: "station_teaching_path", param: this.teachingMode.Stations || [] param: { list: this.teachingMode.Stations || [], show: this.showTeachingPathFlag } }, { @@ -939,7 +974,14 @@ receiveRenderData(param) { console.log('接收到视图层的数据:', param); if (param.method == "set_backgroud_progress") { if (param.method === "destroy_complete") { if (param.param) { this.destroyFlag = true uni.navigateBack({ delta: 1 }) } } else if (param.method == "set_backgroud_progress") { if (param.type == "start") { this.setData({ bgProgressPercent: 50, @@ -1129,6 +1171,7 @@ this.mapOperationType = "edit_map" }, clickExtendMap() { const _this = this uni.navigateTo({ url: `/pages/map/scene?ip=${this.vehicleIp}&opType=extend&sceneId=${this.sceneId}`, events: { @@ -1170,6 +1213,7 @@ }, async loadSceneList() { try { uni.showLoading({ title: "加载场景中" }) @@ -1846,26 +1890,40 @@ } } }, async reloadTeachingMode() { async reloadTeachingMode(finish) { try { this.teachingMode = await this.loadTeachingMode() this.ctxDataStr = JSON.stringify([{ const list = [{ method: "clear_teaching_path", }, { method: "public_teaching_path", param: this.teachingMode.Public || [] param: { list: this.teachingMode.Public || [], show: this.showTeachingPathFlag } }, { method: "station_teaching_path", param: this.teachingMode.Stations || [] }, { method: "show_teaching_path", param: { list: this.teachingMode.Stations || [], show: this.showTeachingPathFlag } } ]) // , { // method: "show_teaching_path", // param: { // show: this.showTeachingPathFlag // } // } ] if (finish) { list.push({ method: "teaching_finish", }) } this.ctxDataStr = JSON.stringify(list) } catch (ex) { showError(ex) @@ -2049,10 +2107,8 @@ }, clickTeachingFinish() { this.mapOperationType = "" this.ctxDataStr = JSON.stringify([{ method: "teaching_finish", }]) this.reloadTeachingMode() this.reloadTeachingMode(true) }, async teachingStart(mode) { @@ -2163,11 +2219,13 @@ const publicList = data.Public || [] const curIndex = publicList.findIndex((a)=>a.name == oldName) if(curIndex > -1) { if (curIndex > -1) { this.ctxDataStr = JSON.stringify([{ method: "public_teaching_path", param: [publicList[curIndex]] param: { list: [publicList[curIndex]], show: true } } ]) } @@ -2705,6 +2763,8 @@ margin-top: 140rpx; margin-left: 225rpx; width: 300rpx; max-height: 50vh; overflow: auto; align-items: center; justify-content: center; flex-direction: column; pages/map/infos/scene-create.vue
@@ -102,6 +102,7 @@ computed: { }, mounted() { const _this = this uni.getSystemInfo({ pages/map/js/ctx.js
@@ -31,7 +31,6 @@ export default { data() { return { vehicleIp: "", canvasId: "", canvas: null, eleWidth: 0, @@ -64,16 +63,17 @@ img_y: 1 }, pressObjTimer: 0, selectable: true, } }, mounted() { console.log("ctx mounted") this.init() }, methods: { async init(ip) { try { this.agvObj = null const _this = this fabric.Object.prototype.setControlsVisibility({ mt: false, // 中间上 @@ -107,6 +107,7 @@ canvas.setAttribute("id", this.canvasId) canvas.setAttribute("type", "2d") cantainerEl.appendChild(canvas) this.canvas = new fabric.Canvas(this.canvasId, { allowTouchScrolling: true, // 允许触摸滚动 selection: true, @@ -120,6 +121,8 @@ renderOnAddRemove: false, imageSmoothingEnabled: true }) this.canvas.clear() this.eleWidth = cantainerEl.clientWidth this.eleHeight = cantainerEl.clientHeight @@ -144,6 +147,28 @@ } catch (ex) { this.showError(ex) } }, destroyCanvas() { console.log("destroyCanvas") if (this.canvas) { // 2. 移除所有事件监听器 this.removeAllEventListeners(); // 3. 清空所有对象(分批处理避免阻塞) this.clearObjects(); // 4. 销毁Fabric.js实例 this.canvas.dispose(); // 6. 清除所有变量引用 this.cleanupReferences(); this.canvas = null // 通知Vue层销毁完成 this.$ownerInstance.callMethod('receiveRenderData', { method: "destroy_complete", param: true }); } }, patchFabricForUniApp(canvas) { @@ -425,10 +450,61 @@ cantainerEl.addEventListener('touchstart', function(e) { // console.log('touchstart:', e.touches.length); e.preventDefault(); // 阻止默认行为 _this.canvas.fire('touch:start', { e: e }); _this.canvasTouchStart(e) // _this.canvas._onMouseDown(e); }); cantainerEl.addEventListener('touchmove', function(e) { // _this.canvas._onMouseMove(e); // console.log('touchmove:', e.touches.length); e.preventDefault(); // 阻止默认行为 // 处理移动 _this.canvasTouchMove(e) }); cantainerEl.addEventListener('touchend', function(e) { // _this.canvas._onMouseUp(e); // console.log('touchend:'); e.preventDefault(); // 阻止默认行为 _this.touchPoint = { x: 0, y: 0 }; const activeObj = _this.canvas.getActiveObject() if (!activeObj) { // 处理结束事件 if (e.touches.length === 0) { _this.handleTouchEnd(); } // if (_this.editObject) { // _this.canvas.setActiveObject(_this.editObject) // } } else { // if (activeObj.lockMovementX) { // _this.canvas.discardActiveObject(); // } } if (this.pressObjTimer) { clearTimeout(this.pressObjTimer); this.pressObjTimer = null } }); cantainerEl.addEventListener('touchcancel', function(e) { // console.log('touchcancel:'); if (this.pressObjTimer) { clearTimeout(this.pressObjTimer); this.pressObjTimer = null } }) }, canvasTouchStart(e) { const _this = this _this.pointerSelectObject(e) if (!_this.canvas.getActiveObject()) { // 根据触摸点数量判断交互类型 @@ -596,13 +672,10 @@ _this.handleMultiTouch(e.touches); } } }); cantainerEl.addEventListener('touchmove', function(e) { // _this.canvas._onMouseMove(e); // console.log('touchmove:', e.touches.length); e.preventDefault(); // 阻止默认行为 // 处理移动 }, canvasTouchMove(e) { const _this = this const list = _this.canvas.getActiveObjects() if (list.length == 0) { if (e.touches.length === 1) { @@ -630,48 +703,6 @@ _this.handleMultiTouchMove(e.touches); } } }); cantainerEl.addEventListener('touchend', function(e) { // _this.canvas._onMouseUp(e); // console.log('touchend:'); e.preventDefault(); // 阻止默认行为 _this.touchPoint = { x: 0, y: 0 }; const activeObj = _this.canvas.getActiveObject() if (!activeObj) { // 处理结束事件 if (e.touches.length === 0) { _this.handleTouchEnd(); } // if (_this.editObject) { // _this.canvas.setActiveObject(_this.editObject) // } } else { // if (activeObj.lockMovementX) { // _this.canvas.discardActiveObject(); // } } if (this.pressObjTimer) { clearTimeout(this.pressObjTimer); this.pressObjTimer = null } }); cantainerEl.addEventListener('touchcancel', function(e) { // console.log('touchcancel:'); if (this.pressObjTimer) { clearTimeout(this.pressObjTimer); this.pressObjTimer = null } // const activeObj = _this.canvas.getActiveObject() // if (activeObj) { // if (activeObj.lockMovementX) { // _this.canvas.discardActiveObject(); // } // } }) }, // 计算点到线段的距离 @@ -753,7 +784,6 @@ objects.splice(0, 1); const objActive = this.canvas.getActiveObject() let pointerList = [] let pointerList2 = [] for (let i = objects.length - 1; i >= 0; i--) { @@ -893,44 +923,6 @@ } return } // objects.forEach(obj => { // if (obj instanceof fabric.Path || obj instanceof fabric.Line) { // // 设置一个“点击容忍度”,比如 5 像素 // const tolerance = 5; // // 临时扩大路径的点击区域 // const originalStrokeWidth = obj.strokeWidth; // obj.strokeWidth = originalStrokeWidth + tolerance * 2; // const isHit = obj.intersectsWithPointer(pointer); // // 恢复原始宽度 // obj.strokeWidth = originalStrokeWidth; // if (isHit) { // pointerList.push(obj) // } // } else if (obj instanceof fabric.Rect || obj instanceof fabric.Ellipse) { // const isHit = obj.containsPoint(pointer); // if (isHit) { // pointerList.push(obj) // } // } // // else if (obj instanceof fabric.Group ) // // { // // const objects2 = obj.getObjects(); // // const isHit = obj.containsPoint(pointer); // // if (isHit) { // // pointerList.push(obj) // // } // // } // }); // if (pointerList.length === 0) { // return // } // const obj = pointerList.pop() // this.canvas.discardActiveObject() // this.canvas.setActiveObject(obj) }, objectMoving(target) { const _this = this @@ -955,7 +947,7 @@ }); _this.createOkCancelControl(obj) _this.canvas.renderAll() _this.canvas.requestRenderAll() } else if (target?.eleType == "edit_teaching") { _this.updateEditTeachingPath(target) @@ -977,7 +969,7 @@ else _this.updateRegion(target, data) _this.canvas.renderAll() _this.canvas.requestRenderAll() } else if (target?.eleType == "wall_pt") { const data = target.mainObj?.data @@ -1007,7 +999,7 @@ _this.updateVirtualWall(target.mainObj, data) _this.canvas.renderAll() _this.canvas.requestRenderAll() } else if (target?.eleType == "region_pt") { const data = target.mainObj?.data if (!data) @@ -1039,10 +1031,8 @@ } _this.updateRegion(target.mainObj, data) } _this.canvas.renderAll() _this.canvas.requestRenderAll() } } else if (target?.eleType == "edit_teaching_pt") { @@ -1126,28 +1116,6 @@ onSelectionChanage() { }, safeLoadImage(url, maxSize = 2048) { console.log(url) return new Promise((resolve) => { const img = new Image(); img.onload = () => { // 检查尺寸是否超出限制 const scale = Math.min( maxSize / Math.max(img.width, img.height), 1 ); resolve(new fabric.Image(img, { scaleX: scale, scaleY: scale })); }; img.onerror = () => { console.error('图片加载失败'); resolve(null); }; img.src = url; }); }, // 将 Base64 转为 Blob,再生成 URL base64ToBlob(base64, mime) { @@ -1234,6 +1202,7 @@ _this.$ownerInstance.callMethod('receiveRenderData', { method: "set_backgroud_progress", type: "error", msg:err }); console.error("图片加载失败", err) reject(new Error('图片加载失败')); @@ -1253,14 +1222,66 @@ } return null; }, clearObjects() { const list = this.canvas.getObjects() list.splice(0, 1) for (let i in list) { const obj = list[i] this.canvas.remove(obj) // 移除所有事件监听器 removeAllEventListeners() { if (!this.canvas) return; // 移除Fabric.js内置事件 this.canvas.off(); // 移除自定义事件监听器 const cantainerEl = document.getElementById("canvasMap"); if (cantainerEl) { cantainerEl.replaceWith(cantainerEl.cloneNode(true)); } }, clearObjects() { if (!this.canvas) return; this.canvas.discardActiveObject() const objects = this.canvas.getObjects() const batchSize = 50; // 每批删除50个对象 for (let i = 0; i < objects.length; i += batchSize) { const batch = objects.slice(i, i + batchSize); this.canvas.remove(...batch); } this.canvas.clear(); this.workSpace = null; this.agvObj = null; this.curTeachingObj = null; this.objEditing = null; this.editObject = null; this.drawingObj = null; if (this.pressObjTimer) { clearTimeout(this.pressObjTimer); this.pressObjTimer = null; } }, // 清理所有引用 cleanupReferences() { this.canvas = null; this.workSpace = null; this.agvObj = null; this.curTeachingObj = null; this.objEditing = null; this.editObject = null; this.drawingObj = null; this.mapInfo = { proportion: 1, img_proportion: 1, max_x: 1, max_y: 1, min_x: 0, min_y: 0, img_x: 1, img_y: 1 }; // 清除所有定时器 if (this.pressObjTimer) { clearTimeout(this.pressObjTimer); this.pressObjTimer = null; } }, setBackground(info) { const _this = this @@ -1277,7 +1298,7 @@ // this.canvas.selectionColor = 'rgba(100, 200, 255, 0.3)'; // 选中背景色 // this.canvas.selectionBorderColor = '#1890ff'; // 边框颜色 // this.canvas.selectionLineWidth = 3; // 边框宽度 this.agvObj = null const cantainerEl = document.getElementById("canvasMap") this.eleWidth = cantainerEl.clientWidth this.eleHeight = cantainerEl.clientHeight @@ -1314,25 +1335,8 @@ left: 0, top: 0, }); // if (_this.workSpace instanceof fabric.Group) { // const objs = _this.workSpace.getObjects() // const rect = objs[1] // _this.workSpace.remove(objs[0]) // _this.workSpace.insertAt(0,img) // rect.set({ // width: _this.mapInfo.img_x, // height: _this.mapInfo.img_y, // }) // _this.workSpace.set({ // width: _this.mapInfo.img_x, // height: _this.mapInfo.img_y, // }) // resolve() // return // } _this.clearObjects() // const rect = new fabric.Rect({ left: 0, top: 0, @@ -1359,21 +1363,48 @@ height: _this.mapInfo.img_y, }); _this.canvas.add(wsGroup) if (_this.workSpace) { _this.canvas.remove(_this.workSpace) } _this.workSpace = wsGroup _this.clearObjects() _this.canvas.add(wsGroup) // _this.canvas.renderAll() _this.workSpace = wsGroup } //_this.checkMemoryUsage() resolve() }).catch((err) => { _this.$ownerInstance.callMethod('receiveRenderData', { method: "set_backgroud_progress", type: "error", // _this.$ownerInstance.callMethod('receiveRenderData', { // method: "set_backgroud_progress", // type: "error", // msg:err // }); const rect = new fabric.Rect({ left: 0, top: 0, width: _this.mapInfo.img_x, height: _this.mapInfo.img_y, stroke: "#333", strokeWidth: 1, strokeDashArray: [5, 5], strokeLineCap: 'butt', fill: "rgba(255,255,255,0)", }) let wsGroup = new fabric.Group([ rect], { id: "workspace", eleType: "workspace", selectable: false, hasControls: false, left: 0, top: 0, width: _this.mapInfo.img_x, height: _this.mapInfo.img_y, }); _this.clearObjects() _this.canvas.add(wsGroup) _this.workSpace = wsGroup resolve() }) @@ -1425,12 +1456,7 @@ scale: scale }); if (!this.workSpace) return; // this.setCenterFromObject(this.workSpace); // 超出画布不展示 // _this.workSpace.clone().then((cloned) => { // _this.canvas.clipPath = cloned; // _this.canvas.requestRenderAll(); // }); }, setDrawingType(type, svg) { if (svg) { @@ -1474,7 +1500,6 @@ y: touch.clientY }; // console.log('单点触摸开始'); let activeObj = this.canvas.getActiveObject(); if (!activeObj) { if (!this.drawType) { @@ -1520,7 +1545,6 @@ } // 移动视口 // console.log('relativePan', deltaX, deltaY); const vpt = this.canvas.viewportTransform; this.canvas.relativePan(new fabric.Point(deltaX, deltaY)); if (this.objEditing) { @@ -1543,7 +1567,7 @@ this.lastPosX = touch.clientX; this.lastPosY = touch.clientY; this.canvas.renderAll() this.canvas.requestRenderAll() } else if (this.isDrawing) { const vpt = this.canvas.viewportTransform; // console.log("viewportTransform", vpt[4], vpt[5]) @@ -1849,7 +1873,7 @@ if (this.objEditing) { this.createOkCancelControl(this.objEditing) } this.canvas.renderAll() this.canvas.requestRenderAll() }, @@ -2222,8 +2246,7 @@ lockScalingY: true, lockMovementX: true, lockMovementY: true, selectable: false, opacity: 1, mainRoad: main_road, data: teachingData }) @@ -2271,8 +2294,8 @@ const obj = list[i2] obj.set({ opacity: show ? 1 : 0, strokeDashArray: [], strokeLineCap: '', // strokeDashArray: [], // strokeLineCap: '', hasControls: show, selectable: show, }) @@ -2432,23 +2455,23 @@ this.createOkCancelControl(obj) this.canvas.requestRenderAll(); }, updateAgv(info) { updateAgv(info, obj) { const _this = this return new Promise((resolve) => { // const scale = this.getAutoScale() const left = _this.getXOnImg(info.x) // * scale const top = _this.getYOnImg(info.y) //* scale const angle = info.angle * 180 / Math.PI if (this.agvObj) { this.agvObj.set({ if (obj) { obj.set({ left, top, angle, data: info }); this.agvObj.setCoords() _this.canvas.requestRenderAll(); resolve() obj.setCoords() this.canvas.requestRenderAll(); resolve(obj) } else { const zoom = _this.canvas.getZoom(); fabric.loadSVGFromURL("static/images/van.svg").then( @@ -2489,16 +2512,13 @@ console.log("agv", JSON.stringify(info)) _this.canvas.add(obj) // _this.canvas.bringObjectToFront(obj); _this.agvObj = obj resolve() resolve(obj) } ) } }) }, addVirtualWallShow(info) { const path = info.path || [] if (path.length != 2) @@ -2526,7 +2546,6 @@ }); return line }, addVirtualWall(info) { const path = info.path || [] if (path.length != 2) @@ -2705,18 +2724,7 @@ y: this.getYOnImg(pt.y) } // if (pt.x < 10) { // pt.x = 10 // } // if (pt.y < 10) { // pt.y = 10 // } // if (pt.x > this.workSpace.width - 10) { // pt.x = 10 // } // if (pt.y > this.workSpace.height - 10) { // pt.y = 10 // } if (index > 0) { path2 += ` L${pt2} ${pt2.y}` } else { @@ -2754,18 +2762,6 @@ const path = info.path || [] let path2 = "" path.forEach((pt, index) => { // if (pt.x < 10) { // pt.x = 10 // } // if (pt.y < 10) { // pt.y = 10 // } // if (pt.x > this.workSpace.width - 10) { // pt.x = this.workSpace.width - 10 // } // if (pt.y > this.workSpace.height - 10) { // pt.y = this.workSpace.height - 10 // } let pt2 = { x: this.getXOnImg(pt.x), y: this.getYOnImg(pt.y) @@ -3083,14 +3079,30 @@ updateLaserPoint(param) { let list2 = this.canvas.getObjects() || [] list2 = list2.filter((a) => a.eleType == "laser_point") list2 = list2.filter((a) => a.eleType == "laser_point_cur_group") for (let i in list2) { const obj = list2[i] const objGroup = list2[i] objGroup.set({ eleType: "laser_point_group", }) const list3 = objGroup.getObjects() for (let i3 in list3) { const obj = list3[i3] obj.set({ fill: "#000", fill: "#0000FF", }) } const list = param.xy || [] } const list = param?.xy || [] const objs = [] let right = 0 let bottom = 0 let left = this.mapInfo.img_x let top = this.mapInfo.img_y for (let i in list) { const pt = list[i] const pt2 = { @@ -3098,35 +3110,15 @@ y: this.getYOnImg(pt[1]) } const point = new fabric.Rect({ id: "laser_point", eleType: "laser_point", // id: "laser_point", // eleType: "laser_point", left: pt2.x, top: pt2.y, width: 1, height: 1, fill: "#F5222D", originX: "center", originY: "center", selectable: false, hasControls: true, lockRotation: true, lockScalingX: true, lockScalingY: true, lockMovementX: true, lockMovementY: true, }); // let point = new fabric.Ellipse({ // id: "laser_point", // eleType: "laser_point", // left: pt[0], // top: pt[1], // rx: 2, // ry: 1, // strokeWidth: 1, // stroke: "#F5222D", // fill: "#F5222D", // originX: "center", // originY: "center", originX: "left", originY: "top", // selectable: false, // hasControls: true, // lockRotation: true, @@ -3134,9 +3126,36 @@ // lockScalingY: true, // lockMovementX: true, // lockMovementY: true, // }); this.canvas.add(point) }); objs.push(point) if (left > pt2.x) { left = pt2.x } if (top > pt2.y) { top = pt2.y } if (right < pt2.x + 1) { right = pt2.x + 1 } if (bottom < pt2.y + 1) { bottom = pt2.y + 1 } } //console.log("updateLaserPoint", list.length, left, right,top,bottom) const groupObj = new fabric.Group(objs, { id: `laser_point_group`, eleType: "laser_point_cur_group", left, top, width: right - left, height: bottom - top, // originX: "left", // originY: "top", selectable: false, hasControls: true, }) this.canvas.add(groupObj) }, @@ -3152,28 +3171,19 @@ if (pt.x * zoom < -vpt[4] + offWidth || pt.x * zoom > -vpt[4] + this.eleWidth - offWidth) { if (pt.x * zoom - this.eleWidth / 2 <offWidth) { newPanX = -offWidth } // else if (pt.x * zoom > this.mapInfo.img_x * zoom - 20) { // newPanX = this.mapInfo.img_x * zoom - this.eleWidth + 20 // } else { } else { newPanX = pt.x * zoom - this.eleWidth / 2 } } if (pt.y * zoom < -vpt[5] +offHeight || pt.y * zoom > -vpt[5] + this.eleHeight - (120+offHeight)) { if (pt.y * zoom < -vpt[5] + offHeight || pt.y * zoom > -vpt[5] + this.eleHeight - (120 + offHeight)) { if (pt.y * zoom - this.eleHeight / 2 <offHeight) { newPanY = -offHeight } // else if (pt.y * zoom > this.mapInfo.img_y * zoom - 180) { // newPanY = this.mapInfo.img_y * zoom - this.eleHeight + 180 // } else { } else { newPanY = pt.y * zoom -(this.eleHeight - 120) / 2 } } // console.log("ensurePointVisible2",newPanX,newPanY) // 只有在需要时才平移 if (newPanX !== -vpt[4] || newPanY !== -vpt[5]) { this.canvas.absolutePan({ @@ -3193,44 +3203,58 @@ }, setAllObjectSelectable(selectable) { let flag = false this.canvas.forEachObject(function(obj) { if (obj.canSelect) { if (!obj.flag) { if (obj.selectable != selectable) { flag = true } obj.set({ selectable: selectable, lockEdit: true }) } } }); if (flag) { if (flag) this.canvas.requestRenderAll() } }, receiveMsg(newValue, oldValue) { if (typeof newValue == "undefined") return; const _this = this //console.log("receiveMsg",_this.initFlag) setTimeout(() => { if (!this.canvas) { return } if (_this.initFlag) { _this.handleMsg(newValue, oldValue) } else { setTimeout(() => { _this.receiveMsg(newValue, oldValue) } }, 100) } }, async handleMsg(newValue, oldValue) { const _this = this if (!this.canvas) { return } try { //console.log("handleMsg", newValue) var data = JSON.parse(newValue); // console.log("handleMsg", data.length) const destroyCommand = data.find(item => item.method === "destroy"); if (destroyCommand) { this.destroyCanvas(); return; } for (var i = 0; i < data.length; i++) { const item = data[i] if (item.method == "init") { if (item.param?.editMode) { @@ -3243,7 +3267,20 @@ await _this.setBackground(item.param) } else if (item.method == "update_agv_state") { const info = item.param || {} await _this.updateAgv(info) const obj = _this.agvObj const obj2 = await _this.updateAgv(info, obj) let obj3 = _this.agvObj _this.agvObj = obj2 if (obj && obj2 != obj) { _this.canvas.remove(obj) if (obj3 == obj) obj3 = undefined } if (obj3 && obj2 != obj3) { _this.canvas.remove(obj3) } } else if (item.method == "update_current_teaching") { const info = item.param || [] await _this.updateCurrentTeaching(info) @@ -3257,17 +3294,14 @@ height: 20 } this.ensurePointVisible(pt) } else if (item.method == "move_pt_center") { } else if (item.method == "move_pt_center") { const info2 = item.param || {} const pt = { x: this.getXOnImg(info2.x), y: this.getYOnImg(info2.y) } this.ensurePointCenter(pt) } else if (item.method == "add_station") { } else if (item.method == "add_station") { const stationList = item.param || [] let list = _this.canvas.getObjects() || [] for (let i2 in stationList) { @@ -3322,7 +3356,6 @@ } } } } else if (item.method == "remove_station") { @@ -3341,9 +3374,7 @@ _this.canvas.remove(list[curIndex]) if (tipObj) { _this.canvas.remove(tipObj) } } } @@ -3475,14 +3506,11 @@ _this.setAllObjectSelectable(false) let list = _this.canvas.getObjects() || [] list.forEach((obj) => { if (obj.eleType == "public_teaching" || obj.eleType == "station_teaching") { if (obj.eleType == "public_teaching" || obj.eleType == "station_teaching") { obj.set({ opacity: 1 }) // obj.set({ // hasControls: false, // selectable: false, // }) } else if (obj.eleType == "agv") obj.set({ opacity: 1 @@ -3507,32 +3535,40 @@ } _this.showTeachingPath(_this.showTeachPathFlag ? true : false) } else if (item.method == "clear_teaching_path") { } else if (item.method == "clear_teaching_path") { let list = _this.canvas.getObjects() || [] list = list.filter((a) => a.eleType == "public_teaching" || a.eleType == "station_teaching") list = list.filter((a) => a.eleType == "public_teaching" || a.eleType == "station_teaching") for (let i2 in list) { this.canvas.remove(list[i2]) } } else if (item.method == "public_teaching_path") { } else if (item.method == "public_teaching_path") { const teachingPathList = item.param || [] const teachingPathList = item.param?.list || [] const show = item.param?.show || false for (let i2 in teachingPathList) { const teachingPath = teachingPathList[i2] const id = `public_teaching_${teachingPath.name}` await this.addTeachingPath(teachingPath, id, "public_teaching") const obj = await this.addTeachingPath(teachingPath, id, "public_teaching", show) obj.set({ selectable: show ? true : false, opacity: show ? 1 : 0, }) } } else if (item.method == "station_teaching_path") { const teachingPathList = item.param || [] const show = item.param?.show || false const teachingPathList = item.param?.list || [] for (let i2 in teachingPathList) { const teachingPath = teachingPathList[i2] const id = `station_teaching_${teachingPath.src_dst}` await this.addTeachingPath(teachingPath, id, "station_teaching") const obj = await this.addTeachingPath(teachingPath, id, "station_teaching", show) obj.set({ selectable: show ? true : false, opacity: show ? 1 : 0, }) } } else if (item.method == "show_teaching_path") { _this.showTeachPathFlag = item.param.show @@ -3559,9 +3595,7 @@ const obj = list[curIndex] this.canvas.remove(obj) } } } else if (item.method == "edit_teaching") { const teachingMode = item.param _this.showEditTeachingPath(teachingMode) @@ -3583,7 +3617,6 @@ for (let i2 in wallList) { const wall = wallList[i2] const obj = await _this.addVirtualWall(wall) } } else if (item.method == "wall_list") { const wallList = item.param || [] @@ -3601,8 +3634,6 @@ for (let i2 in regionList) { const region = regionList[i2] const obj = await _this.addRegion(region) } } else if (item.method == "region_list") { const regionList = item.param || [] @@ -3615,7 +3646,6 @@ await _this.addRegionShow(region) } } } else if (item.method == "remove_wall") { const wallList = item.param || [] let list = _this.canvas.getObjects() || [] @@ -3644,6 +3674,7 @@ this.updateLaserPoint(item.param || {}) } } if (_this.canvas) _this.canvas.renderAll() } catch (ex) { console.log(ex) @@ -3685,6 +3716,5 @@ verticalAlign: "center" }); // undefined, "错误" }, }, } } pages/map/scene.vue
@@ -1,15 +1,18 @@ <template> <view class="pages-scene"> <view class="map-content" v-if="opSceneType =='' "> <image class="img" src="/images/image 25.png" alt=" 图片" mode="aspectFit" /> <view class="space">没有找到符合条件的地图</view> <image v-if="opType != 'extend'" class="img" src="/images/image 25.png" alt=" 图片" mode="aspectFit" /> <image v-else class="img" :src="extendBase64Img" alt=" 图片" mode="aspectFit" /> <view v-if="opType != 'extend'" class="space">没有找到符合条件的地图</view> <!-- <view class="loading-view">{{mapserverIsOk?"构图程序准备就绪":"等待构图程序就绪..."}} <view v-if="!mapserverIsOk" class="auto-circle"></view>:disabled="!mapserverIsOk" </view> --> <view class="text-button-group"> <a-button type="primary" class="button" @click="clickStartConstructScene"> 开始构建 {{opType == 'extend'?"开始扩展":'开始构建'}} </a-button> <a-button type="primary" class="button" :disabled="loading && localSceneList.length == 0" @click="clickDownloadScene" disabled> <a-button v-if="opType != 'extend'" type="primary" class="button" :disabled="loading && localSceneList.length == 0" @click="clickDownloadScene" disabled> 下载场景 </a-button> </view> @@ -49,10 +52,10 @@ </view> <view class="bottom-content" v-else-if="opSceneType =='finish'"> <view class="tip">场景构建完成</view> <view> 已成功构建“{{sceneName}}” </view> <view>已成功构建“{{sceneName}}”</view> <!-- <view class="loading-view">{{saveMapIsOk?"构图保存完成":"等待构图保存完成..."}} <view v-if="!saveMapIsOk" class="auto-circle"></view> </view> !saveMapIsOk ||--> <view class="text-button-group"> <a-button type="primary" class="button" :disabled="loading" @click="clickFinish">构建完成</a-button> </view> @@ -81,6 +84,11 @@ //getAgvState, getMapLaserData, saveDBData, checkMapServerIsStart, startOrStopMapServer, checkMapServerIsOk, checkSaveMapIsOk, getMapUrl } from "@/api/vehicle.js" export default { @@ -101,7 +109,11 @@ ctxDataStr: "[]", localSceneList: [], positioningAgv: true, robotPos: {} robotPos: {}, mapserverIsOk: false, extendBase64Img: "", saveMapIsOk: false, destroyFlag: false, } }, @@ -137,6 +149,7 @@ if (res) { this.opSceneType = "" if (this.opType != "") { uni.navigateBack({ delta: 1, //返回层数,2则上上页 }) @@ -147,11 +160,27 @@ return true } else if (this.opSceneType == "finish") { if (this.destroyFlag) { const eventChannel = this.getOpenerEventChannel(); eventChannel.emit('create_finish', this.sceneName); return false } else { this.ctxDataStr = JSON.stringify([{ method: "destroy", }]) return true } } else { if (this.destroyFlag) return false else { this.ctxDataStr = JSON.stringify([{ method: "destroy", }]) return true } } }, @@ -180,6 +209,7 @@ async loadData() { try { // this.loadMapServerState() if (this.opType == "") { this.localSceneList = await this.loadLocalScene() } else { @@ -190,8 +220,19 @@ await addMap(this.ip, this.sceneName, "extend") this.opSceneType = 'scan' } } // if (this.opType == "extend") { // // const infoMap = await this.loadMapInfo(this.sceneName) // // if (infoMap.filedata) { // // var base64Image = infoMap.filedata // // if (base64Image.indexOf("data:image/png;base64,") < 0) { // // base64Image = "data:image/png;base64," + infoMap.filedata // // } // // this.extendBase64Img = base64Image // // } // } } this.refreshMapLaserData() @@ -200,9 +241,81 @@ showError(ex) } }, async loadMapInfo(id) { try { const info = await getMapUrl(this.ip, id) return info } catch (ex) { return {} } }, async loadMapServerState() { try { this.mapserverIsOk = false const res = await checkMapServerIsStart(this.ip) if (res) { this.mapserverIsOk = true } else { this.mapserverIsOk = false const res = await startOrStopMapServer(this.ip, 1) if (res) { this.checkMapServerState() } } } catch (ex) { showError(ex) } }, async checkMapServerState() { try { const res = await checkMapServerIsOk(this.ip) if (res) { this.mapserverIsOk = true } else { this.mapserverIsOk = false setTimeout(this.checkMapServerState, 1000); } } catch (ex) { showError(ex).then((res) => { setTimeout(this.checkMapServerState, 1000); }) } }, async checkSaveMapState() { try { const res = await checkSaveMapIsOk(this.ip) if (res) { this.saveMapIsOk = true } else { this.saveMapIsOk = false setTimeout(this.checkSaveMapState, 1000); } } catch (ex) { showError(ex).then((res) => { setTimeout(this.checkSaveMapState, 1000); }) } }, receiveRenderData(param) { console.log('接收到视图层的数据:', param); if (param.method == "set_backgroud_progress") { if (param.method === "destroy_complete") { if (param.param) { this.destroyFlag = true uni.navigateBack({ delta: 1 }) } } else if (param.method == "set_backgroud_progress") { if (param.type == "start") { this.setData({ bgProgressPercent: 50, @@ -224,14 +337,34 @@ }, 500) } else if (param.type == "error") { console.log("set_backgroud_progress error") this.setData({ bgProgressPercent: 0, bgLoading: false }) const now = new Date() const date = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}` showToast("加载底图失败") const log = { date, method: `POST`, url: "app/log/load_img", param: param.msg, statusCode: 100, data: "加载底图失败" } const listLog = session.getValue("request_log") || [] listLog.unshift(log) session.setValue("request_log", listLog) } } else if (param.method == "cancel_positioning_agv") { this.positioningAgv = false } else if (param.method == "show_log") { const listLog = session.getValue("request_log") || [] listLog.unshift(param.data) session.setValue("request_log", listLog) } }, @@ -244,8 +377,17 @@ return [] } }, clickStartConstructScene() { async clickStartConstructScene() { try { if (this.opType == "extend") { await addMap(this.ip, this.sceneName, "extend") this.opSceneType = 'scan' } else { this.opSceneType = "add_name" } } catch (ex) { showError(ex) } }, async clickDownloadScene() { try { @@ -328,7 +470,10 @@ uni.setNavigationBarTitle({ title: this.sceneName }) this.saveMapIsOk = false await stopMap(this.ip, this.sceneName) // await startOrStopMapServer(this.ip, 2) // this.checkSaveMapState(); if (this.opType == "extend") { this.opSceneType = "" const eventChannel = this.getOpenerEventChannel(); @@ -339,14 +484,10 @@ } } catch (ex) { console.log(ex) showModal("请检查车辆连接,并重新开始构建场景", "场景构建失败", false, "确定").then((res) => { this.opSceneType = '' if (this.opType != "") { uni.navigateBack({ delta: 1, //返回层数,2则上上页 }) } // this.loadMapServerState() }) } finally { this.loading = false @@ -368,14 +509,7 @@ delta: 1, //返回层数,2则上上页 }) } catch (ex) { showModal("请检查车辆连接,并重新开始构建场景", "场景构建失败", false, "确定").then((res) => { this.opSceneType = '' if (this.opType != "") { uni.navigateBack({ delta: 1, //返回层数,2则上上页 }) } }) console.log(ex) } finally { this.loading = false uni.hideLoading() @@ -399,34 +533,49 @@ const data = await this.loadMapLaserData() const listCtrData = [] let newMap = false if (data.base_map?.image_base64) { this.robotPos = {} newMap = true const mapData = data.base_map.image_base64 //this.mapId ?"terdy": this.mapId = data.base_map.map_id listCtrData.push({ method: "background", param: { proportion: 1, img_proportion: 1, max_x: data.base_map.width, max_y: data.base_map.height, max_x: data.base_map.width || 100, max_y: data.base_map.height || 100, min_x: 0, min_y: 0, img_x: data.base_map.width, img_y: data.base_map.height, filedata: data.base_map.image_base64 img_x: data.base_map.width || 100, img_y: data.base_map.height || 100, filedata: mapData } }) } listCtrData.push({ method: "agv_laser", param: data.robot_pose }) listCtrData.push({ method: "point_cloud", param: data.point_cloud }) if (data.robot_pose) { listCtrData.push({ method: "agv_laser", param: data.robot_pose }) if (newMap) { listCtrData.push({ method: "move_pt_center", param: { x: data.robot_pose.x, y: data.robot_pose.y, } }) } else { if (this.positioningAgv) { listCtrData.push({ method: "move_pt_visible", @@ -438,18 +587,21 @@ } }) } } } // console.log("ctxDataStr",listCtrData.length) this.ctxDataStr = JSON.stringify(listCtrData) if (data.robot_pose) { this.robotPos = { x: data.robot_pose.x, y: data.robot_pose.y } } } setTimeout(this.refreshMapLaserData, 1000); } catch (ex) { showError(ex).then((res) => { showToast(ex) setTimeout(this.refreshMapLaserData, 1000); }) } }, async clickVehiclePosition() { @@ -517,6 +669,7 @@ justify-content: center; .text-button-group { display: flex; width: 100%; @@ -533,6 +686,32 @@ } .loading-view { display: flex; flex-direction: row; .auto-circle { margin-left: 20rpx; width: 50rpx; height: 50rpx; border-radius: 50%; border: 10rpx solid #1890FF; border-top-color: transparent; animation: drawCircle 1s infinite linear; } @keyframes drawCircle { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } } .bottom { position: fixed; pages/map/task.vue
@@ -320,6 +320,8 @@ margin-top: 75px; margin-left: 120px; width: 150px; max-height: 50vh; overflow: auto; align-items: center; justify-content: center; flex-direction: column; pages/my/help-feedback.vue
@@ -1,31 +1,33 @@ <template> <view class="pages-my"> <view class="group"> <view class="item line" @click="clickRemoteAssistance"> <view class="item line"> <view>远程协助:</view> <view class="right"></view> <a> <a @click="clickRemoteAssistance"> <uni-icons class="icon" type="right" size="24" color="#888"></uni-icons> </a> </view> <view class="item line" @click="clickUploadLog"> <view class="item line"> <view>日志上传:</view> <view class="right"></view> <a> <a @click="clickUploadLog"> <uni-icons class="icon" type="right" size="24" color="#888"></uni-icons> </a> </view> <view class="item line" @click="clickViewInstruction"> <view class="item line"> <view>查看说明书:</view> <view class="right"></view> <a> <a @click="clickViewInstruction"> <uni-icons class="icon" type="right" size="24" color="#888"></uni-icons> </a> </view> <view class="item line" @click="clickApiLog"> <view class="item line"> <view>接口日志:</view> <switch :checked="withLog" style="transform:scale(0.7)" @change="switchChangeLog"/>{{withLog?"记录接口日志":"不记录接口日志"}} <view class="right"></view> <a> <a @click="clickApiLog"> <uni-icons class="icon" type="right" size="24" color="#888"></uni-icons> </a> </view> @@ -48,7 +50,7 @@ }, data() { return { withLog: getApp().globalData.withLog || false } }, onLoad() { @@ -58,6 +60,11 @@ }, methods: { switchChangeLog(e) { this.withLog = e.detail.value getApp().globalData.withLog =this.withLog session.setValue("write_log",this.withLog ? 1:0) }, clickRemoteAssistance() { showToast("暂未实现") pages/my/index.vue
@@ -32,7 +32,7 @@ </view> --> <view class="item line" @click="clickClearCache"> <view>清楚缓存:</view> <view>清除缓存:</view> <view class="right">{{cacheSizeStr}}</view> <a > <uni-icons class="icon" type="right" size="24" color="#888"></uni-icons>