164 lines
3.2 KiB
Vue
164 lines
3.2 KiB
Vue
<template>
|
|
<div class="external-input-container">
|
|
<div class="branch-input-container">
|
|
<el-input
|
|
v-model="inputValue"
|
|
placeholder="输入分支需求..."
|
|
size="small"
|
|
class="branch-input"
|
|
@keydown="handleKeydown"
|
|
ref="inputRef"
|
|
/>
|
|
<span
|
|
class="submit-icon"
|
|
:class="{ 'is-disabled': !inputValue.trim() }"
|
|
@click="handleSubmit"
|
|
>
|
|
<svg-icon icon-class="paper-plane" size="14px" color="#fff" />
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, nextTick } from 'vue'
|
|
import SvgIcon from '@/components/SvgIcon/index.vue'
|
|
|
|
interface Props {
|
|
modelValue?: string
|
|
placeholder?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
modelValue: '',
|
|
placeholder: '输入分支需求...'
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'update:modelValue', value: string): void
|
|
(e: 'submit', value: string): void
|
|
(e: 'cancel'): void
|
|
}>()
|
|
|
|
const inputValue = ref(props.modelValue)
|
|
const inputRef = ref<InstanceType<typeof HTMLInputElement>>()
|
|
|
|
// 聚焦输入框
|
|
const focus = () => {
|
|
nextTick(() => {
|
|
inputRef.value?.focus()
|
|
})
|
|
}
|
|
|
|
// 暴露方法给父组件
|
|
defineExpose({
|
|
focus
|
|
})
|
|
|
|
const handleSubmit = () => {
|
|
if (inputValue.value.trim()) {
|
|
emit('submit', inputValue.value.trim())
|
|
inputValue.value = ''
|
|
}
|
|
}
|
|
|
|
const handleCancel = () => {
|
|
inputValue.value = ''
|
|
emit('cancel')
|
|
}
|
|
|
|
const handleKeydown = (event: KeyboardEvent) => {
|
|
if (event.key === 'Enter') {
|
|
event.preventDefault()
|
|
handleSubmit()
|
|
} else if (event.key === 'Escape') {
|
|
handleCancel()
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.external-input-container {
|
|
position: absolute;
|
|
bottom: -80px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 260px;
|
|
background: linear-gradient(var(--color-card-bg-task), var(--color-card-bg-task)) padding-box,
|
|
linear-gradient(to right, var(--color-accent), var(--color-accent-secondary)) border-box;
|
|
border: 2px solid transparent;
|
|
border-radius: 30px;
|
|
padding: 10px 12px;
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
z-index: 100;
|
|
animation: slideDown 0.2s ease-out;
|
|
}
|
|
|
|
.branch-input-container {
|
|
width: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.branch-input {
|
|
width: 100%;
|
|
|
|
:deep(.el-input__wrapper) {
|
|
background: transparent;
|
|
border: none;
|
|
box-shadow: none;
|
|
|
|
&:hover {
|
|
border: none;
|
|
}
|
|
|
|
&.is-focus {
|
|
border: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.el-input__inner {
|
|
font-size: 14px;
|
|
color: var(--color-text-taskbar);
|
|
}
|
|
}
|
|
}
|
|
|
|
.submit-icon {
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(to right, var(--color-accent), var(--color-accent-secondary));
|
|
|
|
&:hover:not(.is-disabled) {
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
&:active:not(.is-disabled) {
|
|
transform: scale(0.95);
|
|
}
|
|
|
|
&.is-disabled {
|
|
opacity: 0.4;
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
|
|
@keyframes slideDown {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateX(-50%) translateY(-10px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateX(-50%) translateY(0);
|
|
}
|
|
}
|
|
</style>
|