feat: ai
This commit is contained in:
@@ -318,7 +318,7 @@ onMounted(async () => {
|
||||
type="primary"
|
||||
@click="createConversation"
|
||||
>
|
||||
<IconifyIcon icon="ep:plus" class="mr-[5px]" />
|
||||
<IconifyIcon icon="lucide:plus" class="mr-[5px]" />
|
||||
新建对话
|
||||
</Button>
|
||||
|
||||
@@ -330,7 +330,7 @@ onMounted(async () => {
|
||||
@keyup="searchConversation"
|
||||
>
|
||||
<template #prefix>
|
||||
<IconifyIcon icon="ep:search" />
|
||||
<IconifyIcon icon="lucide:search" />
|
||||
</template>
|
||||
</Input>
|
||||
|
||||
@@ -389,28 +389,28 @@ onMounted(async () => {
|
||||
type="link"
|
||||
@click.stop="handleTop(conversation)"
|
||||
>
|
||||
<span
|
||||
<IconifyIcon
|
||||
v-if="!conversation.pinned"
|
||||
class="icon-[ant-design--arrow-up-outlined]"
|
||||
></span>
|
||||
<span
|
||||
icon="lucide:arrow-up"
|
||||
/>
|
||||
<IconifyIcon
|
||||
v-if="conversation.pinned"
|
||||
class="icon-[ant-design--arrow-down-outlined]"
|
||||
></span>
|
||||
icon="lucide:arrow-down"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
class="btn mr-0 px-[5px]"
|
||||
type="link"
|
||||
@click.stop="updateConversationTitle(conversation)"
|
||||
>
|
||||
<IconifyIcon icon="ep:edit" />
|
||||
<IconifyIcon icon="lucide:edit" />
|
||||
</Button>
|
||||
<Button
|
||||
class="btn mr-0 px-[5px]"
|
||||
type="link"
|
||||
@click.stop="deleteChatConversation(conversation)"
|
||||
>
|
||||
<IconifyIcon icon="ep:delete" />
|
||||
<IconifyIcon icon="lucide:trash" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -430,14 +430,14 @@ onMounted(async () => {
|
||||
class="flex cursor-pointer items-center text-[#606266]"
|
||||
@click="handleRoleRepository"
|
||||
>
|
||||
<IconifyIcon icon="ep:user" />
|
||||
<IconifyIcon icon="lucide:user" />
|
||||
<span class="ml-[5px]">角色仓库</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex cursor-pointer items-center text-[#606266]"
|
||||
@click="handleClearConversation"
|
||||
>
|
||||
<IconifyIcon icon="ep:delete" />
|
||||
<IconifyIcon icon="lucide:trash" />
|
||||
<span class="ml-[5px]">清空未置顶对话</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -60,7 +60,7 @@ function handleClick(doc: any) {
|
||||
class="mt-[10px] rounded-[8px] bg-[#f5f5f5] p-[10px]"
|
||||
>
|
||||
<div class="text-14px mb-8px flex items-center text-[#666]">
|
||||
<IconifyIcon icon="ep:document" class="mr-[5px]" /> 知识引用
|
||||
<IconifyIcon icon="lucide:file-text" class="mr-[5px]" /> 知识引用
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-[8px]">
|
||||
<div
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { AiChatMessageApi } from '#/api/ai/chat/message';
|
||||
|
||||
import { computed, nextTick, onMounted, ref, toRefs } from 'vue';
|
||||
|
||||
import { IconifyIcon, SvgGptIcon } from '@vben/icons';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { useUserStore } from '@vben/stores';
|
||||
import { formatDate } from '@vben/utils';
|
||||
@@ -41,9 +42,6 @@ const isScrolling = ref(false); // 用于判断用户是否在滚动
|
||||
const userAvatar = computed(
|
||||
() => userStore.userInfo?.avatar || preferences.app.defaultAvatar,
|
||||
);
|
||||
const roleAvatar = computed(
|
||||
() => props.conversation.roleAvatar ?? '/static/gpt.svg',
|
||||
);
|
||||
|
||||
const { list } = toRefs(props); // 定义 emits
|
||||
|
||||
@@ -121,7 +119,11 @@ onMounted(async () => {
|
||||
<!-- 左侧消息:system、assistant -->
|
||||
<div v-if="item.type !== 'user'" class="flex flex-row">
|
||||
<div class="avatar">
|
||||
<Avatar :src="roleAvatar" />
|
||||
<Avatar
|
||||
v-if="conversation.roleAvatar"
|
||||
:src="conversation.roleAvatar"
|
||||
/>
|
||||
<SvgGptIcon v-else class="size-8" />
|
||||
</div>
|
||||
<div class="mx-[15px] flex flex-col text-left">
|
||||
<div class="text-left leading-[30px]">
|
||||
@@ -142,7 +144,7 @@ onMounted(async () => {
|
||||
type="text"
|
||||
@click="copyContent(item.content)"
|
||||
>
|
||||
<img class="h-[20px]" src="/static/copy.svg" />
|
||||
<IconifyIcon icon="lucide:copy" />
|
||||
</Button>
|
||||
<Button
|
||||
v-if="item.id > 0"
|
||||
@@ -150,7 +152,7 @@ onMounted(async () => {
|
||||
type="text"
|
||||
@click="onDelete(item.id)"
|
||||
>
|
||||
<img class="h-[17px]" src="/static/delete.svg" />
|
||||
<IconifyIcon icon="lucide:trash" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -178,28 +180,28 @@ onMounted(async () => {
|
||||
type="text"
|
||||
@click="copyContent(item.content)"
|
||||
>
|
||||
<img class="h-[20px]" src="/static/copy.svg" />
|
||||
<IconifyIcon icon="lucide:copy" />
|
||||
</Button>
|
||||
<Button
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
type="text"
|
||||
@click="onDelete(item.id)"
|
||||
>
|
||||
<img class="h-[17px]" src="/static/delete.svg" />
|
||||
<IconifyIcon icon="lucide:trash" />
|
||||
</Button>
|
||||
<Button
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
type="text"
|
||||
@click="onRefresh(item)"
|
||||
>
|
||||
<span class="icon-[ant-design--redo-outlined]"></span>
|
||||
<IconifyIcon icon="lucide:refresh-cw" />
|
||||
</Button>
|
||||
<Button
|
||||
class="flex items-center bg-transparent px-[5px] hover:bg-[#f6f6f6]"
|
||||
type="text"
|
||||
@click="onEdit(item)"
|
||||
>
|
||||
<span class="icon-[ant-design--form-outlined]"></span>
|
||||
<IconifyIcon icon="lucide:edit" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -214,7 +216,7 @@ onMounted(async () => {
|
||||
@click="handleGoBottom"
|
||||
>
|
||||
<Button shape="circle">
|
||||
<span class="icon-[ant-design--down-outlined]"></span>
|
||||
<IconifyIcon icon="lucide:chevron-down" />
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -27,7 +27,7 @@ async function handleCategoryClick(category: string) {
|
||||
<template>
|
||||
<div class="flex flex-wrap items-center">
|
||||
<div
|
||||
class="mr-[10px] flex flex-row"
|
||||
class="mr-2 flex flex-row"
|
||||
v-for="category in categoryList"
|
||||
:key="category"
|
||||
>
|
||||
|
||||
@@ -86,19 +86,19 @@ async function handleTabsScroll() {
|
||||
<div v-if="showMore" class="absolute right-[12px] top-0">
|
||||
<Dropdown>
|
||||
<Button type="text">
|
||||
<span class="icon-[ant-design--more-outlined] text-2xl"></span>
|
||||
<IconifyIcon icon="lucide:ellipsis-vertical" />
|
||||
</Button>
|
||||
<template #overlay>
|
||||
<Menu>
|
||||
<Menu.Item @click="handleMoreClick(['edit', role])">
|
||||
<div class="flex items-center">
|
||||
<IconifyIcon icon="ep:edit" color="#787878" />
|
||||
<IconifyIcon icon="lucide:edit" color="#787878" />
|
||||
<span>编辑</span>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
<Menu.Item @click="handleMoreClick(['delete', role])">
|
||||
<div class="flex items-center">
|
||||
<IconifyIcon icon="ep:delete" color="red" />
|
||||
<IconifyIcon icon="lucide:trash" color="red" />
|
||||
<span class="text-red-500">编辑</span>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useRouter } from 'vue-router';
|
||||
import { useVbenDrawer, useVbenModal } from '@vben/common-ui';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Button, Input, Layout, TabPane, Tabs } from 'ant-design-vue';
|
||||
import { Button, Input, Layout, Tabs } from 'ant-design-vue';
|
||||
|
||||
import { createChatConversationMy } from '#/api/ai/chat/conversation';
|
||||
import { deleteMy, getCategoryList, getMyPage } from '#/api/ai/model/chatRole';
|
||||
@@ -194,7 +194,7 @@ onMounted(async () => {
|
||||
@click="handlerAddRole"
|
||||
class="ml-[20px]"
|
||||
>
|
||||
<IconifyIcon icon="ep:user" style="margin-right: 5px" />
|
||||
<IconifyIcon icon="lucide:user" style="margin-right: 5px" />
|
||||
添加角色
|
||||
</Button>
|
||||
</div>
|
||||
@@ -205,7 +205,7 @@ onMounted(async () => {
|
||||
class="relative h-full p-4"
|
||||
@tab-click="handleTabsClick"
|
||||
>
|
||||
<TabPane
|
||||
<Tabs.TabPane
|
||||
key="my-role"
|
||||
class="flex h-full flex-col overflow-y-auto"
|
||||
tab="我的角色"
|
||||
@@ -220,9 +220,9 @@ onMounted(async () => {
|
||||
@on-page="handlerCardPage('my')"
|
||||
class="mt-[20px]"
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs.TabPane>
|
||||
|
||||
<TabPane
|
||||
<Tabs.TabPane
|
||||
key="public-role"
|
||||
class="flex h-full flex-col overflow-y-auto"
|
||||
tab="公共角色"
|
||||
@@ -242,7 +242,7 @@ onMounted(async () => {
|
||||
class="mt-[20px]"
|
||||
loading
|
||||
/>
|
||||
</TabPane>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
|
||||
@@ -521,32 +521,21 @@ onMounted(async () => {
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
class="mr-[10px] px-[10px]"
|
||||
class="mr-2 px-2"
|
||||
size="small"
|
||||
@click="openChatConversationUpdateForm"
|
||||
>
|
||||
<span v-html="activeConversation?.modelName"></span>
|
||||
<IconifyIcon icon="ep:setting" class="ml-[10px]" />
|
||||
<IconifyIcon icon="lucide:settings" class="ml-2" />
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
class="mr-[10px] px-[10px]"
|
||||
@click="handlerMessageClear"
|
||||
>
|
||||
<IconifyIcon
|
||||
icon="heroicons-outline:archive-box-x-mark"
|
||||
color="#787878"
|
||||
/>
|
||||
<Button size="small" class="mr-2 px-2" @click="handlerMessageClear">
|
||||
<IconifyIcon icon="lucide:trash" color="#787878" />
|
||||
</Button>
|
||||
<Button size="small" class="mr-[10px] px-[10px]">
|
||||
<IconifyIcon icon="ep:download" color="#787878" />
|
||||
<Button size="small" class="mr-2 px-2">
|
||||
<IconifyIcon icon="lucide:download" color="#787878" />
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
class="mr-[10px] px-[10px]"
|
||||
@click="handleGoTopMessage"
|
||||
>
|
||||
<IconifyIcon icon="ep:top" color="#787878" />
|
||||
<Button size="small" class="mr-2 px-2" @click="handleGoTopMessage">
|
||||
<IconifyIcon icon="lucide:arrow-up" color="#787878" />
|
||||
</Button>
|
||||
</div>
|
||||
</Layout.Header>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ref } from 'vue';
|
||||
|
||||
import { DocAlert, Page } from '@vben/common-ui';
|
||||
|
||||
import { Card, TabPane, Tabs } from 'ant-design-vue';
|
||||
import { Card, Tabs } from 'ant-design-vue';
|
||||
|
||||
import ChatConversationList from './modules/ChatConversationList.vue';
|
||||
import ChatMessageList from './modules/ChatMessageList.vue';
|
||||
@@ -18,12 +18,12 @@ const activeTabName = ref('conversation');
|
||||
</template>
|
||||
<Card>
|
||||
<Tabs v-model:active-key="activeTabName">
|
||||
<TabPane tab="对话列表" key="conversation">
|
||||
<Tabs.TabPane tab="对话列表" key="conversation">
|
||||
<ChatConversationList />
|
||||
</TabPane>
|
||||
<TabPane tab="消息列表" key="message">
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab="消息列表" key="message">
|
||||
<ChatMessageList />
|
||||
</TabPane>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Card>
|
||||
</Page>
|
||||
|
||||
@@ -87,9 +87,10 @@ onMounted(async () => {
|
||||
<TableAction :actions="[]" />
|
||||
</template>
|
||||
<template #userId="{ row }">
|
||||
<span>{{
|
||||
userList.find((item) => item.id === row.userId)?.nickname
|
||||
}}</span>
|
||||
<span>
|
||||
{{ userList.find((item) => item.id === row.userId)?.nickname }}
|
||||
</span>
|
||||
<span v-if="row.userId === 0">系统</span>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<TableAction
|
||||
|
||||
Reference in New Issue
Block a user