|
|
@@ -55,7 +55,11 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div class="chat-main-area">
|
|
|
+ <div
|
|
|
+ ref="chatMainAreaRef"
|
|
|
+ class="chat-main-area"
|
|
|
+ :class="{ 'is-ai-writing-resizing': aiWritingSidebarResizing }"
|
|
|
+ >
|
|
|
<!-- 右侧AI问答区域 -->
|
|
|
<div class="main-chat" :class="{ 'sidebar-open': webSearchSidebarVisible }">
|
|
|
<!-- 聊天头部 -->
|
|
|
@@ -301,18 +305,24 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- AI写作:状态文字 + 文件卡片 -->
|
|
|
- <div v-if="message.isAIWriting" class="ai-writing-block">
|
|
|
+ <!-- AI写作/安全培训:状态文字 + 文件卡片 -->
|
|
|
+ <div v-if="message.isAIWriting || message.isSafetyTrainingDocument" class="ai-writing-block">
|
|
|
<div class="ai-writing-status-text">
|
|
|
{{ message.aiWritingStatusText || 'AI智能助手正在为您输出...' }}
|
|
|
</div>
|
|
|
- <div class="ai-writing-file-card" @click="openAIWritingSidebar(message)">
|
|
|
- <div class="file-card-icon">
|
|
|
- <span class="word-icon">W</span>
|
|
|
+ <div class="ai-writing-file-card" @click="handleGeneratedDocumentCardClick(message)">
|
|
|
+ <div class="file-card-icon" :class="{ 'safety-file-card-icon': message.isSafetyTrainingDocument }">
|
|
|
+ <img
|
|
|
+ v-if="message.isSafetyTrainingDocument"
|
|
|
+ :src="safetyTrainingCardIcon"
|
|
|
+ alt="安全培训"
|
|
|
+ class="safety-card-icon"
|
|
|
+ >
|
|
|
+ <span v-else class="word-icon">W</span>
|
|
|
</div>
|
|
|
<div class="file-card-info">
|
|
|
- <div class="file-card-title">{{ message.aiWritingTitle || currentQuestion || 'AI写作文档' }}</div>
|
|
|
- <div class="file-card-time">创建于 {{ formatTime(message.timestamp) }}</div>
|
|
|
+ <div class="file-card-title">{{ getGeneratedDocumentTitle(message) }}</div>
|
|
|
+ <div class="file-card-time">{{ getGeneratedDocumentCardTime(message) }}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -584,10 +594,42 @@
|
|
|
|
|
|
<!-- AI写作侧边栏 -->
|
|
|
<transition name="sidebar-slide">
|
|
|
- <div v-if="aiWritingSidebarVisible" class="ai-writing-sidebar">
|
|
|
+ <div
|
|
|
+ v-if="aiWritingSidebarVisible"
|
|
|
+ class="ai-writing-sidebar"
|
|
|
+ :class="{ 'is-resizing': aiWritingSidebarResizing }"
|
|
|
+ :style="aiWritingSidebarStyle"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="ai-writing-sidebar-resizer"
|
|
|
+ role="separator"
|
|
|
+ aria-orientation="vertical"
|
|
|
+ :aria-valuenow="aiWritingSidebarWidth"
|
|
|
+ :aria-valuemin="AI_WRITING_SIDEBAR_SIZE.min"
|
|
|
+ :aria-valuemax="aiWritingSidebarMaxWidth"
|
|
|
+ tabindex="0"
|
|
|
+ title="Resize"
|
|
|
+ @pointerdown.prevent="startAIWritingSidebarResize"
|
|
|
+ @keydown="handleAIWritingSidebarResizeKeydown"
|
|
|
+ ></div>
|
|
|
<div class="sidebar-header">
|
|
|
<h3 class="sidebar-title">{{ aiWritingSidebarTitle }}</h3>
|
|
|
<div class="sidebar-header-actions">
|
|
|
+ <button
|
|
|
+ v-if="!aiWritingIsGenerating"
|
|
|
+ class="sidebar-save-btn"
|
|
|
+ @click="saveAIWritingSidebarDocument"
|
|
|
+ >
|
|
|
+ 保存
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ v-if="!aiWritingIsGenerating"
|
|
|
+ class="sidebar-download-btn"
|
|
|
+ @click="downloadAIWritingSidebarDocument"
|
|
|
+ title="下载Word"
|
|
|
+ >
|
|
|
+ 下载
|
|
|
+ </button>
|
|
|
<button class="sidebar-close-btn" @click="closeAIWritingSidebar">
|
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
|
<path d="M12 4L4 12M4 4L12 12" stroke="#909399" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
|
@@ -595,17 +637,23 @@
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="sidebar-toolbar" v-if="!aiWritingIsGenerating">
|
|
|
- <span class="toolbar-label">正文</span>
|
|
|
- <span class="toolbar-font-size">15px</span>
|
|
|
- <div class="toolbar-divider"></div>
|
|
|
- <button class="toolbar-btn"><b>B</b></button>
|
|
|
- <button class="toolbar-btn"><s>S</s></button>
|
|
|
- <button class="toolbar-btn"><u>U</u></button>
|
|
|
- <button class="toolbar-btn"><i>I</i></button>
|
|
|
- </div>
|
|
|
<div class="sidebar-content">
|
|
|
- <div class="sidebar-doc-content" v-text="aiWritingSidebarContent"></div>
|
|
|
+ <div v-if="!aiWritingIsGenerating" class="ai-writing-rich-editor-container">
|
|
|
+ <Toolbar
|
|
|
+ class="ai-writing-rich-toolbar"
|
|
|
+ :editor="aiWritingEditorRef"
|
|
|
+ :defaultConfig="aiWritingToolbarConfig"
|
|
|
+ :mode="aiWritingEditorMode"
|
|
|
+ />
|
|
|
+ <Editor
|
|
|
+ class="ai-writing-rich-editor"
|
|
|
+ v-model="aiWritingEditorContent"
|
|
|
+ :defaultConfig="aiWritingEditorConfig"
|
|
|
+ :mode="aiWritingEditorMode"
|
|
|
+ @onCreated="handleAIWritingEditorCreated"
|
|
|
+ @onChange="handleAIWritingEditorChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
<div v-if="aiWritingIsGenerating" class="sidebar-generating-hint">
|
|
|
<span class="generating-text-hint">AI智能助手正在输出</span>
|
|
|
<span class="generating-dots">
|
|
|
@@ -670,6 +718,8 @@
|
|
|
<script setup>
|
|
|
import { ref, nextTick, reactive, triggerRef, markRaw, onMounted, onBeforeUnmount, computed, watch, onActivated } from 'vue'
|
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
|
+import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
|
|
+import '@wangeditor/editor/dist/css/style.css'
|
|
|
import Sidebar from '@/components/Sidebar.vue'
|
|
|
import ExamWorkshop from '@/views/ExamWorkshop.vue'
|
|
|
import * as mammoth from 'mammoth'
|
|
|
@@ -690,6 +740,17 @@ import {
|
|
|
shouldClearSummaryForOnlineAnswer,
|
|
|
splitHtmlIntoTypewriterChunks
|
|
|
} from '@/utils/chatHistoryPersistence.js'
|
|
|
+import {
|
|
|
+ buildDocumentGenerationRequestMessage,
|
|
|
+ buildDocumentGenerationUserMessage,
|
|
|
+ shouldAttachDocumentToRequest
|
|
|
+} from '@/utils/aiWritingRequest.js'
|
|
|
+import { prepareAIWritingEditorHtml } from '@/utils/aiWritingContent.js'
|
|
|
+import { getGeneratedDocumentCardTime } from '@/utils/generatedDocumentCard.js'
|
|
|
+import {
|
|
|
+ AI_WRITING_SIDEBAR_SIZE,
|
|
|
+ calculateResizableSidebarWidth
|
|
|
+} from '@/utils/resizableSidebar.js'
|
|
|
import { getToken } from '@/utils/auth.js'
|
|
|
import { renderMarkdown } from '@/utils/markdown'
|
|
|
import 'katex/dist/katex.min.css'
|
|
|
@@ -737,6 +798,7 @@ import voiceInputIcon from '@/assets/Chat/18.png'
|
|
|
import networkSearchIconOn from '@/assets/Chat/24.png'
|
|
|
import networkSearchIconOff from '@/assets/Chat/25.png'
|
|
|
import wordDocIcon from '@/assets/Chat/26.png'
|
|
|
+import safetyTrainingCardIcon from '@/assets/Chat/14.png'
|
|
|
import { Link } from '@element-plus/icons-vue'
|
|
|
|
|
|
import { apis } from '@/request/apis.js'
|
|
|
@@ -1012,25 +1074,299 @@ const webSearchSidebarVisible = ref(false) // 网络搜索侧边栏显示状态
|
|
|
const aiWritingSidebarVisible = ref(false)
|
|
|
const aiWritingSidebarTitle = ref('')
|
|
|
const aiWritingSidebarContent = ref('')
|
|
|
+const aiWritingEditorContent = ref('')
|
|
|
+const aiWritingEditorRef = ref(null)
|
|
|
+const aiWritingActiveMessage = ref(null)
|
|
|
+const aiWritingEditorMode = 'default'
|
|
|
const aiWritingIsGenerating = ref(false)
|
|
|
const aiWritingFullContent = ref('') // 保存完整内容,用于点击文件卡片时重新打开
|
|
|
|
|
|
-const normalizeAiWritingText = (content) => {
|
|
|
- if (!content) return ''
|
|
|
- return String(content).replace(/\r\n/g, '\n')
|
|
|
+const chatMainAreaRef = ref(null)
|
|
|
+const aiWritingSidebarWidth = ref(AI_WRITING_SIDEBAR_SIZE.default)
|
|
|
+const aiWritingSidebarResizing = ref(false)
|
|
|
+let aiWritingSidebarResizeFrame = null
|
|
|
+
|
|
|
+const aiWritingToolbarConfig = {
|
|
|
+ excludeKeys: [
|
|
|
+ 'group-video',
|
|
|
+ 'group-more-style',
|
|
|
+ 'fullScreen',
|
|
|
+ 'emotion',
|
|
|
+ 'insertLink',
|
|
|
+ 'insertImage',
|
|
|
+ 'uploadImage',
|
|
|
+ 'insertTable',
|
|
|
+ 'codeBlock',
|
|
|
+ 'divider'
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+const aiWritingEditorConfig = {
|
|
|
+ placeholder: '请输入内容...',
|
|
|
+ readOnly: false,
|
|
|
+ autoFocus: false,
|
|
|
+ scroll: true,
|
|
|
+ hoverbarKeys: {
|
|
|
+ text: { menuKeys: [] },
|
|
|
+ link: { menuKeys: [] },
|
|
|
+ image: { menuKeys: [] },
|
|
|
+ table: { menuKeys: [] },
|
|
|
+ video: { menuKeys: [] }
|
|
|
+ },
|
|
|
+ MENU_CONF: {
|
|
|
+ color: {
|
|
|
+ colors: ['#000000', '#333333', '#666666', '#999999', '#cccccc', '#ffffff', '#ff0000', '#00ff00', '#0000ff']
|
|
|
+ },
|
|
|
+ fontFamily: {
|
|
|
+ fontFamilyList: ['黑体', '楷体', '仿宋', '微软雅黑', 'Arial', 'Tahoma', 'Verdana']
|
|
|
+ },
|
|
|
+ fontSize: {
|
|
|
+ fontSizeList: ['12px', '13px', '14px', '15px', '16px', '19px', '22px', '24px', '32px', '48px']
|
|
|
+ },
|
|
|
+ uploadImage: {
|
|
|
+ server: '',
|
|
|
+ allowedFileTypes: [],
|
|
|
+ maxFileSize: 0,
|
|
|
+ maxNumberOfFiles: 0,
|
|
|
+ customInsert: () => {},
|
|
|
+ customBrowseAndUpload: () => {},
|
|
|
+ customUpload: () => {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const getAIWritingSidebarResizeRect = () => {
|
|
|
+ return chatMainAreaRef.value?.getBoundingClientRect?.() || {
|
|
|
+ right: window.innerWidth,
|
|
|
+ width: window.innerWidth
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const getAIWritingSidebarMaxWidth = () => {
|
|
|
+ const rect = getAIWritingSidebarResizeRect()
|
|
|
+ return Math.max(
|
|
|
+ AI_WRITING_SIDEBAR_SIZE.min,
|
|
|
+ Math.min(AI_WRITING_SIDEBAR_SIZE.max, rect.width - AI_WRITING_SIDEBAR_SIZE.minMain)
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const clampAIWritingSidebarWidth = (width) => {
|
|
|
+ const rect = getAIWritingSidebarResizeRect()
|
|
|
+ return calculateResizableSidebarWidth({
|
|
|
+ pointerX: rect.right - width,
|
|
|
+ containerRight: rect.right,
|
|
|
+ containerWidth: rect.width,
|
|
|
+ minWidth: AI_WRITING_SIDEBAR_SIZE.min,
|
|
|
+ maxWidth: AI_WRITING_SIDEBAR_SIZE.max,
|
|
|
+ minMainWidth: AI_WRITING_SIDEBAR_SIZE.minMain
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const aiWritingSidebarMaxWidth = computed(() => getAIWritingSidebarMaxWidth())
|
|
|
+
|
|
|
+const aiWritingSidebarStyle = computed(() => ({
|
|
|
+ '--ai-writing-sidebar-width': `${aiWritingSidebarWidth.value}px`,
|
|
|
+ '--ai-writing-sidebar-min-width': `${AI_WRITING_SIDEBAR_SIZE.min}px`,
|
|
|
+ '--ai-writing-sidebar-max-width': `${AI_WRITING_SIDEBAR_SIZE.max}px`
|
|
|
+}))
|
|
|
+
|
|
|
+const applyAIWritingSidebarPointerWidth = (pointerX) => {
|
|
|
+ const rect = getAIWritingSidebarResizeRect()
|
|
|
+ aiWritingSidebarWidth.value = calculateResizableSidebarWidth({
|
|
|
+ pointerX,
|
|
|
+ containerRight: rect.right,
|
|
|
+ containerWidth: rect.width,
|
|
|
+ minWidth: AI_WRITING_SIDEBAR_SIZE.min,
|
|
|
+ maxWidth: AI_WRITING_SIDEBAR_SIZE.max,
|
|
|
+ minMainWidth: AI_WRITING_SIDEBAR_SIZE.minMain
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const stopAIWritingSidebarResize = () => {
|
|
|
+ aiWritingSidebarResizing.value = false
|
|
|
+ if (aiWritingSidebarResizeFrame) {
|
|
|
+ cancelAnimationFrame(aiWritingSidebarResizeFrame)
|
|
|
+ aiWritingSidebarResizeFrame = null
|
|
|
+ }
|
|
|
+ window.removeEventListener('pointermove', handleAIWritingSidebarPointerMove)
|
|
|
+ window.removeEventListener('pointerup', stopAIWritingSidebarResize)
|
|
|
+ window.removeEventListener('pointercancel', stopAIWritingSidebarResize)
|
|
|
+ document.body.style.cursor = ''
|
|
|
+ document.body.style.userSelect = ''
|
|
|
+}
|
|
|
+
|
|
|
+const handleAIWritingSidebarPointerMove = (event) => {
|
|
|
+ if (!aiWritingSidebarResizing.value) return
|
|
|
+ const pointerX = event.clientX
|
|
|
+ if (aiWritingSidebarResizeFrame) {
|
|
|
+ cancelAnimationFrame(aiWritingSidebarResizeFrame)
|
|
|
+ }
|
|
|
+ aiWritingSidebarResizeFrame = requestAnimationFrame(() => {
|
|
|
+ applyAIWritingSidebarPointerWidth(pointerX)
|
|
|
+ aiWritingSidebarResizeFrame = null
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const startAIWritingSidebarResize = (event) => {
|
|
|
+ if (window.innerWidth <= 1200) return
|
|
|
+ aiWritingSidebarResizing.value = true
|
|
|
+ document.body.style.cursor = 'col-resize'
|
|
|
+ document.body.style.userSelect = 'none'
|
|
|
+ applyAIWritingSidebarPointerWidth(event.clientX)
|
|
|
+ window.addEventListener('pointermove', handleAIWritingSidebarPointerMove)
|
|
|
+ window.addEventListener('pointerup', stopAIWritingSidebarResize)
|
|
|
+ window.addEventListener('pointercancel', stopAIWritingSidebarResize)
|
|
|
+}
|
|
|
+
|
|
|
+const handleAIWritingSidebarResizeKeydown = (event) => {
|
|
|
+ if (window.innerWidth <= 1200) return
|
|
|
+
|
|
|
+ if (event.key === 'ArrowLeft') {
|
|
|
+ event.preventDefault()
|
|
|
+ aiWritingSidebarWidth.value = clampAIWritingSidebarWidth(
|
|
|
+ aiWritingSidebarWidth.value + AI_WRITING_SIDEBAR_SIZE.keyboardStep
|
|
|
+ )
|
|
|
+ } else if (event.key === 'ArrowRight') {
|
|
|
+ event.preventDefault()
|
|
|
+ aiWritingSidebarWidth.value = clampAIWritingSidebarWidth(
|
|
|
+ aiWritingSidebarWidth.value - AI_WRITING_SIDEBAR_SIZE.keyboardStep
|
|
|
+ )
|
|
|
+ } else if (event.key === 'Home') {
|
|
|
+ event.preventDefault()
|
|
|
+ aiWritingSidebarWidth.value = AI_WRITING_SIDEBAR_SIZE.min
|
|
|
+ } else if (event.key === 'End') {
|
|
|
+ event.preventDefault()
|
|
|
+ aiWritingSidebarWidth.value = getAIWritingSidebarMaxWidth()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const syncAIWritingEditorContent = (content) => {
|
|
|
+ const html = prepareAIWritingEditorHtml(content)
|
|
|
+ aiWritingSidebarContent.value = html
|
|
|
+ aiWritingEditorContent.value = html
|
|
|
+
|
|
|
+ nextTick(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (!aiWritingEditorRef.value) return
|
|
|
+ try {
|
|
|
+ aiWritingEditorRef.value.setHtml(html)
|
|
|
+ } catch (error) {
|
|
|
+ console.error('设置AI写作富文本编辑器内容失败:', error)
|
|
|
+ }
|
|
|
+ }, 0)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const getAIWritingEditorHtml = () => {
|
|
|
+ if (aiWritingEditorRef.value?.getHtml) {
|
|
|
+ try {
|
|
|
+ return aiWritingEditorRef.value.getHtml()
|
|
|
+ } catch (error) {
|
|
|
+ console.error('读取AI写作富文本编辑器内容失败:', error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return aiWritingEditorContent.value || aiWritingSidebarContent.value || ''
|
|
|
+}
|
|
|
+
|
|
|
+const handleAIWritingEditorCreated = (editor) => {
|
|
|
+ aiWritingEditorRef.value = editor
|
|
|
+ if (aiWritingSidebarContent.value) {
|
|
|
+ syncAIWritingEditorContent(aiWritingSidebarContent.value)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleAIWritingEditorChange = (editor) => {
|
|
|
+ const html = editor?.getHtml ? editor.getHtml() : aiWritingEditorContent.value
|
|
|
+ aiWritingEditorContent.value = html
|
|
|
+ aiWritingSidebarContent.value = html
|
|
|
+ if (aiWritingActiveMessage.value) {
|
|
|
+ aiWritingActiveMessage.value.fullContent = html
|
|
|
+ aiWritingActiveMessage.value.content = html
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const isSafetyTrainingBusinessType = (businessType) => Number(businessType) === 1
|
|
|
+const isAIWritingBusinessType = (businessType) => Number(businessType) === 2
|
|
|
+
|
|
|
+const getGeneratedDocumentTitle = (message) => {
|
|
|
+ if (message?.aiWritingTitle) return message.aiWritingTitle
|
|
|
+ if (message?.userQuestion) return message.userQuestion
|
|
|
+ if (currentQuestion.value) return currentQuestion.value
|
|
|
+ return message?.isSafetyTrainingDocument ? '安全培训大纲' : 'AI写作文档'
|
|
|
}
|
|
|
|
|
|
// 关闭AI写作侧边栏
|
|
|
const closeAIWritingSidebar = () => {
|
|
|
+ aiWritingActiveMessage.value = null
|
|
|
aiWritingSidebarVisible.value = false
|
|
|
}
|
|
|
|
|
|
// 打开AI写作侧边栏(点击文件卡片时)
|
|
|
const openAIWritingSidebar = (message) => {
|
|
|
+ aiWritingActiveMessage.value = message
|
|
|
aiWritingSidebarTitle.value = message.aiWritingTitle || currentQuestion.value || 'AI写作文档'
|
|
|
- aiWritingSidebarContent.value = normalizeAiWritingText(message.fullContent || message.content || '')
|
|
|
aiWritingIsGenerating.value = message.aiWritingStatus === 'generating' || message.isTyping
|
|
|
aiWritingSidebarVisible.value = true
|
|
|
+ if (window.innerWidth > 1200) {
|
|
|
+ aiWritingSidebarWidth.value = clampAIWritingSidebarWidth(aiWritingSidebarWidth.value)
|
|
|
+ }
|
|
|
+ syncAIWritingEditorContent(message.fullContent || message.content || '')
|
|
|
+}
|
|
|
+
|
|
|
+const saveAIWritingSidebarDocument = async () => {
|
|
|
+ const html = getAIWritingEditorHtml()
|
|
|
+ const message = aiWritingActiveMessage.value
|
|
|
+ const aiMessageId = message?.ai_message_id || message?.rawData?.id
|
|
|
+
|
|
|
+ if (!aiMessageId) {
|
|
|
+ ElMessage.warning('暂无可保存的AI消息ID')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await apis.saveEditDocument({
|
|
|
+ ai_message_id: aiMessageId,
|
|
|
+ content: html
|
|
|
+ })
|
|
|
+ if (response.statusCode === 200) {
|
|
|
+ message.fullContent = html
|
|
|
+ message.content = html
|
|
|
+ ElMessage.success('保存成功')
|
|
|
+ } else {
|
|
|
+ throw new Error(response.msg || '保存失败')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error(`保存失败: ${error.message}`)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const downloadAIWritingSidebarDocument = () => {
|
|
|
+ const html = getAIWritingEditorHtml()
|
|
|
+ if (!html.trim()) {
|
|
|
+ ElMessage.warning('暂无可下载的内容')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const title = (aiWritingSidebarTitle.value || 'AI写作文档').replace(/[<>:"/\\|?*]/g, '').trim() || 'AI写作文档'
|
|
|
+ const documentHtml = `<!DOCTYPE html><html><head><meta charset="UTF-8"><title>${title}</title></head><body>${html}</body></html>`
|
|
|
+ const blob = new Blob([documentHtml], { type: 'application/msword;charset=utf-8' })
|
|
|
+ const url = URL.createObjectURL(blob)
|
|
|
+ const link = document.createElement('a')
|
|
|
+ link.href = url
|
|
|
+ link.download = `${title}.doc`
|
|
|
+ document.body.appendChild(link)
|
|
|
+ link.click()
|
|
|
+ document.body.removeChild(link)
|
|
|
+ URL.revokeObjectURL(url)
|
|
|
+}
|
|
|
+
|
|
|
+const handleGeneratedDocumentCardClick = (message) => {
|
|
|
+ if (message?.isSafetyTrainingDocument) {
|
|
|
+ handleSafetyDocClick(message)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ openAIWritingSidebar(message)
|
|
|
}
|
|
|
|
|
|
const currentWebSearchData = ref({
|
|
|
@@ -1614,6 +1950,14 @@ const getConversationMessages = async (conversationId) => {
|
|
|
completedCount = actualReports.filter(r => r.status === 'completed').length
|
|
|
progress = totalFiles > 0 ? Math.round((completedCount / totalFiles) * 100) : 100
|
|
|
}
|
|
|
+
|
|
|
+ const isGeneratedDocumentHistory =
|
|
|
+ message.type === 'ai' &&
|
|
|
+ (currentMode.value === 'ai-writing' || currentMode.value === 'safety-training')
|
|
|
+
|
|
|
+ if (isGeneratedDocumentHistory) {
|
|
|
+ displayContent = ''
|
|
|
+ }
|
|
|
|
|
|
return {
|
|
|
type: message.type, // 'user' 或 'ai'
|
|
|
@@ -1646,7 +1990,16 @@ const getConversationMessages = async (conversationId) => {
|
|
|
? (message.webSearchRaw?.total > 0
|
|
|
? ` <span class="ai-name">蜀道安全管理AI智能助手</span>正在为您分析 <span class="file-count">${totalFiles}</span> 个知识库文件,以及 <span class="file-count">${message.webSearchRaw.total}</span> 个相关网络资源`
|
|
|
: ` <span class="ai-name">蜀道安全管理AI智能助手</span>正在为您分析 <span class="file-count">${totalFiles}</span> 个知识库文件`)
|
|
|
- : ''
|
|
|
+ : '',
|
|
|
+ isAIWriting: isGeneratedDocumentHistory && currentMode.value === 'ai-writing',
|
|
|
+ isSafetyTrainingDocument: isGeneratedDocumentHistory && currentMode.value === 'safety-training',
|
|
|
+ aiWritingTitle: userQuestion || currentQuestion.value || (currentMode.value === 'safety-training' ? '安全培训大纲' : 'AI写作文档'),
|
|
|
+ aiWritingStatus: isGeneratedDocumentHistory ? 'completed' : undefined,
|
|
|
+ aiWritingStatusText: currentMode.value === 'safety-training'
|
|
|
+ ? '已按要求输出大纲,你可以基于当前结果进一步编辑调整~'
|
|
|
+ : '已按照要求输出文章,你可以基于当前结果进一步编辑整理~',
|
|
|
+ fullContent: message.type === 'ai' ? message.content : '',
|
|
|
+ ai_conversation_id: conversationId
|
|
|
}
|
|
|
}))
|
|
|
|
|
|
@@ -1927,11 +2280,20 @@ const handleAIWritingStream = async (data) => {
|
|
|
}
|
|
|
|
|
|
currentQuestion.value = data.question
|
|
|
-
|
|
|
+ const attachedFile = shouldAttachDocumentToRequest(data.businessType) ? selectedFile.value : null
|
|
|
+ const userMessagePayload = shouldAttachDocumentToRequest(data.businessType)
|
|
|
+ ? buildDocumentGenerationUserMessage(data.question, attachedFile)
|
|
|
+ : { content: data.question, file: null }
|
|
|
+ const requestMessage = shouldAttachDocumentToRequest(data.businessType)
|
|
|
+ ? buildDocumentGenerationRequestMessage(data.question, attachedFile)
|
|
|
+ : data.question
|
|
|
+ const isAIWritingMode = isAIWritingBusinessType(data.businessType)
|
|
|
+ const isSafetyTrainingMode = isSafetyTrainingBusinessType(data.businessType)
|
|
|
chatMessages.value.push({
|
|
|
id: Date.now(),
|
|
|
type: 'user',
|
|
|
- content: data.question,
|
|
|
+ content: userMessagePayload.content,
|
|
|
+ file: userMessagePayload.file,
|
|
|
timestamp: new Date().toISOString()
|
|
|
})
|
|
|
|
|
|
@@ -1946,17 +2308,20 @@ const handleAIWritingStream = async (data) => {
|
|
|
displayContent: '',
|
|
|
timestamp: aiMsgTimestamp,
|
|
|
reports: [],
|
|
|
- isAIWriting: true,
|
|
|
+ isAIWriting: isAIWritingMode,
|
|
|
+ isSafetyTrainingDocument: isSafetyTrainingMode,
|
|
|
aiWritingTitle: data.question,
|
|
|
aiWritingStatusText: 'AI智能助手正在为您输出...',
|
|
|
aiWritingStatus: 'generating',
|
|
|
ai_message_id: null
|
|
|
})
|
|
|
|
|
|
- aiWritingSidebarTitle.value = data.question
|
|
|
- aiWritingSidebarContent.value = ''
|
|
|
- aiWritingIsGenerating.value = true
|
|
|
- aiWritingSidebarVisible.value = true
|
|
|
+ if (isAIWritingMode) {
|
|
|
+ aiWritingSidebarTitle.value = data.question
|
|
|
+ aiWritingSidebarContent.value = ''
|
|
|
+ aiWritingIsGenerating.value = true
|
|
|
+ aiWritingSidebarVisible.value = true
|
|
|
+ }
|
|
|
|
|
|
const aiMessage = chatMessages.value[aiMessageIndex]
|
|
|
let fullContent = ''
|
|
|
@@ -1976,7 +2341,7 @@ const handleAIWritingStream = async (data) => {
|
|
|
method: 'POST',
|
|
|
headers,
|
|
|
body: JSON.stringify({
|
|
|
- message: data.question,
|
|
|
+ message: requestMessage,
|
|
|
ai_conversation_id: ai_conversation_id.value,
|
|
|
business_type: data.businessType
|
|
|
})
|
|
|
@@ -2028,6 +2393,7 @@ const handleAIWritingStream = async (data) => {
|
|
|
if (parsed.type === 'initial') {
|
|
|
if (parsed.ai_conversation_id) {
|
|
|
ai_conversation_id.value = parsed.ai_conversation_id
|
|
|
+ aiMessage.ai_conversation_id = parsed.ai_conversation_id
|
|
|
}
|
|
|
if (parsed.ai_message_id) {
|
|
|
aiMessage.ai_message_id = parsed.ai_message_id
|
|
|
@@ -2046,14 +2412,16 @@ const handleAIWritingStream = async (data) => {
|
|
|
fullContent += normalizedChunk
|
|
|
aiMessage.fullContent = fullContent
|
|
|
aiMessage.content = fullContent
|
|
|
- aiWritingSidebarContent.value = normalizeAiWritingText(fullContent)
|
|
|
+ aiWritingSidebarContent.value = fullContent
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
aiMessage.isTyping = false
|
|
|
aiMessage.aiWritingStatus = 'completed'
|
|
|
- aiMessage.aiWritingStatusText = '已按照要求输出文章,你可以基于当前结果进一步编辑整理~'
|
|
|
+ aiMessage.aiWritingStatusText = isSafetyTrainingMode
|
|
|
+ ? '已按要求输出大纲,你可以基于当前结果进一步编辑调整~'
|
|
|
+ : '已按照要求输出文章,你可以基于当前结果进一步编辑整理~'
|
|
|
aiWritingIsGenerating.value = false
|
|
|
aiWritingFullContent.value = fullContent
|
|
|
aiWritingSidebarVisible.value = false
|
|
|
@@ -2065,7 +2433,7 @@ const handleAIWritingStream = async (data) => {
|
|
|
aiMessage.aiWritingStatus = 'error'
|
|
|
aiMessage.aiWritingStatusText = '生成失败,请重试'
|
|
|
aiWritingIsGenerating.value = false
|
|
|
- aiWritingSidebarContent.value = normalizeAiWritingText(fullContent || '生成失败,请重试。')
|
|
|
+ aiWritingSidebarContent.value = fullContent || '生成失败,请重试。'
|
|
|
ElMessage.error(`请求失败: ${error.message}`)
|
|
|
} finally {
|
|
|
isSending.value = false
|
|
|
@@ -2073,23 +2441,27 @@ const handleAIWritingStream = async (data) => {
|
|
|
}
|
|
|
|
|
|
const handleNonStreamingSubmit = async (data) => {
|
|
|
- if (data.businessType === 2) {
|
|
|
- await handleAIWritingStream(data)
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
if (!isSending.value) {
|
|
|
isSending.value = true
|
|
|
}
|
|
|
|
|
|
currentQuestion.value = data.question
|
|
|
+ const attachedFile = shouldAttachDocumentToRequest(data.businessType) ? selectedFile.value : null
|
|
|
+ const userMessagePayload = shouldAttachDocumentToRequest(data.businessType)
|
|
|
+ ? buildDocumentGenerationUserMessage(data.question, attachedFile)
|
|
|
+ : { content: data.question, file: null }
|
|
|
+ const requestMessage = shouldAttachDocumentToRequest(data.businessType)
|
|
|
+ ? buildDocumentGenerationRequestMessage(data.question, attachedFile)
|
|
|
+ : data.question
|
|
|
+ const isAIWritingMode = isAIWritingBusinessType(data.businessType)
|
|
|
+ const isSafetyTrainingMode = isSafetyTrainingBusinessType(data.businessType)
|
|
|
|
|
|
// 添加用户消息
|
|
|
chatMessages.value.push({
|
|
|
id: Date.now(),
|
|
|
type: 'user',
|
|
|
- content: data.question,
|
|
|
+ content: userMessagePayload.content,
|
|
|
+ file: userMessagePayload.file,
|
|
|
timestamp: new Date().toISOString()
|
|
|
})
|
|
|
|
|
|
@@ -2106,8 +2478,9 @@ const handleNonStreamingSubmit = async (data) => {
|
|
|
timestamp: aiMsgTimestamp,
|
|
|
reports: [],
|
|
|
// AI写作模式下,立即显示文件卡片和状态文字
|
|
|
- ...(data.businessType === 2 ? {
|
|
|
- isAIWriting: true,
|
|
|
+ ...(isAIWritingMode || isSafetyTrainingMode ? {
|
|
|
+ isAIWriting: isAIWritingMode,
|
|
|
+ isSafetyTrainingDocument: isSafetyTrainingMode,
|
|
|
aiWritingTitle: data.question,
|
|
|
aiWritingStatusText: 'AI智能助手正在为您输出...',
|
|
|
aiWritingStatus: 'generating'
|
|
|
@@ -2115,16 +2488,19 @@ const handleNonStreamingSubmit = async (data) => {
|
|
|
})
|
|
|
|
|
|
// AI写作模式:立即打开侧边栏,显示生成中状态
|
|
|
- if (data.businessType === 2) {
|
|
|
+ if (isAIWritingMode) {
|
|
|
aiWritingSidebarTitle.value = data.question
|
|
|
aiWritingSidebarContent.value = ''
|
|
|
aiWritingIsGenerating.value = true
|
|
|
aiWritingSidebarVisible.value = true
|
|
|
+ } else if (isSafetyTrainingMode) {
|
|
|
+ aiWritingSidebarVisible.value = false
|
|
|
+ aiWritingIsGenerating.value = false
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const response = await apis.sendDeepseekMessage({
|
|
|
- message: data.question,
|
|
|
+ message: requestMessage,
|
|
|
business_type: data.businessType,
|
|
|
enable_online_model: isOnlineModel.value,
|
|
|
conversation_id: ai_conversation_id.value
|
|
|
@@ -2145,6 +2521,11 @@ const handleNonStreamingSubmit = async (data) => {
|
|
|
responseData.conversation_id ||
|
|
|
response.ai_conversation_id ||
|
|
|
response.conversation_id
|
|
|
+ const aiMessageId =
|
|
|
+ responseData.ai_message_id ||
|
|
|
+ responseData.message_id ||
|
|
|
+ response.ai_message_id ||
|
|
|
+ response.message_id
|
|
|
|
|
|
// 如果用户已经点击了停止,则不再继续输出
|
|
|
if (aiMessage._stopped) {
|
|
|
@@ -2161,24 +2542,24 @@ const handleNonStreamingSubmit = async (data) => {
|
|
|
// 更新 conversation ID
|
|
|
if (conversationId) {
|
|
|
ai_conversation_id.value = conversationId
|
|
|
+ aiMessage.ai_conversation_id = conversationId
|
|
|
+ }
|
|
|
+ if (aiMessageId) {
|
|
|
+ aiMessage.ai_message_id = aiMessageId
|
|
|
}
|
|
|
|
|
|
// 添加打字机效果显示
|
|
|
- if (data.businessType === 1) {
|
|
|
- // 安全培训: 只展示一个输出文档
|
|
|
- aiMessage.isDocument = true
|
|
|
- aiMessage.displayContent = `<div class="safety-training-doc-card">
|
|
|
- <div class="doc-header">
|
|
|
- <span class="doc-icon">📄</span>
|
|
|
- <span class="doc-title">安全培训生成文档</span>
|
|
|
- </div>
|
|
|
- <div class="doc-actions">
|
|
|
- <button class="view-doc-btn">查看详情</button>
|
|
|
- </div>
|
|
|
- </div>`
|
|
|
- // 实际内容保存起来,点击查看详情时可以使用
|
|
|
+ if (isSafetyTrainingMode) {
|
|
|
+ // 安全培训: 复用AI写作卡片样式,但不打开侧边栏
|
|
|
+ aiMessage.isSafetyTrainingDocument = true
|
|
|
+ aiMessage.isAIWriting = false
|
|
|
+ aiMessage.aiWritingTitle = data.question
|
|
|
aiMessage.fullContent = aiReply
|
|
|
- } else if (data.businessType === 2) {
|
|
|
+ aiMessage.displayContent = ''
|
|
|
+ aiMessage.aiWritingStatus = 'completed'
|
|
|
+ aiMessage.aiWritingStatusText = '已按要求输出大纲,你可以基于当前结果进一步编辑调整~'
|
|
|
+ aiMessage.ai_conversation_id = conversationId || ai_conversation_id.value
|
|
|
+ } else if (isAIWritingMode) {
|
|
|
// AI写作: 显示文件卡片 + 打开侧边栏输出
|
|
|
aiMessage.isAIWriting = true
|
|
|
aiMessage.aiWritingTitle = data.question
|
|
|
@@ -2311,10 +2692,25 @@ const isCategoryExpanded = (messageIndex, category) => {
|
|
|
|
|
|
// 处理安全培训文档点击
|
|
|
const handleSafetyDocClick = (message) => {
|
|
|
- if (message.rawData && message.rawData.ai_conversation_id) {
|
|
|
- router.push({ path: '/safety-hazard', query: { id: message.rawData.ai_conversation_id } })
|
|
|
- } else if (ai_conversation_id.value) {
|
|
|
- router.push({ path: '/safety-hazard', query: { id: ai_conversation_id.value } })
|
|
|
+ const conversationId =
|
|
|
+ message?.ai_conversation_id ||
|
|
|
+ message?.conversationId ||
|
|
|
+ message?.rawData?.ai_conversation_id ||
|
|
|
+ ai_conversation_id.value
|
|
|
+
|
|
|
+ if (conversationId && (message?.fullContent || message?.content)) {
|
|
|
+ sessionStorage.setItem('safety-training-draft', JSON.stringify({
|
|
|
+ ai_conversation_id: conversationId,
|
|
|
+ ai_message_id: message.ai_message_id || message.rawData?.id || null,
|
|
|
+ title: getGeneratedDocumentTitle(message),
|
|
|
+ content: message.fullContent || message.content || '',
|
|
|
+ userQuestion: message.userQuestion || message.aiWritingTitle || currentQuestion.value || '',
|
|
|
+ timestamp: Date.now()
|
|
|
+ }))
|
|
|
+ }
|
|
|
+
|
|
|
+ if (conversationId) {
|
|
|
+ router.push({ path: '/safety-hazard', query: { id: conversationId } })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -3996,7 +4392,6 @@ const handleFileSelect = async (event) => {
|
|
|
icon: getFileIcon(fileExtension),
|
|
|
content: extractedContent
|
|
|
}
|
|
|
-
|
|
|
ElMessage.success(`文件读取成功,共提取 ${extractedContent.length} 个字符`)
|
|
|
} catch (error) {
|
|
|
console.error('文件读取失败:', error)
|
|
|
@@ -5090,6 +5485,10 @@ const handleBrowserResize = () => {
|
|
|
|
|
|
// 强制浏览器完成layout重排
|
|
|
document.body.offsetHeight
|
|
|
+
|
|
|
+ if (aiWritingSidebarVisible.value && window.innerWidth > 1200) {
|
|
|
+ aiWritingSidebarWidth.value = clampAIWritingSidebarWidth(aiWritingSidebarWidth.value)
|
|
|
+ }
|
|
|
|
|
|
// 临时解除所有吸附状态,以便重新计算正确位置
|
|
|
const stickyStates = {}
|
|
|
@@ -5301,6 +5700,13 @@ onBeforeUnmount(() => {
|
|
|
window.removeEventListener('beforeunload', handlePageUnload)
|
|
|
window.removeEventListener('unload', handlePageUnload)
|
|
|
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
|
|
+
|
|
|
+ stopAIWritingSidebarResize()
|
|
|
+
|
|
|
+ if (aiWritingEditorRef.value?.destroy) {
|
|
|
+ aiWritingEditorRef.value.destroy()
|
|
|
+ aiWritingEditorRef.value = null
|
|
|
+ }
|
|
|
})
|
|
|
|
|
|
// 页面重新激活时,重新渲染所有AI消息的markdown内容
|
|
|
@@ -5359,6 +5765,15 @@ onActivated(async () => {
|
|
|
min-width: 0;
|
|
|
height: 100vh;
|
|
|
overflow: hidden;
|
|
|
+
|
|
|
+ &.is-ai-writing-resizing {
|
|
|
+ cursor: col-resize;
|
|
|
+
|
|
|
+ .main-chat,
|
|
|
+ .ai-writing-sidebar {
|
|
|
+ transition: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* 中间历史记录栏 */
|
|
|
@@ -7613,6 +8028,17 @@ onActivated(async () => {
|
|
|
font-weight: 700;
|
|
|
font-family: 'Segoe UI', sans-serif;
|
|
|
}
|
|
|
+
|
|
|
+ &.safety-file-card-icon {
|
|
|
+ background: #EAF7EF;
|
|
|
+ border: 1px solid #B7E2C3;
|
|
|
+ }
|
|
|
+
|
|
|
+ .safety-card-icon {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ object-fit: contain;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.file-card-info {
|
|
|
@@ -7640,10 +8066,10 @@ onActivated(async () => {
|
|
|
/* AI写作侧边栏样式 */
|
|
|
.ai-writing-sidebar {
|
|
|
position: relative;
|
|
|
- flex: 0 0 40%;
|
|
|
- width: 40%;
|
|
|
- min-width: 360px;
|
|
|
- max-width: 520px;
|
|
|
+ flex: 0 0 var(--ai-writing-sidebar-width);
|
|
|
+ width: var(--ai-writing-sidebar-width);
|
|
|
+ min-width: var(--ai-writing-sidebar-min-width);
|
|
|
+ max-width: var(--ai-writing-sidebar-max-width);
|
|
|
height: 100%;
|
|
|
background: white;
|
|
|
box-shadow: -4px 0 24px rgba(0, 0, 0, 0.1);
|
|
|
@@ -7652,6 +8078,45 @@ onActivated(async () => {
|
|
|
flex-direction: column;
|
|
|
overflow: hidden;
|
|
|
border-left: 1px solid #E4E7ED;
|
|
|
+ transition: flex-basis 0.18s ease, width 0.18s ease;
|
|
|
+
|
|
|
+ &.is-resizing {
|
|
|
+ box-shadow: -8px 0 28px rgba(62, 123, 250, 0.14);
|
|
|
+
|
|
|
+ .ai-writing-sidebar-resizer::after {
|
|
|
+ background: #3E7BFA;
|
|
|
+ box-shadow: 0 0 0 3px rgba(62, 123, 250, 0.12);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .ai-writing-sidebar-resizer {
|
|
|
+ position: absolute;
|
|
|
+ left: -5px;
|
|
|
+ top: 0;
|
|
|
+ bottom: 0;
|
|
|
+ width: 10px;
|
|
|
+ z-index: 3;
|
|
|
+ cursor: col-resize;
|
|
|
+ outline: none;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ left: 4px;
|
|
|
+ top: 16px;
|
|
|
+ bottom: 16px;
|
|
|
+ width: 2px;
|
|
|
+ border-radius: 999px;
|
|
|
+ background: transparent;
|
|
|
+ transition: background 0.18s ease, box-shadow 0.18s ease;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover::after,
|
|
|
+ &:focus-visible::after {
|
|
|
+ background: #3E7BFA;
|
|
|
+ box-shadow: 0 0 0 3px rgba(62, 123, 250, 0.12);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
.sidebar-header {
|
|
|
display: flex;
|
|
|
@@ -7694,6 +8159,36 @@ onActivated(async () => {
|
|
|
background: #E4E7ED;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ .sidebar-save-btn,
|
|
|
+ .sidebar-download-btn {
|
|
|
+ height: 32px;
|
|
|
+ padding: 0 12px;
|
|
|
+ border: 1px solid #D9E2F2;
|
|
|
+ background: #fff;
|
|
|
+ color: #3E7BFA;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #EEF4FF;
|
|
|
+ border-color: #BFD3FF;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .sidebar-save-btn {
|
|
|
+ background: #3E7BFA;
|
|
|
+ border-color: #3E7BFA;
|
|
|
+ color: #fff;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #2F66D8;
|
|
|
+ border-color: #2F66D8;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -7747,38 +8242,54 @@ onActivated(async () => {
|
|
|
.sidebar-content {
|
|
|
flex: 1;
|
|
|
overflow-y: auto;
|
|
|
- padding: 24px;
|
|
|
+ padding: 0;
|
|
|
|
|
|
- .sidebar-doc-content {
|
|
|
- font-size: 15px;
|
|
|
- line-height: 1.8;
|
|
|
- color: #303133;
|
|
|
- white-space: pre-wrap;
|
|
|
- word-break: break-word;
|
|
|
-
|
|
|
- :deep(h1), :deep(h2), :deep(h3) {
|
|
|
- margin: 16px 0 8px 0;
|
|
|
- color: #1F2937;
|
|
|
+ .ai-writing-rich-editor-container {
|
|
|
+ height: 100%;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ background: #fff;
|
|
|
+
|
|
|
+ .ai-writing-rich-toolbar {
|
|
|
+ border-bottom: 1px solid #EEF0F4;
|
|
|
+ padding: 0 12px;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
-
|
|
|
- :deep(p) {
|
|
|
- margin: 8px 0;
|
|
|
+
|
|
|
+ .ai-writing-rich-editor {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
-
|
|
|
- :deep(ul), :deep(ol) {
|
|
|
- padding-left: 24px;
|
|
|
- margin: 8px 0;
|
|
|
+
|
|
|
+ :deep(.w-e-text-container) {
|
|
|
+ height: calc(100vh - 154px) !important;
|
|
|
+ background: #fff;
|
|
|
}
|
|
|
-
|
|
|
- :deep(li) {
|
|
|
- margin: 4px 0;
|
|
|
+
|
|
|
+ :deep(.w-e-scroll) {
|
|
|
+ min-height: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.w-e-text) {
|
|
|
+ padding: 24px 28px 40px 28px;
|
|
|
+ font-size: 15px;
|
|
|
+ line-height: 1.8;
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.w-e-text h1),
|
|
|
+ :deep(.w-e-text h2),
|
|
|
+ :deep(.w-e-text h3) {
|
|
|
+ color: #1F2937;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.sidebar-generating-hint {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- margin-top: 24px;
|
|
|
+ margin: 24px;
|
|
|
color: #3E7BFA;
|
|
|
font-size: 14px;
|
|
|
|
|
|
@@ -7815,6 +8326,10 @@ onActivated(async () => {
|
|
|
height: 45vh;
|
|
|
border-left: none;
|
|
|
border-top: 1px solid #E4E7ED;
|
|
|
+
|
|
|
+ .ai-writing-sidebar-resizer {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|