diff --git a/apps/web-antd/src/api/ai/mindmap/index.ts b/apps/web-antd/src/api/ai/mindmap/index.ts index 69e437341..192b9950f 100644 --- a/apps/web-antd/src/api/ai/mindmap/index.ts +++ b/apps/web-antd/src/api/ai/mindmap/index.ts @@ -6,6 +6,7 @@ import { requestClient } from '#/api/request'; const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); const accessStore = useAccessStore(); + export namespace AiMindmapApi { // AI 思维导图 export interface MindMap { @@ -19,7 +20,7 @@ export namespace AiMindmapApi { } // AI 思维导图生成 - export interface AiMindMapGenerateReq { + export interface AiMindMapGenerateReqVO { prompt: string; } } @@ -32,7 +33,7 @@ export function generateMindMap({ ctrl, }: { ctrl: AbortController; - data: AiMindmapApi.AiMindMapGenerateReq; + data: AiMindmapApi.AiMindMapGenerateReqVO; onClose?: (...args: any[]) => void; onError?: (...args: any[]) => void; onMessage?: (res: any) => void; @@ -53,12 +54,12 @@ export function generateMindMap({ }); } -// 查询思维导图分页 +/** 查询思维导图分页 */ export function getMindMapPage(params: any) { return requestClient.get(`/ai/mind-map/page`, { params }); } -// 删除思维导图 +/** 删除思维导图 */ export function deleteMindMap(id: number) { return requestClient.delete(`/ai/mind-map/delete?id=${id}`); } diff --git a/apps/web-antd/src/views/ai/mindmap/index/index.vue b/apps/web-antd/src/views/ai/mindmap/index/index.vue index a859b663b..325268661 100644 --- a/apps/web-antd/src/views/ai/mindmap/index/index.vue +++ b/apps/web-antd/src/views/ai/mindmap/index/index.vue @@ -3,13 +3,15 @@ import type { AiMindmapApi } from '#/api/ai/mindmap'; import { nextTick, onMounted, ref } from 'vue'; -import { alert, Page } from '@vben/common-ui'; +import { Page } from '@vben/common-ui'; import { MindMapContentExample } from '@vben/constants'; +import { message } from 'ant-design-vue'; + import { generateMindMap } from '#/api/ai/mindmap'; -import Left from './modules/Left.vue'; -import Right from './modules/Right.vue'; +import Left from './modules/left.vue'; +import Right from './modules/right.vue'; const ctrl = ref(); // 请求控制 const isGenerating = ref(false); // 是否正在生成思维导图 @@ -26,8 +28,9 @@ function directGenerate(existPrompt: string) { generatedContent.value = existPrompt; isEnd.value = true; } + /** 提交生成 */ -function submit(data: AiMindmapApi.AiMindMapGenerateReq) { +function handleSubmit(data: AiMindmapApi.AiMindMapGenerateReqVO) { isGenerating.value = true; isStart.value = true; isEnd.value = false; @@ -38,8 +41,8 @@ function submit(data: AiMindmapApi.AiMindMapGenerateReq) { onMessage: async (res: any) => { const { code, data, msg } = JSON.parse(res.data); if (code !== 0) { - alert(`生成思维导图异常! ${msg}`); - stopStream(); + message.error(`生成思维导图异常! ${msg}`); + handleStopStream(); return; } generatedContent.value = generatedContent.value + data; @@ -49,19 +52,20 @@ function submit(data: AiMindmapApi.AiMindMapGenerateReq) { onClose() { isEnd.value = true; leftRef.value?.setGeneratedContent(generatedContent.value); - stopStream(); + handleStopStream(); }, onError(err) { console.error('生成思维导图失败', err); - stopStream(); + handleStopStream(); // 需要抛出异常,禁止重试 throw err; }, ctrl: ctrl.value, }); } + /** 停止 stream 生成 */ -function stopStream() { +function handleStopStream() { isGenerating.value = false; isStart.value = false; ctrl.value?.abort(); @@ -80,7 +84,7 @@ onMounted(() => { ref="leftRef" class="mr-4" :is-generating="isGenerating" - @submit="submit" + @submit="handleSubmit" @direct-generate="directGenerate" /> (); + const emits = defineEmits(['submit', 'directGenerate']); + const formData = reactive({ prompt: '', }); diff --git a/apps/web-antd/src/views/ai/mindmap/index/modules/Right.vue b/apps/web-antd/src/views/ai/mindmap/index/modules/right.vue similarity index 97% rename from apps/web-antd/src/views/ai/mindmap/index/modules/Right.vue rename to apps/web-antd/src/views/ai/mindmap/index/modules/right.vue index 58dcb63e7..a2537f393 100644 --- a/apps/web-antd/src/views/ai/mindmap/index/modules/Right.vue +++ b/apps/web-antd/src/views/ai/mindmap/index/modules/right.vue @@ -18,6 +18,7 @@ const props = defineProps<{ isGenerating: boolean; // 是否正在生成 isStart: boolean; // 开始状态,开始时需要清除 html }>(); + const md = MarkdownIt(); const contentRef = ref(); // 右侧出来 header 以下的区域 const mdContainerRef = ref(); // markdown 的容器,用来滚动到底下的 @@ -30,12 +31,14 @@ let markMap: Markmap | null = null; const transformer = new Transformer(); let resizeObserver: null | ResizeObserver = null; const initialized = false; + +/** 初始化 */ onMounted(() => { resizeObserver = new ResizeObserver(() => { contentAreaHeight.value = contentRef.value?.clientHeight || 0; // 先更新高度,再更新思维导图 if (contentAreaHeight.value && !initialized) { - /** 初始化思维导图 */ + // 初始化思维导图 try { if (!markMap) { markMap = Markmap.create(svgRef.value!); @@ -52,11 +55,15 @@ onMounted(() => { resizeObserver.observe(contentRef.value); } }); + +/** 卸载 */ onBeforeUnmount(() => { if (resizeObserver && contentRef.value) { resizeObserver.unobserve(contentRef.value); } }); + +/** 监听 props 变化 */ watch(props, ({ generatedContent, isGenerating, isEnd, isStart }) => { // 开始生成的时候清空一下 markdown 的内容 if (isStart) { @@ -84,6 +91,7 @@ function update() { console.error(error); } } + /** 处理内容 */ function processContent(text: string) { const arr: string[] = []; @@ -98,6 +106,7 @@ function processContent(text: string) { } return arr.join('\n'); } + /** 下载图片:download SVG to png file */ function downloadImage() { const svgElement = mindMapRef.value; @@ -112,6 +121,7 @@ function downloadImage() { drawWithImageSize: false, }); } + defineExpose({ scrollBottom() { mdContainerRef.value?.scrollTo(0, mdContainerRef.value?.scrollHeight); @@ -135,7 +145,6 @@ defineExpose({
-
-
(userList = data)); /** 列表的搜索表单 */ export function useGridFormSchema(): VbenFormSchema[] { diff --git a/apps/web-antd/src/views/ai/mindmap/manager/index.vue b/apps/web-antd/src/views/ai/mindmap/manager/index.vue index ca4426a23..b952e87eb 100644 --- a/apps/web-antd/src/views/ai/mindmap/manager/index.vue +++ b/apps/web-antd/src/views/ai/mindmap/manager/index.vue @@ -2,8 +2,6 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { AiMindmapApi } from '#/api/ai/mindmap'; -import { nextTick, ref } from 'vue'; - import { DocAlert, Page, useVbenDrawer } from '@vben/common-ui'; import { message } from 'ant-design-vue'; @@ -12,21 +10,21 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { deleteMindMap, getMindMapPage } from '#/api/ai/mindmap'; import { $t } from '#/locales'; -import Right from '../index/modules/Right.vue'; +import Right from '../index/modules/right.vue'; import { useGridColumns, useGridFormSchema } from './data'; -const previewContent = ref(''); const [Drawer, drawerApi] = useVbenDrawer({ header: false, footer: false, destroyOnClose: true, }); + /** 刷新表格 */ function handleRefresh() { gridApi.query(); } -/** 删除 */ +/** 删除思维导图记录 */ async function handleDelete(row: AiMindmapApi.MindMap) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.id]), @@ -34,14 +32,18 @@ async function handleDelete(row: AiMindmapApi.MindMap) { }); try { await deleteMindMap(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.id]), - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.id])); handleRefresh(); } finally { hideLoading(); } } + +/** 预览思维导图 */ +async function openPreview(row: AiMindmapApi.MindMap) { + drawerApi.setData(row.generatedContent).open(); +} + const [Grid, gridApi] = useVbenVxeGrid({ formOptions: { schema: useGridFormSchema(), @@ -63,6 +65,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: true, @@ -70,11 +73,6 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, } as VxeTableGridOptions, }); -async function openPreview(row: AiMindmapApi.MindMap) { - previewContent.value = row.generatedContent; - drawerApi.open(); - await nextTick(); -}