feat(@vben/web-antd): 优化部分功能

This commit is contained in:
Kven 2025-05-14 19:48:01 +08:00
parent d860741384
commit dcafd5e3b0
13 changed files with 217 additions and 115 deletions

View File

@ -1,6 +1,6 @@
import type { RouteRecordRaw } from 'vue-router';
import { EosRole, IconSystem, MdiUser, RiDept } from '@vben/icons';
import { EosRole, IconLog, IconSystem, MdiUser, RiDept } from '@vben/icons';
const routes: RouteRecordRaw[] = [
{
@ -48,7 +48,7 @@ const routes: RouteRecordRaw[] = [
path: '/system/log',
component: () => import('#/views/log/list.vue'),
meta: {
icon: MdiUser,
icon: IconLog,
title: '系统日志',
authority: ['system'],
},

View File

@ -5,6 +5,8 @@ import { onMounted, reactive, ref } from 'vue';
import { PptHistoryView, PptListView, PptWorkView } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { getWorkflowInfo, getWorkflowList, sendWorkflow } from '#/api';
let temp = reactive<PPTTempItem>({
@ -57,6 +59,7 @@ async function handleClick(item: PPTTempItem) {
}
async function handleClickMode(item: PPTTempItem) {
message.success(`已选取${item.name}为模板`);
temp = item;
}
@ -66,9 +69,9 @@ onMounted(() => {
</script>
<template>
<div class="px-5">
<div class="mt-5 flex flex-col lg:flex-row">
<div class="mr-4 w-full lg:w-1/4">
<div class="pr-5" style="height: calc(100vh - 80px)">
<div class="flex h-full flex-col lg:flex-row">
<div class="mr-4 w-full lg:w-1/6">
<PptHistoryView
:loading="loading"
:items="hitsory"
@ -77,7 +80,7 @@ onMounted(() => {
/>
<PptListView title="选择模板" @click="handleClickMode" />
</div>
<div class="w-full lg:w-3/4">
<div class="h-full w-full lg:w-5/6">
<PptWorkView
:item="temp"
:run-workflow="sendWorkflow"

View File

@ -12,6 +12,10 @@ const spiderList = ref<SpiderItem[]>([
id: 'a2a55334-a111-45e6-942f-9f3f70af8826',
name: '全国公共资源交易平台_数据爬取',
},
{
id: 'c736edd0-925d-4877-9223-56aab7342311',
name: '广州公共资源交易中心',
},
]);
const spider = ref<SpiderItem>();
@ -35,14 +39,14 @@ function handleClick(item: SpiderItem) {
<template>
<div class="px-5">
<div class="mt-5 flex flex-col lg:flex-row">
<div class="mr-4 w-full lg:w-1/4">
<div class="mr-4 w-full lg:w-1/5">
<SpiderListView
:items="spiderList"
title="数据爬取工具"
@click="handleClick"
/>
</div>
<div class="w-full lg:w-3/4">
<div class="w-full lg:w-4/5">
<SpiderWorkView
:item="spider"
:run-spider="sendWorkflow"

View File

@ -5,6 +5,8 @@ import { onMounted, reactive, ref } from 'vue';
import { WordHistoryView, WordListView, WordWorkView } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { getChatList, sendChatflow } from '#/api';
let temp = reactive<WordTempItem>({
@ -37,7 +39,13 @@ const getLogs = async (appid: string) => {
loading.value = false;
};
function handleClickMode(item: WordTempItem) {
message.success(`已选取${item.name}为模板`);
temp = item;
}
function handleClick(item: WordTempItem) {
message.error('暂不支持查看历史');
temp = item;
}
@ -47,18 +55,18 @@ onMounted(() => {
</script>
<template>
<div class="px-5">
<div class="mt-5 flex flex-col lg:flex-row">
<div class="mr-4 w-full lg:w-1/4">
<div class="pr-5" style="height: calc(100vh - 80px)">
<div class="flex h-full flex-col lg:flex-row">
<div class="mr-4 w-full lg:w-1/6">
<WordHistoryView
:loading="loading"
:items="hitsory"
title="运行历史"
@click="handleClick"
/>
<WordListView title="选择模板" @click="handleClick" />
<WordListView title="选择模板" @click="handleClickMode" />
</div>
<div class="w-full lg:w-3/4">
<div class="h-full w-full lg:w-5/6">
<WordWorkView :item="temp" :run-chatflow="sendChatflow" />
</div>
</div>

View File

@ -23,9 +23,7 @@ defineEmits(['click']);
</script>
<template>
<Card
style="height: calc(55vh - 120px); margin-bottom: 20px; overflow-y: auto"
>
<Card style="height: 45vh; overflow-y: auto; border-radius: 0">
<CardHeader class="py-4">
<CardTitle class="text-lg">运行历史</CardTitle>
</CardHeader>

View File

@ -18,7 +18,7 @@ const items: PPTTempItem[] = [
</script>
<template>
<Card style="height: calc(55vh - 120px); overflow-y: auto">
<Card style="height: 50vh; overflow-y: auto; border-radius: 0">
<CardHeader class="py-4">
<CardTitle class="text-lg">选择模板</CardTitle>
</CardHeader>

View File

@ -12,9 +12,8 @@ import { useVbenDrawer } from '@vben/common-ui';
import { Card } from '@vben-core/shadcn-ui';
import { UserOutlined } from '@ant-design/icons-vue';
import { Button, Flex, Typography } from 'ant-design-vue';
import { Button, Flex } from 'ant-design-vue';
import { Attachments, BubbleList, Sender } from 'ant-design-x-vue';
import markdownit from 'markdown-it';
import PptPreview from './ppt-perview.vue';
@ -69,24 +68,6 @@ const props = withDefaults(defineProps<Props>(), {
}),
});
// markdown
const md = markdownit({ html: true, breaks: true });
const renderMarkdown: BubbleListProps['roles'][string]['messageRender'] = (
content: string,
) => {
return h(Typography, [
h('div', {
innerHTML: content,
style: {
padding: '8px',
lineHeight: '1.6',
whiteSpace: 'break-spaces',
},
}),
]);
};
const [PreviewDrawer, previewDrawerApi] = useVbenDrawer({
//
connectedComponent: PptPreview,
@ -134,6 +115,7 @@ const startFetching = async () => {
},
);
const { result } = res.data.outputs;
value.value = '';
const filename = ref('');
@ -209,17 +191,6 @@ const roles: BubbleListProps['roles'] = {
},
},
avatar: { icon: h(UserOutlined), style: { background: '#fde3cf' } },
messageRender: (content) =>
h(Typography, [
h('div', {
innerHTML: md.render(content),
style: {
padding: '8px',
lineHeight: '1.6',
whiteSpace: 'break-spaces',
},
}),
]),
},
file: {
placement: 'start',
@ -316,14 +287,14 @@ watch(
</script>
<template>
<div>
<div style="display: flex; flex-direction: column" class="h-full">
<PreviewDrawer />
<div style="height: calc(67vh - 120px); margin: 20px; overflow-y: auto">
<div style="flex: 1; padding: 20px; overflow-y: auto">
<BubbleList
variant="shadow"
:roles="roles"
:typing="true"
:items="resultItems"
:message-render="renderMarkdown"
/>
</div>
<Card class="w-full">
@ -331,9 +302,15 @@ watch(
v-model:value="value"
:loading="isFetching"
:disabled="isFetching"
:auto-size="{ minRows: 6, maxRows: 12 }"
:auto-size="{ minRows: 1, maxRows: 12 }"
@submit="startFetching"
/>
</Card>
</div>
</template>
<style scoped>
.markdown-content p:empty {
display: none;
}
</style>

View File

@ -13,7 +13,11 @@ import {
} from '@vben-core/shadcn-ui';
import { message, RangePicker } from 'ant-design-vue';
import dayjs from 'dayjs';
import dayjs, { Dayjs } from 'dayjs';
// import {Attachments, BubbleList, type BubbleListProps} from "ant-design-x-vue";
// import {UserOutlined} from "@ant-design/icons-vue";
// import PptPreview from "../ppt/ppt-perview.vue";
// import {type DrawerPlacement, useVbenDrawer} from "@vben-core/popup-ui";
interface SpiderParams {
appid: string;
@ -34,6 +38,13 @@ interface SpiderResult {
};
}
// interface ResultItem {
// key: number;
// role: 'ai' | 'user';
// content: string;
// footer?: any;
// }
interface Props {
item?: SpiderItem;
title: string;
@ -60,7 +71,40 @@ const props = withDefaults(defineProps<Props>(), {
}),
});
const selectedDateRange = ref<string[]>([]);
// const resultItems = ref<ResultItem[]>([]);
// const [PreviewDrawer, previewDrawerApi] = useVbenDrawer({
// //
// connectedComponent: PptPreview,
// // placement: 'left',
// });
// function openPreviewDrawer(
// placement: DrawerPlacement = 'right',
// filename?: string,
// ) {
// const fileData = filename.value;
// previewDrawerApi.setState({ placement }).setData(fileData).open();
// }
const selectedDateRange = ref<[Dayjs, Dayjs]>([
dayjs('2025-05-05'),
dayjs('2025-05-07'),
]);
// .docx URL
// function isDocxURL(str: string): boolean {
// return str.endsWith('.docx');
// }
//
// // 使 /static/
// function extractDocxFilename(url: string): null | string {
// const match = url.match(/\/static\/([a-f0-9-]+\.docx)$/i);
// if (match) {
// return match[1]; // 9e1c421e-991c-411f-8176-6350a97e70f3.docx
// }
// return null;
// }
const startFetching = async () => {
//
@ -100,6 +144,54 @@ const startFetching = async () => {
fetchResult.value = '';
message.error('抓取无结果');
}
// const { result } = res.data.outputs;
//
// const filename = ref('');
//
// if (result && isDocxURL(result)) {
// filename.value = extractDocxFilename(result);
// }
//
// // url http://47.112.173.8:6802/static/66f3cfd95e364a239d8036390db658ae.docx
// fetchResult.value = `/static/${filename.value}`;
// resultItems.value.push({
// key: resultItems.value.length + 1,
// role: 'ai',
// content: '',
// footer: h(Flex, null, [
// h(
// Button,
// {
// size: 'nomarl',
// type: 'primary',
// onClick: () => {
// openPreviewDrawer('right', filename);
// },
// },
// '',
// ),
// h(
// Button,
// {
// size: 'nomarl',
// type: 'primary',
// style: {
// marginLeft: '10px',
// },
// onClick: () => {
// // <a>
// const link = document.createElement('a');
// link.href = result; //
// link.download = filename; //
// document.body.append(link); // <a>
// link.click(); //
// link.remove(); // <a>
// },
// },
// '',
// ),
// ]),
// });
} catch (error) {
console.error(error);
}
@ -127,13 +219,59 @@ const downloadFile = () => {
link.click();
};
//
// const roles: BubbleListProps['roles'] = {
// user: {
// placement: 'end',
// typing: false,
// avatar: { icon: h(UserOutlined), style: { background: '#87d068' } },
// },
// ai: {
// placement: 'start',
// typing: false,
// style: {
// maxWidth: 600,
// marginInlineEnd: 44,
// },
// styles: {
// footer: {
// width: '100%',
// },
// },
// avatar: { icon: h(UserOutlined), style: { background: '#fde3cf' } },
// },
// file: {
// placement: 'start',
// avatar: { icon: h(UserOutlined), style: { visibility: 'hidden' } },
// variant: 'borderless',
// messageRender: (items: any) =>
// h(
// Flex,
// { vertical: true, gap: 'middle' },
// items.map((item: any) =>
// h(Attachments.FileCard, { key: item.uid, item }),
// ),
// ),
// },
// };
const isFetching = ref(false);
const fetchResult = ref('');
const fetchStatus = ref('');
</script>
<template>
<!-- style="flex-direction: column"-->
<div class="flex h-full">
<!-- <PreviewDrawer />-->
<!-- <div style="flex:1; padding: 20px; overflow-y: auto">-->
<!-- <BubbleList-->
<!-- variant="shadow"-->
<!-- :roles="roles"-->
<!-- :typing="true"-->
<!-- :items="resultItems"-->
<!-- />-->
<!-- </div>-->
<Card class="w-full self-end" v-loading="isFetching">
<CardHeader class="py-4">
<CardTitle class="text-lg">{{ title }}</CardTitle>

View File

@ -4,6 +4,7 @@ interface WordTempItem {
}
interface WordHistoryItem {
name: string;
id: string;
workflowRun: {
id: string;

View File

@ -21,9 +21,7 @@ defineEmits(['click']);
</script>
<template>
<Card
style="height: calc(55vh - 120px); margin-bottom: 20px; overflow-y: auto"
>
<Card style="height: 45vh; overflow-y: auto; border-radius: 0">
<CardHeader class="py-4">
<CardTitle class="text-lg">运行历史</CardTitle>
</CardHeader>
@ -35,7 +33,7 @@ defineEmits(['click']);
@click="$emit('click', item)"
class="flex cursor-pointer justify-between gap-x-6 py-5"
>
{{ item.id }}
{{ item.name }}
</li>
</ul>
</CardContent>

View File

@ -18,7 +18,7 @@ const items: WordTempItem[] = [
</script>
<template>
<Card style="height: calc(55vh - 120px); overflow-y: auto">
<Card style="height: 50vh; overflow-y: auto; border-radius: 0">
<CardHeader class="py-4">
<CardTitle class="text-lg">选择模板</CardTitle>
</CardHeader>

View File

@ -12,7 +12,7 @@ import { useVbenDrawer } from '@vben/common-ui';
import { Card } from '@vben-core/shadcn-ui';
import { UserOutlined } from '@ant-design/icons-vue';
import { Button, Flex, Typography } from 'ant-design-vue';
import { Button, Flex, message, Typography } from 'ant-design-vue';
import { Attachments, BubbleList, Sender } from 'ant-design-x-vue';
import markdownit from 'markdown-it';
@ -33,6 +33,8 @@ interface WorkflowContext {
}
interface WorkflowResult {
conversationId: string;
answer: {};
data: {
outputs: {
result: string;
@ -73,7 +75,7 @@ const renderMarkdown: BubbleListProps['roles'][string]['messageRender'] = (
h('div', {
innerHTML: content,
style: {
padding: '8px',
// padding: '8px',
lineHeight: '1.6',
whiteSpace: 'break-spaces',
},
@ -81,6 +83,8 @@ const renderMarkdown: BubbleListProps['roles'][string]['messageRender'] = (
]);
};
const conversationId = ref('');
const [PreviewDrawer, previewDrawerApi] = useVbenDrawer({
//
connectedComponent: WordPreview,
@ -93,8 +97,15 @@ function openPreviewDrawer(
const fileData = filename.value;
previewDrawerApi.setState({ placement }).setData(fileData).open();
}
const inputStatus = ref<string>('');
const startFetching = async () => {
//
if (!projectName.value.trim()) {
inputStatus.value = 'error';
message.error('请输入项目名称');
return;
}
isFetching.value = true;
fetchStatus.value = 'fetching';
resultItems.value.push({
@ -104,28 +115,13 @@ const startFetching = async () => {
});
try {
// const res = await props.runWorkflow(
// {
// appid: props.item.id,
// },
// {
// userId: '1562',
// conversationId: '',
// files: [],
// inputs: {
// declarationDoc: value.value,
// },
// },
// );
// url
const res = await props.runChatflow(
{
appid: 'baca08c1-e92b-4dc9-a445-3584803f54d4',
},
{
userId: '1562',
conversationId: '',
conversationId: conversationId.value,
files: [],
inputs: {
projectName: projectName.value,
@ -133,7 +129,9 @@ const startFetching = async () => {
content: value.value || '',
},
);
value.value = '';
const { answer } = res;
conversationId.value = res.conversationId;
// .docx URL
function isDocxURL(str: string): boolean {
@ -200,36 +198,6 @@ const startFetching = async () => {
}
fetchResult.value = `/static/${filename.value}`;
// resultItems.value.push({
// key: resultItems.value.length + 1,
// role: 'ai',
// content: '',
// footer: h(Flex, null, [
// h(
// Button,
// {
// size: 'nomarl',
// type: 'primary',
// onClick: () => {
// openPreviewDrawer('right');
// },
// },
// '',
// ),
// h(
// Button,
// {
// size: 'nomarl',
// type: 'primary',
// style: {
// marginLeft: '10px',
// },
// onClick: () => {},
// },
// '',
// ),
// ]),
// });
} catch (error) {
console.error(error);
}
@ -263,7 +231,7 @@ const roles: BubbleListProps['roles'] = {
h('div', {
innerHTML: md.render(content),
style: {
padding: '8px',
// padding: '8px',
lineHeight: '1.6',
whiteSpace: 'break-spaces',
},
@ -306,12 +274,17 @@ const resultItems = ref<ResultItem[]>([]);
</script>
<template>
<div>
<div style="display: flex; flex-direction: column" class="h-full">
<PreviewDrawer />
<a-space class="w-full" direction="vertical">
<a-input v-model:value="projectName" required placeholder="项目名称" />
<a-space class="w-full" direction="vertical" style="padding-top: 20px">
<a-input
v-model:value="projectName"
required
placeholder="项目名称"
:status="inputStatus"
/>
</a-space>
<div style="height: calc(67vh - 180px); margin: 20px; overflow-y: auto">
<div style="flex: 1; padding: 20px; overflow-y: auto">
<BubbleList
:roles="roles"
:typing="true"
@ -319,7 +292,7 @@ const resultItems = ref<ResultItem[]>([]);
:message-render="renderMarkdown"
/>
</div>
<Flex wrap="wrap" :gap="12">
<Flex wrap="wrap" :gap="12" class="w-full" style="align-items: flex-end">
<Button @click="insertTextToInput('生成项目摘要')">生成项目摘要</Button>
<Button @click="insertTextToInput('生成目前存在问题')">
生成目前存在问题
@ -344,7 +317,7 @@ const resultItems = ref<ResultItem[]>([]);
v-model:value="value"
:loading="isFetching"
:disabled="isFetching"
:auto-size="{ minRows: 6, maxRows: 12 }"
:auto-size="{ minRows: 1, maxRows: 12 }"
@submit="startFetching"
/>
</Card>

View File

@ -16,4 +16,6 @@ export const MageRobot = createIconifyIcon('mage:robot');
export const RiDept = createIconifyIcon('ri:door-open-line');
export const EosRole = createIconifyIcon('eos-icons:role-binding-outlined');
export const IconSystem = createIconifyIcon('icon-park-twotone:system');
export const MaterPerson = createIconifyIcon('material-symbols:person');
export const IconLog = createIconifyIcon('icon-park-outline:log');
// export const MdiUser = createIconifyIcon('mdi:user');