Commit e3e5939c by 周田

Merge branch 'liucan' into 'main'

fix:修改监控状态页面错误日志弹窗标题为"错误详情",任务执行记录页面优先加载当日数据

See merge request !15
parents 1d23619c 0859477c
# 开发环境配置
VITE_APP_BASE_API = '/api'
VITE_APP_TITLE = 'Spider Admin Pro'
VITE_WEBSOCKET_API = "http://192.168.3.10:5001/"
\ No newline at end of file
......@@ -97,8 +97,10 @@ export const spiderTaskApi = {
resumeJob: "/schedule/resumeJob",
jobDetail: "/schedule/jobDetail",
taskCount: "/schedule/getAllJobCount",
addSateNo: "/schedule/resetNoradID",
getSateIdList: "/schedule/getNoradIDList",
addSateNo: "/noradId/add",
getSateIdList: "/noradId/list",
deleteSateNoList: "/noradId/delete",
addSateNoList: "/noradId/batchAdd",
} as const;
// 爬虫数据相关接口
......
......@@ -62,7 +62,7 @@ export function getSpiderList(data: UserQueryParams) {
}
//添加卫星编号
export function addSateNo(data: { id: string[] }) {
export function addSateNo(data: { norad_id: string }) {
return request({
url: spiderTaskApi.addSateNo,
method: POST,
......@@ -70,6 +70,24 @@ export function addSateNo(data: { id: string[] }) {
}) as unknown as Promise<ApiResponse>;
}
//批量删除编号
export function deleteSateNoList(data: { norad_id: string[] }) {
return request({
url: spiderTaskApi.deleteSateNoList,
method: POST,
data,
}) as unknown as Promise<ApiResponse>;
}
//批量添加编号
export function addSateNoList(data: { norad_id: string[] }) {
return request({
url: spiderTaskApi.addSateNoList,
method: POST,
data,
}) as unknown as Promise<ApiResponse>;
}
//获取编号列表
export function getSateIdList() {
return request({
......
<script setup lang="ts">
import { computed } from "vue";
import { ElNotification } from "element-plus";
import { Manager, Socket } from "socket.io-client";
import { computed, onMounted, onUnmounted, ref } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
const key = computed(() => route.path);
const socket = ref<Socket | null>(null);
//错误消息通知
const handleErrorMsgNotify = () => {
//websocket连接
const manager = new Manager(import.meta.env.VITE_WEBSOCKET_API);
socket.value = manager.socket("/");
//收到错误通知
socket.value.on("error_message", onErrorMsg);
};
//错误消息处理
const onErrorMsg = ({ message }: { message: any }) => {
ElNotification({
title: "爬虫错误提示",
message,
type: "error",
});
};
onMounted(() => {
handleErrorMsgNotify();
});
onUnmounted(() => {
if (socket.value) {
socket.value.disconnect();
}
});
</script>
<template>
......
import router from './router'
import { useUserStore } from './store/user'
import { getToken } from '@/utils/auth'
import {useUserStore} from './store/user'
import {getToken} from '@/utils/auth'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
// NProgress 配置
NProgress.configure({ showSpinner: false })
NProgress.configure({showSpinner: false})
// 白名单路由
const whiteList = ['/login', '/404']
......@@ -15,12 +15,12 @@ router.beforeEach(async (to, from, next) => {
NProgress.start()
const userStore = useUserStore()
const hasToken = getToken()
const hasToken = getToken();
if (hasToken) {
if (to.path === '/login') {
// 已登录,重定向到首页
next({ path: '/' })
next({path: '/'})
NProgress.done()
} else {
// 确定用户是否有用户信息
......
......@@ -10,14 +10,14 @@
import { ref, watch } from "vue";
const props = defineProps<{
No: string | number;
No: string;
resetSelected?: boolean;
}>();
const isSelected = ref(false);
const emit = defineEmits<{
(e: "addNo", sateNo: string | number): void;
(e: "delNo", sateNo: string | number): void;
(e: "addNo", sateNo: string): void;
(e: "delNo", sateNo: string): void;
}>();
const selectNo = () => {
......
......@@ -47,7 +47,7 @@
v-for="(no, index) in sateNoList"
:key="index"
class="no-item-row"
:-no="no"
:-no="no.norad_cat_id"
@add-no="handleSateAdd"
@del-no="handleSateDel"
:reset-selected="resetSelected"
......@@ -59,7 +59,7 @@
<span style="color: white; font-weight: 500">NORAD编号:</span>
<el-input
@input="handleNumInput"
maxlength="5"
maxlength="6"
placeholder="请输入编号"
v-model="curSateNo"
style="width: 100px"
......@@ -77,8 +77,8 @@
type="danger"
size="small"
@click="
() => {
confirm();
(e:MouseEvent) => {
confirm(e);
delNoList();
}
"
......@@ -107,7 +107,7 @@
import { ref, onMounted, nextTick, watch } from "vue";
import Pagination from "@/components/pagination/index.vue";
import { useRouter } from "vue-router";
import { getSpiderList, addSateNo, getSateIdList } from "@/api/system.ts";
import { getSpiderList, addSateNo, getSateIdList, deleteSateNoList, addSateNoList } from "@/api/system.ts";
import NoItem from "./components/NoItem.vue";
import { ElMessage, type UploadProps, type UploadRawFile } from "element-plus";
import MenuTitle from "@/components/MenuTitle.vue";
......@@ -137,57 +137,53 @@ const getData = async () => {
const editDialogVisible = ref(false);
const sateNoList = ref<string[]>([]);
//编号item类型定义
interface noradItem {
id: number;
norad_cat_id: string;
create_time: string;
}
const sateNoList = ref<noradItem[]>([]);
const curSateNo = ref("");
const curSelSateNo = ref<(string | number)[]>([]);
const curSelSateNo = ref<string[]>([]);
const resetSelected = ref(false);
//添加选中项到当前列表
const handleSateAdd = (no: string | number) => {
curSelSateNo.value.push(padZeroTo5Digits(no));
const handleSateAdd = (no: string) => {
if (checkNoLeSix(no)) {
curSelSateNo.value.push(no);
}
};
//从当前列表删除选中项
const handleSateDel = (no: string | number) => {
curSelSateNo.value = curSelSateNo.value.filter((item) => item != no);
};
//添加编号到列表并整体发到后端
//添加编号发到后端
const addNoToList = async () => {
try {
if (curSateNo.value && sateNoList.value.includes(padZeroTo5Digits(curSateNo.value))) {
ElMessage.error("当前编号已存在,请重新输入");
curSateNo.value = "";
return;
}
sateNoList.value.push(padZeroTo5Digits(curSateNo.value));
const res = await addSateNo({ id: sateNoList.value });
const res = await addSateNo({ norad_id: curSateNo.value });
if (res.code === 0) {
ElMessage.success("添加编号成功");
} else {
sateNoList.value.pop();
ElMessage.error(res.message);
getSateNoList();
}
curSateNo.value = "";
scrollToBottom();
} catch (error: any) {
ElMessage.error(error.message);
}
};
//编号文件导入后发送到后端
const fileImptAddNoList = async () => {
try {
const res = await addSateNo({ id: sateNoList.value });
console.log(textFileNumbers.value);
const res = await addSateNoList({ norad_id: textFileNumbers.value });
console.log(res);
if (res.code === 0) {
ElMessage.success("编号导入成功");
} else {
sateNoList.value.pop();
ElMessage.error(res.message);
ElMessage.success("导入编号成功");
}
scrollToBottom();
getSateNoList();
} catch (error: any) {
ElMessage.error(error.message);
}
......@@ -196,8 +192,7 @@ const fileImptAddNoList = async () => {
//删除选中编号
const delNoList = async () => {
try {
sateNoList.value = sateNoList.value.filter((item) => !curSelSateNo.value.includes(item));
const res = await addSateNo({ id: sateNoList.value as string[] });
const res = await deleteSateNoList({ norad_id: curSelSateNo.value });
if (res.code === 0) {
ElMessage.success("删除编号成功");
}
......@@ -206,6 +201,7 @@ const delNoList = async () => {
nextTick(() => {
resetSelected.value = false;
});
getSateNoList();
} catch (error: any) {
ElMessage.error(error.message);
}
......@@ -223,24 +219,31 @@ const scrollToBottom = () => {
});
};
const handleNumInput = (value: string) => {
const filtered = value.replace(/\D/g, "");
curSateNo.value = filtered.slice(0, 5);
//检查输入的编号个数不大于6
const checkNoLeSix = (no: number | string): boolean => {
if (String(no).length > 6) {
ElMessage.error("编号位数错误,长度不能大于6位");
return false;
}
return true;
};
//编号格式化
const padZeroTo5Digits = (num: number | string): string => {
const numStr = String(num);
const pureNumStr = numStr.replace(/\D/g, "");
return pureNumStr.padStart(5, "0").slice(-5);
const handleNumInput = (value: string) => {
const filtered = value.replace(/\D/g, "");
curSateNo.value = filtered.slice(0, 6);
};
const handleEditSateId = async () => {
editDialogVisible.value = true;
getSateNoList();
};
//获取编号列表
const getSateNoList = async () => {
try {
const res = await getSateIdList();
if (res.code === 0) {
sateNoList.value = res.data || [];
sateNoList.value = res.data.list || [];
}
} catch (error: any) {
ElMessage.error(error.message);
......@@ -248,16 +251,12 @@ const handleEditSateId = async () => {
};
//读取文本文件后存储读取的编号
const textFileNumbers = ref<number[]>([]);
const textFileNumbers = ref<string[]>([]);
//监听导入文件的数组变化
watch(textFileNumbers, (newVal) => {
if (newVal.length > 0) {
newVal.map((num) => {
if (!sateNoList.value.includes(padZeroTo5Digits(num))) {
sateNoList.value.push(padZeroTo5Digits(num));
}
});
newVal.forEach((num) => {});
fileImptAddNoList();
}
});
......@@ -306,13 +305,12 @@ const handleFileChange: UploadProps["onChange"] = (uploadFile) => {
if (!textContent) {
throw new Error("文件内容为空");
}
textFileNumbers.value = parseTextToNumbers(textContent);
textFileNumbers.value = parseTextToNumbers(textContent).map((item) => String(item));
};
//失败的回调
reader.onerror = () => {
ElMessage.error("文件导入失败,请检查文件是否损坏或重试");
};
//读取文件
reader.readAsText(file, "utf-8");
};
......
......@@ -2,13 +2,17 @@
<div class="dataCard">
<div class="titleStyle">错误日志统计</div>
<div class="chart-container" ref="chartRef"></div>
<el-dialog draggable v-model="DialogVisible" :title="`日志详情丨${curDate}`" @close="tableData = []">
<el-dialog draggable v-model="DialogVisible" :title="`错误详情丨${curDate}`" @close="tableData = []">
<div class="table-content">
<el-table :data="curTableData" border style="width: 100%">
<el-table-column width="55" label="序号" type="index" />
<el-table-column width="150" property="spider" label="爬虫名称" />
<el-table-column property="error" label="错误信息" />
<el-table-column width="160" property="timestamp" label="发生时间" />
<el-table-column property="error" label="错误信息">
<template #default="scope">
{{ scope.row.error.error }}
</template>
</el-table-column>
<el-table-column width="160" property="timestamp" label="记录时间" />
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination
......@@ -65,7 +69,7 @@ const logCountList = computed(() => {
return logList.value.map((item) => item.count);
});
//x轴日期列表
//X轴日期列表
const dateList = ref<string[]>([]);
//Y轴最大值
......@@ -138,6 +142,7 @@ const setChartData = async () => {
data: dateList.value,
name: "日期",
nameLocation: "middle",
nameGap: 20,
nameTextStyle: {
color: "#fff",
fontSize: 12,
......@@ -155,6 +160,7 @@ const setChartData = async () => {
type: "value",
name: "数量",
nameLocation: "middle",
nameGap: 20,
max: maxVal.value,
axisLabel: {
color: "#fff",
......@@ -192,6 +198,7 @@ const handleClickChart = (params: any) => {
});
pageObj.value.total = tableData.value.length;
curTableData.value = tableData.value.slice(0, 5);
console.log(curTableData.value);
};
//生成图表
......
......@@ -90,18 +90,17 @@
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from "vue";
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import addTaskDialog from "./addTaskDialog.vue";
import { getSpiderTaskList, resumeSpiderTask, pauseSpiderTask, getTaskCount } from "@/api/spiderTask";
import { DeleteMode } from "@/components/Delete/enum.ts";
import { AddMode } from "./enum";
import deleteDialog from "./deleteDialog.vue";
import { ElMessage, ElNotification } from "element-plus";
import { ElMessage } from "element-plus";
import { getSpiderList } from "@/api/system.ts";
import formatExactLargeNum from "@/utils/formatExactLargeNum";
import TableSearch from "@/components/TableSearch.vue";
import { Manager, Socket } from "socket.io-client";
const props = defineProps({
spiderType: {
......@@ -118,26 +117,6 @@ const props = defineProps({
},
});
const socket = ref<Socket | null>(null);
//错误消息通知
const handleErrorMsgNotify = () => {
//websocket连接
const manager = new Manager("/api:5001");
socket.value = manager.socket("/");
//收到错误通知
socket.value.on("error_message", onErrorMsg);
};
//错误消息处理
const onErrorMsg = ({ message }: { message: any }) => {
ElNotification({
title: "任务错误提示",
message,
type: "error",
});
};
// 所有响应式变量初始化时避免 undefined
const taskSelectOptions = ref<any[]>([]); // 初始化为空数组
const searchCondition = ref({
......@@ -311,15 +290,6 @@ onMounted(() => {
}
getData();
getSpiderTypeList();
//开启socket连接
handleErrorMsgNotify();
});
onUnmounted(() => {
//关闭socket连接
if (socket.value) {
socket.value.disconnect();
}
});
</script>
......
......@@ -102,7 +102,7 @@ zhCn.el.pagination.pageClassifier = "页";
const route = useRoute();
const router = useRouter();
//初始数据为近七天
const timeValue = ref([dayjs().subtract(7, "day").format("YYYY-MM-DD"), dayjs().format("YYYY-MM-DD")]);
const timeValue = ref<string[]>([]);
const tableData = ref([]);
const pageObj = ref({
total: 10,
......@@ -128,18 +128,34 @@ const tableLoading = ref(false);
//重置查询
const resetQuery = () => {
timeValue.value = [dayjs().subtract(7, "day").format("YYYY-MM-DD"), dayjs().format("YYYY-MM-DD")];
timeValue.value = [];
getData();
};
// 获取任务执行记录列表
const getData = async () => {
searchData();
let resTime: any[] = [];
resTime.push(dayjs().subtract(7, "day").format("YYYY-MM-DD HH:mm:ss"));
resTime.push(dayjs().format("YYYY-MM-DD HH:mm:ss"));
console.log(resTime);
tableLoading.value = true;
const res = await getSpiderTaskRecord({
page: pageObj.value.pageNo,
size: pageObj.value.pageSize,
status: "total",
times: resTime,
});
pageObj.value.total = res.data.total;
tableData.value = res.data.list;
console.log(tableData.value);
tableLoading.value = false;
};
//查询数据的方法
const searchData = async () => {
if (!timeValue.value) {
if (timeValue.value.length == 0) {
ElMessage.warning("请先选择时间段");
return;
}
......
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