|
@@ -19,6 +19,7 @@ import {
|
|
|
Promotion,
|
|
|
VideoPause,
|
|
|
CopyDocument,
|
|
|
+ Plus,
|
|
|
} from '@element-plus/icons-vue'
|
|
|
import { MarkdownPlugin } from '/@/components/markdown/type/markdown'
|
|
|
import EChartsPlugin from '/@/components/markdown/plugins/echarts'
|
|
@@ -32,6 +33,7 @@ import { Setting as EleSetting } from '@element-plus/icons-vue'
|
|
|
import { useRouter } from 'vue-router'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
import StructDataPlugin from '/@/components/markdown/plugins/struct-data'
|
|
|
+import { useFileDialog } from '@vueuse/core'
|
|
|
|
|
|
const plugins: Array<MarkdownPlugin<any>> = [EChartsPlugin(), ToolsLoadingPlugin(), TablePlugin(), StructDataPlugin()]
|
|
|
|
|
@@ -41,8 +43,35 @@ const messages = ref<Message[]>([])
|
|
|
|
|
|
// 输入框内容
|
|
|
const inputMessage = ref('')
|
|
|
+const {open,reset,files: attachments} = useFileDialog({
|
|
|
+ multiple: true,
|
|
|
+})
|
|
|
const messagesContainer = ref<HTMLElement>()
|
|
|
|
|
|
+// 附件管理:使用本地列表以支持单个移除
|
|
|
+const selectedFiles = ref<File[]>([])
|
|
|
+
|
|
|
+// 监听文件选择并合并到本地列表(按 name+size+lastModified 去重)
|
|
|
+watch(
|
|
|
+ attachments,
|
|
|
+ (newFiles) => {
|
|
|
+ const incoming = Array.from(newFiles ?? [])
|
|
|
+ const merged = [...selectedFiles.value, ...incoming]
|
|
|
+ const map = new Map<string, File>()
|
|
|
+ for (const f of merged) {
|
|
|
+ const key = `${f.name}_${f.size}_${(f as any).lastModified ?? ''}`
|
|
|
+ if (!map.has(key)) map.set(key, f)
|
|
|
+ }
|
|
|
+ selectedFiles.value = Array.from(map.values())
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+)
|
|
|
+
|
|
|
+const removeAttachment = (index: number) => {
|
|
|
+ if (index < 0 || index >= selectedFiles.value.length) return
|
|
|
+ selectedFiles.value.splice(index, 1)
|
|
|
+}
|
|
|
+
|
|
|
// // 选中的工具和模型
|
|
|
// const selectedTool = ref([])
|
|
|
// // 工具选择
|
|
@@ -1114,9 +1143,36 @@ const isBlank = (str: string) => {
|
|
|
<div class="messages-spacer"></div>
|
|
|
</div>
|
|
|
|
|
|
+ <!-- 附件栏(内嵌到输入框上方) -->
|
|
|
+
|
|
|
<div class="input-container" v-if="activeConversationId !== -1">
|
|
|
<!-- 大输入框容器 -->
|
|
|
<div class="large-input-container">
|
|
|
+ <!-- 附件栏:紧贴输入框上方,位于容器内部 -->
|
|
|
+ <div class="attachments-inline">
|
|
|
+ <el-scrollbar>
|
|
|
+ <div class="attachments-inline-scroll">
|
|
|
+ <div
|
|
|
+ v-for="(file, fIdx) in selectedFiles"
|
|
|
+ :key="file.name + '_' + file.size + '_' + (file as any).lastModified"
|
|
|
+ class="attachment-card"
|
|
|
+ title=""
|
|
|
+ >
|
|
|
+ <button class="control-btn attachment-item" :title="`${file.name}`">
|
|
|
+ <el-icon :size="10"><CopyDocument /></el-icon>
|
|
|
+ <span class="attachment-name">{{ file.name }}</span>
|
|
|
+ </button>
|
|
|
+ <button class="remove-attachment-icon" @click="removeAttachment(fIdx)">
|
|
|
+ <el-icon><Close /></el-icon>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-scrollbar>
|
|
|
+ <button class="control-btn add-attachment-btn" @click="open">
|
|
|
+ <el-icon :size="10"><Plus /></el-icon>
|
|
|
+ <span>添加附件</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
<!-- 输入框 -->
|
|
|
<textarea
|
|
|
v-model="inputMessage"
|
|
@@ -1873,6 +1929,70 @@ const isBlank = (str: string) => {
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
+/* 附件栏(内嵌)样式 */
|
|
|
+.attachments-inline {
|
|
|
+ width: 100%;
|
|
|
+ padding: 8px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.attachments-inline-scroll {
|
|
|
+ flex: 1;
|
|
|
+ //overflow-x: auto;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.attachment-card {
|
|
|
+ position: relative;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.attachment-item {
|
|
|
+ /* 对齐下方控制按钮的尺寸与风格 */
|
|
|
+ max-width: 260px;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+
|
|
|
+ font-size: 10px!important;
|
|
|
+}
|
|
|
+
|
|
|
+.attachment-name {
|
|
|
+ max-width: 200px;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+
|
|
|
+.add-attachment-btn {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 10px!important;
|
|
|
+}
|
|
|
+
|
|
|
+.remove-attachment-icon {
|
|
|
+ position: absolute;
|
|
|
+ top: -6px;
|
|
|
+ right: -6px;
|
|
|
+ width: 18px;
|
|
|
+ height: 18px;
|
|
|
+ border-radius: 50%;
|
|
|
+ border: 1px solid var(--el-border-color-light);
|
|
|
+ background: var(--el-bg-color);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ cursor: pointer;
|
|
|
+ color: var(--el-text-color-regular);
|
|
|
+ padding: 0;
|
|
|
+}
|
|
|
+
|
|
|
.large-input-container {
|
|
|
position: relative;
|
|
|
width: 100%;
|