<template>
    <div class="main-content"

        @dragstart="handleDragStart"
        @dragenter.prevent="handleDragEnter"
        @dragover.prevent="handleDragOver"
        @mouseup="handleMainMouseUp">
        <div class="inner-dropzone"  v-show="isDragging" @dragleave.prevent="handleDragLeave">
            <div class="inner-dropzone-content" >
                <div class="inner-dropzone-icon">
                    <img :src="isDarkMode? 'icons/upload-dark.svg':'icons/upload-light.svg'" alt=""   class="inner-dropzone-icon-icon"/>
                    <!-- <svgIcon :icon="isDarkMode? 'icons/upload-dark.svg':'icons/upload-light.svg'" class="inner-dropzone-icon-icon"/> --> 
                </div>
                <div class="inner-dropzone-text"> <span class="inner-dropzone-text-span">{{(store.loadTranslations['Drag files here to add them.'])}}</span></div>
                <div class="inner-dropzone-text-suffix"> <span class="inner-dropzone-text-suffix-span" id="innerDropzoneTextSuffix">{{(store.loadTranslations['You can only add one file, supported file types include: txt, doc, docx, xls, xlsx, ppt, pptx, pdf.'])}}</span></div>
            </div>
        </div>
        <!-- 历史会话列表 -->
        <ConversionList class="conversion-list-wrapper"
            :historyList="historyList" 
            :isDarkMode="isDarkMode"
            :show="showConversionList"
            @close="closeHistoryList" 
            @selectHistoryItem="selectHistoryItem"
            @showAlertDialog="showAlertDialog"/>
        <ChatTop />
        <WelcomePage ref="welcomePageRef" 
            v-model:question="question" 
            :recording="recording" 
            :historyLength="history.length"
            :currentAssistant="currentAssistant"
            :isKnowledgeBaseExist="isKnowledgeBaseExist"
            :isEmbeddingPluginsExist="isEmbeddingPluginsExist"
            :isLLMExist="isLLMExist"
            :currentAccount="currentAccount"
            v-show="history.length === 0" />
        <div class="chat-history" v-show="history.length > 0" @mousewheel="handleHistoryScroll">
            <custom-scrollbar class="history-scrollbar" id="chatHistory" ref="chatHistoryScrollbarRef"
                :autoHideDelay="2000" :thumbWidth="6" 
                :wrapperStyle="{height: '100%'}" :style="{ width: '100%', height: '100%'}" >
                <div class="bubble-div">
                    <!-- 重写聊天气泡 -->
                    <ChatBubble v-for="(item, index) in history" :key="index"
                        v-model:playAudioID="playAudioID" 
                        :historyIndex="index"
                        :item="item" :showStop="showStop"
                        :isLast="history.length === index + 1" 
                        :recording="recording" 
                        :netState="netState" 
                        :hasOutput="hasOutput"
                        :isKnowledgeBaseExist="isKnowledgeBaseExist"
                        :isEmbeddingPluginsExist="isEmbeddingPluginsExist"
                        @handleShowTip="handleShowTip" 
                        @retryRequest="retryRequest" 
                        @updateLikeOrDislike="updateLikeOrDislike" 
                        :currentAssistant="currentAssistant"
                        :isLLMExist="isLLMExist"
                        :isDarkMode="isDarkMode"
                        :isWindowMode="isWindowMode"
                    />
                </div>
            </custom-scrollbar>
        </div>
        <div class="chat-bottom">
            <div class="handle-tip">
                <div class="tip-item" v-show="showTopTip">
                    {{ topTipMsg }}
                </div>
                <div class="tip-item" v-show="showCount" v-if="store.loadTranslations['Stop recording after %1 seconds']">
                    {{ store.loadTranslations['Stop recording after %1 seconds'].replace('%1', countDown) }}
                </div>
                <div class="top-stop tip-item" v-show="showStop"  @click="stopRequest">
                    <svgIcon icon="stop" /> {{ store.loadTranslations['Stop'] }}
                </div>
            </div>
            <div class="top-returnBtnOut">
                <el-tooltip popper-class="uos-tooltip" effect="light" :show-arrow="false" :enterable="false"
                    :show-after="1000" :offset="2" :content="store.loadTranslations['Back to bottom']">
                    <div class="top-returnBtn" @click="returnBottom" v-show="showReturnBottom && history.length > 0">
                        <SvgIcon icon="combobox-arrow"/>
                    </div>
                </el-tooltip>
            </div>            
            <div class="top" v-show="!showPropmptList">
                <!-- 创建新会话记录按钮 -->
                <el-tooltip popper-class="uos-tooltip" effect="light" :show-arrow="false" :enterable="false"
                    :show-after="1000" :offset="2" :content="store.loadTranslations['New Conversation']">
                    <div class="add-new-conversation" :class="{'disabled': history.length === 0 || disabled || recording}"
                         :style="{ 'margin-right': '6px'}"
                        @click="createNewConversation">
                        <SvgIcon icon="new-conversation" />
                    </div>
                </el-tooltip>
                <!-- 历史记录按钮 -->
                <el-tooltip popper-class="uos-tooltip" effect="light" :show-arrow="false" :enterable="false"
                    :show-after="1000" :offset="2" :content="store.loadTranslations['History']">
                    <div class="prompt-btn" :class="{'disabled': (recording || disabled)}"
                         :style="{ 'margin-right': ((currentAssistant.type === store.AssistantType.UOS_AI || currentAssistant.id === 'PPT Assistant') && isShowPromptBtn) ? '6px' : 'auto' }"
                        @click="openHistoryList">
                        <SvgIcon icon="open-history" />
                    </div>
                </el-tooltip>
                <!-- 指令按钮 -->
                <el-tooltip popper-class="uos-tooltip" effect="light" :show-arrow="false" :enterable="false"
                    :show-after="1000" :offset="2" :content="store.loadTranslations['Instruction']" 
                    :class="{ 'disabled': !(recording || disabled) }">
                    <div class="prompt-btn" @click="selectPrompt" 
                        style="margin-right: auto;"
                        :class="{ 'disabled': (recording || disabled) }"
                        v-show="(currentAssistant.type === store.AssistantType.UOS_AI || currentAssistant.id === 'PPT Assistant') && isShowPromptBtn">
                        <SvgIcon icon="prompt"/>
                    </div>
                </el-tooltip>
                <!-- 切换助手模型下拉框 -->
                <SwitchModel ref="switchModel" class="switchModel"
                v-model:currentAccount="currentAccount" v-model:accountList="accountList" 
                    v-model:assistantList="assistantList" v-model:currentAssistant="currentAssistant"
                    :disabled="disabled || recording"  @update:currentAssistant="updateCurAssistant" @update:currentAccountChanged="currentAccountChanged"/>
            </div>
            <div class="input-content" @mouseup="handleMouseUp" :class="{ 'foucs': isFocus}">
                <!-- 指令列表 -->
                <PromptList ref="promptListRef" class="propmpt-list"
                    :showPropmptList="showPropmptList" 
                    :searchQuery="searchQuery"
                    :promptInfos="promptInfos"
                    @sigHidePromptLists="sigHidePromptLists" 
                    @sigSelectOnePrompt="sigSelectOnePrompt"/>
                <div class="input-content-all" :style="{'border-radius': showPropmptList ? '0px 0px 8px 8px' : '8px', }">
                    <!-- 挂起来的标签部分 -->
                    <div class="input-tag">
                        <!-- 文档总结 -->
                        <DocumentParsing ref="documentParsingRef" v-show="isShowFile"
                            style="display: auto; top: 0; left: 0;margin-top: 8px;margin-left: 10px;"
                            @sigDeleteFile="sigDeleteFile" :filePath="filePath" :fileNameText="fileNameText" :imgBase64="imgBase64"/>
                        <!-- 指令标签 -->
                        <PromptTag v-show="showPromptTag" :promptTag="promptTag" 
                            style="margin-top: 8px;margin-left: 10px;"/>
                    </div>
                    <el-input v-model="question" 
                        ref="questionInput" 
                        resize="none"
                        :autosize="{ minRows: 4, maxRows: 10 }"
                        type="textarea" 
                        :placeholder="placeHolder" 
                        @focus="handleInputFocus"
                        @blur="handleInputNoFocus"  
                        @keydown.enter.native="handeleEnter" 
                        @input="handleInput"
                        @keydown.up="highlightPrevious"
                        @keydown.down="highlightNext"
                        @keydown.left="handleKeyLeft"
                        @keydown.right="handleKeyRight"
                        @keydown.enter="handleEnterKeyDown"
                        @keydown.backspace="handleBackspace"
                        @mousedown="handleMouseDown"
                        @mouseup="handleInputMouseUp"
                        :disabled="recording || (currentAssistant.type === store.AssistantType.PERSONAL_KNOWLEDGE_ASSISTANT && (!isKnowledgeBaseExist ||!isEmbeddingPluginsExist)&& history.length === 0)
                        || ((currentAssistant.type === store.AssistantType.UOS_SYSTEM_ASSISTANT||currentAssistant.type === store.AssistantType.DEEPIN_SYSTEM_ASSISTANT) && !isEmbeddingPluginsExist && history.length === 0)" />
                    <div class="bottom">
                        <div style="margin-left: 10px; display: flex;">
                            <div v-show="showDeepThinkAndSearchOnline"  style="display: flex;">
                                <el-tooltip popper-class="uos-tooltip" effect="light" :show-arrow="false" :enterable="false"
                                :show-after="1000" :offset="2"
                                :content="store.loadTranslations['DeepThink(R1)']">
                                    <div class="deep-think-btn" @click="deepThinkClick" :style="{'color': store.IsDeepThink ? 'var(--activityColor)' : 'var(--uosai-think-search-color)', 'width' : isChineseLanguage ? '88px' : '120px'}">
                                        <SvgIcon icon="deep-think" :style="{'fill': store.IsDeepThink ?  'var(--activityColor)' : 'var(--uosai-think-search-color)'}"/>
                                        {{ store.loadTranslations['DeepThink(R1)'] }}
                                    </div>
                                </el-tooltip>
                                <el-tooltip popper-class="uos-tooltip" effect="light" :show-arrow="false" :enterable="false"
                                :show-after="1000" :offset="2"
                                :content="store.loadTranslations['Search']">
                                    <div class="deep-think-btn" @click="searchOnlineClick" :style="{'color': store.IsSearchOnline? 'var(--activityColor)' : 'var(--uosai-think-search-color)', 'width' : isChineseLanguage ? '88px' : '78px', 'margin-left': '10px'}">
                                        <SvgIcon icon="search-online" :style="{'fill': store.IsSearchOnline ?  'var(--activityColor)' : 'var(--uosai-think-search-color)'}"/>
                                        {{ store.loadTranslations['Search'] }}
                                    </div>
                                </el-tooltip>
                            </div>
                        </div>
                        <div class="send-btn">
                            <!-- 文档总结按钮 -->
                            <el-tooltip popper-class="uos-tooltip" effect="light" :show-arrow="false" :enterable="false"
                                :show-after="1000" :offset="2"
                                :content="isFileInInput? store.loadTranslations['You can only add a maximum of one file.'] : store.loadTranslations['Upload a document']"
                                :class="{ 'disabled': !(isFileInInput || recording || disabled || (currentAssistant.type != store.AssistantType.UOS_AI && currentAssistant.id != 'PPT Assistant'))}">
                                <div class="file-btn btn"
                                v-show="(currentAssistant.type === store.AssistantType.UOS_AI || currentAssistant.id === 'PPT Assistant')"
                                :class="{ 'disabled': (isFileInInput || recording || disabled || (currentAssistant.type != store.AssistantType.UOS_AI && currentAssistant.id != 'PPT Assistant')) }"
                                    @click="selectFile">
                                    <SvgIcon icon="file" />
                                </div>
                            </el-tooltip>
                            <el-tooltip popper-class="uos-tooltip" effect="light" :show-arrow="false" :enterable="false"
                                :show-after="1000" :offset="2"
                                :content="netState ? !isAudioInput ? store.loadTranslations['Please connect the microphone and try again'] : store.loadTranslations['Voice input'] : store.loadTranslations['Voice input is temporarily unavailable, please check the network!']">
                                <div class="voice-btn btn"
                                    :class="{ recording, disabled: !isAudioInput || showStop || !netState || 
                                        (currentAssistant.type === store.AssistantType.PERSONAL_KNOWLEDGE_ASSISTANT && (!isKnowledgeBaseExist ||!isEmbeddingPluginsExist) && history.length === 0)
                                        || ((currentAssistant.type === store.AssistantType.UOS_SYSTEM_ASSISTANT||currentAssistant.type === store.AssistantType.DEEPIN_SYSTEM_ASSISTANT) && !isEmbeddingPluginsExist && history.length === 0 )
                                        , notalking: audioLevel === 0 }"
                                    @click="handleRecorder">
                                    <SvgIcon icon="voice" />
                                </div>
                            </el-tooltip>
                            <div class="send btn" :class="{ 'disabled': (question.trim().length === 0  && !isFileInInput) || disabled 
                                || (currentAssistant.type === store.AssistantType.PERSONAL_KNOWLEDGE_ASSISTANT && (!isKnowledgeBaseExist ||!isEmbeddingPluginsExist) && history.length === 0)
                                || ((currentAssistant.type === store.AssistantType.UOS_SYSTEM_ASSISTANT||currentAssistant.type === store.AssistantType.DEEPIN_SYSTEM_ASSISTANT)&& !isEmbeddingPluginsExist  && history.length === 0)
                                || (isFileInInput && !isFileParsingSuccess)}"
                                @click="sendQuestion">
                                <SvgIcon icon="send" />
                            </div>
                        </div>
                    </div>
                    
                </div>
            </div>
            <div class="tip">
                {{ store.loadTranslations[`The content generated by AI is for reference only, please pay attention to the accuracy of the information.`] }}
            </div>
        </div>
    </div>
</template>

<script setup>
import { useGlobalStore } from "@/store/global";
import { Qrequest } from "@/utils";
import _ from "lodash";
import SwitchModel from "./components/SwitchModel.vue";
import WelcomePage from "./components/welcomePage.vue";
import ChatBubble from "./components/ChatBubble.vue";
import ChatTop from "./components/ChatTop.vue";
import PromptList from "./components/PromptList.vue";
import PromptTag from "./components/PromptTag.vue";
import ConversionList from "./components/ConversionList.vue"
import CustomScrollbar from 'custom-vue-scrollbar';
import 'custom-vue-scrollbar/dist/style.css';
import { ref } from "vue";
import { useRouter } from "vue-router";

//*******************************************************************************
/**
 * 拖拽蒙版js
 */
import DocumentParsing from "./components/DocumentParsing.vue"
import SvgIcon from "@/components/svgIcon/svgIcon.vue";
const documentParsingRef = ref()
const showFile=ref(false)
const fileNameText=ref('')
const filePath= ref('')
const imgBase64= ref('')
const isDragging = ref(false); // 控制蒙版显示的变量
const isFileInInput = ref(false)  //输入框是否存在文件
const isFileParsingSuccess = ref(false)  //文件解析状态成功
const isDarkMode = ref(false)  //是否为深色主题
const isShowDocInHistory = ref(false)

//历史记录中文件属性
const fileContentParam = {
            isShowDoc:false,
            docPath:"",
            iconData:""
        }

function handleDragEnter(event) {
    event.preventDefault(); // 阻止默认事件
    event.stopPropagation();

    if(disabled.value) return  //回答中
    if(recording.value) return  //录音中
    // if(isFileInInput.value) return  //文件存在
    if(currentAssistant.value.type != store.AssistantType.UOS_AI && currentAssistant.value.id != 'PPT Assistant') return  //非UOS AI助手
    const messageElement = document.getElementById('innerDropzoneTextSuffix');
    if(currentAssistant.value.type === store.AssistantType.UOS_AI) {
       messageElement.textContent = store.loadTranslations['You can only add one file, supported file types include: txt, doc, docx, xls, xlsx, ppt, pptx, pdf.']
    } else if(currentAssistant.value.id === 'PPT Assistant') {
       messageElement.textContent = "最多只能添加一个文件，文件类型：docx"
    }
    isDragging.value = true;
}


function handleDragOver(event) {
    event.preventDefault(); // 阻止默认事件

    if(disabled.value) return  //回答中
    if(recording.value) return  //录音中
    // if(isFileInInput.value) return  //文件存在
    if(currentAssistant.value.type != store.AssistantType.UOS_AI && currentAssistant.value.id != 'PPT Assistant') return  //非UOS AI助手
    const messageElement = document.getElementById('innerDropzoneTextSuffix');
    if(currentAssistant.value.type === store.AssistantType.UOS_AI) {
       messageElement.textContent = store.loadTranslations['You can only add one file, supported file types include: txt, doc, docx, xls, xlsx, ppt, pptx, pdf.']
    } else if(currentAssistant.value.id === 'PPT Assistant') {
       messageElement.textContent = "最多只能添加一个文件，文件类型：docx"
    }
    isDragging.value = true;
}

function handleDragLeave(event) {
    event.stopPropagation();
    isDragging.value = false;
}

function handleDragLeaveChild(event) {
    event.stopPropagation();
    event.preventDefault(); // 阻止默认事件
}

function handleDragEnterChild(event) {
    event.preventDefault(); // 阻止默认事件
    event.stopPropagation();
}

/**
 * 文档显示图标js
 */

//*******************************************************************************

const router = useRouter();
const { chatQWeb, updateActivityColor, updateTheme, updateFont, updateMainContentBackgroundColor} = useGlobalStore()
const store = useGlobalStore()
const instance = getCurrentInstance()
const question = ref('')
const isFocus = ref(false)
const showTopTip = ref(false)
// showStop控制 底部的清除icon、发送按钮、语音图标、模型切换、状态切换按钮、<>置灰，播放按钮置灰，设置不置灰，可正常点击
const showStop = ref(false)
const topTipMsg = ref('')
const accountList = ref([])
const assistantList = ref([])
const currentAccount = ref('')
const currentAssistant = ref('')
const playAudioID = ref('')
const isKnowledgeBaseExist = ref(false)
const isEmbeddingPluginsExist = ref(false)
const isLLMExist = ref(false)
const disabled = computed(() => {
    return showStop.value
})
const isAudioInput = ref(false)
const isWindowMode = ref(false);
const isChineseLanguage = ref(false);

const initChat = async () => {
    const resAccount = await Qrequest(chatQWeb.queryLLMAccountList)
    const resCurAccountID = await Qrequest(chatQWeb.currentLLMAccountId)
    const resAssistant = await Qrequest(chatQWeb.queryAssistantList)
    const resCurAssistantID = await Qrequest(chatQWeb.currentAssistantId)
    isAudioInput.value = await Qrequest(chatQWeb.isAudioInputAvailable)
    hasOutput.value = await Qrequest(chatQWeb.isAudioOutputAvailable)
    netState.value = await Qrequest(chatQWeb.isNetworkAvailable)
    isKnowledgeBaseExist.value = await Qrequest(chatQWeb.isKnowledgeBaseExist)
    isEmbeddingPluginsExist.value = await Qrequest(chatQWeb.isEmbeddingPluginsExist)

    isChineseLanguage.value = await Qrequest(chatQWeb.isChineseLanguage)

    // 获取当前对话信息
    await getNowConversationInfo(resCurAssistantID)

    //新版查询历史记录
    const _history = await Qrequest(chatQWeb.getConversations)
    history.value = JSON.parse(_history)

    //查询当前系统主题
    const theme = await Qrequest(chatQWeb.getThemeType)
    sigThemeChanged(theme)

    //查询窗口模式
    isWindowMode.value = await Qrequest(chatQWeb.isWindowMode);

    //查询当前后端统一背景色
    const backgroundColor = await Qrequest(chatQWeb.getMainContentbackgroundColor);
    sigMainContentBackgroundColor(backgroundColor)

    console.log("assistant list: ", resAssistant);
    console.log("current assistant id: ", resCurAssistantID);
    if (resAssistant) {
        const list = JSON.parse(resAssistant);
        assistantList.value = list;
        list.forEach(element => {
            if (element.id === resCurAssistantID) {
                element.active = true
                currentAssistant.value = element
            }
        });
    }
    if (resAccount) {
        const list = JSON.parse(resAccount)
        isLLMExist.value = list.length > 0;
        list.forEach(element => {
            if (element.id === resCurAccountID) {
                element.active = true
                currentAccount.value = element
            }
        });
        accountList.value = list;
    }

    //查询指令列表
    currentAccountChanged(currentAccount)

    //渲染完成，通知后端
    Qrequest(chatQWeb.webViewLoadFinished)
    Qrequest(chatQWeb.chatInitFinished)

    isMouseScroll.value = false  //初始化滚轮状态
    showReturnBottom.value = false  //初始化返回底部按钮状态
    nextTick(() => handelScrol())

    // 解决输入框重新计算行高导致页面跳动问题
    question.value = " "
    setTimeout(() => {
        question.value = ""
    }, 5); 
}

const currentTime = () => {
    //获取当前年月日时分秒
    var today = new Date().toISOString().slice(0, 10);

    const now = new Date();
    const hours = String(now.getHours()).padStart(2, '0');
    const minutes = String(now.getMinutes()).padStart(2, '0');
    const seconds = String(now.getSeconds()).padStart(2, '0');
    const milliseconds = String(now.getMilliseconds()).padStart(3, '0');

    return `${today} ${hours}:${minutes}:${seconds}.${milliseconds}`;
}

const likeOrNotAgent = ['ztbbd', 'xxzsk', 'yzsbs']
const initLikeOrNotExt = () => {
    //招投标初始化ext
    if(likeOrNotAgent.includes(currentAssistant.value.id)){
        let questionVec = []
        for (let index = 0; index < history.value.length; index++) {
            const element = history.value[index];
            
            questionVec.push({
                content: element.question.content,
                role:"user"
            })

            if (index < history.value.length - 1) {
                questionVec.push({
                    content: _.last(element.answers).displayContent,
                    role:"assistant"
                })
            }
        }

        let ext = [{
            type: store.ExtentionType.LikeOrNot,
            question: JSON.stringify(questionVec),
            questionTime:currentTime(),
            answer: "",
            answerTime: currentTime(),
            assistantName: currentAssistant.value.displayname ? currentAssistant.value.displayname : '',
            modelType:currentAccount.value.model ? currentAccount.value.model : '',
            llm:currentAccount.value.displayname ? currentAccount.value.displayname : '',
            likeOrNot: store.LikeOrNot.NONE
        }]
        _.last(_.last(history.value).answers).extention = JSON.stringify(ext)
    }
}

const talkID = ref('')
const waitSend = ref(false)
//修改历史记录结构体
const history = ref([])
const isShowFile = ref(false)
const sendQuestion = async () => {
//*****************************************************************************************************************
    if ((question.value.trim().length === 0 && !isFileInInput.value) || disabled.value) return
    if (currentAssistant.value.type == store.AssistantType.PERSONAL_KNOWLEDGE_ASSISTANT && (!isEmbeddingPluginsExist.value || !isKnowledgeBaseExist.value) && history.value.length === 0) return
    if (currentAssistant.value.type == store.AssistantType.DEEPIN_SYSTEM_ASSISTANT && !isEmbeddingPluginsExist.value && history.value.length === 0) return
    if (currentAssistant.value.type == store.AssistantType.UOS_SYSTEM_ASSISTANT && !isEmbeddingPluginsExist.value && history.value.length === 0) return
    if (isFileInInput.value && !isFileParsingSuccess.value) return  //文件存在但解析失败

    // 录音中点击发送按钮
    if (recording.value) {
        waitSend.value = true
        sigAudioASRError()
        return
    }
    await Qrequest(chatQWeb.stopPlayTextAudio)
    playAudioID.value = ''
    if (recording.value) sigAudioASRError()
//*****************************************************************************************************************

    /**
     * TODO:
     * 1.发送问题：只传question结构体
     * 2.应答：只回复answer结构体
     * 3.维护历史记录结构体
     */


    /**
     * 后期改接口
     */
     if(isFileInInput.value && isFileParsingSuccess.value && question.value.trim().length === 0){
        if (showPromptTag.value ) {
            question.value = ''
        } else if (currentAssistant.value.id === 'PPT Assistant') {
            question.value = '根据文档生成PPT。'
        } else {
            question.value = docParsingPlaceHolder.value
        }
     }
    const { id, model, icon, displayname } = currentAccount.value
    const extention = []
    const ques = {
        displayContent:question.value,
        reqId:"0",
        chatType:0,
        isRetry:false,
        onlineSearch: store.IsSearchOnline,
	    extention:JSON.stringify(extention)
    }
    // ques添加openThink字段
    if (showDeepThinkAndSearchOnline.value) {
        ques.openThink = store.IsDeepThink
    }else{
        ques.openThink = false
    }
    
    //文档存在
    if(isFileInInput.value && isFileParsingSuccess.value){
        isShowFile.value = false
        isFileInInput.value = false
        isFileParsingSuccess.value = false
        extention.push({
            type: store.ExtentionType.DocSummary,
        	docPath: filePath.value,
        	docName:fileNameText.value,
		    iconData:imgBase64.value,
		    docContent:docContent.value
        })
        ques.extention = JSON.stringify(extention)
    }
    //标签存在
    if(showPromptTag.value){
        extention.push({
            type: store.ExtentionType.PromptTag,
            tagType:promptInfo.value.tagType,
            tagName:promptInfo.value.tagName,
            content:promptInfo.value.content,
            description:promptInfo.value.content
        })
        ques.extention = JSON.stringify(extention)
        showPromptTag.value = false
    }
    //标签列表存在
    if (showPropmptList.value) {
        showPropmptList.value = false
    }
    history.value.push({
        question:ques,
        answers:[
            {
                displayContent:"",
                content:"",
                displayHash:"",
                reqId:"0",
                llmIcon: icon ? icon : '',
                llmName: displayname ? displayname : '',
                llmId: currentAccount.value.id ? currentAccount.value.id : '',
                llmModel:model,
                assistantId: currentAssistant.value.id ? currentAssistant.value.id : '',
                assistantName : currentAssistant.value.displayname,
                errCode:0,
                errInfo:{},  //补充json
                chatType:0,  //问答、文生图、FunctionCall
                isRetry:false,
                extention:"[]",
                thinkTime: "-1",
                openThink: store.IsDeepThink,
                onlineSearch: store.IsSearchOnline
            }
        ]
     })

    showStop.value = true
    question.value = ''
    const quesResp = await Qrequest(chatQWeb.sendRequest, id ? id : '', JSON.stringify(ques))
   
    try{
        JSON.parse(quesResp)
    }
    catch(e){
        return
    }

    isFoundThinkStart.value = false
    isFoundThinkStop.value = false
    
    
    _.last(history.value).question = JSON.parse(quesResp)
    _.last(_.last(history.value).answers).reqId = JSON.parse(quesResp).reqId
    
    //初始化like or not
    initLikeOrNotExt()

    talkID.value = JSON.parse(quesResp).reqId

    isMouseScroll.value = false  //初始化滚轮状态
    showReturnBottom.value = false  //初始化返回底部按钮状态
    handelScrol()

    Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))
    
}
const sendEmptyAnswers = async () => {
    const { id, model, icon, displayname } = currentAccount.value
    const extention = []

    const reqId = _.last(_.last(history.value).answers).reqId

    history.value.push({
        // question:ques,
        answers:[
            {
                displayContent:"",
                content:"",
                displayHash:"",
                reqId:"0",
                llmIcon: icon ? icon : '',
                llmName: displayname ? displayname : '',
                llmId: currentAccount.value.id ? currentAccount.value.id : '',
                llmModel: model,
                assistantId: currentAssistant.value.id ? currentAssistant.value.id : '',
                assistantName : currentAssistant.value.displayname,
                errCode:0,
                errInfo:{},  //补充json
                chatType:0,  //问答、文生图、FunctionCall
                isRetry:false,
                extention:"[]",
                thinkTime: "-1",
                openThink: store.IsDeepThink,
                onlineSearch: store.IsSearchOnline
            }
        ]
     })

    showStop.value = true
    question.value = ''
   
    try{
        JSON.parse(quesResp)
    }
    catch(e){
        return
    }
    
    _.last(_.last(history.value).answers).reqId = reqId

    talkID.value = reqId
}
const clearHistory = async () => {
    if (history.value.length === 0 || disabled.value || recording.value) return
    await Qrequest(chatQWeb.clearConversations)
    await Qrequest(chatQWeb.stopPlayTextAudio)
    playAudioID.value = ''
    history.value = []
    handleShowTip(store.loadTranslations['Chat history cleared'])
    // Qrequest(chatQWeb.showToast,1)
    showFile.value = false  //清除后历史记录不显示文件标签在聊天窗口
    // act.value = 1
    store.QuestionAiAction = 1
}

const selectFile = async () => {
    if(disabled.value) return  //回答中
    if(recording.value) return  //录音中
    if(isFileInInput.value) return  //文件存在
    if(currentAssistant.value.type != store.AssistantType.UOS_AI && currentAssistant.value.id != 'PPT Assistant') return  //非UOS AI助手
    await Qrequest(chatQWeb.onDocSummarySelect)

}

const handeleEnter = (event) => {
    if (!event.ctrlKey) {
        // sendQuestion()
    } else {
        event.preventDefault();
        event.stopPropagation();
        document.execCommand('insertText', false, '\n')
    }

}

const handleShowTip = (msg) => {
    showTopTip.value = true
    topTipMsg.value = msg
    setTimeout(() => {
        showTopTip.value = false
    }, 3000)
}

const updateCurAssistant = async (assistant) => {
    console.log("current assistant id changed: ", assistant.id);
    await getNowConversationInfo(assistant.id)
    const _history = await Qrequest(chatQWeb.getConversations)
    history.value = JSON.parse(_history)
    question.value = ''

    //切换助手，聊天窗口存在文件则删除
    if(isFileInInput.value){
        isShowFile.value = false
        isFileInInput.value = false
        isFileParsingSuccess.value = false
        // await Qrequest(chatQWeb.onDocSummaryRemove, documentParsingRef.value.filePath)  //通知后端删除当前的文件
        
        filePath.value = ''
        imgBase64.value = ''
        fileNameText.value = ''
    }

    //切换助手，聊天窗口存在标签则删除
    if (showPromptTag.value) {
        showPromptTag.value = false
        showPropmptList.value = false
    }

    /**
     * TODO:
     * 查询当前助手指令列表
     */
     currentAccountChanged()

     isMouseScroll.value = false  //初始化滚轮状态
     showReturnBottom.value = false  //初始化返回底部按钮状态
     nextTick(() => handelScrol())

}

const isShowPromptBtn = ref(false)
const currentAccountChanged  = async (accent) => {
    /**
     * TODO:
     * 查询当前助手指令列表
     */
     const getInstList_ = await Qrequest(chatQWeb.getInstList)
    try {
        promptInfos.value = JSON.parse(getInstList_)
    } catch (error) {
        isShowPromptBtn.value = false
        showPropmptList.value = false
        showPromptTag.value = false
        return
    }
    
    if (promptInfos.value.length == 0) {
        isShowPromptBtn.value = false
        showPropmptList.value = false
        showPromptTag.value = false
        return
    }
    isShowPromptBtn.value = true

    //当前模型不支持当前指令，清空
    let promptNameLists = []
    promptInfos.value.forEach(element => {
        promptNameLists.push(element.tagName)
    })
    
    if (showPromptTag.value && !promptNameLists.includes(promptTag.value)) {
        showPromptTag.value = false
    }  
}
//*********************************************
//提示词相关
const showPropmptList = ref(false)
const promptListRef=ref()
const searchQuery = ref('')
const showPromptTag = ref(false)
const promptTag = ref("")
const promptInfos = ref([])
const isInputPrompt = ref(false)
const handleInput = async (value) => {
    const selectionStart = questionInput.value.$el.querySelector('textarea').selectionStart
    searchQuery.value = ''
    if (value.startsWith('/') || value.startsWith('、')) {
        /**
         * TODO:
         * 查询当前助手指令列表
         */
        const getInstList_ = await Qrequest(chatQWeb.getInstList)
        try {
            promptInfos.value = JSON.parse(getInstList_)
        } catch (error) {
            return
        }
        
        if (promptInfos.value.length == 0) {
            showPropmptList.value = false;
            return
        }

        showPropmptList.value = true;
        if (value.startsWith('/')) {
            searchQuery.value = value.substr(0,selectionStart).replace('/','')
        }
        if (value.startsWith('、')) {
            searchQuery.value = value.substr(0,selectionStart).replace('、','')
            question.value = question.value.replace('、','/')
            nextTick(() => questionInput.value.$refs.textarea.setSelectionRange(1, 1))  //解决中文状态下修改question导致光标跑到最后的问题
            
        }
        
        promptListRef.value.highlightedIndex = 0 
        // question.value = question.value.replace('/','、')
        isInputPrompt.value = true
    } else {
      showPropmptList.value = false;
      isInputPrompt.value = false;
    }
};

const sigHidePromptLists = async (value) => {
    showPropmptList.value = false
    if (value && !isInputPrompt.value) {  //非手动输入状态关闭列表时删除/
        question.value = question.value.replace('/','')
    }
    isInputPrompt.value = false
}

const promptInfo = ref({})
const sigSelectOnePrompt = async (promptInfo_) => {
    questionInput.value.focus()
    /**
     * TODO:
     * 聊天框中显示指令
     */
     
    promptTag.value = promptInfo_.tagName
    promptInfo.value = promptInfo_
    showPromptTag.value = true
    question.value = question.value.replace('/'+searchQuery.value,'')
}

const highlightPrevious = (event) => {
    if (showPropmptList.value) {
        promptListRef.value.highlightPrevious()
        nextTick(() => event.target.setSelectionRange(1, 1))
    }
};
const highlightNext = (event) => {
    if (showPropmptList.value) {
        promptListRef.value.highlightNext()
        nextTick(() => event.target.setSelectionRange(1, 1))
    }
};

const handleKeyLeft = async (event) => {
    // handleInput(question.value)
};
const handleKeyRight = (event) => {
    // handleInput(question.value)
};

const handleEnterKeyDown = (event) => {
    if (showPropmptList.value) {
        promptListRef.value.handleEnterKeyDown()
        nextTick(() => event.target.setSelectionRange(0, 0))
    }
};

const handleBackspace = (event) => {
    // Backspace键被按下时执行的逻辑
    // start用于判断光标在第一位
    // end用于判断是否为全选，全选时end != 0
    if (showPromptTag.value 
        && questionInput.value.$el.querySelector('textarea').selectionStart == 0 
        && questionInput.value.$el.querySelector('textarea').selectionEnd == 0) {
        showPromptTag.value = false
    }
};

const inputSelectStart = ref(0)
const inputSelectEnd = ref(0)
const handleMouseDown = (event) => {
    //获取鼠标按下时选中的文本范围
    inputSelectStart.value = questionInput.value.$el.querySelector('textarea').selectionStart 
    inputSelectEnd.value = questionInput.value.$el.querySelector('textarea').selectionEnd
}

const handleInputMouseUp = (event) => {
    //获取鼠标按下时选中的文本范围
    //与鼠标按下时选中的文本范围比较，如果范围相同，则取消选中状态，将光标设置到最后
    if (questionInput.value.$el.querySelector('textarea').selectionStart == inputSelectStart.value
        && questionInput.value.$el.querySelector('textarea').selectionEnd == inputSelectEnd.value) {
        nextTick(() => event.target.setSelectionRange(question.value.length, question.value.length))
    }
    event.preventDefault(); // 阻止默认事件
    event.stopPropagation();
}

const handleMouseUp = (event) => {
    questionInput.value.focus()
    event.preventDefault(); // 阻止默认事件
    event.stopPropagation();
};

const handleMainMouseUp = (event) => {
    isFocus.value = false
    if (showPropmptList.value && !isFocus.value) {
        nextTick(() => {
            if (!isInputPrompt.value) {
                sigHidePromptLists(true)
            }else{
                sigHidePromptLists(false)
            }
            
        }) 
    }
};

const handleDragStart = (event) => {
    event.preventDefault();
    event.stopPropagation();
}

const handleInputFocus = (event) => {
    isFocus.value = true  
    if (showPropmptList.value) {
        nextTick(() =>event.target.setSelectionRange(1, 1))
    }
    

    if (isAudioInInpit.value) {  //语音录入的文字
        nextTick(() =>event.target.setSelectionRange(question.value.length, question.value.length))
        isAudioInInpit.value = false
        return
    }
};
const handleInputNoFocus = (event) => {
    // isFocus.value = false
    // if (showPropmptList.value) {
        // nextTick(() => sigHidePromptLists(false))
    // }
};

const selectPrompt = async (event)  => {
    if(disabled.value) return  //回答中
    if(recording.value) return  //录音中

    question.value = "/" + question.value
    // handleInput(question.value)

    /**
     * TODO:
     * 查询当前助手指令列表
     */
     const getInstList_ = await Qrequest(chatQWeb.getInstList)
    try {
        promptInfos.value = JSON.parse(getInstList_)
    } catch (error) {
        showPropmptList.value = false;
        return
    }
    
    if (promptInfos.value.length == 0) {
        showPropmptList.value = false;
        return
    }

    showPropmptList.value = true;
    searchQuery.value = ''
    promptListRef.value.highlightedIndex = 0 
    questionInput.value.focus()

    nextTick(() => {

        if (focus.value) {
            nextTick(() =>event.target.setSelectionRange(1, 1))
        }
    })
};

//输入框暗文
const docParsingPlaceHolder = ref('')
const placeHolder = computed(() => {
    //没有文件或标签
    if (!isFileInInput.value && !showPromptTag.value) {
        if (currentAssistant.value.id === 'PPT Assistant') {
            return '请输入PPT主题或者内容；'
        }
        return store.loadTranslations["Enter your question, or enter \"/\" to select a command\n\"Ctrl+Enter\"  to start a new line"]
    }

    //文件和标签同时存在, 或标签单独存在
    if (showPromptTag.value) {
        return promptInfo.value.content
    }

    //文件存在，标签不存在
    if (isFileInInput.value) {
        if (currentAssistant.value.id === 'PPT Assistant') {
            return '根据文档生成PPT。'
        }
        return docParsingPlaceHolder.value
    }
});

// 点赞踩变化
const updateLikeOrDislike = () => {
    // Qrequest(chatQWeb.logConversations,  JSON.stringify(history.value))
    Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))
};

// 会话记录添加状态控制
const showConversionList = ref(false);
const historyList = ref(null);
const alertMessage = ref('确定要永久删除此聊天记录吗？');
// const currentConversationId = ref(null);
const createNewConversation= async () => {
    if (history.value.length === 0 || disabled.value || recording.value) return
    await Qrequest(chatQWeb.createNewConversation)
    await getNowConversationInfo(currentAssistant.value.id)  //设置当前助手的最后一个会话信息
    //新版查询历史记录
    const _history = await Qrequest(chatQWeb.getConversations)
    history.value = JSON.parse(_history)
}

const openHistoryList =  async () => {
    if(disabled.value) return  //回答中
    if(recording.value) return  //录音中
    showConversionList.value = true;
    const historyList_ = await  Qrequest(chatQWeb.getConversationHistoryList)
    historyList.value = JSON.parse(historyList_)
}

const lastConversationInfo = ref({})
const getNowConversationInfo = async (assistantId) => {
    //更新最后会话信息情况：
    //1. 切换助手
    //2. 新建会话 已做
    //3. 切换会话
    //4. 初始化 已做
    // TODO:重新获取当前助手会话的信息，再根据conversationTitle去判断当前是否为新会话
    const lastConversationInfo_= await Qrequest(chatQWeb.getLastConversation, assistantId)  //拿到当前助手的最后一个会话信息
    lastConversationInfo.value = JSON.parse(lastConversationInfo_)  //解析当前助手的最后一个会话信息
    await Qrequest(chatQWeb.setCurrentConversationId, assistantId, lastConversationInfo.value.conversationId)  //设置当前助手的最后一个会话信息
}

const closeHistoryList = () => {
    showConversionList.value = false
    Qrequest(chatQWeb.setTitleBarMaskStatus, false)  //设置当前助手的最后一个会话信息
}

const selectHistoryItem = async (item) => {        // 新增助手存在性检查
    if (assistantList.value.some(a => a.id === item.assistantId)) {
        //切换助手和模型
        assistantList.value.forEach(element => {
            if (element.id === item.assistantId) {
                element.active = true
                currentAssistant.value.active = false
                currentAssistant.value = element
            }
        });
    }else{
        //当前助手被删除，弹窗提示
        alertMessage.value = store.loadTranslations['The %1 agent used in this conversation has been deleted'] + "_&_" + store.loadTranslations['This conversation cannot be viewed. To view it, please install the %1 agent and try again.'] 
        alertMessage.value = alertMessage.value.replace(/%1/g, item.assistantDisplayName)
        await Qrequest(chatQWeb.showWarningDialog, item.assistantId, item.conversationId, alertMessage.value, false, false)
        return
    }

    //输入框内容清空
    question.value = ''

    //切换助手，聊天窗口存在文件则删除
    if(isFileInInput.value){
        isShowFile.value = false
        isFileInInput.value = false
        isFileParsingSuccess.value = false
        // await Qrequest(chatQWeb.onDocSummaryRemove, documentParsingRef.value.filePath)  //通知后端删除当前的文件
        
        filePath.value = ''
        imgBase64.value = ''
        fileNameText.value = ''
    }

    //切换助手，聊天窗口存在标签则删除
    if (showPromptTag.value) {
        showPromptTag.value = false
        showPropmptList.value = false
    }

    //新版查询历史记录
    await Qrequest(chatQWeb.setCurrentConversationId, item.assistantId, item.conversationId)  //设置当前助手的最后一个会话信息
    const _history = await Qrequest(chatQWeb.getConversations)
    history.value = JSON.parse(_history)
    lastConversationInfo.value = item

    if (accountList.value.some(a => a.id === _.last(_.last(history.value).answers).llmId)) {
        accountList.value.forEach(element => {
            if (element.id === _.last(_.last(history.value).answers).llmId) {
                element.active = true
                currentAccount.value.active = false
                currentAccount.value = element
            }
        });
    }else{
        alertMessage.value = store.loadTranslations['The original conversation model has been deleted. We have switched to a new model for you to continue the conversation.']
        await Qrequest(chatQWeb.showWarningDialog, item.assistantId, item.conversationId, alertMessage.value, false, true)
        // 当前模型被删除时，自动切换第一个可用模型
        if (accountList.value.length > 0) {
            const firstAccount = accountList.value[0]
            firstAccount.active = true
            currentAccount.value.active = false
            currentAccount.value = firstAccount
        }
        return
    }
    Qrequest(chatQWeb.setTitleBarMaskStatus, false)  //设置当前助手的最后一个会话信息
    showConversionList.value = false
    
}

const showAlertDialog = async (item) => {
    alertMessage.value = store.loadTranslations['Are you sure to delete the conversation? It will be unrecoverable once deleted.']
    await Qrequest(chatQWeb.showWarningDialog, item.assistantId, item.conversationId, alertMessage.value, true, false)
}
//*********************************************

// 接受AI文本信息
const thinkStart = ref("<think>\n\n")
const thinkEnd = ref("\n\n</think>\n\n")
const startThinkTime = ref('')
const endThinkTime = ref('')
const isFoundThinkStart = ref(false)  //是否找到think开始标签
const isFoundThinkStop = ref(false)  //是否找到think结束标签
const sigAiReplyStream = (type, value, status) => {
    //新版历史记录维护
    if (status === 0) {
        _.last(_.last(history.value).answers).displayContent = _.last(_.last(history.value).answers).displayContent + value

        //获取开始时间
        if (_.last(_.last(history.value).answers).displayContent.includes(thinkStart.value) && !isFoundThinkStart.value) {
            startThinkTime.value = new Date().getTime()
            isFoundThinkStart.value = true
        }

        //计算思考时间
        if (_.last(_.last(history.value).answers).displayContent.includes(thinkEnd.value) && !isFoundThinkStop.value) {
            endThinkTime.value = new Date().getTime()
            _.last(_.last(history.value).answers).thinkTime = (Math.floor((endThinkTime.value - startThinkTime.value) / 1000)).toString()
            isFoundThinkStop.value = true
        }
    } else if (status === 200) {
        _.last(_.last(history.value).answers).errCode = status

        console.log("isEmbeddingPluginsExist.value: ", isEmbeddingPluginsExist.value);
    } else {
        _.last(_.last(history.value).answers).displayContent = value
        _.last(_.last(history.value).answers).errCode = status
    }

    if (status !== 0) {
        _.last(_.last(history.value).answers).reqId = _.last(history.value).question.reqId
        const { icon, displayname } = currentAccount.value
        _.last(_.last(history.value).answers).llmIcon = icon
        _.last(_.last(history.value).answers).llmName = displayname
        _.last(_.last(history.value).answers).llmId = currentAccount.value.id
        _.last(_.last(history.value).answers).assistantId = currentAssistant.value.id
        _.last(_.last(history.value).answers).assistantName =  currentAssistant.value.displayname,
        _.last(_.last(history.value).answers).errInfo = JSON.stringify(judgeInstallOrConfig(status))


        if(likeOrNotAgent.includes(currentAssistant.value.id)){
            //填充点赞踩结束时间
            let ext = JSON.parse(_.last(_.last(history.value).answers).extention)
            let answer = {
                answer: _.last(_.last(history.value).answers).displayContent,
                reference:""
            }

            for (let index = 0; index < ext.length; index++) {
                const element = ext[index];
                if (element.type == store.ExtentionType.PerView) {
                    answer.reference = element.sources[0].docContents
                }
            }

            let rate = {}
            for (let index = 0; index < ext.length; index++) {
                const element = ext[index];
                if (element.type == store.ExtentionType.LikeOrNot) {
                    ext[index].answer = JSON.stringify(answer)
                    ext[index].answerTime = currentTime()
                    rate = ext[index]
                }
            }

            _.last(_.last(history.value).answers).extention = JSON.stringify(ext)

            //写数据库
            Qrequest(chatQWeb.rateAnwser, history.value.length - 1, _.last(history.value).answers.length - 1, store.LikeOrNot.EMPTY, JSON.stringify(rate))
        }

         //存日志
        //  Qrequest(chatQWeb.logConversations,  JSON.stringify(history.value))
         Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))

         /**
         * TODO
         * 发送完成，需要复制应答的answer
         */

        showStop.value = false
        isRetry.value = false
        isFoundThinkStart.value = false
        isFoundThinkStop.value = false
    }

    handelScrol()
}

//判断当前历史记录为去安装还是去配置
const needConfigErrCodeArr = [-9000, -9001, -9003, -9002, -9004, -9100]
const judgeInstallOrConfig = (errCode) => {
    const errInfo = {
        info:"",
        exec:''
    }
    
    if(!needConfigErrCodeArr.includes(errCode)){
        return errInfo
    }

    //无模型
    if(!isLLMExist.value){
        errInfo.info = store.loadTranslations['Go to configuration']
        errInfo.exec = 'Qrequest(chatQWeb.launchLLMConfigWindow, false)'
        return errInfo
    }

    if(currentAssistant.value.type == store.AssistantType.UOS_SYSTEM_ASSISTANT 
        || currentAssistant.value.type == store.AssistantType.DEEPIN_SYSTEM_ASSISTANT 
        || currentAssistant.value.type == store.AssistantType.PERSONAL_KNOWLEDGE_ASSISTANT){
        if(!isEmbeddingPluginsExist.value){
            errInfo.info = store.loadTranslations['To install']
            errInfo.exec = 'Qrequest(chatQWeb.installEmbeddingPlugins)'
            return errInfo
        }
        if(!isKnowledgeBaseExist.value && currentAssistant.value.type == store.AssistantType.PERSONAL_KNOWLEDGE_ASSISTANT){
            errInfo.info = store.loadTranslations['Go to configuration']
            errInfo.exec = 'Qrequest(chatQWeb.launchKnowledgeBaseConfigWindow)'  //TODO:跳转到具体配置位置
            return errInfo
        }
    }

    errInfo.info = store.loadTranslations['Go to configuration']
    errInfo.exec = 'Qrequest(chatQWeb.launchLLMConfigWindow, false)'
    return errInfo
}

const isMouseScroll = ref(false)  //是否鼠标滚动
const showReturnBottom = ref(false)  //是否显示返回按钮
const handleHistoryScroll = () => {
    setTimeout(() => {
       if (chatHistory.scrollHeight - chatHistory.clientHeight > chatHistory.scrollTop + 50) {
            isMouseScroll.value = true
            showReturnBottom.value = true
        }else {
            isMouseScroll.value = false
            showReturnBottom.value = false
        }
    }, 20)
}

const returnBottom = () => {
    isMouseScroll.value = false
    showReturnBottom.value = false
    handelScrol()
}

const handelScrol = () => {
    if (isMouseScroll.value) {
        return
    }
    
    let chatHistory = document.getElementById('chatHistory')
    if (chatHistory.scrollHeight > chatHistory.clientHeight) {
        setTimeout(() => {
            chatHistory.scrollTop = chatHistory.scrollHeight;
            showReturnBottom.value = false
        }, 0);  
    }else {
        setTimeout(() => {
            showReturnBottom.value = true
        }, 20);  
    }

    handleHistoryScroll()
}

const stopRequest = async () => {
    await Qrequest(chatQWeb.cancelAiRequest, talkID.value)

    if(likeOrNotAgent.includes(currentAssistant.value.id)){
        //填充结束时间
        let ext = JSON.parse(_.last(_.last(history.value).answers).extention)
        for (let index = 0; index < ext.length; index++) {
            const element = ext[index];
            if (element.type == store.ExtentionType.LikeOrNot) {
                ext[index].answerTime = currentTime()
            }
        }
        _.last(_.last(history.value).answers).extention = JSON.stringify(ext)
    }    

    _.last(_.last(history.value).answers).errCode = 298  //请求被取消

    //存日志
    // Qrequest(chatQWeb.logConversations, JSON.stringify(history.value))
    Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))

    showStop.value = false
    isRetry.value = false
    isFoundThinkStart.value = false
    isFoundThinkStop.value = false

    nextTick(() => handelScrol())
}

// 重新生成
const isRetry = ref(false)
const retryRequest = async () => {
    _.last(history.value).question.isRetry = true
    const _question = history.value[history.value.length - 1].question
    await Qrequest(chatQWeb.stopPlayTextAudio)
    playAudioID.value = ''
    if (recording.value) sigAudioASRError()
    const { id, model, icon, displayname } = currentAccount.value
    // ques添加openThink字段
    if (showDeepThinkAndSearchOnline.value) {
        _question.openThink = store.IsDeepThink
    }else{
        _question.openThink = false
    }
    _question.onlineSearch = store.IsSearchOnline
        
    _.last(history.value).answers.push(
        {
            displayContent:"",
            content:"",
            displayHash:"",
            reqId:"0",
            llmIcon: icon ? icon : '',
            llmName: displayname ? displayname : '',
            llmModel: model,
            llmId :  id ? id : '',
            assistantId : currentAssistant.value.id,
            assistantName : currentAssistant.value.displayname,
            errCode:0,
            errInfo:JSON.stringify(judgeInstallOrConfig(0)),  //补充json
            chatType:0,  //问答、文生图、FunctionCall
            isRetry:true,
            extention:"[]",
            thinkTime: "-1",
            openThink: store.IsDeepThink,
            onlineSearch: store.IsSearchOnline
        }
    )

    

    const quesResp = await Qrequest(chatQWeb.sendRequest, id ? id : '', JSON.stringify(_question))
    try{
        JSON.parse(quesResp)
    }catch(e){
        return
    }

    //开始时间
    isFoundThinkStart.value = false
    isFoundThinkStop.value = false

    _.last(history.value).question = JSON.parse(quesResp)
    _.last(_.last(history.value).answers).reqId = JSON.parse(quesResp).reqId

    //初始化like or not
    initLikeOrNotExt()

    talkID.value = JSON.parse(quesResp).reqId
    isRetry.value = true
    showStop.value = true
    // question.value = ''
}

// 是否显示深度思考和联网搜索
const showDeepThinkAndSearchOnline = computed(() => {
    return currentAccount.value.model == store.DeepSeek_Uos_Free
})
// 深度思考
const deepThinkClick = async () => {
    if (store.IsDeepThink) {
        store.IsDeepThink = false
    }else {
        store.IsDeepThink = true
    }
}

// 联网搜索
const searchOnlineClick = async () => {
    if (store.IsSearchOnline) {
        store.IsSearchOnline = false
    }else {
        store.IsSearchOnline = true
    }
}


const recording = ref(false)
const startQus = ref('')
const endQus = ref('')

const handleRecorder = async () => {

    console.log("handleRecorder:clicked: currentAccount.displayname:", currentAccount.value.displayname);
    console.log(recording.value)
    if (!isAudioInput.value || showStop.value || !netState.value) return
    if (currentAssistant.value.type == store.AssistantType.PERSONAL_KNOWLEDGE_ASSISTANT && (!isKnowledgeBaseExist.value || !isEmbeddingPluginsExist.value) && history.value.length === 0) return
    if (currentAssistant.value.type == store.AssistantType.UOS_SYSTEM_ASSISTANT && !isEmbeddingPluginsExist.value && history.value.length === 0) return
    if (currentAssistant.value.type == store.AssistantType.DEEPIN_SYSTEM_ASSISTANT && !isEmbeddingPluginsExist.value && history.value.length === 0) return
    if (recording.value) return sigAudioASRError()
    if (!recording.value) {
        isAudioInput.value = await Qrequest(chatQWeb.isAudioInputAvailable)
        await Qrequest(chatQWeb.stopPlayTextAudio)
        if (isAudioInput.value) {
            await Qrequest(chatQWeb.startRecorder, 0)
            const start = questionInput.value.textarea.selectionStart;
            const end = questionInput.value.textarea.selectionEnd;
            startQus.value = questionInput.value.textarea.value.substr(0, start)
            endQus.value = questionInput.value.textarea.value.substr(end)
            recording.value = true
            playAudioID.value = ''
        }
    }
}

// AI模型列表更新
const llmAccountLstChanged = (id, list) => {
    isLLMExist.value = id.trim().length > 0;
    console.log("index.vue: llmAccountLstChanged.........  id: ", id);
    console.log("index.vue: llmAccountLstChanged.........  list: ", list);
    if (list) {
        const accounts = JSON.parse(list)
        isLLMExist.value = accounts.length > 0;
        accounts.forEach(element => {
            if (element.id === id) {
                element.active = true
                currentAccount.value = element
            }
        });
        accountList.value = list;
    }
    instance.proxy.$Bus.emit("llmAccountLstChanged", { id, list });

    /**
     * TODO:
     * 查询当前助手指令列表
     */
     currentAccountChanged()
}

const questionInput = ref(null)
const isAudioInInpit = ref(false)
const sigAudioASRStream = (res, isEnd) => {
    if (!(isEnd && res == "")) {
        question.value = startQus.value + res + endQus.value
    }
    // console.log('sigAudioASRStream', res, isEnd)
    if (isEnd) {
        if (waitSend.value) {
            waitSend.value = false
            sendQuestion()
        }
        sigAudioASRError()

        //添加指令匹配
        handleInput(question.value)

        isAudioInInpit.value = true

        questionInput.value.focus()
    }
}

const countDown = ref(0)
const showCount = ref(false)
const sigAudioCountDown = (res) => {
    countDown.value = res
    if (res > 0) showCount.value = true
    if (res === 0) {
        setTimeout(() => showCount.value = false, 1000)
    }
}

const sigAudioASRError = () => {
    recording.value = false
    countDown.value = 0
    audioLevel.value = 0
    showCount.value = false
    Qrequest(chatQWeb.stopRecorder)
}
// 语音播放结束
const sigPlayTTSFinished = (res) => {
    console.log('sigPlayTTSFinished', res)
    if (playAudioID.value === res) playAudioID.value = ''
}

const sigPlayTTSError = (res) => playAudioID.value = ''

// const sigAudioRecShortcutPressed = () => handleRecorder()
const sigAudioInputDevChange = (res) => {
    isAudioInput.value = res
    if (!res) recording.value = false
}
const hasOutput = ref(true)
const sigAudioOutputDevChanged = (res) => {
    if (!res) playAudioID.value = ''
    hasOutput.value = res
}

const sigChatConversationType = (id, type) => {
    // console.log(id, action)
    if (_.last(history.value) === undefined)
        return;
    _.last(_.last(history.value).answers).chatType = type
}

// 接受AI图片信息
const sigText2PicFinish = (id, paths) => {
    _.last(_.last(history.value).answers).displayContent = JSON.stringify(paths)

    //存日志
    // Qrequest(chatQWeb.logConversations, JSON.stringify(history.value))
    Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))

    handelScrol()
    showStop.value = false
    isRetry.value = false
}
// 接受PPT图片信息
const sigPPTCreateSuccess = (id, paths) => {
    sendEmptyAnswers()
    _.last(_.last(history.value).answers).displayContent = JSON.stringify(paths)
    _.last(_.last(history.value).answers).chatType = store.ChatAction.ChatText2Image
    let extention = []
    extention.push({
            type: store.ExtentionType.PictureId,
        	idValue: id
        })
    _.last(_.last(history.value).answers).extention = JSON.stringify(extention)

    //存日志
    // Qrequest(chatQWeb.logConversations, JSON.stringify(history.value))
    Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))

    handelScrol()
    showStop.value = false
    isRetry.value = false
}
const sigPPTChangeSuccess = (id, paths) => {
    for (let index = 0; index < history.value.length; index++) {
        for(let answerIndex = 0; answerIndex < history.value.at(index).answers.length; answerIndex++) {
            const ext = JSON.parse(history.value.at(index).answers[answerIndex].extention);
            for(let extIndex = 0; extIndex < ext.length; extIndex++) {
                const element = ext[extIndex];
                if (element.type == store.ExtentionType.PictureId && element.idValue == id) {
                    history.value.at(index).answers[answerIndex].displayContent = JSON.stringify(paths)
                    //存日志
                    // Qrequest(chatQWeb.logConversations, JSON.stringify(history.value))
                    Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))
                    break
                }
            }
        }
    }
}
const sigPosterCreateSuccess = (id, paths) => {
    sendEmptyAnswers()
    _.last(_.last(history.value).answers).displayContent = JSON.stringify(paths)
    _.last(_.last(history.value).answers).chatType = store.ChatAction.ChatText2Image
    let extention = []
    extention.push({
            type: store.ExtentionType.PictureId,
        	idValue: id
        })
    _.last(_.last(history.value).answers).extention = JSON.stringify(extention)

    //存日志
    // Qrequest(chatQWeb.logConversations, JSON.stringify(history.value))
    Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))

    handelScrol()
    showStop.value = false
    isRetry.value = false
}
const welcomePageRef = ref()
const sigWebchat2BeHiden = () => {
    Qrequest(chatQWeb.stopPlayTextAudio)
    playAudioID.value = ''
    welcomePageRef.value.getAiFAQ()
    sigAudioASRError()
}
// 监听AI进程被杀
// const connectStateChanged = (status) => instance.proxy.$Bus.emit("connectStateChanged", status)
// 活动色改变
const sigActiveColorChanged = (res) => updateActivityColor(res)
const audioLevel = ref(0)
const sigAudioSampleLevel = (res) => audioLevel.value = res
const sigThemeChanged = (res) => {
    updateTheme(res)
    //切换深色主题时，文档图标用深色图标
    if(res == 2){
        documentParsingRef.value.isDarkMode = true
        isDarkMode.value = true
    }else{
        documentParsingRef.value.isDarkMode = false
        isDarkMode.value = false
    }
}

const sigFontChanged = (family, pixelSize) => {
    updateFont(family, pixelSize)
    //字号切换时
    documentParsingRef.value.sysFontPixelSize = pixelSize
}
const netState = ref(true)
const sigNetStateChanged = (res) => {
    netState.value = res;
    if (recording.value) {
        recording.value = false;
        Qrequest(chatQWeb.stopRecorder)
    }
}
//ctrl+super+c跳转到数字人
// const chatTopRef = ref()
const sigDigitalModeActive = () => {
    if (router.currentRoute.value.name == "DigitalImage") {

    } else {
        Qrequest(chatQWeb.stopPlayTextAudio)
        router.push("/DigitalImage");
    }
};

const sigChatModeActive = () => {

}

const isModalState = ref(false)
const handleActive = (res) => {
    let maskDom = document.querySelector('#drop-mask');
    if (!maskDom) {
        maskDom = document.createElement("div");
        maskDom.id = "drop-mask"
        document.body.appendChild(maskDom);
    }
    maskDom.style.height = '100vh'
    maskDom.style.width = '100vw'
    maskDom.style.display = res ? 'flex' : 'none'
    isModalState.value = res
}
const switchModel = ref()
const sigWebchatActiveChanged = (res) => {
    if (!res) {
        switchModel.value.showSwitchMenu = false
        switchModel.value.showAssistantMenu = false
        // chatTopRef.value.showSeting = false
    }
    // handleActive(res)
}
const sigWebchatModalityChanged = (res) => handleActive(res)

const sigMainContentBackgroundColor = (color) => {
    updateMainContentBackgroundColor(color);
}

const sigKnowledgeBaseStatusChanged = (status) => {
    console.log("knowledge base status changed: ", status);
    isKnowledgeBaseExist.value = status;
}

const sigEmbeddingPluginsStatusChanged = (status) => {
    console.log("EmbeddingPlugins base status changed: ", status);
    isEmbeddingPluginsExist.value = status;
}

const sigWindowModeChanged = (res) => {
    console.log("onWindowModeChanged, is window mode: ", res);
    isWindowMode.value = res;
}

const sigDocSummaryParsingStart = async (filePath_, iconPath, defaultPrompt, status) => {
    isDragging.value = false;
    if(disabled.value) return  //回答中
    if(recording.value) return  //录音中
    // if(isFileInInput.value) return  //文件存在
    if(currentAssistant.value.type != store.AssistantType.UOS_AI && currentAssistant.value.id != 'PPT Assistant') return  //非UOS AI助手 非PPT助手
    switch (status) {
        case store.DocParsingStatusType.Success:
            break
        case store.DocParsingStatusType.MoreOneError:
            handleShowTip(store.loadTranslations['You can only add a maximum of one file.'])
            return
        case store.DocParsingStatusType.SuffixError:
            handleShowTip(store.loadTranslations['The file format is not supported.'])
            return
        case store.DocParsingStatusType.NoDocError:
            handleShowTip(store.loadTranslations['The file format is not supported.'])
            return
        case store.DocParsingStatusType.ExceedSize:
            handleShowTip(store.loadTranslations['The file size exceeds the 100MB limit.'])
        return
    }
   
    if (!isFileInInput.value) {
        isShowFile.value = true  //drop后显示
        documentParsingRef.value.isEnabledMouthOver = true
        isFileInInput.value = true
        
        filePath.value = filePath_
        //通过正则表达式在完整路径中获取文件名
        // documentParsingRef.value.fileNameText = filePath.substring(filePath.lastIndexOf('/') + 1)  
        fileNameText.value = documentParsingRef.value.handleFileNameLength(filePath_.substring(filePath_.lastIndexOf('/') + 1))
        imgBase64.value = iconPath 
        // question.value = store.loadTranslations['Summarize the key content of the file.'] 

        /**
         * TODO
         * 1.文件拖入就调用后端接口进行解析
         * 2.解析中和解析失败情况下都将发送按钮置灰
         */
        await Qrequest(chatQWeb.onDocSummaryParsing, filePath_)  //开始解析
        documentParsingRef.value.isShowParsingStatus = true
        documentParsingRef.value.isParsingStatusEnd = false
        documentParsingRef.value.parsingStatusText = store.loadTranslations['Parsing...']

        if (defaultPrompt != '') {
            docParsingPlaceHolder.value = defaultPrompt
            nextTick(() => {
                questionInput.value.focus()  //全局搜索带入文档时直接让输入框可编辑
            })
        }else{
            docParsingPlaceHolder.value = store.loadTranslations['Summarize the key content of the file.']
        }
        
    }else{
        handleShowTip(store.loadTranslations['You can only add a maximum of one file.'])
    }
}

const docContent = ref("")
const sigDocSummaryParserResult = (status, fileName, docContent_) => {
    if(isFileInInput.value && !isFileParsingSuccess.value){
        console.log("status : ", status)
        //解析中和解析失败情况下都将发送按钮置灰
        if(status == 0){//解析成功
            documentParsingRef.value.isShowParsingStatus = false
            isFileParsingSuccess.value = true
            docContent.value = docContent_
        }else{
            documentParsingRef.value.isShowParsingStatus = true
            isFileParsingSuccess.value = false
            documentParsingRef.value.isParsingStatusEnd = true
            if(status == 1){//解析失败
                documentParsingRef.value.parsingStatusText = store.loadTranslations['File Error']
            }else{ //未解析出文字
                documentParsingRef.value.parsingStatusText = store.loadTranslations['No text was parsed']
            }
            fileNameText.value = documentParsingRef.value.handleFileNameLength(filePath.value.substring(filePath.value.lastIndexOf('/') + 1))
        }
    }
   
}

const sigOpenFileFromPathResult = (status) => {
    if(!status){
        handleShowTip(store.loadTranslations['File has been deleted.'])
    }
}

const sigAppendWordWizardConv = async () => {
    //打断正在进行的对话
    if(showStop.value){
        await Qrequest(chatQWeb.cancelAiRequest, talkID.value)

        _.last(_.last(history.value).answers).errCode = 298  //请求被取消

        //存日志
        // await Qrequest(chatQWeb.logConversations, JSON.stringify(history.value))
        await Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))

        //打断语音播放
        await Qrequest(chatQWeb.stopPlayTextAudio)

        showStop.value = false
        isRetry.value = false
    }

     

    //通知后端添加划词对话历史记录到UOS AI历史记录
    Qrequest(chatQWeb.appendWordWizardConv)

    //切助手到UOS AI
    assistantList.value.forEach(element => {
        if (element.type === store.AssistantType.UOS_AI) {
            switchModel.value.clickAssistantItem(element)
        }
    });
    
}

const sigPreviewReference = async (preViewList) => {
    let extention = []
    extention = extention.concat(JSON.parse(_.last(_.last(history.value).answers).extention))
    extention.push(JSON.parse(preViewList))
    _.last(_.last(history.value).answers).extention = JSON.stringify(extention)
}

const sigOverrideQues = async (inputQuestion) => {
    if (
        (currentAssistant.value.type === store.AssistantType.PERSONAL_KNOWLEDGE_ASSISTANT && (!isKnowledgeBaseExist.value ||!isEmbeddingPluginsExist.value)&& history.value.length === 0)||
        ((currentAssistant.value.type === store.AssistantType.UOS_SYSTEM_ASSISTANT||currentAssistant.value.type === store.AssistantType.DEEPIN_SYSTEM_ASSISTANT) && !isEmbeddingPluginsExist.value && history.value.length === 0))
        return
    
    question.value = question.value + inputQuestion
    endQus.value =  endQus.value + inputQuestion //如果中断语音输入，可能会延迟返回语音输入信号，需要将随航带过来的值追加
    nextTick(() => {
        questionInput.value.focus()  //随航带入文档时直接让输入框可编辑
    })
}

const sigAsyncWorker = async (type) => {
    if (type === 1) {
        //中断当前对话，切助手
        //打断正在进行的对话
        if(showStop.value){
            await Qrequest(chatQWeb.cancelAiRequest, talkID.value)

            _.last(_.last(history.value).answers).errCode = 298  //请求被取消

            //存日志
            // await Qrequest(chatQWeb.logConversations, JSON.stringify(history.value))
            await Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))


            showStop.value = false
            isRetry.value = false
        }

        //打断语音播报

        //打断正在进行的语音输入
        if (recording.value) {
            recording.value = false;
            Qrequest(chatQWeb.stopRecorder)
        }

        question.value = ''

        //切换助手，聊天窗口存在文件则删除
        if(isFileInInput.value){
            isShowFile.value = false
            isFileInInput.value = false
            isFileParsingSuccess.value = false
            // await Qrequest(chatQWeb.onDocSummaryRemove, documentParsingRef.value.filePath)  //通知后端删除当前的文件
            
            filePath.value = ''
            imgBase64.value = ''
            fileNameText.value = ''
        }

        //切换助手，聊天窗口存在标签则删除
        if (showPromptTag.value) {
            showPromptTag.value = false
            showPropmptList.value = false
        }

        //切换助手为UOS AI
        assistantList.value.forEach(element => {
            if (element.type === store.AssistantType.UOS_AI) {
                Qrequest(chatQWeb.setCurrentAssistantId, element.id)
            }
        });    

        //切助手和模型
        currentAssistant.value.active = false
        const resCurAccountID = await Qrequest(chatQWeb.currentLLMAccountId)
        const resCurAssistantID = await Qrequest(chatQWeb.currentAssistantId)
        assistantList.value.forEach(element => {
            if (element.id === resCurAssistantID) {
                element.active = true
                currentAssistant.value = element
            }
        });
        
        currentAccount.value.active = false
        accountList.value.forEach(element => {
            if (element.id === resCurAccountID) {
                element.active = true
                currentAccount.value = element
            }
        });

        /**
         * TODO:
         * 查询当前助手指令列表
         */
        currentAccountChanged()

        const _history = await Qrequest(chatQWeb.getConversations)
        history.value = JSON.parse(_history)
        await Qrequest(chatQWeb.onAsyncWorkerFinished, type)
      } else if (type === 2) {
             //打断正在进行的语音输入
        if (recording.value) {
            recording.value = false;
            await Qrequest(chatQWeb.stopRecorder)
        }

        await Qrequest(chatQWeb.onAsyncWorkerFinished, type)
      }
}

const sigAssistantListChanged = async () => {
    const resAssistant = await Qrequest(chatQWeb.queryAssistantList)
    const resCurAssistantID = await Qrequest(chatQWeb.currentAssistantId)
    if (resAssistant) {
        const list = JSON.parse(resAssistant);
        //判断当前助手ID是否在列表中
        const isExist = list.some(item => item.id === resCurAssistantID)
        assistantList.value = list;
        if (!isExist) {
            //打断正在进行的语音输入
            if (recording.value) {
                recording.value = false;
                await Qrequest(chatQWeb.stopRecorder)
            }
            //打断正在进行的对话
            if(showStop.value){
                await Qrequest(chatQWeb.cancelAiRequest, talkID.value)

                _.last(_.last(history.value).answers).errCode = 298  //请求被取消

                //存日志
                // await Qrequest(chatQWeb.logConversations, JSON.stringify(history.value))
                await Qrequest(chatQWeb.logCurrentConversations, currentAssistant.value.id, lastConversationInfo.value.conversationId, currentAssistant.value.displayname,  JSON.stringify(history.value))

                //打断语音播放
                await Qrequest(chatQWeb.stopPlayTextAudio)

                showStop.value = false
                isRetry.value = false
            }
            //切助手到UOS AI
            assistantList.value.forEach(element => {
                if (element.type === store.AssistantType.UOS_AI) {
                    switchModel.value.clickAssistantItem(element)
                }
            });
        }else {
            //切助手到当前助手
            assistantList.value.forEach(element => {
                if (element.id === resCurAssistantID) {
                    currentAssistant.value.active = true
                }
            });
        }
    }
}

const sigGetNewHistoryList = async (currentConversationId) => {
    //重新查询历史记录列表
    await openHistoryList()

    // 如果删除的是当前会话，需要重新创建新会话
    if (currentConversationId === lastConversationInfo.value.conversationId) {
        await createNewConversation()
    }
}

const sigHideHistoryList = async () => {
    showConversionList.value = false
}

const sigDeleteFile = async () => {
    isFileInInput.value = false
    isFileParsingSuccess.value = false
    isShowFile.value = false
    // question.value=''
}


// const sigKnowledgeBaseFAQGenFinished = () => {

// }

function handleKeyDown(event) {
    if (event.key === "Enter" && showPropmptList.value) {
        event.stopPropagation()
        event.preventDefault()
        showPropmptList.value = false
        return
    }
    if (event.key === "Enter") {
        event.stopPropagation()
        event.preventDefault()
        console.log('chat ')
        sendQuestion()
    }
}

const responseAIFunObj = {
    sigAiReplyStream,
    llmAccountLstChanged,
    sigActiveColorChanged,
    sigAudioASRStream,
    sigAudioASRError,
    sigAudioCountDown,
    sigPlayTTSFinished,
    sigPlayTTSError,
    // sigAudioRecShortcutPressed,
    sigAudioInputDevChange,
    sigAudioOutputDevChanged,
    sigChatConversationType,
    sigText2PicFinish,
    sigPPTCreateSuccess,
    sigPPTChangeSuccess,
    sigPosterCreateSuccess,
    sigThemeChanged,
    sigFontChanged,
    sigWebchat2BeHiden,
    sigAudioSampleLevel,
    sigNetStateChanged,
    sigDigitalModeActive,
    sigChatModeActive,
    sigWebchatActiveChanged,
    sigWebchatModalityChanged,
    sigMainContentBackgroundColor,
    sigKnowledgeBaseStatusChanged,
    sigEmbeddingPluginsStatusChanged,
    // sigKnowledgeBaseFAQGenFinished,
    sigWindowModeChanged,
    sigDocSummaryParsingStart,  //拖入文档
    sigDocSummaryParserResult,  //文档解析结果
    sigOpenFileFromPathResult,  //文档打开结果
    sigAppendWordWizardConv,  //随航继续对话接口 : 停止当前对话,获取随航历史记录
    sigPreviewReference, //预览列表
    sigAsyncWorker,
    sigOverrideQues,
    sigAssistantListChanged,  //助手列表变化
    sigGetNewHistoryList,
    sigHideHistoryList,
}

const chatHistoryScrollbarRef = ref(null);
onMounted(async () => {
    for (const key in responseAIFunObj) {
        if (Object.hasOwnProperty.call(responseAIFunObj, key)) {
            chatQWeb[key].connect(responseAIFunObj[key]);
        }
    }
    document.addEventListener("keydown", handleKeyDown);
    initChat()

    useGlobalStore().loadTranslations = await Qrequest(chatQWeb.loadTranslations)
    console.log(useGlobalStore().loadTranslations)

    var fontInfo = await Qrequest(chatQWeb.fontInfo);
    var fontInfoList = fontInfo.split('#');
    document.documentElement.style.fontFamily = fontInfoList[0];
    document.documentElement.style.fontSize = fontInfoList[1] + 'px';
    documentParsingRef.value.sysFontPixelSize = fontInfoList[1]  //设置字体大小，计算宽度

    if (chatHistoryScrollbarRef.value) {
        document.getElementById('chatHistory').addEventListener('scroll', handleHistoryScroll);
    }
})
onBeforeUnmount(() => {
    for (const key in responseAIFunObj) {
        if (Object.hasOwnProperty.call(responseAIFunObj, key)) {
            chatQWeb[key].disconnect(responseAIFunObj[key]);
        }
    }
    document.removeEventListener("keydown", handleKeyDown);

    if (chatHistoryScrollbarRef.value) {
        document.getElementById('chatHistory').removeEventListener('scroll', handleHistoryScroll);
    }
})
</script>

<style lang="scss" scoped>
.main-content {
    display: flex;
    flex-direction: column; /* 垂直方向顺序布局 */  
    align-items: center; /* 水平方向居中 */  
    justify-content: center; /* 垂直方向居中 */
    height: 100vh;
    width: 100vw;
    overflow: hidden;
    background-color: var(--main-content-background-color);

    position: relative; /* 为蒙版层定位 */
    // user-select: none;
    img {
        user-select: none;
    }

    .chat-history {
        width: calc(100% - 8px);
        padding: 15px 0;
        max-width: 1020px;
        flex: 1 1 0;
        overflow: hidden;
        // background-color: aquamarine;

        .history-scrollbar {
            overflow-y: overlay;
            overflow-x: hidden;
            height: 100%;

            .bubble-div {
                width: calc(100% - 12px);
                margin-left: 16px;
            }
        }
    }

    .chat-bottom {
        padding: 0;
        margin-top: auto;
        margin-bottom: 10px;
        position: relative;
        max-width: 1000px;
        width: calc(100% - 20px);

        .handle-tip {
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
            top: -50px;

            .tip-item {
                color: var(--uosai-color-tip);
                font-size: 0.93rem;
                font-weight: 500;
                font-style: normal;
                padding: 6px 15px;
                border-radius: 18px;
                border: 1px solid rgba(0, 0, 0, 0.05);
                box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.05);
                background-color: var(--uosai-color-tip-bg);
                margin: 0 auto;
                text-align: center;
                margin-bottom: 10px;
                width: fit-content;
                user-select: none;
            }

            .top-stop {
                color: var(--activityColor);
                background-color: var(--uosai-color-stop-bg);
                border-radius: 8px;
                display: flex;
                align-items: center;

                cursor: pointer;
                box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.08);
                border: none;

                svg {
                    width: 15px;
                    height: 15px;
                    margin-right: 4px;
                }
            }

            
        }

        .top-returnBtnOut {
            position: absolute;
            left: 98%;
            transform: translateX(-50%);
            top: -50px;
            cursor: pointer;

            

            .top-returnBtn {
                display: flex;
                align-items: center;
                justify-content: center;
                transform: translateX(-50%);
                // border: 1px solid rgba(0, 0, 0, 0.05);
                box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.2);
                background-color: var(--uosai-color-tip-bg);
                width: 32px;
                height: 32px;
                border-radius: 50%;

                svg {
                    width: 8px;
                    height: 8px;
                    fill: var(--uosai-color-modelbtn);
                }

                &:not(.disabled):active {

                    svg {
                        fill: var(--activityColor);
                    }
                }
            }
        }


        .top {
            position: relative;
            margin-bottom: 10px;
            padding-left: 5px;
            display: flex;
            align-items: center;

            .clear {
                width: 36px;
                height: 36px;
                background-color: var(--uosai-color-clear-bg);
                border-radius: 8px;
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                // margin-right: auto;
                margin-right: 6px;

                &:not(.disabled):hover {
                    background-color: var(--uosai-color-clear-hover-bg);

                    svg {
                        fill: var(--uosai-color-clear-hover);
                    }
                }

                &:not(.disabled):active {
                    background-color: var(--uosai-color-clear-press-bg);

                    svg {
                        fill: var(--activityColor);
                    }
                }

                svg {
                    height: 20px;
                    width: 20px;
                    fill: var(--uosai-color-clear);
                }
            }

            .add-new-conversation {
                width: 36px;
                height: 36px;
                background-color: var(--activityAddNewConversationBtnBgNormal);
                border-radius: 8px;
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                // margin-right: auto;
                margin-right: 6px;

                &:not(.disabled):hover {
                    background-color: var(--activityAddNewConversationBtnBgHover);

                    svg {
                        // fill: var(--uosai-color-clear-hover);
                    }
                }

                &:not(.disabled):active {
                    background-color: var(--activityAddNewConversationBtnBgActive);

                    svg {
                        // fill: var(--activityColor);
                    }
                }

                svg {
                    height: 20px;
                    width: 20px;
                    // fill: var(--uosai-color-clear);
                }
            }

            .prompt-btn{
                width: 36px;
                height: 36px;
                background-color: var(--uosai-color-clear-bg);
                border-radius: 8px;
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                margin-right: 10px;

                &:not(.disabled):hover {
                    background-color: var(--uosai-color-clear-hover-bg);

                    svg {
                        fill: var(--uosai-color-clear-hover);
                    }
                }

                &:not(.disabled):active {
                    background-color: var(--uosai-color-clear-press-bg);

                    svg {
                        fill: var(--activityColor);
                    }
                }

                svg {
                    height: 20px;
                    width: 20px;
                    fill: var(--uosai-color-clear);
                }
            }
        }

        .input-content {
            min-height: 120px;
            border-radius: 8px;
            // opacity: 1;
            // background-color: var(--uosai-color-inputcontent-bg);
            margin-bottom: 7px;
            // padding-bottom: 8px;
            border: 2px solid rgba(0, 0, 0, 0);

            .input-content-all{
                background-color: var(--uosai-color-inputcontent-bg);
                opacity: 1;
                // margin-bottom: 7px;
                padding-bottom: 8px; 
                border-radius: 8px;
                overflow: hidden;
                // border: 2px solid rgba(0, 0, 0, 0);

                .input-tag{
                    display: block;
                    align-content: center;
                }
            }

            // user-select:auto;
            &.foucs {
                border: 2px solid var(--activityColor);
            }

            :deep(.el-textarea) {
                padding-top: 10px;
                max-height: 185px;
                display: flex;

                .el-textarea__inner {
                    box-shadow: none;
                    background: none;
                    color: var(--uosai-color-inputcontent);
                    max-height: 185px;
                    font-size: 0.93rem;  // 会影响高度 

                    &::placeholder {
                        color: var(--uosai-color-inputcontent-placeholder);
                        font-size: 0.93rem;
                        font-weight: 500;
                        user-select: none;
                    }

                    &::-webkit-scrollbar {
                        background: none;
                        width: 6px;
                        height: 6px;

                        &:hover {
                            width: 8px;
                            height: 8px;
                        }
                    }

                    &::-webkit-scrollbar-thumb {
                        border-radius: 4px;
                        background: var(--uosai-color-scroll-bg);
                        border: 1px solid var(--uosai-color-border);
                        // box-shadow: 0px 0px 10px 0px var(--uosai-color-border);
                    }

                    &:focus {
                        outline: 0;
                        box-shadow: none;
                    }
                }
            }

            .bottom {
                display: flex;
                justify-content: space-between;
                align-items: center;
            }

            .deep-think-btn {
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                width: 88px;
                height: 30px;
                border-radius: 8px;
                // border: 1px solid rgba(0, 0, 0, 0.05);
                margin-top: 6px;
                background-color: var(--uosai-think-search-normal-bg);
                user-select: none;
                color: var(--uosai-think-search-color);
                font-size: 12px;

                svg {
                    width: 16px;
                    height: 16px;
                    margin-right: 5px;
                    fill: var(--uosai-color-clear);
                }

                // &:not(.disabled):hover {
                //     background-color: var(--uosai-color-clear-hover-bg);

                //     svg {
                //         fill: var(--uosai-color-clear-hover);
                //     }
                // }

                // &:not(.disabled):active {
                //     background-color: var(--uosai-color-clear-press-bg);

                //     svg {
                //         fill: var(--activityColor);
                //     }
                // }

            }

            .send-btn {
                height: 30px;
                display: flex;
                justify-content: flex-end;
                margin-top: 6px;
                // background-color: violet;

                .btn {
                    // box-shadow: 0px 4px 6px rgba(44, 167, 248, 0.4);
                    background-color: var(--activityColor);
                    width: 30px;
                    height: 30px;
                    border-radius: 50%;
                    margin-right: 8px;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    cursor: pointer;

                    &.send {
                        box-shadow: 0 4px 6px 0 var(--boxShadow);

                        svg {
                            fill: #fff;
                        }
                    }

                    svg {
                        width: 16px;
                        height: 16px;
                    }

                    &.disabled {
                        opacity: 0.4;
                        cursor: not-allowed;
                    }

                    &.send:not(.disabled):hover {
                        filter: brightness(1.2);
                    }

                    &.send:not(.disabled):active {
                        filter: brightness(1.1);

                        svg {
                            fill: rgba(255, 255, 255, 0.6);
                        }
                    }

                }

                .voice-btn {
                    background-color: var(--uosai-color-voicebtn-bg);
                    margin-right: 15px;

                    &:not(.disabled):hover {
                        background-color: var(--uosai-color-voicebtn-bg-hover);
                    }

                    &:not(.disabled):active {
                        background-color: var(--uosai-color-voicebtn-bg-active);

                        svg {
                            opacity: 0.6;
                        }
                    }

                    svg {
                        width: 12px;
                        height: 17px;
                        fill: var(--activityColor);
                    }

                    &.recording::before {
                        content: '';
                        position: absolute;
                        opacity: 0.4;
                        border-radius: 50%;
                    }

                    &.recording::after {
                        content: '';
                        position: absolute;
                        opacity: 0.1;
                        border-radius: 50%;

                    }

                    @keyframes Wave1 {
                        0% {
                            border: 2px solid var(--activityColor);
                            width: 30px;
                            height: 30px;
                        }

                        100% {
                            border: 6px solid var(--activityColor);
                            width: 30px;
                            height: 30px;
                        }
                    }

                    @keyframes Wave2 {
                        0% {
                            border: 3px solid var(--activityColor);
                            width: 34px;
                            height: 34px;
                        }

                        100% {
                            border: 5px solid var(--activityColor);
                            width: 40px;
                            height: 40px;

                        }
                    }

                    &:not(.notalking).recording::before {
                        animation: Wave1 0.4s ease-in-out infinite;
                        animation-direction: alternate-reverse;

                    }

                    &:not(.notalking).recording::after {
                        animation: Wave2 0.4s ease-in-out infinite;
                        animation-direction: alternate-reverse;
                    }

                    @keyframes notalking1 {
                        0% {
                            border: 1px solid var(--activityColor);
                            width: 30px;
                            height: 30px;
                        }

                        100% {
                            border: 3px solid var(--activityColor);
                            width: 30px;
                            height: 30px;
                        }
                    }

                    @keyframes notalking2 {
                        0% {
                            border: 3px solid var(--activityColor);
                            width: 32px;
                            height: 32px;
                        }

                        100% {
                            border: 4px solid var(--activityColor);
                            width: 36px;
                            height: 36px;

                        }
                    }

                    &.notalking::before {
                        animation: notalking1 0.8s ease-in-out infinite;
                        animation-direction: alternate-reverse;

                    }

                    &.notalking::after {
                        animation: notalking2 0.8s ease-in-out infinite;
                        animation-direction: alternate-reverse;
                    }
                }

                .file-btn{
                    background-color: var(--uosai-color-voicebtn-bg);
                    margin-right: 15px;

                    &:not(.disabled):hover {
                        background-color: var(--uosai-color-voicebtn-bg-hover);

                        svg {
                            fill: var(--uosai-color-clear-hover);
                        }
                    }

                    &:not(.disabled):active {
                        background-color: var(--uosai-color-voicebtn-bg-active);

                        svg {
                            fill: var(--activityColor);
                        }
                    }

                    svg {
                        height: 20px;
                        width: 20px;
                        fill: var(--uosai-color-clear);
                    }
                }
            }
        }

        .tip {
            color: var(--uosai-bottom-tip-color);
            font-size: 12px;
            font-weight: 500;
            font-style: normal;
            text-align: left;
            padding-left: 10px;
            user-select: none;
        }
    }

    .inner-dropzone {
        /* 确保子div可以接收拖拽事件 */
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: linear-gradient(rgba(255, 255, 255, 0) 5%,
                                    rgba(255, 255, 255, 0.35) 10%,
                                    rgba(255, 255, 255, 0.65) 15%,
                                    rgba(255, 255, 255, 0.75) 23%,
                                    rgba(255, 255, 255, 0.85) 30%, 
                                    rgba(255, 255, 255, 0.95) 42%, 
                                    rgba(255, 255, 255, 0.95) 100%); /* 半透明渐变蒙版 */
        z-index: 9999; /* 确保蒙版在内容之上 */
        align-items: center; /* 水平方向居中 */  
        justify-content: center; /* 垂直方向居中 */
        display: grid;

        .inner-dropzone-content{
            width: 230px;
            // height: 186px;
            display: flex;
            // place-items: center;
            align-items: center; /* 水平方向居中 */  
            justify-content: center; /* 垂直方向居中 */
            z-index: 1; 
            // border: 1px solid black;
            pointer-events: none; /* 使层不响应鼠标事件 ,防止蒙版闪烁*/
            flex-direction: column; /* 子元素垂直排列 */
            margin-top: -40%;

            .inner-dropzone-icon{
                display: grid;
                // width: 94px;
                // height: 106px;
                width: 150px;
                height: 150px;
                display: flex;
                align-items: center; /* 水平方向居中 */  
                justify-content: center; /* 垂直方向居中 */
                // border: 1px solid black;
                z-index: 1; 

                .inner-dropzone-icon-icon{
                    // width: 94px;
                    // height: 106px;
                    width: 150px;
                    height: 150px;
                }
            }

            .inner-dropzone-text{
                // width: 187px;
                // height: 25px;
                height: auto; /* 让容器根据内容自动调整高度 */
                display: flex;
                font-size: 1.21rem;
                font-weight: 500;
                font-style: normal;
                font-family: var(--font-family);
                color:rgba(0, 0, 0, 0.9);
                align-items: center; /* 水平方向居中 */  
                justify-content: center; /* 垂直方向居中 */
                margin-top: none;

                z-index: 1; 
                white-space: nowrap; /* 不换行 */
                // border: 1px solid red;
            }

            .inner-dropzone-text-suffix{
                // width: 230px;
                height: auto;
                display: flex;
                font-size: 0.85rem;
                font-weight: 500;
                font-style: normal;
                font-family: var(--font-family);
                font-weight: 500;
                color:rgba(0, 0, 0, 0.6);
                align-items: center; /* 水平方向居中 */  
                justify-content: center; /* 垂直方向居中 */
                text-align: center;
                margin-top: 8px;
                // border: 1px solid blue;
                z-index: 1; 
            }
        }

    }

    .conversion-list-wrapper {
        position: absolute;
        // top: 60px;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 1000;
    }
}


.dark {
    .top-stop {
        box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15) !important;
    }

    .inner-dropzone{
        background: linear-gradient(rgba(33, 33, 33, 0) 5%,
                                    rgba(33, 33, 33, 0.35) 10%,
                                    rgba(33, 33, 33, 0.65) 15%,
                                    rgba(33, 33, 33, 0.75) 23%,
                                    rgba(33, 33, 33, 0.85) 30%, 
                                    rgba(33, 33, 33, 0.95) 42%, 
                                    rgba(33, 33, 33, 0.95) 100%); /* 半透明渐变蒙版 */
        // background: linear-gradient(rgba(33, 33, 33, 0) 0%, rgba(33, 33, 33, 0.1) 5%,rgba(33, 33, 33, 0.85) 21%, rgba(33, 33, 33, 0.95) 42%, rgba(33, 33, 33, 0.95) 100%); /* 半透明渐变蒙版 */
    }

    .inner-dropzone-text-span{
        color: rgba(255, 255, 255, 0.9);
    }

    .inner-dropzone-text-suffix-span{
        color: rgba(255, 255, 255, 0.6);
    }
}
</style>
