feat:任务大纲编辑文字悬浮边框重构
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
import type { IRawStepTask } from '@/stores'
|
import type { IRawStepTask } from '@/stores'
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue'
|
import SvgIcon from '@/components/SvgIcon/index.vue'
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const isEditing = ref(false)
|
const isEditing = ref(false)
|
||||||
const editingContent = ref('')
|
const editingContent = ref('')
|
||||||
|
const editorRef = ref<HTMLElement>()
|
||||||
|
|
||||||
const startEditing = () => {
|
const startEditing = () => {
|
||||||
editingContent.value = props.task.TaskContent || ''
|
editingContent.value = props.task.TaskContent || ''
|
||||||
@@ -37,11 +38,25 @@ const handleKeydown = (event: KeyboardEvent) => {
|
|||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 点击外部保存
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
if (isEditing.value && editorRef.value && !editorRef.value.contains(event.target as Node)) {
|
||||||
|
save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener('click', handleClickOutside)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener('click', handleClickOutside)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="isEditing" class="w-full">
|
<div ref="editorRef" v-if="isEditing" class="w-full">
|
||||||
<div class="flex flex-col gap-3">
|
|
||||||
<el-input
|
<el-input
|
||||||
v-model="editingContent"
|
v-model="editingContent"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
@@ -51,43 +66,65 @@ const handleKeydown = (event: KeyboardEvent) => {
|
|||||||
class="task-content-editor"
|
class="task-content-editor"
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
<div class="flex justify-end">
|
|
||||||
<svg-icon
|
|
||||||
icon-class="Check"
|
|
||||||
size="20px"
|
|
||||||
color="#328621"
|
|
||||||
class="cursor-pointer mr-4"
|
|
||||||
@click="save"
|
|
||||||
title="保存"
|
|
||||||
/>
|
|
||||||
<svg-icon
|
|
||||||
icon-class="Cancel"
|
|
||||||
size="20px"
|
|
||||||
color="#8e0707"
|
|
||||||
class="cursor-pointer mr-1"
|
|
||||||
@click="cancel"
|
|
||||||
title="取消"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-else @dblclick="startEditing" class="w-full cursor-pointer task-content-wrapper">
|
||||||
</div>
|
|
||||||
<div v-else @dblclick="startEditing" class="w-full cursor-pointer">
|
|
||||||
<slot name="display">
|
<slot name="display">
|
||||||
<div class="text-[14px] text-[var(--color-text-secondary)] task-content-display">
|
<div class="text-[14px] text-[var(--color-text-secondary)] task-content-display">
|
||||||
{{ task.TaskContent }}
|
{{ task.TaskContent }}
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
|
<div class="edit-icon-bg" @click.stop="startEditing">
|
||||||
|
<svg-icon icon-class="Edit" class="edit-icon-svg" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
.task-content-wrapper {
|
||||||
|
position: relative;
|
||||||
|
padding: 4px;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 7px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: border-color 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--color-task-edit-hover-border) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-icon-bg {
|
||||||
|
position: absolute;
|
||||||
|
right: -1px;
|
||||||
|
bottom: -1px;
|
||||||
|
width: 26px;
|
||||||
|
height: 22px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
background: var(--color-edit-icon-bg);
|
||||||
|
border-radius: 8px 0px 7px 0px;
|
||||||
|
|
||||||
|
.edit-icon-svg {
|
||||||
|
color: var(--color-text-detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .edit-icon-bg {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.task-content-editor {
|
.task-content-editor {
|
||||||
:deep(.el-textarea__inner) {
|
:deep(.el-textarea__inner) {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 1px solid #dcdfe6;
|
border: 1px solid var(--color-task-edit-hover-border) !important;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
resize: none;
|
resize: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user