| | |
| | | @mousemove="handleRectDragging"
|
| | | @mouseup="handleRectDragEnd"
|
| | | @mouseleave="handleRectDragEnd"
|
| | | @click="handleRectClick(layoutIndex, rectIndex)"
|
| | | >
|
| | | <div class="rect-content">
|
| | | <div class="size">{{ rect.w }}×{{ rect.h }}</div>
|
| | |
| | | const { t } = useI18n();
|
| | | const userStore = useUserInfoStore()
|
| | | const username = userStore.user.userName
|
| | |
|
| | |
|
| | | let clickEventListener = null;
|
| | | const props = defineProps({
|
| | | layoutData: { type: Object, required: true },
|
| | | gw: { type: Number, default: 1000 },
|
| | |
| | | const dragging = ref(false);
|
| | | const dragStartPos = ref({ x: 0, y: 0 });
|
| | | const dragRect = ref(null);
|
| | | const showJiaHao = ref(false); // 新增:控制jia-hao的显示状态
|
| | | const showProcessId= ref(false);
|
| | | const themeColor=ref(null)
|
| | | // 提交布局数据到后端
|
| | | const showJiaHao = ref(false);
|
| | | const showProcessId = ref(false);
|
| | | const themeColor = ref(null);
|
| | |
|
| | | const submitLayouts = async () => {
|
| | | layouts.value.forEach(layout => {
|
| | | layout.rects.forEach(rect => {
|
| | |
| | | });
|
| | | };
|
| | |
|
| | |
|
| | | //获取优化设置
|
| | | const fetchSettings = async (username) => {
|
| | | try {
|
| | | const response = await request.post(`/glassOptimize/selectOptimizeParms/${username}`);
|
| | |
| | | return;
|
| | | }
|
| | | const parsedData = JSON.parse(response.data);
|
| | | console.log(parsedData.display.frameNumber)
|
| | | if (parsedData.display && parsedData.display.frameNumber) {
|
| | | showJiaHao.value = parsedData.display.frameNumber;
|
| | |
|
| | | }
|
| | | if (parsedData.display && parsedData.display.orderNumber) {
|
| | | showProcessId.value = parsedData.display.orderNumber;
|
| | | |
| | | }
|
| | | if (parsedData.display ) {
|
| | | if (parsedData.display) {
|
| | | themeColor.value = parsedData.display.themeColor;
|
| | | |
| | | }
|
| | | |
| | | |
| | | |
| | | console.log( parsedData);
|
| | | } else {
|
| | | console.error('请求失败,状态码:', response.code);
|
| | | }
|
| | |
| | | console.error('请求发生错误:', error);
|
| | | }
|
| | | };
|
| | |
|
| | |
|
| | |
|
| | | const showAddDialog = (layoutIndex, rectIndex) => {
|
| | | ElMessageBox.prompt('请输入成品的宽度和高度', '添加成品', {
|
| | |
| | | },
|
| | | inputErrorMessage: '输入格式不正确'
|
| | | })
|
| | | .then(({ value }) => {
|
| | | const values = value.split(',').map(v => parseFloat(v.trim()));
|
| | | const newRect = {
|
| | | x: 0,
|
| | | y: 0,
|
| | | w: values[0],
|
| | | h: values[1],
|
| | | isRemain: false
|
| | | |
| | | };
|
| | | addNewRect(layoutIndex, newRect);
|
| | | })
|
| | | .catch(() => {
|
| | | // 用户取消
|
| | | });
|
| | | .then(({ value }) => {
|
| | | const values = value.split(',').map(v => parseFloat(v.trim()));
|
| | | const newRect = {
|
| | | x: 0,
|
| | | y: 0,
|
| | | w: values[0],
|
| | | h: values[1],
|
| | | isRemain: false
|
| | | };
|
| | | addNewRect(layoutIndex, newRect);
|
| | | })
|
| | | .catch(() => {
|
| | | // 用户取消
|
| | | });
|
| | | };
|
| | |
|
| | | const addNewRect = (layoutIndex, newRect) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | layout.rects.push(newRect);
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | const bestFitPosition = findBestFitPosition(layoutIndex, newRect);
|
| | | if (bestFitPosition) {
|
| | | newRect.x = bestFitPosition.x;
|
| | | newRect.y = bestFitPosition.y;
|
| | | layout.rects.push(newRect);
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | ElMessage.warning('无法放置,没有足够的空间');
|
| | | }
|
| | | };
|
| | |
|
| | | const findBestFitPosition = (layoutIndex, newRect) => {
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const obstacles = layout.rects.filter(r => !r.isRemain);
|
| | | let bestFit = null;
|
| | | let minAreaDifference = Infinity;
|
| | |
|
| | | const remainingAreas = calculateRemainingAreas(layout.width, layout.height, obstacles);
|
| | | remainingAreas.forEach(area => {
|
| | | if (newRect.w <= area.w && newRect.h <= area.h) {
|
| | | const areaDifference = Math.abs(area.w * area.h - newRect.w * newRect.h);
|
| | | if (areaDifference < minAreaDifference) {
|
| | | minAreaDifference = areaDifference;
|
| | | bestFit = {
|
| | | x: area.x,
|
| | | y: area.y,
|
| | | w: newRect.w,
|
| | | h: newRect.h
|
| | | };
|
| | | }
|
| | | }
|
| | | });
|
| | |
|
| | | return bestFit;
|
| | | };
|
| | |
|
| | | const layoutContainerStyle = (layoutIndex) => {
|
| | | const containerWidth = (props.gw - 210) / 2;
|
| | | const containerHeight = (props.gh - 100) / 3;
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const scale = Math.min(
|
| | | (props.gw - 100) / layout.width,
|
| | |
| | | const deltaX = event.clientX - dragStartPos.value.x;
|
| | | const deltaY = event.clientY - dragStartPos.value.y;
|
| | |
|
| | | // 只调整位置,不调整大小
|
| | | const newRect = { ...rect };
|
| | | newRect.x += deltaX / scale;
|
| | | newRect.y += deltaY / scale;
|
| | |
|
| | | // 检查是否与其他蓝色矩形重叠
|
| | | const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
|
| | | let isValidMove = true;
|
| | | |
| | |
|
| | | otherRects.forEach(otherRect => {
|
| | | if (checkOverlap(newRect, otherRect)) {
|
| | | isValidMove = false;
|
| | | }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (newRect.x < 0 || newRect.y < 0 ||
|
| | | newRect.x + newRect.w > layout.width ||
|
| | | newRect.y + newRect.h > layout.height) {
|
| | |
| | | (props.gh - 100) / layout.height
|
| | | );
|
| | |
|
| | | // 拖动结束后自动对齐到最近的整数位置
|
| | | rect.x = Math.round(rect.x);
|
| | | rect.y = Math.round(rect.y);
|
| | |
|
| | | // 只调整位置对齐,不调整大小
|
| | | adjustAlignmentPosition(layoutIndex, rectIndex);
|
| | |
|
| | | // 调整灰色矩形
|
| | | //adjustAlignmentPosition(layoutIndex, rectIndex);
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | }
|
| | |
|
| | |
| | | const threshold = Math.max(rect.w, rect.h) * 0.1;
|
| | |
|
| | | otherRects.forEach(otherRect => {
|
| | | // 水平对齐
|
| | | if (Math.abs(rect.x - otherRect.x) < threshold) {
|
| | | rect.x = Math.round((rect.x + otherRect.x) / 2);
|
| | | }
|
| | | // 水平对齐右侧边缘
|
| | | if (Math.abs((rect.x + rect.w) - (otherRect.x + otherRect.w)) < threshold) {
|
| | | // 不调整宽度
|
| | | rect.x = Math.round((otherRect.x + otherRect.w - rect.w));
|
| | | }
|
| | | // 垂直对齐
|
| | | if (Math.abs(rect.y - otherRect.y) < threshold) {
|
| | | rect.y = Math.round((rect.y + otherRect.y) / 2);
|
| | | }
|
| | | // 垂直对齐下边缘
|
| | | if (Math.abs((rect.y + rect.h) - (otherRect.y + otherRect.h)) < threshold) {
|
| | | // 不调整高度
|
| | | rect.y = Math.round((otherRect.y + otherRect.h - rect.h));
|
| | | }
|
| | | });
|
| | |
|
| | | // 确保矩形不会超出布局边界
|
| | | rect.x = Math.max(0, rect.x);
|
| | | rect.y = Math.max(0, rect.y);
|
| | | rect.x = Math.min(rect.x, layout.width - rect.w);
|
| | | rect.y = Math.min(rect.y, layout.height - rect.h);
|
| | |
|
| | | // 调整后重新计算灰色余料
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | };
|
| | |
|
| | |
|
| | | const mergeAdjacentGrayRects = (rects) => {
|
| | | const grayRects = rects.filter(r => r.isRemain);
|
| | | let merged = [];
|
| | | |
| | |
|
| | | grayRects.sort((a, b) => {
|
| | | if (a.x !== b.x) return a.x - b.x;
|
| | | return a.y - b.y;
|
| | |
| | | const last = merged[merged.length - 1];
|
| | | const current = grayRects[i];
|
| | |
|
| | | if (current.x === last.x + last.w && |
| | | current.y === last.y && |
| | | if (current.x === last.x + last.w &&
|
| | | current.y === last.y &&
|
| | | current.h === last.h) {
|
| | | last.w += current.w;
|
| | | last.x = Math.round(last.x);
|
| | | last.y = Math.round(last.y);
|
| | | last.w = Math.round(last.w);
|
| | | last.h = Math.round(last.h);
|
| | | } else if (current.y === last.y + last.h && |
| | | current.x === last.x && |
| | | } else if (current.y === last.y + last.h &&
|
| | | current.x === last.x &&
|
| | | current.w === last.w) {
|
| | | last.h += current.h;
|
| | | last.x = Math.round(last.x);
|
| | |
| | | last.w = Math.round(last.w);
|
| | | last.h = Math.round(last.h);
|
| | | } else {
|
| | | merged.push({ |
| | | merged.push({
|
| | | x: Math.round(current.x),
|
| | | y: Math.round(current.y),
|
| | | w: Math.round(current.w),
|
| | |
| | | const rect = layout.rects[rectIndex];
|
| | | const originalState = { ...rect };
|
| | |
|
| | | // 旋转矩形
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | |
|
| | | // 检查旋转后是否与其他蓝色矩形重叠
|
| | | const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
|
| | | let isValidRotation = true;
|
| | |
|
| | | otherRects.forEach(otherRect => {
|
| | | if (checkOverlap(rect, otherRect)) {
|
| | | isValidRotation = false;
|
| | | }
|
| | | isValidRotation = false }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (rect.x + rect.w > layout.width || rect.y + rect.h > layout.height) {
|
| | | isValidRotation = false;
|
| | | }
|
| | |
| | | if (isValidRotation) {
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | // 恢复原状
|
| | | rect.w = originalState.w;
|
| | | rect.h = originalState.h;
|
| | | ElMessage.warning('无法旋转,存在重叠或超出边界');
|
| | |
| | | const rect = layout.rects[rectIndex];
|
| | | const grayRects = layout.rects.filter(r => r.isRemain);
|
| | |
|
| | | // 旋转矩形
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | |
|
| | | // 检查旋转后的矩形是否可以放置在某个灰色矩形的位置
|
| | | const canPlace = grayRects.some(grayRect => {
|
| | | return grayRect.w >= rect.w && grayRect.h >= rect.h;
|
| | | });
|
| | |
|
| | | if (!canPlace) {
|
| | | // 如果不能放置,恢复原状
|
| | | const temp = rect.w;
|
| | | rect.w = rect.h;
|
| | | rect.h = temp;
|
| | |
| | | return;
|
| | | }
|
| | |
|
| | | // 调整灰色矩形
|
| | | adjustGrayRectangles(layoutIndex);
|
| | |
|
| | | // 移动矩形
|
| | | moveRect(layoutIndex, rectIndex, direction);
|
| | | };
|
| | |
|
| | |
| | | const rect = layout.rects[rectIndex];
|
| | | const originalState = { ...rect };
|
| | |
|
| | | // 计算剩余空间
|
| | | const remainingAreas = calculateRemainingAreas(layout.width, layout.height, layout.rects.filter(r => !r.isRemain));
|
| | | |
| | | // 根据方向计算可移动的最大步长
|
| | | let maxStep = 0;
|
| | | const obstacles = layout.rects.filter(r => r.isRemain || r !== rect);
|
| | |
|
| | | switch (direction) {
|
| | | case 'up':
|
| | | maxStep = rect.y;
|
| | | maxStep = getAvailableSpaceUp(rect, layout, obstacles);
|
| | | break;
|
| | | case 'down':
|
| | | maxStep = layout.height - (rect.y + rect.h);
|
| | | maxStep = getAvailableSpaceDown(rect, layout, obstacles);
|
| | | break;
|
| | | case 'left':
|
| | | maxStep = rect.x;
|
| | | maxStep = getAvailableSpaceLeft(rect, layout, obstacles);
|
| | | break;
|
| | | case 'right':
|
| | | maxStep = layout.width - (rect.x + rect.w);
|
| | | maxStep = getAvailableSpaceRight(rect, layout, obstacles);
|
| | | break;
|
| | | }
|
| | |
|
| | | // 移动步长,根据剩余空间动态调整
|
| | | const stepSize = maxStep;
|
| | | const actualStep = Math.min(maxStep, stepSize);
|
| | | if (maxStep <= 0) {
|
| | | ElMessage.warning('无法移动,没有足够的空间');
|
| | | return;
|
| | | }
|
| | |
|
| | | // 移动矩形
|
| | | switch (direction) {
|
| | | case 'up':
|
| | | rect.y -= actualStep;
|
| | | rect.y -= maxStep;
|
| | | break;
|
| | | case 'down':
|
| | | rect.y += actualStep;
|
| | | rect.y += maxStep;
|
| | | break;
|
| | | case 'left':
|
| | | rect.x -= actualStep;
|
| | | rect.x -= maxStep;
|
| | | break;
|
| | | case 'right':
|
| | | rect.x +=actualStep;
|
| | | rect.x += maxStep;
|
| | | break;
|
| | | }
|
| | |
|
| | | // 检查是否与其他蓝色矩形重叠
|
| | | const otherRects = layout.rects.filter(r => !r.isRemain && r !== rect);
|
| | | let isValidMove = true;
|
| | |
|
| | |
| | | }
|
| | | });
|
| | |
|
| | | // 检查是否超出布局边界
|
| | | if (rect.x < 0 || rect.y < 0 ||
|
| | | rect.x + rect.w > layout.width ||
|
| | | rect.y + rect.h > layout.height) {
|
| | |
| | | if (isValidMove) {
|
| | | adjustGrayRectangles(layoutIndex);
|
| | | } else {
|
| | | // 恢复原状
|
| | | rect.x = originalState.x;
|
| | | rect.y = originalState.y;
|
| | | ElMessage.warning('无法移动,存在重叠或超出边界');
|
| | |
| | | layouts.value = props.layoutData.Layouts;
|
| | | };
|
| | |
|
| | | const getAvailableSpaceUp = (rect, layout, obstacles) => {
|
| | | let maxSpace = rect.y;
|
| | | obstacles.forEach(obstacle => {
|
| | | if (obstacle.y + obstacle.h < rect.y &&
|
| | | obstacle.x <= rect.x + rect.w &&
|
| | | obstacle.x + obstacle.w >= rect.x) {
|
| | | maxSpace = Math.min(maxSpace, rect.y - (obstacle.y + obstacle.h));
|
| | | }
|
| | | });
|
| | | return maxSpace;
|
| | | };
|
| | |
|
| | | let clickEventListener = null;
|
| | | const getAvailableSpaceDown = (rect, layout, obstacles) => {
|
| | | let maxSpace = layout.height - (rect.y + rect.h);
|
| | | obstacles.forEach(obstacle => {
|
| | | if (obstacle.y > rect.y + rect.h &&
|
| | | obstacle.x <= rect.x + rect.w &&
|
| | | obstacle.x + obstacle.w >= rect.x) {
|
| | | maxSpace = Math.min(maxSpace, obstacle.y - (rect.y + rect.h));
|
| | | }
|
| | | });
|
| | | return maxSpace;
|
| | | };
|
| | |
|
| | | const getAvailableSpaceLeft = (rect, layout, obstacles) => {
|
| | | let maxSpace = rect.x;
|
| | | obstacles.forEach(obstacle => {
|
| | | if (obstacle.x + obstacle.w < rect.x &&
|
| | | obstacle.y <= rect.y + rect.h &&
|
| | | obstacle.y + obstacle.h >= rect.y) {
|
| | | maxSpace = Math.min(maxSpace, rect.x - (obstacle.x + obstacle.w));
|
| | | }
|
| | | });
|
| | | return maxSpace;
|
| | | };
|
| | |
|
| | | const getAvailableSpaceRight = (rect, layout, obstacles) => {
|
| | | let maxSpace = layout.width - (rect.x + rect.w);
|
| | | obstacles.forEach(obstacle => {
|
| | | if (obstacle.x > rect.x + rect.w &&
|
| | | obstacle.y <= rect.y + rect.h &&
|
| | | obstacle.y + obstacle.h >= rect.y) {
|
| | | maxSpace = Math.min(maxSpace, obstacle.x - (rect.x + rect.w));
|
| | | }
|
| | | });
|
| | | return maxSpace;
|
| | | };
|
| | |
|
| | | let moveInterval = null;
|
| | |
|
| | | const handleKeyDown = (event) => {
|
| | | if (!focusIndex.value) return;
|
| | |
|
| | | const { layoutIndex, rectIndex } = focusIndex.value;
|
| | | const layout = layouts.value[layoutIndex];
|
| | | const rect = layout.rects[rectIndex];
|
| | | const obstacles = layout.rects.filter(r => r.isRemain || r !== rect);
|
| | |
|
| | | switch (event.key) {
|
| | | case 'ArrowUp':
|
| | | event.preventDefault();
|
| | | if (!moveInterval) {
|
| | | moveInterval = setInterval(() => {
|
| | | moveRect(layoutIndex, rectIndex, 'up');
|
| | | }, 50);
|
| | | }
|
| | | break;
|
| | | case 'ArrowDown':
|
| | | event.preventDefault();
|
| | | if (!moveInterval) {
|
| | | moveInterval = setInterval(() => {
|
| | | moveRect(layoutIndex, rectIndex, 'down');
|
| | | }, 50);
|
| | | }
|
| | | break;
|
| | | case 'ArrowLeft':
|
| | | event.preventDefault();
|
| | | if (!moveInterval) {
|
| | | moveInterval = setInterval(() => {
|
| | | moveRect(layoutIndex, rectIndex, 'left');
|
| | | }, 50);
|
| | | }
|
| | | break;
|
| | | case 'ArrowRight':
|
| | | event.preventDefault();
|
| | | if (!moveInterval) {
|
| | | moveInterval = setInterval(() => {
|
| | | moveRect(layoutIndex, rectIndex, 'right');
|
| | | }, 50);
|
| | | }
|
| | | break;
|
| | | }
|
| | | };
|
| | |
|
| | | const handleKeyUp = (event) => {
|
| | | if (event.key === 'ArrowUp' || event.key === 'ArrowDown' ||
|
| | | event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
|
| | | if (moveInterval) {
|
| | | clearInterval(moveInterval);
|
| | | moveInterval = null;
|
| | | }
|
| | | }
|
| | | };
|
| | |
|
| | |
|
| | |
|
| | | onMounted(() => {
|
| | | fetchSettings(username);
|
| | | setTimeout(updateLayout, 500);
|
| | |
|
| | | selectedLayoutIndex.value = 0;
|
| | |
|
| | | // 添加全局点击事件监听器
|
| | | clickEventListener = (event) => {
|
| | | // 检查是否存在右键菜单
|
| | | clickEventListener = (event) => {
|
| | | const contextMenus = document.querySelectorAll('.context-menu');
|
| | | if (contextMenus.length > 0) {
|
| | | // 移除所有右键菜单
|
| | | contextMenus.forEach(menu => menu.remove());
|
| | | }
|
| | | };
|
| | | document.addEventListener('click', clickEventListener);
|
| | |
|
| | | document.addEventListener('keydown', handleKeyDown);
|
| | | document.addEventListener('keyup', handleKeyUp);
|
| | | });
|
| | |
|
| | |
|
| | |
|
| | | onUnmounted(() => {
|
| | | rectsElements.value = {};
|
| | | // 移除全局点击事件监听器
|
| | | if (clickEventListener) {
|
| | | if (clickEventListener) {
|
| | | document.removeEventListener('click', clickEventListener);
|
| | | clickEventListener = null;
|
| | | }
|
| | | document.removeEventListener('keydown', handleKeyDown);
|
| | | document.removeEventListener('keyup', handleKeyUp);
|
| | | });
|
| | |
|
| | | </script>
|
| | |
|
| | |
|
| | | <style scoped>
|
| | | .layout-wrapper {
|
| | |
| | | font-size: 12px;
|
| | | }
|
| | |
|
| | | .jia-hao .liuchengka {
|
| | | .jia-hao, .liuchengka {
|
| | | grid-row: 2;
|
| | | grid-column: 1;
|
| | | margin: auto;
|