Files
xSynergy-manage/src/components/ToolBox/index.vue
2025-09-19 17:24:46 +08:00

228 lines
7.4 KiB
Vue

<template>
<div class="tool-mid-box-left">
<!-- 工具循环 -->
<div class="tool-box-cell-box-left" v-for="item in tools" :key="item.shapeType">
<!-- <el-tooltip :content="item.name" placement="top-end">
<div class="tool-box-cell" @click="clickAppliance(item.shapeType)">
<img :src="item.shapeType === currentShapType ? item.iconActive : item.icon" :alt="item.name" />
</div>
</el-tooltip> -->
<el-tooltip :content="item.name" placement="top-end">
<div class="tool-box-cell" @click="clickAppliance(item.shapeType)">
<img
:src="(
// 当前是该工具
item.shapeType === currentShapType
// 当前在选颜色 / 粗细时保持上一个绘图工具高亮
|| (['colorSelector','brushSize'].includes(currentShapType) && item.shapeType === lastDrawingTool)
)
? item.iconActive
: item.icon"
:alt="item.name"
/>
</div>
</el-tooltip>
<!-- 颜色选择器 -->
<div v-if="item.shapeType === 'colorSelector' && currentShapType === 'colorSelector' && colorSelectorControl"
class="tool-popup">
<el-color-picker ref="colorPickerRef" v-model="selectedColor" v-model:visible="colorVisible" show-alpha
@change="handleColorChange" />
</div>
<!-- 画笔大小选择器 -->
<div v-if="item.shapeType === 'brushSize' && currentShapType === 'brushSize' && brushSizeControl"
class="tool-popup">
<el-select ref="brushSizeRef" v-model="selectedThickness" placeholder="画笔粗细" size="small"
@change="handleThicknessChange" v-model:visible="brushSizeVisible" style="width: 60px">
<el-option v-for="size in thicknessOptions" :key="size" :label="size + 'px'" :value="size" />
</el-select>
</div>
</div>
</div>
</template>
<script setup>
import { ref, nextTick, onMounted, onBeforeUnmount } from "vue";
const props = defineProps({
canvas: {
type: Object,
required: true,
validator: (value) => value && typeof value.setDrawingTool === "function",
},
});
// 工具图标导入
import pen from "./image/pencil.svg";
import penActive from "./image/pencil-active.svg";
import eraser from "./image/eraser.svg";
import eraserActive from "./image/eraser-active.svg";
import ellipse from "./image/ellipse.svg";
import ellipseActive from "./image/ellipse-active.svg";
import rectangle from "./image/rectangle.svg";
import rectangleActive from "./image/rectangle-active.svg";
import straight from "./image/straight.svg";
import straightActive from "./image/straight-active.svg";
import brushSize from "./image/brushSize.svg";
import brushSizeActive from "./image/brushSize-active.svg";
import colorSelector from "./image/colorSelector.svg";
import colorSelectorActive from "./image/colorSelector-active.svg";
const tools = ref([
{ name: "笔", icon: pen, iconActive: penActive, shapeType: "pencil" },
{ name: "圆形", icon: ellipse, iconActive: ellipseActive, shapeType: "circle" },
{ name: "矩形", icon: rectangle, iconActive: rectangleActive, shapeType: "rectangle" },
{ name: "直线", icon: straight, iconActive: straightActive, shapeType: "line" },
{ name: "选色器", icon: colorSelector, iconActive: colorSelectorActive, shapeType: "colorSelector" },
{ name: "画笔大小", icon: brushSize, iconActive: brushSizeActive, shapeType: "brushSize" },
{ name: "橡皮擦", icon: eraser, iconActive: eraserActive, shapeType: "eraser" },
]);
// 状态
const selectedColor = ref("#ffcc00");
const selectedThickness = ref(2);
const thicknessOptions = [1, 2, 4, 8, 16];
const colorSelectorControl = ref(false);
const brushSizeControl = ref(false);
const colorVisible = ref(false);
const brushSizeVisible = ref(false);
const currentShapType = ref("pencil"); // 当前点击的工具
const lastDrawingTool = ref("pencil"); // 记录最后一个绘图工具
// refs
const colorPickerRef = ref();
const brushSizeRef = ref();
// 颜色选择逻辑
const handleColorChange = (color) => {
props.canvas?.setColor(color);
colorSelectorControl.value = false;
colorVisible.value = false;
};
// 粗细选择逻辑
const handleThicknessChange = (size) => {
props.canvas?.setThickness(size);
brushSizeControl.value = false;
brushSizeVisible.value = false;
};
// 点击工具逻辑
function clickAppliance(type) {
// 点击同一个工具时切换关闭
if (currentShapType.value === type) {
if (type === "colorSelector") {
colorSelectorControl.value = !colorSelectorControl.value;
colorVisible.value = colorSelectorControl.value;
} else if (type === "brushSize") {
brushSizeControl.value = !brushSizeControl.value;
brushSizeVisible.value = brushSizeControl.value;
}
return;
}
// 切换到新工具
currentShapType.value = type;
lastDrawingTool.value = type; // 记录最新绘图工具
if (type === "colorSelector") {
colorSelectorControl.value = true;
brushSizeControl.value = false;
nextTick(() => {
colorVisible.value = true;
});
} else if (type === "brushSize") {
brushSizeControl.value = true;
colorSelectorControl.value = false;
nextTick(() => {
brushSizeVisible.value = true;
});
} else {
colorSelectorControl.value = false;
brushSizeControl.value = false;
colorVisible.value = false;
brushSizeVisible.value = false;
props.canvas?.setDrawingTool(type);
}
}
// 点击工具栏外部关闭弹窗
function handleClickOutside(event) {
const toolBox = document.querySelector(".tool-mid-box-left");
if (!toolBox.contains(event.target)) {
// colorSelectorControl.value = false;
brushSizeControl.value = false;
// colorVisible.value = false;
brushSizeVisible.value = false;
}
}
onMounted(() => {
if (!props.canvas || typeof props.canvas.setDrawingTool !== "function") {
console.error("Invalid canvas prop passed to ToolBox");
}
document.addEventListener("click", handleClickOutside);
});
onBeforeUnmount(() => {
document.removeEventListener("click", handleClickOutside);
});
</script>
<style lang="scss" scoped>
.tool-mid-box-left {
width: 40px;
display: flex;
border-radius: 4px;
background-color: white;
justify-content: flex-start;
align-items: center;
flex-direction: column;
padding: 4px 0;
box-shadow: 0 8px 24px 0 rgba(0, 0, 0, 0.1);
}
.tool-box-cell {
width: 24px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
position: relative;
}
.tool-box-cell-box-left {
width: 32px;
height: 32px;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
border-radius: 2px;
position: relative;
&:hover {
background: rgba(33, 35, 36, 0.1);
}
}
/* 弹出层样式:显示在图标右侧 */
.tool-popup {
position: absolute;
left: 40px;
/* 距离工具栏宽度 */
top: 50%;
transform: translateY(-50%);
background: white;
padding: 6px;
border-radius: 4px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 1000;
}
</style>