Commit 518e8e10 by yzh

feat:任务信息接口接上

parent 33062b3a
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"@types/nprogress": "^0.2.3", "@types/nprogress": "^0.2.3",
"@types/uuid": "^10.0.0", "@types/uuid": "^10.0.0",
"axios": "^1.9.0", "axios": "^1.9.0",
"cron-parser": "^5.4.0",
"echarts": "^5.6.0", "echarts": "^5.6.0",
"element-plus": "^2.9.10", "element-plus": "^2.9.10",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
......
...@@ -26,6 +26,9 @@ importers: ...@@ -26,6 +26,9 @@ importers:
axios: axios:
specifier: ^1.9.0 specifier: ^1.9.0
version: 1.9.0 version: 1.9.0
cron-parser:
specifier: ^5.4.0
version: 5.4.0
echarts: echarts:
specifier: ^5.6.0 specifier: ^5.6.0
version: 5.6.0 version: 5.6.0
...@@ -706,6 +709,10 @@ packages: ...@@ -706,6 +709,10 @@ packages:
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
engines: {node: '>=12.13'} engines: {node: '>=12.13'}
cron-parser@5.4.0:
resolution: {integrity: sha512-HxYB8vTvnQFx4dLsZpGRa0uHp6X3qIzS3ZJgJ9v6l/5TJMgeWQbLkR5yiJ5hOxGbc9+jCADDnydIe15ReLZnJA==}
engines: {node: '>=18'}
css-tree@3.1.0: css-tree@3.1.0:
resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
...@@ -918,6 +925,10 @@ packages: ...@@ -918,6 +925,10 @@ packages:
lodash@4.17.21: lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
luxon@3.7.2:
resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==}
engines: {node: '>=12'}
magic-string@0.30.17: magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
...@@ -1967,6 +1978,10 @@ snapshots: ...@@ -1967,6 +1978,10 @@ snapshots:
dependencies: dependencies:
is-what: 4.1.16 is-what: 4.1.16
cron-parser@5.4.0:
dependencies:
luxon: 3.7.2
css-tree@3.1.0: css-tree@3.1.0:
dependencies: dependencies:
mdn-data: 2.12.2 mdn-data: 2.12.2
...@@ -2179,6 +2194,8 @@ snapshots: ...@@ -2179,6 +2194,8 @@ snapshots:
lodash@4.17.21: {} lodash@4.17.21: {}
luxon@3.7.2: {}
magic-string@0.30.17: magic-string@0.30.17:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/sourcemap-codec': 1.5.0
......
...@@ -95,6 +95,7 @@ export const spiderTaskApi = { ...@@ -95,6 +95,7 @@ export const spiderTaskApi = {
pauseJob: '/schedule/pauseJob', pauseJob: '/schedule/pauseJob',
resumeJob: '/schedule/resumeJob', resumeJob: '/schedule/resumeJob',
jobDetail: '/schedule/jobDetail', jobDetail: '/schedule/jobDetail',
taskCount:'/schedule/getAllJobCount'
} as const } as const
// 爬虫数据相关接口 // 爬虫数据相关接口
...@@ -108,6 +109,7 @@ export const spiderDataApi = { ...@@ -108,6 +109,7 @@ export const spiderDataApi = {
stList: '/spaceTrack/list', stList: '/spaceTrack/list',
stDetail: '/spaceTrack/detail', stDetail: '/spaceTrack/detail',
stDataDelete: '/sspaceTrackt/delete', stDataDelete: '/sspaceTrackt/delete',
exportSpiderData: '/export/downloadFile',
} as const } as const
...@@ -116,6 +118,6 @@ export const dataApi = { ...@@ -116,6 +118,6 @@ export const dataApi = {
dataStatistics: '/statistic/dataStatistics', dataStatistics: '/statistic/dataStatistics',
taskStatistics: '/statistic/taskStatistics', taskStatistics: '/statistic/taskStatistics',
performanceStatistics: '/statistic/performanceStatistics', performanceStatistics: '/statistic/performanceStatistics',
allSpiderTaskStatistics: '/statistic/getAllTaskStatistics',
} as const } as const
...@@ -81,4 +81,13 @@ export function deleteStData(data: UserQueryParams) { ...@@ -81,4 +81,13 @@ export function deleteStData(data: UserQueryParams) {
method: POST, method: POST,
data data
}) as unknown as Promise<ApiResponse> }) as unknown as Promise<ApiResponse>
}
// 导出爬虫数据
export function esportSpiderData(data: UserQueryParams) {
return request({
url: spiderDataApi.exportSpiderData,
method: POST,
data
}) as unknown as Promise<ApiResponse>
} }
\ No newline at end of file
...@@ -63,4 +63,13 @@ export function getTaskData(data: UserQueryParams) { ...@@ -63,4 +63,13 @@ export function getTaskData(data: UserQueryParams) {
method: POST, method: POST,
data data
}) as unknown as Promise<ApiResponse> }) as unknown as Promise<ApiResponse>
}
// 获取爬虫任务统计
export function getTaskCount(data: UserQueryParams) {
return request({
url: spiderTaskApi.taskCount,
method: POST,
data
}) as unknown as Promise<ApiResponse>
} }
\ No newline at end of file
...@@ -20,11 +20,20 @@ export function getSpiderTaskList(params: QueryParams): Promise<ApiResponse> { ...@@ -20,11 +20,20 @@ export function getSpiderTaskList(params: QueryParams): Promise<ApiResponse> {
}) as unknown as Promise<ApiResponse> }) as unknown as Promise<ApiResponse>
} }
// 获取爬虫任务列表 // 获取性能统计列表
export function getPerformanceList(params: QueryParams): Promise<ApiResponse> { export function getPerformanceList(params: QueryParams): Promise<ApiResponse> {
return request({ return request({
url: dataApi.performanceStatistics, url: dataApi.performanceStatistics,
method: POST, method: POST,
params params
}) as unknown as Promise<ApiResponse> }) as unknown as Promise<ApiResponse>
}
// 获取爬虫任务统计列表
export function getAllSpiderTaskStatistics(params: QueryParams): Promise<ApiResponse> {
return request({
url: dataApi.allSpiderTaskStatistics,
method: POST,
params
}) as unknown as Promise<ApiResponse>
} }
\ No newline at end of file
...@@ -4,12 +4,12 @@ ...@@ -4,12 +4,12 @@
<!-- <span style="color: #fff;font-size: 15px;">请选择导出数据时间与数据类型。</span> <!-- <span style="color: #fff;font-size: 15px;">请选择导出数据时间与数据类型。</span>
<br> --> <br> -->
<el-date-picker v-model="timeValue" type="datetimerange" format="YYYY-MM-DD HH:mm:ss" start-placeholder="开始时间" <el-date-picker v-model="timeValue" type="datetimerange" format="YYYY-MM-DD HH:mm:ss" start-placeholder="开始时间"
end-placeholder="结束时间" date-format="YYYY/MM/DD ddd" time-format="A hh:mm:ss" style="width: 270px" end-placeholder="结束时间" date-format="YYYY/MM/DD ddd" time-format="A hh:mm:ss" style="width: 280px"
value-format="YYYY-MM-DD HH:mm:ss" /> value-format="YYYY-MM-DD HH:mm:ss" />
<el-checkbox-group v-model="checkList"> <el-checkbox-group v-model="checkList">
<el-checkbox label="DSN数据" value="dsn" /> <el-checkbox label="DSN数据" value="dsn" />
<el-checkbox label="ITU数据" value="itu" /> <el-checkbox label="ITU数据" value="itu" />
<el-checkbox label="ST数据" value="st" /> <el-checkbox label="ST数据" value="spaceTrack" />
</el-checkbox-group> </el-checkbox-group>
</div> </div>
<template #footer> <template #footer>
...@@ -26,7 +26,8 @@ ...@@ -26,7 +26,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import { defineProps } from 'vue'; import { defineProps } from 'vue';
import { esportSpiderData } from '@/api/spiderData';
import axios from 'axios'
const props = defineProps({ const props = defineProps({
dialogVisible: { dialogVisible: {
type: Boolean, type: Boolean,
...@@ -42,8 +43,28 @@ const exportDialogVisible = ref(props.dialogVisible) ...@@ -42,8 +43,28 @@ const exportDialogVisible = ref(props.dialogVisible)
const checkList = ref([]) const checkList = ref([])
const timeValue = ref('') const timeValue = ref('')
// 导出方法 // 导出方法
const handleExport = () => { const handleExport = async () => {
emit('confirm') const result = await esportSpiderData({ times: timeValue.value, filters: checkList.value })
// aaa(result)
// axios({
// method: 'post',
// url: 'http://localhost:5001/api/export/downloadFile',
// responseType: 'blob',
// data: { times: timeValue.value, filters: checkList.value }
// // he
// })
// .then(res => {
// // 假设 data 是返回来的二进制数据
// const url = window.URL.createObjectURL(new Blob([res], { type: "application/zip" }))
// const link = document.createElement('a')
// link.style.display = 'none'
// link.href = url
// link.setAttribute('download', '333.zip')
// document.body.appendChild(link)
// link.click()
// document.body.removeChild(link)
// })
exportDialogVisible.value = false exportDialogVisible.value = false
} }
// 关闭弹窗的方法 // 关闭弹窗的方法
...@@ -62,4 +83,89 @@ watch(() => exportDialogVisible.value, ...@@ -62,4 +83,89 @@ watch(() => exportDialogVisible.value,
emit('update:dialogVisible', newVal) emit('update:dialogVisible', newVal)
} }
) )
// const triggerDownload = (blobData: any) => {
// const zipFile = new File([blobData], 'archive.zip', {
// type: 'application/zip',
// });
// console.log(zipFile);
// const fileUrl = URL.createObjectURL(zipFile);
// // 创建下载链接
// const downloadLink = document.createElement('a');
// downloadLink.href = fileUrl;
// // 使用File对象的名称作为下载文件名
// downloadLink.download = zipFile.name;
// // 将链接添加到页面并触发点击
// document.body.appendChild(downloadLink);
// downloadLink.click();
// // 清理资源
// setTimeout(() => {
// // 移除链接元素
// document.body.removeChild(downloadLink);
// // 释放临时URL
// URL.revokeObjectURL(fileUrl);
// }, 0);
// }
// const aaa = (res: any) => {
// // const blob = new Blob([res], { type: 'application/zip' })
// // const link = document.createElement('a')
// // link.style.display = 'none'
// // link.href = URL.createObjectURL(blob)
// // link.setAttribute('download', `${'111'}.zip`)
// // document.body.appendChild(link)
// // link.click()
// // document.body.removeChild(link)
// // const url = window.URL.createObjectURL(new Blob([res], { type: "application/zip" }))
// // const link = document.createElement('a')
// // link.style.display = 'none'
// // link.href = url
// // link.setAttribute('download', '222.zip')
// // document.body.appendChild(link)
// // link.click()
// // document.body.removeChild(link)
// const url = window.URL.createObjectURL(res);
// const a = document.createElement('a');
// a.style.display = 'none';
// a.href = url;
// a.download = 'example.zip';
// document.body.appendChild(a);
// a.click();
// window.URL.revokeObjectURL(url);
// }
// function downloadZipFromBinary(binaryString: any, fileName: string) {
// try {
// if (!fileName.endsWith('.zip')) {
// fileName += '.zip';
// }
// const uint8Array = new Uint8Array(binaryString);
// const blob = new Blob([uint8Array], { type: 'application/zip' });
// const url = URL.createObjectURL(blob);
// const a = document.createElement('a');
// a.href = url;
// a.download = fileName;
// document.body.appendChild(a);
// a.click();
// setTimeout(() => {
// document.body.removeChild(a);
// URL.revokeObjectURL(url);
// }, 100);
// } catch (error) {
// console.error('下载ZIP文件时发生错误:', error);
// throw error;
// }
// }
</script> </script>
\ No newline at end of file
...@@ -62,4 +62,38 @@ ...@@ -62,4 +62,38 @@
--el-segmented-color: #FFFFFF; --el-segmented-color: #FFFFFF;
--el-segmented-item-hover-color: #FFFFFF; --el-segmented-item-hover-color: #FFFFFF;
--el-segmented-item-active-bg-color: #1977d5d7; --el-segmented-item-active-bg-color: #1977d5d7;
}
.el-dialog {
background-image: url("@/assets/picture/dialog1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
.el-form-item__label {
color: #ffffff;
}
.el-dialog__header {
color: #ffffff;
}
.el-dialog__title {
color: #ffffff;
}
.el-textarea__inner {
background-color: #1d5484;
color: #ffffff;
box-shadow: none;
}
}
// .el-date-editor {
// .el-date-editor {
// color: #ffffff;
// }
// }
.el-date-editor .el-range-input{
color: #ffffff;
} }
\ No newline at end of file
...@@ -7,7 +7,7 @@ const instance = axios.create({ ...@@ -7,7 +7,7 @@ const instance = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API || '', baseURL: import.meta.env.VITE_APP_BASE_API || '',
timeout: 10000, // 毫秒 timeout: 10000, // 毫秒
headers: { headers: {
'Content-Type': 'application/json; charset=utf-8' 'Content-Type': 'application/zip; charset=utf-8'
} }
}) })
...@@ -120,4 +120,5 @@ export interface UserQueryParams { ...@@ -120,4 +120,5 @@ export interface UserQueryParams {
options?: string options?: string
sat_name?: string sat_name?: string
ntc_id?: string ntc_id?: string
filters?: any
} }
\ No newline at end of file
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
<el-text class="mx-1">获取时间:</el-text> <el-text class="mx-1">获取时间:</el-text>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-date-picker v-model="timeValue" type="datetimerange" format="YYYY-MM-DD HH:mm:ss" start-placeholder="开始时间" <el-date-picker v-model="timeValue" type="datetimerange" format="YYYY-MM-DD HH:mm:ss"
style="width: 250px" end-placeholder="结束时间" date-format="YYYY/MM/DD ddd" time-format="A hh:mm:ss" start-placeholder="开始时间" style="width: 250px" end-placeholder="结束时间"
value-format="YYYY-MM-DD HH:mm:ss" /> date-format="YYYY/MM/DD ddd" time-format="A hh:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-text class="mx-1">SNS Notice ID:</el-text> <el-text class="mx-1">SNS Notice ID:</el-text>
...@@ -90,9 +90,10 @@ ...@@ -90,9 +90,10 @@
</el-table-column> </el-table-column>
<el-table-column property="regulatory_status.active_status" label="状态" show-overflow-tooltip /> <el-table-column property="regulatory_status.active_status" label="状态" show-overflow-tooltip />
<el-table-column property="regulatory_status.prd_valid" label="有效期" show-overflow-tooltip /> <el-table-column property="regulatory_status.prd_valid" label="有效期" show-overflow-tooltip />
<el-table-column property="regulatory_status.d_reg_limit" label="最早使用日期" show-overflow-tooltip > <el-table-column property="regulatory_status.d_reg_limit" label="最早使用日期" show-overflow-tooltip>
<template #default="scope"> <template #default="scope">
{{ scope.row.regulatory_status.d_reg_limit === null ? '-' : scope.row.regulatory_status.d_reg_limit }} {{ scope.row.regulatory_status.d_reg_limit === null ? '-' : scope.row.regulatory_status.d_reg_limit
}}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column property="regulatory_status.f_biu_grps" label="是否确认使用" show-overflow-tooltip /> <el-table-column property="regulatory_status.f_biu_grps" label="是否确认使用" show-overflow-tooltip />
...@@ -334,9 +335,8 @@ const handleDetails = async (id: any) => { ...@@ -334,9 +335,8 @@ const handleDetails = async (id: any) => {
// console.log(id._id); // console.log(id._id);
const res = await getItuDetail({ id: id._id }) const res = await getItuDetail({ id: id._id })
console.log(res); console.log(res);
detailVisibleValue.value = true
snsId.value = res.data.item.ntc_id snsId.value = res.data.item.ntc_id
department.value = res.data.item.notifying_adm_tooltip department.value = res.data.item.adm
targetName.value = res.data.identity.sat_name targetName.value = res.data.identity.sat_name
planType.value = res.data.identity.plan_type planType.value = res.data.identity.plan_type
syncType.value = res.data.identity.ntc_type syncType.value = res.data.identity.ntc_type
...@@ -349,15 +349,17 @@ const handleDetails = async (id: any) => { ...@@ -349,15 +349,17 @@ const handleDetails = async (id: any) => {
highestFrequency.value = res.data.item.freq_max === null ? '无' : res.data.item.freq_max highestFrequency.value = res.data.item.freq_max === null ? '无' : res.data.item.freq_max
status.value = res.data.regulatory_status.active_status status.value = res.data.regulatory_status.active_status
validityPeriod.value = res.data.regulatory_status.prd_valid validityPeriod.value = res.data.regulatory_status.prd_valid
earliestUsageDate.value = res.data.regulatory_status.d_reg_limit earliestUsageDate.value = res.data.regulatory_status.d_reg_limit === null ? '无' : res.data.regulatory_status.d_reg_limit
isUsed.value = res.data.regulatory_status.f_biu_grps isUsed.value = res.data.regulatory_status.f_biu_grps
isPauseUsed.value = res.data.regulatory_status.resumption_list isPauseUsed.value = res.data.regulatory_status.resumption_list
// recordTime.value = res.data.regulatory_status.d_inuse_list recordTime.value = res.data.crawl_time
IsInTheInternationalFrequencyList.value = res.data.regulatory_status.mifr IsInTheInternationalFrequencyList.value = res.data.regulatory_status.mifr
earliestRegulatoryDate.value = JSON.parse(res.data.regulatory_status.d_inuse_list) earliestRegulatoryDate.value = res.data.regulatory_status.d_inuse_list
isRestoreUsed.value = res.data.regulatory_status.resumption_list isRestoreUsed.value = res.data.regulatory_status.resumption_list
validityPeriodSatelliteNetworkOldName.value = res.data.regulatory_status.old_satellite_network_name validityPeriodSatelliteNetworkOldName.value = res.data.regulatory_status.old_satellite_network_name
BFIFICdate.value = res.data.regulatory_status.d_wic BFIFICdate.value = res.data.regulatory_status.d_wic === null ? '无' : res.data.regulatory_status.d_wic
detailVisibleValue.value = true
} }
const getData = async () => { const getData = async () => {
const res = await getItulist({ page: pageObj.value.pageNo, size: pageObj.value.pageSize }) const res = await getItulist({ page: pageObj.value.pageNo, size: pageObj.value.pageSize })
...@@ -397,6 +399,9 @@ onMounted(() => { ...@@ -397,6 +399,9 @@ onMounted(() => {
<style scoped lang="scss"> <style scoped lang="scss">
// 调整表单项间距 // 调整表单项间距
.detailForm { .detailForm {
// background-image: url("@/assets/picture/dialog1.png");
// background-size: 100% 100%;
// background-repeat: no-repeat;
.el-dialog-title { .el-dialog-title {
font-size: 180px; font-size: 180px;
} }
...@@ -425,9 +430,11 @@ onMounted(() => { ...@@ -425,9 +430,11 @@ onMounted(() => {
.el-text { .el-text {
color: #FFFFFF; color: #FFFFFF;
} }
</style> </style>
<style> <style>
.el-input { .el-input {
--el-input-text-color: #FFFFFF; --el-input-text-color: #FFFFFF;
} }
......
...@@ -338,4 +338,6 @@ onMounted(() => { ...@@ -338,4 +338,6 @@ onMounted(() => {
.el-button:focus { .el-button:focus {
outline: none; outline: none;
} }
</style> </style>
\ No newline at end of file
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
<div> <div>
<div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToStatus" /> <div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToStatus" />
<div class="text-left p-4 "> <div class="text-left p-4 ">
<div class="custom-style"> <div class="custom-style flex gap-4">
<el-segmented v-model="mode" :options="sizeOptions" style="margin-bottom: 1rem" size="default" /> <el-segmented v-model="mode" :options="sizeOptions" style="margin-bottom: 1rem" size="default" />
<el-button type="primary" @click="handleExport <el-button type="primary" @click="handleExport" class="m-r-10">导出</el-button>
">导出最近</el-button>
</div> </div>
</div> </div>
<!-- 综合数据页面组件 --> <!-- 综合数据页面组件 -->
......
...@@ -96,9 +96,6 @@ const getData = async () => { ...@@ -96,9 +96,6 @@ const getData = async () => {
speed.value = performance.data.success speed.value = performance.data.success
errorRate.value = performance.data.error errorRate.value = performance.data.error
unusualRate.value = performance.data.exception unusualRate.value = performance.data.exception
console.log(staticData);
console.log(spiderTask);
console.log(performance);
} }
onMounted(() => { onMounted(() => {
......
...@@ -6,16 +6,16 @@ ...@@ -6,16 +6,16 @@
<span>DSN爬取任务</span> <span>DSN爬取任务</span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>任务采集目标数: {{ totalDataNumber }} 638</span> <span>DSN爬虫任务数: {{ dsnTotalTaskNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>任务执行成功统计: {{ totalPageNumber }} 79</span> <span>任务执行成功统计: {{ dsnTaskSuccessNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>采集速度: {{ totalTargetNumber }} 324</span> <span>任务执行失败统计: {{ dsnTaskFailNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>错误率: {{ totalTargetNumber }} 1%</span> <span>错误率: {{ dsnErrorRate }} </span>
</div> </div>
</div> </div>
<div class="dataCard" @click="goToITUTaskRecordPage"> <div class="dataCard" @click="goToITUTaskRecordPage">
...@@ -23,16 +23,16 @@ ...@@ -23,16 +23,16 @@
<span>ITU爬取任务</span> <span>ITU爬取任务</span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>任务采集目标数: {{ totalDataNumber }} 148</span> <span>ITU爬虫任务数: {{ ituTotalTaskNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>任务执行成功统计: {{ totalPageNumber }} 98</span> <span>任务执行成功统计: {{ ituTaskSuccessNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>采集速度: {{ totalTargetNumber }} 322</span> <span>任务执行失败统计: {{ ituTaskFailNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>错误率: {{ totalTargetNumber }} 1%</span> <span>错误率: {{ ituErrorRate }} </span>
</div> </div>
</div> </div>
<div class="dataCard" @click="goToSTTaskRecordPage"> <div class="dataCard" @click="goToSTTaskRecordPage">
...@@ -40,16 +40,16 @@ ...@@ -40,16 +40,16 @@
<span>ST爬取任务</span> <span>ST爬取任务</span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>任务采集目标数: {{ totalDataNumber }} 136</span> <span>ST爬虫任务数: {{ stTotalTaskNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>任务执行成功统计: {{ totalPageNumber }} 86</span> <span>任务执行成功统计: {{ stTaskSuccessNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>采集速度: {{ totalTargetNumber }} 342</span> <span>采集速度: {{ stTaskFailNumber }} </span>
</div> </div>
<div class="wordStyle"> <div class="wordStyle">
<span>错误率: {{ totalTargetNumber }} 0%</span> <span>错误率: {{ stErrorRate }} </span>
</div> </div>
</div> </div>
</div> </div>
...@@ -57,41 +57,24 @@ ...@@ -57,41 +57,24 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { getAllSpiderTaskStatistics } from '@/api/staticData';
import { onMounted,ref } from 'vue';
const router = useRouter() const router = useRouter()
defineProps({
totalDataNumber: { const dsnTotalTaskNumber = ref('')
type: String, const dsnTaskSuccessNumber = ref('')
default: '' const dsnTaskFailNumber = ref('')
}, const dsnErrorRate = ref('')
totalPageNumber: { const ituTotalTaskNumber = ref('')
type: String, const ituTaskSuccessNumber = ref('')
default: '' const ituTaskFailNumber = ref('')
}, const ituErrorRate = ref('')
totalTargetNumber: { const stTotalTaskNumber = ref('')
type: String, const stTaskSuccessNumber = ref('')
default: '' const stTaskFailNumber = ref('')
}, const stErrorRate = ref('')
successTask: {
type: String,
default: ''
},
failTask: {
type: String,
default: ''
},
unusualTask: {
type: String,
default: ''
},
speed: {
type: String,
default: ''
},
errorRate: {
type: String,
default: ''
}
})
const goToDSNTaskRecordPage = () => { const goToDSNTaskRecordPage = () => {
router.push({ router.push({
...@@ -122,6 +105,25 @@ const goToSTTaskRecordPage = () => { ...@@ -122,6 +105,25 @@ const goToSTTaskRecordPage = () => {
} }
}) })
} }
const getData = async () => {
const res = await getAllSpiderTaskStatistics({})
console.log(res);
dsnTotalTaskNumber.value = res.data.dsn_now.totalCount
dsnTaskSuccessNumber.value = res.data.dsn_now.successCount
dsnTaskFailNumber.value = res.data.dsn_now.failCount
dsnErrorRate.value = res.data.dsn_now.errorRate
ituTotalTaskNumber.value = res.data.itu_space_explorer.totalCount
ituTaskSuccessNumber.value = res.data.itu_space_explorer.successCount
ituTaskFailNumber.value = res.data.itu_space_explorer.failCount
ituErrorRate.value = res.data.itu_space_explorer.errorRate
stTotalTaskNumber.value = res.data.space_track.totalCount
stTaskSuccessNumber.value = res.data.space_track.successCount
stTaskFailNumber.value = res.data.space_track.failCount
stErrorRate.value = res.data.space_track.errorRate
}
onMounted(() => {
getData()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
<!-- 任务执行统计卡片组件 --> <!-- 任务执行统计卡片组件 -->
<template> <template>
<div class="text-left p-4 toolbarStyle "> <div>
<div class="formStyle"> <div class="text-left p-4 toolbarStyle ">
<el-form inline> <div class="formStyle">
<el-form-item> <el-form inline>
<el-text class="mx-1" style="color: #fff;">所属爬虫:</el-text> <el-form-item>
</el-form-item> <el-text class="mx-1" style="color: #fff;">所属爬虫:</el-text>
<el-form-item> </el-form-item>
<div> <el-form-item>
<el-select v-model="searchCondition.spiders" placeholder="请选择" style="width: 220px"> <div>
<el-option v-for="item in taskSelectOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-select v-model="searchCondition.spiders" placeholder="请选择" style="width: 220px">
</el-select> <el-option v-for="item in taskSelectOptions" :key="item.value" :label="item.label"
</div> :value="item.value" />
</el-form-item> </el-select>
<!-- <el-form-item> </div>
</el-form-item>
<!-- <el-form-item>
<el-text class="mx-1" style="color: #fff;">任务名称:</el-text> <el-text class="mx-1" style="color: #fff;">任务名称:</el-text>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-input v-model="taskName" placeholder="请输入" style="width: 220px" /> <el-input v-model="taskName" placeholder="请输入" style="width: 220px" />
</el-form-item> --> </el-form-item> -->
<el-form-item>
<el-space>
<el-button type="primary" @Click="search">查询</el-button>
</el-space>
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary" @click="openTaskDialog">新建任务</el-button>
</el-space>
</el-form-item>
</el-form>
</div>
</div>
<div class="cardStyle">
<div class="taskCard p-6 " v-for="task in taskList" :key="task.taskId">
<div class="taskContent">
<div>
<el-form-item>
<span class="titleStyle">{{ task.kwargs.options === '' ? '无名称' : JSON.parse(task.kwargs.options).jobName
}}</span>
</el-form-item>
</div>
<div>
<el-form-item>
<el-button type="primary" @click="editTask(task)" class="editButton">编辑</el-button>
<el-button type="success" @click="goToTaskRecord" class="recordButton">执行记录 </el-button>
<el-button type="danger" @click="deleteTask(task)" class="deleteButton">删除</el-button>
</el-form-item>
</div>
<div class="wordStyle">
<el-form-item>
<el-space>
<span class="wordStyle">启用/停止: </span>
<el-switch v-model="task.status" :active-value="'running'" :inactive-value="'paused'"
@change="(newStatus: any) => changeStatus(task, newStatus)" />
<span class="wordStyle">执行频率: {{ task.frequency }} </span>
</el-space>
</el-form-item>
</div>
<div class="wordStyle">
<el-form-item>
<el-space>
<span class="wordStyle">执行次数: 个; </span>
<span class="wordStyle">成功次数: 个</span>
</el-space>
</el-form-item>
</div>
<div class="wordStyle ">
<el-form-item> <el-form-item>
<el-space> <el-space>
<span class="wordStyle">失败次数: 个; </span> <el-button type="primary" @Click="search">查询</el-button>
<span class="wordStyle">异常记录: 个</span> <el-button type="primary" @Click="resetData">重置列表</el-button>
<span class="wordStyle">所属爬虫: </span> <el-button type="primary" @click="openTaskDialog">新建任务</el-button>
</el-space> </el-space>
</el-form-item> </el-form-item>
</el-form>
</div>
</div>
<div class="cardStyle">
<div class="taskCard p-6" v-for="task in taskList" :key="task.taskId">
<div class="taskContent">
<div>
<el-form-item class="form-item">
<span class="titleStyle">{{ task.kwargs.options === '' ? '无名称' : JSON.parse(task.kwargs.options).jobName
}}</span>
</el-form-item>
</div>
<div>
<el-form-item class="form-item">
<el-button type="primary" @click="editTask(task)" class="editButton">编辑</el-button>
<el-button type="success" @click="goToTaskRecord" class="recordButton">执行记录 </el-button>
<el-button type="danger" @click="deleteTask(task)" class="deleteButton">删除</el-button>
</el-form-item>
</div>
<div class="wordStyle">
<el-form-item class="form-item">
<el-space>
<span class="wordStyle">启用/停止: </span>
<el-switch v-model="task.status" :active-value="'running'" :inactive-value="'paused'"
@change="(newStatus: any) => changeStatus(task, newStatus)" />
</el-space>
</el-form-item>
</div>
<div class="wordStyle">
<el-form-item class="form-item">
<el-space>
<span class="wordStyle">执行频率: {{ task.frequency }} </span>
<span class="wordStyle">执行次数: {{ task.count }} </span>
</el-space>
</el-form-item>
</div>
<div class="wordStyle">
<el-form-item class="form-item">
<el-space>
<span class="wordStyle">所属爬虫: {{ task.kwargs.spider }}</span>
</el-space>
</el-form-item>
</div>
<!-- <div class="wordStyle">
<el-form-item class="form-item">
<el-space>
<span class="wordStyle">失败次数: </span>
<span class="wordStyle">异常记录: </span>
</el-space>
</el-form-item>
</div> -->
</div> </div>
</div> </div>
</div> </div>
<addTaskDialog v-model:dialogVisible="showTaskDialog" @confirm="handleEdit" :mode="editMode" @getTaskList="getData"
:jobId="jobId" :cron="frequency" :spiderType="belongSpiderType" :options="taskOptions" />
<deleteDialog v-model:dialogVisible="showDeleteDialog" @get-user-list="getData" :jobId="jobId" />
</div> </div>
<addTaskDialog v-model:dialogVisible="showTaskDialog" @confirm="handleEdit" :mode="editMode" @getTaskList="getData"
:jobId="jobId" :cron="frequency" :spiderType="belongSpiderType" :options="taskOptions" />
<deleteDialog v-model:dialogVisible="showDeleteDialog" @get-user-list="getData" :jobId="jobId" />
</template> </template>
...@@ -90,10 +99,12 @@ ...@@ -90,10 +99,12 @@
import { ref, onMounted, watch } from 'vue' import { ref, onMounted, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import addTaskDialog from './addTaskDialog.vue' import addTaskDialog from './addTaskDialog.vue'
import { getSpiderTaskList, resumeSpiderTask, pauseSpiderTask } from '@/api/spiderTask' import { getSpiderTaskList, resumeSpiderTask, pauseSpiderTask, getTaskCount } from '@/api/spiderTask'
import { DeleteMode } from '@/components/Delete/enum.ts' import { DeleteMode } from '@/components/Delete/enum.ts'
import { AddMode } from './enum' import { AddMode } from './enum'
import deleteDialog from './deleteDialog.vue' import deleteDialog from './deleteDialog.vue'
import { CronExpressionParser } from 'cron-parser';
import { log } from 'echarts/types/src/util/log.js'
const props = defineProps({ const props = defineProps({
spiderType: { spiderType: {
type: String, type: String,
...@@ -126,6 +137,7 @@ const searchCondition = ref({ ...@@ -126,6 +137,7 @@ const searchCondition = ref({
spiders: '', spiders: '',
options: '' options: ''
}) })
const belongSpider = ref('')
const taskName = ref('') const taskName = ref('')
const taskValue = ref('') const taskValue = ref('')
const belongSpiderType = ref('') const belongSpiderType = ref('')
...@@ -181,13 +193,22 @@ const openTaskDialog = () => { ...@@ -181,13 +193,22 @@ const openTaskDialog = () => {
showTaskDialog.value = true showTaskDialog.value = true
} }
const getData = async () => { const getData = async () => {
if (props.spiderType !== '') { const res = await getSpiderTaskList({ spiders: searchCondition.value.spiders ? [searchCondition.value.spiders] : [] })
const res = await getSpiderTaskList({ spiders: props.spiderType, options: JSON.stringify({ jobName: taskName.value }) }) // for (let i = 0; i < res.data.length; i++) {
taskList.value = res.data // const resId = await getTaskCount({id:res.data[i].id})
}else{ // res.data[i].count = resId.data.count
const res = await getSpiderTaskList({ spiders: searchCondition.value.spiders ? [searchCondition.value.spiders] : [], options: JSON.stringify({ jobName: taskName.value }) }) // }
taskList.value = res.data const resId = await getTaskCount({})
for(let i = 0; i < res.data.length; i++){
res.data[i].count = resId.data[res.data[i].id] === undefined ? 0 : resId.data[res.data[i].id]
} }
taskList.value = res.data
}
const resetData = async () => {
searchCondition.value.spiders = ''
const res = await getSpiderTaskList({ spiders: [], options: JSON.stringify({ jobName: taskName.value }) })
taskList.value = res.data
} }
const search = async () => { const search = async () => {
const res = await getSpiderTaskList({ spiders: searchCondition.value.spiders ? [searchCondition.value.spiders] : [], options: JSON.stringify({ jobName: taskName.value }) }) const res = await getSpiderTaskList({ spiders: searchCondition.value.spiders ? [searchCondition.value.spiders] : [], options: JSON.stringify({ jobName: taskName.value }) })
...@@ -198,77 +219,94 @@ onMounted(() => { ...@@ -198,77 +219,94 @@ onMounted(() => {
searchCondition.value.spiders = props.spiderType searchCondition.value.spiders = props.spiderType
} }
getData() getData()
const interval = CronExpressionParser.parse('*/2 * * * *');
console.log(interval);
}) })
// const parseCronExpression=(cronExpression: string)=> {
// try {
// const interval = cronParser.parseExpression(cronExpression);
// const nextDate = interval.next().toDate();
// const hours = nextDate.getHours();
// const minutes = nextDate.getMinutes();
// const seconds = nextDate.getSeconds();
// return {
// hours,
// minutes,
// seconds
// };
// } catch (err) {
// console.error('Error parsing cron expression:', err);
// return null;
// }
// }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.taskContent {
display: flex;
flex-direction: column; // 垂直排列
align-items: center; // 水平居中
justify-content: center; // 垂直居中
height: 100%;
gap: -15px;
padding: 10px 0;
}
// .editButton{
// background: none;
// background-image: url("@/assets/picture/button1.png");
// background-size: 100% 100%;
// background-repeat: no-repeat;
// }
// .recordButton{
// background: none;
// background-image: url("@/assets/picture/button2.png");
// background-size: 100% 100%;
// background-repeat: no-repeat;
// }
// .deleteButton{
// background: none;
// background-image: url("@/assets/picture/button3.png");
// background-size: 100% 100%;
// background-repeat: no-repeat;
// }
.cardStyle { .cardStyle {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
// justify-content:center;
justify-content: space-between;
margin-top: 1.5%; margin-top: 1.5%;
padding: 18px; padding: 18px;
height: 26vh; gap: 15px;
width: auto !important;
justify-content: space-between;
}
.taskContent {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
gap: 6px;
/* 进一步减小项目之间的间距 */
padding: 5px 0;
} }
// 任务卡片样式 /* 任务卡片样式 */
.taskCard { .taskCard {
margin-left: 1%;
background-image: url("@/assets/picture/box2.png"); background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%; background-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
margin-bottom: 20px; margin-bottom: 10px;
width: 380px; width: 380px;
font-size: 20px; font-size: 20px;
height: 100%; min-height: 240px;
border-radius: 7px; border-radius: 7px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.titleStyle { }
font-size: 22px;
margin-top: -5px;
color: #FFFFFF;
}
.wordStyle { /* 减小表单的间距 */
font-size: 16px; .form-item {
color: #FFFFFF; margin-bottom: 3px !important;
}
} .taskCard .titleStyle {
font-size: 22px;
color: #FFFFFF;
}
.taskCard .wordStyle {
font-size: 16px;
color: #FFFFFF;
} }
/* 按钮样式微调 */
.editButton,
.recordButton,
.deleteButton {
margin: 0 3px !important;
}
/* 工具栏样式 */ /* 工具栏样式 */
.toolbarStyle { .toolbarStyle {
background-image: url("@/assets/picture/box3.png"); background-image: url("@/assets/picture/box3.png");
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div> <div>
<div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToTaskInformation" /> <div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToTaskInformation" />
<div class="m-t-8" /> <div class="m-t-8" />
<div > <div>
<taskCard :spiderType="spiderType" failTask="10" unusualTask="1" /> <taskCard :spiderType="spiderType" failTask="10" unusualTask="1" />
<!-- <div class="pagination w-full flex flex-row-reverse pr-18 m-t-0"> <!-- <div class="pagination w-full flex flex-row-reverse pr-18 m-t-0">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize" <Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
......
...@@ -30,7 +30,7 @@ export default defineConfig({ ...@@ -30,7 +30,7 @@ export default defineConfig({
proxy: { proxy: {
// 代理API请求,使用更精确的路径匹配 // 代理API请求,使用更精确的路径匹配
'/api': { '/api': {
target: 'http://192.168.0.200:5001/', target: 'http://127.0.0.1:5001/',
changeOrigin: true, changeOrigin: true,
}, },
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment