mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-12-26 10:05:57 +08:00
支持在 Chat 页面显示,隐藏对话列表
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
<template>
|
||||
<div class="chat-page">
|
||||
<el-container>
|
||||
<el-aside>
|
||||
<el-aside v-show="store.chatListExtend">
|
||||
<div class="flex w-full justify-center pt-3 pb-3">
|
||||
<img :src="logo" style="max-height: 40px" :alt="title" v-if="logo !== ''"/>
|
||||
<h2 v-else>{{ title }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="media-page">
|
||||
<el-button @click="_newChat" type="primary" class="newChat">
|
||||
<el-icon style="margin-right: 5px">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
<i class="iconfont icon-new-chat mr-1"></i>
|
||||
新建对话
|
||||
</el-button>
|
||||
|
||||
@@ -19,7 +22,7 @@
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-scrollbar :height="chatBoxHeight">
|
||||
<el-scrollbar :height="chatListHeight">
|
||||
<div class="content">
|
||||
<el-row v-for="chat in chatList" :key="chat.chat_id">
|
||||
<div :class="chat.chat_id === chatId ? 'chat-list-item active' : 'chat-list-item'" @click="loadChat(chat)">
|
||||
@@ -111,7 +114,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="flex justify-center">
|
||||
<div id="container" :style="{ height: mainWinHeight + 'px' }">
|
||||
<div class="chat-box" id="chat-box" :style="{ height: chatBoxHeight + 'px' }">
|
||||
<div v-if="showHello">
|
||||
@@ -229,26 +232,29 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import {nextTick, onMounted, onUnmounted, ref, watch} from "vue";
|
||||
import ChatPrompt from "@/components/ChatPrompt.vue";
|
||||
import ChatReply from "@/components/ChatReply.vue";
|
||||
import { Delete, Edit, InfoFilled, More, Plus, Promotion, Search, Share, VideoPause } from "@element-plus/icons-vue";
|
||||
import {Delete, Edit, InfoFilled, More, Promotion, Search, Share, VideoPause} from "@element-plus/icons-vue";
|
||||
import "highlight.js/styles/a11y-dark.css";
|
||||
import { isMobile, randString, removeArrayItem, UUID } from "@/utils/libs";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { httpGet, httpPost } from "@/utils/http";
|
||||
import { useRouter } from "vue-router";
|
||||
import {isMobile, randString, removeArrayItem, UUID} from "@/utils/libs";
|
||||
import {ElMessage, ElMessageBox} from "element-plus";
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
import {useRouter} from "vue-router";
|
||||
import Clipboard from "clipboard";
|
||||
import { checkSession, getClientId, getSystemInfo } from "@/store/cache";
|
||||
import {checkSession, getClientId, getSystemInfo} from "@/store/cache";
|
||||
import Welcome from "@/components/Welcome.vue";
|
||||
import { useSharedStore } from "@/store/sharedata";
|
||||
import {useSharedStore} from "@/store/sharedata";
|
||||
import FileSelect from "@/components/FileSelect.vue";
|
||||
import FileList from "@/components/FileList.vue";
|
||||
import ChatSetting from "@/components/ChatSetting.vue";
|
||||
import BackTop from "@/components/BackTop.vue";
|
||||
import { closeLoading, showLoading, showMessageError } from "@/utils/dialog";
|
||||
import {closeLoading, showLoading, showMessageError} from "@/utils/dialog";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import emoji from "markdown-it-emoji";
|
||||
|
||||
const title = ref("GeekAI-智能助手");
|
||||
const logo = ref("");
|
||||
const models = ref([]);
|
||||
const modelID = ref(0);
|
||||
const chatData = ref([]);
|
||||
@@ -256,7 +262,7 @@ const allChats = ref([]); // 会话列表
|
||||
const chatList = ref(allChats.value);
|
||||
const mainWinHeight = ref(0); // 主窗口高度
|
||||
const chatBoxHeight = ref(0); // 聊天内容框高度
|
||||
const leftBoxHeight = ref(0);
|
||||
const chatListHeight = ref(0); // 聊天列表高度
|
||||
const loading = ref(false);
|
||||
const loginUser = ref(null);
|
||||
const roles = ref([]);
|
||||
@@ -311,6 +317,7 @@ if (!chatId.value) {
|
||||
// 查询对话信息
|
||||
httpGet("/api/chat/detail", { chat_id: chatId.value })
|
||||
.then((res) => {
|
||||
document.title = res.data.title;
|
||||
roleId.value = res.data.role_id;
|
||||
modelID.value = res.data.model_id;
|
||||
})
|
||||
@@ -324,14 +331,12 @@ getSystemInfo()
|
||||
.then((res) => {
|
||||
config.value = res.data;
|
||||
title.value = config.value.title;
|
||||
logo.value = res.data.bar_logo;
|
||||
})
|
||||
.catch((e) => {
|
||||
ElMessage.error("获取系统配置失败:" + e.message);
|
||||
});
|
||||
|
||||
import MarkdownIt from "markdown-it";
|
||||
import emoji from "markdown-it-emoji";
|
||||
|
||||
const md = new MarkdownIt({
|
||||
breaks: true,
|
||||
html: true,
|
||||
@@ -540,17 +545,10 @@ const getRoleById = function (rid) {
|
||||
};
|
||||
|
||||
const resizeElement = function () {
|
||||
chatBoxHeight.value = window.innerHeight - 101 - 82 - 38;
|
||||
chatListHeight.value = window.innerHeight - 240;
|
||||
// chatBoxHeight.value = window.innerHeight;
|
||||
|
||||
// mainWinHeight.value = window.innerHeight - 101;
|
||||
mainWinHeight.value = window.innerHeight - 59;
|
||||
|
||||
// mainWinHeight.value = window.innerHeight;
|
||||
|
||||
// leftBoxHeight.value = window.innerHeight - 90 - 45 - 82;
|
||||
// leftBoxHeight.value = window.innerHeight - 90 - 82;
|
||||
leftBoxHeight.value = window.innerHeight - 90 - 100;
|
||||
mainWinHeight.value = window.innerHeight - 50;
|
||||
chatBoxHeight.value = window.innerHeight - 101 - 82 - 38;
|
||||
};
|
||||
|
||||
const _newChat = () => {
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
<template>
|
||||
<div class="layout">
|
||||
<div class="tab-box">
|
||||
<div class="flex-center-col big-top-title xxx">
|
||||
<div class="flex-center-col" @click="isCollapse = !isCollapse">
|
||||
<el-tooltip content="展开菜单" placement="right" v-if="isCollapse">
|
||||
<i class="iconfont icon-expand"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="flex" :class="{ 'top-collapse': !isCollapse }">
|
||||
<div class="top-avatar flex">
|
||||
<span class="title" v-if="!isCollapse">{{ title }}</span>
|
||||
<el-tooltip :content="title" placement="right">
|
||||
<img :src="logo" alt="" :class="{ marr: !isCollapse }" v-if="isCollapse" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="menuIcon xxx" @click="isCollapse = !isCollapse">
|
||||
<el-tooltip content="关闭菜单" placement="right" v-if="!isCollapse">
|
||||
<div class="flex-center-col pt-2 mb-2">
|
||||
<div class="flex flex-center-col">
|
||||
<div class="menuIcon" @click="store.setChatListExtend(!store.chatListExtend)">
|
||||
<el-tooltip content="隐藏对话列表" placement="right" v-if="store.chatListExtend">
|
||||
<i class="iconfont icon-colspan"></i>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="展开对话列表" placement="right" v-else>
|
||||
<i class="iconfont icon-expand"></i>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu-list" :style="{ width: isCollapse ? '65px' : '170px' }" :class="{ 'menu-list-collapse': !isCollapse }">
|
||||
<div class="menu-list">
|
||||
<ul>
|
||||
<li
|
||||
class="menu-list-item flex-center-col"
|
||||
@@ -31,29 +23,28 @@
|
||||
@click="changeNav(item)"
|
||||
:class="item.url === curPath ? 'active' : ''"
|
||||
>
|
||||
<span v-if="item.icon.startsWith('icon')" :class="{ 'mr-1 ml-2': !isCollapse }">
|
||||
<span v-if="item.icon.startsWith('icon')">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
</span>
|
||||
<el-image :src="item.icon" class="el-icon ml-1" v-else />
|
||||
<div class="menu-title" :class="{ 'menu-title-collapse': !isCollapse }">
|
||||
<div class="menu-title">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- 更多 -->
|
||||
<div class="bot" :style="{ width: isCollapse ? '65px' : '170px' }">
|
||||
<div class="bot-line"></div>
|
||||
|
||||
<el-popover v-if="moreNavs.length > 0" placement="right-end" trigger="hover">
|
||||
<template #reference>
|
||||
<li class="menu-list-item flex-center-col">
|
||||
<el-icon><CirclePlus /></el-icon>
|
||||
<div class="menu-title">更多</div>
|
||||
</li>
|
||||
</template>
|
||||
<template #default>
|
||||
<ul class="more-menus">
|
||||
<li
|
||||
<!-- 更多 -->
|
||||
<div class="bot p-2">
|
||||
<div class="bot-line"></div>
|
||||
<el-popover v-if="moreNavs.length > 0" placement="right-end" trigger="hover">
|
||||
<template #reference>
|
||||
<li class="menu-list-item flex-center-col">
|
||||
<i class="iconfont icon-more"/>
|
||||
</li>
|
||||
</template>
|
||||
<template #default>
|
||||
<ul class="more-menus">
|
||||
<li
|
||||
v-for="(item, index) in moreNavs"
|
||||
:key="item.url"
|
||||
:class="{
|
||||
@@ -61,57 +52,52 @@
|
||||
moreTitle: index !== 3 && index !== 4,
|
||||
twoTittle: index === 3 || index === 4,
|
||||
}"
|
||||
>
|
||||
<a @click="changeNav(item)">
|
||||
>
|
||||
<a @click="changeNav(item)">
|
||||
<span v-if="item.icon.startsWith('icon')" class="mr-2">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
</span>
|
||||
<el-image :src="item.icon" style="width: 20px; height: 20px" v-else />
|
||||
<span :class="item.url === curPath ? 'title active' : 'title'">{{ item.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-popover placement="right-end" trigger="hover" v-if="loginUser.id">
|
||||
<template #reference>
|
||||
<li class="menu-list-item flex-center-col">
|
||||
<el-icon><Setting /></el-icon>
|
||||
<div v-if="!isCollapse">设置</div>
|
||||
<el-image :src="item.icon" style="width: 20px; height: 20px" v-else/>
|
||||
<span :class="item.url === curPath ? 'title active' : 'title'">{{ item.name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
<template #default>
|
||||
<ul class="more-menus setting-menus">
|
||||
<li>
|
||||
<div @click="showConfigDialog = true" class="flex">
|
||||
<el-icon>
|
||||
<UserFilled />
|
||||
</el-icon>
|
||||
<span class="username title">{{ loginUser.nickname }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a @click="logout" class="flex">
|
||||
<i class="iconfont icon-logout"></i>
|
||||
<span class="title">退出登录</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</el-popover>
|
||||
<li class="menu-bot-item">
|
||||
<a :href="gitURL" class="link-button" target="_blank" v-if="!license.de_copy && !isCollapse">
|
||||
<i class="iconfont icon-github"></i>
|
||||
</a>
|
||||
|
||||
<a @click="router.push('/')" class="link-button">
|
||||
<i class="iconfont icon-house"></i>
|
||||
</a>
|
||||
|
||||
<ThemeChange />
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-popover placement="right-end" trigger="hover" v-if="loginUser.id">
|
||||
<template #reference>
|
||||
<li class="menu-list-item flex-center-col">
|
||||
<i class="iconfont icon-config"/>
|
||||
</li>
|
||||
</template>
|
||||
<template #default>
|
||||
<ul class="more-menus setting-menus">
|
||||
<li>
|
||||
<div @click="showConfigDialog = true" class="flex">
|
||||
<el-icon>
|
||||
<UserFilled/>
|
||||
</el-icon>
|
||||
<span class="username title">{{ loginUser.nickname }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a @click="logout" class="flex">
|
||||
<i class="iconfont icon-logout"></i>
|
||||
<span class="title">退出登录</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</el-popover>
|
||||
<div class="menu-bot-item">
|
||||
<a @click="router.push('/')" class="link-button">
|
||||
<i class="iconfont icon-house"></i>
|
||||
</a>
|
||||
<div class="pl-1">
|
||||
<ThemeChange/>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-scrollbar class="right-main">
|
||||
@@ -141,21 +127,19 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { CirclePlus, Setting, UserFilled } from "@element-plus/icons-vue";
|
||||
import {UserFilled} from "@element-plus/icons-vue";
|
||||
import ThemeChange from "@/components/ThemeChange.vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { httpGet } from "@/utils/http";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { checkSession, getLicenseInfo, getSystemInfo } from "@/store/cache";
|
||||
import { removeUserToken } from "@/store/session";
|
||||
import { useSharedStore } from "@/store/sharedata";
|
||||
import {useRouter} from "vue-router";
|
||||
import {onMounted, ref, watch} from "vue";
|
||||
import {httpGet} from "@/utils/http";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {checkSession, getLicenseInfo, getSystemInfo} from "@/store/cache";
|
||||
import {removeUserToken} from "@/store/session";
|
||||
import {useSharedStore} from "@/store/sharedata";
|
||||
import ConfigDialog from "@/components/UserInfoDialog.vue";
|
||||
import { showMessageError } from "@/utils/dialog";
|
||||
import {showMessageError} from "@/utils/dialog";
|
||||
import LoginDialog from "@/components/LoginDialog.vue";
|
||||
import { substr } from "@/utils/libs";
|
||||
|
||||
const isCollapse = ref(true);
|
||||
const router = useRouter();
|
||||
const logo = ref("");
|
||||
const mainNavs = ref([]);
|
||||
@@ -163,13 +147,11 @@ const moreNavs = ref([]);
|
||||
const curPath = ref();
|
||||
|
||||
const title = ref("");
|
||||
const avatarImg = ref("/images/avatar/default.jpg");
|
||||
const store = useSharedStore();
|
||||
const loginUser = ref({});
|
||||
const routerViewKey = ref(0);
|
||||
const showConfigDialog = ref(false);
|
||||
const license = ref({ de_copy: true });
|
||||
const gitURL = ref(process.env.VUE_APP_GIT_URL);
|
||||
const showLoginDialog = ref(false);
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,25 +9,24 @@
|
||||
</div>
|
||||
<div class="menu-item">
|
||||
<span v-if="!license.de_copy">
|
||||
<el-tooltip v-if="!license.de_copy" class="box-item" content="部署文档" placement="bottom">
|
||||
<el-tooltip class="box-item" content="部署文档" placement="bottom">
|
||||
<a :href="docsURL" class="link-button mr-2" target="_blank">
|
||||
<i class="iconfont icon-book"></i>
|
||||
</a>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="!license.de_copy" class="box-item" content="项目源码" placement="bottom">
|
||||
<el-tooltip class="box-item" content="Github 源码" placement="bottom">
|
||||
<a :href="gitURL" class="link-button" target="_blank">
|
||||
<i class="iconfont icon-github"></i>
|
||||
</a>
|
||||
</el-tooltip>
|
||||
<el-tooltip class="box-item" content="Gitee 源码" placement="bottom">
|
||||
<a :href="gitURL" class="link-button" target="_blank">
|
||||
<i class="iconfont icon-gitee"></i>
|
||||
</a>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
|
||||
<span v-if="!isLogin">
|
||||
<!-- <el-button @click="router.push('/login')" class="shadow" round
|
||||
>登录</el-button
|
||||
>
|
||||
<el-button @click="router.push('/register')" class="shadow" round
|
||||
>注册</el-button
|
||||
> -->
|
||||
<el-button @click="router.push('/login')" class="btn-go animate__animated animate__pulse animate__infinite" round>登录/注册</el-button>
|
||||
</span>
|
||||
</div>
|
||||
@@ -59,14 +58,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import {onMounted, ref} from "vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import FooterBar from "@/components/FooterBar.vue";
|
||||
import ThemeChange from "@/components/ThemeChange.vue";
|
||||
import { httpGet } from "@/utils/http";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { checkSession, getLicenseInfo, getSystemInfo } from "@/store/cache";
|
||||
import { isMobile } from "@/utils/libs";
|
||||
import {httpGet} from "@/utils/http";
|
||||
import {ElMessage} from "element-plus";
|
||||
import {checkSession, getLicenseInfo, getSystemInfo} from "@/store/cache";
|
||||
import {isMobile} from "@/utils/libs";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -81,7 +80,7 @@ const license = ref({ de_copy: true });
|
||||
|
||||
const isLogin = ref(false);
|
||||
const docsURL = ref(process.env.VUE_APP_DOCS_URL);
|
||||
const gitURL = ref(process.env.VUE_APP_GIT_URL);
|
||||
const gitURL = ref(process.env.VUE_APP_GITHUB_URL);
|
||||
const navs = ref([]);
|
||||
|
||||
const iconMap = ref({
|
||||
@@ -150,7 +149,6 @@ const setContent = () => {
|
||||
displayedChars.value = [];
|
||||
if (timer) clearInterval(timer);
|
||||
timer = setInterval(setContent, interTime.value);
|
||||
return;
|
||||
} else {
|
||||
const nextChar = slogan.value.charAt(initAnimation.value.length);
|
||||
initAnimation.value += slogan.value.charAt(initAnimation.value.length); // 逐字符追加
|
||||
@@ -164,7 +162,7 @@ const setContent = () => {
|
||||
const rainbowColor = (index) => {
|
||||
const hue = (index * 40) % 360; // 每个字符间隔40度,形成彩虹色
|
||||
return `hsl(${hue}, 90%, 50%)`; // 色调(hue),饱和度(70%),亮度(50%)
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
<el-form-item label="网站Slogan" prop="slogan">
|
||||
<el-input v-model="system['slogan']" />
|
||||
</el-form-item>
|
||||
<el-form-item label="网站 LOGO" prop="logo">
|
||||
<el-input v-model="system['logo']" placeholder="网站LOGO图片">
|
||||
<el-form-item label="圆形 LOGO" prop="logo">
|
||||
<el-input v-model="system['logo']" placeholder="正方形或者圆形 Logo">
|
||||
<template #append>
|
||||
<el-upload :auto-upload="true" :show-file-list="false" @click="beforeUpload('logo')" :http-request="uploadImg">
|
||||
<el-icon class="uploader-icon">
|
||||
@@ -26,7 +26,18 @@
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="条形 LOGO" prop="logo">
|
||||
<el-input v-model="system['bar_logo']" placeholder="长方形 Logo">
|
||||
<template #append>
|
||||
<el-upload :auto-upload="true" :show-file-list="false" @click="beforeUpload('bar_logo')"
|
||||
:http-request="uploadImg">
|
||||
<el-icon class="uploader-icon">
|
||||
<UploadFilled/>
|
||||
</el-icon>
|
||||
</el-upload>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<div class="label-title">
|
||||
@@ -359,17 +370,17 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref } from "vue";
|
||||
import { httpGet, httpPost } from "@/utils/http";
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import {httpGet, httpPost} from "@/utils/http";
|
||||
import Compressor from "compressorjs";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { CloseBold, InfoFilled, Select, UploadFilled } from "@element-plus/icons-vue";
|
||||
import {ElMessage, ElMessageBox} from "element-plus";
|
||||
import {CloseBold, InfoFilled, Select, UploadFilled} from "@element-plus/icons-vue";
|
||||
import MdEditor from "md-editor-v3";
|
||||
import "md-editor-v3/lib/style.css";
|
||||
import Menu from "@/views/admin/Menu.vue";
|
||||
import { copyObj, dateFormat } from "@/utils/libs";
|
||||
import {copyObj, dateFormat} from "@/utils/libs";
|
||||
import ItemsInput from "@/components/ui/ItemsInput.vue";
|
||||
import { useSharedStore } from "@/store/sharedata";
|
||||
import {useSharedStore} from "@/store/sharedata";
|
||||
|
||||
const activeName = ref("basic");
|
||||
const system = ref({ models: [] });
|
||||
|
||||
Reference in New Issue
Block a user