feat(@vben/common-ui): 优化数据抓取

This commit is contained in:
Kven 2025-05-17 22:07:52 +08:00
parent e4a74a5f8c
commit 2e3a7806fc
4 changed files with 314 additions and 118 deletions

View File

@ -6,13 +6,13 @@ export function runSpider(data: any) {
} }
export function getSpiderStatus() { export function getSpiderStatus() {
return requestClient.get(`/spider/status`); return requestClient.post(`/spider/status`);
} }
export function getSpiderLogs() { export function getSpiderLogs() {
return requestClient.get(`/v1/workflow/list`); return requestClient.post(`/v1/workflow/list`);
} }
export function stopSpider() { export function stopSpider() {
return requestClient.get(`/spider/stop`); return requestClient.post(`/spider/stop`);
} }

View File

@ -5,7 +5,14 @@ import { SpiderListView, SpiderWorkView } from '@vben/common-ui';
import { notification } from 'ant-design-vue'; import { notification } from 'ant-design-vue';
import { getWorkflowInfo, getWorkflowList, runSpider } from '#/api'; import {
getSpiderStatus,
getWorkflowInfo,
getWorkflowList,
runSpider,
sendWorkflow,
stopSpider,
} from '#/api';
// sendWorkflow // sendWorkflow
interface TempItem { interface TempItem {
id: string; id: string;
@ -87,6 +94,9 @@ async function handleClickMode(item: TempItem) {
title="目标网址:" title="目标网址:"
:item="temp" :item="temp"
:run-spider="runSpider" :run-spider="runSpider"
:stop-spider="stopSpider"
:get-spider-status="getSpiderStatus"
:send-workflow="sendWorkflow"
:item-message="itemMessage" :item-message="itemMessage"
/> />
</div> </div>

View File

@ -17,7 +17,7 @@ import {
import { Badge, Button, Flex, Space, Typography } from 'ant-design-vue'; import { Badge, Button, Flex, Space, Typography } from 'ant-design-vue';
import { Attachments, Bubble, Sender, Welcome } from 'ant-design-x-vue'; import { Attachments, Bubble, Sender, Welcome } from 'ant-design-x-vue';
import WordPreview from '../word/word-preview.vue'; import PptPreview from './ppt-perview.vue';
interface ResultItem { interface ResultItem {
key: number; key: number;
@ -140,7 +140,7 @@ const fetchResult = ref('');
const [PreviewDrawer, previewDrawerApi] = useVbenDrawer({ const [PreviewDrawer, previewDrawerApi] = useVbenDrawer({
// //
connectedComponent: WordPreview, connectedComponent: PptPreview,
// placement: 'left', // placement: 'left',
}); });
function openPreviewDrawer( function openPreviewDrawer(

View File

@ -37,7 +37,7 @@ interface SpiderParams {
interface SpiderContext { interface SpiderContext {
userId: string; userId: string;
conversationId: string; conversationId: string;
files: unknown[]; files: [];
inputs: Record<string, unknown>; inputs: Record<string, unknown>;
} }
@ -60,10 +60,14 @@ interface Props {
itemMessage?: ResultItem; itemMessage?: ResultItem;
item?: SpiderItem; item?: SpiderItem;
title: string; title: string;
runSpider?: ( runSpider?: (context: any) => Promise<SpiderResult>;
params: SpiderParams, getSpiderStatus?: () => Promise<{
context: SpiderContext, status: string;
) => Promise<SpiderResult>; }>;
stopSpider?: () => Promise<{
status: string;
}>;
sendWorkflow?: (params: SpiderParams, data: SpiderContext) => Promise<any>;
} }
defineOptions({ defineOptions({
@ -76,10 +80,21 @@ const props = withDefaults(defineProps<Props>(), {
return null; return null;
}, },
runSpider: () => async () => ({ runSpider: () => async () => ({
data: { msg: '',
outputs: { code: '',
result: '', }),
}, getSpiderStatus: () => async () => ({
msg: '',
code: '',
}),
stopSpider: () => async () => ({
msg: '',
code: '',
}),
sendWorkflow: () => async () => ({
outputs: {
result: '',
files: [],
}, },
}), }),
}); });
@ -112,11 +127,8 @@ function isDocxURL(str: string): boolean {
// 使 /static/ // 使 /static/
function extractDocxFilename(url: string): null | string { function extractDocxFilename(url: string): null | string {
const match = url.match(/\/static\/([a-f0-9-]+\.docx)$/i); const match = url.match(/\/static\/([^/]+\.docx)$/i); // /static/ .docx
if (match) { return match ? match[1] : null;
return match[1]; // 9e1c421e-991c-411f-8176-6350a97e70f3.docx
}
return null;
} }
const startFetching = async () => { const startFetching = async () => {
@ -133,97 +145,276 @@ const startFetching = async () => {
publish_end_time = publish_end_time =
dayjs(selectedDateRange.value[1]).format('YYYYMMDDhhmmss') || ''; dayjs(selectedDateRange.value[1]).format('YYYYMMDDhhmmss') || '';
} }
if (props.item.id === '77c068fd-d5b6-4c33-97d8-db5511a09b26') {
try { try {
notification.info({ notification.info({
message: '正在获取中...', message: '正在获取中...',
duration: 3,
});
const res = await props.runSpider(
{
publish_start_time,
publish_end_time,
llm_api_key: '77c068fd-d5b6-4c33-97d8-db5511a09b26',
},
// {
// appid: props.item.id,
// },
// {
// userId: '1562',
// conversationId: '',
// files: [],
// inputs: {
// publish_start_time,
// publish_end_time,
// },
// },
);
if (res.data.outputs.result) {
//
fetchResult.value = res.data.outputs.result;
notification.success({
message: '获取成功',
duration: 3, duration: 3,
}); });
const { result } = res.data.outputs;
const filename = ref(''); const res = await props.runSpider({
publish_start_time,
publish_end_time,
llm_api_key: props.item.id,
});
if (result && isDocxURL(result)) { if (res.code !== 0) {
filename.value = extractDocxFilename(result); isFetching.value = false;
fetchResult.value = '';
message.error('抓取无结果');
return;
} }
// url http://47.112.173.8:6802/static/66f3cfd95e364a239d8036390db658ae.docx let statusPollingInterval: null | number = null;
fetchResult.value = `/static/${filename.value}`; let pollingCount = 0;
resultItems.value.push({ const maxPollingAttempts = 300; // 300
key: resultItems.value.length + 1,
role: 'ai', const startPolling = async () => {
content: '文档已生成', try {
footer: h(Flex, null, [ const response = await props.getSpiderStatus();
h(
Button, if (!response.data.is_running) {
{ clearInterval(statusPollingInterval!);
size: 'nomarl', statusPollingInterval = null;
type: 'primary',
onClick: () => { if (response.data.download_url) {
openPreviewDrawer('right', filename); const download_url = response.data.download_url;
}, fetchResult.value = download_url;
}, notification.success({ message: '获取成功', duration: 3 });
'文档预览',
), let filename = '';
h( if (isDocxURL(download_url)) {
Button, filename = extractDocxFilename(download_url);
{ }
size: 'normal',
type: 'primary', fetchResult.value = `/static/${filename}`;
style: { resultItems.value.push({
marginLeft: '10px', key: resultItems.value.length + 1,
}, role: 'ai',
onClick: () => { content: '文档已生成',
// <a> footer: h(Flex, null, [
const link = document.createElement('a'); h(
link.href = msg.content; // Button,
link.download = filename; // {
document.body.append(link); // <a> size: 'normal',
link.click(); // type: 'primary',
link.remove(); // <a> onClick: () => {
}, openPreviewDrawer('right', safeFilename);
}, },
'文档下载', },
), '文档预览',
]), ),
}); h(
fetchStatus.value = 'completed'; Button,
} else { {
size: 'normal',
type: 'primary',
style: { marginLeft: '10px' },
onClick: () => {
const link = document.createElement('a');
link.href = download_url;
link.download = safeFilename;
document.body.append(link);
link.click();
link.remove();
},
},
'文档下载',
),
]),
});
isFetching.value = false;
fetchStatus.value = 'completed';
} else {
isFetching.value = false;
fetchResult.value = '';
message.error('抓取无结果');
}
} else if (++pollingCount >= maxPollingAttempts) {
clearInterval(statusPollingInterval!);
statusPollingInterval = null;
props.stopSpider();
message.warn('轮询超时,请稍后再试');
}
} catch (error) {
clearInterval(statusPollingInterval!);
statusPollingInterval = null;
message.error(`状态查询失败:${error}`);
}
};
statusPollingInterval = window.setInterval(startPolling, 1000);
// onUnmounted
//
// onUnmounted(() => {
// if (statusPollingInterval) {
// clearInterval(statusPollingInterval);
// }
// });
} catch (error) {
isFetching.value = false;
fetchResult.value = ''; fetchResult.value = '';
message.error('抓取无结果'); console.error(error);
} }
} catch (error) { }
message.error(`${error}`); if (props.item.id === 'c736edd0-925d-4877-9223-56aab7342311') {
try {
notification.info({
message: '正在获取中...',
duration: 3,
});
const res = await props.sendWorkflow(
{
appid: props.item.id,
},
{
userId: '1562',
conversationId: '',
files: [],
inputs: {
publish_start_time,
publish_end_time,
},
},
);
if (res.data.outputs.files) {
//
fetchResult.value = res.data.outputs.files[0].url;
notification.success({
message: '获取成功',
duration: 3,
});
const fileUrl = ref('');
fileUrl.value = `http://47.112.173.8:6800${fetchResult.value}`;
// url http://47.112.173.8:6802/static/66f3cfd95e364a239d8036390db658ae.docx
resultItems.value.push({
key: resultItems.value.length + 1,
role: 'ai',
content: '文档已生成',
footer: h(Flex, null, [
// h(
// Button,
// {
// size: 'nomarl',
// type: 'primary',
// onClick: () => {
// openPreviewDrawer('right', fetchResult);
// },
// },
// '',
// ),
h(
Button,
{
size: 'normal',
type: 'primary',
style: {
marginLeft: '10px',
},
onClick: () => {
// <a>
const link = document.createElement('a');
link.href = fileUrl; //
link.download = '广州公共资源交易中心数据获取'; //
document.body.append(link); // <a>
link.click(); //
link.remove(); // <a>
},
},
'文档下载',
),
]),
});
fetchStatus.value = 'completed';
} else {
fetchResult.value = '';
message.error('抓取无结果');
}
} catch (error) {
message.error(`${error}`);
}
isFetching.value = false;
} }
// // try {
isFetching.value = false; // notification.info({
// message: '...',
// duration: 3,
// });
// const res = await props.runSpider(
// {
// publish_start_time,
// publish_end_time,
// llm_api_key: '77c068fd-d5b6-4c33-97d8-db5511a09b26',
// },
// );
// if (res.data.outputs.result) {
// //
// fetchResult.value = res.data.outputs.result;
// notification.success({
// message: '',
// duration: 3,
// });
// 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: 'normal',
// type: 'primary',
// style: {
// marginLeft: '10px',
// },
// onClick: () => {
// // <a>
// const link = document.createElement('a');
// link.href = msg.content; //
// link.download = filename; //
// document.body.append(link); // <a>
// link.click(); //
// link.remove(); // <a>
// },
// },
// '',
// ),
// ]),
// });
// fetchStatus.value = 'completed';
// } else {
// fetchResult.value = '';
// message.error('');
// }
// } catch (error) {
// message.error(`${error}`);
// }
}; };
// //
@ -287,27 +478,22 @@ watch(
footer: msg.footer, footer: msg.footer,
}); });
} else { } else {
const filename = ref('');
if (msg.content && isDocxURL(msg.content)) {
filename.value = extractDocxFilename(msg.content);
}
resultItems.value.push({ resultItems.value.push({
key: resultItems.value.length + 1, key: resultItems.value.length + 1,
role: msg.role, // 'user' or 'ai' role: msg.role, // 'user' or 'ai'
content: '文档已生成', content: '文档已生成',
footer: h(Flex, null, [ footer: h(Flex, null, [
h( // h(
Button, // Button,
{ // {
size: 'normal', // size: 'normal',
type: 'primary', // type: 'primary',
onClick: () => { // onClick: () => {
openPreviewDrawer('right', filename); // openPreviewDrawer('right', filename);
}, // },
}, // },
'文档预览', // '',
), // ),
h( h(
Button, Button,
{ {
@ -320,7 +506,7 @@ watch(
// <a> // <a>
const link = document.createElement('a'); const link = document.createElement('a');
link.href = msg.content; // link.href = msg.content; //
link.download = filename; // link.download = '广州公共资源交易中心数据获取'; //
document.body.append(link); // <a> document.body.append(link); // <a>
link.click(); // link.click(); //
link.remove(); // <a> link.remove(); // <a>