wujingjing
2024-11-08 a791a033d892fb08f5acdcba915b98a863866e99
分享对话为空的情况
已修改2个文件
426 ■■■■ 文件已修改
src/components/chat/Chat.vue 424 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/hooks/useScrollLoad.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/Chat.vue
@@ -7,226 +7,242 @@
                    v-loading="moreIsLoading"
                ></span>
                <div class="h-full relative" v-loading="chatListLoading" :style="{ width: chatWidth }">
                    <div
                        class="flex px-4 py-6 rounded-lg relative"
                        :class="{ 'flex-row-reverse': item.role === RoleEnum.user, 'px-10': isShareCheck }"
                        v-for="(item, msgIndex) of computedMessageList"
                        :key="`${item.historyId}_${item.role}`"
                    >
                        <div class="absolute top-0 left-[72px] text-[#8d8e99]">{{ item?.createTime }}</div>
                        <!-- :class="{ 'top-[30px]': item.role === RoleEnum.user, 'top-[30px]': item.role === RoleEnum.assistant }" -->
                    <template v-if="computedMessageList?.length > 0">
                        <div
                            class="flex px-4 py-6 rounded-lg relative"
                            :class="{ 'flex-row-reverse': item.role === RoleEnum.user, 'px-10': isShareCheck }"
                            v-for="(item, msgIndex) of computedMessageList"
                            :key="`${item.historyId}_${item.role}`"
                        >
                            <div class="absolute top-0 left-[72px] text-[#8d8e99]">{{ item?.createTime }}</div>
                            <!-- :class="{ 'top-[30px]': item.role === RoleEnum.user, 'top-[30px]': item.role === RoleEnum.assistant }" -->
                        <el-checkbox
                            v-if="isShareCheck"
                            class="absolute left-0 top-[28px]"
                            size="large"
                            v-model="item.isChecked"
                            @change="(isChecked) => shareCheckChange(isChecked as boolean, item)"
                        ></el-checkbox>
                        <img
                            class="rounded-full size-12 flex-0"
                            :class="{ 'mr-4': item.role === RoleEnum.assistant, 'ml-4': item.role === RoleEnum.user }"
                            :src="roleImageMap[item.role]"
                            alt=""
                            srcset=""
                        />
                        <div class="flex-auto flex" :class="{ 'justify-end': item.role === RoleEnum.user }">
                            <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }">
                                <div class="w-full">
                                    <div
                                        class="text-sm rounded-[6px] p-4 leading-relaxed"
                                        :style="{ backgroundColor: item.role === RoleEnum.user ? 'rgb(197 224 255)' : 'white' }"
                                        :class="{ group: item.role === RoleEnum.user }"
                                    >
                                        <div class="flex flex-col" v-if="item?.stepList?.length > 0">
                                            <div class="flex items-center mb-3">
                                                <span class="mr-2">意图分析:</span>
                                                <div
                                                    @click="toggleStepList(item)"
                                                    class="cursor-pointer border border-gray-300 border-solid w-fit px-2 flex items-center space-x-2 rounded-lg hover:bg-gray-100 active:bg-gray-200"
                                                >
                                                    <span>
                                                        {{ toggleStepLabel(item) }}
                                                    </span>
                                                    <span class="ywifont" :class="{ 'ywicon-unfold': !item.stepIsShow, 'ywicon-fold': item.stepIsShow }"></span>
                            <el-checkbox
                                v-if="isShareCheck"
                                class="absolute left-0 top-[28px]"
                                size="large"
                                v-model="item.isChecked"
                                @change="(isChecked) => shareCheckChange(isChecked as boolean, item)"
                            ></el-checkbox>
                            <img
                                class="rounded-full size-12 flex-0"
                                :class="{ 'mr-4': item.role === RoleEnum.assistant, 'ml-4': item.role === RoleEnum.user }"
                                :src="roleImageMap[item.role]"
                                alt=""
                                srcset=""
                            />
                            <div class="flex-auto flex" :class="{ 'justify-end': item.role === RoleEnum.user }">
                                <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }">
                                    <div class="w-full">
                                        <div
                                            class="text-sm rounded-[6px] p-4 leading-relaxed"
                                            :style="{ backgroundColor: item.role === RoleEnum.user ? 'rgb(197 224 255)' : 'white' }"
                                            :class="{ group: item.role === RoleEnum.user }"
                                        >
                                            <div class="flex flex-col" v-if="item?.stepList?.length > 0">
                                                <div class="flex items-center mb-3">
                                                    <span class="mr-2">意图分析:</span>
                                                    <div
                                                        @click="toggleStepList(item)"
                                                        class="cursor-pointer border border-gray-300 border-solid w-fit px-2 flex items-center space-x-2 rounded-lg hover:bg-gray-100 active:bg-gray-200"
                                                    >
                                                        <span>
                                                            {{ toggleStepLabel(item) }}
                                                        </span>
                                                        <span
                                                            class="ywifont"
                                                            :class="{ 'ywicon-unfold': !item.stepIsShow, 'ywicon-fold': item.stepIsShow }"
                                                        ></span>
                                                    </div>
                                                </div>
                                                <!-- 过程输出 -->
                                                <el-steps v-show="item.stepIsShow" direction="vertical" :active="activeStep">
                                                    <el-step
                                                        v-for="(subItem, index) in item.stepList"
                                                        :title="subItem.title"
                                                        :status="stepEnumMap[subItem.status]"
                                                    >
                                                        <template
                                                            #icon
                                                            v-if="index + 1 === item.stepList.length && isTalking && msgIndex === computedMessageList.length - 1"
                                                        >
                                                            <span class="ywifont ywicon-loading1 animate-spin !text-[24px]"></span>
                                                        </template>
                                                        <template #title>
                                                            <span class="text-sm"
                                                                >{{ subItem.title
                                                                }}<span v-if="subItem.ms" class="text-green-600">{{ `(${subItem.ms})` }}</span></span
                                                            >
                                                        </template>
                                                    </el-step>
                                                </el-steps>
                                            </div>
                                            <!-- 过程输出 -->
                                            <el-steps v-show="item.stepIsShow" direction="vertical" :active="activeStep">
                                                <el-step
                                                    v-for="(subItem, index) in item.stepList"
                                                    :title="subItem.title"
                                                    :status="stepEnumMap[subItem.status]"
                                            <div
                                                v-if="item.role === RoleEnum.user && item.content?.values && !isSharePage && !isShareCheck"
                                                class="absolute flex items-center bottom-0 group invisible"
                                            >
                                                <div
                                                    class="bg-[#fff] flex items-center mr-4 space-x-2 flex-nowrap rounded-[6px] py-2 px-2 group-hover:visible"
                                                >
                                                    <template
                                                        #icon
                                                        v-if="index + 1 === item.stepList.length && isTalking && msgIndex === computedMessageList.length - 1"
                                                    <el-tooltip effect="dark" content="复制" placement="top">
                                                        <div class="flex items-center justify-center size-[20px]">
                                                            <i
                                                                class="p-2 ywifont ywicon-copy cursor-pointer hover:text-[#0284ff] font-medium !text-[15px] hover:!text-[18px]"
                                                                @click="copyUserClick(item)"
                                                            />
                                                        </div>
                                                    </el-tooltip>
                                                    <el-tooltip effect="dark" content="设为常用语" placement="top">
                                                        <div class="flex items-center justify-center size-[20px]">
                                                            <i
                                                                class="p-2 ywifont ywicon-cubelifangti cursor-pointer hover:text-[#0284ff] text-[#000] font-[590] !text-[15px] hover:!text-[18px]"
                                                                @click="setCommonQuestionClick(item)"
                                                            />
                                                        </div>
                                                    </el-tooltip>
                                                    <el-tooltip effect="dark" content="分享" placement="top">
                                                        <div class="flex items-center justify-center size-[15px]">
                                                            <i
                                                                :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }"
                                                                class="p-2 ywifont ywicon-fenxiang cursor-pointer hover:text-[#0284ff] !text-[15px] hover:!text-[18px]"
                                                                @click="shareClick(item)"
                                                            />
                                                        </div>
                                                    </el-tooltip>
                                                </div>
                                            </div>
                                            <template v-if="item.content?.values">
                                                <div v-if="item.content.errCode === ErrorCode.Message" class="flex-column w-full">
                                                    <p class="text-red-500">
                                                        {{ item.content.errMsg }}
                                                    </p>
                                                    <div class="mt-5 flex items-center" v-if="showFixQuestion(item)">
                                                        <div class="text-gray-600 flex-0">
                                                            {{ item.content.origin.err_json.fix_question.title + ':' }}
                                                        </div>
                                                        <div class="ml-1 space-x-2 inline-flex flex-wrap">
                                                            <div
                                                                v-for="fixItem in item.content.origin.err_json.fix_question?.values"
                                                                :key="fixItem"
                                                                class="bg-gray-200 p-3 hover:bg-[#c5e0ff] hover:text-[#1c86ff] cursor-pointer rounded-lg"
                                                                @click="fixQuestionClick(fixItem, item.content.origin)"
                                                            >
                                                                {{ fixItem.title }}
                                                            </div>
                                                        </div>
                                                    </div>
                                                </div>
                                                <template v-else>
                                                    <component
                                                        :conclusion="item.conclusion"
                                                        :is="answerTypeMapCom[item.content.type]"
                                                        :data="item.content.values"
                                                        :originData="item"
                                                        :isTalking="isTalking && msgIndex === computedMessageList.length - 1"
                                                    />
                                                    <div
                                                        v-if="item.role === RoleEnum.assistant && item.content.origin?.ext_call_list"
                                                        class="flex font-bold items-center mt-6"
                                                    >
                                                        <span class="ywifont ywicon-loading1 animate-spin !text-[24px]"></span>
                                                    </template>
                                                    <template #title>
                                                        <span class="text-sm"
                                                            >{{ subItem.title }}<span v-if="subItem.ms" class="text-green-600">{{ `(${subItem.ms})` }}</span></span
                                                        >
                                                    </template>
                                                </el-step>
                                            </el-steps>
                                                        <div class="flex-0 mb-auto -mr-4">关联功能:</div>
                                                        <div class="space-x-5 flex flex-wrap">
                                                            <div
                                                                v-for="callItem in item.content.origin?.ext_call_list"
                                                                :key="callItem.call_ext_id"
                                                                @click="relativeQueryClick(callItem)"
                                                                class="cursor-pointer hover:underline first-of-type:ml-5"
                                                            >
                                                                {{ callItem.question }}
                                                            </div>
                                                        </div>
                                                    </div>
                                                </template>
                                            </template>
                                        </div>
                                        <div
                                            v-if="item.role === RoleEnum.user && item.content?.values && !isSharePage && !isShareCheck"
                                            class="absolute flex items-center bottom-0 group invisible"
                                            v-if="item.role === RoleEnum.assistant && item.content?.values && !isSharePage && !isShareCheck"
                                            class="absolute flex items-center right-0 mr-4 mt-2 space-x-2"
                                        >
                                            <div class="bg-[#fff] flex items-center mr-4 space-x-2 flex-nowrap rounded-[6px] py-2 px-2 group-hover:visible">
                                                <el-tooltip effect="dark" content="复制" placement="top">
                                                    <div class="flex items-center justify-center size-[20px]">
                                            <div
                                                class="flex items-center justify-center size-[15px]"
                                                v-if="item.content?.type === AnswerType.Text || item.content?.type === AnswerType.Knowledge"
                                            >
                                                <i
                                                    class="p-2 ywifont ywicon-copy cursor-pointer hover:text-[#0284ff] hover:!text-[18px]"
                                                    @click="copyClick(item)"
                                                />
                                            </div>
                                            <template v-if="item.content.errCode !== ErrorCode.Message">
                                                <el-tooltip effect="dark" content="点赞" placement="top">
                                                    <div class="flex items-center justify-center size-[15px]">
                                                        <i
                                                            class="p-2 ywifont ywicon-copy cursor-pointer hover:text-[#0284ff] font-medium !text-[15px] hover:!text-[18px]"
                                                            @click="copyUserClick(item)"
                                                            :class="{ 'text-[#0284ff]': item.state === AnswerState.Like }"
                                                            class="p-2 ywifont ywicon-dianzan cursor-pointer hover:text-[#0284ff] font-medium hover:!text-[18px]"
                                                            @click="likeClick(item)"
                                                        />
                                                    </div>
                                                </el-tooltip>
                                                <el-tooltip effect="dark" content="设为常用语" placement="top">
                                                    <div class="flex items-center justify-center size-[20px]">
                                                        <i
                                                            class="p-2 ywifont ywicon-cubelifangti cursor-pointer hover:text-[#0284ff] text-[#000] font-[590] !text-[15px] hover:!text-[18px]"
                                                            @click="setCommonQuestionClick(item)"
                                                        />
                                                    </div>
                                                </el-tooltip>
                                                <el-tooltip effect="dark" content="分享" placement="top">
                                                <el-tooltip effect="dark" content="点踩" placement="top">
                                                    <div class="flex items-center justify-center size-[15px]">
                                                        <i
                                                            :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }"
                                                            class="p-2 ywifont ywicon-fenxiang cursor-pointer hover:text-[#0284ff] !text-[15px] hover:!text-[18px]"
                                                            @click="shareClick(item)"
                                                            class="p-2 ywifont ywicon-buzan cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]"
                                                            @click="unLikeClick(item)"
                                                        />
                                                    </div>
                                                </el-tooltip>
                                            </div>
                                        </div>
                                        <template v-if="item.content?.values">
                                            <div v-if="item.content.errCode === ErrorCode.Message" class="flex-column w-full">
                                                <p class="text-red-500">
                                                    {{ item.content.errMsg }}
                                                </p>
                                                <div class="mt-5 flex items-center" v-if="showFixQuestion(item)">
                                                    <div class="text-gray-600 flex-0">
                                                        {{ item.content.origin.err_json.fix_question.title + ':' }}
                                                    </div>
                                                    <div class="ml-1 space-x-2 inline-flex flex-wrap">
                                                        <div
                                                            v-for="fixItem in item.content.origin.err_json.fix_question?.values"
                                                            :key="fixItem"
                                                            class="bg-gray-200 p-3 hover:bg-[#c5e0ff] hover:text-[#1c86ff] cursor-pointer rounded-lg"
                                                            @click="fixQuestionClick(fixItem, item.content.origin)"
                                                        >
                                                            {{ fixItem.title }}
                                                        </div>
                                                    </div>
                                                </div>
                                            </div>
                                            <template v-else>
                                                <component
                                                    :conclusion="item.conclusion"
                                                    :is="answerTypeMapCom[item.content.type]"
                                                    :data="item.content.values"
                                                    :originData="item"
                                                    :isTalking="isTalking && msgIndex === computedMessageList.length - 1"
                                                />
                                                <div
                                                    v-if="item.role === RoleEnum.assistant && item.content.origin?.ext_call_list"
                                                    class="flex font-bold items-center mt-6"
                                                >
                                                    <div class="flex-0 mb-auto -mr-4">关联功能:</div>
                                                    <div class="space-x-5 flex flex-wrap">
                                                        <div
                                                            v-for="callItem in item.content.origin?.ext_call_list"
                                                            :key="callItem.call_ext_id"
                                                            @click="relativeQueryClick(callItem)"
                                                            class="cursor-pointer hover:underline first-of-type:ml-5"
                                                        >
                                                            {{ callItem.question }}
                                                        </div>
                                                    </div>
                                                </div>
                                            </template>
                                        </template>
                                    </div>
                                    <div
                                        v-if="item.role === RoleEnum.assistant && item.content?.values && !isSharePage && !isShareCheck"
                                        class="absolute flex items-center right-0 mr-4 mt-2 space-x-2"
                                    >
                                        <div
                                            class="flex items-center justify-center size-[15px]"
                                            v-if="item.content?.type === AnswerType.Text || item.content?.type === AnswerType.Knowledge"
                                        >
                                            <i
                                                class="p-2 ywifont ywicon-copy cursor-pointer hover:text-[#0284ff] hover:!text-[18px]"
                                                @click="copyClick(item)"
                                            />
                                        </div>
                                        <template v-if="item.content.errCode !== ErrorCode.Message">
                                            <el-tooltip effect="dark" content="点赞" placement="top">
                                                <div class="flex items-center justify-center size-[15px]">
                                                    <i
                                                        :class="{ 'text-[#0284ff]': item.state === AnswerState.Like }"
                                                        class="p-2 ywifont ywicon-dianzan cursor-pointer hover:text-[#0284ff] font-medium hover:!text-[18px]"
                                                        @click="likeClick(item)"
                                                    />
                                                </div>
                                            </el-tooltip>
                                            <el-tooltip effect="dark" content="点踩" placement="top">
                                            <el-tooltip effect="dark" content="分享" placement="top">
                                                <div class="flex items-center justify-center size-[15px]">
                                                    <i
                                                        :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }"
                                                        class="p-2 ywifont ywicon-buzan cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]"
                                                        @click="unLikeClick(item)"
                                                        class="p-2 ywifont ywicon-fenxiang cursor-pointer hover:text-[#0284ff] !text-[15px] hover:!text-[18px]"
                                                        @click="shareClick(item)"
                                                    />
                                                </div>
                                            </el-tooltip>
                                        </template>
                                        <el-tooltip effect="dark" content="分享" placement="top">
                                            <div class="flex items-center justify-center size-[15px]">
                                                <i
                                                    :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }"
                                                    class="p-2 ywifont ywicon-fenxiang cursor-pointer hover:text-[#0284ff] !text-[15px] hover:!text-[18px]"
                                                    @click="shareClick(item)"
                                                />
                                            </div>
                                        </el-tooltip>
                                        <el-tooltip effect="dark" content="反馈" placement="top">
                                            <div class="flex items-center justify-center size-[15px] relative">
                                                <i
                                                    class="p-2 ywifont ywicon-wentifankui cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]"
                                                    @click="
                                                        ($event) =>
                                                            feedbackClick(
                                                                $event,
                                                                item,
                                                                computedMessageList
                                                                    .filter((v) => v.role === RoleEnum.assistant)
                                                                    .findIndex((v) => v.historyId === item.historyId)
                                                            )
                                                    "
                                                />
                                                <FeedbackPanel
                                                    v-show="feedbackIsShow && currentFeedbackMapItem === item"
                                                    ref="feedbackPanelRef"
                                                    v-model:isShow="feedbackIsShow"
                                                    v-model:content="feedbackContent"
                                                    :chatItem="currentFeedbackMapItem"
                                                    :position="feedbackPosition"
                                                />
                                            </div>
                                        </el-tooltip>
                                            <el-tooltip effect="dark" content="反馈" placement="top">
                                                <div class="flex items-center justify-center size-[15px] relative">
                                                    <i
                                                        class="p-2 ywifont ywicon-wentifankui cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]"
                                                        @click="
                                                            ($event) =>
                                                                feedbackClick(
                                                                    $event,
                                                                    item,
                                                                    computedMessageList
                                                                        .filter((v) => v.role === RoleEnum.assistant)
                                                                        .findIndex((v) => v.historyId === item.historyId)
                                                                )
                                                        "
                                                    />
                                                    <FeedbackPanel
                                                        v-show="feedbackIsShow && currentFeedbackMapItem === item"
                                                        ref="feedbackPanelRef"
                                                        v-model:isShow="feedbackIsShow"
                                                        v-model:content="feedbackContent"
                                                        :chatItem="currentFeedbackMapItem"
                                                        :position="feedbackPosition"
                                                    />
                                                </div>
                                            </el-tooltip>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    </template>
                    <el-empty v-else-if="isSharePage && !chatListLoading" :image-size="200"  >
                        <template #description>
                            <span class="text-[15px]">
                                分享的对话不存在或已失效
                            </span>
                        </template>
                    </el-empty>
                    <div v-if="showAskMore && !isShareCheck" class="ml-4 mt-5 text-sm pb-10">
                        <div class="text-gray-600 mb-5">你可以继续问我:</div>
                        <div class="space-y-2 inline-flex flex-col">
@@ -243,10 +259,7 @@
                </div>
            </div>
            <div
                class="sticky bottom-0 w-full p-6 bg-[rgb(247,248,250)] flex justify-center"
                v-if="!isSharePage && !isShareCheck"
            >
            <div class="sticky bottom-0 w-full p-6 bg-[rgb(247,248,250)] flex justify-center" v-if="!isSharePage && !isShareCheck">
                <PlayBar
                    v-model:voicePageIsShow="voicePageIsShow"
                    :isTalking="isTalking"
@@ -285,15 +298,15 @@
import { Logger } from '/@/model/logger/Logger';
import router from '/@/router';
import {
activeChatRoom,
activeGroupType,
activeLLMId,
activeRoomId,
activeSampleId,
activeSectionAId,
getRoomConfig,
isSharePage,
roomConfig,
    activeChatRoom,
    activeGroupType,
    activeLLMId,
    activeRoomId,
    activeSampleId,
    activeSectionAId,
    getRoomConfig,
    isSharePage,
    roomConfig,
} from '/@/stores/chatRoom';
import { ErrorCode } from '/@/utils/request';
import { toMyFixed } from '/@/utils/util';
@@ -606,7 +619,6 @@
    }
};
const { loadRangeData, onChatListScroll, moreIsLoading, nextUserMsgEndIndex } = useScrollLoad({
    isSharePage: isSharePage,
    container: chatListDom,
@@ -615,21 +627,21 @@
    parseAnswerContent: parseContent,
});
const chatListLoading = ref(false);
const chatListLoading = ref(true);
const { scrollToBottom, scrollToTop } = useScrollToBottom({
    chatListDom: chatListDom,
});
onMounted(async () => {
    messageList.value = [];
    // 加载初始数据
    chatListLoading.value = true;
    await loadRangeData().finally(() => {
        chatListLoading.value = false;
    });
    if (messageList.value.length === 0) {
        messageContent.value = {
            type: AnswerType.Text,
src/components/chat/hooks/useScrollLoad.ts
@@ -146,7 +146,7 @@
     */
    const loadRangeData = async (lastEnd = nextUserMsgEndIndex.value) => {
        if (isSharePage.value) {
            loadShareData();
            await loadShareData();
            return;
        }
        const res = await QueryHistoryDetail({