pull/146/head^2
xingyu4j 2025-06-16 19:17:15 +08:00
parent 014785a1ad
commit e219e8f868
39 changed files with 175 additions and 138 deletions

View File

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715352878351" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1499" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M624.5 786.3c92.9 0 168.2-75.3 168.2-168.2V309c0-92.4-75.3-168.2-168.2-168.2H303.6c-92.4 0-168.2 75.3-168.2 168.2v309.1c0 92.4 75.3 168.2 168.2 168.2h320.9zM178.2 618.1V309c0-69.4 56.1-125.5 125.5-125.5h320.9c69.4 0 125.5 56.1 125.5 125.5v309.1c0 69.4-56.1 125.5-125.5 125.5h-321c-69.4 0-125.4-56.1-125.4-125.5z" p-id="1500" fill="#8a8a8a"></path><path d="M849.8 295.1v361.5c0 102.7-83.6 186.3-186.3 186.3H279.1v42.7h384.4c126.3 0 229.1-102.8 229.1-229.1V295.1h-42.8zM307.9 361.8h312.3c11.8 0 21.4-9.6 21.4-21.4 0-11.8-9.6-21.4-21.4-21.4H307.9c-11.8 0-21.4 9.6-21.4 21.4 0 11.9 9.6 21.4 21.4 21.4zM307.9 484.6h312.3c11.8 0 21.4-9.6 21.4-21.4 0-11.8-9.6-21.4-21.4-21.4H307.9c-11.8 0-21.4 9.6-21.4 21.4 0 11.9 9.6 21.4 21.4 21.4z" p-id="1501" fill="#8a8a8a"></path><path d="M620.2 607.4c11.8 0 21.4-9.6 21.4-21.4 0-11.8-9.6-21.4-21.4-21.4H307.9c-11.8 0-21.4 9.6-21.4 21.4 0 11.8 9.6 21.4 21.4 21.4h312.3z" p-id="1502" fill="#8a8a8a"></path></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715354120346" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3256" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M907.1 263.7H118.9c-9.1 0-16.4-7.3-16.4-16.4s7.3-16.4 16.4-16.4H907c9.1 0 16.4 7.3 16.4 16.4s-7.3 16.4-16.3 16.4z" fill="#8a8a8a" p-id="3257"></path><path d="M772.5 928.3H257.4c-27.7 0-50.2-22.5-50.2-50.2V247.2c0-9.1 7.3-16.4 16.4-16.4H801c12.1 0 21.9 9.8 21.9 21.9v625.2c0 27.8-22.6 50.4-50.4 50.4zM240 263.7v614.4c0 9.6 7.8 17.4 17.4 17.4h515.2c9.7 0 17.5-7.9 17.5-17.5V263.7H240zM657.4 131.1H368.6c-9.1 0-16.4-7.3-16.4-16.4s7.3-16.4 16.4-16.4h288.7c9.1 0 16.4 7.3 16.4 16.4s-7.3 16.4-16.3 16.4z" fill="#8a8a8a" p-id="3258"></path><path d="M416 754.5c-9.1 0-16.4-7.3-16.4-16.4V517.8c0-9.1 7.3-16.4 16.4-16.4s16.4 7.3 16.4 16.4V738c0.1 9.1-7.3 16.5-16.4 16.5z" fill="#8a8a8a" p-id="3259"></path><path d="M416 465.2c-9.1 0-16.4-7.3-16.4-16.4v-59.4c0-9.1 7.3-16.4 16.4-16.4s16.4 7.3 16.4 16.4v59.4c0.1 9.1-7.3 16.4-16.4 16.4zM604.9 754.5c-9.1 0-16.4-7.3-16.4-16.4v-67.2c0-9.1 7.3-16.4 16.4-16.4s16.4 7.3 16.4 16.4V738c0 9.1-7.3 16.5-16.4 16.5z" fill="#8a8a8a" opacity=".4" p-id="3260"></path><path d="M604.9 619.1c-9.1 0-16.4-7.3-16.4-16.4V389.4c0-9.1 7.3-16.4 16.4-16.4s16.4 7.3 16.4 16.4v213.3c0 9.1-7.3 16.4-16.4 16.4z" fill="#8a8a8a" p-id="3261"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View File

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -365,12 +365,12 @@ export const Dall3Models: ImageModelVO[] = [
{
key: 'dall-e-3',
name: 'DALL·E 3',
image: `/static/dall2.jpg`,
image: `/static/imgs/ai/dall2.jpg`,
},
{
key: 'dall-e-2',
name: 'DALL·E 2',
image: `/static/dall3.jpg`,
image: `/static/imgs/ai/dall3.jpg`,
},
];
@ -378,12 +378,12 @@ export const Dall3StyleList: ImageModelVO[] = [
{
key: 'vivid',
name: '清晰',
image: `/static/qingxi.jpg`,
image: `/static/imgs/ai/qingxi.jpg`,
},
{
key: 'natural',
name: '自然',
image: `/static/ziran.jpg`,
image: `/static/imgs/ai/ziran.jpg`,
},
];
export const MidjourneyModels: ImageModelVO[] = [

View File

@ -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>

View File

@ -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

View File

@ -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 () => {
<!-- 左侧消息systemassistant -->
<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>

View File

@ -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"
>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -6,6 +6,7 @@ import type { AiImageApi } from '#/api/ai/image';
import { onMounted, ref, toRefs, watch } from 'vue';
import { confirm } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';
import { Button, Card, Image, message } from 'ant-design-vue';
@ -86,28 +87,28 @@ onMounted(async () => {
type="text"
@click="handleButtonClick('download', detail)"
>
<span class="icon-[ant-design--download-outlined]"></span>
<IconifyIcon icon="lucide:download" />
</Button>
<Button
class="m-0 p-[10px]"
type="text"
@click="handleButtonClick('regeneration', detail)"
>
<span class="icon-[ant-design--redo-outlined]"></span>
<IconifyIcon icon="lucide:refresh-cw" />
</Button>
<Button
class="m-0 p-[10px]"
type="text"
@click="handleButtonClick('delete', detail)"
>
<span class="icon-[ant-design--delete-outlined]"></span>
<IconifyIcon icon="lucide:trash" />
</Button>
<Button
class="m-0 p-[10px]"
type="text"
@click="handleButtonClick('more', detail)"
>
<span class="icon-[ant-design--more-outlined]"></span>
<IconifyIcon icon="lucide:ellipsis-vertical" />
</Button>
</div>
</div>

View File

@ -92,7 +92,9 @@ onMounted(async () => {
<template>
<Page auto-content-height>
<template #doc>
<DocAlert title="AI 绘图创作" url="https://doc.iocoder.cn/ai/image/" />
</template>
<Grid table-title="">
<template #toolbar-tools>
<TableAction :actions="[]" />
@ -101,9 +103,9 @@ onMounted(async () => {
<Image :src="row.picUrl" class="h-80px w-80px" />
</template>
<template #userId="{ row }">
<span>{{
userList.find((item) => item.id === row.userId)?.nickname
}}</span>
<span>
{{ userList.find((item) => item.id === row.userId)?.nickname }}
</span>
</template>
<template #publicStatus="{ row }">
<Switch

View File

@ -45,7 +45,7 @@ onMounted(async () => {
</script>
<template>
<Page auto-content-height>
<div class="bg-[#fff] p-[20px]">
<div class="bg-white p-[20px]">
<!-- TODO @fanSearch 可以换成 Icon 组件么 -->
<Input.Search
v-model="queryParams.prompt"
@ -55,14 +55,14 @@ onMounted(async () => {
@keyup.enter="handleQuery"
/>
<div
class="grid gap-[10px] bg-[#fff] shadow-[0_0_10px_rgba(0,0,0,0.1)]"
class="grid gap-[10px] bg-white shadow-[0_0_10px_rgba(0,0,0,0.1)]"
style="grid-template-columns: repeat(auto-fill, minmax(200px, 1fr))"
>
<!-- TODO @fan这个图片的风格要不和 ImageCard.vue 界面一致只有卡片没有操作因为看着更有相框的感觉~~~ -->
<div
v-for="item in list"
:key="item.id"
class="relative cursor-pointer overflow-hidden bg-[#f0f0f0] transition-transform duration-300 hover:scale-[1.05]"
class="relative cursor-pointer overflow-hidden bg-white transition-transform duration-300 hover:scale-[1.05]"
>
<img
:src="item.picUrl"

View File

@ -122,10 +122,10 @@ onBeforeUnmount(() => {
>
<!-- 文件图标和名称 -->
<div class="mr-[10px] flex min-w-[200px] items-center">
<IconifyIcon icon="ep:document" class="mr-8px text-[#409eff]" />
<span class="break-all text-[13px] text-[#303133]">{{
file.name
}}</span>
<IconifyIcon icon="lucide:file-text" class="mr-8px text-[#409eff]" />
<span class="break-all text-[13px] text-[#303133]">
{{ file.name }}
</span>
</div>
<!-- 处理进度 -->

View File

@ -176,7 +176,10 @@ onMounted(async () => {
<template #title>
系统会自动将文档内容分割成多个段落您可以根据需要调整分段方式和内容
</template>
<IconifyIcon icon="ep:warning" class="ml-[5px] text-gray-400" />
<IconifyIcon
icon="lucide:circle-alert"
class="ml-[5px] text-gray-400"
/>
</Tooltip>
</div>
<div>
@ -206,7 +209,7 @@ onMounted(async () => {
trigger="click"
>
<div class="flex cursor-pointer items-center">
<IconifyIcon icon="ep:document" class="text-danger mr-[5px]" />
<IconifyIcon icon="lucide:file-text" class="text-danger mr-[5px]" />
<span>{{ currentFile?.name || '请选择文件' }}</span>
<span
v-if="currentFile?.segments"
@ -214,7 +217,7 @@ onMounted(async () => {
>
({{ currentFile.segments.length }}个分片)
</span>
<IconifyIcon icon="ep:arrow-down" class="ml-[5px]" />
<IconifyIcon icon="lucide:chevron-down" class="ml-[5px]" />
</div>
<template #overlay>
<Menu>
@ -244,7 +247,7 @@ onMounted(async () => {
v-if="splitLoading"
class="flex items-center justify-center py-[20px]"
>
<IconifyIcon icon="ep:loading" class="is-loading" />
<IconifyIcon icon="lucide:loader" class="is-loading" />
<span class="ml-[10px]">正在加载分段内容...</span>
</div>
<template

View File

@ -231,7 +231,10 @@ onMounted(() => {
class="flex items-center justify-between rounded-sm border-l-4 border-l-[#409eff] px-[12px] py-[4px] shadow-sm transition-all duration-300 hover:bg-[#ecf5ff]"
>
<div class="flex items-center">
<IconifyIcon icon="ep:document" class="mr-[8px] text-[#409eff]" />
<IconifyIcon
icon="lucide:file-text"
class="mr-[8px] text-[#409eff]"
/>
<span class="break-all text-[13px] text-[#303133]">{{
file.name
}}</span>
@ -243,7 +246,7 @@ onMounted(() => {
@click="removeFile(index)"
class="ml-2"
>
<IconifyIcon icon="ep:delete" />
<IconifyIcon icon="lucide:trash" />
</Button>
</div>
</div>

View File

@ -104,7 +104,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template>
<Page auto-content-height>
<template #doc>
<DocAlert title="AI 手册" url="https://doc.iocoder.cn/ai/build/" />
</template>
<FormModal @success="onRefresh" />
<Grid table-title="AI ">
<template #toolbar-tools>

View File

@ -3,6 +3,7 @@ import { onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';
import {
Button,
@ -183,14 +184,18 @@ onMounted(() => {
</div>
<div class="flex items-center justify-between">
<div class="text-13 flex items-center text-gray-500">
<span class="ep:document mr-5"></span>
<IconifyIcon icon="lucide:file-text" class="mr-5" />
<span>{{ segment.documentName || '未知文档' }}</span>
</div>
<Button size="small" @click="toggleExpand(segment)">
{{ segment.expanded ? '收起' : '展开' }}
<span
class="mr-5"
:class="segment.expanded ? 'ep:arrow-up' : 'ep:arrow-down'"
:class="
segment.expanded
? 'lucide:chevron-up'
: 'lucide:chevron-down'
"
></span>
</Button>
</div>

View File

@ -1,6 +1,7 @@
<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { IconifyIcon } from '@vben/icons';
import {
MarkdownIt,
Markmap,
@ -126,7 +127,7 @@ defineExpose({
<Button type="primary" size="small" class="flex" @click="downloadImage">
<template #icon>
<div class="flex items-center justify-center">
<span class="icon-[ant-design--copy-twotone]"></span>
<IconifyIcon icon="lucide:copy" />
</div>
</template>
下载图片

View File

@ -90,7 +90,9 @@ onMounted(async () => {
<template>
<Page auto-content-height>
<template #doc>
<DocAlert title="AI 思维导图" url="https://doc.iocoder.cn/ai/mindmap/" />
</template>
<Drawer class="w-[800px]">
<Right
v-if="previewVisible"
@ -105,9 +107,9 @@ 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>
</template>
<template #actions="{ row }">
<TableAction

View File

@ -83,7 +83,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template>
<Page auto-content-height>
<template #doc>
<DocAlert title="AI 手册" url="https://doc.iocoder.cn/ai/build/" />
</template>
<FormModal @success="onRefresh" />
<Grid table-title="API ">
<template #toolbar-tools>

View File

@ -83,7 +83,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template>
<Page auto-content-height>
<template #doc>
<DocAlert title="AI 对话聊天" url="https://doc.iocoder.cn/ai/chat/" />
</template>
<FormModal @success="onRefresh" />
<Grid table-title="">
<template #toolbar-tools>

View File

@ -92,7 +92,9 @@ onMounted(async () => {
<template>
<Page auto-content-height>
<template #doc>
<DocAlert title="AI 手册" url="https://doc.iocoder.cn/ai/build/" />
</template>
<FormModal @success="onRefresh" />
<Grid table-title="">
<template #toolbar-tools>

View File

@ -83,10 +83,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template>
<Page auto-content-height>
<template #doc>
<DocAlert
title="AI 工具调用function calling"
url="https://doc.iocoder.cn/ai/tool/"
/>
</template>
<FormModal @success="onRefresh" />
<Grid table-title="">
<template #toolbar-tools>

View File

@ -92,7 +92,9 @@ onMounted(async () => {
<template>
<Page auto-content-height>
<template #doc>
<DocAlert title="AI 音乐创作" url="https://doc.iocoder.cn/ai/music/" />
</template>
<Grid table-title="">
<template #toolbar-tools>
<TableAction :actions="[]" />

View File

@ -75,7 +75,9 @@ onMounted(async () => {
<template>
<Page auto-content-height>
<template #doc>
<DocAlert title="AI 写作助手" url="https://doc.iocoder.cn/ai/write/" />
</template>
<Grid table-title="">
<template #toolbar-tools>
<TableAction :actions="[]" />

View File

@ -160,7 +160,9 @@ async function getApprovalDetail() {
: [];
}
}
} finally {}
} finally {
//
}
}
/** 审批相关:选择发起人 */
function selectUserConfirm(id: string, userList: any[]) {

View File

@ -111,10 +111,12 @@ function onRefresh() {
<template>
<Page auto-content-height>
<template #doc>
<DocAlert
title="审批接入(业务表单)"
url="https://doc.iocoder.cn/bpm/use-business-form/"
/>
</template>
<Grid table-title="">
<template #toolbar-tools>

View File

@ -102,10 +102,12 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template>
<Page auto-content-height>
<template #doc>
<DocAlert
title="流程发起、取消、重新发起"
url="https://doc.iocoder.cn/bpm/process-instance"
/>
</template>
<Grid table-title="">
<!-- 摘要 -->

View File

@ -4,6 +4,7 @@ import type { SystemUserApi } from '#/api/system/user';
import { computed, onMounted, ref, watchEffect } from 'vue';
import { DocAlert, Page } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';
import { useAccessStore } from '@vben/stores';
import { formatDate } from '@vben/utils';
@ -266,7 +267,7 @@ onMounted(async () => {
@click="handlerSend"
>
<template #icon>
<span class="i-ant-design:send-outlined mr-1"></span>
<IconifyIcon icon="lucide:send-horizontal" />
</template>
发送消息
</Button>
@ -276,7 +277,10 @@ onMounted(async () => {
<Card :bordered="false" class="w-full md:w-1/2">
<template #title>
<div class="flex items-center">
<span class="i-ant-design:message-outlined mr-2 text-lg"></span>
<IconifyIcon
icon="lucide:message-circle-more"
class="mr-2 text-lg"
/>
<span class="text-lg font-medium">消息记录</span>
<Tag v-if="messageList.length > 0" class="ml-2">
{{ messageList.length }}
@ -294,16 +298,16 @@ onMounted(async () => {
<div class="mb-1 flex items-center justify-between">
<div class="flex items-center">
<Badge :color="getMessageBadgeColor(msg.type)" />
<span class="ml-1 font-medium text-gray-600">{{
getMessageTypeText(msg.type)
}}</span>
<span class="ml-1 font-medium text-gray-600">
{{ getMessageTypeText(msg.type) }}
</span>
<span v-if="msg.userId" class="ml-2 text-gray-500">
用户 ID: {{ msg.userId }}
</span>
</div>
<span class="text-xs text-gray-400">{{
formatDate(msg.time)
}}</span>
<span class="text-xs text-gray-400">
{{ formatDate(msg.time) }}
</span>
</div>
<div class="mt-2 break-words text-gray-800">
{{ msg.text }}

View File

@ -91,6 +91,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<template>
<Page auto-content-height>
<template #doc>
<DocAlert
title="支付宝支付接入"
url="https://doc.iocoder.cn/pay/alipay-pay-demo/"
@ -107,6 +108,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
title="微信小程序支付接入"
url="https://doc.iocoder.cn/pay/wx-lite-pay-demo/"
/>
</template>
<FormModal @success="onRefresh" />
<Grid table-title="">

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -12,6 +12,9 @@ const SvgBellIcon = createIconifyIcon('svg:bell');
const SvgCakeIcon = createIconifyIcon('svg:cake');
const SvgAntdvLogoIcon = createIconifyIcon('svg:antdv-logo');
/** AI */
const SvgGptIcon = createIconifyIcon('svg:gpt');
/** 支付 */
const SvgAlipayPcIcon = createIconifyIcon('svg:alipay-pc');
const SvgAlipayWapIcon = createIconifyIcon('svg:alipay-wap');
@ -41,6 +44,7 @@ export {
SvgCakeIcon,
SvgCardIcon,
SvgDownloadIcon,
SvgGptIcon,
SvgMockIcon,
SvgWalletIcon,
SvgWxAppIcon,