|
|
@@ -1,100 +1,184 @@
|
|
|
<template>
|
|
|
- <div class="ai-chat-container">
|
|
|
- <!-- 聊天区域 -->
|
|
|
- <div class="chat-section" v-if="messages.length > 0" ref="chatSection">
|
|
|
- <!-- 消息列表 -->
|
|
|
- <div v-for="(message, index) in messages" :key="index" class="chat-message">
|
|
|
- <div class="message-content user-message chat" v-if="message.content">
|
|
|
- <div v-html="message.content"></div>
|
|
|
- <!-- 显示上传的文件 -->
|
|
|
- <div class="message-files" v-if="message.sourceFiles && message.sourceFiles.length > 0">
|
|
|
- <div v-for="(file, index) in message.sourceFiles" :key="index" class="message-file-item">
|
|
|
- <span>{{ file.title }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="message-content ai-message chat" v-if="message.aiContent || message.loading">
|
|
|
- <div v-if="message.aiContent" v-html="message.aiContent"></div>
|
|
|
- <svg v-else xmlns="http://www.w3.org/2000/svg" width="32" height="32"
|
|
|
- viewBox="0 0 24 24"><!-- Icon from SVG Spinners by Utkarsh Verma - https://github.com/n3r4zzurr0/svg-spinners/blob/main/LICENSE -->
|
|
|
- <circle cx="4" cy="12" r="3" fill="currentColor">
|
|
|
- <animate id="svgSpinners3DotsBounce0" attributeName="cy"
|
|
|
- begin="0;svgSpinners3DotsBounce1.end+0.25s" calcMode="spline" dur="0.6s"
|
|
|
- keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12" />
|
|
|
- </circle>
|
|
|
- <circle cx="12" cy="12" r="3" fill="currentColor">
|
|
|
- <animate attributeName="cy" begin="svgSpinners3DotsBounce0.begin+0.1s" calcMode="spline"
|
|
|
- dur="0.6s" keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12" />
|
|
|
- </circle>
|
|
|
- <circle cx="20" cy="12" r="3" fill="currentColor">
|
|
|
- <animate id="svgSpinners3DotsBounce1" attributeName="cy"
|
|
|
- begin="svgSpinners3DotsBounce0.begin+0.2s" calcMode="spline" dur="0.6s"
|
|
|
- keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12" />
|
|
|
- </circle>
|
|
|
+ <div class="ai-chat-container">
|
|
|
+ <div class="message-quick-box">
|
|
|
+ <div class="message-quick-box-item" :class="{ 'active': isQuickActions.includes('quick') }">
|
|
|
+ <button type="button" class="coco-collapse-trigger" @click="toggleQuickActions('quick')">
|
|
|
+ <span class="coco-collapse-icon soft-orange">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"
|
|
|
+ stroke-linecap="round">
|
|
|
+ <path d="M4 7h16"></path>
|
|
|
+ <path d="M4 12h10"></path>
|
|
|
+ <path d="M4 17h7"></path>
|
|
|
+ </svg>
|
|
|
+ </span>
|
|
|
+ <span class="coco-collapse-copy">
|
|
|
+ <span class="coco-collapse-title">{{ lang.ssAiChatQuickTitle }}</span>
|
|
|
+ <span class="coco-collapse-subtitle" id="cocoQuickSectionHint">{{ lang.ssAiChatQuickSubtitle }}</span>
|
|
|
+ </span>
|
|
|
+ <span class="coco-collapse-chevron">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <polyline points="6 9 12 15 18 9"></polyline>
|
|
|
+ </svg>
|
|
|
+ </span>
|
|
|
+ </button>
|
|
|
+ <div class="coco-collapse-body" v-if="isQuickActions.includes('quick')">
|
|
|
+ <!-- <div class="coco-quick-tabs">
|
|
|
+ <button type="button" class="coco-quick-tab" :class="{ 'active': cocoQuickTab === 'page' }"
|
|
|
+ @click="setCocoQuickTab('page')">{{ lang.ssAiChatQuickTabPage }}</button>
|
|
|
+ <button type="button" class="coco-quick-tab" :class="{ 'active': cocoQuickTab === 'course' }"
|
|
|
+ @click="setCocoQuickTab('course')">{{ lang.ssAiChatQuickTabCourse }}</button>
|
|
|
+ </div> -->
|
|
|
+ <div class="coco-quick-list">
|
|
|
+ <button type="button" class="coco-quick-action" v-if="cocoQuickTab === 'page'" @click="sendQuickAction(lang.ssAiChatQuickAction3)">
|
|
|
+ <span class="coco-quick-action-copy">
|
|
|
+ <span class="coco-quick-action-title">{{ lang.ssAiChatQuickGenChoicesTitle }}</span>
|
|
|
+ <span class="coco-quick-action-desc">{{ lang.ssAiChatQuickGenChoicesDesc }}</span>
|
|
|
+ </span>
|
|
|
+ <span class="coco-quick-action-arrow">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
|
+ stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M5 12h14"></path>
|
|
|
+ <path d="M13 5l7 7-7 7"></path>
|
|
|
+ </svg>
|
|
|
+ </span>
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <!-- <button type="button" class="coco-quick-action" v-if="cocoQuickTab === 'page'" @click="sendQuickAction(lang.ssAiChatQuickAction4)">
|
|
|
+ <span class="coco-quick-action-copy">
|
|
|
+ <span class="coco-quick-action-title">{{ lang.ssAiChatQuickGenWebTitle }}</span>
|
|
|
+ <span class="coco-quick-action-desc">{{ lang.ssAiChatQuickGenWebDesc }}</span>
|
|
|
+ </span>
|
|
|
+ <span class="coco-quick-action-arrow">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
|
+ stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M5 12h14"></path>
|
|
|
+ <path d="M13 5l7 7-7 7"></path>
|
|
|
+ </svg>
|
|
|
+ </span>
|
|
|
+ </button> -->
|
|
|
+ <button type="button" class="coco-quick-action" v-if="cocoQuickTab === 'course'">
|
|
|
+ <span class="coco-quick-action-copy">
|
|
|
+ <span class="coco-quick-action-title">{{ lang.ssAiChatQuickRecommendToolsTitle }}</span>
|
|
|
+ <span class="coco-quick-action-desc">{{ lang.ssAiChatQuickRecommendToolsDesc }}</span>
|
|
|
+ </span>
|
|
|
+ <span class="coco-quick-action-arrow">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M5 12h14"></path>
|
|
|
+ <path d="M13 5l7 7-7 7"></path>
|
|
|
</svg>
|
|
|
- <button class="confirm-btn" :class="{ disabled: message.jsonData?.isGenerate }" v-if="message.jsonData?.gType !== 'chat' && !message.chatloading && message.aiContent"
|
|
|
- @click="generate(message)">{{ message.gLoading ? lang.ssLoading : lang.ssConfirm}}</button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ </span>
|
|
|
+ </button>
|
|
|
+ <button type="button" class="coco-quick-action" v-if="cocoQuickTab === 'course'">
|
|
|
+ <span class="coco-quick-action-copy">
|
|
|
+ <span class="coco-quick-action-title">{{ lang.ssAiChatQuickBatchGenToolsTitle }}</span>
|
|
|
+ <span class="coco-quick-action-desc">{{ lang.ssAiChatQuickBatchGenToolsDesc }}</span>
|
|
|
+ </span>
|
|
|
+ <span class="coco-quick-action-arrow">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M5 12h14"></path>
|
|
|
+ <path d="M13 5l7 7-7 7"></path>
|
|
|
+ </svg>
|
|
|
+ </span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <!-- 输入区域 -->
|
|
|
- <div class="input-section">
|
|
|
- <div class="input-wrapper">
|
|
|
- <div class="file-box" v-show="files.length">
|
|
|
- <div v-for="(file, index) in files" :key="index" class="file-item">
|
|
|
- <span class="file-name">{{ file.title }}</span>
|
|
|
- <button class="remove-file-btn" @click="removeFile(index)">
|
|
|
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
- <line x1="18" y1="6" x2="6" y2="18"></line>
|
|
|
- <line x1="6" y1="6" x2="18" y2="18"></line>
|
|
|
- </svg>
|
|
|
- </button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <textarea class="ai-input"
|
|
|
- :placeholder="messages.length === 0 ? lang.ssAiChatExample : lang.ssAiChatShortcut"
|
|
|
- v-model="inputText" @keyup.enter.exact="sendMessage" rows="5" />
|
|
|
- <div class="input-actions">
|
|
|
- <FileInput accept="*" @change="handleFileUpload" >
|
|
|
- <button class="attach-btn">
|
|
|
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
- <path
|
|
|
- d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48">
|
|
|
- </path>
|
|
|
- </svg>
|
|
|
- </button>
|
|
|
- </FileInput>
|
|
|
- <button class="send-btn" @click="sendMessage" v-if="!chatLoading">
|
|
|
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
|
- stroke-linecap="round" stroke-linejoin="round">
|
|
|
- <line x1="22" y1="2" x2="11" y2="13"></line>
|
|
|
- <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
|
|
|
- </svg>
|
|
|
- </button>
|
|
|
- <button class="send-btn stop" @click="stopMessage" v-if="chatLoading">
|
|
|
- <svg width="32" height="32" viewBox="0 0 32 32"
|
|
|
- fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
- <rect width="32" height="32" rx="16" fill="black" fill-opacity="0.4"></rect>
|
|
|
- <path
|
|
|
- d="M11.3333 12.333C11.3333 11.7807 11.781 11.333 12.3333 11.333H19.6666C20.2189 11.333 20.6666 11.7807 20.6666 12.333V19.6663C20.6666 20.2186 20.2189 20.6663 19.6666 20.6663H12.3333C11.781 20.6663 11.3333 20.2186 11.3333 19.6663V12.333Z"
|
|
|
- fill="white" fill-opacity="0.9"></path>
|
|
|
- </svg>
|
|
|
- </button>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 聊天区域 -->
|
|
|
+ <div class="chat-section" ref="chatSection">
|
|
|
+ <!-- 消息列表 -->
|
|
|
+ <div v-for="(message, index) in messages" :key="index" class="chat-message">
|
|
|
+ <div class="message-content user-message chat" v-if="message.content">
|
|
|
+ <div v-html="message.content"></div>
|
|
|
+ <!-- 显示上传的文件 -->
|
|
|
+ <div class="message-files" v-if="message.sourceFiles && message.sourceFiles.length > 0">
|
|
|
+ <div v-for="(file, index) in message.sourceFiles" :key="index" class="message-file-item">
|
|
|
+ <span>{{ file.title }}</span>
|
|
|
</div>
|
|
|
- <!-- 输入时的快捷操作弹出 -->
|
|
|
- <div class="quick-actions-popup" v-if="showQuickActions">
|
|
|
- <button v-for="(action, index) in quickActions" :key="index" class="quick-action-btn" @click="sendQuickAction(action)">{{ action }}</button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+ <div class="message-content ai-message chat" v-if="message.aiContent || message.loading">
|
|
|
+ <div v-if="message.aiContent" v-html="message.aiContent"></div>
|
|
|
+ <svg v-else xmlns="http://www.w3.org/2000/svg" width="32" height="32"
|
|
|
+ viewBox="0 0 24 24"><!-- Icon from SVG Spinners by Utkarsh Verma - https://github.com/n3r4zzurr0/svg-spinners/blob/main/LICENSE -->
|
|
|
+ <circle cx="4" cy="12" r="3" fill="currentColor">
|
|
|
+ <animate id="svgSpinners3DotsBounce0" attributeName="cy" begin="0;svgSpinners3DotsBounce1.end+0.25s"
|
|
|
+ calcMode="spline" dur="0.6s" keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12" />
|
|
|
+ </circle>
|
|
|
+ <circle cx="12" cy="12" r="3" fill="currentColor">
|
|
|
+ <animate attributeName="cy" begin="svgSpinners3DotsBounce0.begin+0.1s" calcMode="spline" dur="0.6s"
|
|
|
+ keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12" />
|
|
|
+ </circle>
|
|
|
+ <circle cx="20" cy="12" r="3" fill="currentColor">
|
|
|
+ <animate id="svgSpinners3DotsBounce1" attributeName="cy" begin="svgSpinners3DotsBounce0.begin+0.2s"
|
|
|
+ calcMode="spline" dur="0.6s" keySplines=".33,.66,.66,1;.33,0,.66,.33" values="12;6;12" />
|
|
|
+ </circle>
|
|
|
+ </svg>
|
|
|
+ <button class="confirm-btn" :class="{ disabled: message.jsonData?.isGenerate }"
|
|
|
+ v-if="message.jsonData?.gType !== 'chat' && !message.chatloading && message.aiContent"
|
|
|
+ @click="generate(message)">{{ message.gLoading ? lang.ssLoading : lang.ssConfirm }}</button>
|
|
|
</div>
|
|
|
- <!-- 初始状态 -->
|
|
|
- <div class="initial-state" v-if="messages.length === 0">
|
|
|
- <!-- 快捷操作 -->
|
|
|
- <div class="quick-actions">
|
|
|
- <button v-for="(action, index) in quickActions" :key="index" class="quick-action-btn" @click="sendQuickAction(action)">{{ action }}</button>
|
|
|
- </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 输入区域 -->
|
|
|
+ <div class="input-section">
|
|
|
+ <div class="input-wrapper">
|
|
|
+ <div class="file-box" v-show="files.length">
|
|
|
+ <div v-for="(file, index) in files" :key="index" class="file-item">
|
|
|
+ <span class="file-name">{{ file.title }}</span>
|
|
|
+ <button class="remove-file-btn" @click="removeFile(index)">
|
|
|
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
|
+ stroke-linejoin="round">
|
|
|
+ <line x1="18" y1="6" x2="6" y2="18"></line>
|
|
|
+ <line x1="6" y1="6" x2="18" y2="18"></line>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <textarea class="ai-input" :placeholder="lang.ssAiChatShortcut"
|
|
|
+ v-model="inputText" @keyup.enter.exact="sendMessage" rows="5" />
|
|
|
+ <div class="input-actions">
|
|
|
+ <FileInput accept="*" @change="handleFileUpload">
|
|
|
+ <button class="attach-btn">
|
|
|
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
|
+ <path
|
|
|
+ d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48">
|
|
|
+ </path>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ </FileInput>
|
|
|
+ <button class="send-btn" @click="sendMessage" v-if="!chatLoading">
|
|
|
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
|
|
+ stroke-linejoin="round">
|
|
|
+ <line x1="22" y1="2" x2="11" y2="13"></line>
|
|
|
+ <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ <button class="send-btn stop" @click="stopMessage" v-if="chatLoading">
|
|
|
+ <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <rect width="32" height="32" rx="16" fill="black" fill-opacity="0.4"></rect>
|
|
|
+ <path
|
|
|
+ d="M11.3333 12.333C11.3333 11.7807 11.781 11.333 12.3333 11.333H19.6666C20.2189 11.333 20.6666 11.7807 20.6666 12.333V19.6663C20.6666 20.2186 20.2189 20.6663 19.6666 20.6663H12.3333C11.781 20.6663 11.3333 20.2186 11.3333 19.6663V12.333Z"
|
|
|
+ fill="white" fill-opacity="0.9"></path>
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
</div>
|
|
|
+ </div>
|
|
|
+ <!-- 输入时的快捷操作弹出 -->
|
|
|
+ <div class="quick-actions-popup" v-if="showQuickActions">
|
|
|
+ <button v-for="(action, index) in quickActions" :key="index" class="quick-action-btn"
|
|
|
+ @click="sendQuickAction(action)">{{ action }}</button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
+ <!-- 初始状态 -->
|
|
|
+ <div class="initial-state" v-if="false">
|
|
|
+ <!-- 快捷操作 -->
|
|
|
+ <div class="quick-actions">
|
|
|
+ <button v-for="(action, index) in quickActions" :key="index" class="quick-action-btn"
|
|
|
+ @click="sendQuickAction(action)">{{ action }}</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
@@ -109,48 +193,48 @@ import axios from '@/services/config'
|
|
|
import message from '@/utils/message'
|
|
|
|
|
|
interface ChatMessage {
|
|
|
- uid?: string
|
|
|
- role: 'ai' | 'user'
|
|
|
- content?: string
|
|
|
- aiContent?: string
|
|
|
- oldContent?: string
|
|
|
- loading?: boolean
|
|
|
- chatloading?: boolean
|
|
|
- gLoading?: boolean
|
|
|
- rawContent?: string
|
|
|
- timestamp?: Date
|
|
|
- like?: boolean
|
|
|
- unlike?: boolean
|
|
|
- isTyping?: boolean
|
|
|
- AI?: string
|
|
|
- isShowSynchronization?: boolean
|
|
|
- filename?: string
|
|
|
- is_mind_map?: boolean
|
|
|
- sourceFiles?: Array<{
|
|
|
- title: string
|
|
|
- id?: string
|
|
|
- url?: string
|
|
|
+ uid?: string
|
|
|
+ role: 'ai' | 'user'
|
|
|
+ content?: string
|
|
|
+ aiContent?: string
|
|
|
+ oldContent?: string
|
|
|
+ loading?: boolean
|
|
|
+ chatloading?: boolean
|
|
|
+ gLoading?: boolean
|
|
|
+ rawContent?: string
|
|
|
+ timestamp?: Date
|
|
|
+ like?: boolean
|
|
|
+ unlike?: boolean
|
|
|
+ isTyping?: boolean
|
|
|
+ AI?: string
|
|
|
+ isShowSynchronization?: boolean
|
|
|
+ filename?: string
|
|
|
+ is_mind_map?: boolean
|
|
|
+ sourceFiles?: Array<{
|
|
|
+ title: string
|
|
|
+ id?: string
|
|
|
+ url?: string
|
|
|
+ }>
|
|
|
+ jsonData?: {
|
|
|
+ gType?: string
|
|
|
+ isGenerate?: boolean
|
|
|
+ headUrl?: string
|
|
|
+ assistantName?: string
|
|
|
+ files?: Array<{
|
|
|
+ title: string
|
|
|
+ id?: string
|
|
|
+ url?: string
|
|
|
}>
|
|
|
- jsonData?: {
|
|
|
- gType?: string
|
|
|
- isGenerate?: boolean
|
|
|
- headUrl?: string
|
|
|
- assistantName?: string
|
|
|
- files?: Array<{
|
|
|
- title: string
|
|
|
- id?: string
|
|
|
- url?: string
|
|
|
- }>
|
|
|
- sourceArray?: Array<{
|
|
|
- text?: string
|
|
|
- id?: string
|
|
|
- title?: string
|
|
|
- }>
|
|
|
- }
|
|
|
+ sourceArray?: Array<{
|
|
|
+ text?: string
|
|
|
+ id?: string
|
|
|
+ title?: string
|
|
|
+ }>
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const props = withDefaults(defineProps<{
|
|
|
- userid?: string | null
|
|
|
+ userid?: string | null
|
|
|
}>(), {
|
|
|
userid: null,
|
|
|
})
|
|
|
@@ -174,7 +258,8 @@ const quickActions = [
|
|
|
|
|
|
// 监听输入变化,当输入"/"时显示快捷操作
|
|
|
watch(inputText, (newValue) => {
|
|
|
- if (messages.value.length > 0 && newValue === '/') {
|
|
|
+ // messages.value.length > 0 &&
|
|
|
+ if (newValue === '/') {
|
|
|
showQuickActions.value = true
|
|
|
}
|
|
|
else if (newValue !== '/') {
|
|
|
@@ -242,7 +327,7 @@ const stopMessage = () => {
|
|
|
const handleFileUpload = async (files2: File[]) => {
|
|
|
const maxSize = 10 * 1024 * 1024 // 10MB
|
|
|
const uploadPromises = []
|
|
|
-
|
|
|
+
|
|
|
for (let i = 0; i < files2.length; i++) {
|
|
|
const file = files2[i]
|
|
|
if (file.size > maxSize) {
|
|
|
@@ -281,10 +366,10 @@ const handleFileUpload = async (files2: File[]) => {
|
|
|
files.value.splice(fileIndex, 1)
|
|
|
}
|
|
|
})
|
|
|
-
|
|
|
+
|
|
|
uploadPromises.push(uploadPromise)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 等待所有文件上传完成
|
|
|
await Promise.allSettled(uploadPromises)
|
|
|
}
|
|
|
@@ -367,7 +452,7 @@ const sendAction = async (action: string) => {
|
|
|
const tempElement = document.createElement('div')
|
|
|
tempElement.innerHTML = textElement.content
|
|
|
return tempElement.textContent || tempElement.innerText || ''
|
|
|
-
|
|
|
+
|
|
|
|
|
|
})
|
|
|
.filter(content => content.trim() !== '') || []
|
|
|
@@ -482,7 +567,7 @@ const uploadFile2 = async (file: File, signal?: AbortSignal): Promise<any> => {
|
|
|
const timestamp = Date.now()
|
|
|
const finalExtension = file.name.split('.').pop()?.toLowerCase() || ''
|
|
|
const baseName = file.name.slice(0, -(finalExtension.length + 1))
|
|
|
-
|
|
|
+
|
|
|
formData.append(
|
|
|
'file',
|
|
|
new File([file], `${baseName}${timestamp}.${finalExtension}`)
|
|
|
@@ -504,7 +589,7 @@ const uploadFile2 = async (file: File, signal?: AbortSignal): Promise<any> => {
|
|
|
signal: signal
|
|
|
}
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
console.log(res)
|
|
|
return res
|
|
|
}
|
|
|
@@ -522,6 +607,22 @@ const uploadFile2 = async (file: File, signal?: AbortSignal): Promise<any> => {
|
|
|
const agentid1 = ref('cbb29b41-2a4a-4453-bf8d-357929ced4bd')// 判断意图
|
|
|
const agentid2 = ref('f86aa63c-b7b7-4d03-9b37-b59f116d36f3')// 生成内容
|
|
|
|
|
|
+const isQuickActions = ref<string[]>([])
|
|
|
+const toggleQuickActions = (section: string) => {
|
|
|
+ if (isQuickActions.value.includes(section)) {
|
|
|
+ isQuickActions.value = isQuickActions.value.filter((item: string) => item !== section)
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ isQuickActions.value.push(section)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const cocoQuickTab = ref('page')
|
|
|
+const setCocoQuickTab = (tab: string) => {
|
|
|
+ cocoQuickTab.value = tab
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
onMounted(() => {
|
|
|
session_name.value = uuidv4()
|
|
|
@@ -532,379 +633,549 @@ onMounted(() => {
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.ai-chat-container {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- padding: 16px;
|
|
|
- gap: 16px;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding: 16px;
|
|
|
+ gap: 16px;
|
|
|
}
|
|
|
|
|
|
.input-section {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 12px;
|
|
|
- position: relative;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12px;
|
|
|
+ position: relative;
|
|
|
}
|
|
|
|
|
|
.input-wrapper {
|
|
|
- position: relative;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- background: #fafbfc;
|
|
|
- border: 1.5px solid #e5e7eb;
|
|
|
- border-radius: 8px;
|
|
|
- padding: 8px 12px;
|
|
|
- min-height: 120px;
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ background: #fafbfc;
|
|
|
+ border: 1.5px solid #e5e7eb;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ min-height: 120px;
|
|
|
}
|
|
|
|
|
|
.ai-input {
|
|
|
- flex: 1;
|
|
|
- border: none;
|
|
|
- background: transparent;
|
|
|
- font-size: 14px;
|
|
|
- color: #374151;
|
|
|
- outline: none;
|
|
|
- resize: none;
|
|
|
- min-height: 80px;
|
|
|
-
|
|
|
- &::placeholder {
|
|
|
- color: #9CA3AF;
|
|
|
- }
|
|
|
+ flex: 1;
|
|
|
+ border: none;
|
|
|
+ background: transparent;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #374151;
|
|
|
+ outline: none;
|
|
|
+ resize: none;
|
|
|
+ min-height: 80px;
|
|
|
+
|
|
|
+ &::placeholder {
|
|
|
+ color: #9CA3AF;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.input-actions {
|
|
|
- display: flex;
|
|
|
- // justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-top: 8px;
|
|
|
+ display: flex;
|
|
|
+ // justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 8px;
|
|
|
}
|
|
|
|
|
|
.attach-btn {
|
|
|
- width: 32px;
|
|
|
- height: 32px;
|
|
|
- background: none;
|
|
|
- border: none;
|
|
|
- cursor: pointer;
|
|
|
- padding: 4px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- transition: all 0.3s ease;
|
|
|
- color: #6b7280;
|
|
|
-
|
|
|
- svg {
|
|
|
- width: 20px;
|
|
|
- height: 20px;
|
|
|
- }
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ background: none;
|
|
|
+ border: none;
|
|
|
+ cursor: pointer;
|
|
|
+ padding: 4px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+ color: #6b7280;
|
|
|
+
|
|
|
+ svg {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ }
|
|
|
|
|
|
- &:hover {
|
|
|
- background: #FFF4E5;
|
|
|
- color: #F78B22;
|
|
|
- border-radius: 4px;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ background: #FFF4E5;
|
|
|
+ color: #F78B22;
|
|
|
+ border-radius: 4px;
|
|
|
+ }
|
|
|
|
|
|
- input[type="file"] {
|
|
|
- display: none;
|
|
|
- }
|
|
|
+ input[type="file"] {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.file-box {
|
|
|
- margin-bottom: 8px;
|
|
|
- min-height: 24px;
|
|
|
- max-height: 70px;
|
|
|
- overflow-y: auto;
|
|
|
-
|
|
|
- .file-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- background: #f5f5f5;
|
|
|
- padding: 4px 8px;
|
|
|
- border-radius: 4px;
|
|
|
- margin-bottom: 4px;
|
|
|
-
|
|
|
- .file-name {
|
|
|
- flex: 1;
|
|
|
- font-size: 12px;
|
|
|
- color: #374151;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- white-space: nowrap;
|
|
|
- }
|
|
|
+ margin-bottom: 8px;
|
|
|
+ min-height: 24px;
|
|
|
+ max-height: 70px;
|
|
|
+ overflow-y: auto;
|
|
|
|
|
|
- .remove-file-btn {
|
|
|
- background: none;
|
|
|
- border: none;
|
|
|
- cursor: pointer;
|
|
|
- color: #9CA3AF;
|
|
|
- font-size: 12px;
|
|
|
- padding: 2px;
|
|
|
- margin-left: 8px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
+ .file-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ background: #f5f5f5;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ margin-bottom: 4px;
|
|
|
+
|
|
|
+ .file-name {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #374151;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
|
|
|
- svg {
|
|
|
- width: 14px;
|
|
|
- height: 14px;
|
|
|
- }
|
|
|
+ .remove-file-btn {
|
|
|
+ background: none;
|
|
|
+ border: none;
|
|
|
+ cursor: pointer;
|
|
|
+ color: #9CA3AF;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 2px;
|
|
|
+ margin-left: 8px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+
|
|
|
+ svg {
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ }
|
|
|
|
|
|
- &:hover {
|
|
|
- color: #EF4444;
|
|
|
- }
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ color: #EF4444;
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.send-btn {
|
|
|
- margin-left: auto;
|
|
|
- width: 32px;
|
|
|
- height: 32px;
|
|
|
- border: none;
|
|
|
- background: #FF9300;
|
|
|
- color: #fff;
|
|
|
- border-radius: 50%;
|
|
|
- cursor: pointer;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- transition: all 0.3s ease;
|
|
|
+ margin-left: auto;
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ border: none;
|
|
|
+ background: #FF9300;
|
|
|
+ color: #fff;
|
|
|
+ border-radius: 50%;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+
|
|
|
+ svg {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ }
|
|
|
|
|
|
- svg {
|
|
|
- width: 20px;
|
|
|
- height: 20px;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ background: #E68A00;
|
|
|
+ }
|
|
|
|
|
|
- &:hover {
|
|
|
- background: #E68A00;
|
|
|
- }
|
|
|
+ &.stop {
|
|
|
+ background: unset;
|
|
|
+ width: auto;
|
|
|
|
|
|
- &.stop {
|
|
|
- background: unset;
|
|
|
- width: auto;
|
|
|
- svg {
|
|
|
- width: 32px;
|
|
|
- height: 32px;
|
|
|
- }
|
|
|
+ svg {
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.quick-actions {
|
|
|
- // display: flex;
|
|
|
- // flex-direction: column;
|
|
|
- // gap: 8px;
|
|
|
-
|
|
|
- .quick-action-btn {
|
|
|
- padding: 5px 10px;
|
|
|
- border: 1px solid #f7c58f;
|
|
|
- background: #FFF9F2;
|
|
|
- color: #6b4a1f;
|
|
|
- border-radius: 16px;
|
|
|
- font-size: 12px;
|
|
|
- cursor: pointer;
|
|
|
- text-align: left;
|
|
|
- display: block;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- border-color: #F78B22;
|
|
|
- background: #FFF4E5;
|
|
|
- color: #111827;
|
|
|
- }
|
|
|
+ // display: flex;
|
|
|
+ // flex-direction: column;
|
|
|
+ // gap: 8px;
|
|
|
+
|
|
|
+ .quick-action-btn {
|
|
|
+ padding: 5px 10px;
|
|
|
+ border: 1px solid #f7c58f;
|
|
|
+ background: #FFF9F2;
|
|
|
+ color: #6b4a1f;
|
|
|
+ border-radius: 16px;
|
|
|
+ font-size: 12px;
|
|
|
+ cursor: pointer;
|
|
|
+ text-align: left;
|
|
|
+ display: block;
|
|
|
|
|
|
- +.quick-action-btn {
|
|
|
- margin-top: 8px;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ border-color: #F78B22;
|
|
|
+ background: #FFF4E5;
|
|
|
+ color: #111827;
|
|
|
+ }
|
|
|
+
|
|
|
+ +.quick-action-btn {
|
|
|
+ margin-top: 8px;
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chat-section {
|
|
|
- // flex: 1;
|
|
|
- height: calc(100% - 155px);
|
|
|
- overflow-y: auto;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- // gap: 16px;
|
|
|
- padding-right: 8px;
|
|
|
-
|
|
|
- &::-webkit-scrollbar {
|
|
|
- width: 6px;
|
|
|
- }
|
|
|
+ // flex: 1;
|
|
|
+ height: calc(100% - 155px);
|
|
|
+ overflow-y: auto;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ // gap: 16px;
|
|
|
+ padding-right: 8px;
|
|
|
+
|
|
|
+ &::-webkit-scrollbar {
|
|
|
+ width: 6px;
|
|
|
+ }
|
|
|
|
|
|
- &::-webkit-scrollbar-track {
|
|
|
- background: #F3F4F6;
|
|
|
- border-radius: 3px;
|
|
|
- }
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
+ background: #F3F4F6;
|
|
|
+ border-radius: 3px;
|
|
|
+ }
|
|
|
|
|
|
- &::-webkit-scrollbar-thumb {
|
|
|
- background: #D1D5DB;
|
|
|
- border-radius: 3px;
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
+ background: #D1D5DB;
|
|
|
+ border-radius: 3px;
|
|
|
|
|
|
- &:hover {
|
|
|
- background: #9CA3AF;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ background: #9CA3AF;
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.chat-message {
|
|
|
- max-width: 100%;
|
|
|
- margin-bottom: 10px;
|
|
|
+ max-width: 100%;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+
|
|
|
+ .message-content {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 8px 10px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.5;
|
|
|
+ color: #374151;
|
|
|
+ width: fit-content;
|
|
|
|
|
|
- .message-content {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- border-radius: 8px;
|
|
|
- padding: 8px 10px;
|
|
|
- font-size: 14px;
|
|
|
- line-height: 1.5;
|
|
|
- color: #374151;
|
|
|
- width: fit-content;
|
|
|
-
|
|
|
- +.message-content {
|
|
|
- margin-top: 10px;
|
|
|
- }
|
|
|
+ +.message-content {
|
|
|
+ margin-top: 10px;
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.message-content {
|
|
|
- word-break: break-word;
|
|
|
+ word-break: break-word;
|
|
|
|
|
|
- &.ai-message {
|
|
|
- align-self: flex-start;
|
|
|
- background: #fafbfc;
|
|
|
- border: 1.5px solid #e5e7eb;
|
|
|
- border-bottom-left-radius: 2px;
|
|
|
+ &.ai-message {
|
|
|
+ align-self: flex-start;
|
|
|
+ background: #fafbfc;
|
|
|
+ border: 1.5px solid #e5e7eb;
|
|
|
+ border-bottom-left-radius: 2px;
|
|
|
|
|
|
- &>svg {
|
|
|
- width: 17px;
|
|
|
- height: 17px;
|
|
|
- }
|
|
|
+ &>svg {
|
|
|
+ width: 17px;
|
|
|
+ height: 17px;
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.message-content {
|
|
|
- &.user-message {
|
|
|
- align-self: flex-end;
|
|
|
- background: #FFF4E5;
|
|
|
- border: 1.5px solid #F78B22;
|
|
|
- border-bottom-right-radius: 2px;
|
|
|
- }
|
|
|
+ &.user-message {
|
|
|
+ align-self: flex-end;
|
|
|
+ background: #FFF4E5;
|
|
|
+ border: 1.5px solid #F78B22;
|
|
|
+ border-bottom-right-radius: 2px;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.initial-state {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- justify-content: flex-start;
|
|
|
- align-items: flex-start;
|
|
|
- // padding: 24px;
|
|
|
- gap: 16px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: flex-start;
|
|
|
+ align-items: flex-start;
|
|
|
+ // padding: 24px;
|
|
|
+ gap: 16px;
|
|
|
}
|
|
|
|
|
|
|
|
|
.confirm-btn {
|
|
|
- margin-top: 10px;
|
|
|
- padding: 6px 15px;
|
|
|
- background: #FF9300;
|
|
|
- color: white;
|
|
|
+ margin-top: 10px;
|
|
|
+ padding: 6px 15px;
|
|
|
+ background: #FF9300;
|
|
|
+ color: white;
|
|
|
+ border: none;
|
|
|
+ border-radius: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-left: auto;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #E68A00;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.disabled {
|
|
|
+ background: #9CA3AF;
|
|
|
+ cursor: not-allowed;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+ul {
|
|
|
+ margin: 8px 0;
|
|
|
+ padding-left: 20px;
|
|
|
+
|
|
|
+ li {
|
|
|
+ margin: 4px 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.quick-actions-popup {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 100%;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ background: white;
|
|
|
+ border: 1px solid #E5E7EB;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
|
+ padding: 8px;
|
|
|
+ z-index: 100;
|
|
|
+ margin-bottom: 8px;
|
|
|
+
|
|
|
+ .quick-action-btn {
|
|
|
+ width: 100%;
|
|
|
+ text-align: left;
|
|
|
+ padding: 10px 12px;
|
|
|
+ background: white;
|
|
|
border: none;
|
|
|
- border-radius: 8px;
|
|
|
+ border-radius: 6px;
|
|
|
font-size: 14px;
|
|
|
+ color: #374151;
|
|
|
cursor: pointer;
|
|
|
- margin-left: auto;
|
|
|
- transition: all 0.3s ease;
|
|
|
+ transition: all 0.2s ease;
|
|
|
|
|
|
&:hover {
|
|
|
- background: #E68A00;
|
|
|
- }
|
|
|
- &.disabled {
|
|
|
- background: #9CA3AF;
|
|
|
- cursor: not-allowed;
|
|
|
+ background: #fff4e5;
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-ul {
|
|
|
- margin: 8px 0;
|
|
|
- padding-left: 20px;
|
|
|
+.message-quick-box {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ flex-shrink: 0;
|
|
|
+ gap: 10px;
|
|
|
+
|
|
|
+ .message-quick-box-item {
|
|
|
+ box-shadow: rgba(17, 24, 39, 0.04) 0px 10px 30px;
|
|
|
+ border-width: 1px;
|
|
|
+ border-style: solid;
|
|
|
+ border-color: rgb(239, 229, 216);
|
|
|
+ border-image: initial;
|
|
|
+ border-radius: 18px;
|
|
|
+ background: rgba(255, 255, 255, 0.96);
|
|
|
+ overflow: hidden;
|
|
|
|
|
|
- li {
|
|
|
- margin: 4px 0;
|
|
|
+
|
|
|
+ .coco-collapse-trigger {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ cursor: pointer;
|
|
|
+ text-align: left;
|
|
|
+ gap: 12px;
|
|
|
+ border-width: initial;
|
|
|
+ border-style: none;
|
|
|
+ border-color: initial;
|
|
|
+ border-image: initial;
|
|
|
+ background: transparent;
|
|
|
+ padding: 12px 14px;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: rgb(255, 251, 245);
|
|
|
+ }
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-.quick-actions-popup {
|
|
|
- position: absolute;
|
|
|
- bottom: 100%;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- background: white;
|
|
|
- border: 1px solid #E5E7EB;
|
|
|
- border-radius: 8px;
|
|
|
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
|
- padding: 8px;
|
|
|
- z-index: 100;
|
|
|
- margin-bottom: 8px;
|
|
|
-
|
|
|
- .quick-action-btn {
|
|
|
- width: 100%;
|
|
|
- text-align: left;
|
|
|
- padding: 10px 12px;
|
|
|
- background: white;
|
|
|
- border: none;
|
|
|
- border-radius: 6px;
|
|
|
+ .coco-collapse-icon.soft-orange {
|
|
|
+ color: rgb(154, 91, 17);
|
|
|
+ background: rgb(255, 240, 219);
|
|
|
+ }
|
|
|
+
|
|
|
+ .coco-collapse-icon {
|
|
|
+ width: 34px;
|
|
|
+ height: 34px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ flex-shrink: 0;
|
|
|
+ border-radius: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .coco-collapse-copy {
|
|
|
+ min-width: 0px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ flex: 1 1 0%;
|
|
|
+ gap: 2px;
|
|
|
+
|
|
|
+ .coco-collapse-title {
|
|
|
font-size: 14px;
|
|
|
- color: #374151;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.2s ease;
|
|
|
+ font-weight: 700;
|
|
|
+ color: rgb(17, 24, 39);
|
|
|
+ }
|
|
|
+
|
|
|
+ .coco-collapse-subtitle {
|
|
|
+ font-size: 12px;
|
|
|
+ color: rgb(139, 115, 86);
|
|
|
+ line-height: 1.5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .coco-collapse-chevron {
|
|
|
+ color: rgb(156, 163, 175);
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ svg {
|
|
|
+ transition: transform 0.2s;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ .coco-collapse-chevron svg {
|
|
|
+ transform: rotate(180deg);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- &:hover {
|
|
|
- background: #fff4e5;
|
|
|
+ .coco-collapse-body {
|
|
|
+ padding: 0px 14px 14px;
|
|
|
+ .coco-quick-tabs {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(2, minmax(0px, 1fr));
|
|
|
+ margin-bottom: 12px;
|
|
|
+ gap: 8px;
|
|
|
+ .coco-quick-tab {
|
|
|
+ height: 34px;
|
|
|
+ color: rgb(124, 92, 56);
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 12px;
|
|
|
+ border-width: 1px;
|
|
|
+ border-style: solid;
|
|
|
+ border-color: rgb(234, 223, 206);
|
|
|
+ border-image: initial;
|
|
|
+ background: rgb(250, 247, 242);
|
|
|
+ transition: 0.2s;
|
|
|
+ &.active {
|
|
|
+ color: rgb(154, 91, 17);
|
|
|
+ box-shadow: rgba(247, 139, 34, 0.12) 0px 8px 18px;
|
|
|
+ border-color: rgba(247, 139, 34, 0.48);
|
|
|
+ background: rgb(255, 244, 229);
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ .coco-quick-list {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 8px;
|
|
|
+ .coco-quick-action {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ cursor: pointer;
|
|
|
+ text-align: left;
|
|
|
+ gap: 12px;
|
|
|
+ border-width: 1px;
|
|
|
+ border-style: solid;
|
|
|
+ border-color: rgb(239, 229, 216);
|
|
|
+ border-image: initial;
|
|
|
+ background: rgb(255, 253, 250);
|
|
|
+ border-radius: 14px;
|
|
|
+ padding: 12px;
|
|
|
+ transition: 0.2s;
|
|
|
+ .coco-quick-action-copy {
|
|
|
+ min-width: 0px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ flex: 1 1 0%;
|
|
|
+ gap: 4px;
|
|
|
+ .coco-quick-action-title {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: rgb(17, 24, 39);
|
|
|
+ line-height: 1.4;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ .coco-quick-action-desc {
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 1.6;
|
|
|
+ color: rgb(139, 115, 86);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .coco-quick-action-arrow {
|
|
|
+ color: rgb(212, 163, 115);
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding-top: 2px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
<style>
|
|
|
.chat table {
|
|
|
- text-align: center;
|
|
|
- border-spacing: 0;
|
|
|
- border-left: 1px solid #000;
|
|
|
- border-bottom: 1px solid #000;
|
|
|
+ text-align: center;
|
|
|
+ border-spacing: 0;
|
|
|
+ border-left: 1px solid #000;
|
|
|
+ border-bottom: 1px solid #000;
|
|
|
}
|
|
|
|
|
|
.chat table td,
|
|
|
.chat table th {
|
|
|
- border-top: 1px solid #000;
|
|
|
- border-right: 1px solid #000;
|
|
|
- padding: 10px;
|
|
|
+ border-top: 1px solid #000;
|
|
|
+ border-right: 1px solid #000;
|
|
|
+ padding: 10px;
|
|
|
}
|
|
|
|
|
|
.message-files {
|
|
|
- margin-top: 8px;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 4px;
|
|
|
+ margin-top: 8px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 4px;
|
|
|
}
|
|
|
|
|
|
.message-file-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 6px;
|
|
|
- font-size: 12px;
|
|
|
- color: #6b7280;
|
|
|
- background: #f3f4f6;
|
|
|
- padding: 4px 8px;
|
|
|
- border-radius: 4px;
|
|
|
- max-width: 200px;
|
|
|
- overflow: hidden;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #6b7280;
|
|
|
+ background: #f3f4f6;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ max-width: 200px;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.message-file-item span {
|
|
|
- flex: 1;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
+ flex: 1;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
}
|
|
|
</style>
|