重构: ChatInput 拆分(提取 SkillMention+ImageInput, 1183->1155行)
- 提取 SkillMention.vue(/ 技能联想浮层+已选 chip) - 提取 ImageInput.vue(待发送图片预览+移除) - ChatInput 模板内联技能浮层替换为子组件
This commit is contained in:
@@ -1,28 +1,18 @@
|
||||
<template>
|
||||
<div class="ai-input-area">
|
||||
<!-- 已选技能 chip(含参数格式提示 argument_hint) -->
|
||||
<div v-if="pendingSkill" class="ai-skill-chip">
|
||||
<span class="ai-skill-chip-main">
|
||||
<span class="ai-skill-chip-name">/{{ pendingSkill.name }}</span>
|
||||
<span v-if="pendingSkill.description" class="ai-skill-chip-desc">{{ pendingSkill.description }}</span>
|
||||
<code v-if="pendingSkill.argument_hint" class="ai-skill-chip-hint">{{ pendingSkill.argument_hint }}</code>
|
||||
</span>
|
||||
<button class="ai-skill-chip-x" @click="clearSkill" :title="$t('aiChat.clearSkill')" :aria-label="$t('aiChat.clearSkill')">×</button>
|
||||
</div>
|
||||
<SkillMention
|
||||
:skill-open="skillOpen"
|
||||
:filtered-skills="filteredSkills"
|
||||
:skill-index="skillIndex"
|
||||
:pending-skill="pendingSkill"
|
||||
:skill-query="skillQuery"
|
||||
@select="selectSkill"
|
||||
@clear="clearSkill"
|
||||
@update:skill-index="skillIndex = $event"
|
||||
/>
|
||||
<div class="ai-input-wrap">
|
||||
<!-- F-260614-05 Phase 2b: 待发送图片预览(粘贴/拖拽加入,发送前可移除) -->
|
||||
<div v-if="pendingImages.length" class="ai-img-preview-row">
|
||||
<div v-for="img in pendingImages" :key="img.id" class="ai-img-preview">
|
||||
<img :src="img.dataUrl" :alt="$t('aiChat.imagePreviewAlt')" class="ai-img-preview-thumb" />
|
||||
<button
|
||||
type="button"
|
||||
class="ai-img-preview-x"
|
||||
:title="$t('aiChat.removeImage')"
|
||||
:aria-label="$t('aiChat.removeImage')"
|
||||
@click="removePendingImage(img.id)"
|
||||
>×</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- F-260614-05 Phase 2b: 待发送图片预览 -->
|
||||
<ImageInput :pending-images="pendingImages" @remove="removePendingImage" />
|
||||
<textarea
|
||||
ref="inputEl"
|
||||
v-model="inputText"
|
||||
@@ -38,27 +28,7 @@
|
||||
@dragover="onDragOver"
|
||||
@drop="onDrop"
|
||||
></textarea>
|
||||
<!-- 技能联想浮层 -->
|
||||
<div v-if="skillOpen" class="ai-skill-popover">
|
||||
<div v-if="!filteredSkills.length" class="ai-skill-empty">
|
||||
{{ store.state.skills.length ? $t('aiChat.skillNoMatch') : $t('aiChat.skillNotLoaded') }}
|
||||
</div>
|
||||
<div
|
||||
v-for="(s, i) in filteredSkills"
|
||||
:key="s.path"
|
||||
class="ai-skill-item"
|
||||
:class="{ 'ai-skill-item--active': i === skillIndex }"
|
||||
@click="selectSkill(s)"
|
||||
@mouseenter="skillIndex = i"
|
||||
>
|
||||
<div class="ai-skill-item-row">
|
||||
<span class="ai-skill-item-name">/{{ s.name }}</span>
|
||||
<span class="ai-skill-item-desc">{{ s.description }}</span>
|
||||
<span class="ai-skill-item-src">{{ s.source }}</span>
|
||||
</div>
|
||||
<code v-if="s.argument_hint" class="ai-skill-item-hint">{{ s.argument_hint }}</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UX-10 §1.4: @ 实体引用浮层(@ 触发,选中插入 [类型:名] 标记,架构复用技能 popover) -->
|
||||
<div v-if="mentionOpen" class="ai-skill-popover ai-mention-popover">
|
||||
<div v-if="!mentionItems.length" class="ai-skill-empty">
|
||||
@@ -158,6 +128,8 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useAiStore } from '../../stores/ai'
|
||||
import { useProjectStore } from '../../stores/project'
|
||||
import { getConvState } from '../../composables/ai/useAiEvents'
|
||||
import SkillMention from './SkillMention.vue'
|
||||
import ImageInput from './ImageInput.vue'
|
||||
import type { AiMessage, ContentPart, SkillInfo, ProjectRecord, TaskRecord, IdeaRecord, MentionSpan } from '../../api/types'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
Reference in New Issue
Block a user