diff --git a/api/app/lib/controllers/metadataAcquisition/initJob.js b/api/app/lib/controllers/metadataAcquisition/initJob.js index 13a361f..0cda79a 100644 --- a/api/app/lib/controllers/metadataAcquisition/initJob.js +++ b/api/app/lib/controllers/metadataAcquisition/initJob.js @@ -26,7 +26,7 @@ module.exports = async function (app, task) { const endTime = moment() const logBody = { task: task.id, - success: true, + success: false, details: '采集失败' + JSON.stringify(error).substring(0, 248), startTime: startTime, endTime: endTime diff --git a/api/app/lib/controllers/metadataAcquisition/log.js b/api/app/lib/controllers/metadataAcquisition/log.js index 70fcfd3..0a40efc 100644 --- a/api/app/lib/controllers/metadataAcquisition/log.js +++ b/api/app/lib/controllers/metadataAcquisition/log.js @@ -1,10 +1,10 @@ 'use strict'; -function getAcquisitionTask(opts) { +function getAcquisitionLog(opts) { return async function (ctx, next) { const models = ctx.fs.dc.models; - const { page, limit, taskName } = ctx.query; + const { page, limit, taskName, logState } = ctx.query; let errMsg = { message: '获取采集任务失败' } const Op = ctx.fs.dc.ORM.Op; try { @@ -28,6 +28,10 @@ function getAcquisitionTask(opts) { ] } + if (logState && logState != '全部') { + searchWhere.success = logState == 'true' ? true : false + } + option.where = searchWhere let limit_ = limit || 10; @@ -50,7 +54,5 @@ function getAcquisitionTask(opts) { } module.exports = { - - getAcquisitionTask, - + getAcquisitionLog, } diff --git a/api/app/lib/controllers/metadataAcquisition/taskHandle.js b/api/app/lib/controllers/metadataAcquisition/taskHandle.js index 97d45f6..b69b509 100644 --- a/api/app/lib/controllers/metadataAcquisition/taskHandle.js +++ b/api/app/lib/controllers/metadataAcquisition/taskHandle.js @@ -170,7 +170,7 @@ async function handleTask(app, task) { const endTime = moment() const logBody = { task: task.id, - success: true, + success: false, details: '采集失败' + JSON.stringify(error).substring(0, 248), startTime: startTime, endTime: endTime diff --git a/api/app/lib/routes/metadataAcquisition/log.js b/api/app/lib/routes/metadataAcquisition/log.js index 76f2367..d72d83b 100644 --- a/api/app/lib/routes/metadataAcquisition/log.js +++ b/api/app/lib/routes/metadataAcquisition/log.js @@ -6,6 +6,6 @@ module.exports = function (app, router, opts, AuthCode) { //获取采集任务列表 app.fs.api.logAttr['GET/meta/acq/logs'] = { content: '获取采集任务列表', visible: true }; - router.get('/meta/acq/logs', log.getAcquisitionTask(opts)); + router.get('/meta/acq/logs', log.getAcquisitionLog(opts)); }; diff --git a/web/client/src/sections/metadataAcquisition/components/steps/postgre/stepThree.js b/web/client/src/sections/metadataAcquisition/components/steps/postgre/stepThree.js index c1648f6..7bc86e7 100644 --- a/web/client/src/sections/metadataAcquisition/components/steps/postgre/stepThree.js +++ b/web/client/src/sections/metadataAcquisition/components/steps/postgre/stepThree.js @@ -28,6 +28,9 @@ function StepThree(props) { const checkCron = async (rule, value) => { try { var interval = parser.parseExpression(value); + if (interval?.fields?.second.length == 60) { + return Promise.reject(new Error('cron最小间隔不能小于一分钟!')); + } console.log('Date: ', moment(interval.next().toString()).format('YYYY-MM-DD HH:mm:ss')); return Promise.resolve(); } catch (err) { @@ -61,7 +64,7 @@ function StepThree(props) { }} > - {dataSourceFilter && < ProFormSelect + {dataSourceFilter && { diff --git a/web/client/src/sections/metadataAcquisition/containers/acquisitionLog.js b/web/client/src/sections/metadataAcquisition/containers/acquisitionLog.js index 5c36487..13a2705 100644 --- a/web/client/src/sections/metadataAcquisition/containers/acquisitionLog.js +++ b/web/client/src/sections/metadataAcquisition/containers/acquisitionLog.js @@ -1,23 +1,37 @@ import React, { useEffect, useState } from 'react' -import { Spin, Popconfirm, Tree, Row, Col, Button, Input, Table } from 'antd'; +import { Spin, Popconfirm, Tree, Row, Col, Button, Input, Table, Select } from 'antd'; import { connect } from 'react-redux'; import ProTable from '@ant-design/pro-table'; import moment from 'moment'; +import { useFsRequest, ApiTable } from '$utils'; +const { Option } = Select; +import xlsx from 'xlsx'; import './style.less'; function AcquisitionLog(props) { const { loading, clientHeight, actions, dispatch, acqlogs } = props; const [pageSize, setPageSize] = useState(10); const [currentPage, setCurrentPage] = useState(1); const [searchValue, setSearchValue] = useState('') + const [logState, setLogState] = useState('全部') + const queryData = (search) => { const query = { limit: search ? 10 : pageSize || 10, page: search ? 1 : currentPage || 1, + logState: logState, taskName: searchValue } dispatch(actions.metadataAcquisition.getLogs(query)); } + const { data: allLogs = {} } = useFsRequest({ + url: ApiTable.getLogs, + query: { + logState: logState, + taskName: searchValue + }, + refreshDeps: [logState, searchValue] + }); useEffect(() => { queryData(); @@ -31,6 +45,13 @@ function AcquisitionLog(props) { return record?.acquisitionTask?.taskName; } }, + // { + // title: '任务描述', + // dataIndex: 'taskDescription', + // render: (text, record) => { + // return record?.acquisitionTask?.description; + // } + // }, { title: '数据源名称', dataIndex: 'dataSourceName', @@ -39,36 +60,111 @@ function AcquisitionLog(props) { } }, { - title: '适配器类型', - dataIndex: 'adapter', - }, - { - title: '采集方式', - dataIndex: 'control', + title: '任务状态', + dataIndex: 'success', + render: (text, record) => { + return record?.success ? '采集成功' : "采集失败"; + }, }, { - title: '执行周期', - dataIndex: 'cron', - // render: (text, record) => { - // return transCron(record?.cron); - // } + title: '开始时间', + dataIndex: 'startTime', + render: (text, record) => { + return moment(record?.startTime).format('YYYY-MM-DD HH:mm:ss'); + }, + sorter: { + compare: (a, b) => moment(b?.startTime).valueOf() - moment(a?.startTime).valueOf(), + multiple: 2, + }, }, { - title: '重复次数', - dataIndex: 'retryCount', + title: '耗时', + dataIndex: 'endTime', + render: (text, record) => { + return moment(record?.endTime).valueOf() - moment(record?.startTime).valueOf() + '毫秒'; + }, + sorter: { + compare: (a, b) => (moment(b?.endTime).valueOf() - moment(b?.startTime).valueOf()) - (moment(a?.endTime).valueOf() - moment(a?.startTime).valueOf()), + multiple: 2, + }, }, { - title: '时间间隔(分钟)', - dataIndex: 'retryTime', + title: '详情', + dataIndex: 'details', + ellipsis: true, }, ]; + const handleTableExport = () => { + let rows = allLogs?.rows; + if (rows.length == 0) { + message.info('当前无采集日志信息!') + } + let excelTitle = columns.map(s => { + return { k: s.dataIndex, v: s.title } + }); + + let workBook = { + SheetNames: [], //sheet名称 + Sheets: {} //根据SheetNames名称顺序依次添加每个sheet数据 + }; + if (rows && rows.length > 0) { + let sheetName = '日志信息'; + let sheetDataMap = new Map(); + let sheetData = [excelTitle]; + let index = 1; + rows.map(record => { + sheetData.push([ + { k: 'taskName', v: record?.acquisitionTask?.taskName }, + // { k: 'taskDescription', v: record?.acquisitionTask?.description || '' }, + { k: 'dataSourceName', v: record?.acquisitionTask?.dataSource?.name }, + { k: 'success', v: record?.success ? '采集成功' : "采集失败" }, + { k: 'startTime', v: moment(record?.startTime).format('YYYY-MM-DD HH:mm:ss') }, + { k: 'endTime', v: moment(record?.endTime).valueOf() - moment(record?.startTime).valueOf() + '毫秒' }, + { k: 'details', v: record?.details }, + ]); + index = index + 1; + }) + + sheetDataMap.set(sheetName, sheetData); + sheetDataMap.forEach((values, key) => { + // 写入excel + workBook.Sheets[key] = xlsx.utils.aoa_to_sheet(values); + workBook.Sheets[key]['!cols'] = [{ wpx: 50 }, { wpx: 150 }, { wpx: 180 }, { wpx: 230 }, { wpx: 230 }, { wpx: 230 }] + }) + workBook.SheetNames = [sheetName]; + } + // 将workBook写入文件 + xlsx.writeFile(workBook, `采集日志-${moment().format('YYYY-MM-DD HH:mm:ss')}.xlsx`); + } + return - + + 关键字搜索: { setSearchValue(e.target.value) }} - style={{ width: 220, marginRight: 15 }} placeholder="数据源或任务名称" /> - + style={{ width: 220, marginRight: 15 }} placeholder="任务名称或数据源" /> + 任务状态: + + + + +