import scss from "./grid-svg/variables.scss"; import scssCanvas from "./grid-canvas/variables-canvas.scss"; export function getScss(type) { if (type === "canvas") { return scssCanvas; } else { return scss; } } export const COMMON_CONST = { idSep: "-", MAIN_TRACK_DIR: { DEFAULT: 0, // 支架的方向 HORIZONTAL: 0, // 横 VERTICAL: 1, // 纵 }, }; export const LOCTYPE = { default: "default", rack: "rack", around: "around", }; export const ITEM_ATTRIBUTE_TYPE = { storageLoc: "storageLoc", dev: "dev", sysSet: "sysSet", }; export const ITEMSTATUS = { default: "default", storageLoc: "storageLoc", shuttle: "shuttle", path: "path", pathHasDrived: "pathHasDrived", xTrack: "xTrack", xTrackEx: "xTrackEx", carriageway: "carriageway", lift: "lift", unExist: "unExist", unUse: "unUse", charge: "charge", entranceAndExit: "entranceAndExit", park: "park", transport: "transport", pillar: "pillar", goods: "goods", }; export const getCFG = (type) => { const scss = getScss(type); return { baseItemStsArr: [ { key: "default", name: "默认", //用于给默认样式 displayControl: { isNotShowInCfg: true, // 不在任何配置中显示 }, sty: { fillColor: scss[ITEMSTATUS.default], borderColor: scss["borderColor"], lineWidth: 1, }, }, { key: "shuttle", name: "四向车", displayControl: { isNotShowInCfg: true, // 不在任何配置中显示 }, sty: { fillColor: scss[ITEMSTATUS.shuttle], }, }, { key: "path", name: "路线", displayControl: { isNotShowInCfg: true, // 不在任何配置中显示 }, sty: { fillColor: scss[ITEMSTATUS.path], lineWidth: 2, }, }, { key: "pathHasDrived", name: "路线", displayControl: { isNotShowInCfg: true, // 不在任何配置中显示 }, sty: { fillColor: scss[ITEMSTATUS.pathHasDrived], lineWidth: 2, }, }, { key: "goods", name: "货物", displayControl: { isNotShowInCfg: true, // 不在任何配置中显示 }, sty: { fillColor: scss[ITEMSTATUS.goods], lineWidth: 1, }, }, { key: "xTrack", name: "主轨道", disableSwitchIsByFloor: true, handleMouseMove: function (e) { return false; }, sty: { fillColor: scss[ITEMSTATUS.xTrack], }, cfgTable: { isNotApplyToOtherFloor: true, isNotApplyToTotalRow: true, isNotApplyToTotalCol: true, columnsCfgArr: function (formData) { if (!formData.mainTrackDir) { return [ { prop: "r", label: "行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, ]; } else { return [ { prop: "c", label: "列", type: "number", template: true, inputProps: { placeholder: "", type: "number", maxWidth: 100, }, }, ]; } }, toPageDataFun: function (formData) { let res = []; if (formData[ITEMSTATUS.xTrack]) { formData[ITEMSTATUS.xTrack].forEach((item) => { let ele = { c: undefined, r: undefined, f: undefined }; if (!item.mainTrackDir) { ele.r = item; } else { ele.c = item; } res.push(ele); }); } return res; }, toBackDataFun: function (formData, cfgTableData) { let res = []; if (cfgTableData.length > 0) { cfgTableData.forEach((item) => { if (!formData.mainTrackDir) { res.push(item.r); } else { res.push(item.c); } }); } return res; }, }, cellSelPanel: { procItemDataFun: function (that) { const uniqueRowsOrCols = that.getUniqueRowsOrCols(); return that.getOperItemsForLine(uniqueRowsOrCols); }, }, }, { key: "xTrackEx", name: "拓展主轨道", sty: { fillColor: scss[ITEMSTATUS.xTrack], }, displayControl: { isNotShowInCfgCellSel: true, }, }, { key: "carriageway", backKey: "yTrack", name: "行车道", sty: { fillColor: scss[ITEMSTATUS.carriageway], }, }, { key: "lift", name: "提升机", disableSwitchIsByFloor: true, displayControl: { isNotShowInCfgCellSel: true, }, sty: { fillColor: scss[ITEMSTATUS.lift], }, cfgTable: { isNotApplyToOtherFloor: true, isNotApplyToTotalRow: true, isNotApplyToTotalCol: true, columnsCfgArr: function (formData) { return [ { prop: "did", label: "did", template: true, }, { prop: "c", label: "列", type: "number", template: true, inputProps: { placeholder: "", type: "number", }, }, { prop: "r", label: "行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "max_floor", label: "最大层", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "rS", label: "起始行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "rE", label: "结束行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "cS", label: "起始列", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "cE", label: "结束列", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, ]; }, }, }, { key: "unUse", // backKey: 'unUse', name: "不可用", sty: { fillColor: scss[ITEMSTATUS.unUse], }, }, { key: "unExist", // backKey: 'unExist', name: "不存在", sty: { fillColor: scss[ITEMSTATUS.unExist], }, }, { key: "park", name: "停车位", sty: { fillColor: scss[ITEMSTATUS.park], }, }, { key: "charge", name: "充电桩", backKey: "charger", itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev, sty: { fillColor: scss[ITEMSTATUS.charge], width: 6, }, cfgTable: { columnsCfgArr: function (formData) { return [ { prop: "did", label: "did", template: true, }, { prop: "c", label: "列", type: "number", template: true, inputProps: { placeholder: "", type: "number", }, }, { prop: "r", label: "行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "f", label: "层", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, ]; }, }, drawFun: function (that, col) { const ctx = that.ctx; ctx.save(); // 设置填充颜色 ctx.fillStyle = this.sty.fillColor; // 获取坐标 const { x1, y1, x2, y2, x3, y3, x4, y4 } = that.calculateCoordinates(col); // 计算矩形的宽度和位置 const width = x2 - x1; const rectHeight = this.sty.width || 6; // 使用配置的宽度,默认为6 // 在顶部绘制矩形 ctx.fillRect(x1, y1, width, rectHeight); ctx.restore(); return true; }, drawFunSvg: function (that, col) { const group = that.createSvgElement("g"); // 获取坐标和倾斜角度 const { x1, y1, x2, y2, x3, y3, x4, y4 } = that.component.calculateCoordinates(col); const angle = that.component.includedAngle || 90; const angleInRadians = (angle * Math.PI) / 180; // 计算充电桩的高度 const rectHeight = this.sty.width || 6; // 计算平行四边形的四个顶点 // a点和b点就是原始的x1,y1和x2,y2 const ax = x1; const ay = y1; const bx = x2; const by = y2; // 计算单元格的倾斜向量 const cellVectorX = x4 - x1; const cellVectorY = y4 - y1; const cellLength = Math.sqrt( cellVectorX * cellVectorX + cellVectorY * cellVectorY ); // 计算单位向量 const unitVectorX = cellVectorX / cellLength; const unitVectorY = cellVectorY / cellLength; // 使用单元格的倾斜方向计算偏移量 const offsetX = rectHeight * unitVectorX; const offsetY = rectHeight * unitVectorY; // 计算c点和d点 const dx = ax + offsetX; const dy = ay + offsetY; const cx = bx + offsetX; const cy = by + offsetY; // 创建平行四边形 const rect = that.createSvgElement("polygon", { points: `${ax},${ay} ${bx},${by} ${cx},${cy} ${dx},${dy}`, fill: this.sty.fillColor, stroke: "none", }); group.appendChild(rect); that.mainGroup.appendChild(group); return true; }, }, { key: "transport", backKey: "conveyor", name: "输送机", itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev, sty: { fillColor: scss[ITEMSTATUS.transport], borderColor: scss[ITEMSTATUS.transport + "BorderColor"], borderWidth: 4, }, cfgTable: { isNotApplyToOtherFloor: true, isNotApplyToTotalRow: true, isNotApplyToTotalCol: true, columnsCfgArr: function (formData) { return [ { prop: "did", label: "did", template: true, }, { prop: "c", label: "列", type: "number", template: true, inputProps: { placeholder: "", type: "number", }, }, { prop: "r", label: "行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "f", label: "层", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "rS", label: "起始行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "rE", label: "结束行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "cS", label: "起始列", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "cE", label: "结束列", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, ]; }, }, drawFun: function (that, col) { const ctx = that.ctx; ctx.save(); // 设置填充和边框颜色 ctx.fillStyle = this.sty.fillColor; ctx.strokeStyle = this.sty.borderColor; const borderWidth = this.sty.borderWidth; const offset = borderWidth / 2; // 获取外部轮廓坐标 const { x1, y1, x2, y2, x3, y3, x4, y4 } = that.calculateCoordinates(col); // 计算内部偏移量 const dx = ((x2 - x1) * offset) / Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2); const dy = ((y2 - y1) * offset) / Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2); // 计算内部轮廓坐标 const ix1 = x1 + dx; const iy1 = y1 + dy; const ix2 = x2 - dx; const iy2 = y2 + dy; const ix3 = x3 - dx; const iy3 = y3 - dy; const ix4 = x4 + dx; const iy4 = y4 - dy; // 绘制主体形状 ctx.beginPath(); ctx.moveTo(ix1, iy1); ctx.lineTo(ix2, iy2); ctx.lineTo(ix3, iy3); ctx.lineTo(ix4, iy4); ctx.closePath(); ctx.fill(); // 绘制左边框 ctx.beginPath(); ctx.lineWidth = borderWidth; ctx.moveTo(ix1, iy1); ctx.lineTo(ix4, iy4); ctx.stroke(); // 绘制右边框 ctx.beginPath(); ctx.moveTo(ix2, iy2); ctx.lineTo(ix3, iy3); ctx.stroke(); ctx.restore(); return true; }, drawFunSvg: function (that, col) { const group = that.createSvgElement("g"); // 获取坐标和计算偏移量 const { x1, y1, x2, y2, x3, y3, x4, y4 } = that.component.calculateCoordinates(col); const borderWidth = this.sty.borderWidth || 4; const offset = borderWidth / 2; // 计算倾斜角度 const angle = that.component.includedAngle || 90; const angleInRadians = (angle * Math.PI) / 180; // 根据倾斜角度调整右侧偏移量,使视觉效果一致 const rightOffset = offset / Math.sin(angleInRadians); // 计算内部轮廓坐标 const ix1 = x1 + offset; const iy1 = y1; const ix2 = x2 - rightOffset; const iy2 = y2; const ix3 = x3 - rightOffset; const iy3 = y3; const ix4 = x4 + offset; const iy4 = y4; // 创建外部轮廓(左侧平行四边形) const leftPolygon = that.createSvgElement("polygon", { points: `${x1},${y1} ${ix1},${iy1} ${ix4},${iy4} ${x4},${y4}`, fill: this.sty.borderColor, stroke: "none", }); // 创建外部轮廓(右侧平行四边形) const rightPolygon = that.createSvgElement("polygon", { points: `${x2},${y2} ${ix2},${iy2} ${ix3},${iy3} ${x3},${y3}`, fill: this.sty.borderColor, stroke: "none", }); // 应用偏移量到所有多边形 [leftPolygon, rightPolygon].forEach((polygon) => { const points = polygon.getAttribute("points"); const offsetPoints = points .split(" ") .map((point) => { const [x, y] = point.split(","); return `${parseFloat(x)},${parseFloat(y)}`; }) .join(" "); polygon.setAttribute("points", offsetPoints); }); group.appendChild(leftPolygon); // 左边框 group.appendChild(rightPolygon); // 右边框 that.mainGroup.appendChild(group); return true; }, getTheTargetStsWhenCfg: function (that, ele) { if (ele.statusList && Array.isArray(ele.statusList)) { // 检查 statusList 中是否存在 this.key 的状态 const existingStatus = ele.statusList.find( (item) => item.status === this.key ); return existingStatus ? "" : this.key; } return this.key; }, }, { key: "entranceAndExit", name: "出入口", itemAttributeType: ITEM_ATTRIBUTE_TYPE.sysSet, displayControl: { isNotShowInCfgCellSel: true, }, paramInfoArr: [ { type: "radio", defaultVal: "", paramKeyVal: "type", options: [ { label: "出入口", value: "" }, { label: "出口", value: "exit" }, { label: "入口", value: "entrance" }, ], }, ], paramToMergeObj: { type: "", arrowFlow: 0, }, sty: { arrowFillColor: scss["arrowColor"], arrowStrokeColor: scss["arrowColor"], arrowLineWidth: 1, }, getTheTargetStsWhenCfg: function (that, ele) { if (ele.statusList && Array.isArray(ele.statusList)) { // 检查 statusList 中是否存在 this.key 的状态 const existingStatus = ele.statusList.find( (item) => item.status === this.key ); const isDisItemSts = existingStatus && (!that.paramToMergeObj.type || (existingStatus.paramToMergeObj && existingStatus.paramToMergeObj.arrowFlow === 1)); return isDisItemSts ? "" : this.key; } return this.key; }, handleDoubleClick: function (e) { return false; }, handleMouseMove: function (e) { return false; }, drawFun: function (that, col) { let arrowType; const isHorizontal = that.isHorizontal(); const angle = that.rotationAngleType || 0; // mergeObj.type = 'exit' //TEST if (col.type === "exit") { if (isHorizontal) { switch (angle) { case 0: arrowType = "down"; break; case 1: arrowType = "left"; break; case 2: arrowType = "up"; break; case 3: arrowType = "right"; break; } } else { switch (angle) { case 0: arrowType = "left"; break; case 1: arrowType = "up"; break; case 2: arrowType = "right"; break; case 3: arrowType = "down"; break; } } } else if (col.type === "entrance") { if (isHorizontal) { switch (angle) { case 0: arrowType = "up"; break; case 1: arrowType = "right"; break; case 2: arrowType = "down"; break; case 3: arrowType = "left"; break; } } else { switch (angle) { case 0: arrowType = "right"; break; case 1: arrowType = "down"; break; case 2: arrowType = "left"; break; case 3: arrowType = "up"; break; } } } else { // 双向箭头的情况保持不变 if (angle === 1 || angle === 3) { arrowType = isHorizontal ? "bidirectional-h" : "bidirectional-v"; } else { arrowType = isHorizontal ? "bidirectional-v" : "bidirectional-h"; } } if (col.type && col.arrowFlow === 1) { const reverseMap = { up: "down", down: "up", left: "right", right: "left", }; arrowType = reverseMap[arrowType] || arrowType; } that.ctx.fillStyle = this.sty.arrowFillColor; that.ctx.strokeStyle = this.sty.arrowStrokeColor; that.ctx.lineWidth = this.sty.arrowLineWidth; const coordinates = that.calculateCoordinates(col); drawArrow(that.ctx, coordinates, arrowType); return "entranceAndExit-drawFun"; }, drawFunSvg: function (that, col) { const group = that.createSvgElement("g"); let arrowType; const isHorizontal = that.component.isHorizontal(); const angle = that.component.rotationAngleType || 0; // 确定箭头类型 if (col.type === "exit") { if (isHorizontal) { switch (angle) { case 0: arrowType = "down"; break; case 1: arrowType = "left"; break; case 2: arrowType = "up"; break; case 3: arrowType = "right"; break; } } else { switch (angle) { case 0: arrowType = "left"; break; case 1: arrowType = "up"; break; case 2: arrowType = "right"; break; case 3: arrowType = "down"; break; } } } else if (col.type === "entrance") { if (isHorizontal) { switch (angle) { case 0: arrowType = "up"; break; case 1: arrowType = "right"; break; case 2: arrowType = "down"; break; case 3: arrowType = "left"; break; } } else { switch (angle) { case 0: arrowType = "right"; break; case 1: arrowType = "down"; break; case 2: arrowType = "left"; break; case 3: arrowType = "up"; break; } } } else { if (angle === 1 || angle === 3) { arrowType = isHorizontal ? "bidirectional-h" : "bidirectional-v"; } else { arrowType = isHorizontal ? "bidirectional-v" : "bidirectional-h"; } } if (col.type && col.arrowFlow === 1) { const reverseMap = { up: "down", down: "up", left: "right", right: "left", }; arrowType = reverseMap[arrowType] || arrowType; } // 获取坐标 const { x1, y1, x2, y2, x3, y3, x4, y4 } = that.component.calculateCoordinates(col); const centerX = (x1 + x2 + x3 + x4) / 4; const centerY = (y1 + y2 + y3 + y4) / 4; const width = Math.max(x2 - x1, x3 - x4); const height = Math.max(y4 - y1, y3 - y2); // 基准尺寸 const BASE_SIZE = { arrowWidth: 16, // 减小箭头宽度,使其更协调 arrowLength: 10, // 减小箭头长度,保持比例 bodyThickness: 6, // 减小主体厚度,使其更精致 }; // 计算缩放比例 const minDimension = Math.min(width, height); const scale = minDimension / 30; // 调整基准缩放比例 const arrowWidth = BASE_SIZE.arrowWidth * scale; const arrowLength = BASE_SIZE.arrowLength * scale; const bodyThickness = BASE_SIZE.bodyThickness * scale; // 创建箭头路径 let pathData = ""; switch (arrowType) { case "bidirectional-h": { const bodyWidth = Math.min(width * 0.5, width - 2 * arrowLength); pathData = ` M ${centerX - bodyWidth / 2} ${centerY - bodyThickness / 2} L ${centerX + bodyWidth / 2} ${centerY - bodyThickness / 2} L ${centerX + bodyWidth / 2} ${centerY + bodyThickness / 2} L ${centerX - bodyWidth / 2} ${centerY + bodyThickness / 2} Z M ${centerX - bodyWidth / 2} ${centerY - arrowWidth / 2} L ${centerX - bodyWidth / 2 - arrowLength} ${centerY} L ${centerX - bodyWidth / 2} ${centerY + arrowWidth / 2} Z M ${centerX + bodyWidth / 2} ${centerY - arrowWidth / 2} L ${centerX + bodyWidth / 2 + arrowLength} ${centerY} L ${centerX + bodyWidth / 2} ${centerY + arrowWidth / 2} Z `; break; } case "bidirectional-v": { const bodyHeight = Math.min( height * 0.5, height - 2 * arrowLength ); pathData = ` M ${centerX - bodyThickness / 2} ${centerY - bodyHeight / 2} L ${centerX + bodyThickness / 2} ${centerY - bodyHeight / 2} L ${centerX + bodyThickness / 2} ${centerY + bodyHeight / 2} L ${centerX - bodyThickness / 2} ${centerY + bodyHeight / 2} Z M ${centerX - arrowWidth / 2} ${centerY - bodyHeight / 2} L ${centerX} ${centerY - bodyHeight / 2 - arrowLength} L ${centerX + arrowWidth / 2} ${centerY - bodyHeight / 2} Z M ${centerX - arrowWidth / 2} ${centerY + bodyHeight / 2} L ${centerX} ${centerY + bodyHeight / 2 + arrowLength} L ${centerX + arrowWidth / 2} ${centerY + bodyHeight / 2} Z `; break; } case "down": { const bodyHeight = height * 0.5; pathData = ` M ${centerX - bodyThickness / 2} ${centerY - bodyHeight / 2} L ${centerX + bodyThickness / 2} ${centerY - bodyHeight / 2} L ${centerX + bodyThickness / 2} ${centerY + bodyHeight / 2} L ${centerX + arrowWidth / 2} ${centerY + bodyHeight / 2} L ${centerX} ${Math.min( centerY + bodyHeight / 2 + arrowLength, y4 )} L ${centerX - arrowWidth / 2} ${centerY + bodyHeight / 2} L ${centerX - bodyThickness / 2} ${centerY + bodyHeight / 2} Z `; break; } case "left": { const bodyWidth = width * 0.5; pathData = ` M ${centerX - bodyWidth / 2} ${centerY - bodyThickness / 2} L ${centerX + bodyWidth / 2} ${centerY - bodyThickness / 2} L ${centerX + bodyWidth / 2} ${centerY + bodyThickness / 2} L ${centerX - bodyWidth / 2} ${centerY + bodyThickness / 2} Z M ${centerX - bodyWidth / 2} ${centerY - arrowWidth / 2} L ${Math.max( centerX - bodyWidth / 2 - arrowLength, x1 )} ${centerY} L ${centerX - bodyWidth / 2} ${centerY + arrowWidth / 2} Z `; break; } case "up": { const bodyHeight = height * 0.5; pathData = ` M ${centerX - bodyThickness / 2} ${centerY - bodyHeight / 2} L ${centerX + bodyThickness / 2} ${centerY - bodyHeight / 2} L ${centerX + bodyThickness / 2} ${centerY + bodyHeight / 2} L ${centerX - bodyThickness / 2} ${centerY + bodyHeight / 2} Z M ${centerX - arrowWidth / 2} ${centerY - bodyHeight / 2} L ${centerX} ${Math.max( centerY - bodyHeight / 2 - arrowLength, y1 )} L ${centerX + arrowWidth / 2} ${centerY - bodyHeight / 2} Z `; break; } case "right": { const bodyWidth = width * 0.5; pathData = ` M ${centerX - bodyWidth / 2} ${centerY - bodyThickness / 2} L ${centerX + bodyWidth / 2} ${centerY - bodyThickness / 2} L ${centerX + bodyWidth / 2} ${centerY - arrowWidth / 2} L ${Math.min( centerX + bodyWidth / 2 + arrowLength, x2 )} ${centerY} L ${centerX + bodyWidth / 2} ${centerY + arrowWidth / 2} L ${centerX + bodyWidth / 2} ${centerY + bodyThickness / 2} L ${centerX - bodyWidth / 2} ${centerY + bodyThickness / 2} Z `; break; } } // 创建SVG路径元素 const path = that.createSvgElement("path", { d: pathData, fill: this.sty.arrowFillColor, stroke: "none", // 移除描边,使外观更清晰 transform: `rotate(${that.component.includedAngle}, ${centerX}, ${centerY})`, // 添加旋转变换 }); group.appendChild(path); that.mainGroup.appendChild(group); return "entranceAndExit-drawFunSvg"; }, cfgTable: { toBackDataFun: function (formData, cfgTableData) { let res = []; if (cfgTableData.length > 0) { cfgTableData.forEach((item) => { if (item.type !== "exit" && item.type !== "entrance") { item.type = ""; res.push(item); } }); } return res; }, }, }, { key: "storageLoc", name: "货位", noToBackData: true, displayControl: { isNotShowInCfgPanel: true, // 不在按钮配置面板显示 }, sty: { fillColor: scss[ITEMSTATUS.storageLoc], }, }, { key: "digitalInput", name: "光电", itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev, displayControl: { isNotShowInCfgCellSel: true, }, cfgTable: { columnsCfgArr: function (formData) { return [ { prop: "did", label: "did", template: true, }, { prop: "c", label: "列", type: "number", template: true, inputProps: { placeholder: "", type: "number", }, }, { prop: "r", label: "行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "f", label: "层", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, ]; }, }, drawFun: function (that, col) { return true; }, }, { key: "narrowGate", name: "限宽门", itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev, displayControl: { isNotShowInCfgCellSel: true, }, cfgTable: { columnsCfgArr: function (formData) { return [ { prop: "did", label: "did", template: true, }, { prop: "c", label: "列", type: "number", template: true, inputProps: { placeholder: "", type: "number", }, }, { prop: "r", label: "行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "f", label: "层", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, ]; }, }, drawFun: function (that, col) { return true; }, }, { key: "codeScanners", name: "扫码器", backKey: "codeScanner", itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev, displayControl: { isNotShowInCfgCellSel: true, }, cfgTable: { columnsCfgArr: function (formData) { return [ { prop: "did", label: "did", template: true, }, { prop: "c", label: "列", type: "number", template: true, inputProps: { placeholder: "", type: "number", }, }, { prop: "r", label: "行", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, { prop: "f", label: "层", type: "number", template: true, inputProps: { type: "number", placeholder: "", }, }, ]; }, }, drawFun: function (that, col) { return true; }, }, { key: LOCTYPE.around, LOCTYPE: LOCTYPE.around, name: "货架外围", //用于给默认样式 locType: LOCTYPE.around, noToBackData: true, disableSwitchIsByFloor: true, sty: { btnStyle: { noIcon: true, }, fillColor: scss[LOCTYPE.around], // numSty:{ // cellNumFontColor:'white' // } }, paramInfoArr: [ { type: "input", defaultVal: "", paramKeyVal: "up", dataType: "number", label: "上", rules: [ { type: "number", min: 0, message: "请输入大于等于0的整数", trigger: "blur", }, ], }, { type: "input", defaultVal: "", paramKeyVal: "down", dataType: "number", label: "下", rules: [ { type: "number", min: 0, message: "请输入大于等于0的整数", trigger: "blur", }, ], }, { type: "input", defaultVal: "", paramKeyVal: "left", label: "左", dataType: "number", rules: [ { type: "number", min: 0, message: "请输入大于等于0的整数", trigger: "blur", }, ], }, { type: "input", defaultVal: "", paramKeyVal: "right", label: "右", dataType: "number", rules: [ { type: "number", min: 0, message: "请输入大于等于0的整数", trigger: "blur", }, ], }, ], // 添加合并参数对象 paramToMergeObj: { up: undefined, down: undefined, left: undefined, right: undefined, }, updateFormDataAround: function (formData) { if (!formData.around) { formData.around = {}; } Object.keys(this.paramToMergeObj).forEach((key) => { formData.around[key] = this.paramToMergeObj[key]; }); }, validateWheConfirmCfg: function (formData, that) { // 从this.paramToMergeObj获取参数 if (!this.paramToMergeObj) { console.warn("paramToMergeObj is missing"); return true; } // 获取旋转角度 const rotation = formData.rotation || 0; // 计算实际的起始行列 let rowStart, colStart; switch (rotation) { case 0: // 0度 rowStart = this.paramToMergeObj.down || 0; colStart = this.paramToMergeObj.left || 0; break; case 1: // 90度 rowStart = this.paramToMergeObj.left || 0; colStart = this.paramToMergeObj.up || 0; break; case 2: // 180度 rowStart = this.paramToMergeObj.up || 0; colStart = this.paramToMergeObj.right || 0; break; case 3: // 270度 rowStart = this.paramToMergeObj.right || 0; colStart = this.paramToMergeObj.down || 0; break; default: rowStart = this.paramToMergeObj.down || 0; colStart = this.paramToMergeObj.left || 0; } // 检查是否在有效范围内 if (rowStart < 0 || rowStart > formData.rowStart) { switch (rotation) { case 0: // 0度 that.$message.error( "下侧增加的外围数量超出仓库范围!请调整rowStart或外围下侧数量" ); break; case 1: // 90度 that.$message.error( "左侧增加的外围数量超出仓库范围!请调整rowStart或外围左侧数量" ); break; case 2: // 180度 that.$message.error( "上侧增加的外围数量超出仓库范围!请调整rowStart或外围上侧数量" ); break; case 3: // 270度 that.$message.error( "右侧增加的外围数量超出仓库范围!请调整rowStart或外围右侧数量" ); break; default: that.$message.error( "下侧增加的外围数量超出仓库范围!请调整rowStart或外围下侧数量" ); break; } return true; } if (colStart < 0 || colStart > formData.colStart) { switch (rotation) { case 0: // 0度 that.$message.error( "左侧增加的外围数量超出仓库范围!请调整colStart或外围左侧数量" ); break; case 1: // 90度 that.$message.error( "上侧增加的外围数量超出仓库范围!请调整colStart或外围上侧数量" ); break; case 2: // 180度 that.$message.error( "右侧增加的外围数量超出仓库范围!请调整colStart或外围右侧数量" ); break; case 3: // 270度 that.$message.error( "下侧增加的外围数量超出仓库范围!请调整colStart或外围下侧数量" ); break; default: that.$message.error( "左侧增加的外围数量超出仓库范围!请调整colStart或外围左侧数量" ); break; } return true; } return false; }, confirmCfg: function (formData, that) { if (!this.paramToMergeObj) { return; } this.updateFormDataAround(formData); that.$emit("operCfg", { operType: "chgAroundBasicInfo", operItemStsObj: this, formData, }); }, cancelCfg: function (formData, that) { this.paramToMergeObj = JSON.parse( JSON.stringify(this.paramToMergeObjStore) ); this.updateFormDataAround(formData); that.$emit("operCfg", { operType: "chgAroundBasicInfo", operItemStsObj: this, formData, }); }, resetCfg: function (formData, that) { this.paramToMergeObj.left = 0; this.paramToMergeObj.right = 0; this.paramToMergeObj.up = 0; this.paramToMergeObj.down = 0; this.paramToMergeObjStore = JSON.parse( JSON.stringify(this.paramToMergeObj) ); this.updateFormDataAround(formData); that.$emit("operCfg", { operType: "chgAroundBasicInfo", operItemStsObj: this, formData, }); }, handleClick: function (e) { return false; }, handleDoubleClick: function (e) { return false; }, handleMouseMove: function (e) { return false; }, }, { key: "exStorage", name: "外围货位", displayControl: { isNotShowInCfgCellSel: true, }, sty: { fillColor: scss[ITEMSTATUS.storageLoc], }, }, ], cellSty: { cellLen: 20, cellWidth: 52, cellNumFont: "12px Arial", cellNumFontColor: "#333333", widthForFlrNum1: 18, cellXOffset: 4, widthColInd2: 24, cellYOffset: 14, cellMinLen: 12, cellMaxLen: 40, rackIdxNumOffsetLen: 24, rackIdxNumFont: "12px Arial", rackIdxNumFontColor: "#666", rackIdxNumSideYPadding: 8, //考虑文字居中渲染 rackIdxNumSideXPadding: 0, }, }; }; /** * 绘制箭头 * @param {CanvasRenderingContext2D} ctx - Canvas上下文 * @param {Object} coordinates - 坐标点对象 { x1, y1, x2, y2, x3, y3, x4, y4 } * @param {string} type - 箭头类型:'bidirectional-h','bidirectional-v','right','left','up','down' */ function drawArrow(ctx, coordinates, type) { const { x1, y1, x2, y2, x3, y3, x4, y4 } = coordinates; const centerX = (x1 + x2 + x3 + x4) / 4; const centerY = (y1 + y2 + y3 + y4) / 4; const width = Math.max(x2 - x1, x3 - x4); const height = Math.max(y4 - y1, y3 - y2); // 调整基准尺寸,使其更适合小格子 const BASE_SIZE = { arrowWidth: 24, // 减小箭头宽度 arrowLength: 12, // 减小箭头长度 bodyThickness: 10, // 减小主体厚度 }; // 计算缩放比例,确保箭头完整显示 const minDimension = Math.min(width, height); const scale = minDimension / 40; // 移除最小值限制,让箭头始终按比例缩放 const arrowWidth = BASE_SIZE.arrowWidth * scale; const arrowLength = BASE_SIZE.arrowLength * scale; const bodyThickness = BASE_SIZE.bodyThickness * scale; switch (type) { case "bidirectional-h": { const bodyWidth = Math.min(width * 0.4, width - 2 * arrowLength); ctx.beginPath(); // 主体矩形 ctx.moveTo(centerX - bodyWidth / 2, centerY - bodyThickness / 2); ctx.lineTo(centerX + bodyWidth / 2, centerY - bodyThickness / 2); ctx.lineTo(centerX + bodyWidth / 2, centerY + bodyThickness / 2); ctx.lineTo(centerX - bodyWidth / 2, centerY + bodyThickness / 2); // 左侧箭头 ctx.moveTo(centerX - bodyWidth / 2, centerY - arrowWidth / 2); ctx.lineTo(centerX - bodyWidth / 2 - arrowLength, centerY); ctx.lineTo(centerX - bodyWidth / 2, centerY + arrowWidth / 2); // 右侧箭头 ctx.moveTo(centerX + bodyWidth / 2, centerY - arrowWidth / 2); ctx.lineTo(centerX + bodyWidth / 2 + arrowLength, centerY); ctx.lineTo(centerX + bodyWidth / 2, centerY + arrowWidth / 2); break; } case "bidirectional-v": { const bodyHeight = Math.min(height * 0.4, height - 2 * arrowLength); ctx.beginPath(); // 主体矩形 ctx.moveTo(centerX - bodyThickness / 2, centerY - bodyHeight / 2); ctx.lineTo(centerX + bodyThickness / 2, centerY - bodyHeight / 2); ctx.lineTo(centerX + bodyThickness / 2, centerY + bodyHeight / 2); ctx.lineTo(centerX - bodyThickness / 2, centerY + bodyHeight / 2); // 上箭头 ctx.moveTo(centerX - arrowWidth / 2, centerY - bodyHeight / 2); ctx.lineTo(centerX, centerY - bodyHeight / 2 - arrowLength); ctx.lineTo(centerX + arrowWidth / 2, centerY - bodyHeight / 2); // 下箭头 ctx.moveTo(centerX - arrowWidth / 2, centerY + bodyHeight / 2); ctx.lineTo(centerX, centerY + bodyHeight / 2 + arrowLength); ctx.lineTo(centerX + arrowWidth / 2, centerY + bodyHeight / 2); break; } case "down": { const bodyHeight = height * 0.4; ctx.beginPath(); // 主体矩形 ctx.moveTo(centerX - bodyThickness / 2, centerY - bodyHeight / 2); ctx.lineTo(centerX + bodyThickness / 2, centerY - bodyHeight / 2); ctx.lineTo(centerX + bodyThickness / 2, centerY + bodyHeight / 2); ctx.lineTo(centerX + arrowWidth / 2, centerY + bodyHeight / 2); // 箭头 ctx.lineTo(centerX, Math.min(centerY + bodyHeight / 2 + arrowLength, y4)); // 确保不超出底部边界 ctx.lineTo(centerX - arrowWidth / 2, centerY + bodyHeight / 2); ctx.lineTo(centerX - bodyThickness / 2, centerY + bodyHeight / 2); break; } case "left": { const bodyWidth = width * 0.4; ctx.beginPath(); // 主体矩形 ctx.moveTo(centerX - bodyWidth / 2, centerY - bodyThickness / 2); ctx.lineTo(centerX + bodyWidth / 2, centerY - bodyThickness / 2); ctx.lineTo(centerX + bodyWidth / 2, centerY + bodyThickness / 2); ctx.lineTo(centerX - bodyWidth / 2, centerY + bodyThickness / 2); // 箭头 ctx.moveTo(centerX - bodyWidth / 2, centerY - arrowWidth / 2); ctx.lineTo(Math.max(centerX - bodyWidth / 2 - arrowLength, x1), centerY); // 确保不超出左侧边界 ctx.lineTo(centerX - bodyWidth / 2, centerY + arrowWidth / 2); break; } case "up": { const bodyHeight = height * 0.4; ctx.beginPath(); // 主体矩形 ctx.moveTo(centerX - bodyThickness / 2, centerY - bodyHeight / 2); ctx.lineTo(centerX + bodyThickness / 2, centerY - bodyHeight / 2); ctx.lineTo(centerX + bodyThickness / 2, centerY + bodyHeight / 2); ctx.lineTo(centerX - bodyThickness / 2, centerY + bodyHeight / 2); // 箭头 ctx.moveTo(centerX - arrowWidth / 2, centerY - bodyHeight / 2); ctx.lineTo(centerX, Math.max(centerY - bodyHeight / 2 - arrowLength, y1)); // 确保不超出顶部边界 ctx.lineTo(centerX + arrowWidth / 2, centerY - bodyHeight / 2); break; } case "right": { const bodyWidth = width * 0.4; ctx.beginPath(); // 主体矩形 ctx.moveTo(centerX - bodyWidth / 2, centerY - bodyThickness / 2); ctx.lineTo(centerX + bodyWidth / 2, centerY - bodyThickness / 2); ctx.lineTo(centerX + bodyWidth / 2, centerY - arrowWidth / 2); ctx.lineTo(Math.min(centerX + bodyWidth / 2 + arrowLength, x2), centerY); // 确保不超出右侧边界 ctx.lineTo(centerX + bodyWidth / 2, centerY + arrowWidth / 2); ctx.lineTo(centerX + bodyWidth / 2, centerY + bodyThickness / 2); ctx.lineTo(centerX - bodyWidth / 2, centerY + bodyThickness / 2); break; } } ctx.closePath(); ctx.fill(); } /** * 根据条件返回相应的 SCSS 对象 * @param {string} type - 类型参数,用于决定返回哪个 SCSS 对象 * @returns {object} - 返回相应的 SCSS 对象 */