feat(@vben/web-antd): 实现模板动态加载
This commit is contained in:
parent
ce60c7194d
commit
7d762aada2
@ -58,8 +58,8 @@ export async function sendChatflow(
|
||||
}
|
||||
|
||||
// word
|
||||
export async function sendWord(data: ChatflowApi.CompletionsBody) {
|
||||
return requestClient.post(`word/completions`, data);
|
||||
export async function sendWord(appId: any, data: ChatflowApi.CompletionsBody) {
|
||||
return requestClient.post(`word/completions/${appId}`, data);
|
||||
}
|
||||
|
||||
export async function getChatList(
|
||||
|
@ -1,5 +1,3 @@
|
||||
import type { SpiderItem } from '@vben/common-ui';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace RepositoryApi {
|
||||
@ -10,7 +8,13 @@ export namespace RepositoryApi {
|
||||
}
|
||||
|
||||
export async function getAppList(params: RepositoryApi.AppListParams) {
|
||||
return requestClient.get<SpiderItem[]>(`/v1/server/apps`, { params });
|
||||
return requestClient.get(`/v1/server/apps`, { params });
|
||||
}
|
||||
|
||||
export async function getAppListByType(appType: any) {
|
||||
return requestClient.get(`/v1/server/apps/type`, {
|
||||
params: { appType },
|
||||
});
|
||||
}
|
||||
|
||||
// export const getAppDetail = (id) => {
|
||||
|
@ -36,8 +36,8 @@ export function sendWorkflow(
|
||||
return requestClient.post(`/v1/workflow/run/${params.appid}`, data);
|
||||
}
|
||||
|
||||
export function sendPpt(data: WorkflowApi.WorkflowRunBody) {
|
||||
return requestClient.post(`/ppt/run`, data);
|
||||
export function sendPpt(appId: any, data: WorkflowApi.WorkflowRunBody) {
|
||||
return requestClient.post(`/ppt/run/${appId}`, data);
|
||||
}
|
||||
|
||||
export function getWorkflowInfo(data: WorkflowApi.WorkflowLogParams) {
|
||||
|
@ -3,7 +3,7 @@ import type { ConversationsProps } from 'ant-design-x-vue';
|
||||
|
||||
import type { Props } from '../typing';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import { Menu } from 'ant-design-vue';
|
||||
import { Conversations } from 'ant-design-x-vue';
|
||||
@ -14,6 +14,7 @@ defineOptions({
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
temp: () => [],
|
||||
});
|
||||
const emit = defineEmits(['click', 'clickMode']);
|
||||
const defaultConversationsItems = computed(() => {
|
||||
@ -27,13 +28,16 @@ const defaultConversationsItems = computed(() => {
|
||||
const conversationsItems = ref(defaultConversationsItems);
|
||||
const activeKey = ref(defaultConversationsItems.value[0]?.key);
|
||||
|
||||
const itemsData = ref([
|
||||
{
|
||||
key: 'baca08c1-e92b-4dc9-a445-3584803f54d4',
|
||||
label: '海南职创申报书生成',
|
||||
title: '海南职创申报书生成',
|
||||
},
|
||||
]);
|
||||
// 将 props.items 映射为 key=id, label=name, title=name 的结构
|
||||
const transformItems = computed(() => {
|
||||
return props.temp.map((item) => ({
|
||||
key: item.id,
|
||||
label: item.name,
|
||||
title: item.name,
|
||||
}));
|
||||
});
|
||||
|
||||
const itemsData = ref([]);
|
||||
|
||||
const handleMenuClick = (item: { key: string }) => {
|
||||
const selectedItem = itemsData.value.find((i) => i.key === item.key);
|
||||
@ -60,6 +64,15 @@ const onConversationClick: ConversationsProps['onActiveChange'] = (key) => {
|
||||
|
||||
const selectedKeys = ref([]);
|
||||
const openKeys = ref([]);
|
||||
|
||||
// 监听 transformItems 变化,更新 itemsData
|
||||
watch(
|
||||
() => transformItems.value,
|
||||
(newVal) => {
|
||||
itemsData.value = newVal;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -10,7 +10,7 @@ import { message } from 'ant-design-vue';
|
||||
// http://47.112.173.8:6802/static/66f3cfd95e364a239d8036390db658ae.pptx
|
||||
// const url = ref('');
|
||||
const isLoading = ref(false); // 新增:加载状态变量
|
||||
const pptx = ref('/pptx/66f3cfd95e364a239d8036390db658ae.pptx');
|
||||
const pptx = ref();
|
||||
const pptStyle = ref({
|
||||
height: 'calc(100vh - 100px)',
|
||||
width: '100%',
|
||||
@ -37,7 +37,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
const data = drawerApi.getData<Record<string, any>>();
|
||||
if (data) {
|
||||
isLoading.value = true; // 开始加载文档,开启加载状态
|
||||
pptx.value = `/pptx/${data}`; // 更新 pptx 的值
|
||||
pptx.value = data; // 更新 pptx 的值
|
||||
}
|
||||
// url.value = drawerApi.getData<Record<string, any>>();
|
||||
}
|
||||
|
@ -96,8 +96,7 @@ function openPreviewDrawer(
|
||||
placement: DrawerPlacement = 'right',
|
||||
filename?: string,
|
||||
) {
|
||||
const fileData = filename.value;
|
||||
previewDrawerApi.setState({ placement }).setData(fileData).open();
|
||||
previewDrawerApi.setState({ placement }).setData(filename).open();
|
||||
}
|
||||
|
||||
// ==================== Event ====================
|
||||
@ -106,18 +105,9 @@ const handleFileChange: AttachmentsProps['onChange'] = (info) =>
|
||||
(attachedFiles.value = info.fileList);
|
||||
|
||||
// 判断是否是以 .pptx 结尾的 URL
|
||||
function isPptxURL(str: string): boolean {
|
||||
return str.endsWith('.pptx');
|
||||
}
|
||||
|
||||
// 使用正则提取 /static/ 后面的文件名部分
|
||||
function extractPptxFilename(url: string): null | string {
|
||||
const match = url.match(/\/static\/([a-f0-9-]+\.pptx)$/i);
|
||||
if (match) {
|
||||
return match[1]; // 返回类似:9e1c421e-991c-411f-8176-6350a97e70f3.pptx
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// function isPptxURL(str: string): boolean {
|
||||
// return str.endsWith('.pptx');
|
||||
// }
|
||||
|
||||
const startFetching = async () => {
|
||||
agentRequestLoading.value = true;
|
||||
@ -129,7 +119,7 @@ const startFetching = async () => {
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await props.runWorkflow({
|
||||
const res = await props.runWorkflow(props.item.id, {
|
||||
userId: userStore.userInfo?.userId || '',
|
||||
conversationId: '',
|
||||
files: [],
|
||||
@ -137,17 +127,17 @@ const startFetching = async () => {
|
||||
declarationDoc: content.value,
|
||||
},
|
||||
});
|
||||
const { result } = res.data.outputs;
|
||||
const files = res.data.outputs.files[0];
|
||||
content.value = '';
|
||||
|
||||
const filename = ref('');
|
||||
// const filename = ref('');
|
||||
|
||||
if (result && isPptxURL(result)) {
|
||||
filename.value = extractPptxFilename(result);
|
||||
}
|
||||
// if (result && isPptxURL(result)) {
|
||||
// filename.value = extractPptxFilename(result);
|
||||
// }
|
||||
|
||||
// 保存抓取结果 url http://47.112.173.8:6802/static/66f3cfd95e364a239d8036390db658ae.pptx
|
||||
fetchResult.value = `/pptx/${filename.value}`;
|
||||
fetchResult.value = files.url;
|
||||
resultItems.value.push({
|
||||
key: resultItems.value.length + 1,
|
||||
role: 'ai',
|
||||
@ -159,7 +149,7 @@ const startFetching = async () => {
|
||||
size: 'nomarl',
|
||||
type: 'primary',
|
||||
onClick: () => {
|
||||
openPreviewDrawer('right', filename);
|
||||
openPreviewDrawer('right', files.url);
|
||||
},
|
||||
},
|
||||
'文档预览',
|
||||
@ -175,8 +165,8 @@ const startFetching = async () => {
|
||||
onClick: () => {
|
||||
// 创建隐藏的 <a> 标签用于触发下载
|
||||
const link = document.createElement('a');
|
||||
link.href = result; // 设置下载链接
|
||||
link.download = filename.value; // 设置下载文件名
|
||||
link.href = files.url; // 设置下载链接
|
||||
link.download = files.filename; // 设置下载文件名
|
||||
document.body.append(link); // 将 <a> 标签添加到页面中
|
||||
link.click(); // 触发点击事件开始下载
|
||||
link.remove(); // 下载完成后移除 <a> 标签
|
||||
@ -212,11 +202,6 @@ watch(
|
||||
footer: msg.footer,
|
||||
});
|
||||
} else {
|
||||
const filename = ref('');
|
||||
|
||||
if (msg.content && isPptxURL(msg.content)) {
|
||||
filename.value = extractPptxFilename(msg.content);
|
||||
}
|
||||
resultItems.value.push({
|
||||
key: resultItems.value.length + 1,
|
||||
role: msg.role, // 'user' or 'ai'
|
||||
@ -228,7 +213,7 @@ watch(
|
||||
size: 'nomarl',
|
||||
type: 'primary',
|
||||
onClick: () => {
|
||||
openPreviewDrawer('right', filename);
|
||||
openPreviewDrawer('right', msg.content.url);
|
||||
},
|
||||
},
|
||||
'文档预览',
|
||||
@ -244,8 +229,8 @@ watch(
|
||||
onClick: () => {
|
||||
// 创建隐藏的 <a> 标签用于触发下载
|
||||
const link = document.createElement('a');
|
||||
link.href = msg.content; // 设置下载链接
|
||||
link.download = filename.value; // 设置下载文件名
|
||||
link.href = msg.content.url; // 设置下载链接
|
||||
link.download = msg.content.filename; // 设置下载文件名
|
||||
document.body.append(link); // 将 <a> 标签添加到页面中
|
||||
link.click(); // 触发点击事件开始下载
|
||||
link.remove(); // 下载完成后移除 <a> 标签
|
||||
|
@ -1,18 +1,20 @@
|
||||
<script lang="ts" setup>
|
||||
import type { PPTTempItem, ResultItem } from './typing';
|
||||
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
import { notification } from 'ant-design-vue';
|
||||
|
||||
import { getWorkflowInfo, getWorkflowList, sendPpt } from '#/api';
|
||||
import {
|
||||
getAppListByType,
|
||||
getWorkflowInfo,
|
||||
getWorkflowList,
|
||||
sendPpt,
|
||||
} from '#/api';
|
||||
|
||||
import { PptListView, PptWorkView } from './components';
|
||||
|
||||
let temp = reactive<PPTTempItem>({
|
||||
id: 'ee3889b6-50fa-463e-b956-3b93447727fc',
|
||||
name: '海南科技项目可研报告PPT生成',
|
||||
});
|
||||
const temp = ref([]);
|
||||
|
||||
const hitsory = ref([]);
|
||||
const loading = ref(true);
|
||||
@ -27,10 +29,18 @@ const getLogs = async (appid: string, limit: number) => {
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const getTemp = async () => {
|
||||
const res = await getAppListByType(2);
|
||||
if (Array.isArray(res) && res.length > 0) {
|
||||
// 提取 id 和 name 并赋值给 temp
|
||||
temp.value = res.map(({ id, name }) => ({ id, name }));
|
||||
}
|
||||
};
|
||||
|
||||
async function handleClick(item: PPTTempItem) {
|
||||
temp = item;
|
||||
// temp = item;
|
||||
const res = await getWorkflowInfo({
|
||||
appid: temp.appId,
|
||||
appid: item.appId,
|
||||
workflowRunId: item.workflowRunId,
|
||||
});
|
||||
itemMessage.value = [];
|
||||
@ -45,22 +55,25 @@ async function handleClick(item: PPTTempItem) {
|
||||
itemMessage.value.push({
|
||||
key: itemMessage.value.length + 1,
|
||||
role: 'ai',
|
||||
content: res.outputs.result,
|
||||
content: res.outputs.files[0],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const currentTemp = ref<null | PPTTempItem>(null);
|
||||
|
||||
async function handleClickMode(item: PPTTempItem) {
|
||||
notification.success({
|
||||
message: `${item.name}`,
|
||||
description: '已选取',
|
||||
duration: 3,
|
||||
});
|
||||
temp = item;
|
||||
currentTemp.value = item;
|
||||
await getLogs(item.id, 5);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getLogs(temp.id, 5);
|
||||
getTemp();
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -69,6 +82,7 @@ onMounted(() => {
|
||||
<div class="lg:w-1/6">
|
||||
<PptListView
|
||||
title="选择模板"
|
||||
:temp="temp"
|
||||
:items="hitsory"
|
||||
:loading="loading"
|
||||
@click-mode="handleClickMode"
|
||||
@ -76,7 +90,7 @@ onMounted(() => {
|
||||
/>
|
||||
</div>
|
||||
<PptWorkView
|
||||
:item="temp"
|
||||
:item="currentTemp"
|
||||
:run-workflow="sendPpt"
|
||||
:item-message="itemMessage"
|
||||
/>
|
||||
|
@ -21,6 +21,7 @@ interface PptHistoryItem {
|
||||
|
||||
interface Props {
|
||||
items?: PptHistoryItem[];
|
||||
temp: PPTTempItem[];
|
||||
title: string;
|
||||
loading: boolean;
|
||||
}
|
||||
@ -50,7 +51,10 @@ interface WorkflowResult {
|
||||
interface PropsWork {
|
||||
itemMessage?: ResultItem;
|
||||
item?: PPTTempItem;
|
||||
runWorkflow?: (context: WorkflowContext) => Promise<WorkflowResult>;
|
||||
runWorkflow?: (
|
||||
appId: any,
|
||||
context: WorkflowContext,
|
||||
) => Promise<WorkflowResult>;
|
||||
}
|
||||
|
||||
export type {
|
||||
|
@ -3,52 +3,37 @@
|
||||
//
|
||||
// import type { SpiderItem } from './typing';
|
||||
|
||||
import { ref } from 'vue';
|
||||
import type { Props } from '#/views/spider/typing';
|
||||
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import { Menu } from 'ant-design-vue';
|
||||
// import { Conversations } from 'ant-design-x-vue';
|
||||
|
||||
// interface Props {
|
||||
// items?: SpiderItem[];
|
||||
// spiderList?: SpiderItem[];
|
||||
// title: string;
|
||||
// }
|
||||
|
||||
defineOptions({
|
||||
name: 'SpiderListView',
|
||||
});
|
||||
// const props = withDefaults(defineProps<Props>(), {
|
||||
// items: () => [],
|
||||
// spiderList: () => [],
|
||||
// });
|
||||
|
||||
// import { Conversations } from 'ant-design-x-vue';
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
temp: () => [],
|
||||
});
|
||||
|
||||
const emit = defineEmits(['click', 'clickMode']);
|
||||
const selectedKeys = ref([]);
|
||||
const openKeys = ref([]);
|
||||
|
||||
// const defaultConversationsItems = computed(() => {
|
||||
// return props.items.map((item) => {
|
||||
// return {
|
||||
// key: item.id,
|
||||
// label: item.id,
|
||||
// };
|
||||
// });
|
||||
// });
|
||||
// const conversationsItems = ref(defaultConversationsItems);
|
||||
// const activeKey = ref(defaultConversationsItems.value[0]?.key);
|
||||
const itemsData = ref([
|
||||
{
|
||||
key: '77c068fd-d5b6-4c33-97d8-db5511a09b26',
|
||||
label: '全国公共资源交易平台_信息爬取',
|
||||
title: '全国公共资源交易平台_信息爬取',
|
||||
url: 'https://ygp.gdzwfw.gov.cn/',
|
||||
},
|
||||
{
|
||||
key: 'c736edd0-925d-4877-9223-56aab7342311',
|
||||
label: '广州公共资源交易中心_信息获取',
|
||||
title: '广州公共资源交易中心_信息获取',
|
||||
url: 'https://www.gzggzy.cn',
|
||||
},
|
||||
]);
|
||||
// 将 props.items 映射为 key=id, label=name, title=name 的结构
|
||||
const transformItems = computed(() => {
|
||||
return props.temp.map((item) => ({
|
||||
key: item.id,
|
||||
label: item.name,
|
||||
title: item.name,
|
||||
}));
|
||||
});
|
||||
|
||||
const itemsData = ref();
|
||||
|
||||
const handleMenuClick = (item: { key: string }) => {
|
||||
const selectedItem = itemsData.value.find((i) => i.key === item.key);
|
||||
@ -73,6 +58,14 @@ const handleMenuClick = (item: { key: string }) => {
|
||||
// emit('click', null); // 或者根据业务需求处理未找到的情况
|
||||
// }
|
||||
// };
|
||||
|
||||
watch(
|
||||
() => transformItems.value,
|
||||
(newVal) => {
|
||||
itemsData.value = newVal;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -2,14 +2,14 @@
|
||||
// sendWorkflow
|
||||
import type { ResultItem, TempItem, WordFlowItem } from './typing';
|
||||
|
||||
import { ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
import { notification } from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
getAppListByType,
|
||||
getSpiderStatus,
|
||||
getWorkflowInfo,
|
||||
getWorkflowList,
|
||||
runSpider,
|
||||
runSpiderGz,
|
||||
stopSpider,
|
||||
@ -19,21 +19,25 @@ import { SelfWorkView, SpiderListView, WorkflowWorkView } from './components';
|
||||
|
||||
const hitsory = ref([]);
|
||||
const loading = ref(true);
|
||||
const temp = ref({
|
||||
id: '',
|
||||
name: '',
|
||||
url: '',
|
||||
});
|
||||
const temp = ref([]);
|
||||
const itemMessage = ref<ResultItem[]>([]);
|
||||
|
||||
// 获取日志
|
||||
const getLogs = async (appid: string, limit: number) => {
|
||||
loading.value = true;
|
||||
hitsory.value = await getWorkflowList({
|
||||
appid,
|
||||
limit,
|
||||
});
|
||||
loading.value = false;
|
||||
// const getLogs = async (appid: string, limit: number) => {
|
||||
// loading.value = true;
|
||||
// hitsory.value = await getWorkflowList({
|
||||
// appid,
|
||||
// limit,
|
||||
// });
|
||||
// loading.value = false;
|
||||
// };
|
||||
|
||||
const getTemp = async () => {
|
||||
const res = await getAppListByType(3);
|
||||
if (Array.isArray(res) && res.length > 0) {
|
||||
// 提取 id 和 name 并赋值给 temp
|
||||
temp.value = res.map(({ id, name }) => ({ id, name }));
|
||||
}
|
||||
};
|
||||
|
||||
async function handleClick(item: WordFlowItem) {
|
||||
@ -51,19 +55,26 @@ async function handleClick(item: WordFlowItem) {
|
||||
}
|
||||
}
|
||||
|
||||
const currentTemp = ref<TempItem>({
|
||||
id: '77c068fd-d5b6-4c33-97d8-db5511a09b26',
|
||||
name: '全国公共资源交易平台_信息爬取',
|
||||
});
|
||||
|
||||
async function handleClickMode(item: TempItem) {
|
||||
notification.success({
|
||||
message: `${item.name}`,
|
||||
description: '已选取',
|
||||
duration: 3,
|
||||
});
|
||||
temp.value = item;
|
||||
getLogs(item.id, 5);
|
||||
currentTemp.value = item;
|
||||
|
||||
// getLogs(item.id, 5);
|
||||
}
|
||||
|
||||
// onMounted(() => {
|
||||
onMounted(() => {
|
||||
getTemp();
|
||||
// getLogs(spiderList.value[0].id);
|
||||
// });
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -71,6 +82,7 @@ async function handleClickMode(item: TempItem) {
|
||||
<div class="lg:w-1/5">
|
||||
<SpiderListView
|
||||
title="选择模板"
|
||||
:temp="temp"
|
||||
:items="hitsory"
|
||||
:loading="loading"
|
||||
@click-mode="handleClickMode"
|
||||
@ -78,9 +90,9 @@ async function handleClickMode(item: TempItem) {
|
||||
/>
|
||||
</div>
|
||||
<SelfWorkView
|
||||
v-if="temp.id === '77c068fd-d5b6-4c33-97d8-db5511a09b26'"
|
||||
v-if="currentTemp.id === '387e1ff7-3385-404d-ba29-80c5c62fbcf7'"
|
||||
title="目标网址:"
|
||||
:item="temp"
|
||||
:item="currentTemp"
|
||||
:run-spider="runSpider"
|
||||
:stop-spider="stopSpider"
|
||||
:get-spider-status="getSpiderStatus"
|
||||
@ -90,7 +102,7 @@ async function handleClickMode(item: TempItem) {
|
||||
<WorkflowWorkView
|
||||
v-else
|
||||
title="目标网址:"
|
||||
:item="temp"
|
||||
:item="currentTemp"
|
||||
:run-spider="runSpider"
|
||||
:stop-spider="stopSpider"
|
||||
:get-spider-status="getSpiderStatus"
|
||||
|
@ -1,7 +1,7 @@
|
||||
interface TempItem {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
interface ResultItem {
|
||||
@ -47,6 +47,7 @@ interface ResultItem {
|
||||
|
||||
interface Props {
|
||||
itemMessage?: ResultItem;
|
||||
temp?: any;
|
||||
item?: SpiderItem;
|
||||
title: string;
|
||||
runSpider?: (context: any) => Promise<SpiderResult>;
|
||||
|
@ -3,7 +3,7 @@ import type { ConversationsProps } from 'ant-design-x-vue';
|
||||
|
||||
import type { PropsHistory } from '../typing';
|
||||
|
||||
import { computed, h, ref } from 'vue';
|
||||
import { computed, h, ref, watch } from 'vue';
|
||||
|
||||
import { DeleteOutlined } from '@ant-design/icons-vue';
|
||||
// import { Card, CardContent, CardHeader, CardTitle } from '@vben-core/shadcn-ui';
|
||||
@ -16,6 +16,7 @@ defineOptions({
|
||||
|
||||
const props = withDefaults(defineProps<PropsHistory>(), {
|
||||
items: () => [],
|
||||
temp: () => [],
|
||||
});
|
||||
const emit = defineEmits(['click', 'clickMode', 'delete']);
|
||||
const defaultConversationsItems = computed(() => {
|
||||
@ -29,23 +30,16 @@ const defaultConversationsItems = computed(() => {
|
||||
const conversationsItems = ref(defaultConversationsItems);
|
||||
const activeKey = ref(defaultConversationsItems.value[0]?.key);
|
||||
|
||||
const itemsData = ref([
|
||||
{
|
||||
key: 'baca08c1-e92b-4dc9-a445-3584803f54d4',
|
||||
label: '海南职创申报书生成',
|
||||
title: '海南职创申报书生成',
|
||||
},
|
||||
]);
|
||||
// 将 props.items 映射为 key=id, label=name, title=name 的结构
|
||||
const transformItems = computed(() => {
|
||||
return props.temp.map((item) => ({
|
||||
key: item.id,
|
||||
label: item.name,
|
||||
title: item.name,
|
||||
}));
|
||||
});
|
||||
|
||||
// const items2: ItemType[] = reactive([
|
||||
// getItem(
|
||||
// '选择模板',
|
||||
// 'grp',
|
||||
// null,
|
||||
// [getItem('海南职创申报书生成', 'baca08c1-e92b-4dc9-a445-3584803f54d4')],
|
||||
// 'group',
|
||||
// ),
|
||||
// ]);
|
||||
const itemsData = ref();
|
||||
|
||||
const handleMenuClick = (item: { key: string }) => {
|
||||
const selectedItem = itemsData.value.find((i) => i.key === item.key);
|
||||
@ -80,6 +74,15 @@ const menuConfig: ConversationsProps['menu'] = (conversation) => ({
|
||||
|
||||
const selectedKeys = ref([]);
|
||||
const openKeys = ref([]);
|
||||
|
||||
// 监听 transformItems 变化,更新 itemsData
|
||||
watch(
|
||||
() => transformItems.value,
|
||||
(newVal) => {
|
||||
itemsData.value = newVal;
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -10,7 +10,7 @@ import '@vue-office/docx/lib/index.css';
|
||||
|
||||
// const url = ref('');
|
||||
const isLoading = ref(false); // 新增:加载状态变量
|
||||
const docx = ref<any>(`/docx/027c6b7c-fea6-4964-839b-27857c4d3181.docx`);
|
||||
const docx = ref<any>();
|
||||
const pptStyle = ref({
|
||||
height: 'calc(100vh - 100px)',
|
||||
width: '100%',
|
||||
@ -36,7 +36,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
const data = drawerApi.getData<Record<string, any>>();
|
||||
if (data) {
|
||||
isLoading.value = true;
|
||||
docx.value = `/docx/${data}`; // 更新 docx 的值
|
||||
docx.value = data; // 更新 docx 的值
|
||||
}
|
||||
// url.value = drawerApi.getData<Record<string, any>>();
|
||||
}
|
||||
|
@ -159,7 +159,6 @@ const open = ref(false);
|
||||
const fetchStatus = ref('');
|
||||
const resultItems = ref<ResultItem[]>([]);
|
||||
const conversationId = ref('');
|
||||
const fetchResult = ref('');
|
||||
const layout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
@ -175,25 +174,39 @@ function openPreviewDrawer(
|
||||
placement: DrawerPlacement = 'right',
|
||||
filename?: string,
|
||||
) {
|
||||
const fileData = filename.value;
|
||||
previewDrawerApi.setState({ placement }).setData(fileData).open();
|
||||
previewDrawerApi.setState({ placement }).setData(filename).open();
|
||||
}
|
||||
|
||||
// ==================== Event ====================
|
||||
|
||||
// 判断是否是以 .docx 结尾的 URL
|
||||
function isDocxURL(str: string): boolean {
|
||||
return str.endsWith('.docx');
|
||||
}
|
||||
// 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
|
||||
// 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;
|
||||
// }
|
||||
function extractDocxInfo(
|
||||
markdownLink: string,
|
||||
): null | { filename: string; url: string } {
|
||||
const fileRegex = /\[(.*?)\]/;
|
||||
const urlRegex = /\((.*?)\)/;
|
||||
const fileMatch = markdownLink.match(fileRegex);
|
||||
const urlMatch = markdownLink.match(urlRegex);
|
||||
if (fileMatch && urlMatch) {
|
||||
const filename = fileMatch[1]; // 提取 [filename] 部分
|
||||
const url = urlMatch[1] || ''; // 提取 (url) 部分
|
||||
return { filename, url };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const startFetching = async () => {
|
||||
if (projectInfo.value.projectName === '') {
|
||||
open.value = true;
|
||||
@ -217,7 +230,7 @@ const startFetching = async () => {
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await props.runChatflow({
|
||||
const res = await props.runChatflow(props.item.id, {
|
||||
userId: userStore.userInfo?.userId || '',
|
||||
conversationId: conversationId.value,
|
||||
files: [],
|
||||
@ -234,10 +247,10 @@ const startFetching = async () => {
|
||||
const { answer } = res;
|
||||
conversationId.value = res.conversationId;
|
||||
|
||||
const filename = ref('');
|
||||
const docxInfo = extractDocxInfo(answer);
|
||||
|
||||
if (answer && isDocxURL(answer)) {
|
||||
filename.value = extractDocxFilename(answer);
|
||||
if (docxInfo) {
|
||||
const { filename, url } = docxInfo;
|
||||
resultItems.value.push({
|
||||
key: resultItems.value.length + 1,
|
||||
role: 'ai',
|
||||
@ -246,10 +259,10 @@ const startFetching = async () => {
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
size: 'nomarl',
|
||||
size: 'normal',
|
||||
type: 'primary',
|
||||
onClick: () => {
|
||||
openPreviewDrawer('right', filename);
|
||||
openPreviewDrawer('right', url);
|
||||
},
|
||||
},
|
||||
'文档预览',
|
||||
@ -257,19 +270,16 @@ const startFetching = async () => {
|
||||
h(
|
||||
Button,
|
||||
{
|
||||
size: 'nomarl',
|
||||
size: 'normal',
|
||||
type: 'primary',
|
||||
style: {
|
||||
marginLeft: '10px',
|
||||
},
|
||||
style: { marginLeft: '10px' },
|
||||
onClick: () => {
|
||||
// 创建隐藏的 <a> 标签用于触发下载
|
||||
const link = document.createElement('a');
|
||||
link.href = answer; // 设置下载链接
|
||||
link.download = filename.value; // 设置下载文件名
|
||||
document.body.append(link); // 将 <a> 标签添加到页面中
|
||||
link.click(); // 触发点击事件开始下载
|
||||
link.remove(); // 下载完成后移除 <a> 标签
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
document.body.append(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
},
|
||||
},
|
||||
'文档下载',
|
||||
@ -283,13 +293,10 @@ const startFetching = async () => {
|
||||
content: res.answer,
|
||||
});
|
||||
}
|
||||
|
||||
fetchResult.value = `/static/${filename.value}`;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
// 模拟抓取完成
|
||||
agentRequestLoading.value = false;
|
||||
fetchStatus.value = 'completed';
|
||||
};
|
||||
@ -308,18 +315,18 @@ watch(
|
||||
if (msg.role === 'user') {
|
||||
resultItems.value.push({
|
||||
key: resultItems.value.length + 1,
|
||||
role: msg.role, // 'user' or 'ai'
|
||||
role: msg.role,
|
||||
content: msg.content,
|
||||
footer: msg.footer,
|
||||
});
|
||||
} else {
|
||||
const filename = ref('');
|
||||
const docxInfo = extractDocxInfo(msg.content);
|
||||
|
||||
if (msg.content && isDocxURL(msg.content)) {
|
||||
filename.value = extractDocxFilename(msg.content);
|
||||
if (docxInfo) {
|
||||
const { filename, url } = docxInfo;
|
||||
resultItems.value.push({
|
||||
key: resultItems.value.length + 1,
|
||||
role: msg.role, // 'user' or 'ai'
|
||||
role: msg.role,
|
||||
content: '文档已生成',
|
||||
footer: h(Flex, null, [
|
||||
h(
|
||||
@ -328,7 +335,7 @@ watch(
|
||||
size: 'normal',
|
||||
type: 'primary',
|
||||
onClick: () => {
|
||||
openPreviewDrawer('right', filename);
|
||||
openPreviewDrawer('right', { value: filename });
|
||||
},
|
||||
},
|
||||
'文档预览',
|
||||
@ -338,17 +345,14 @@ watch(
|
||||
{
|
||||
size: 'normal',
|
||||
type: 'primary',
|
||||
style: {
|
||||
marginLeft: '10px',
|
||||
},
|
||||
style: { marginLeft: '10px' },
|
||||
onClick: () => {
|
||||
// 创建隐藏的 <a> 标签用于触发下载
|
||||
const link = document.createElement('a');
|
||||
link.href = msg.content; // 设置下载链接
|
||||
link.download = filename.value; // 设置下载文件名
|
||||
document.body.append(link); // 将 <a> 标签添加到页面中
|
||||
link.click(); // 触发点击事件开始下载
|
||||
link.remove(); // 下载完成后移除 <a> 标签
|
||||
link.href = url;
|
||||
link.download = filename;
|
||||
document.body.append(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
},
|
||||
},
|
||||
'文档下载',
|
||||
@ -358,7 +362,7 @@ watch(
|
||||
} else {
|
||||
resultItems.value.push({
|
||||
key: resultItems.value.length + 1,
|
||||
role: msg.role, // 'user' or 'ai'
|
||||
role: msg.role,
|
||||
content: msg.content,
|
||||
});
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
<script lang="ts" setup>
|
||||
import type { WordTempItem } from '@vben/common-ui';
|
||||
import type { ResultItem, WordTempItem } from './typing';
|
||||
|
||||
import type { ResultItem } from './typing';
|
||||
import type { PPTTempItem } from '#/views/ppt/typing';
|
||||
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
import { message, notification } from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
deleteChatflow,
|
||||
getAppListByType,
|
||||
getChatflowMessage,
|
||||
getChatList,
|
||||
getChatParameters,
|
||||
@ -17,10 +18,7 @@ import {
|
||||
|
||||
import { WordListView, WordWorkView } from './components';
|
||||
|
||||
let temp = reactive<WordTempItem>({
|
||||
id: 'baca08c1-e92b-4dc9-a445-3584803f54d4',
|
||||
name: '海南职创申报书生成',
|
||||
});
|
||||
const temp = ref([]);
|
||||
|
||||
const hitsory = ref([]);
|
||||
const loading = ref(true);
|
||||
@ -48,26 +46,38 @@ const getLogs = async (appid: string) => {
|
||||
loading.value = false;
|
||||
};
|
||||
|
||||
const getTemp = async () => {
|
||||
const res = await getAppListByType(1);
|
||||
if (Array.isArray(res) && res.length > 0) {
|
||||
// 提取 id 和 name 并赋值给 temp
|
||||
temp.value = res.map(({ id, name }) => ({ id, name }));
|
||||
}
|
||||
};
|
||||
|
||||
const currentTemp = ref<null | PPTTempItem>(null);
|
||||
|
||||
function handleClickMode(item: WordTempItem) {
|
||||
notification.success({
|
||||
message: `${item.name}`,
|
||||
description: '已选取',
|
||||
duration: 3,
|
||||
});
|
||||
temp = item;
|
||||
getParameters(temp.id);
|
||||
currentTemp.value = item;
|
||||
getLogs(item.id);
|
||||
getParameters(item.id);
|
||||
}
|
||||
|
||||
const itemMessage = ref<ResultItem[]>([]);
|
||||
|
||||
async function deleteLog(item: any) {
|
||||
const res = await deleteChatflow({
|
||||
appId: temp.id,
|
||||
appId: temp.value.id,
|
||||
conversationId: item,
|
||||
userId: '1562',
|
||||
});
|
||||
if (res.code === 0) {
|
||||
message.success('删除成功');
|
||||
getLogs(temp.id);
|
||||
getLogs(temp.value.id);
|
||||
} else {
|
||||
message.error('删除失败');
|
||||
}
|
||||
@ -79,7 +89,7 @@ async function getParameters(id: string) {
|
||||
}
|
||||
|
||||
async function handleClick(item: string) {
|
||||
const res = await getChatflowMessage(temp.id, {
|
||||
const res = await getChatflowMessage(currentTemp.value.id, {
|
||||
userId: '1562',
|
||||
firstId: '',
|
||||
conversationId: item,
|
||||
@ -108,8 +118,7 @@ async function handleClick(item: string) {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getLogs(temp.id);
|
||||
getParameters(temp.id);
|
||||
getTemp();
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -118,6 +127,7 @@ onMounted(() => {
|
||||
<div class="lg:w-1/6">
|
||||
<WordListView
|
||||
title="选择模板"
|
||||
:temp="temp"
|
||||
:items="hitsory"
|
||||
:loading="loading"
|
||||
@click-mode="handleClickMode"
|
||||
@ -126,7 +136,7 @@ onMounted(() => {
|
||||
/>
|
||||
</div>
|
||||
<WordWorkView
|
||||
:item="temp"
|
||||
:item="currentTemp"
|
||||
:params-data="params"
|
||||
:run-chatflow="sendWord"
|
||||
:item-message="itemMessage"
|
||||
|
@ -44,10 +44,14 @@ interface Props {
|
||||
itemMessage?: ResultItem;
|
||||
item?: WordTempItem;
|
||||
paramsData?: object;
|
||||
runChatflow?: (context: WorkflowContext) => Promise<WorkflowResult>;
|
||||
runChatflow?: (
|
||||
appId: any,
|
||||
context: WorkflowContext,
|
||||
) => Promise<WorkflowResult>;
|
||||
}
|
||||
|
||||
interface PropsHistory {
|
||||
temp: any;
|
||||
items?: WordHistoryItem[];
|
||||
title: string;
|
||||
loading: boolean;
|
||||
|
@ -15,10 +15,10 @@ export default defineConfig(async () => {
|
||||
// target: 'http://192.168.3.238:8081/api',
|
||||
ws: true,
|
||||
},
|
||||
'/docx': {
|
||||
'/files': {
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/docx/, ''),
|
||||
target: 'http://47.112.173.8:6805/static',
|
||||
rewrite: (path) => path.replace(/^\/files/, ''),
|
||||
target: 'http://47.112.173.8:6800/files/',
|
||||
},
|
||||
'/guangzhou': {
|
||||
changeOrigin: true,
|
||||
|
Loading…
Reference in New Issue
Block a user