管理在对话中上传的文件。需要让 AI 引用某文件时,在列表中点击「复制路径」,到对话里粘贴即可。
+管理在对话中上传的文件。可将文件拖拽到下方列表区域,或点击「上传文件」选择文件(支持多选)。需要让 AI 引用某文件时,在列表中点击「复制路径」,到对话里粘贴即可。
diff --git a/web/static/css/style.css b/web/static/css/style.css index d48d02e8..8442b61e 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -2750,6 +2750,19 @@ html[data-theme="dark"] .openapi-doc-btn:hover { flex-shrink: 0; } +.message-avatar svg { + width: 17px; + height: 17px; + flex-shrink: 0; +} + +.message-avatar-img { + width: 20px; + height: 20px; + border-radius: 4px; + object-fit: contain; +} + .message.user .message-avatar { background: var(--accent-color); color: white; @@ -20943,8 +20956,17 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible { } .vulnerability-header:hover { - background-color: var(--bg-secondary); - border-radius: 4px; + background-color: rgba(0, 102, 255, 0.04); + border-radius: 6px; +} + +html[data-theme="dark"] .vulnerability-header:hover { + background-color: rgba(96, 165, 250, 0.08); +} + +html[data-theme="dark"] .vulnerability-card:hover { + border-color: #334155; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.22); } .vulnerability-title-section { @@ -23750,6 +23772,12 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible { border-radius: 8px; } +.chat-files-table-wrap.drag-over { + background: rgba(0, 102, 255, 0.06); + outline: 2px dashed rgba(0, 102, 255, 0.35); + outline-offset: -2px; +} + /* 分组视图:外层不再套一层大边框,由各分组卡片承担 */ .chat-files-table-wrap.chat-files-table-wrap--grouped { border: none; @@ -24049,7 +24077,13 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - vertical-align: bottom; + vertical-align: middle; + padding: 2px 8px; + border-radius: 6px; + background: var(--bg-secondary); + color: var(--text-primary); + border: 1px solid var(--border-color); + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; } .chat-files-cell-subpath { @@ -24181,7 +24215,8 @@ button.chat-files-dropdown-item:hover:not(:disabled) { } /* 文件管理:重命名 / 新建文件夹 — 紧凑表单弹窗,无全局紫色标题条 */ -.chat-files-form-modal { +/* display 由 .modal(默认 none)与 openAppModal 内联 flex 控制,勿在此写 display:flex */ +.modal.chat-files-form-modal { align-items: center; justify-content: center; padding: 24px 16px; @@ -24310,18 +24345,19 @@ button.chat-files-dropdown-item:hover:not(:disabled) { .chat-files-toast { position: fixed; - z-index: 1100; + z-index: 10100; bottom: 28px; left: 50%; transform: translateX(-50%) translateY(12px); max-width: min(520px, calc(100vw - 32px)); padding: 12px 18px; - background: var(--text-primary, #1a1a1a); - color: #fff; + background: #111827; + color: #f1f5f9; + border: 1px solid #334155; border-radius: 8px; font-size: 0.875rem; line-height: 1.45; - box-shadow: var(--shadow-lg); + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.28); opacity: 0; transition: opacity 0.25s ease, transform 0.25s ease; pointer-events: none; @@ -24335,6 +24371,21 @@ button.chat-files-dropdown-item:hover:not(:disabled) { .chat-files-toast.chat-toast--error { background: #b91c1c; + color: #fff; + border-color: #991b1b; +} + +html[data-theme="dark"] .chat-files-toast { + background: var(--bg-tertiary); + color: var(--text-primary); + border-color: var(--border-color); + box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45); +} + +html[data-theme="dark"] .chat-files-toast.chat-toast--error { + background: #991b1b; + color: #fecaca; + border-color: #b91c1c; } /* 对话附件读取 / 文件管理上传 进度条 */ @@ -27566,6 +27617,12 @@ html[data-theme="dark"] .chat-files-table tr:hover td { background: rgba(96, 165, 250, 0.08); } +html[data-theme="dark"] .chat-files-cell-conv code { + background: var(--bg-secondary) !important; + color: var(--text-primary); + border: 1px solid var(--border-color); +} + html[data-theme="dark"] code, html[data-theme="dark"] pre, html[data-theme="dark"] .code-block, @@ -27612,6 +27669,33 @@ html[data-theme="dark"] .message.user .message-bubble { color: #ffffff; } +html[data-theme="dark"] .message-avatar { + border-radius: 50%; +} + +html[data-theme="dark"] .message.user .message-avatar { + background: linear-gradient(135deg, #2563eb 0%, #4f46e5 100%); + color: #ffffff; + box-shadow: + 0 0 0 2px rgba(96, 165, 250, 0.22), + 0 2px 10px rgba(37, 99, 235, 0.38); + border: none; +} + +html[data-theme="dark"] .message.assistant .message-avatar { + background: linear-gradient(145deg, #1e293b 0%, #0f172a 100%); + color: var(--text-secondary); + border: 1px solid rgba(96, 165, 250, 0.28); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.32); + padding: 3px; +} + +html[data-theme="dark"] .message.assistant .message-avatar-img { + width: 22px; + height: 22px; + border-radius: 50%; +} + html[data-theme="dark"] .message.system .message-bubble, html[data-theme="dark"] .loading-spinner, html[data-theme="dark"] .empty-state, @@ -28158,7 +28242,6 @@ html[data-theme="dark"] .hitl-page-tab--active { html[data-theme="dark"] .hitl-page-reviewer-label, html[data-theme="dark"] .hitl-page-whitelist-label, html[data-theme="dark"] .hitl-page-strategy-label, -html[data-theme="dark"] .hitl-pending-item-title, html[data-theme="dark"] .hitl-log-detail-row dd, html[data-theme="dark"] .projects-sidebar-title, html[data-theme="dark"] .projects-list-item-name, @@ -28312,6 +28395,79 @@ html[data-theme="dark"] .webshell-db-count { border-color: rgba(96, 165, 250, 0.24) !important; } +html[data-theme="dark"] .hitl-tool-badge { + background: linear-gradient(135deg, #2563eb 0%, #4f46e5 100%) !important; + color: #ffffff !important; + -webkit-text-fill-color: #ffffff !important; +} + +html[data-theme="dark"] .hitl-mode-tag { + background: rgba(96, 165, 250, 0.14) !important; + color: #93c5fd !important; + border: 1px solid rgba(96, 165, 250, 0.28) !important; + -webkit-text-fill-color: #93c5fd !important; +} + +html[data-theme="dark"] .hitl-mode-tag--review_edit { + background: rgba(251, 191, 36, 0.14) !important; + color: #fde68a !important; + border-color: rgba(251, 191, 36, 0.28) !important; + -webkit-text-fill-color: #fde68a !important; +} + +html[data-theme="dark"] .hitl-pending-meta { + color: var(--text-muted) !important; +} + +html[data-theme="dark"] .hitl-context-label { + color: var(--text-secondary) !important; +} + +html[data-theme="dark"] .hitl-context-block--execution .hitl-context-text { + background: rgba(52, 211, 153, 0.08) !important; + border-color: rgba(52, 211, 153, 0.28) !important; + color: var(--text-primary) !important; +} + +html[data-theme="dark"] .hitl-pending-actions { + border-top-color: #263244 !important; +} + +html[data-theme="dark"] .hitl-inline-approval { + background: rgba(96, 165, 250, 0.08) !important; + border-color: rgba(96, 165, 250, 0.22) !important; +} + +html[data-theme="dark"] .hitl-apply-feedback { + background: rgba(52, 211, 153, 0.12) !important; + color: #6ee7b7 !important; + border-color: rgba(52, 211, 153, 0.28) !important; +} + +html[data-theme="dark"] .hitl-apply-feedback.hitl-apply-feedback--error { + background: rgba(248, 113, 113, 0.12) !important; + color: #fca5a5 !important; + border-color: rgba(248, 113, 113, 0.28) !important; +} + +html[data-theme="dark"] .hitl-apply-feedback.hitl-apply-feedback--partial { + background: rgba(251, 191, 36, 0.12) !important; + color: #fde68a !important; + border-color: rgba(251, 191, 36, 0.28) !important; +} + +html[data-theme="dark"] .hitl-decision-tag.hitl-decision--approve { + background: rgba(52, 211, 153, 0.14) !important; + color: #6ee7b7 !important; + border: 1px solid rgba(52, 211, 153, 0.28) !important; +} + +html[data-theme="dark"] .hitl-decision-tag.hitl-decision--reject { + background: rgba(248, 113, 113, 0.14) !important; + color: #fca5a5 !important; + border: 1px solid rgba(248, 113, 113, 0.28) !important; +} + html[data-theme="dark"] #page-projects .projects-graph-stat-badge { background: rgba(15, 23, 42, 0.6) !important; color: var(--text-secondary) !important; diff --git a/web/static/i18n/en-US.json b/web/static/i18n/en-US.json index 7903b27e..2f1778de 100644 --- a/web/static/i18n/en-US.json +++ b/web/static/i18n/en-US.json @@ -683,7 +683,7 @@ "hitl": { "pageTitle": "HITL approvals", "pageReviewerLabel": "Current reviewer", - "pageReviewerHint": "Applies to the selected conversation. Without a conversation, saved locally for new chats. Takes effect immediately.", + "pageReviewerHint": "Applies to the selected conversation. Without a conversation, saved to config.yaml as the global default for new chats. Takes effect immediately.", "pageReviewerSaved": "Reviewer saved.", "whitelistLabel": "Tool whitelist (no approval)", "whitelistHint": "One per line or comma-separated. Saved to config.yaml global whitelist and takes effect immediately (synced with chat sidebar).", @@ -1915,7 +1915,7 @@ }, "chatFilesPage": { "title": "File Management", - "intro": "Files uploaded in chat appear here. Click “Copy path” to copy the server absolute path and paste it into a conversation so the model can reference the file.", + "intro": "Files uploaded in chat appear here. Drag files into the list below, or click Upload to pick files (multiple allowed). Click “Copy path” to copy the server absolute path and paste it into a conversation so the model can reference the file.", "upload": "Upload", "conversationFilter": "Conversation ID", "conversationPlaceholder": "Leave empty for all", diff --git a/web/static/i18n/zh-CN.json b/web/static/i18n/zh-CN.json index 9df82203..7be6e6da 100644 --- a/web/static/i18n/zh-CN.json +++ b/web/static/i18n/zh-CN.json @@ -671,7 +671,7 @@ "hitl": { "pageTitle": "人机协同审批", "pageReviewerLabel": "当前审批方", - "pageReviewerHint": "作用于当前选中会话;未选会话时保存到本机,新建会话时沿用。切换后立即生效。", + "pageReviewerHint": "作用于当前选中会话;未选会话时写入 config.yaml 作为全局默认,新建会话时沿用。切换后立即生效。", "pageReviewerSaved": "审批方已保存。", "whitelistLabel": "免审批工具白名单", "whitelistHint": "每行一个或逗号分隔;保存后写入 config.yaml 全局白名单并立即生效(与聊天侧栏同步展示)。", @@ -1903,7 +1903,7 @@ }, "chatFilesPage": { "title": "文件管理", - "intro": "管理在对话中上传的文件。需要让 AI 引用某文件时,在列表中点击「复制路径」,到对话里粘贴即可(路径为服务器上的绝对路径,与对话附件保存位置一致)。", + "intro": "管理在对话中上传的文件。可将文件拖拽到下方列表区域,或点击「上传文件」选择文件(支持多选)。需要让 AI 引用某文件时,在列表中点击「复制路径」,到对话里粘贴即可(路径为服务器上的绝对路径,与对话附件保存位置一致)。", "upload": "上传文件", "conversationFilter": "会话 ID", "conversationPlaceholder": "留空表示全部", diff --git a/web/static/js/chat-files.js b/web/static/js/chat-files.js index 5c71999d..cd79fa4c 100644 --- a/web/static/js/chat-files.js +++ b/web/static/js/chat-files.js @@ -84,6 +84,7 @@ function initChatFilesPage() { /* ignore */ } } + setupChatFilesDragDrop(); loadChatFilesPage(); } @@ -1226,21 +1227,31 @@ function chatFilesUploadToFolderClick(ev, btn) { if (inp) inp.click(); } -async function onChatFilesUploadPick(ev) { - const input = ev.target; - const file = input && input.files && input.files[0]; - if (!file) return; - const form = new FormData(); - form.append('file', file); +function chatFilesResolveUploadTarget() { const pendingDir = chatFilesPendingUploadDir; chatFilesPendingUploadDir = ''; if (pendingDir) { - form.append('relativeDir', pendingDir); - } else { - const conv = document.getElementById('chat-files-filter-conv'); - if (conv && conv.value.trim()) { - form.append('conversationId', conv.value.trim()); - } + return { relativeDir: pendingDir }; + } + if (chatFilesGetGroupByMode() === 'folder') { + const dir = chatFilesBrowsePath.join('/'); + return dir ? { relativeDir: dir } : {}; + } + const conv = document.getElementById('chat-files-filter-conv'); + if (conv && conv.value.trim()) { + return { conversationId: conv.value.trim() }; + } + return {}; +} + +async function chatFilesUploadFile(file, target) { + if (!file || chatFilesXHRUploadBusy) return false; + const form = new FormData(); + form.append('file', file); + if (target && target.relativeDir) { + form.append('relativeDir', target.relativeDir); + } else if (target && target.conversationId) { + form.append('conversationId', target.conversationId); } chatFilesSetUploadBusy(true); chatFilesSetUploadProgressUI(true, 0, file.name); @@ -1265,15 +1276,75 @@ async function onChatFilesUploadPick(ev) { : '上传成功。在列表中点击「复制路径」即可粘贴到对话中引用。'; chatFilesShowToast(msg); } + return true; } catch (e) { alert((e && e.message) ? e.message : String(e)); + return false; } finally { chatFilesSetUploadBusy(false); chatFilesSetUploadProgressUI(false); + } +} + +async function chatFilesUploadFiles(fileList) { + if (!fileList || !fileList.length || chatFilesXHRUploadBusy) return; + const files = Array.from(fileList).filter(function (f) { + return f && (f.name || f.size > 0); + }); + if (!files.length) return; + const target = chatFilesResolveUploadTarget(); + for (let i = 0; i < files.length; i++) { + const ok = await chatFilesUploadFile(files[i], target); + if (!ok) break; + } +} + +async function onChatFilesUploadPick(ev) { + const input = ev.target; + const files = input && input.files; + if (!files || !files.length) return; + try { + await chatFilesUploadFiles(files); + } finally { input.value = ''; } } +let chatFilesDragDropBound = false; + +function setupChatFilesDragDrop() { + if (chatFilesDragDropBound) return; + const wrap = document.getElementById('chat-files-list-wrap'); + if (!wrap) return; + chatFilesDragDropBound = true; + + wrap.addEventListener('dragover', function (e) { + e.preventDefault(); + e.stopPropagation(); + if (chatFilesXHRUploadBusy) return; + this.classList.add('drag-over'); + }); + wrap.addEventListener('dragleave', function (e) { + e.preventDefault(); + e.stopPropagation(); + if (!this.contains(e.relatedTarget)) { + this.classList.remove('drag-over'); + } + }); + wrap.addEventListener('drop', function (e) { + e.preventDefault(); + e.stopPropagation(); + this.classList.remove('drag-over'); + if (chatFilesXHRUploadBusy) return; + const files = e.dataTransfer && e.dataTransfer.files; + if (files && files.length) { + chatFilesUploadFiles(files).catch(function (err) { + if (err) alert((err && err.message) ? err.message : String(err)); + }); + } + }); +} + // 语言切换后重新渲染列表:表头与「更多」菜单由 JS 拼接,无 data-i18n,需用当前语言的 t() 再生成一遍 document.addEventListener('languagechange', function () { if (typeof window.currentPage !== 'function') return; diff --git a/web/static/js/chat.js b/web/static/js/chat.js index a4cbc827..85c9a03d 100644 --- a/web/static/js/chat.js +++ b/web/static/js/chat.js @@ -137,9 +137,12 @@ function normalizeHitlMode(mode) { } function defaultHitlConfig() { + const serverReviewer = (typeof window !== 'undefined' && window.csaiHitlDefaultReviewer) + ? window.csaiHitlDefaultReviewer + : 'human'; return { mode: HITL_MODE_OFF, - reviewer: 'human', + reviewer: normalizeHitlReviewer(serverReviewer), sensitiveTools: '', updatedAt: '' }; @@ -315,16 +318,18 @@ async function onHitlReviewerChanged(reviewer) { const cfg = readHitlConfigFromForm(); const cid = typeof currentConversationId === 'string' ? currentConversationId.trim() : ''; saveHitlConfigForConversation(cid, cfg, { syncGlobalLast: true }); - if (cid && typeof window.saveHitlConversationConfig === 'function') { - try { + try { + if (cid && typeof window.saveHitlConversationConfig === 'function') { await window.saveHitlConversationConfig(cid, cfg); - const ok = typeof window.t === 'function' ? window.t('hitl.pageReviewerSaved') : '审批方已保存。'; - showChatToast(ok, 'success'); - } catch (e) { - console.warn('onHitlReviewerChanged', e); - const prefix = typeof window.t === 'function' ? window.t('chat.hitlApplyFail') : '同步到服务器失败'; - showChatToast(prefix, 'error'); + } else if (typeof window.putHitlDefaultReviewer === 'function') { + await window.putHitlDefaultReviewer(cfg.reviewer); } + const ok = typeof window.t === 'function' ? window.t('hitl.pageReviewerSaved') : '审批方已保存。'; + showChatToast(ok, 'success'); + } catch (e) { + console.warn('onHitlReviewerChanged', e); + const prefix = typeof window.t === 'function' ? window.t('chat.hitlApplyFail') : '同步到服务器失败'; + showChatToast(prefix, 'error'); } } @@ -507,6 +512,7 @@ function chatAgentModeNormalizeStored(stored, cfg) { if (typeof window !== 'undefined') { window.csaiHitlGlobalToolWhitelist = window.csaiHitlGlobalToolWhitelist || []; + window.csaiHitlDefaultReviewer = window.csaiHitlDefaultReviewer || 'human'; window.csaiChatAgentMode = { EINO_MODES: CHAT_AGENT_EINO_MODES, EINO_SINGLE: CHAT_AGENT_MODE_EINO_SINGLE, @@ -518,6 +524,7 @@ if (typeof window !== 'undefined') { window.applyHitlSidebarConfig = applyHitlSidebarConfig; window.readHitlConfigFromForm = readHitlConfigFromForm; window.applyHitlConfigToUI = applyHitlConfigToUI; + window.refreshHitlConfigByCurrentConversation = refreshHitlConfigByCurrentConversation; window.saveHitlConfigForConversation = saveHitlConfigForConversation; window.getHitlConfigForConversation = getHitlConfigForConversation; bindHitlSidebarModeListener(); @@ -2020,6 +2027,19 @@ function refreshSystemReadyMessageBubbles() { }); } +function createMessageAvatar(role) { + const avatar = document.createElement('div'); + avatar.className = 'message-avatar'; + if (role === 'user') { + avatar.innerHTML = ''; + } else if (role === 'assistant') { + avatar.innerHTML = ''; + } else { + avatar.textContent = 'S'; + } + return avatar; +} + // 添加消息(options.systemReadyMessage 为 true 时,语言切换会刷新该条文案) function addMessage(role, content, mcpExecutionIds = null, progressId = null, createdAt = null, options = null) { const messagesDiv = document.getElementById('chat-messages'); @@ -2030,16 +2050,7 @@ function addMessage(role, content, mcpExecutionIds = null, progressId = null, cr messageDiv.className = 'message ' + role; // 创建头像 - const avatar = document.createElement('div'); - avatar.className = 'message-avatar'; - if (role === 'user') { - avatar.textContent = 'U'; - } else if (role === 'assistant') { - avatar.textContent = 'A'; - } else { - avatar.textContent = 'S'; - } - messageDiv.appendChild(avatar); + messageDiv.appendChild(createMessageAvatar(role)); // 创建消息内容容器 const contentWrapper = document.createElement('div'); diff --git a/web/static/js/hitl.js b/web/static/js/hitl.js index d35d0b10..b52ee233 100644 --- a/web/static/js/hitl.js +++ b/web/static/js/hitl.js @@ -231,10 +231,66 @@ async function fetchHitlConversationConfig(conversationId) { if (!data || !data.hitl) return null; return { hitl: data.hitl, + defaultReviewer: hitlReviewerNormalize(data.defaultReviewer || 'human'), hitlGlobalToolWhitelist: Array.isArray(data.hitlGlobalToolWhitelist) ? data.hitlGlobalToolWhitelist : [] }; } +function applyHitlDefaultReviewerFromServer(reviewer) { + const v = hitlReviewerNormalize(reviewer); + if (typeof window !== 'undefined') { + window.csaiHitlDefaultReviewer = v; + } + if (typeof window.saveHitlLastGlobalConfig === 'function' && typeof window.getHitlLastGlobalConfig === 'function') { + const gl = window.getHitlLastGlobalConfig(); + const base = gl && typeof gl === 'object' + ? gl + : { mode: 'off', sensitiveTools: '', updatedAt: '' }; + window.saveHitlLastGlobalConfig(Object.assign({}, base, { + reviewer: v, + updatedAt: new Date().toISOString() + })); + } + return v; +} + +async function fetchHitlDefaultReviewer() { + const resp = await hitlApiFetch('/api/hitl/default-reviewer', { credentials: 'same-origin' }); + if (!resp.ok) { + return applyHitlDefaultReviewerFromServer('human'); + } + const data = await resp.json(); + return applyHitlDefaultReviewerFromServer(data && data.defaultReviewer); +} + +async function putHitlDefaultReviewer(reviewer) { + const normalized = hitlReviewerNormalize(reviewer); + const resp = await hitlApiFetch('/api/hitl/default-reviewer', { + method: 'PUT', + credentials: 'same-origin', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ reviewer: normalized }) + }); + if (!resp.ok) { + const msg = await readHitlApiError(resp); + throw new Error(msg || ('HTTP ' + resp.status)); + } + const data = await resp.json(); + return applyHitlDefaultReviewerFromServer(data && data.defaultReviewer); +} + +async function initHitlDefaultReviewerFromServer() { + try { + await fetchHitlDefaultReviewer(); + if (!getCurrentConversationIdForHitl() && typeof window.refreshHitlConfigByCurrentConversation === 'function') { + window.refreshHitlConfigByCurrentConversation(); + } + refreshHitlPageReviewerBar(); + } catch (e) { + console.warn('initHitlDefaultReviewerFromServer', e); + } +} + /** 无会话时:将免审批工具合并进服务端 config.yaml,返回更新后的全局白名单数组 */ async function mergeHitlGlobalToolWhitelist(sensitiveTools) { const list = Array.isArray(sensitiveTools) ? sensitiveTools : []; @@ -462,6 +518,9 @@ async function syncHitlConfigFromServer(conversationId) { const pack = await fetchHitlConversationConfig(conversationId); if (!pack || !pack.hitl) return; const cfg = pack.hitl; + if (pack.defaultReviewer) { + applyHitlDefaultReviewerFromServer(pack.defaultReviewer); + } const globalWL = pack.hitlGlobalToolWhitelist || []; if (typeof window !== 'undefined') { window.csaiHitlGlobalToolWhitelist = globalWL; @@ -1460,6 +1519,7 @@ document.addEventListener('DOMContentLoaded', function () { if (typeof window.bindHitlReviewerToggleListeners === 'function') { window.bindHitlReviewerToggleListeners(); } + initHitlDefaultReviewerFromServer(); setTimeout(reconcileHitlUiState, 0); }); @@ -1478,3 +1538,5 @@ window.mergeHitlGlobalToolWhitelist = mergeHitlGlobalToolWhitelist; // 由 chat.js 在 loadConversation 内 await 调用;挂到 window 供其它入口显式触发 window.syncHitlConfigFromServer = syncHitlConfigFromServer; +window.fetchHitlDefaultReviewer = fetchHitlDefaultReviewer; +window.putHitlDefaultReviewer = putHitlDefaultReviewer; diff --git a/web/static/js/modal.js b/web/static/js/modal.js index f882100e..1a8e5dcd 100644 --- a/web/static/js/modal.js +++ b/web/static/js/modal.js @@ -34,6 +34,9 @@ if (el.classList.contains('info-collect-cell-modal')) { return 'flex'; } + if (el.classList.contains('chat-files-form-modal')) { + return 'flex'; + } if (FLEX_MODAL_IDS.has(el.id)) { return 'flex'; } diff --git a/web/templates/index.html b/web/templates/index.html index a21497c4..eacc1dc7 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -2290,12 +2290,12 @@
管理在对话中上传的文件。需要让 AI 引用某文件时,在列表中点击「复制路径」,到对话里粘贴即可。
+管理在对话中上传的文件。可将文件拖拽到下方列表区域,或点击「上传文件」选择文件(支持多选)。需要让 AI 引用某文件时,在列表中点击「复制路径」,到对话里粘贴即可。