feat: style
This commit is contained in:
@@ -6,9 +6,9 @@ import type { AiChatConversationApi } from '#/api/ai/chat/conversation';
|
||||
import { h, onMounted, ref, toRefs, watch } from 'vue';
|
||||
|
||||
import { confirm, prompt, useVbenDrawer } from '@vben/common-ui';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
import { IconifyIcon, SvgGptIcon } from '@vben/icons';
|
||||
|
||||
import { Button, Empty, Input, Layout, message } from 'ant-design-vue';
|
||||
import { Avatar, Button, Empty, Input, Layout, message } from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
createChatConversationMy,
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
|
||||
import RoleRepository from '../role/RoleRepository.vue';
|
||||
|
||||
// 加载中定时器
|
||||
// 定义组件 props
|
||||
const props = defineProps({
|
||||
activeId: {
|
||||
@@ -308,24 +307,24 @@ onMounted(async () => {
|
||||
<template>
|
||||
<Layout.Sider
|
||||
width="260px"
|
||||
class="conversation-container relative flex h-full flex-col justify-between overflow-hidden bg-[hsl(var(--primary-foreground))!important] p-[10px_10px_0]"
|
||||
class="!bg-primary-foreground conversation-container relative flex h-full flex-col justify-between overflow-hidden py-2.5 pb-0 pt-2.5"
|
||||
>
|
||||
<Drawer />
|
||||
<!-- 左顶部:对话 -->
|
||||
<div class="flex h-full flex-col">
|
||||
<Button
|
||||
class="btn-new-conversation h-[38px] w-full"
|
||||
class="btn-new-conversation h-9 w-full"
|
||||
type="primary"
|
||||
@click="createConversation"
|
||||
>
|
||||
<IconifyIcon icon="lucide:plus" class="mr-[5px]" />
|
||||
<IconifyIcon icon="lucide:plus" class="mr-1" />
|
||||
新建对话
|
||||
</Button>
|
||||
|
||||
<Input
|
||||
v-model:value="searchName"
|
||||
size="large"
|
||||
class="search-input mt-[20px]"
|
||||
class="search-input mt-5"
|
||||
placeholder="搜索历史记录"
|
||||
@keyup="searchConversation"
|
||||
>
|
||||
@@ -335,7 +334,7 @@ onMounted(async () => {
|
||||
</Input>
|
||||
|
||||
<!-- 左中间:对话列表 -->
|
||||
<div class="conversation-list mt-[10px] flex-1 overflow-auto">
|
||||
<div class="conversation-list mt-2.5 flex-1 overflow-auto">
|
||||
<!-- 情况一:加载中 -->
|
||||
<Empty v-if="loading" description="." v-loading="loading" />
|
||||
|
||||
@@ -347,9 +346,9 @@ onMounted(async () => {
|
||||
>
|
||||
<div
|
||||
v-if="conversationMap[conversationKey].length > 0"
|
||||
class="conversation-item classify-title pt-[10px]"
|
||||
class="conversation-item classify-title pt-2.5"
|
||||
>
|
||||
<b class="mx-[4px]">
|
||||
<b class="mx-1">
|
||||
{{ conversationKey }}
|
||||
</b>
|
||||
</div>
|
||||
@@ -360,21 +359,22 @@ onMounted(async () => {
|
||||
@click="handleConversationClick(conversation.id)"
|
||||
@mouseover="hoverConversationId = conversation.id"
|
||||
@mouseout="hoverConversationId = null"
|
||||
class="conversation-item mt-[5px]"
|
||||
class="conversation-item mt-1"
|
||||
>
|
||||
<div
|
||||
class="conversation flex cursor-pointer flex-row items-center justify-between rounded-[5px] px-[5px] leading-[30px]"
|
||||
class="conversation flex cursor-pointer flex-row items-center justify-between rounded-lg px-2.5 leading-10"
|
||||
:class="[
|
||||
conversation.id === activeConversationId ? 'bg-[#e6e6e6]' : '',
|
||||
conversation.id === activeConversationId ? 'bg-gray-100' : '',
|
||||
]"
|
||||
>
|
||||
<div class="title-wrapper flex items-center">
|
||||
<img
|
||||
class="avatar h-[25px] w-[25px] rounded-[5px]"
|
||||
:src="conversation.roleAvatar ?? '/static/gpt.svg'"
|
||||
<Avatar
|
||||
v-if="conversation.roleAvatar"
|
||||
:src="conversation.roleAvatar"
|
||||
/>
|
||||
<SvgGptIcon v-else class="size-8" />
|
||||
<span
|
||||
class="title text-black/77 max-w-[150px] overflow-hidden text-ellipsis whitespace-nowrap px-[10px] py-[2px] text-[14px] font-normal"
|
||||
class="max-w-36 overflow-hidden text-ellipsis whitespace-nowrap px-2.5 py-1 text-sm font-normal text-gray-600"
|
||||
>
|
||||
{{ conversation.title }}
|
||||
</span>
|
||||
@@ -382,35 +382,35 @@ onMounted(async () => {
|
||||
|
||||
<div
|
||||
v-show="hoverConversationId === conversation.id"
|
||||
class="button-wrapper relative right-[2px] flex items-center text-[#606266]"
|
||||
class="button-wrapper relative right-0.5 flex items-center text-gray-400"
|
||||
>
|
||||
<Button
|
||||
class="btn mr-0 px-[5px]"
|
||||
class="mr-0 px-1"
|
||||
type="link"
|
||||
@click.stop="handleTop(conversation)"
|
||||
>
|
||||
<IconifyIcon
|
||||
v-if="!conversation.pinned"
|
||||
icon="lucide:arrow-up"
|
||||
icon="lucide:arrow-up-to-line"
|
||||
/>
|
||||
<IconifyIcon
|
||||
v-if="conversation.pinned"
|
||||
icon="lucide:arrow-down"
|
||||
icon="lucide:arrow-down-from-line"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
class="btn mr-0 px-[5px]"
|
||||
class="mr-0 px-1"
|
||||
type="link"
|
||||
@click.stop="updateConversationTitle(conversation)"
|
||||
>
|
||||
<IconifyIcon icon="lucide:edit" />
|
||||
</Button>
|
||||
<Button
|
||||
class="btn mr-0 px-[5px]"
|
||||
class="mr-0 px-1"
|
||||
type="link"
|
||||
@click.stop="deleteChatConversation(conversation)"
|
||||
>
|
||||
<IconifyIcon icon="lucide:trash" />
|
||||
<IconifyIcon icon="lucide:trash-2" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -419,26 +419,26 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<!-- 底部占位 -->
|
||||
<div class="h-[50px] w-full"></div>
|
||||
<div class="h-12 w-full"></div>
|
||||
</div>
|
||||
|
||||
<!-- 左底部:工具栏 -->
|
||||
<div
|
||||
class="tool-box absolute bottom-0 left-0 right-0 flex items-center justify-between bg-[#f4f4f4] px-[20px] leading-[35px] text-[var(--el-text-color)] shadow-[0_0_1px_1px_rgba(228,228,228,0.8)]"
|
||||
class="tool-box absolute bottom-0 left-0 right-0 flex items-center justify-between bg-gray-50 px-5 leading-9 text-gray-400 shadow-sm"
|
||||
>
|
||||
<div
|
||||
class="flex cursor-pointer items-center text-[#606266]"
|
||||
class="flex cursor-pointer items-center text-gray-400"
|
||||
@click="handleRoleRepository"
|
||||
>
|
||||
<IconifyIcon icon="lucide:user" />
|
||||
<span class="ml-[5px]">角色仓库</span>
|
||||
<span class="ml-1">角色仓库</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex cursor-pointer items-center text-[#606266]"
|
||||
class="flex cursor-pointer items-center text-gray-400"
|
||||
@click="handleClearConversation"
|
||||
>
|
||||
<IconifyIcon icon="lucide:trash" />
|
||||
<span class="ml-[5px]">清空未置顶对话</span>
|
||||
<span class="ml-1">清空未置顶对话</span>
|
||||
</div>
|
||||
</div>
|
||||
</Layout.Sider>
|
||||
|
||||
@@ -76,7 +76,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal class="w-[600px]" title="设定">
|
||||
<Modal class="w-2/5" title="设定">
|
||||
<Form class="mx-4" />
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
@@ -57,21 +57,21 @@ function handleClick(doc: any) {
|
||||
<!-- 知识引用列表 -->
|
||||
<div
|
||||
v-if="segments && segments.length > 0"
|
||||
class="mt-[10px] rounded-[8px] bg-[#f5f5f5] p-[10px]"
|
||||
class="mt-2 rounded-lg bg-gray-50 p-2"
|
||||
>
|
||||
<div class="text-14px mb-8px flex items-center text-[#666]">
|
||||
<IconifyIcon icon="lucide:file-text" class="mr-[5px]" /> 知识引用
|
||||
<div class="mb-2 flex items-center text-sm text-gray-400">
|
||||
<IconifyIcon icon="lucide:file-text" class="mr-1" /> 知识引用
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-[8px]">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<div
|
||||
v-for="(doc, index) in documentList"
|
||||
:key="index"
|
||||
class="cursor-pointer rounded-[6px] bg-white p-[8px] px-[12px] transition-all hover:bg-[#e6f4ff]"
|
||||
class="cursor-pointer rounded-lg bg-white p-2 px-3 transition-all hover:bg-blue-50"
|
||||
@click="handleClick(doc)"
|
||||
>
|
||||
<div class="mb-[4px] text-[14px] text-[#333]">
|
||||
<div class="mb-1 text-sm text-gray-600">
|
||||
{{ doc.title }}
|
||||
<span class="ml-[4px] text-[12px] text-[#999]">
|
||||
<span class="ml-1 text-xs text-gray-300">
|
||||
({{ doc.segments.length }} 条)
|
||||
</span>
|
||||
</div>
|
||||
@@ -81,19 +81,19 @@ function handleClick(doc: any) {
|
||||
<Tooltip placement="topLeft" trigger="click">
|
||||
<div ref="documentRef"></div>
|
||||
<template #title>
|
||||
<div class="mb-[12px] text-[16px] font-bold">{{ document?.title }}</div>
|
||||
<div class="mb-3 text-base font-bold">{{ document?.title }}</div>
|
||||
<div class="max-h-[60vh] overflow-y-auto">
|
||||
<div
|
||||
v-for="(segment, index) in document?.segments"
|
||||
:key="index"
|
||||
class="border-b-solid border-b-[#eee] p-[12px] last:border-b-0"
|
||||
class="border-b-solid border-b-gray-200 p-3 last:border-b-0"
|
||||
>
|
||||
<div
|
||||
class="mb-[8px] block w-fit rounded-[4px] bg-[#f5f5f5] px-[8px] py-[2px] text-[12px] text-[#666]"
|
||||
class="mb-2 block w-fit rounded-sm bg-gray-50 px-2 py-1 text-xs text-gray-400"
|
||||
>
|
||||
分段 {{ segment.id }}
|
||||
</div>
|
||||
<div class="mt-[10px] text-[14px] leading-[1.6] text-[#333]">
|
||||
<div class="mt-2 text-sm leading-[1.6] text-gray-600">
|
||||
{{ segment.content }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -114,7 +114,7 @@ onMounted(async () => {
|
||||
<div
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
class="mt-[50px] flex flex-col overflow-y-hidden px-[20px]"
|
||||
class="mt-12 flex flex-col overflow-y-hidden px-5"
|
||||
>
|
||||
<!-- 左侧消息:system、assistant -->
|
||||
<div v-if="item.type !== 'user'" class="flex flex-row">
|
||||
@@ -125,22 +125,22 @@ onMounted(async () => {
|
||||
/>
|
||||
<SvgGptIcon v-else class="size-8" />
|
||||
</div>
|
||||
<div class="mx-[15px] flex flex-col text-left">
|
||||
<div class="text-left leading-[30px]">
|
||||
<div class="mx-4 flex flex-col text-left">
|
||||
<div class="text-left leading-10">
|
||||
{{ formatDate(item.createTime) }}
|
||||
</div>
|
||||
<div
|
||||
class="relative flex flex-col break-words rounded-[10px] bg-[#e4e4e4cc] p-[10px] pb-[5px] pt-[10px] shadow-[0_0_0_1px_rgba(228,228,228,0.8)]"
|
||||
class="relative flex flex-col break-words rounded-lg bg-gray-100 p-2.5 pb-1 pt-2.5 shadow-sm"
|
||||
>
|
||||
<MarkdownView
|
||||
class="text-[0.95rem] text-[#393939]"
|
||||
class="text-sm text-gray-600"
|
||||
:content="item.content"
|
||||
/>
|
||||
<MessageKnowledge v-if="item.segments" :segments="item.segments" />
|
||||
</div>
|
||||
<div class="mt-[8px] flex flex-row">
|
||||
<div class="mt-2 flex flex-row">
|
||||
<Button
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
class="flex items-center bg-transparent px-1.5 hover:bg-gray-100"
|
||||
type="text"
|
||||
@click="copyContent(item.content)"
|
||||
>
|
||||
@@ -148,7 +148,7 @@ onMounted(async () => {
|
||||
</Button>
|
||||
<Button
|
||||
v-if="item.id > 0"
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
class="flex items-center bg-transparent px-1.5 hover:bg-gray-100"
|
||||
type="text"
|
||||
@click="onDelete(item.id)"
|
||||
>
|
||||
@@ -163,41 +163,41 @@ onMounted(async () => {
|
||||
<div class="avatar">
|
||||
<Avatar :src="userAvatar" />
|
||||
</div>
|
||||
<div class="mx-[15px] flex flex-col text-left">
|
||||
<div class="text-left leading-[30px]">
|
||||
<div class="mx-4 flex flex-col text-left">
|
||||
<div class="text-left leading-8">
|
||||
{{ formatDate(item.createTime) }}
|
||||
</div>
|
||||
<div class="flex flex-row-reverse">
|
||||
<div
|
||||
class="inline w-auto whitespace-pre-wrap break-words rounded-[10px] bg-[#267fff] p-[10px] text-[0.95rem] text-white shadow-[0_0_0_1px_#267fff]"
|
||||
class="inline w-auto whitespace-pre-wrap break-words rounded-lg bg-blue-500 p-2.5 text-sm text-white shadow-sm"
|
||||
>
|
||||
{{ item.content }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-[8px] flex flex-row-reverse">
|
||||
<div class="mt-2 flex flex-row-reverse">
|
||||
<Button
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
class="flex items-center bg-transparent px-1.5 hover:bg-gray-100"
|
||||
type="text"
|
||||
@click="copyContent(item.content)"
|
||||
>
|
||||
<IconifyIcon icon="lucide:copy" />
|
||||
</Button>
|
||||
<Button
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
class="flex items-center bg-transparent px-1.5 hover:bg-gray-100"
|
||||
type="text"
|
||||
@click="onDelete(item.id)"
|
||||
>
|
||||
<IconifyIcon icon="lucide:trash" />
|
||||
</Button>
|
||||
<Button
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
class="flex items-center bg-transparent px-1.5 hover:bg-gray-100"
|
||||
type="text"
|
||||
@click="onRefresh(item)"
|
||||
>
|
||||
<IconifyIcon icon="lucide:refresh-cw" />
|
||||
</Button>
|
||||
<Button
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
class="flex items-center bg-transparent px-1.5 hover:bg-gray-100"
|
||||
type="text"
|
||||
@click="onEdit(item)"
|
||||
>
|
||||
@@ -212,7 +212,7 @@ onMounted(async () => {
|
||||
<!-- 回到底部按钮 -->
|
||||
<div
|
||||
v-if="isScrolling"
|
||||
class="absolute bottom-0 right-1/2 z-[1000]"
|
||||
class="z-1000 absolute bottom-0 right-1/2"
|
||||
@click="handleGoBottom"
|
||||
>
|
||||
<Button shape="circle">
|
||||
|
||||
@@ -20,17 +20,15 @@ async function handlerPromptClick(prompt: any) {
|
||||
<!-- center-container -->
|
||||
<div class="flex flex-col justify-center">
|
||||
<!-- title -->
|
||||
<div class="text-center text-[28px] font-bold">芋道 AI</div>
|
||||
<div class="text-center text-3xl font-bold">芋道 AI</div>
|
||||
|
||||
<!-- role-list -->
|
||||
<div
|
||||
class="mt-[20px] flex w-[460px] flex-wrap items-center justify-center"
|
||||
>
|
||||
<div class="mt-5 flex w-96 flex-wrap items-center justify-center">
|
||||
<div
|
||||
v-for="prompt in promptList"
|
||||
:key="prompt.prompt"
|
||||
@click="handlerPromptClick(prompt)"
|
||||
class="m-[10px] flex w-[180px] cursor-pointer justify-center rounded-[10px] border border-[#e4e4e4] leading-[50px] hover:bg-[rgba(243,243,243,0.73)]"
|
||||
class="m-2.5 flex w-44 cursor-pointer justify-center rounded-lg border border-gray-200 leading-10 hover:bg-gray-100"
|
||||
>
|
||||
{{ prompt.prompt }}
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Skeleton } from 'ant-design-vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-[30px]">
|
||||
<div class="p-8">
|
||||
<Skeleton active />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -12,10 +12,10 @@ function handlerNewChat() {
|
||||
<template>
|
||||
<div class="flex h-full w-full flex-row justify-center">
|
||||
<div class="flex flex-col justify-center">
|
||||
<div class="text-center text-[14px] text-[#858585]">
|
||||
<div class="text-center text-sm text-gray-400">
|
||||
点击下方按钮,开始你的对话吧
|
||||
</div>
|
||||
<div class="mt-[20px] flex flex-row justify-center">
|
||||
<div class="mt-5 flex flex-row justify-center">
|
||||
<Button type="primary" round @click="handlerNewChat">新建对话</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { ref } from 'vue';
|
||||
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Button, Card, Dropdown, Menu } from 'ant-design-vue';
|
||||
import { Avatar, Button, Card, Dropdown, Menu } from 'ant-design-vue';
|
||||
|
||||
// tabs ref
|
||||
|
||||
@@ -61,17 +61,13 @@ async function handleTabsScroll() {
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="relative flex h-full flex-wrap content-start items-start overflow-auto px-[25px] pb-[140px]"
|
||||
class="relative flex h-full flex-wrap content-start items-start overflow-auto px-6 pb-36"
|
||||
ref="tabsRef"
|
||||
@scroll="handleTabsScroll"
|
||||
>
|
||||
<div
|
||||
class="mb-[20px] mr-[20px] inline-block"
|
||||
v-for="role in roleList"
|
||||
:key="role.id"
|
||||
>
|
||||
<div class="mb-5 mr-5 inline-block" v-for="role in roleList" :key="role.id">
|
||||
<Card
|
||||
class="relative rounded-[10px]"
|
||||
class="relative rounded-lg"
|
||||
:body-style="{
|
||||
position: 'relative',
|
||||
display: 'flex',
|
||||
@@ -83,9 +79,9 @@ async function handleTabsScroll() {
|
||||
}"
|
||||
>
|
||||
<!-- 更多操作 -->
|
||||
<div v-if="showMore" class="absolute right-[12px] top-0">
|
||||
<div v-if="showMore" class="absolute right-3 top-0">
|
||||
<Dropdown>
|
||||
<Button type="text">
|
||||
<Button type="link">
|
||||
<IconifyIcon icon="lucide:ellipsis-vertical" />
|
||||
</Button>
|
||||
<template #overlay>
|
||||
@@ -99,7 +95,7 @@ async function handleTabsScroll() {
|
||||
<Menu.Item @click="handleMoreClick(['delete', role])">
|
||||
<div class="flex items-center">
|
||||
<IconifyIcon icon="lucide:trash" color="red" />
|
||||
<span class="text-red-500">编辑</span>
|
||||
<span class="text-red-500">删除</span>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
@@ -109,22 +105,19 @@ async function handleTabsScroll() {
|
||||
|
||||
<!-- 角色信息 -->
|
||||
<div>
|
||||
<img
|
||||
:src="role.avatar"
|
||||
class="h-[40px] w-[40px] overflow-hidden rounded-[10px]"
|
||||
/>
|
||||
<Avatar :src="role.avatar" class="h-10 w-10 overflow-hidden" />
|
||||
</div>
|
||||
|
||||
<div class="ml-[10px] w-full">
|
||||
<div class="h-[85px]">
|
||||
<div class="max-w-[140px] text-[18px] font-bold text-[#3e3e3e]">
|
||||
<div class="ml-2 w-full">
|
||||
<div class="h-20">
|
||||
<div class="max-w-36 text-lg font-bold text-gray-600">
|
||||
{{ role.name }}
|
||||
</div>
|
||||
<div class="mt-[10px] text-[14px] text-[#6a6a6a]">
|
||||
<div class="mt-2 text-sm text-gray-400">
|
||||
{{ role.description }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-[2px] flex flex-row-reverse">
|
||||
<div class="mt-1 flex flex-row-reverse">
|
||||
<Button type="primary" size="small" @click="handleUseClick(role)">
|
||||
使用
|
||||
</Button>
|
||||
|
||||
@@ -21,7 +21,7 @@ const router = useRouter(); // 路由对象
|
||||
const [Drawer] = useVbenDrawer({
|
||||
title: '角色管理',
|
||||
footer: false,
|
||||
class: 'w-[754px]',
|
||||
class: 'w-2/5',
|
||||
});
|
||||
|
||||
const [FormModal, formModalApi] = useVbenModal({
|
||||
@@ -179,12 +179,12 @@ onMounted(async () => {
|
||||
<FormModal @success="handlerAddRoleSuccess" />
|
||||
|
||||
<Layout.Content class="relative m-0 flex-1 overflow-hidden p-0">
|
||||
<div class="absolute right-0 top-[-5px] z-[100] mr-[20px] mt-[20px]">
|
||||
<div class="z-100 absolute right-0 top--1 mr-5 mt-5">
|
||||
<!-- 搜索输入框 -->
|
||||
<Input.Search
|
||||
:loading="loading"
|
||||
v-model:value="search"
|
||||
class="w-[240px]"
|
||||
class="w-60"
|
||||
placeholder="请输入搜索的内容"
|
||||
@search="getActiveTabsRole"
|
||||
/>
|
||||
@@ -192,9 +192,9 @@ onMounted(async () => {
|
||||
v-if="activeTab === 'my-role'"
|
||||
type="primary"
|
||||
@click="handlerAddRole"
|
||||
class="ml-[20px]"
|
||||
class="ml-5"
|
||||
>
|
||||
<IconifyIcon icon="lucide:user" style="margin-right: 5px" />
|
||||
<IconifyIcon icon="lucide:user" class="mr-1.5" />
|
||||
添加角色
|
||||
</Button>
|
||||
</div>
|
||||
@@ -218,7 +218,7 @@ onMounted(async () => {
|
||||
@on-edit="handlerCardEdit"
|
||||
@on-use="handlerCardUse"
|
||||
@on-page="handlerCardPage('my')"
|
||||
class="mt-[20px]"
|
||||
class="mt-5"
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
|
||||
@@ -231,7 +231,7 @@ onMounted(async () => {
|
||||
:category-list="categoryList"
|
||||
:active="activeCategory"
|
||||
@on-category-click="handlerCategoryClick"
|
||||
class="mx-[27px]"
|
||||
class="mx-6"
|
||||
/>
|
||||
<RoleList
|
||||
:role-list="publicRoleList"
|
||||
@@ -239,7 +239,7 @@ onMounted(async () => {
|
||||
@on-edit="handlerCardEdit"
|
||||
@on-use="handlerCardUse"
|
||||
@on-page="handlerCardPage('public')"
|
||||
class="mt-[20px]"
|
||||
class="mt-5"
|
||||
loading
|
||||
/>
|
||||
</Tabs.TabPane>
|
||||
|
||||
@@ -494,10 +494,10 @@ onMounted(async () => {
|
||||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<Layout class="absolute left-0 top-0 h-full w-full flex-1">
|
||||
<Layout class="absolute left-0 top-0 m-4 h-full w-full flex-1">
|
||||
<!-- 左侧:对话列表 -->
|
||||
<ConversationList
|
||||
:active-id="activeConversationId"
|
||||
:active-id="activeConversationId as any"
|
||||
ref="conversationListRef"
|
||||
@on-conversation-create="handleConversationCreateSuccess"
|
||||
@on-conversation-click="handleConversationClick"
|
||||
@@ -506,18 +506,18 @@ onMounted(async () => {
|
||||
/>
|
||||
|
||||
<!-- 右侧:详情部分 -->
|
||||
<Layout class="bg-white">
|
||||
<Layout class="ml-4 bg-white">
|
||||
<Layout.Header
|
||||
class="flex items-center justify-between bg-[#fbfbfb!important] shadow-none"
|
||||
class="flex items-center justify-between !bg-gray-50 shadow-none"
|
||||
>
|
||||
<div class="text-[18px] font-bold">
|
||||
<div class="text-lg font-bold">
|
||||
{{ activeConversation?.title ? activeConversation?.title : '对话' }}
|
||||
<span v-if="activeMessageList.length > 0">
|
||||
({{ activeMessageList.length }})
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex w-[300px] justify-end" v-if="activeConversation">
|
||||
<div class="flex w-72 justify-end" v-if="activeConversation">
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
@@ -526,10 +526,10 @@ onMounted(async () => {
|
||||
@click="openChatConversationUpdateForm"
|
||||
>
|
||||
<span v-html="activeConversation?.modelName"></span>
|
||||
<IconifyIcon icon="lucide:settings" class="ml-2" />
|
||||
<IconifyIcon icon="lucide:settings" class="ml-2 size-4" />
|
||||
</Button>
|
||||
<Button size="small" class="mr-2 px-2" @click="handlerMessageClear">
|
||||
<IconifyIcon icon="lucide:trash" color="#787878" />
|
||||
<IconifyIcon icon="lucide:trash-2" color="#787878" />
|
||||
</Button>
|
||||
<Button size="small" class="mr-2 px-2">
|
||||
<IconifyIcon icon="lucide:download" color="#787878" />
|
||||
@@ -567,12 +567,12 @@ onMounted(async () => {
|
||||
</div>
|
||||
</Layout.Content>
|
||||
|
||||
<Layout.Footer class="m-0 flex flex-col bg-[white!important] p-0">
|
||||
<Layout.Footer class="m-0 flex flex-col !bg-white p-0">
|
||||
<form
|
||||
class="m-[10px_20px_20px] flex flex-col rounded-[10px] border border-[#e3e3e3] p-[9px_10px]"
|
||||
class="my-5 mb-5 mt-2 flex flex-col rounded-xl border border-gray-200 px-2 py-2.5"
|
||||
>
|
||||
<textarea
|
||||
class="box-border h-[80px] resize-none overflow-auto border-none p-[0_2px] focus:outline-none"
|
||||
class="box-border h-20 resize-none overflow-auto border-none px-0 py-0.5 focus:outline-none"
|
||||
v-model="prompt"
|
||||
@keydown="handleSendByKeydown"
|
||||
@input="handlePromptInput"
|
||||
@@ -580,10 +580,10 @@ onMounted(async () => {
|
||||
@compositionend="onCompositionend"
|
||||
placeholder="问我任何问题...(Shift+Enter 换行,按下 Enter 发送)"
|
||||
></textarea>
|
||||
<div class="flex justify-between pb-0 pt-[5px]">
|
||||
<div class="flex justify-between pb-0 pt-1">
|
||||
<div class="flex items-center">
|
||||
<Switch v-model:checked="enableContext" />
|
||||
<span class="ml-[5px] text-[14px] text-[#8f8f8f]">上下文</span>
|
||||
<span class="ml-1 text-sm text-gray-400">上下文</span>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
@@ -591,13 +591,22 @@ onMounted(async () => {
|
||||
:loading="conversationInProgress"
|
||||
v-if="conversationInProgress === false"
|
||||
>
|
||||
<IconifyIcon
|
||||
:icon="
|
||||
conversationInProgress
|
||||
? 'lucide:loader'
|
||||
: 'lucide:send-horizontal'
|
||||
"
|
||||
/>
|
||||
{{ conversationInProgress ? '进行中' : '发送' }}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
danger
|
||||
@click="stopStream()"
|
||||
v-if="conversationInProgress === true"
|
||||
>
|
||||
<IconifyIcon icon="lucide:circle-stop" />
|
||||
停止
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user