ForcePilot/web/src/components/AiTextarea.vue
Wenjie Zhang 62685b7ffe refactor: 重构组件和样式以改善UI/UX
- 重构FileDetailModal.vue,增加了下载选项下拉菜单并优化了布局。
- 移除部分页面的响应式媒体查询,不做响应式适配,仅适配大众尺寸
- 改进了ChunkParamsConfig.vue的布局,更好地分组参数。
- 调整了FileTable.vue,改善排序和筛选UI,包括状态筛选逻辑。
- 优化了FileUploadModal.vue的布局,提高OCR引擎配置的可见性。
- 其他  AiTextarea.vue / DataBaseView.vue / AppLayout.vue / file_utils.js / DataBaseInfoView.vue / FeedbackModalComponent.vue / FileTable.vue
2026-01-15 04:54:53 +08:00

121 lines
2.5 KiB
Vue

<template>
<div class="ai-textarea-wrapper">
<a-textarea
:value="modelValue"
@update:value="$emit('update:modelValue', $event)"
:placeholder="placeholder"
:rows="rows"
:auto-size="autoSize"
/>
<a-tooltip v-if="name" title="使用 AI 生成或优化描述">
<a-button
class="ai-btn"
type="text"
size="small"
:loading="loading"
@click="generateDescription"
>
<template #icon>
<WandSparkles size="14" />
</template>
<span v-if="!loading" class="ai-text">{{ modelValue?.trim() ? '润色' : '生成' }}</span>
</a-button>
</a-tooltip>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { message } from 'ant-design-vue'
import { databaseApi } from '@/apis/knowledge_api'
import { WandSparkles } from 'lucide-vue-next'
const props = defineProps({
modelValue: {
type: String,
default: ''
},
name: {
type: String,
default: ''
},
placeholder: {
type: String,
default: ''
},
rows: {
type: Number,
default: 4
},
autoSize: {
type: [Boolean, Object],
default: false
},
files: {
type: Array,
default: () => []
}
})
const emit = defineEmits(['update:modelValue'])
const loading = ref(false)
const generateDescription = async () => {
if (!props.name?.trim()) {
message.warning('请先输入知识库名称')
return
}
loading.value = true
try {
const result = await databaseApi.generateDescription(props.name, props.modelValue, props.files)
if (result.status === 'success' && result.description) {
emit('update:modelValue', result.description)
message.success('描述生成成功')
} else {
message.error(result.message || '生成失败')
}
} catch (error) {
console.error('生成描述失败:', error)
message.error(error.message || '生成描述失败')
} finally {
loading.value = false
}
}
</script>
<style lang="less" scoped>
.ai-textarea-wrapper {
position: relative;
.ai-btn {
position: absolute;
opacity: 0.9;
top: 4px;
right: 4px;
z-index: 1;
display: flex;
align-items: center;
gap: 4px;
padding: 2px 6px;
height: 24px;
color: var(--main-color);
background: var(--gray-50);
border: 1px solid var(--gray-200);
border-radius: 4px;
font-size: 12px;
transition: all 0.2s ease;
&:hover {
background: var(--main-10);
border-color: var(--main-color);
}
.ai-text {
font-weight: 500;
}
}
}
</style>