CMVR-IOT-UI/src/views/flow/components/NodeTitle.vue

304 lines
7.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="title__container">
<div class="title">
<div class="left">
<img :src="imageUrl()" alt="" />
<div class="text__container">
<div class="text__title" v-if="showTextTitle">
<span class="text">{{ localName }}</span>
<el-icon class="editIcon" @click="startEditing"><EditPen/></el-icon>
</div>
<div class="input_name_container" v-else >
<el-input
v-model="localName"
@focus="handleInputFocus"
@blur="handleInputBlur"
@keydown="handleInputKeydown"
@click.stop
@mousedown.stop
/>
<el-button
class="input_name_select"
circle
size="small"
@click="confirmNodeName"
>
<el-icon><Select /></el-icon>
</el-button>
<el-button
class="input_name_closeBold"
circle
size="small"
@click="cancelNodeName"
>
<el-icon><CloseBold /></el-icon>
</el-button>
</div>
</div>
</div>
<div class="right">
<el-tooltip
class="box-item"
effect="dark"
content="执行"
placement="top"
>
<el-button v-if="nodeType && nodeType !=='NONE'" circle @click="execute">
<el-icon>
<VideoPlay />
</el-icon>
</el-button>
</el-tooltip>
<el-tooltip
class="box-item"
effect="dark"
content="删除"
placement="top"
>
<el-button circle @click="deleteNode">
<el-icon><Delete /></el-icon>
</el-button>
</el-tooltip>
</div>
</div>
<div class="subTitle">{{ props.nodeDesc }}</div>
</div>
</template>
<script setup lang="js">
import { onUnmounted, ref } from 'vue'
import { EditPen, Select, CloseBold, Delete, VideoPlay } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus'
import { computed } from 'vue'
import { emitter } from "@/utils/eventBus";
const props = defineProps({
icon: {
type: String,
default: ''
},
nodeId: {
type: String,
default: ''
},
nodeProperties: {
type: Object,
default: () => {}
},
nodeDesc: {
type: String,
default: ''
},
nodeName: {
type: String,
default: ''
},
nodeType: {
type: String,
default: ''
},
})
const emits = defineEmits(['setNodeName'])
const showTextTitle = ref(true)
const localName = ref('')
const isEditing = ref(false)
// 开始编辑
const startEditing = () => {
isEditing.value = true
showTextTitle.value = false
// 使用 nextTick 确保 DOM 更新后再聚焦
nextTick(() => {
if (inputRef.value && inputRef.value.input) {
inputRef.value.input.focus()
// 选择所有文本
inputRef.value.input.select()
}
})
}
const confirmNodeName = () => {
emits('setNodeName', localName.value)
showTextTitle.value = true
}
const cancelNodeName = () => {
localName.value = props.nodeProperties?.name || props.nodeName
showTextTitle.value = true
}
const deleteNode = () => {
ElMessageBox.confirm(
'是否删除该节点?',
'警告',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
if (props.nodeType === 'selectArea') {
const children = lf.getNodeModelById(props.nodeId).children
lf.getNodeModelById(props.nodeId).children = []
children.forEach(item => {
lf.getNodeModelById(item).draggable = true
})
}
lf.deleteNode(props.nodeId);
emitter.emit('deleteNode', props.nodeId);
})
}
const execute = () => {
const myEvent = new CustomEvent('singleNodeExecution', {
bubbles: false, // 是否冒泡(默认 false
cancelable: false, // 是否可被 preventDefault() 取消(默认 false
detail: { ...props.nodeProperties } // 自定义数据(任意类型,通过 event.detail 读取)
});
document.dispatchEvent(myEvent);
}
const handleInputFocus = (e) => {
console.log('Input focused')
// 阻止事件冒泡到 LogicFlow
e.stopPropagation()
e.preventDefault()
// 设置编辑状态
isEditing.value = true
// 延迟执行,确保事件处理完成
setTimeout(() => {
if (inputRef.value && inputRef.value.input) {
inputRef.value.input.focus()
}
}, 0)
}
const handleInputBlur = (e) => {
console.log('Input blurred')
// 如果正在编辑,不要立即取消编辑状态
if (isEditing.value) {
// 可以选择在失焦时自动保存或取消
// 这里我们选择不自动保存,让用户点击确认按钮
}
}
const handleInputKeydown = (e) => {
// 阻止事件冒泡到 Logic Flow 节点,避免被其事件拦截
e.stopPropagation();
// 可选:明确放行 Ctrl+V增强兼容性
if ((e.ctrlKey || e.metaKey) && e.key === "v") {
e.returnValue = true; // 允许默认粘贴行为
}
}
const imageUrl = () => {
return new URL(props.icon, import.meta.url).href;
}
onMounted(() => {
localName.value = props.nodeProperties?.name || props.nodeName
})
onUnmounted(() => {
console.log(34566)
emitter.off("deleteNode");
})
</script>
<style lang="scss" scoped>
.title__container {
.title {
display: flex;
align-items: center;
justify-content: space-between;
.left {
display: flex;
align-items: center; // 添加垂直居中
img {
width: 24px;
height: 24px;
}
.text__container {
.text__title {
display: flex;
align-items: center;
.text {
font-size: 16px;
font-weight: bold;
margin: 0 12px;
}
.editIcon {
cursor: pointer;
}
}
.input_name_container {
display: flex;
align-items: center;
.el-input {
margin-left: 12px;
width: 120px;
// 确保输入框有更高的 z-index
position: relative;
z-index: 1000;
// 覆盖 Element Plus 的默认样式,确保焦点状态明显
:deep(.el-input__wrapper) {
box-shadow: 0 0 0 1px #409eff !important;
&:focus-within {
box-shadow: 0 0 0 2px #409eff !important;
}
}
}
.input_name_select {
color: #00b42a;
margin-left: 4px;
border: none;
}
.input_name_closeBold {
color: #f53f3f;
margin-left: 4px;
border: none;
}
}
}
}
.right {
cursor: pointer;
.el-button {
border: none;
font-size: 24px;
}
}
}
.subTitle {
color: #737a87;
font-size: 12px;
margin: 8px 0;
}
}
// 添加全局样式,确保输入框焦点不被其他元素干扰
:global(.lf-node) {
.el-input__inner {
user-select: text !important;
}
}
</style>