import { W as connection_default, a7 as loading_default, ab as warning_default, i as ElIcon, aa as delete_default, ac as setting_default, h as ElButton, ad as chat_dot_round_default, ae as user_default, af as arrow_down_default, ag as arrow_up_default, ah as copy_document_default, K as refresh_left_default, a0 as ElAlert, y as ElInput, ai as promotion_default, E as ElMessage, D as ElMessageBox } from "./element-plus.CkEW9frc.js"; import { J as defineComponent, ej as MarkdownIt, ek as markdownItHighlightjs, t as onMounted, ah as onUnmounted, S as openBlock, _ as createElementBlock, a1 as createBaseVNode, $ as createVNode, a0 as withCtx, T as createBlock, o as unref, a3 as normalizeClass, aa as toDisplayString, a9 as createTextVNode, a8 as createCommentVNode, H as Fragment, ay as renderList, a_ as withKeys, aw as withModifiers, r as ref, j as computed, n as nextTick, el as HighlightJS } from "./.pnpm.BW3P1y8f.js"; import { _ as _export_sfc } from "./_plugin-vue_export-helper.1tPrXgE0.js"; const _hoisted_1 = { class: "chatgpt-container" }; const _hoisted_2 = { class: "main-chat" }; const _hoisted_3 = { class: "chat-navbar" }; const _hoisted_4 = { class: "navbar-right" }; const _hoisted_5 = { class: "connection-status" }; const _hoisted_6 = { class: "status-text" }; const _hoisted_7 = { key: 0, class: "welcome-screen" }; const _hoisted_8 = { class: "welcome-content" }; const _hoisted_9 = { class: "ai-logo" }; const _hoisted_10 = { class: "example-prompts" }; const _hoisted_11 = { key: 1, class: "messages-list" }; const _hoisted_12 = { class: "message-avatar" }; const _hoisted_13 = { key: 0, class: "user-avatar" }; const _hoisted_14 = { key: 1, class: "ai-avatar" }; const _hoisted_15 = { class: "message-content" }; const _hoisted_16 = { class: "message-header" }; const _hoisted_17 = { class: "sender-name" }; const _hoisted_18 = { class: "message-body" }; const _hoisted_19 = ["innerHTML"]; const _hoisted_20 = { key: 1, class: "typing-indicator" }; const _hoisted_21 = { key: 0, class: "message-actions" }; const _hoisted_22 = { key: 2, class: "error-banner" }; const _hoisted_23 = { class: "chat-input" }; const _hoisted_24 = { class: "input-wrapper" }; const _hoisted_25 = { class: "input-container" }; const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "index", setup(__props) { const md = new MarkdownIt({ html: true, linkify: true, typographer: true, breaks: true, highlight(str, lang) { if (lang && HighlightJS.getLanguage(lang)) { try { return `
${HighlightJS.highlight(str, { language: lang, ignoreIllegals: true }).value}
`; } catch { } } return `
${md.utils.escapeHtml(str)}
`; } }).use(markdownItHighlightjs); const defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) { return self.renderToken(tokens, idx, options, env, self); }; md.renderer.rules.link_open = function(tokens, idx, options, env, self) { tokens[idx].attrPush(["target", "_blank"]); tokens[idx].attrPush(["rel", "noopener noreferrer"]); return defaultRender(tokens, idx, options, env, self); }; const messages = ref([]); const inputMessage = ref(""); const sending = ref(false); const isConnected = ref(false); const connectionStatus = ref("disconnected"); const error = ref(""); const messagesContainer = ref(); let ws = null; const WS_URL = "undefined/api/v1/application/ai/ws"; const connectionStatusText = computed(() => { switch (connectionStatus.value) { case "connected": return "已连接"; case "connecting": return "连接中..."; case "disconnected": return "未连接"; default: return "未知状态"; } }); const connectWebSocket = () => { if ((ws == null ? void 0 : ws.readyState) === WebSocket.OPEN) { return; } connectionStatus.value = "connecting"; error.value = ""; try { ws = new WebSocket(WS_URL); ws.onopen = () => { console.log("WebSocket 连接已建立"); isConnected.value = true; connectionStatus.value = "connected"; ElMessage.success("连接成功"); }; ws.onmessage = (event) => { handleWebSocketMessage({ content: event.data }); }; ws.onclose = (event) => { console.log("WebSocket 连接已关闭", event.code, event.reason); isConnected.value = false; connectionStatus.value = "disconnected"; messages.value.forEach((message) => { if (message.type === "assistant" && message.loading) { message.loading = false; message.collapsed = message.content.length > 200; } }); }; ws.onerror = (error2) => { console.error("WebSocket 错误:", error2); isConnected.value = false; connectionStatus.value = "disconnected"; ElMessage.error("连接失败,请检查服务器状态"); messages.value.forEach((message) => { if (message.type === "assistant" && message.loading) { message.loading = false; message.collapsed = message.content.length > 200; } }); }; } catch (err) { console.error("创建 WebSocket 连接失败:", err); connectionStatus.value = "disconnected"; error.value = "无法创建连接"; } }; const disconnectWebSocket = () => { if (ws) { ws.close(1e3, "用户主动断开"); ws = null; } isConnected.value = false; connectionStatus.value = "disconnected"; messages.value.forEach((message) => { if (message.type === "assistant" && message.loading) { message.loading = false; } }); }; const toggleConnection = () => { if (isConnected.value) { disconnectWebSocket(); ElMessage.info("已断开连接"); } else { connectWebSocket(); } }; const handleWebSocketMessage = (data) => { const lastMessage = messages.value[messages.value.length - 1]; if (lastMessage && lastMessage.type === "assistant" && lastMessage.loading) { lastMessage.content += data.content || data.message || ""; } else { addMessage("assistant", data.content || data.message || "收到回复"); } scrollToBottom(); }; const sendMessage = async () => { const message = inputMessage.value.trim(); if (!message || !isConnected.value || sending.value) { return; } const lastMessage = messages.value[messages.value.length - 1]; if (lastMessage && lastMessage.type === "assistant" && lastMessage.loading) { lastMessage.loading = false; } addMessage("user", message); inputMessage.value = ""; const loadingMessage = { id: generateId(), type: "assistant", content: "", timestamp: Date.now(), loading: true }; messages.value.push(loadingMessage); sending.value = true; scrollToBottom(); try { if ((ws == null ? void 0 : ws.readyState) === WebSocket.OPEN) { ws.send(message); } else { throw new Error("WebSocket 连接未建立"); } } catch (err) { console.error("发送消息失败:", err); messages.value.pop(); error.value = "发送消息失败,请检查连接状态"; ElMessage.error("发送失败"); } finally { sending.value = false; } }; const addMessage = (type, content) => { const message = { id: generateId(), type, content, timestamp: Date.now(), // 长消息自动折叠 collapsed: content.length > 200 }; messages.value.push(message); nextTick(() => scrollToBottom()); }; const clearCurrentChat = async () => { try { await ElMessageBox.confirm("确定要清空当前对话吗?此操作不可恢复。", "确认清空", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }); messages.value = []; ElMessage.success("对话已清空"); } catch { } }; const setPrompt = (prompt) => { inputMessage.value = prompt; }; const copyMessage = async (content) => { try { await navigator.clipboard.writeText(content); ElMessage.success("已复制到剪贴板"); } catch { const textArea = document.createElement("textarea"); textArea.value = content; document.body.appendChild(textArea); textArea.select(); document.execCommand("copy"); document.body.removeChild(textArea); ElMessage.success("已复制到剪贴板"); } }; const toggleMessageFold = (message) => { message.collapsed = !message.collapsed; }; const scrollToBottom = () => { nextTick(() => { if (messagesContainer.value) { messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight; } }); }; const formatMessage = (content) => { if (!content) return ""; return md.render(content); }; const generateId = () => { return Date.now().toString(36) + Math.random().toString(36).substr(2); }; onMounted(() => { connectWebSocket(); }); onUnmounted(() => { disconnectWebSocket(); }); return (_ctx, _cache) => { const _component_el_icon = ElIcon; const _component_el_button = ElButton; const _component_el_alert = ElAlert; const _component_el_input = ElInput; return openBlock(), createElementBlock("div", _hoisted_1, [ createBaseVNode("div", _hoisted_2, [ createBaseVNode("div", _hoisted_3, [ _cache[8] || (_cache[8] = createBaseVNode("div", { class: "navbar-left" }, [ createBaseVNode("h2", null, "FA智能助手") ], -1)), createBaseVNode("div", _hoisted_4, [ createBaseVNode("div", _hoisted_5, [ createVNode(_component_el_icon, { class: normalizeClass(["status-icon", connectionStatus.value]) }, { default: withCtx(() => [ connectionStatus.value === "connected" ? (openBlock(), createBlock(unref(connection_default), { key: 0 })) : connectionStatus.value === "connecting" ? (openBlock(), createBlock(unref(loading_default), { key: 1 })) : (openBlock(), createBlock(unref(warning_default), { key: 2 })) ]), _: 1 }, 8, ["class"]), createBaseVNode("span", _hoisted_6, toDisplayString(connectionStatusText.value), 1) ]), messages.value.length > 0 ? (openBlock(), createBlock(_component_el_button, { key: 0, text: "", icon: unref(delete_default), onClick: clearCurrentChat }, { default: withCtx(() => [..._cache[7] || (_cache[7] = [ createTextVNode(" 清空对话 ", -1) ])]), _: 1 }, 8, ["icon"])) : createCommentVNode("", true), createVNode(_component_el_button, { text: "", icon: unref(setting_default), onClick: toggleConnection }, { default: withCtx(() => [ createTextVNode(toDisplayString(isConnected.value ? "断开连接" : "重新连接"), 1) ]), _: 1 }, 8, ["icon"]) ]) ]), createBaseVNode("div", { ref_key: "messagesContainer", ref: messagesContainer, class: "chat-messages" }, [ messages.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_7, [ createBaseVNode("div", _hoisted_8, [ createBaseVNode("div", _hoisted_9, [ createVNode(_component_el_icon, { size: "64" }, { default: withCtx(() => [ createVNode(unref(chat_dot_round_default)) ]), _: 1 }) ]), _cache[13] || (_cache[13] = createBaseVNode("h1", null, "FA智能助手", -1)), _cache[14] || (_cache[14] = createBaseVNode("p", { class: "welcome-subtitle" }, " 我是您的专属AI助手,可以帮您回答问题、处理任务和进行智能对话 ", -1)), createBaseVNode("div", _hoisted_10, [ createBaseVNode("div", { class: "prompt-card", onClick: _cache[0] || (_cache[0] = ($event) => setPrompt("请介绍一下FastApiAdmin系统")) }, [..._cache[9] || (_cache[9] = [ createBaseVNode("h4", null, "系统介绍", -1), createBaseVNode("p", null, "请介绍一下FastApiAdmin系统", -1) ])]), createBaseVNode("div", { class: "prompt-card", onClick: _cache[1] || (_cache[1] = ($event) => setPrompt("如何在系统中创建新的模块?")) }, [..._cache[10] || (_cache[10] = [ createBaseVNode("h4", null, "开发指导", -1), createBaseVNode("p", null, "如何在系统中创建新的模块?", -1) ])]), createBaseVNode("div", { class: "prompt-card", onClick: _cache[2] || (_cache[2] = ($event) => setPrompt("系统的权限管理是如何工作的?")) }, [..._cache[11] || (_cache[11] = [ createBaseVNode("h4", null, "权限管理", -1), createBaseVNode("p", null, "FA系统的权限管理是如何工作的?", -1) ])]), createBaseVNode("div", { class: "prompt-card", onClick: _cache[3] || (_cache[3] = ($event) => setPrompt("如何优化FA系统的性能?")) }, [..._cache[12] || (_cache[12] = [ createBaseVNode("h4", null, "性能优化", -1), createBaseVNode("p", null, "如何优化系统的性能?", -1) ])]) ]) ]) ])) : (openBlock(), createElementBlock("div", _hoisted_11, [ (openBlock(true), createElementBlock(Fragment, null, renderList(messages.value, (message) => { return openBlock(), createElementBlock("div", { key: message.id, class: normalizeClass(["message-group", message.type]) }, [ createBaseVNode("div", _hoisted_12, [ message.type === "user" ? (openBlock(), createElementBlock("div", _hoisted_13, [ createVNode(_component_el_icon, null, { default: withCtx(() => [ createVNode(unref(user_default)) ]), _: 1 }) ])) : (openBlock(), createElementBlock("div", _hoisted_14, [ createVNode(_component_el_icon, null, { default: withCtx(() => [ createVNode(unref(chat_dot_round_default)) ]), _: 1 }) ])) ]), createBaseVNode("div", _hoisted_15, [ createBaseVNode("div", _hoisted_16, [ createBaseVNode("strong", _hoisted_17, toDisplayString(message.type === "user" ? "You" : "FA助手"), 1) ]), createBaseVNode("div", _hoisted_18, [ message.content.length > 200 ? (openBlock(), createBlock(_component_el_button, { key: 0, text: "", size: "small", icon: message.collapsed ? unref(arrow_down_default) : unref(arrow_up_default), class: "fold-button", onClick: ($event) => toggleMessageFold(message) }, { default: withCtx(() => [ createTextVNode(toDisplayString(message.collapsed ? "展开" : "收起"), 1) ]), _: 2 }, 1032, ["icon", "onClick"])) : createCommentVNode("", true), createBaseVNode("div", { class: normalizeClass(["message-text", { collapsed: message.collapsed }]), innerHTML: formatMessage(message.content) }, null, 10, _hoisted_19), message.type === "assistant" && message.loading && !message.content ? (openBlock(), createElementBlock("div", _hoisted_20, [..._cache[15] || (_cache[15] = [ createBaseVNode("div", { class: "typing-dots" }, [ createBaseVNode("span"), createBaseVNode("span"), createBaseVNode("span") ], -1) ])])) : createCommentVNode("", true) ]), !message.loading ? (openBlock(), createElementBlock("div", _hoisted_21, [ createVNode(_component_el_button, { text: "", size: "small", icon: unref(copy_document_default), onClick: ($event) => copyMessage(message.content) }, null, 8, ["icon", "onClick"]), message.type === "assistant" ? (openBlock(), createBlock(_component_el_button, { key: 0, text: "", size: "small", icon: unref(refresh_left_default) }, null, 8, ["icon"])) : createCommentVNode("", true) ])) : createCommentVNode("", true) ]) ], 2); }), 128)) ])), error.value ? (openBlock(), createElementBlock("div", _hoisted_22, [ createVNode(_component_el_alert, { title: error.value, type: "error", closable: true, "show-icon": "", onClose: _cache[4] || (_cache[4] = ($event) => error.value = "") }, null, 8, ["title"]) ])) : createCommentVNode("", true) ], 512), createBaseVNode("div", _hoisted_23, [ createBaseVNode("div", _hoisted_24, [ createBaseVNode("div", _hoisted_25, [ createVNode(_component_el_input, { modelValue: inputMessage.value, "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => inputMessage.value = $event), placeholder: isConnected.value ? "向FA助手发送消息..." : "请先连接到服务器", disabled: !isConnected.value || sending.value, type: "textarea", rows: 1, autosize: { minRows: 1, maxRows: 6 }, resize: "none", class: "message-input", onKeydown: [ withKeys(withModifiers(sendMessage, ["exact", "prevent"]), ["enter"]), _cache[6] || (_cache[6] = withKeys(withModifiers(($event) => inputMessage.value += "\n", ["shift", "exact"]), ["enter"])) ] }, null, 8, ["modelValue", "placeholder", "disabled", "onKeydown"]), createVNode(_component_el_button, { disabled: !inputMessage.value.trim() || !isConnected.value || sending.value, loading: sending.value, class: "send-button", type: "primary", circle: "", onClick: sendMessage }, { default: withCtx(() => [ createVNode(_component_el_icon, null, { default: withCtx(() => [ createVNode(unref(promotion_default)) ]), _: 1 }) ]), _: 1 }, 8, ["disabled", "loading"]) ]), _cache[16] || (_cache[16] = createBaseVNode("div", { class: "input-footer" }, [ createBaseVNode("span", { class: "input-hint" }, "按 Enter 发送消息,Shift + Enter 换行") ], -1)) ]) ]) ]) ]); }; } }); const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9253047d"]]); export { index as default };