Commit 865f028d by 周田

Merge branch 'liucan' into 'main'

feat:新增状态监控页loading效果,重写表单搜索栏组件,调整文字排版

See merge request !12
parents cff37174 d1356d4d
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -14,6 +14,7 @@
"@types/node": "^22.15.17",
"@types/nprogress": "^0.2.3",
"@types/uuid": "^10.0.0",
"animate.css": "^4.1.1",
"axios": "^1.9.0",
"cron-parser": "^5.4.0",
"echarts": "^5.6.0",
......
......@@ -7,7 +7,8 @@
</template>
<style>
html, body {
html,
body {
margin: 0;
padding: 0;
height: 100%;
......
// API路径配置文件
// 这个文件确保所有API路径在一处统一管理,方便修改
import { pauseJob } from "./schedule"
import { pauseJob } from "./schedule";
export const authApi = {
login: '/auth/login',
logout: '/auth/logout'
} as const
login: "/auth/login",
logout: "/auth/logout",
} as const;
export const scrapydApi = {
// scrapyd相关接口
listProjects: '/scrapyd/listProjects',
listVersions: '/scrapyd/listVersions',
listSpiders: '/scrapyd/listSpiders',
listJobsMerge: '/scrapyd/listJobsMerge',
cancel: '/scrapyd/cancel',
cancelAllJob: '/scrapyd/cancelAllJob',
deleteVersion: '/scrapyd/deleteVersion',
deleteProject: '/scrapyd/deleteProject',
schedule: '/scrapyd/schedule',
daemonStatus: '/scrapyd/daemonStatus',
addVersion: '/scrapyd/addVersion',
listProjects: "/scrapyd/listProjects",
listVersions: "/scrapyd/listVersions",
listSpiders: "/scrapyd/listSpiders",
listJobsMerge: "/scrapyd/listJobsMerge",
cancel: "/scrapyd/cancel",
cancelAllJob: "/scrapyd/cancelAllJob",
deleteVersion: "/scrapyd/deleteVersion",
deleteProject: "/scrapyd/deleteProject",
schedule: "/scrapyd/schedule",
daemonStatus: "/scrapyd/daemonStatus",
addVersion: "/scrapyd/addVersion",
// 日志相关
logs: '/scrapyd/logs',
projectLogs: '/scrapyd/projectLogs',
spiderLogs: '/scrapyd/spiderLogs',
jobLog: '/scrapyd/jobLog'
} as const
logs: "/scrapyd/logs",
projectLogs: "/scrapyd/projectLogs",
spiderLogs: "/scrapyd/spiderLogs",
jobLog: "/scrapyd/jobLog",
} as const;
export const scheduleApi = {
// 调度任务相关
addJob: '/schedule/addJob',
getJobs: '/schedule/getJobs',
pauseJob: '/schedule/pauseJob',
resumeJob: '/schedule/resumeJob',
removeJob: '/schedule/removeJob',
jobDetail: '/schedule/jobDetail',
state: '/schedule/state',
start: '/schedule/start',
shutdown: '/schedule/shutdown',
pause: '/schedule/pause',
resume: '/schedule/resume',
removeAllJobs: '/schedule/removeAllJobs',
scheduleLogs: '/schedule/scheduleLogs',
removeScheduleLogs: '/schedule/removeScheduleLogs',
} as const
addJob: "/schedule/addJob",
getJobs: "/schedule/getJobs",
pauseJob: "/schedule/pauseJob",
resumeJob: "/schedule/resumeJob",
removeJob: "/schedule/removeJob",
jobDetail: "/schedule/jobDetail",
state: "/schedule/state",
start: "/schedule/start",
shutdown: "/schedule/shutdown",
pause: "/schedule/pause",
resume: "/schedule/resume",
removeAllJobs: "/schedule/removeAllJobs",
scheduleLogs: "/schedule/scheduleLogs",
removeScheduleLogs: "/schedule/removeScheduleLogs",
} as const;
export const scrapydServerApi = {
getScrapydServerPage: '/scrapydServer/getScrapydServerPage',
addScrapydServer: '/scrapydServer/addScrapydServer',
updateScrapydServer: '/scrapydServer/updateScrapydServer',
updateScrapydServerStatus: '/scrapydServer/updateScrapydServerStatus',
deleteScrapydServer: '/scrapydServer/deleteScrapydServer'
} as const
// 系统相关
getScrapydServerPage: "/scrapydServer/getScrapydServerPage",
addScrapydServer: "/scrapydServer/addScrapydServer",
updateScrapydServer: "/scrapydServer/updateScrapydServer",
updateScrapydServerStatus: "/scrapydServer/updateScrapydServerStatus",
deleteScrapydServer: "/scrapydServer/deleteScrapydServer",
} as const;
// 系统相关
export const systemApi = {
systemInfo: '/system/systemInfo',
systemData: '/system/systemData',
systemConfig: '/system/systemConfig',
loginHistoryList: '/actionHistory/loginHistoryList',
scrapydServerList: '/system/scrapydServerList' // 没用
} as const
// 统计相关
systemInfo: "/system/systemInfo",
systemData: "/system/systemData",
systemConfig: "/system/systemConfig",
loginHistoryList: "/actionHistory/loginHistoryList",
scrapydServerList: "/system/scrapydServerList", // 没用
} as const;
// 统计相关
export const statsApi = {
statsList: '/statsCollection/listItem',
statsDetail: '/statsCollection/detail',
removeStats: '/statsCollection/delete',
clearAllStats: '/statsCollection/clearAll' // TODO 未实现
} as const
statsList: "/statsCollection/listItem",
statsDetail: "/statsCollection/detail",
removeStats: "/statsCollection/delete",
clearAllStats: "/statsCollection/clearAll", // TODO 未实现
} as const;
// 系统用户相关接口
// 系统用户相关接口
export const userApi = {
userList: '/user/list',
addUser: '/user/insert',
updateUser: '/user/update',
deleteUser: '/user/delete',
batchDelete: '/user/batchDelete',
} as const
// 系统用户相关接口
userList: "/user/list",
addUser: "/user/insert",
updateUser: "/user/update",
deleteUser: "/user/delete",
batchDelete: "/user/batchDelete",
} as const;
// 系统用户相关接口
export const spiderApi = {
spiderList: '/scrapyd/listSpiders',
} as const
spiderList: "/scrapyd/listSpiders",
} as const;
// 爬虫任务相关接口
// 爬虫任务相关接口
export const spiderTaskApi = {
taskList: '/schedule/getJobs',
taskRecord: '/schedule/scheduleLogs',
addTask: '/schedule/addJob',
deleteTask: '/schedule/removeJob',
pauseJob: '/schedule/pauseJob',
resumeJob: '/schedule/resumeJob',
jobDetail: '/schedule/jobDetail',
taskCount:'/schedule/getAllJobCount'
} as const
// 爬虫数据相关接口
taskList: "/schedule/getJobs",
taskRecord: "/schedule/scheduleLogs",
addTask: "/schedule/addJob",
deleteTask: "/schedule/removeJob",
pauseJob: "/schedule/pauseJob",
resumeJob: "/schedule/resumeJob",
jobDetail: "/schedule/jobDetail",
taskCount: "/schedule/getAllJobCount",
addSateNo: "/schedule/resetNoradID",
getSateIdList: "/schedule/getNoradIDList",
} as const;
// 爬虫数据相关接口
export const spiderDataApi = {
dsnList: '/dsn/list',
dsnDetail: '/dsn/detail',
dsnDataDelete: '/dsn/delete',
ituList: '/itu/list',
ituDetail: '/itu/detail',
ituDataDelete: '/itu/delete',
stList: '/spaceTrack/list',
stDetail: '/spaceTrack/detail',
stDataDelete: '/sspaceTrackt/delete',
exportSpiderData: '/export/downloadFile',
esaList: '/esa/list',
esaMissionDetail: '/esa/missionDetail',
esaStationDetail: '/esa/stationDetail',
} as const
// 爬虫数据相关接口
dsnList: "/dsn/list",
dsnDetail: "/dsn/detail",
dsnDataDelete: "/dsn/delete",
ituList: "/itu/list",
ituDetail: "/itu/detail",
ituDataDelete: "/itu/delete",
stList: "/spaceTrack/list",
stDetail: "/spaceTrack/detail",
stDataDelete: "/sspaceTrackt/delete",
exportSpiderData: "/export/downloadFile",
esaList: "/esa/list",
esaMissionDetail: "/esa/missionDetail",
esaStationDetail: "/esa/stationDetail",
} as const;
// 爬虫数据相关接口
export const dataApi = {
dataStatistics: '/statistic/dataStatistics',
taskStatistics: '/statistic/taskStatistics',
performanceStatistics: '/statistic/performanceStatistics',
allSpiderTaskStatistics: '/statistic/getAllTaskStatistics',
} as const
dataStatistics: "/statistic/dataStatistics",
taskStatistics: "/statistic/taskStatistics",
performanceStatistics: "/statistic/performanceStatistics",
allSpiderTaskStatistics: "/statistic/getAllTaskStatistics",
} as const;
import { request, POST } from '@/utils/request'
import type { ApiResponse, QueryParams ,UserQueryParams } from '@/utils/request'
import { systemApi, scrapydServerApi, spiderApi } from './apiPaths'
import { request, POST } from "@/utils/request";
import type { ApiResponse, QueryParams, UserQueryParams } from "@/utils/request";
import { systemApi, scrapydServerApi, spiderApi, spiderTaskApi } from "./apiPaths";
// 获取系统信息
export function getSystemInfo(): Promise<ApiResponse> {
return request({
url: systemApi.systemInfo,
method: POST
}) as unknown as Promise<ApiResponse>
method: POST,
}) as unknown as Promise<ApiResponse>;
}
// 获取系统数据
......@@ -15,16 +15,16 @@ export function getSystemData(data: QueryParams): Promise<ApiResponse> {
return request({
url: systemApi.systemData,
method: POST,
data
}) as unknown as Promise<ApiResponse>
data,
}) as unknown as Promise<ApiResponse>;
}
// 获取系统配置
export function getSystemConfig(): Promise<ApiResponse> {
return request({
url: systemApi.systemConfig,
method: POST
}) as unknown as Promise<ApiResponse>
method: POST,
}) as unknown as Promise<ApiResponse>;
}
// 更新系统配置
......@@ -32,8 +32,8 @@ export function updateSystemConfig(data: Record<string, any>): Promise<ApiRespon
return request({
url: systemApi.systemConfig,
method: POST,
data
}) as unknown as Promise<ApiResponse>
data,
}) as unknown as Promise<ApiResponse>;
}
// 获取登录历史
......@@ -41,22 +41,39 @@ export function getLoginHistory(params: QueryParams): Promise<ApiResponse> {
return request({
url: systemApi.loginHistoryList,
method: POST,
params
}) as unknown as Promise<ApiResponse>
params,
}) as unknown as Promise<ApiResponse>;
}
export const getScrapydServerList = (): Promise<ApiResponse> => {
return request({
url: scrapydServerApi.getScrapydServerPage,
method: POST,
}) as unknown as Promise<ApiResponse>
}
}) as unknown as Promise<ApiResponse>;
};
// 爬虫列表
export function getSpiderList(data: UserQueryParams) {
return request({
url: spiderApi.spiderList,
method: POST,
data
}) as unknown as Promise<ApiResponse>
}
\ No newline at end of file
data,
}) as unknown as Promise<ApiResponse>;
}
//添加卫星编号
export function addSateNo(data: { id: string[] }) {
return request({
url: spiderTaskApi.addSateNo,
method: POST,
data,
}) as unknown as Promise<ApiResponse>;
}
//获取编号列表
export function getSateIdList() {
return request({
url: spiderTaskApi.getSateIdList,
method: POST,
}) as unknown as Promise<ApiResponse>;
}
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 20 20"><g fill="none"><path fill="url(#SVG4JAgqc9r)" d="M16 17V5.5a.5.5 0 0 0-.812-.39l-4.735 3.787l-3.205-1.831a.5.5 0 0 0-.451-.023L3 8.731V17z"/><path fill="url(#SVGazSFLmzC)" fill-opacity="0.3" d="M16 17V5.5a.5.5 0 0 0-.812-.39l-4.735 3.787l-3.205-1.831a.5.5 0 0 0-.451-.023L3 8.731V17z"/><path fill="url(#SVGctjeee0c)" fill-opacity="0.3" d="M16 17V5.5a.5.5 0 0 0-.812-.39l-4.735 3.787l-3.205-1.831a.5.5 0 0 0-.451-.023L3 8.731V17z"/><path fill="url(#SVGZhcbtstm)" fill-opacity="0.3" d="M16 17V5.5a.5.5 0 0 0-.812-.39l-4.735 3.787l-3.205-1.831a.5.5 0 0 0-.451-.023L3 8.731V17z"/><path fill="url(#SVGaypZDdDD)" d="M2.75 2a.75.75 0 0 1 .75.75v12.5c0 .69.56 1.25 1.25 1.25h12.5a.75.75 0 0 1 0 1.5H4.75A2.75 2.75 0 0 1 2 15.25V2.75A.75.75 0 0 1 2.75 2"/><defs><linearGradient id="SVG4JAgqc9r" x1="-1.5" x2="20" y1="6.5" y2="19" gradientUnits="userSpaceOnUse"><stop offset=".164" stop-color="#3bd5ff"/><stop offset=".537" stop-color="#9c6cfe"/><stop offset=".908" stop-color="#e656eb"/></linearGradient><linearGradient id="SVGctjeee0c" x1="9.5" x2="9.5" y1="15" y2="17" gradientUnits="userSpaceOnUse"><stop stop-color="#163697" stop-opacity="0"/><stop offset="1" stop-color="#163697"/></linearGradient><linearGradient id="SVGZhcbtstm" x1="5" x2="3" y1="13.5" y2="13.5" gradientUnits="userSpaceOnUse"><stop stop-color="#163697" stop-opacity="0"/><stop offset="1" stop-color="#163697"/></linearGradient><linearGradient id="SVGaypZDdDD" x1="16.5" x2="2.498" y1="3" y2="23.849" gradientUnits="userSpaceOnUse"><stop stop-color="#70777d"/><stop offset="1" stop-color="#b9c0c7"/></linearGradient><radialGradient id="SVGazSFLmzC" cx="0" cy="0" r="1" gradientTransform="matrix(-10.00002 8.99995 -9.1043 -10.11597 14 7)" gradientUnits="userSpaceOnUse"><stop offset=".636" stop-color="#0fafff" stop-opacity="0"/><stop offset=".962" stop-color="#0067bf"/></radialGradient></defs></g></svg>
\ No newline at end of file
<template>
<el-dialog v-model="deleteDialogVisible" title="删除" width="250" center align-center @close="close" draggable>
<div class="text-center">
<span style="color: #fff;font-size: 15px;">确定删除吗?</span>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="handleDelelte">
确定
</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="deleteDialogVisible" title="删除" width="250" center align-center @close="close" draggable>
<div class="text-center">
<span style="color: #fff; font-size: 15px">确定删除吗?</span>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="handleDelelte"> 确定 </el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { defineProps } from 'vue';
import { getUserList, addUser, deleteUser, updateUser, batchDeleteUser } from '@/api/user.ts'
import { DeleteMode } from '@/components/Delete/enum.ts'
import { ref, watch } from "vue";
import { defineProps } from "vue";
import { deleteUser, batchDeleteUser } from "@/api/user.ts";
import { DeleteMode } from "@/components/Delete/enum.ts";
interface deleteDialogPropType {
dialogVisible: boolean,
deleteMode: DeleteMode,
id: number,
ids: number[],
dialogVisible: boolean;
deleteMode: DeleteMode;
id: number;
ids: number[];
}
const props = defineProps<deleteDialogPropType>()
const emit = defineEmits(['update:dialogVisible', 'confirm', 'getUserList', 'update:deleteMode'])
const deleteDialogVisible = ref(props.dialogVisible)
const deleteMode = ref(props.deleteMode)
const props = defineProps<deleteDialogPropType>();
const emit = defineEmits(["update:dialogVisible", "confirm", "getUserList", "update:deleteMode"]);
const deleteDialogVisible = ref(props.dialogVisible);
const deleteMode = ref(props.deleteMode);
// 删除方法
const handleDelelte = async () => {
if (props.deleteMode == DeleteMode.SINGLE_DELETE) {
await deleteUser({ id: props.id })
emit('getUserList')
deleteDialogVisible.value = false
}
else if (props.deleteMode == DeleteMode.BATCH_DELETE) {
console.log(props.ids);
await batchDeleteUser({ ids: props.ids })
emit('getUserList')
deleteDialogVisible.value = false
}
}
if (props.deleteMode == DeleteMode.SINGLE_DELETE) {
await deleteUser({ id: props.id });
emit("getUserList");
deleteDialogVisible.value = false;
} else if (props.deleteMode == DeleteMode.BATCH_DELETE) {
console.log(props.ids);
await batchDeleteUser({ ids: props.ids });
emit("getUserList");
deleteDialogVisible.value = false;
}
};
// 关闭弹窗的方法
const close = () => {
deleteDialogVisible.value = false
}
deleteDialogVisible.value = false;
};
// 监听父组件传过来的值
watch(() => props.dialogVisible,
(newVal) => {
deleteDialogVisible.value = newVal
}
)
watch(
() => props.dialogVisible,
(newVal) => {
deleteDialogVisible.value = newVal;
}
);
// 监听组件内的值并向父组件更新
watch(() => deleteDialogVisible.value,
(newVal) => {
emit('update:dialogVisible', newVal)
}
)
watch(
() => deleteDialogVisible.value,
(newVal) => {
emit("update:dialogVisible", newVal);
}
);
// 监听父组件传过来的值
watch(() => props.deleteMode,
(newVal) => {
deleteMode.value = newVal
}
)
watch(
() => props.deleteMode,
(newVal) => {
deleteMode.value = newVal;
}
);
// 监听组件内的值并向父组件更新
watch(() => deleteMode.value,
(newVal) => {
emit('update:deleteMode', newVal)
}
)
</script>
\ No newline at end of file
watch(
() => deleteMode.value,
(newVal) => {
emit("update:deleteMode", newVal);
}
);
</script>
<template>
<div>
<el-dialog v-model="exportDialogVisible" v-loading="fullscreenLoading" title="导出" width="500" center align-center
@close="close" draggable>
<el-form class="formStyle" :rules="rules" ref="formRef" :model="exportObject">
<el-form-item prop="timeValue">
<el-date-picker v-model="exportObject.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"
value-format="YYYY-MM-DD HH:mm:ss" id="export-time-picker"/>
</el-form-item>
<el-form-item prop="spiderType">
<el-checkbox-group v-model="exportObject.spiderType" class="checkboxStyle">
<el-checkbox label="DSN数据" value="dsn" id="dsn-checkbox"/>
<el-checkbox label="ITU数据" value="itu" id="itu-checkbox"/>
<el-checkbox label="ST数据" value="spaceTrack" id="st-checkbox"/>
<el-checkbox label="ESA数据" value="esa" id="st-checkbox"/>
</el-checkbox-group>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="handleExport">
确定
</el-button>
</div>
</template>
</el-dialog>
</div>
<div>
<el-dialog v-model="exportDialogVisible" title="导出" width="500" center align-center @close="close" draggable>
<div class="dialog-content" v-loading="fullscreenLoading">
<el-form class="formStyle" :rules="rules" ref="formRef" :model="exportObject">
<el-form-item prop="timeValue">
<el-date-picker
v-model="exportObject.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"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-form-item>
<el-form-item prop="spiderType">
<el-checkbox-group v-model="exportObject.spiderType" class="checkboxStyle">
<el-checkbox label="DSN数据" value="dsn" id="dsn-checkbox" />
<el-checkbox label="ITU数据" value="itu" id="itu-checkbox" />
<el-checkbox label="ST数据" value="spaceTrack" id="st-checkbox" />
<el-checkbox label="ESA数据" value="esa" id="esa-checkbox" />
</el-checkbox-group>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="handleExport"> 确定 </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { defineProps } from 'vue';
import axios from 'axios'
import { ElLoading, ElMessage } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { ref, watch } from "vue";
import { defineProps } from "vue";
import axios from "axios";
import { ElLoading, ElMessage } from "element-plus";
import type { FormInstance, FormRules } from "element-plus";
interface RuleForm {
//表单字段的类型
timeValue: string
spiderType: Array<string>
//表单字段的类型
timeValue: string;
spiderType: Array<string>;
}
const formRef = ref<FormInstance>()
const formRef = ref<FormInstance>();
const rules = ref<FormRules<RuleForm>>({
timeValue: [
{
// type: 'date',
required: true,
message: '请选择时间段',
trigger: 'change',
validator: (rule, value, callback) => {
// 检查是否为数组且长度为2
if (!Array.isArray(value) || value.length !== 2) {
callback(new Error('请选择完整的时间段'));
} else {
// 检查日期格式是否有效(可选)
const isValid = value.every(date => /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(date));
if (!isValid) {
callback(new Error('时间段格式不正确'));
} else {
callback();
}
}
}
},
],
spiderType: [
{
type: 'array',
required: true,
message: '请至少选择一种数据类型',
trigger: 'change',
},
]
})
timeValue: [
{
// type: 'date',
required: true,
message: "请选择时间段",
trigger: "change",
validator: (rule, value, callback) => {
// 检查是否为数组且长度为2
if (!Array.isArray(value) || value.length !== 2) {
callback(new Error("请选择完整的时间段"));
} else {
// 检查日期格式是否有效(可选)
const isValid = value.every((date) => /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(date));
if (!isValid) {
callback(new Error("时间段格式不正确"));
} else {
callback();
}
}
},
},
],
spiderType: [
{
type: "array",
required: true,
message: "请至少选择一种数据类型",
trigger: "change",
},
],
});
//表单绑定的字段
const exportObject = ref({
timeValue: [],
spiderType: []
})
const fullscreenLoading = ref(false)
timeValue: [],
spiderType: [],
});
const fullscreenLoading = ref(false);
const props = defineProps({
dialogVisible: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:dialogVisible'])
const exportDialogVisible = ref(props.dialogVisible)
dialogVisible: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["update:dialogVisible"]);
const exportDialogVisible = ref(props.dialogVisible);
// 导出方法
// const handleExport = async () => {
......@@ -145,7 +150,6 @@ const exportDialogVisible = ref(props.dialogVisible)
// }
// })
// }
// const handleExport = async () => {
......@@ -203,135 +207,136 @@ const exportDialogVisible = ref(props.dialogVisible)
// }
const handleExport = async () => {
if (!formRef.value) return;
if (!formRef.value) return;
try {
// 1. 先在用户点击时获取保存文件句柄(关键:在用户手势中执行)
const fileHandle = await getSaveFileHandle();
if (!fileHandle) {
ElMessage.info('已取消保存');
return;
}
try {
// 1. 先在用户点击时获取保存文件句柄(关键:在用户手势中执行)
const fileHandle = await getSaveFileHandle();
if (!fileHandle) {
ElMessage.info("已取消保存");
return;
}
// 2. 执行表单验证
await formRef.value.validate(async (valid, fields) => {
if (valid) {
const loading = ElLoading.service({
lock: true,
text: '正在导出文件...',
background: 'rgba(0, 0, 0, 0.7)',
});
// 2. 执行表单验证
await formRef.value.validate(async (valid, fields) => {
if (valid) {
const loading = ElLoading.service({
lock: true,
text: "正在导出文件...",
background: "rgba(0, 0, 0, 0.7)",
});
try {
// 3. 请求文件数据
const res = await axios.post(
'/api/export/downloadFile',
{ times: exportObject.value.timeValue, filters: exportObject.value.spiderType },
{
responseType: 'blob',
headers: {
'Token': localStorage.getItem('Admin-Token') || '',
},
}
);
try {
// 3. 请求文件数据
const res = await axios.post(
"/api/export/downloadFile",
{ times: exportObject.value.timeValue, filters: exportObject.value.spiderType },
{
responseType: "blob",
headers: {
Token: localStorage.getItem("Admin-Token") || "",
},
}
);
// 4. 使用之前获取的句柄保存文件
await saveToSelectedLocation(res.data, fileHandle);
loading.close();
ElMessage.success('数据导出成功');
close()
} catch (e) {
console.error('导出失败', e);
loading.close();
ElMessage.error('ZIP文件导出失败,请重试');
}
}
});
} catch (error) {
console.error(error);
// ElMessage.error('无法打开保存对话框,请使用浏览器默认下载');
}
// 4. 使用之前获取的句柄保存文件
await saveToSelectedLocation(res.data, fileHandle);
loading.close();
ElMessage.success("数据导出成功");
close();
} catch (e) {
console.error("导出失败", e);
loading.close();
ElMessage.error("ZIP文件导出失败,请重试");
}
}
});
} catch (error) {
console.error(error);
// ElMessage.error('无法打开保存对话框,请使用浏览器默认下载');
}
};
// 获取用户选择的保存位置
const getSaveFileHandle = async () => {
// 检查浏览器是否支持
if (!(window as any).showSaveFilePicker) {
ElMessage.warning('您的浏览器不支持选择保存位置,请使用最新版Chrome或Edge浏览器');
return null;
}
// 检查浏览器是否支持
if (!(window as any).showSaveFilePicker) {
ElMessage.warning("您的浏览器不支持选择保存位置,请使用最新版Chrome或Edge浏览器");
return null;
}
try {
// 弹出保存对话框(必须在用户直接交互中调用)
return await (window as any).showSaveFilePicker({
suggestedName: 'export.zip',
types: [{
description: 'ZIP压缩文件',
accept: { 'application/zip': ['.zip'] },
}],
excludeAcceptAllOption: true
});
} catch (error: any) {
// 用户取消选择时也会触发错误,这里视为正常取消
if (error.name !== 'AbortError') {
console.error('获取保存位置失败', error);
}
return null;
}
try {
// 弹出保存对话框(必须在用户直接交互中调用)
return await (window as any).showSaveFilePicker({
suggestedName: "export.zip",
types: [
{
description: "ZIP压缩文件",
accept: { "application/zip": [".zip"] },
},
],
excludeAcceptAllOption: true,
});
} catch (error: any) {
// 用户取消选择时也会触发错误,这里视为正常取消
if (error.name !== "AbortError") {
console.error("获取保存位置失败", error);
}
return null;
}
};
// 保存数据到用户选择的位置
const saveToSelectedLocation = async (blobData: any, fileHandle: any) => {
if (!(blobData instanceof Blob) || blobData.size === 0) {
throw new Error('无效的ZIP文件数据');
}
if (!(blobData instanceof Blob) || blobData.size === 0) {
throw new Error("无效的ZIP文件数据");
}
// 将blob转换为可写数据
const arrayBuffer = await blobData.arrayBuffer();
// 将blob转换为可写数据
const arrayBuffer = await blobData.arrayBuffer();
// 写入到用户选择的文件
const writable = await fileHandle.createWritable();
await writable.write(arrayBuffer);
await writable.close();
// 写入到用户选择的文件
const writable = await fileHandle.createWritable();
await writable.write(arrayBuffer);
await writable.close();
};
// 关闭弹窗的方法
const close = () => {
exportObject.value = {
timeValue: [],
spiderType: []
}
formRef.value?.clearValidate()
exportDialogVisible.value = false
}
exportObject.value = {
timeValue: [],
spiderType: [],
};
formRef.value?.clearValidate();
exportDialogVisible.value = false;
};
// 监听父组件传过来的值
watch(() => props.dialogVisible,
(newVal) => {
exportDialogVisible.value = newVal
}
)
watch(
() => props.dialogVisible,
(newVal) => {
exportDialogVisible.value = newVal;
}
);
// 监听组件内的值并向父组件更新
watch(() => exportDialogVisible.value,
(newVal) => {
emit('update:dialogVisible', newVal)
}
)
watch(
() => exportDialogVisible.value,
(newVal) => {
emit("update:dialogVisible", newVal);
}
);
</script>
<style lang="scss" scoped>
.formStyle {
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
}
.checkboxStyle {
display: flex;
gap: 30px;
/* 复选框之间的间距 */
display: flex;
gap: 30px;
/* 复选框之间的间距 */
}
</style>
\ No newline at end of file
</style>
<template>
<div style="margin-bottom: 0" class="menu-title">
<div class="title">{{ props.title }}</div>
<div class="low-titme">{{ props.subtitle }}</div>
</div>
</template>
<script setup lang="ts">
const props = defineProps<{
title?: string;
subtitle?: string;
}>();
</script>
<style scoped>
.title {
text-align: left;
font-size: 18px;
font-weight: 500;
color: white;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.low-titme {
color: rgba(255, 255, 255, 0.8);
text-align: left;
margin-left: 20px;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
}
.menu-title {
padding: 20px 0 10px 20px;
user-select: none;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.15);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1), inset 0 0 10px rgba(255, 255, 255, 0.05);
}
</style>
<template>
<div class="box">
<div class="left"></div>
<div class="content">
<slot></slot>
</div>
<div class="right"></div>
</div>
</template>
<script setup lang="ts"></script>
<style scoped>
.box {
position: relative;
}
.content {
width: 95%;
height: 80px;
margin: auto;
border: 1.5px solid #0270b6;
border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
border-top-right-radius: 20px;
border-left: none;
border-right: none;
background-image: linear-gradient(
120deg,
rgba(7, 47, 70, 0.6) 0%,
/* 起始色:80% 透明度 */ rgba(6, 20, 37, 0.4) 100% /* 结束色:60% 透明度 */
);
}
.left {
width: 50px;
height: 40px;
background-color: white;
position: absolute;
top: 50%;
transform: translateY(-50%);
background-image: linear-gradient(to right, #00a8ff, #003366);
}
.right {
width: 50px;
height: 40px;
background-color: white;
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
background-image: linear-gradient(to left, #00a8ff, #003366);
}
</style>
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { computed } from "vue";
import { useRoute } from "vue-router";
const route = useRoute()
const key = computed(() => route.path)
const route = useRoute();
const key = computed(() => route.path);
</script>
<template>
......@@ -28,7 +28,7 @@ const key = computed(() => route.path)
overflow-y: auto; /* 修改为auto允许垂直滚动 */
overflow-x: hidden; /* 防止水平滚动 */
}
.fixed-header+.app-main {
.fixed-header + .app-main {
padding-top: 50px;
}
</style>
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/store/user'
import { useAppStore } from '@/store/app'
import { storeToRefs } from 'pinia'
import Breadcrumb from '@/components/Breadcrumb/index.vue'
import Hamburger from '@/components/Hamburger/index.vue'
const router = useRouter()
const userStore = useUserStore()
const appStore = useAppStore()
const { sidebar } = storeToRefs(appStore)
const avatar = computed(() => userStore.avatar || 'user-avatar.gif')
import { computed } from "vue";
import { useRouter } from "vue-router";
import { useUserStore } from "@/store/user";
import { useAppStore } from "@/store/app";
import { storeToRefs } from "pinia";
import Breadcrumb from "@/components/Breadcrumb/index.vue";
import Hamburger from "@/components/Hamburger/index.vue";
const router = useRouter();
const userStore = useUserStore();
const appStore = useAppStore();
const { sidebar } = storeToRefs(appStore);
const avatar = computed(() => userStore.avatar || "user-avatar.gif");
const toggleSideBar = () => {
appStore.toggleSidebar()
}
appStore.toggleSidebar();
};
const logout = async () => {
await userStore.logout()
router.push(`/login?redirect=${router.currentRoute.value.fullPath}`)
}
await userStore.logout();
router.push(`/login?redirect=${router.currentRoute.value.fullPath}`);
};
</script>
<template>
......@@ -30,18 +30,16 @@ const logout = async () => {
<div class="right-menu">
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img :src="avatar" class="user-avatar">
<img :src="avatar" class="user-avatar" />
<el-icon><CaretBottom /></el-icon>
</div>
<template #dropdown>
<el-dropdown-menu class="user-dropdown">
<router-link to="/">
<el-dropdown-item>
首页
</el-dropdown-item>
<el-dropdown-item> 首页 </el-dropdown-item>
</router-link>
<el-dropdown-item divided @click="logout">
<span style="display:block;">退出</span>
<span style="display: block">退出</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
......@@ -56,18 +54,18 @@ const logout = async () => {
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container {
line-height: 46px;
height: 100%;
float: left;
cursor: pointer;
transition: background .3s;
-webkit-tap-highlight-color:transparent;
transition: background 0.3s;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, .025)
background: rgba(0, 0, 0, 0.025);
}
}
......@@ -94,10 +92,10 @@ const logout = async () => {
&.hover-effect {
cursor: pointer;
transition: background .3s;
transition: background 0.3s;
&:hover {
background: rgba(0, 0, 0, .025)
background: rgba(0, 0, 0, 0.025);
}
}
}
......
<script setup lang="ts">
import settings from '@/settings'
import settings from "@/settings";
const props = defineProps({
collapse: {
type: Boolean,
required: true
}
})
required: true,
},
});
const title = settings.title || 'fk spider web'
const title = settings.title || "fk spider web";
// Logo 图片可在后续使用实际的 logo 文件
// const logo = require('@/assets/logo.png')
const logo = '' // 暂时为空
const logo = ""; // 暂时为空
</script>
<template>
<div class="sidebar-logo-container" :class="{'collapse': collapse}">
<div class="sidebar-logo-container" :class="{ collapse: collapse }">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" alt="logo">
<img v-if="logo" :src="logo" class="sidebar-logo" alt="logo" />
<h1 v-else class="sidebar-title">{{ title }}</h1>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo" alt="logo">
<img v-if="logo" :src="logo" class="sidebar-logo" alt="logo" />
<h1 class="sidebar-title">{{ title }}</h1>
</router-link>
</transition>
......@@ -55,6 +53,7 @@ const logo = '' // 暂时为空
& .sidebar-title {
display: inline-block;
letter-spacing: 2px;
margin: 0;
color: #fff;
font-weight: 600;
......
import { createApp } from 'vue'
import 'virtual:uno.css'
import App from './App.vue'
import router from './router'
import pinia from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import { createApp } from "vue";
import "virtual:uno.css";
import App from "./App.vue";
import router from "./router";
import pinia from "./store";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import {
UserFilled,
Lock,
......@@ -31,46 +31,47 @@ import {
Message,
DataAnalysis,
Notebook,
Setting
} from '@element-plus/icons-vue'
import 'normalize.css/normalize.css'
import './styles/index.scss'
import './style.css'
import './permission' // 权限控制
Setting,
} from "@element-plus/icons-vue";
import "normalize.css/normalize.css";
import "./styles/index.scss";
import "./style.css";
import "./permission"; // 权限控制
import "animate.css";
const app = createApp(App)
const app = createApp(App);
// 注册 Element Plus 图标
app.component('Monitor', Monitor)
app.component('Document', Document)
app.component('List', List)
app.component('Key', Key)
app.component('House', House)
app.component('Clock', Clock)
app.component('Message', Message)
app.component('DataAnalysis', DataAnalysis)
app.component('Notebook', Notebook)
app.component('Setting', Setting)
app.component("Monitor", Monitor);
app.component("Document", Document);
app.component("List", List);
app.component("Key", Key);
app.component("House", House);
app.component("Clock", Clock);
app.component("Message", Message);
app.component("DataAnalysis", DataAnalysis);
app.component("Notebook", Notebook);
app.component("Setting", Setting);
app.component('UserFilled', UserFilled)
app.component('Lock', Lock)
app.component('View', View)
app.component('Hide', Hide)
app.component('CaretBottom', CaretBottom)
app.component('HomeFilled', HomeFilled)
app.component('Menu', Menu)
app.component('Tickets', Tickets)
app.component('Folder', Folder)
app.component('Files', Files)
app.component('Loading', Loading)
app.component('VideoPlay', VideoPlay)
app.component('Refresh', Refresh)
app.component('Back', Back)
app.component('Upload', Upload)
app.component('Plus', Plus)
app.component("UserFilled", UserFilled);
app.component("Lock", Lock);
app.component("View", View);
app.component("Hide", Hide);
app.component("CaretBottom", CaretBottom);
app.component("HomeFilled", HomeFilled);
app.component("Menu", Menu);
app.component("Tickets", Tickets);
app.component("Folder", Folder);
app.component("Files", Files);
app.component("Loading", Loading);
app.component("VideoPlay", VideoPlay);
app.component("Refresh", Refresh);
app.component("Back", Back);
app.component("Upload", Upload);
app.component("Plus", Plus);
app.use(router)
app.use(pinia)
app.use(ElementPlus, { size: 'default' })
app.use(router);
app.use(pinia);
app.use(ElementPlus, { size: "default" });
app.mount('#app')
app.mount("#app");
interface ISettings {
title: string
fixedHeader: boolean
sidebarLogo: boolean
title: string;
fixedHeader: boolean;
sidebarLogo: boolean;
}
const settings: ISettings = {
title: 'Spider Admin Pro',
title: "互联网信息采集",
fixedHeader: true,
sidebarLogo: true
}
sidebarLogo: true,
};
export default settings
export default settings;
import { defineStore } from 'pinia'
import { defineStore } from "pinia";
import { useSlideStateStore } from "./slideState";
interface AppState {
sidebar: {
opened: boolean
withoutAnimation: boolean
},
device: 'desktop' | 'mobile'
opened: boolean;
withoutAnimation: boolean;
};
device: "desktop" | "mobile";
}
export const useAppStore = defineStore('app', {
export const useAppStore = defineStore("app", {
state: (): AppState => ({
sidebar: {
opened: localStorage.getItem('sidebarStatus')
? !!+localStorage.getItem('sidebarStatus')! // 将获取到的值转换为布尔值 其中 + 为先转为数字 !! 为转成 bool 值
opened: localStorage.getItem("sidebarStatus")
? !!+localStorage.getItem("sidebarStatus")! // 将获取到的值转换为布尔值 其中 + 为先转为数字 !! 为转成 bool 值
: true,
withoutAnimation: false
withoutAnimation: false,
},
device: 'desktop',
device: "desktop",
}),
actions: {
toggleSidebar() {
this.sidebar.opened = !this.sidebar.opened
this.sidebar.withoutAnimation = false
const slideStateStore = useSlideStateStore();
this.sidebar.opened = !this.sidebar.opened;
this.sidebar.withoutAnimation = false;
if (this.sidebar.opened) {
localStorage.setItem('sidebarStatus', '1')
localStorage.setItem("sidebarStatus", "1");
} else {
localStorage.setItem('sidebarStatus', '0')
localStorage.setItem("sidebarStatus", "0");
}
slideStateStore.setSlideState(this.sidebar.opened ? "1" : "0");
},
closeSideBar(options: { withoutAnimation: boolean }) {
this.sidebar.opened = false
this.sidebar.withoutAnimation = options.withoutAnimation
localStorage.setItem('sidebarStatus', '0')
this.sidebar.opened = false;
this.sidebar.withoutAnimation = options.withoutAnimation;
localStorage.setItem("sidebarStatus", "0");
const slideStateStore = useSlideStateStore();
slideStateStore.setSlideState("0");
},
toggleDevice(device: 'desktop' | 'mobile') {
this.device = device
}
}
})
toggleDevice(device: "desktop" | "mobile") {
this.device = device;
},
},
});
import { defineStore } from "pinia";
import { ref } from "vue";
export const useSlideStateStore = defineStore("slideState", () => {
const slideState = ref<boolean>(localStorage.getItem("sidebarStatus") == "1");
function getSlideState(): boolean {
return slideState.value;
}
function setSlideState(state: any) {
slideState.value = state == "1" ? true : false;
}
return {
slideState,
getSlideState,
setSlideState,
};
});
......@@ -38,7 +38,6 @@
--el-table-text-color: #FFFFFF;
}
// 分段选择器的样式
.custom-style .el-segmented {
// 选中选项的背景颜色
......@@ -91,9 +90,37 @@
// .el-date-editor {
// .el-date-editor {
// color: #ffffff;
// }
// }
// }
.el-date-editor .el-range-input{
color: #ffffff;
}
.el-loading-spinner .path {
stroke: white !important;
/* 替换为你需要的颜色(如 #304156 或 rgb(48, 65, 86)) */
}
/* 卡片外层容器透明 */
.el-card {
background-color: transparent !important;
border: none;
/* 可选:去除边框 */
}
/* 卡片内容区域透明 */
.el-card__body {
background-color: transparent !important;
padding: 16px;
/* 保持默认内边距,可按需调整 */
}
.el-popover {
background-color: #1D5484 !important;
color: white !important;
}
.el-popper__arrow::before{
background-color: #1D5484 !important;
}
\ No newline at end of file
......@@ -58,3 +58,7 @@ body {
display: table;
clear: both;
}
:root {
--animate-duration: 0.15s !important;
}
\ No newline at end of file
const getCurTime = () => {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1;
const date = now.getDate();
const weekdays = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
const weekday = weekdays[now.getDay()];
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const seconds = String(now.getSeconds()).padStart(2, "0");
return `${year}${month}${date}${weekday} ${hours}${minutes}${seconds}`;
};
export default getCurTime;
\ No newline at end of file
const formatExactLargeNum = (num: number | string | null) => {
if (num === null || num === undefined) return "";
if (typeof num !== "number" && typeof num !== "string") return num;
const parsedNum = typeof num === "string" ? Number(num.replace(/,/g, "")) : num;
if (isNaN(parsedNum)) return num;
if (Math.abs(parsedNum) > 100000000) {
return parsedNum.toExponential(2);
} else {
return parsedNum.toLocaleString("en-US", {
useGrouping: true,
maximumFractionDigits: 0,
minimumFractionDigits: 0,
});
}
};
export default formatExactLargeNum;
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { getToken, removeToken } from '@/utils/auth'
import axios from "axios";
import { ElMessage } from "element-plus";
import { getToken, removeToken } from "@/utils/auth";
// 创建axios实例
const instance = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API || '',
baseURL: import.meta.env.VITE_APP_BASE_API || "",
timeout: 10000, // 毫秒
headers: {
'Content-Type': 'application/zip; charset=utf-8'
}
})
"Content-Type": "application/zip; charset=utf-8",
},
});
// 请求拦截器
instance.interceptors.request.use(
(config) => {
const token = getToken()
const token = getToken();
if (token) {
// 保持与原项目相同的Token头设置
config.headers['Token'] = token
config.headers["Token"] = token;
}
return config
return config;
},
(err) => {
console.log('请求出错')
return Promise.reject(err)
console.log("请求出错");
return Promise.reject(err);
}
)
);
// 响应拦截器
instance.interceptors.response.use(
(res) => {
let result = res.data
let result = res.data;
if (typeof res.data === 'string') {
if (typeof res.data === "string") {
try {
result = JSON.parse(res.data)
result = JSON.parse(res.data);
} catch (e) {
// 不是JSON格式,保持原样
}
} else {
// 4000 token无效或者过期
if (result.code === 4000) {
removeToken()
window.location.reload()
removeToken();
window.location.reload();
}
if (result.code === 0) {
result.ok = true
result.ok = true;
} else {
result.ok = false
ElMessage.error(result.msg || '请求失败')
result.ok = false;
ElMessage.error(result.msg || "请求失败");
}
}
return result
return result;
},
(err) => {
ElMessage.error('网络请求出错, 请检查网络')
return Promise.reject(err)
ElMessage.error("网络请求出错, 请检查网络");
return Promise.reject(err);
}
)
);
// HTTP 请求方法常量
export const GET = 'get'
export const POST = 'post'
export const PUT = 'put'
export const DELETE = 'delete'
export const GET = "get";
export const POST = "post";
export const PUT = "put";
export const DELETE = "delete";
// 请求函数类型
export interface RequestConfig {
url: string;
method: 'get' | 'post' | 'put' | 'delete';
method: "get" | "post" | "put" | "delete";
params?: any;
data?: any;
headers?: Record<string, string>;
}
export interface ApiResponse<T = any> {
code: number
data: T
message: string
code: number;
data: T;
message: string;
}
export interface QueryParams {
page?: number
size?: number
project?: string
spider?: string
scrapydServerId?: string
order_prop?: string
order_type?: string
status?: any
job?:any
page?: number;
size?: number;
project?: string;
spider?: string;
scrapydServerId?: string;
order_prop?: string;
order_type?: string;
status?: any;
job?: any;
}
// 请求函数
export const request = (config: RequestConfig) => {
return instance(config);
}
};
export interface UserQueryParams {
page?: number
size?: number
username?: string
nickname?: string
password?: string
role?: number
status?: any
id?: number
ids?: any
scrapydServerId?: string
project?: string
spiders?: any
times?: any
job_id?: string
scrapyd_server_id?: string
schedule_type?: string
spider?: string
cron?: string
options?: string
sat_name?: string
ntc_id?: string
filters?: any
norad_cat_id?: string
object_name?: string
name?:string
spacecraft?:string
station?:string
}
\ No newline at end of file
page?: number;
size?: number;
username?: string;
nickname?: string;
password?: string;
role?: number;
status?: any;
id?: number;
ids?: any;
scrapydServerId?: string;
project?: string;
spiders?: any;
times?: any;
job_id?: string;
scrapyd_server_id?: string;
schedule_type?: string;
spider?: string;
cron?: string;
options?: string;
sat_name?: string;
ntc_id?: string;
filters?: any;
norad_cat_id?: string;
object_name?: string;
name?: string;
spacecraft?: string;
station?: string;
interval?: number[];
}
<template>
<div class="text-left p-4 toolbarStyle">
<div class="formStyle">
<el-form inline>
<el-form-item>
<el-text class="mx-1">目标名称:</el-text>
</el-form-item>
<el-form-item>
<div>
<el-input placeholder="请选择" style="width: 220px" />
</div>
</el-form-item>
<el-form-item>
<el-text class="mx-1">时间:</el-text>
</el-form-item>
<el-form-item>
<el-date-picker v-model="timeValue" type="datetimerange" start-placeholder="开始时间" end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm:ss" date-format="YYYY/MM/DD ddd" time-format="A hh:mm:ss" />
</el-form-item>
<el-form-item>
<el-text class="mx-1">站点名称:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" style="width: 220px" />
</el-form-item>
<br></br>
<el-form-item>
<el-text class="mx-1">Norad Cat ID:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" style="width: 220px" />
</el-form-item>
<el-form-item>
<el-text class="mx-1">SNS Notice ID:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" style="width: 220px" />
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary" @click="handleExport">导出最近</el-button>
</el-space>
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary" @click="handleExport">导出选中</el-button>
</el-space>
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary">查询</el-button>
</el-space>
</el-form-item>
</el-form>
</div>
</div>
<div class="m-t-5" />
<div>
<el-table :data="tableData" style="width: 100%" border :row-style="{ height: '45px' }"
:header-cell-style="{ textAlign: 'center' }" :cell-style="{ textAlign: 'center' }">
<!-- <el-table-column type="selection" width="40" /> -->
<el-table-column property="number" label="序号" width="55" />
<el-table-column property="targetName" label="目标名称" show-overflow-tooltip />
<el-table-column property="stationPosition" label="站点位置" show-overflow-tooltip />
<el-table-column property="stationName" label="站点名称" show-overflow-tooltip />
<el-table-column property="NoradCatId" label="Norad Cat ID" show-overflow-tooltip />
<el-table-column property="SNSNoticeId" label="SNS Notice ID" show-overflow-tooltip />
<el-table-column property="dataTime" label="数据时间" show-overflow-tooltip />
<el-table-column property="recordTime" label="记录时间" show-overflow-tooltip />
<el-table-column property="tle" label="TLE" show-overflow-tooltip />
<el-table-column property="isSync" label="是否为同步" show-overflow-tooltip />
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="primary" plain link @click="handleDetails(scope.row)">
详情
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
@pagination="getData" />
</div>
</div>
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="765px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-8">
详情
</div>
</template>
<el-form label-width="155px" size="small" class="px-4">
<div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="SNS Notice ID:" label-position="left">
<el-input v-model="snsId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="主管部门:" label-position="left">
<el-input v-model="department" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标名称:" label-position="left">
<el-input v-model="targetName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="计划/非计划类型:" label-position="left">
<el-select placeholder=" ">
<el-option label="计划" value="planned" />
<el-option label="非计划" value="unplanned" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否为同步:" label-position="left">
<el-input v-model="syncType" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="同步位置:" label-position="left">
<el-input v-model="syncPosition" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="近地点:" label-position="left">
<el-input v-model="perigee" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="远地点:" label-position="left">
<el-input v-model="apogee" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最低海拔:" label-position="left">
<el-input v-model="lowestAltitude" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="参考主体:" label-position="left">
<el-input v-model="referenceSubject" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最低频率:" label-position="left">
<el-input v-model="lowestFrequency" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最高频率:" label-position="left">
<el-input v-model="highestFrequency" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="状态:" label-position="left">
<el-input v-model="status" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="有效期:" label-position="left">
<el-input v-model="validityPeriod" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最早使用日期:" label-position="left">
<el-input v-model="earliestUsageDate" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否确认使用:" label-position="left">
<el-input v-model="isUsed" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否暂停使用:" label-position="left">
<el-input v-model="isPauseUsed" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="记录时间:" label-position="left">
<el-input v-model="recordTime" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否纳入国际频率总表:" label-position="left">
<el-input v-model="IsInTheInternationalFrequencyList" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最早监管日期:" label-position="left">
<el-input v-model="earliestRegulatoryDate" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否恢复使用:" label-position="left">
<el-input v-model="isRestoreUsed" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="有效期卫星网络旧名称:" label-position="left">
<el-input v-model="BFIFICdate" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="最新相关 BR IFIC 发布日期:" label-position="left">
<el-input v-model="roundTripTime" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="往返光时(s):" label-position="left">
<el-input v-model="distance" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="距离(km):" label-position="left">
<el-input v-model="targetAzimuth" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标方位:" label-position="left">
<el-input v-model="targetElevation" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="目标俯仰:" label-position="left">
<el-input v-model="upstreamSignalSource" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号来源:" label-position="left">
<el-input v-model="upstreamSignalSource" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上行发射功率:" label-position="left">
<el-input v-model="upstreamLaunchPower" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号频段:" label-position="left">
<el-input v-model="upstreamFrequencyBand" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="风速(km/kr):" label-position="left">
<el-input v-model="windSpeed" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行信号来源:" label-position="left">
<el-input v-model="downstreamSignalSource" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下行信号频段:" label-position="left">
<el-input v-model="downstreamFrequencyBand" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行接收功率:" label-position="left">
<el-input v-model="downstreamReceptionPower" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型:" label-position="left">
<el-input v-model="type" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="INTLDES:" label-position="left">
<el-input v-model="intldes" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="失效时间:" label-position="left">
<el-input v-model="expirationTime" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="周期(min):" label-position="left">
<el-input v-model="period" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="INCL:" label-position="left">
<el-input v-model="incl" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="RCS:" label-position="left">
<el-input v-model="rcs" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="SITE:" label-position="left">
<el-input v-model="site" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="TLE:" label-position="left">
<el-input type="textarea" :rows="3" v-model="tle" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</el-dialog>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" @confirm="handleExportConfirm" />
<div class="text-left p-4 toolbarStyle">
<div class="formStyle">
<el-form inline>
<el-form-item>
<el-text class="mx-1">目标名称:</el-text>
</el-form-item>
<el-form-item>
<div>
<el-input placeholder="请选择" style="width: 220px" />
</div>
</el-form-item>
<el-form-item>
<el-text class="mx-1">时间:</el-text>
</el-form-item>
<el-form-item>
<el-date-picker
v-model="timeValue"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm:ss"
date-format="YYYY/MM/DD ddd"
time-format="A hh:mm:ss"
/>
</el-form-item>
<el-form-item>
<el-text class="mx-1">站点名称:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" style="width: 220px" />
</el-form-item>
<el-form-item>
<el-text class="mx-1">Norad Cat ID:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" style="width: 220px" />
</el-form-item>
<el-form-item>
<el-text class="mx-1">SNS Notice ID:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" style="width: 220px" />
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary" @click="handleExport">导出最近</el-button>
</el-space>
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary" @click="handleExport">导出选中</el-button>
</el-space>
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary">查询</el-button>
</el-space>
</el-form-item>
</el-form>
</div>
</div>
<div class="m-t-5" />
<div>
<el-table
:data="tableData"
style="width: 100%"
border
:row-style="{ height: '45px' }"
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
>
<!-- <el-table-column type="selection" width="40" /> -->
<el-table-column property="number" label="序号" width="55" />
<el-table-column property="targetName" label="目标名称" show-overflow-tooltip />
<el-table-column property="stationPosition" label="站点位置" show-overflow-tooltip />
<el-table-column property="stationName" label="站点名称" show-overflow-tooltip />
<el-table-column property="NoradCatId" label="Norad Cat ID" show-overflow-tooltip />
<el-table-column property="SNSNoticeId" label="SNS Notice ID" show-overflow-tooltip />
<el-table-column property="dataTime" label="数据时间" show-overflow-tooltip />
<el-table-column property="recordTime" label="记录时间" show-overflow-tooltip />
<el-table-column property="tle" label="TLE" show-overflow-tooltip />
<el-table-column property="isSync" label="是否为同步" show-overflow-tooltip />
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="primary" plain link @click="handleDetails(scope.row)"> 详情 </el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination
:total="pageObj.total"
v-model:page="pageObj.pageNo"
v-model:limit="pageObj.pageSize"
@pagination="getData"
/>
</div>
</div>
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="765px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-8">详情</div>
</template>
<el-form label-width="155px" size="small" class="px-4">
<div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="SNS Notice ID:" label-position="left">
<el-input v-model="snsId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="主管部门:" label-position="left">
<el-input v-model="department" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标名称:" label-position="left">
<el-input v-model="targetName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="计划/非计划类型:" label-position="left">
<el-select placeholder=" ">
<el-option label="计划" value="planned" />
<el-option label="非计划" value="unplanned" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否为同步:" label-position="left">
<el-input v-model="syncType" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="同步位置:" label-position="left">
<el-input v-model="syncPosition" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="近地点:" label-position="left">
<el-input v-model="perigee" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="远地点:" label-position="left">
<el-input v-model="apogee" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最低海拔:" label-position="left">
<el-input v-model="lowestAltitude" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="参考主体:" label-position="left">
<el-input v-model="referenceSubject" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最低频率:" label-position="left">
<el-input v-model="lowestFrequency" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最高频率:" label-position="left">
<el-input v-model="highestFrequency" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="状态:" label-position="left">
<el-input v-model="status" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="有效期:" label-position="left">
<el-input v-model="validityPeriod" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最早使用日期:" label-position="left">
<el-input v-model="earliestUsageDate" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否确认使用:" label-position="left">
<el-input v-model="isUsed" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否暂停使用:" label-position="left">
<el-input v-model="isPauseUsed" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="记录时间:" label-position="left">
<el-input v-model="recordTime" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否纳入国际频率总表:" label-position="left">
<el-input v-model="IsInTheInternationalFrequencyList" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最早监管日期:" label-position="left">
<el-input v-model="earliestRegulatoryDate" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否恢复使用:" label-position="left">
<el-input v-model="isRestoreUsed" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="有效期卫星网络旧名称:" label-position="left">
<el-input v-model="BFIFICdate" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="最新相关 BR IFIC 发布日期:" label-position="left">
<el-input v-model="roundTripTime" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="往返光时(s):" label-position="left">
<el-input v-model="distance" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="距离(km):" label-position="left">
<el-input v-model="targetAzimuth" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标方位:" label-position="left">
<el-input v-model="targetElevation" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="目标俯仰:" label-position="left">
<el-input v-model="upstreamSignalSource" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号来源:" label-position="left">
<el-input v-model="upstreamSignalSource" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上行发射功率:" label-position="left">
<el-input v-model="upstreamLaunchPower" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号频段:" label-position="left">
<el-input v-model="upstreamFrequencyBand" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="风速(km/kr):" label-position="left">
<el-input v-model="windSpeed" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行信号来源:" label-position="left">
<el-input v-model="downstreamSignalSource" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下行信号频段:" label-position="left">
<el-input v-model="downstreamFrequencyBand" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行接收功率:" label-position="left">
<el-input v-model="downstreamReceptionPower" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型:" label-position="left">
<el-input v-model="type" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="INTLDES:" label-position="left">
<el-input v-model="intldes" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="失效时间:" label-position="left">
<el-input v-model="expirationTime" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="周期(min):" label-position="left">
<el-input v-model="period" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="INCL:" label-position="left">
<el-input v-model="incl" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="RCS:" label-position="left">
<el-input v-model="rcs" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="SITE:" label-position="left">
<el-input v-model="site" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="TLE:" label-position="left">
<el-input type="textarea" :rows="3" v-model="tle" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</el-dialog>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" @confirm="handleExportConfirm" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import exportDialog from '@/components/Export/index.vue'
const timeValue = ref('')
const detailVisibleValue = ref(false)
const showDeleteDialog = ref(false)
import { ref } from "vue";
import Pagination from "@/components/pagination/index.vue";
import exportDialog from "@/components/Export/index.vue";
const timeValue = ref("");
const detailVisibleValue = ref(false);
const showDeleteDialog = ref(false);
// SNS Notice ID
const snsId = ref('')
const snsId = ref("");
// 主管部门
const department = ref('')
const department = ref("");
// 目标名称
const targetName = ref('')
const targetName = ref("");
// 计划类型
const planType = ref('')
const planType = ref("");
// 是否为同步
const syncType = ref('')
const syncType = ref("");
// 同步位置
const syncPosition = ref('')
const syncPosition = ref("");
// 近地点
const perigee = ref('')
const perigee = ref("");
// 远地点
const apogee = ref('')
const apogee = ref("");
// 最低海拔
const lowestAltitude = ref('')
const lowestAltitude = ref("");
// 参考主体
const referenceSubject = ref('')
const referenceSubject = ref("");
// 最低频率
const lowestFrequency = ref('')
const lowestFrequency = ref("");
// 最高频率
const highestFrequency = ref('')
const highestFrequency = ref("");
// 状态
const status = ref('')
const status = ref("");
// 有效期
const validityPeriod = ref('')
const validityPeriod = ref("");
// 最早使用日期
const earliestUsageDate = ref('')
const earliestUsageDate = ref("");
// 是否确认使用
const isUsed = ref('')
const isUsed = ref("");
// 是否暂停使用
const isPauseUsed = ref('')
const isPauseUsed = ref("");
// 记录时间
const recordTime = ref('')
const recordTime = ref("");
// 是否在国际频率列表中
const IsInTheInternationalFrequencyList = ref('')
const IsInTheInternationalFrequencyList = ref("");
// 最早监管日期
const earliestRegulatoryDate = ref('')
const earliestRegulatoryDate = ref("");
// 是否恢复使用
const isRestoreUsed = ref('')
const isRestoreUsed = ref("");
// 最新相关BF IFIC发布日期
const BFIFICdate = ref('')
const BFIFICdate = ref("");
// 往返光时
const roundTripTime = ref('')
const roundTripTime = ref("");
// 距离
const distance = ref('')
const distance = ref("");
// 目标方位
const targetAzimuth = ref('')
const targetAzimuth = ref("");
// 目标俯仰
const targetElevation = ref('')
const targetElevation = ref("");
// 上行信号来源
const upstreamSignalSource = ref('')
const upstreamSignalSource = ref("");
// 上行发射功率
const upstreamLaunchPower = ref('')
const upstreamLaunchPower = ref("");
// 上行信号频段
const upstreamFrequencyBand = ref('')
const upstreamFrequencyBand = ref("");
// 风速
const windSpeed = ref('')
const windSpeed = ref("");
// 下行信号来源
const downstreamSignalSource = ref('')
const downstreamSignalSource = ref("");
// 下行信号频段
const downstreamFrequencyBand = ref('')
const downstreamFrequencyBand = ref("");
// 下行接收功率
const downstreamReceptionPower = ref('')
const downstreamReceptionPower = ref("");
// 类型
const type = ref('')
const type = ref("");
// INTLDES
const intldes = ref('')
const intldes = ref("");
// 失效时间
const expirationTime = ref('')
const expirationTime = ref("");
// 周期
const period = ref('')
const period = ref("");
// INCL
const incl = ref('')
const incl = ref("");
// RCS
const rcs = ref('')
const rcs = ref("");
// SITE
const site = ref('')
const site = ref("");
// TLE
const tle = ref('')
const tle = ref("");
const tableData = ref([
{
number: '1',
targetName: 'VOYAGER-2',
stationPosition: '[148.98,-35.22]',
stationName: 'CANBERRA',
NoradCatId: '2134',
SNSNoticeId: '90504649',
dataTime: '2025-06-24 14:35:23',
recordTime: '2025-06-25 14:35:23',
tle: '-',
isSync: '是',
},
{
name: '1',
},
{
name: '1',
},
{
name: '1',
},
{
name: '1',
},
{
name: '1',
},
{
name: '1',
},
{
name: '1',
},
{
name: '1',
},
{
name: '1',
},
])
{
number: "1",
targetName: "VOYAGER-2",
stationPosition: "[148.98,-35.22]",
stationName: "CANBERRA",
NoradCatId: "2134",
SNSNoticeId: "90504649",
dataTime: "2025-06-24 14:35:23",
recordTime: "2025-06-25 14:35:23",
tle: "-",
isSync: "是",
},
{
name: "1",
},
{
name: "1",
},
{
name: "1",
},
{
name: "1",
},
{
name: "1",
},
{
name: "1",
},
{
name: "1",
},
{
name: "1",
},
{
name: "1",
},
]);
const pageObj = ref({
total: 10,
pageSize: 10,
pageNo: 1
})
total: 10,
pageSize: 10,
pageNo: 1,
});
const handleDetails = (row: any) => {
console.log(row);
detailVisibleValue.value = true
}
console.log(row);
detailVisibleValue.value = true;
};
const getData = () => {
console.log('getData');
}
console.log("getData");
};
const handleClose = () => {
detailVisibleValue.value = false
}
detailVisibleValue.value = false;
};
const handleExportConfirm = () => {
}
const handleExportConfirm = () => {};
const handleExport = () => {
showDeleteDialog.value = true
}
showDeleteDialog.value = true;
};
</script>
<style scoped lang="scss">
// 调整表单项间距
.detailForm {
.el-form-item {
margin-bottom: 7px !important;
}
.el-form-item {
margin-bottom: 7px !important;
}
}
/* 工具栏样式 */
.toolbarStyle {
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
/* 表格样式 */
.formStyle {
display: flex;
justify-content: space-around;
padding: 1px;
margin-top: 1%;
display: flex;
justify-content: space-around;
padding: 1px;
margin-top: 1%;
}
/* 文字样式 */
.el-text {
color: #FFFFFF;
color: #ffffff;
}
</style>
<style>
/* 修改el文本域的背景颜色与边框 */
.el-textarea__inner {
background-color: #1d5484;
--el-input-border-color: none;
background-color: #1d5484;
--el-input-border-color: none;
}
/* 修改el选择器的样式 */
.el-select__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 删除el选择器选中时的边框 */
.is-hovering {
box-shadow: none !important;
box-shadow: none !important;
}
/* 修改el输入框的样式 */
.el-input__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 修改el下拉框的背景颜色 */
.el-select-dropdown {
background-color: #1d5484;
background-color: #1d5484;
}
/* 修改el下拉框选项的字体颜色 */
.el-select-dropdown__item {
color: #FFFFFF;
color: #ffffff;
}
/* 修改el下拉框选项选中时的文字颜色 */
.el-select-dropdown__item:hover {
color: #409eff;
color: #409eff;
}
/* 修改el日期选择器的边框为none */
.el-date-editor {
--el-input-border-color: none
--el-input-border-color: none;
}
/* 去除按钮点击后的黑边框 */
.el-button:focus {
outline: none;
outline: none;
}
</style>
<style>
/* 修改弹窗样式 */
.el-dialog {
background: transparent;
background-image: url("@/assets/picture/dialog1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
color: #ffffff;
background: transparent;
background-image: url("@/assets/picture/dialog1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
color: #ffffff;
.el-dialog__title {
color: #ffffff;
}
.el-dialog__title {
color: #ffffff;
}
}
/* 修改表单样式 */
.el-form {
.el-form-item__label {
color: #ffffff;
}
.el-form-item__label {
color: #ffffff;
}
}
</style>
\ No newline at end of file
</style>
<template>
<!-- <div class="text-left p-1 toolbarStyle">
<div class="formStyle">
<el-form inline>
<el-form-item>
<el-text class="mx-1">目标名称:</el-text>
</el-form-item>
<el-form-item>
<div>
<el-input placeholder="请输入" style="width: 190px" />
</div>
</el-form-item>
<el-form-item>
<el-text class="mx-1">获取时间:</el-text>
</el-form-item>
<el-form-item>
<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: 330px" value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
<el-form-item>
<el-text class="mx-1">站点名称:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" style="width: 180.5px" />
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary">查询</el-button>
</el-space>
</el-form-item>
</el-form>
</div>
</div> -->
<div class="flex justify-left m-l-1%">
<el-button :type="statusMode === false ? 'primary' : 'danger'" @click="handleRefresh" size="small">{{ statusMode === false ?
'开始刷新' : '停止刷新' }}</el-button>
</div>
<div class="m-t-5" />
<div>
<el-table :data="tableData" style="width: 100%" border :row-style="{ height: '46px' }"
:header-cell-style="{ textAlign: 'center' }" :cell-style="{ textAlign: 'center' }">
<!-- <el-table-column type="selection" width="40" /> -->
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="name" label="天线名称" show-overflow-tooltip />
<el-table-column property="targets[0].name" label="目标名称" show-overflow-tooltip />
<!-- <el-table-column property="distance" label="距离(km)" show-overflow-tooltip />
<div class="flex justify-left" style="padding-left: 10px">
<el-button :type="statusMode === false ? 'primary' : 'danger'" @click="handleRefresh" size="small">{{
statusMode === false ? "开始刷新" : "停止刷新"
}}</el-button>
</div>
<div class="m-t-5" />
<div class="table-content">
<el-table
v-loading="!tableData"
element-loading-background="rgba(48, 65, 86, 0.7)"
:data="tableData"
style="width: 100%"
border
:row-style="{ height: '46px' }"
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
>
<!-- <el-table-column type="selection" width="40" /> -->
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="name" label="天线名称" show-overflow-tooltip />
<el-table-column property="targets[0].name" label="目标名称" show-overflow-tooltip />
<!-- <el-table-column property="distance" label="距离(km)" show-overflow-tooltip />
<el-table-column property="roundTripTime" label="往返光时(s)" show-overflow-tooltip />
<el-table-column property="stationName" label="站点名称" show-overflow-tooltip /> -->
<el-table-column property="azimuthAngle" label="目标方位" show-overflow-tooltip />
<el-table-column property="elevationAngle" label="目标俯仰" show-overflow-tooltip />
<!-- <el-table-column property="targetDistance" label="目标距离" show-overflow-tooltip /> -->
<el-table-column property="windSpeed" label="风速(km/hr)" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.windSpeed === '' ? '无' : scope.row.windSpeed }}
</template>
</el-table-column>
<el-table-column property="targets[0].name" label="上行信号来源" show-overflow-tooltip />
<el-table-column property="signals[0].band" label="上行信号频段" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.signals.length === 0 ? '无' : scope.row.signals[0].band }}
</template>
</el-table-column>
<el-table-column property="signals[0].power" label="上行发射功率" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.signals.length === 0 ? '无' : scope.row.signals[0].power }}
</template>
</el-table-column>
<el-table-column property="targets[0].name" label="下行信号来源" show-overflow-tooltip />
<el-table-column property="signals[1].band" label="下行信号频段" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.signals.length < 2 ? '无' : scope.row.signals[1].band }} </template>
</el-table-column>
<el-table-column property="signals[1].power" label="下行接收功率" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.signals.length < 2 ? '无' : scope.row.signals[1].power }} </template>
</el-table-column>
<!-- <el-table-column property="dataTime" label="数据时间" show-overflow-tooltip /> -->
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="primary" plain link @click="handleDetails(scope.row)">
详情
</el-button>
</template>
</el-table-column>
</el-table>
<!-- <div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
@pagination="getData" />
</div> -->
</div>
<el-table-column property="azimuthAngle" label="目标方位" show-overflow-tooltip />
<el-table-column property="elevationAngle" label="目标俯仰" show-overflow-tooltip />
<!-- <el-table-column property="targetDistance" label="目标距离" show-overflow-tooltip /> -->
<el-table-column property="windSpeed" label="风速(km/hr)" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.windSpeed === "" ? "-" : scope.row.windSpeed }}
</template>
</el-table-column>
<el-table-column property="targets[0].name" label="上行信号来源" show-overflow-tooltip />
<el-table-column property="signals[0].band" label="上行信号频段" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.signals.length === 0 ? "-" : scope.row.signals[0].band }}
</template>
</el-table-column>
<el-table-column property="signals[0].power" label="上行发射功率" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.signals.length === 0 ? "-" : scope.row.signals[0].power }}
</template>
</el-table-column>
<el-table-column property="targets[0].name" label="下行信号来源" show-overflow-tooltip />
<el-table-column property="signals[1].band" label="下行信号频段" show-overflow-tooltip>
<template #default="scope"> {{ scope.row.signals.length < 2 ? "-" : scope.row.signals[1].band }} </template>
</el-table-column>
<el-table-column property="signals[1].power" label="下行接收功率" show-overflow-tooltip>
<template #default="scope"> {{ scope.row.signals.length < 2 ? "-" : scope.row.signals[1].power }} </template>
</el-table-column>
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="primary" plain link @click="handleDetails(scope.row)"> 详情 </el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="800px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-8">
详情
</div>
</template>
<el-form label-width="94px" size="small" class="px-4">
<div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="天线名称:" label-position="left">
<el-input v-model="antennaName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="风速(km/hr):" label-position="left">
<el-input v-model="windSpeed" />
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="距离(km):" label-position="left">
<el-input v-model="distance" />
</el-form-item>
</el-col> -->
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标名称:" label-position="left">
<el-input v-model="targetName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="天线状态:" label-position="left">
<el-input v-model="antennaStatus" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- <el-col :span="12">
<el-form-item label="往返光时:" label-position="left">
<el-input v-model="roundTripTime" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="站点名称:" label-position="left">
<el-input v-model="stationName" />
</el-form-item>
</el-col> -->
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标方位:" label-position="left">
<el-input v-model="targetAzimuth" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="目标俯仰:" label-position="left">
<el-input v-model="targetElevation" />
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="20"> -->
<!-- <el-col :span="12">
<el-form-item label="目标距离:" label-position="left">
<el-input v-model="targetDistance" />
</el-form-item>
</el-col> -->
<!-- <el-col :span="12">
<el-form-item label="风速(km/hr):" label-position="left">
<el-input v-model="windSpeed" />
</el-form-item>
</el-col> -->
<!-- </el-row> -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号状态:" label-position="left">
<el-input v-model="upSignalStatus" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上行信号来源:" label-position="left">
<el-input v-model="upSignalSource" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号频段:" label-position="left">
<el-input v-model="upSignalFrequencyBand" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上行发射功率:" label-position="left">
<el-input v-model="upSignalLaunchPower" />
</el-form-item>
</el-col>
<!-- <el-col :span="12">
<el-form-item label="下行信号来源:" label-position="left">
<el-input v-model="downSignalSignalSource" />
</el-form-item>
</el-col> -->
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行信号状态:" label-position="left">
<el-input v-model="downSignalStatus" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下行信号来源:" label-position="left">
<el-input v-model="downSignalSource" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行信号频段:" label-position="left">
<el-input v-model="downSignalFrequencyBand" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下行接收功率:" label-position="left">
<el-input v-model="downSignalReceptionPower" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="往返光时(s):" label-position="left">
<el-input v-model="roundTripTime" />
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="数据时间:" label-position="left">
<el-input v-model="dataTime" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="记录时间:" label-position="left">
<el-input v-model="recordTime" />
</el-form-item>
</el-col>
</el-row> -->
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否暂停使用:" label-position="left">
<el-input v-model="isSuspended" />
</el-form-item>
</el-col>
</el-row> -->
</div>
</el-form>
</el-dialog>
</div>
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="800px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-6">详情-{{ antennaName }}</div>
</template>
<el-row>
<el-col :span="12">
<el-card>
<div class="title">航天器信息:</div>
<el-divider style="margin: 0"></el-divider>
<div class="info-item">
<span class="item-title">目标名称:</span>
<span class="item">{{ targetName }}</span>
</div>
<div class="info-item">
<span class="item-title">距离:</span>
<span class="item">{{ targetDistance }}</span>
</div>
<div class="info-item">
<span class="item-title">往返光时:</span>
<span class="item">{{ roundTripTime }}</span>
</div>
</el-card>
<el-card>
<div class="title">天线信息:</div>
<el-divider style="margin: 0"></el-divider>
<div class="info-item">
<span class="item-title">天线名称:</span>
<span class="item">{{ antennaName }}</span>
</div>
<div class="info-item">
<span class="item-title">状态:</span>
<span class="item">{{ antennaStatus }}</span>
</div>
<div class="info-item">
<span class="item-title">方位:</span>
<span class="item">{{ targetAzimuth }}</span>
</div>
<div class="info-item">
<span class="item-title">仰俯:</span>
<span class="item">{{ targetElevation }}</span>
</div>
<div class="info-item">
<span class="item-title">风速(km/hr):</span>
<span class="item">{{ windSpeed }}</span>
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<div class="title">上行信号信息:</div>
<el-divider style="margin: 0"></el-divider>
<div class="info-item">
<span class="item-title">信号来源:</span>
<span class="item">{{ upSignalSource }}</span>
</div>
<div class="info-item">
<span class="item-title">信号频段:</span>
<span class="item">{{ upSignalFrequencyBand }}</span>
</div>
<div class="info-item">
<span class="item-title">发射功率:</span>
<span class="item">{{ upSignalLaunchPower }}</span>
</div>
</el-card>
<el-card>
<div class="title">下行信号信息:</div>
<el-divider style="margin: 0"></el-divider>
<div class="info-item">
<span class="item-title">信号来源:</span>
<span class="item">{{ downSignalSource }}</span>
</div>
<div class="info-item">
<span class="item-title">信号频段:</span>
<span class="item">{{ downSignalFrequencyBand }}</span>
</div>
<div class="info-item">
<span class="item-title">接收功率:</span>
<span class="item">{{ downSignalReceptionPower }}</span>
</div>
</el-card>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import { getDsnList } from '@/api/spiderData'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from "vue";
import Pagination from "@/components/pagination/index.vue";
import { getDsnList } from "@/api/spiderData";
import { ElMessage } from "element-plus";
const timeValue = ref('')
const statusMode = ref(false)
const detailVisibleValue = ref(false)
const timeValue = ref("");
const statusMode = ref(false);
const detailVisibleValue = ref(false);
// 目标名称
const targetName = ref('')
const targetName = ref("");
// 距离(km)
const distance = ref('')
const distance = ref("");
// 往返光时
const roundTripTime = ref('')
const roundTripTime = ref("");
// 站点名称
const stationName = ref('')
const stationName = ref("");
// 天线名称
const antennaName = ref('')
const antennaName = ref("");
// 天线状态
const antennaStatus = ref('')
const antennaStatus = ref("");
// 目标方位
const targetAzimuth = ref('')
const targetAzimuth = ref("");
// 目标俯仰
const targetElevation = ref('')
const targetElevation = ref("");
// 目标距离
const targetDistance = ref('')
const targetDistance = ref("");
// 风速(km/hr)
const windSpeed = ref('')
const windSpeed = ref("");
// 上行信号状态
const upSignalStatus = ref('')
const upSignalStatus = ref("");
// 上行信号来源
const upSignalSource = ref('')
const upSignalSource = ref("");
// 上行信号频段
const upSignalFrequencyBand = ref('')
const upSignalFrequencyBand = ref("");
// 上行发射功率
const upSignalLaunchPower = ref('')
const upSignalLaunchPower = ref("");
// 下行信号状态
const downSignalStatus = ref('')
const downSignalStatus = ref("");
// 下行信号来源
const downSignalSource = ref('')
const downSignalSource = ref("");
// 下行信号频段
const downSignalFrequencyBand = ref('')
const downSignalFrequencyBand = ref("");
// 下行接收功率
const downSignalReceptionPower = ref('')
const downSignalReceptionPower = ref("");
// 数据时间
const dataTime = ref('')
const dataTime = ref("");
// 记录时间
const recordTime = ref('')
const recordTime = ref("");
// 是否暂停使用
const isSuspended = ref('')
const isSuspended = ref("");
interface dsnInfo {
targetName:string
targetNam:string
targetName: string;
targetNam: string;
}
const dsnInfoDialog = ref<dsnInfo>()
const dsnInfoDialog = ref<dsnInfo>();
// 存放定时器的id
const timerId = ref<number | null>()
const tableData = ref()
const timerId = ref<number | null>();
const tableData = ref();
const pageObj = ref({
total: 10,
pageSize: 1,
pageNo: 1
})
total: 10,
pageSize: 1,
pageNo: 1,
});
// 查看数据详情的方法
const handleDetails = (row: any) => {
console.log(row);
targetName.value = row.targets[0].name
windSpeed.value = row.windSpeed === '' ? '无' : row.windSpeed
antennaName.value = row.name
antennaStatus.value = row.activity
targetAzimuth.value = row.azimuthAngle
targetElevation.value = row.elevationAngle
upSignalStatus.value = row.signals.length < 1 ? '无' : row.signals[0].active
upSignalSource.value = row.signals.length < 1 ? '无' : row.targets[0].name
upSignalFrequencyBand.value = row.signals.length < 1 ? '无' : row.signals[0].band
upSignalLaunchPower.value = row.signals.length < 1 ? '无' : row.signals[0].power
downSignalStatus.value = row.signals.length < 2 ? '无' : row.signals[1].active
downSignalSource.value = row.signals.length < 2 ? '无' : row.targets[0].name
downSignalFrequencyBand.value = row.signals.length < 2 ? '无' : row.signals[1].band
downSignalReceptionPower.value = row.signals.length < 2 ? '无' : row.signals[1].power
roundTripTime.value = row.targets[0].rtlt
detailVisibleValue.value = true
}
targetName.value = row.targets[0].name;
windSpeed.value = row.windSpeed === "" ? "-" : row.windSpeed;
antennaName.value = row.name;
antennaStatus.value = row.activity;
targetAzimuth.value = row.azimuthAngle;
targetDistance.value = row.targets[0].uplegRange;
targetElevation.value = row.elevationAngle;
upSignalStatus.value = row.signals.length < 1 ? "-" : row.signals[0].active;
upSignalSource.value = row.signals.length < 1 ? "-" : row.targets[0].name;
upSignalFrequencyBand.value = row.signals.length < 1 ? "-" : row.signals[0].band;
upSignalLaunchPower.value = row.signals.length < 1 ? "-" : row.signals[0].power;
downSignalStatus.value = row.signals.length < 2 ? "-" : row.signals[1].active;
downSignalSource.value = row.signals.length < 2 ? "-" : row.targets[0].name;
downSignalFrequencyBand.value = row.signals.length < 2 ? "-" : row.signals[1].band;
downSignalReceptionPower.value = row.signals.length < 2 ? "-" : row.signals[1].power;
roundTripTime.value = row.targets[0].rtlt;
detailVisibleValue.value = true;
};
// 获取dsn数据列表的方法
const getData = async () => {
const res = await getDsnList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize })
let dishesData = []
for(let i = 0; i < res.data.list[0].stations.length; i++){
for(let j = 0; j < res.data.list[0].stations[i].dishes.length; j++){
dishesData.push(res.data.list[0].stations[i].dishes[j])
}
}
pageObj.value.total = dishesData.length
tableData.value = dishesData
}
const res = await getDsnList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize });
let dishesData = [];
for (let i = 0; i < res.data.list[0].stations.length; i++) {
for (let j = 0; j < res.data.list[0].stations[i].dishes.length; j++) {
dishesData.push(res.data.list[0].stations[i].dishes[j]);
}
}
pageObj.value.total = dishesData.length;
tableData.value = dishesData;
};
const handleClose = () => {
detailVisibleValue.value = false
}
detailVisibleValue.value = false;
};
// 刷新数据的方法
const handleRefresh = () => {
// 切换是否开始刷新的状态
statusMode.value = !statusMode.value
// 删除定时器
if (timerId.value !== null) {
clearInterval(timerId.value);
timerId.value = null;
}
// 开始刷新时重新设置一个定时器
if (statusMode.value) {
ElMessage.success('开始刷新')
// 保存id删除的时候用
timerId.value = setInterval(async () => {
const res = await getDsnList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize });
tableData.value = res.data.list[0].dishes
}, 5000);
} else {
ElMessage.success('停止刷新')
getData()
}
}
// 切换是否开始刷新的状态
statusMode.value = !statusMode.value;
// 删除定时器
if (timerId.value !== null) {
clearInterval(timerId.value);
timerId.value = null;
}
// 开始刷新时重新设置一个定时器
if (statusMode.value) {
ElMessage.success("开始刷新");
// 保存id删除的时候用
timerId.value = setInterval(async () => {
const res = await getDsnList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize });
tableData.value = res.data.list[0].dishes;
}, 5000);
} else {
ElMessage.success("停止刷新");
getData();
}
};
onMounted(async () => {
// 进入页面时先删除定时器
if (timerId.value !== null) {
// 进入页面时先删除定时器
if (timerId.value !== null) {
clearInterval(timerId.value);
}
statusMode.value = false
// 先获取一次
getData()
})
statusMode.value = false;
// 先获取一次
getData();
});
</script>
<style scoped lang="scss">
// 调整表单项间距
.detailForm {
.el-dialog-title {
font-size: 180px;
}
.el-dialog-title {
font-size: 180px;
}
.el-form-item {
margin-bottom: 30px !important;
}
.el-form-item {
margin-bottom: 30px !important;
}
}
/* 工具栏样式 */
.toolbarStyle {
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
/* 表格样式 */
.formStyle {
display: flex;
justify-content: space-around;
padding: 3px;
margin-top: 1%;
display: flex;
justify-content: space-around;
padding: 3px;
margin-top: 1%;
}
/* 文字样式 */
.el-text {
color: #FFFFFF;
color: #ffffff;
}
.title {
color: #4edaff;
font-size: 18px;
font-weight: 500;
}
.info-item {
display: flex;
align-items: center;
margin: 10px 0;
justify-content: space-between;
}
.item-title {
color: #b0dfff;
}
.item {
color: #eee;
}
.table-content {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(8px);
border: 1px solid rgba(78, 237, 255, 0.2);
box-shadow: 0 0 15px rgba(78, 237, 255, 0.1);
border-radius: 8px;
padding: 10px !important;
}
</style>
<style>
.el-input {
--el-input-text-color: #FFFFFF;
--el-input-text-color: #ffffff;
}
/* 修改el选择器的样式 */
.el-select__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 删除el选择器选中时的边框 */
.is-hovering {
box-shadow: none !important;
box-shadow: none !important;
}
/* 修改el输入框的样式 */
.el-input__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 修改el下拉框的背景颜色 */
.el-select-dropdown {
background-color: #1d5484;
background-color: #1d5484;
}
/* 修改el下拉框选项的字体颜色 */
.el-select-dropdown__item {
color: #FFFFFF;
color: #ffffff;
}
/* 修改el下拉框选项选中时的文字颜色 */
.el-select-dropdown__item:hover {
color: #409eff;
color: #409eff;
}
/* 修改el日期选择器的边框为none */
.el-date-editor {
--el-input-border-color: none
--el-input-border-color: none;
}
.el-button:focus {
outline: none;
outline: none;
}
</style>
\ No newline at end of file
.table-content {
padding: 0 10px;
}
</style>
<template>
<div class="text-left p-4 toolbarStyle">
<div class="formStyle">
<el-form inline>
<el-form-item>
<el-text class="mx-1">目标名称:</el-text>
</el-form-item>
<el-form-item>
<div>
<el-input placeholder="请输入" v-model="searchTargetName" style="width: 180px" />
</div>
</el-form-item>
<el-form-item>
<el-text class="mx-1">获取时间:</el-text>
</el-form-item>
<el-form-item>
<el-config-provider :locale="zhCn">
<el-date-picker type="datetimerange" format="YYYY-MM-DD HH:mm:ss" v-model="searchTimeValue"
start-placeholder="开始时间" style="width: 330px" end-placeholder="结束时间"
date-format="YYYY/MM/DD ddd" time-format="A hh:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" />
</el-config-provider>
</el-form-item>
<el-form-item>
<el-text class="mx-1">站点名称:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" v-model="searchStation" style="width: 170.5px" />
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button type="primary" @click="getData">重置表格</el-button>
</el-space>
</el-form-item>
</el-form>
<div class="text-left">
<table-search>
<div class="form-content">
<div class="left">
<div>
<span style="color: white">目标名称:</span>
<el-input placeholder="请输入目标名称:" v-model="searchTargetName" style="width: 180px" />
</div>
<div>
<span style="color: white">时间范围:</span>
<el-config-provider :locale="zhCn">
<el-date-picker
type="datetimerange"
format="YYYY-MM-DD HH:mm:ss"
v-model="searchTimeValue"
start-placeholder="开始时间"
style="width: 200px"
end-placeholder="结束时间"
date-format="YYYY/MM/DD ddd"
time-format="A hh:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-config-provider>
</div>
<div>
<span style="color: white">站点名称:</span>
<el-input placeholder="请输入" v-model="searchStation" style="width: 170.5px" />
</div>
</div>
</div>
<div class="m-t-5" />
<div>
<el-table :data="tableData" style="width: 100%" border :row-style="{ height: '45.5px' }"
:header-cell-style="{ textAlign: 'center' }" :cell-style="{ textAlign: 'center' }">
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="data.mission" label="目标名称" width="86" show-overflow-tooltip />
<el-table-column property="data.station" label="站点名称" width="88" show-overflow-tooltip />
<el-table-column property="data.distance" label="距离" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.data.distance === null ? '-' : scope.row.data.distance }}
</template>
</el-table-column>
<el-table-column property="data.roundTripLightTime" label="往返光时" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.data.roundTripLightTime === null ? '-' : scope.row.data.roundTripLightTime }}
</template>
</el-table-column>
<el-table-column property="data.boa" label="行动开始时间" show-overflow-tooltip>
<template #default="scope">
{{ formatTimestamp(scope.row.data.boa) }}
</template>
</el-table-column>
<el-table-column property="data.plan_txt" label="行动结束时间" show-overflow-tooltip>
<template #default="scope">
{{ formatTimestamp(scope.row.data.bot) }}
</template>
</el-table-column>
<el-table-column property="data.plan_txt" label="跟踪结束时间" show-overflow-tooltip>
<template #default="scope">
{{ formatTimestamp(scope.row.data.eoa) }}
</template>
</el-table-column>
<el-table-column property="data.plan_txt" label="跟踪开始时间" show-overflow-tooltip>
<template #default="scope">
{{ formatTimestamp(scope.row.data.eot) }}
</template>
</el-table-column>
<el-table-column label="目标在线状态" width="110" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.data.target?.[scope.row.data.mission] === 'true' ? '是' : '否' }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="85">
<template #default="scope">
<el-button link type="primary" size="small" @click="handleMissionDetails(scope.row.data.mission)">
目标信息
</el-button>
<el-button link type="primary" size="small"
@click="handleStationDetails(scope.row.data.station)">站点信息</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
@pagination="getData" />
<div class="btns">
<el-button plain type="primary" @click="handleSearch">查询</el-button>
<el-button plain @click="getData">重置表格</el-button>
</div>
</div>
</div>
</table-search>
</div>
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="765px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-8">
详情
</div>
</template>
<el-form label-width="155px" size="small" class="px-4">
<div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标名称:" label-position="left">
<el-input v-model="targetName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务类型:" label-position="left">
<el-input v-model="targetMissionType" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标运行轨道:" label-position="left">
<el-input v-model="targetOrbit" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="目标尺寸:" label-position="left">
<el-input v-model="targetDimension" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标发射质量:" label-position="left">
<el-input v-model="targetLaunchMass" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="目标干质量:" label-position="left">
<el-input v-model="targetDryMass" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="近地点:" label-position="left">
<el-input v-model="targetPerigee" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="远地点:" label-position="left">
<el-input v-model="targetApogee" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标功率:" label-position="left">
<el-input v-model="targetPower" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="轨道倾角:" label-position="left">
<el-input v-model="targetInclination" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="发射日期:" label-position="left">
<el-input v-model="targetLaunchDate" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="发射站点:" label-position="left">
<el-input v-model="targetLaunchLocation" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="轨道周期:" label-position="left">
<el-input v-model="targetPeriod" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="相关仪器:" label-position="left">
<el-input v-model="targetInstruments" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="服役日期:" label-position="left">
<el-input v-model="targetServiceDate" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否为核心任务:" label-position="left">
<el-input v-model="targetIsCoreMission" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="太阳风速:" label-position="left">
<el-input v-model="targetSolarWindSpeed" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="太阳通量密度:" label-position="left">
<el-input v-model="targetSolarFluxDensity" />
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否在仪表盘中显示:" label-position="left">
<el-input v-model="targetIsShowInDashboard" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型:" label-position="left">
<el-input v-model="targetType" />
</el-form-item>
</el-col>
</el-row> -->
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="描述:" label-position="left">
<el-input v-model="targetDescription" type="textarea" :rows="3" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</el-dialog>
<div class="m-t-5" />
<div class="table-content">
<el-table
:data="tableData"
style="width: 100%"
border
:row-style="{ height: '45.5px' }"
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
v-loading="tableData.length == 0"
element-loading-background="rgba(48, 65, 86, 0.7)"
>
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="data.mission" label="目标名称" width="86" show-overflow-tooltip />
<el-table-column property="data.station" label="站点名称" width="88" show-overflow-tooltip />
<el-table-column property="data.distance" label="距离" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.data.distance === null ? "-" : scope.row.data.distance }}
</template>
</el-table-column>
<el-table-column property="data.roundTripLightTime" label="往返光时" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.data.roundTripLightTime === null ? "-" : scope.row.data.roundTripLightTime }}
</template>
</el-table-column>
<el-table-column property="data.boa" label="行动开始时间" show-overflow-tooltip>
<template #default="scope">
{{ formatTimestamp(scope.row.data.boa) }}
</template>
</el-table-column>
<el-table-column property="data.plan_txt" label="行动结束时间" show-overflow-tooltip>
<template #default="scope">
{{ formatTimestamp(scope.row.data.bot) }}
</template>
</el-table-column>
<el-table-column property="data.plan_txt" label="跟踪结束时间" show-overflow-tooltip>
<template #default="scope">
{{ formatTimestamp(scope.row.data.eoa) }}
</template>
</el-table-column>
<el-table-column property="data.plan_txt" label="跟踪开始时间" show-overflow-tooltip>
<template #default="scope">
{{ formatTimestamp(scope.row.data.eot) }}
</template>
</el-table-column>
<el-table-column label="目标在线状态" width="110" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.data.target?.[scope.row.data.mission] === "true" ? "是" : "否" }}
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" min-width="85">
<template #default="scope">
<div class="btns">
<el-button link type="primary" size="small" @click="handleMissionDetails(scope.row.data.mission)">
目标信息
</el-button>
<el-button link type="primary" size="small" @click="handleStationDetails(scope.row.data.station)"
>站点信息</el-button
>
</div>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination
:total="pageObj.total"
v-model:page="pageObj.pageNo"
v-model:limit="pageObj.pageSize"
@pagination="getData"
/>
</div>
</div>
<div class="detailForm">
<el-dialog v-model="stationVisibleValue" center width="880px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-8">
详情
</div>
</template>
<el-form label-width="196px" size="small" class="px-4">
<div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="站点名称:" label-position="left">
<el-input v-model="stationName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所在国家:" label-position="left">
<el-input v-model="stationCountry" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="站点经度:" label-position="left">
<el-input v-model="stationLongitude" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="站点纬度:" label-position="left">
<el-input v-model="stationLatitude" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="站点海拔:" label-position="left">
<el-input v-model="stationAltitude" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="站点直径:" label-position="left">
<el-input v-model="stationDiameter" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="天线方位角速度:" label-position="left">
<el-input v-model="stationAzimuthSpeed" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="天线俯仰角速度:" label-position="left">
<el-input v-model="stationElevationSpeed" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="信号频段:" label-position="left">
<el-input v-model="stationBand" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="TMTC标准:" label-position="left">
<el-input v-model="stationTMTC" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="信号频率与定时:" label-position="left">
<el-input v-model="stationFrequencyAndTiming" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="站点天气情况:" label-position="left">
<el-input v-model="stationWeather" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号S频段极化:" label-position="left">
<el-input v-model="stationUplinkSPolarization" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上行信号S频段等效全向辐射功率:" label-position="left">
<el-input v-model="stationUplinkSEirp" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号X频段极化:" label-position="left">
<el-input v-model="stationUplinkXPolarization" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上行信号X频段等效全向辐射功率:" label-position="left">
<el-input v-model="stationUplinkXEirp" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="上行信号Ka频段极化:" label-position="left">
<el-input v-model="stationUplinkKaPolarization" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上行信号Ka频段等效全向辐射功率:" label-position="left">
<el-input v-model="stationUplinkKaEirp" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行信号S频段极化:" label-position="left">
<el-input v-model="stationDownlinkSPolarization" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下行信号S频段G/T比:" label-position="left">
<el-input v-model="stationDownlinkSGt" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行信号X频段极化:" label-position="left">
<el-input v-model="stationDownlinkXPolarization" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下行信号X频段G/T比:" label-position="left">
<el-input v-model="stationDownlinkXGt" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="下行信号Ka频段极化:" label-position="left">
<el-input v-model="stationDownlinkKaPolarization" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下行信号Ka频段G/T比:" label-position="left">
<el-input v-model="stationDownlinkKaGt" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="站点温度:" label-position="left">
<el-input v-model="stationTemperature" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="站点气压:" label-position="left">
<el-input v-model="stationPressure" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="站点湿度:" label-position="left">
<el-input v-model="stationHumidity" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="站点类型:" label-position="left">
<el-input v-model="stationType" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="描述:" label-position="left">
<el-input v-model="stationDescription" type="textarea" :rows="3" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</el-dialog>
</div>
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="765px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-6">目标详情-{{ targetName }}</div>
</template>
<el-row>
<el-col>
<el-card>
<div class="title">目标信息:</div>
<el-divider style="margin: 0"></el-divider>
<el-row :gutter="50" style="display: flex; justify-content: space-between">
<el-col :span="12">
<div class="info-item">
<span class="item-title">目标名称:</span>
<span class="item">{{ targetName }}</span>
</div>
<div class="info-item">
<span class="item-title">任务类型:</span>
<span class="item">{{ targetMissionType }}</span>
</div>
<div class="info-item">
<span class="item-title">运行轨道:</span>
<span class="item">{{ targetOrbit }}</span>
</div>
<div class="info-item">
<span class="item-title">目标尺寸:</span>
<span class="item">{{ targetDimension ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">发射质量:</span>
<span class="item">{{ targetLaunchMass ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">干质量:</span>
<span class="item">{{ targetDryMass }}</span>
</div>
<div class="info-item">
<span class="item-title">近地点:</span>
<span class="item">{{ targetPerigee }}</span>
</div>
<div class="info-item">
<span class="item-title">远地点:</span>
<span class="item">{{ targetApogee }}</span>
</div>
<div class="info-item">
<span class="item-title">目标功率:</span>
<span class="item">{{ targetPower }}</span>
</div>
</el-col>
<el-col :span="12">
<div class="info-item">
<span class="item-title">发射日期::</span>
<span class="item">{{ targetLaunchDate }}</span>
</div>
<div class="info-item">
<span class="item-title">发射站点:</span>
<span class="item">{{ targetLaunchLocation ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">轨道周期:</span>
<span class="item">{{ targetPeriod }}</span>
</div>
<div class="info-item">
<span class="item-title">相关仪器:</span>
<span class="item">{{ targetInstruments ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">服役日期:</span>
<span class="item">{{ targetServiceDate ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">是否为核心任务:</span>
<span class="item">{{ targetIsCoreMission ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">太阳风速:</span>
<span class="item">{{ targetSolarWindSpeed ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">太阳通量密度:</span>
<span class="item">{{ targetSolarFluxDensity ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">轨道倾角:</span>
<span class="item">{{ targetInclination }}</span>
</div>
</el-col>
</el-row>
<div class="title">描述信息:</div>
<el-divider style="margin: 0"></el-divider>
<p class="target-desc">{{ targetDescription }}</p>
</el-card>
</el-col>
</el-row>
</el-dialog>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" />
<div class="detailForm">
<el-dialog v-model="stationVisibleValue" center width="880px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-6">站点详情-{{ stationName }}</div>
</template>
<el-row>
<el-col>
<el-card>
<div class="title">站点信息:</div>
<el-divider style="margin: 0"></el-divider>
<el-row :gutter="50" style="display: flex; justify-content: space-between">
<el-col :span="12">
<div class="info-item">
<span class="item-title">站点名称:</span>
<span class="item">{{ stationName }}</span>
</div>
<div class="info-item">
<span class="item-title">所在国家:</span>
<span class="item">{{ stationCountry }}</span>
</div>
<div class="info-item">
<span class="item-title">站点经度:</span>
<span class="item">{{ stationLongitude }}</span>
</div>
<div class="info-item">
<span class="item-title">站点纬度:</span>
<span class="item">{{ stationLatitude }}</span>
</div>
<div class="info-item">
<span class="item-title">站点海拔:</span>
<span class="item">{{ stationAltitude }}</span>
</div>
<div class="info-item">
<span class="item-title">站点直径:</span>
<span class="item">{{ stationDiameter }}</span>
</div>
<div class="info-item">
<span class="item-title">天线方位角速度:</span>
<span class="item">{{ stationAzimuthSpeed }}</span>
</div>
<div class="info-item">
<span class="item-title">天线俯仰角速度:</span>
<span class="item">{{ stationElevationSpeed }}</span>
</div>
<div class="info-item">
<span class="item-title">信号频段:</span>
<span class="item">{{ stationBand }}</span>
</div>
<div class="info-item">
<span class="item-title">TMTC标准:</span>
<span class="item">{{ stationTMTC }}</span>
</div>
<div class="info-item">
<span class="item-title">信号频率与定时:</span>
<span class="item">{{ stationFrequencyAndTiming }}</span>
</div>
<div class="info-item">
<span class="item-title">站点类型:</span>
<span class="item">{{ stationType }}</span>
</div>
<div class="info-item">
<span class="item-title">站点气压:</span>
<span class="item">{{ stationPressure === "" ? "-" : stationPressure }}</span>
</div>
<div class="info-item">
<span class="item-title">站点天气情况:</span>
<span class="item">{{ stationWeather }}</span>
</div>
</el-col>
<el-col :span="12">
<div class="info-item">
<span class="item-title">上行信号S频段极化:</span>
<span class="item">{{ stationUplinkSPolarization }}</span>
</div>
<div class="info-item">
<span class="item-title">上行信号S频段等效全向辐射功率:</span>
<span class="item">{{ stationUplinkSPolarization }}</span>
</div>
<div class="info-item">
<span class="item-title">上行信号X频段极化:</span>
<span class="item">{{ stationUplinkXPolarization }}</span>
</div>
<div class="info-item">
<span class="item-title">上行信号X频段等效全向辐射功率:</span>
<span class="item">{{ stationUplinkXEirp }}</span>
</div>
<div class="info-item">
<span class="item-title">上行信号Ka频段极化:</span>
<span class="item">{{ stationUplinkKaPolarization }}</span>
</div>
<div class="info-item">
<span class="item-title">上行信号Ka频段等效全向辐射功率:</span>
<span class="item">{{ stationUplinkKaEirp }}</span>
</div>
<div class="info-item">
<span class="item-title">下行信号S频段极化:</span>
<span class="item">{{ stationDownlinkSPolarization }}</span>
</div>
<div class="info-item">
<span class="item-title">下行信号S频段G/T比:</span>
<span class="item">{{ stationDownlinkSGt }}</span>
</div>
<div class="info-item">
<span class="item-title">下行信号X频段极化:</span>
<span class="item">{{ stationDownlinkXPolarization }}</span>
</div>
<div class="info-item">
<span class="item-title">下行信号X频段G/T比:</span>
<span class="item">{{ stationDownlinkXGt }}</span>
</div>
<div class="info-item">
<span class="item-title">下行信号Ka频段极化:</span>
<span class="item">{{ stationDownlinkKaPolarization }}</span>
</div>
<div class="info-item">
<span class="item-title">下行信号Ka频段G/T比:</span>
<span class="item">{{ stationDownlinkKaGt }}</span>
</div>
<div class="info-item">
<span class="item-title">站点温度:</span>
<span class="item">{{ stationTemperature === "" ? "-" : stationTemperature }}</span>
</div>
<div class="info-item">
<span class="item-title">站点湿度:</span>
<span class="item">{{ stationHumidity === "" ? "-" : stationHumidity }}</span>
</div>
</el-col>
</el-row>
<div class="title">描述信息:</div>
<el-divider style="margin: 0"></el-divider>
<p class="target-desc">{{ stationDescription }}</p>
</el-card>
</el-col>
</el-row>
</el-dialog>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" />
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import exportDialog from '@/components/Export/index.vue'
import { getESAList, getESAMissionDetail, getESAStationDetail } from '@/api/spiderData'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from "vue";
import Pagination from "@/components/pagination/index.vue";
import exportDialog from "@/components/Export/index.vue";
import { getESAList, getESAMissionDetail, getESAStationDetail } from "@/api/spiderData";
import { ElMessage } from "element-plus";
// ElConfigProvider 组件
import { ElConfigProvider } from 'element-plus';
import { ElConfigProvider } from "element-plus";
// 引入中文包
import zhCn from 'element-plus/es/locale/lang/zh-cn';
defineOptions({ name: 'Pagination' })
import zhCn from "element-plus/es/locale/lang/zh-cn";
import TableSearch from "@/components/TableSearch.vue";
defineOptions({ name: "Pagination" });
// 更改分页文字
zhCn.el.pagination.total = '共 `{total} 条`';
zhCn.el.pagination.goto = '跳至';
zhCn.el.pagination.pagesize = '条/页';
zhCn.el.pagination.pageClassifier = '页';
zhCn.el.pagination.total = "共 `{total} 条`";
zhCn.el.pagination.goto = "跳至";
zhCn.el.pagination.pagesize = "条/页";
zhCn.el.pagination.pageClassifier = "页";
// 查找字段
const searchTargetName = ref('')
const searchTimeValue = ref('')
const searchStation = ref('')
const showDeleteDialog = ref(false)
const detailVisibleValue = ref(false)
const stationVisibleValue = ref(false)
const searchTargetName = ref("");
const searchTimeValue = ref("");
const searchStation = ref("");
const showDeleteDialog = ref(false);
const detailVisibleValue = ref(false);
const stationVisibleValue = ref(false);
// 目标详情信息
const targetName = ref('')
const targetName = ref("");
// 任务类型
const targetMissionType = ref('')
const targetMissionType = ref("");
// 目标运行轨道
const targetOrbit = ref('')
const targetOrbit = ref("");
// 目标尺寸
const targetDimension = ref('')
const targetDimension = ref("");
// 目标发射质量
const targetLaunchMass = ref('')
const targetLaunchMass = ref("");
// 目标干质量
const targetDryMass = ref('')
const targetDryMass = ref("");
// 近地点
const targetPerigee = ref('')
const targetPerigee = ref("");
// 远地点
const targetApogee = ref('')
const targetApogee = ref("");
// 目标功率
const targetPower = ref('')
const targetPower = ref("");
// 轨道倾角
const targetInclination = ref('')
const targetInclination = ref("");
// 轨道周期
const targetPeriod = ref('')
const targetPeriod = ref("");
// 发射日期
const targetLaunchDate = ref('')
const targetLaunchDate = ref("");
// 发射站点
const targetLaunchLocation = ref('')
const targetLaunchLocation = ref("");
// 相关仪器
const targetInstruments = ref('')
const targetInstruments = ref("");
// 服役日期
const targetServiceDate = ref('')
const targetServiceDate = ref("");
// 是否为核心任务
const targetIsCoreMission = ref('')
const targetIsCoreMission = ref("");
// 太阳风速
const targetSolarWindSpeed = ref('')
const targetSolarWindSpeed = ref("");
// 太阳通量密度
const targetSolarFluxDensity = ref('')
const targetSolarFluxDensity = ref("");
// 是否在仪表盘中显示
// const targetIsShowInDashboard = ref('')
// 目标类型
const targetType = ref('')
const targetType = ref("");
// 描述
const targetDescription = ref('')
const targetDescription = ref("");
// 站点详情信息
// 站点名称
const stationName = ref('')
const stationName = ref("");
// 站点所在国家
const stationCountry = ref('')
const stationCountry = ref("");
// 站点经度
const stationLongitude = ref('')
const stationLongitude = ref("");
// 站点纬度
const stationLatitude = ref('')
const stationLatitude = ref("");
// 站点海拔高度
const stationAltitude = ref('')
const stationAltitude = ref("");
// 站点直径
const stationDiameter = ref('')
const stationDiameter = ref("");
// 天线方位角速度
const stationAzimuthSpeed = ref('')
const stationAzimuthSpeed = ref("");
// 天线俯仰角速度
const stationElevationSpeed = ref('')
const stationElevationSpeed = ref("");
// 天线信号频段
const stationBand = ref('')
const stationBand = ref("");
// TMTC标准
const stationTMTC = ref('')
const stationTMTC = ref("");
// 信号频率与定时
const stationFrequencyAndTiming = ref('')
const stationFrequencyAndTiming = ref("");
// 天气
const stationWeather = ref('')
const stationWeather = ref("");
// 上行信号S频段极化
const stationUplinkSPolarization = ref('')
const stationUplinkSPolarization = ref("");
// 上行信号S频段等效全向辐射功率
const stationUplinkSEirp = ref('')
const stationUplinkSEirp = ref("");
// 上行信号X频段极化
const stationUplinkXPolarization = ref('')
const stationUplinkXPolarization = ref("");
// 上行信号X频段等效全向辐射功率
const stationUplinkXEirp = ref('')
const stationUplinkXEirp = ref("");
// 上行信号Ka频段极化
const stationUplinkKaPolarization = ref('')
const stationUplinkKaPolarization = ref("");
// 上行信号Ka频段等效全向辐射功率
const stationUplinkKaEirp = ref('')
const stationUplinkKaEirp = ref("");
// 下行信号S频段极化
const stationDownlinkSPolarization = ref('')
const stationDownlinkSPolarization = ref("");
// 下行信号S频段G/T比
const stationDownlinkSGt = ref('')
const stationDownlinkSGt = ref("");
// 下行信号X频段极化
const stationDownlinkXPolarization = ref('')
const stationDownlinkXPolarization = ref("");
// 下行信号X频段G/T比
const stationDownlinkXGt = ref('')
const stationDownlinkXGt = ref("");
// 下行信号Ka频段极化
const stationDownlinkKaPolarization = ref('')
const stationDownlinkKaPolarization = ref("");
// 下行信号Ka频段G/T比
const stationDownlinkKaGt = ref('')
const stationDownlinkKaGt = ref("");
// 温度
const stationTemperature = ref('')
const stationTemperature = ref("");
// 气压
const stationPressure = ref('')
const stationPressure = ref("");
// 湿度
const stationHumidity = ref('')
const stationHumidity = ref("");
// 站点类型
const stationType = ref('')
const stationType = ref("");
// 描述
const stationDescription = ref('')
const stationDescription = ref("");
// 查看esa站点详情的方法
const handleStationDetails = async (id: any) => {
const res = await getESAStationDetail({ name: id })
// 防止残留数据
stationDescription.value = ''
// 字段赋值
stationName.value = res.data.data[0].name
stationCountry.value = res.data.data[0].country
stationLongitude.value = res.data.data[0].longitude
stationLatitude.value = res.data.data[0].latitude
stationAltitude.value = res.data.data[0].altitude
stationDiameter.value = res.data.data[0].diameter
stationAzimuthSpeed.value = res.data.data[0].antennaSpeedAzimuth
stationElevationSpeed.value = res.data.data[0].antennaSpeedElevation
stationBand.value = res.data.data[0].band
stationTMTC.value = res.data.data[0].tmtcStandards
stationFrequencyAndTiming.value = res.data.data[0].frequencyAndTiming
stationWeather.value = res.data.data[0].weather === null ? '无' : res.data.data[0].weather
stationUplinkSPolarization.value = res.data.data[0].uplinkSBandPolarization === null ? '无' : res.data.data[0].uplinkSBandPolarization
stationUplinkSEirp.value = res.data.data[0].uplinkSBandEirp === null ? '无' : res.data.data[0].uplinkSBandEirp
stationUplinkXPolarization.value = res.data.data[0].uplinkXBandPolarization === null ? '无' : res.data.data[0].uplinkXBandPolarization
stationUplinkXEirp.value = res.data.data[0].uplinkXBandEirp === null ? '无' : res.data.data[0].uplinkXBandEirp
stationUplinkKaPolarization.value = res.data.data[0].uplinkKaBandPolarization === null ? '无' : res.data.data[0].uplinkKaBandPolarization
stationUplinkKaEirp.value = res.data.data[0].uplinkKaBandEirp === null ? '无' : res.data.data[0].uplinkKaBandEirp
stationDownlinkSPolarization.value = res.data.data[0].downlinkSBandPolarization === null ? '无' : res.data.data[0].downlinkSBandPolarization
stationDownlinkSGt.value = res.data.data[0].downlinkSBandGT === null ? '无' : res.data.data[0].downlinkSBandGT
stationDownlinkXPolarization.value = res.data.data[0].downlinkXBandPolarization === null ? '无' : res.data.data[0].downlinkXBandPolarization
stationDownlinkXGt.value = res.data.data[0].downlinkXBandGT === null ? '无' : res.data.data[0].downlinkXBandGT
stationDownlinkKaPolarization.value = res.data.data[0].downlinkKaBandPolarization === null ? '无' : res.data.data[0].downlinkKaBandPolarization
stationDownlinkKaGt.value = res.data.data[0].downlinkKaBandGT === null ? '无' : res.data.data[0].downlinkKaBandGT
stationTemperature.value = res.data.data[0].temperature
stationPressure.value = res.data.data[0].airPressure
stationHumidity.value = res.data.data[0].humidity
stationType.value = res.data.data[0].type
for (let i = 0; i < res.data.data[0].description.length; i++) {
stationDescription.value += res.data.data[0].description[i]
try {
const res = await getESAStationDetail({ name: id });
// 1. 初始化清空数据
stationName.value = "";
stationCountry.value = "";
stationLongitude.value = "";
stationLatitude.value = "";
stationAltitude.value = "";
stationDiameter.value = "";
stationAzimuthSpeed.value = "";
stationElevationSpeed.value = "";
stationBand.value = "";
stationTMTC.value = "";
stationFrequencyAndTiming.value = "";
stationWeather.value = "";
stationUplinkSPolarization.value = "";
stationUplinkSEirp.value = "";
stationUplinkXPolarization.value = "";
stationUplinkXEirp.value = "";
stationUplinkKaPolarization.value = "";
stationUplinkKaEirp.value = "";
stationDownlinkSPolarization.value = "";
stationDownlinkSGt.value = "";
stationDownlinkXPolarization.value = "";
stationDownlinkXGt.value = "";
stationDownlinkKaPolarization.value = "";
stationDownlinkKaGt.value = "";
stationTemperature.value = "";
stationPressure.value = "";
stationHumidity.value = "";
stationType.value = "";
stationDescription.value = "";
// 2.判断 data 是否存在且非空
if (!res?.data?.data || res.data.data.length === 0) {
ElMessage.warning("未查询到该站点的详细信息");
return;
}
stationVisibleValue.value = true
}
const tableData = ref([])
// 3. 安全赋值
const stationData = res.data.data[0];
stationName.value = stationData.name || "";
stationCountry.value = stationData.country || "";
stationLongitude.value = stationData.longitude || "";
stationLatitude.value = stationData.latitude || "";
stationAltitude.value = stationData.altitude || "";
stationDiameter.value = stationData.diameter || "";
stationAzimuthSpeed.value = stationData.antennaSpeedAzimuth || "";
stationElevationSpeed.value = stationData.antennaSpeedElevation || "";
stationBand.value = stationData.band || "";
stationTMTC.value = stationData.tmtcStandards || "";
stationFrequencyAndTiming.value = stationData.frequencyAndTiming || "";
stationWeather.value = stationData.weather === null ? "-" : stationData.weather || "-";
stationUplinkSPolarization.value =
stationData.uplinkSBandPolarization === null ? "-" : stationData.uplinkSBandPolarization || "-";
stationUplinkSEirp.value = stationData.uplinkSBandEirp === null ? "-" : stationData.uplinkSBandEirp || "-";
stationUplinkXPolarization.value =
stationData.uplinkXBandPolarization === null ? "-" : stationData.uplinkXBandPolarization || "-";
stationUplinkXEirp.value = stationData.uplinkXBandEirp === null ? "-" : stationData.uplinkXBandEirp || "-";
stationUplinkKaPolarization.value =
stationData.uplinkKaBandPolarization === null ? "-" : stationData.uplinkKaBandPolarization || "-";
stationUplinkKaEirp.value = stationData.uplinkKaBandEirp === null ? "-" : stationData.uplinkKaBandEirp || "-";
stationDownlinkSPolarization.value =
stationData.downlinkSBandPolarization === null ? "-" : stationData.downlinkSBandPolarization || "-";
stationDownlinkSGt.value = stationData.downlinkSBandGT === null ? "-" : stationData.downlinkSBandGT || "-";
stationDownlinkXPolarization.value =
stationData.downlinkXBandPolarization === null ? "-" : stationData.downlinkXBandPolarization || "-";
stationDownlinkXGt.value = stationData.downlinkXBandGT === null ? "-" : stationData.downlinkXBandGT || "-";
stationDownlinkKaPolarization.value =
stationData.downlinkKaBandPolarization === null ? "-" : stationData.downlinkKaBandPolarization || "-";
stationDownlinkKaGt.value = stationData.downlinkKaBandGT === null ? "-" : stationData.downlinkKaBandGT || "-";
stationTemperature.value = stationData.temperature || "";
stationPressure.value = stationData.airPressure || "";
stationHumidity.value = stationData.humidity || "";
stationType.value = stationData.type || "";
// 处理描述信息(避免 description 为 undefined 时报错)
if (Array.isArray(stationData.description)) {
stationDescription.value = stationData.description.join("");
} else {
stationDescription.value = stationData.description || "-";
}
stationVisibleValue.value = true;
} catch (error) {
ElMessage.error("查询站点详情失败,请稍后重试");
console.error("站点详情查询错误:", error);
}
};
const tableData = ref([]);
const pageObj = ref({
total: 0,
pageSize: 10,
pageNo: 1
})
total: 0,
pageSize: 10,
pageNo: 1,
});
const formatTimestamp = (timestamp: any) => {
if (!timestamp || typeof timestamp !== 'number' || timestamp <= 0) {
return '-';
}
const msTimestamp = String(timestamp).length === 10 ? timestamp * 1000 : timestamp;
const date = new Date(msTimestamp);
if (isNaN(date.getTime())) {
return '-';
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
if (!timestamp || typeof timestamp !== "number" || timestamp <= 0) {
return "-";
}
const msTimestamp = String(timestamp).length === 10 ? timestamp * 1000 : timestamp;
const date = new Date(msTimestamp);
if (isNaN(date.getTime())) {
return "-";
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hour = String(date.getHours()).padStart(2, "0");
const minute = String(date.getMinutes()).padStart(2, "0");
const second = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
};
// 查看esa任务详情的方法
const handleMissionDetails = async (id: any) => {
const res = await getESAMissionDetail({ name: id })
// 防止残留数据
targetDescription.value = ''
// 字段赋值
targetName.value = res.data.data[0].name
targetMissionType.value = res.data.data[0].type
targetOrbit.value = res.data.data[0].orbitsAround
targetDimension.value = res.data.data[0].dimensions
targetLaunchMass.value = res.data.data[0].launchMass
targetDryMass.value = res.data.data[0].dryMass
targetPerigee.value = res.data.data[0].perigee
targetApogee.value = res.data.data[0].apogee
targetPower.value = res.data.data[0].power
targetInclination.value = res.data.data[0].inclination
targetLaunchDate.value = formatTimestamp(res.data.data[0].launchDate)
targetLaunchLocation.value = res.data.data[0].launchSite
targetPeriod.value = res.data.data[0].period
targetInstruments.value = res.data.data[0].instruments
targetServiceDate.value = formatTimestamp(res.data.data[0].enteredService)
targetIsCoreMission.value = res.data.data[0].coreMission
targetSolarWindSpeed.value = res.data.data[0].solarWindSpeed
targetSolarFluxDensity.value = res.data.data[0].solarFluxDensity
for (let i = 0; i < res.data.data[0].description.length; i++) {
targetDescription.value += res.data.data[0].description[i]
}
detailVisibleValue.value = true
}
const res = await getESAMissionDetail({ name: id });
// 防止残留数据
targetDescription.value = "";
// 字段赋值
targetName.value = res.data.data[0].name;
targetMissionType.value = res.data.data[0].type;
targetOrbit.value = res.data.data[0].orbitsAround;
targetDimension.value = res.data.data[0].dimensions;
targetLaunchMass.value = res.data.data[0].launchMass;
targetDryMass.value = res.data.data[0].dryMass;
targetPerigee.value = res.data.data[0].perigee;
targetApogee.value = res.data.data[0].apogee;
targetPower.value = res.data.data[0].power;
targetInclination.value = res.data.data[0].inclination;
targetLaunchDate.value = formatTimestamp(res.data.data[0].launchDate);
targetLaunchLocation.value = res.data.data[0].launchSite;
targetPeriod.value = res.data.data[0].period;
targetInstruments.value = res.data.data[0].instruments;
targetServiceDate.value = formatTimestamp(res.data.data[0].enteredService);
targetIsCoreMission.value = res.data.data[0].coreMission;
targetSolarWindSpeed.value = res.data.data[0].solarWindSpeed;
targetSolarFluxDensity.value = res.data.data[0].solarFluxDensity;
for (let i = 0; i < res.data.data[0].description.length; i++) {
targetDescription.value += res.data.data[0].description[i];
}
detailVisibleValue.value = true;
};
// 获取esa数据列表的方法
const getData = async () => {
searchStation.value = ''
searchTargetName.value = ''
searchTimeValue.value = ''
const res = await getESAList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize })
pageObj.value.total = res.data.total
tableData.value = res.data.list
}
searchStation.value = "";
searchTargetName.value = "";
searchTimeValue.value = "";
const res = await getESAList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize });
pageObj.value.total = res.data.total;
tableData.value = res.data.list;
};
const handleClose = () => {
detailVisibleValue.value = false
}
detailVisibleValue.value = false;
};
const handleSearch = async () => {
if (searchTargetName.value === '' && searchStation.value === '' && searchTimeValue.value === '') {
ElMessage.warning('请输入搜索内容')
return
}
const res = await getESAList({ spacecraft: searchTargetName.value, station: searchStation.value, times: searchTimeValue.value, page: pageObj.value.pageNo, size: pageObj.value.pageSize })
pageObj.value.total = res.data.total
tableData.value = res.data.list
}
if (searchTargetName.value === "" && searchStation.value === "" && searchTimeValue.value === "") {
ElMessage.warning("请输入搜索内容");
return;
}
const res = await getESAList({
spacecraft: searchTargetName.value,
station: searchStation.value,
times: searchTimeValue.value,
page: pageObj.value.pageNo,
size: pageObj.value.pageSize,
});
pageObj.value.total = res.data.total;
tableData.value = res.data.list;
};
onMounted(() => {
getData()
})
getData();
});
</script>
<style scoped lang="scss">
:deep(.el-form-item__label) {
color: white;
}
// 调整表单项间距
.detailForm {
.el-dialog-title {
font-size: 180px;
}
.el-dialog-title {
font-size: 180px;
}
.el-form-item {
margin-bottom: 20px !important;
}
.el-form-item {
margin-bottom: 20px !important;
}
}
/* 工具栏样式 */
.toolbarStyle {
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
/* 表格样式 */
.formStyle {
display: flex;
justify-content: space-around;
padding: 3px;
margin-top: 1%;
display: flex;
justify-content: space-around;
padding: 3px;
margin-top: 1%;
}
.title {
color: #4edaff;
font-size: 18px;
font-weight: 500;
}
.info-item {
display: flex;
align-items: center;
margin: 10px 0;
justify-content: space-between;
}
.item-title {
color: #b0dfff;
}
.item {
color: #eee;
}
/* 文字样式 */
.el-text {
color: #FFFFFF;
color: #ffffff;
}
.target-desc {
color: #d0e8ff;
}
.btns {
display: flex;
justify-content: center;
}
.form-content {
display: flex;
height: 80px;
align-items: center;
padding: 0 30px;
justify-content: space-between;
}
.left {
display: flex;
gap: 10px;
}
.table-content {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(8px);
border: 1px solid rgba(78, 237, 255, 0.2);
box-shadow: 0 0 15px rgba(78, 237, 255, 0.1);
border-radius: 8px;
padding: 10px !important;
}
</style>
<style>
.el-input {
--el-input-text-color: #FFFFFF;
--el-input-text-color: #ffffff;
}
/* 修改el选择器的样式 */
.el-select__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 删除el选择器选中时的边框 */
.is-hovering {
box-shadow: none !important;
box-shadow: none !important;
}
/* 修改el输入框的样式 */
.el-input__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 修改el下拉框的背景颜色 */
.el-select-dropdown {
background-color: #1d5484;
background-color: #1d5484;
}
/* 修改el下拉框选项的字体颜色 */
.el-select-dropdown__item {
color: #FFFFFF;
color: #ffffff;
}
/* 修改el下拉框选项选中时的文字颜色 */
.el-select-dropdown__item:hover {
color: #409eff;
color: #409eff;
}
/* 修改el日期选择器的边框为none */
.el-date-editor {
--el-input-border-color: none
--el-input-border-color: none;
}
.el-button:focus {
outline: none;
outline: none;
}
</style>
\ No newline at end of file
.table-content {
padding: 0 10px;
}
</style>
<template>
<div class="text-left p-4 toolbarStyle">
<div class="formStyle">
<el-form inline>
<el-form-item>
<el-text class="mx-1">目标名称:</el-text>
</el-form-item>
<el-form-item>
<div>
<el-input placeholder="请输入" v-model="searchTargetName" style="width: 180px" />
</div>
</el-form-item>
<el-form-item>
<el-text class="mx-1">获取时间:</el-text>
</el-form-item>
<el-form-item>
<el-config-provider :locale="zhCn">
<el-date-picker type="datetimerange" format="YYYY-MM-DD HH:mm:ss" v-model="searchTimeValue"
start-placeholder="开始时间" style="width: 330px" end-placeholder="结束时间"
date-format="YYYY/MM/DD ddd" time-format="A hh:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" />
</el-config-provider>
</el-form-item>
<el-form-item>
<el-text class="mx-1">SNS Notice ID:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" v-model="searchTargetId" style="width: 170.5px" />
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button type="primary" @click="getData">重置表格</el-button>
</el-space>
</el-form-item>
</el-form>
</div>
</div>
<div class="text-left">
<TableSearch>
<div class="form-content">
<div class="left">
<div>
<span style="color: white">目标名称:</span>
<el-input placeholder="请输入目标名称" v-model="searchTargetName" style="width: 180px" />
</div>
<div>
<span style="color: white">时间范围:</span>
<el-config-provider :locale="zhCn">
<el-date-picker
type="datetimerange"
format="YYYY-MM-DD HH:mm:ss"
v-model="searchTimeValue"
start-placeholder="开始时间"
style="width: 200px"
end-placeholder="结束时间"
date-format="YYYY/MM/DD ddd"
time-format="A hh:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-config-provider>
</div>
<div>
<span style="color: white">SNS Notice ID:</span>
<el-input placeholder="请输入ID" v-model="searchTargetId" style="width: 170.5px" />
</div>
</div>
<div class="btns">
<el-button plain type="primary" @click="handleSearch">查询</el-button>
<el-button plain="" @click="getData">重置</el-button>
</div>
</div>
</TableSearch>
</div>
<div class="m-t-5" />
<div>
<el-table :data="tableData" style="width: 100%" border :row-style="{ height: '45px' }"
:header-cell-style="{ textAlign: 'center' }" :cell-style="{ textAlign: 'center' }">
<!-- <el-table-column type="selection" width="40" /> -->
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="item.ntc_id" label="SNS Notice ID" show-overflow-tooltip />
<el-table-column property="identity.adm_name_e" label="主管部门" show-overflow-tooltip />
<el-table-column property="identity.sat_name" label="目标名称" show-overflow-tooltip />
<el-table-column property="item.plan_txt" label="计划/非计划类型" show-overflow-tooltip />
<el-table-column property="identity.ntc_type" label="是否为同步" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.identity.ntc_type === 'G' ? '是' : '否' }}
</template>
</el-table-column>
<el-table-column property="identity.long_nom" label="同步位置" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.identity.long_nom === null ? '-' : scope.row.identity.long_nom }}
</template>
</el-table-column>
<!-- <el-table-column property="item.minPerigee" label="近地点" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.item.minPerigee === null ? '-' : scope.row.item.minPerigee }}
</template>
</el-table-column>
<el-table-column property="item.maxApog" label="远地点" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.item.maxApog === null ? '-' : scope.row.identity.maxApog }}
</template>
</el-table-column>
<el-table-column property="item.minAltitude" label="最低海拔" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.item.minAltitude === null ? '-' : scope.row.item.minAltitude }}
</template>
</el-table-column>
<el-table-column property="item.ref_body" label="参考主体" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.item.ref_body === null ? '-' : scope.row.item.ref_body }}
</template>
</el-table-column> -->
<el-table-column property="item.freq_min" label="最低频率" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.item.freq_min === null ? '-' : scope.row.item.freq_min }}
</template>
</el-table-column>
<el-table-column property="item.freq_max" label="最高频率" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.item.freq_max === null ? '-' : scope.row.item.freq_max }}
</template>
</el-table-column>
<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.d_reg_limit" label="最早使用日期" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.regulatory_status.d_reg_limit === null ? '-' : scope.row.regulatory_status.d_reg_limit
}}
</template>
</el-table-column>
<el-table-column property="regulatory_status.f_biu_grps" label="是否确认使用" show-overflow-tooltip />
<el-table-column property="regulatory_status.resumption_list" label="是否暂停使用" show-overflow-tooltip />
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="primary" plain link @click="handleDetails(scope.row)">
详情
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
@pagination="getData" />
</div>
</div>
<div class="m-t-5" />
<div class="itu-table">
<el-table
:data="tableData"
style="width: 100%"
border
:row-style="{ height: '45px' }"
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
v-loading="tableData.length == 0"
element-loading-background="rgba(48, 65, 86, 0.7)"
>
<!-- <el-table-column type="selection" width="40" /> -->
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="item.ntc_id" label="SNS Notice ID" show-overflow-tooltip />
<el-table-column min-width="100" property="identity.adm_name_e" label="主管部门" show-overflow-tooltip />
<el-table-column property="identity.sat_name" label="目标名称" show-overflow-tooltip />
<el-table-column property="item.plan_txt" label="计划/非计划类型" show-overflow-tooltip />
<el-table-column property="identity.ntc_type" label="是否为同步" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.identity.ntc_type === "G" ? "是" : "否" }}
</template>
</el-table-column>
<el-table-column property="identity.long_nom" label="同步位置" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.identity.long_nom === null ? "-" : scope.row.identity.long_nom }}
</template>
</el-table-column>
<el-table-column property="item.freq_min" label="最低频率" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.item.freq_min === null ? "-" : scope.row.item.freq_min }}
</template>
</el-table-column>
<el-table-column property="item.freq_max" label="最高频率" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.item.freq_max === null ? "-" : scope.row.item.freq_max }}
</template>
</el-table-column>
<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.d_reg_limit" label="最早使用日期" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.regulatory_status.d_reg_limit === null ? "-" : scope.row.regulatory_status.d_reg_limit }}
</template>
</el-table-column>
<el-table-column
min-width="100"
property="regulatory_status.f_biu_grps"
label="是否确认使用"
show-overflow-tooltip
/>
<el-table-column property="regulatory_status.resumption_list" label="是否暂停使用" show-overflow-tooltip />
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="primary" plain link @click="handleDetails(scope.row)"> 详情 </el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination
:total="pageObj.total"
v-model:page="pageObj.pageNo"
v-model:limit="pageObj.pageSize"
@pagination="getData"
/>
</div>
</div>
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="765px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-8">
详情
</div>
</template>
<el-form label-width="155px" size="small" class="px-4">
<div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="SNS Notice ID:" label-position="left">
<el-input v-model="snsId" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="主管部门:" label-position="left">
<el-input v-model="department" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="目标名称:" label-position="left">
<el-input v-model="targetName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="计划/非计划类型:" label-position="left">
<el-input v-model="planType" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否为同步:" label-position="left">
<el-input v-model="syncType" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="同步位置:" label-position="left">
<el-input v-model="syncPosition" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="近地点:" label-position="left">
<el-input v-model="perigee" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="远地点:" label-position="left">
<el-input v-model="apogee" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最低海拔:" label-position="left">
<el-input v-model="lowestAltitude" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="参考主体:" label-position="left">
<el-input v-model="referenceSubject" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最低频率:" label-position="left">
<el-input v-model="lowestFrequency" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最高频率:" label-position="left">
<el-input v-model="highestFrequency" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="状态:" label-position="left">
<el-input v-model="status" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="有效期:" label-position="left">
<el-input v-model="validityPeriod" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="最早使用日期:" label-position="left">
<el-input v-model="earliestUsageDate" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否确认使用:" label-position="left">
<el-input v-model="isUsed" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否暂停使用:" label-position="left">
<el-input v-model="isPauseUsed" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="记录时间:" label-position="left">
<el-input v-model="recordTime" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否纳入国际频率总表:" label-position="left">
<el-input v-model="IsInTheInternationalFrequencyList" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最早监管日期:" label-position="left">
<el-input v-model="earliestRegulatoryDate" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否恢复使用:" label-position="left">
<el-input v-model="isRestoreUsed" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最新相关 BR IFIC 发布日期:" label-position="left">
<el-input v-model="BFIFICdate" />
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="20">
<el-col :span="24">
<el-form-item label="最新相关 BR IFIC 发布日期:" label-position="top">
<el-input v-model="BRIFICdate" />
</el-form-item>
</el-col>
</el-row> -->
</div>
</el-form>
</el-dialog>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" />
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="765px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-6">详情-{{ targetName }}</div>
</template>
<el-row>
<el-col :span="12">
<el-card>
<div class="title">身份信息:</div>
<el-divider style="margin: 0"></el-divider>
<div class="info-item">
<span class="item-title">卫星网络名称:</span>
<span class="item">{{ targetName }}</span>
</div>
<div class="info-item">
<span class="item-title">主管部门:</span>
<span class="item">{{ department }}({{ departmentDetail }})</span>
</div>
<div class="info-item">
<span class="item-title">网络组织:</span>
<span class="item">{{ ntwkOrg ?? "-" }}</span>
</div>
<div class="info-item">
<span class="item-title">计划/非计划类型:</span>
<span class="item">{{ planType }}</span>
</div>
<div class="info-item">
<span class="item-title">卫星网络类型:</span>
<span class="item">{{ ntwkType }}</span>
</div>
</el-card>
<el-card>
<div class="title">监管状态跟踪:</div>
<el-divider style="margin: 0"></el-divider>
<div class="info-item">
<span class="item-title">状态:</span>
<span class="item">{{ status }}</span>
</div>
<div class="info-item">
<span class="item-title">是否纳入国际频率总表:</span>
<span class="item">{{ IsInTheInternationalFrequencyList }}</span>
</div>
<div class="info-item">
<span class="item-title">有效期:</span>
<span class="item">{{ validityPeriod }} 年</span>
</div>
<div class="info-item">
<span class="item-title">是否确认使用:</span>
<span class="item">{{ isUsed }}</span>
</div>
<div class="info-item">
<span class="item-title">是否暂停使用:</span>
<span class="item">{{ isPauseUsed }}</span>
</div>
<div class="info-item">
<span class="item-title">最早监管日期:</span>
<span class="item">{{ earliestRegulatoryDate }}</span>
</div>
</el-card>
</el-col>
<el-col :span="12">
<el-card>
<div class="title">特征信息:</div>
<el-divider style="margin: 0"></el-divider>
<div class="info-item">
<span class="item-title">近地点:</span>
<span class="item">{{ perigee }}</span>
</div>
<div class="info-item">
<span class="item-title">远地点:</span>
<span class="item">{{ apogee }}</span>
</div>
<div class="info-item">
<span class="item-title">最低频率:</span>
<span class="item">{{ lowestFrequency }}</span>
</div>
<div class="info-item">
<span class="item-title">最高频率:</span>
<span class="item">{{ highestFrequency }}</span>
</div>
<div class="info-item">
<span class="item-title">最低海拔:</span>
<span class="item">{{ lowestAltitude }}</span>
</div>
</el-card>
<el-card>
<div class="title">其他信息:</div>
<el-divider style="margin: 0"></el-divider>
<div class="info-item">
<span class="item-title">是否为同步:</span>
<span class="item">{{ isNtcType === "G" ? "是" : "否" }}</span>
</div>
<div class="info-item">
<span class="item-title">同步位置:</span>
<span class="item">{{ syncPosition }}</span>
</div>
<div class="info-item">
<span class="item-title">参考主体:</span>
<span class="item">{{ referenceSubject }}</span>
</div>
<div class="info-item">
<span class="item-title">是否恢复使用:</span>
<span class="item">{{ isRestoreUsed }}</span>
</div>
<div class="info-item">
<span class="item-title">最新相关 BR IFIC 发布日期:</span>
<span class="item">{{ BFIFICdate }}</span>
</div>
</el-card>
</el-col>
</el-row>
</el-dialog>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" />
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import exportDialog from '@/components/Export/index.vue'
import { getItuList, getItuDetail, deleteItuData } from '@/api/spiderData'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from "vue";
import Pagination from "@/components/pagination/index.vue";
import exportDialog from "@/components/Export/index.vue";
import { getItuList, getItuDetail } from "@/api/spiderData";
import { ElMessage } from "element-plus";
import TableSearch from "@/components/TableSearch.vue";
// ElConfigProvider 组件
import { ElConfigProvider } from 'element-plus';
import { ElConfigProvider } from "element-plus";
// 引入中文包
import zhCn from 'element-plus/es/locale/lang/zh-cn';
defineOptions({ name: 'Pagination' })
import zhCn from "element-plus/es/locale/lang/zh-cn";
defineOptions({ name: "Pagination" });
// 更改分页文字
zhCn.el.pagination.total = '共 `{total} 条`';
zhCn.el.pagination.goto = '跳至';
zhCn.el.pagination.pagesize = '条/页';
zhCn.el.pagination.pageClassifier = '页';
const searchTargetName = ref('')
const searchTimeValue = ref('')
const searchTargetId = ref('')
const showDeleteDialog = ref(false)
const detailVisibleValue = ref(false)
zhCn.el.pagination.total = "共 `{total} 条`";
zhCn.el.pagination.goto = "跳至";
zhCn.el.pagination.pagesize = "条/页";
zhCn.el.pagination.pageClassifier = "页";
const searchTargetName = ref("");
const searchTimeValue = ref("");
const searchTargetId = ref("");
const showDeleteDialog = ref(false);
const detailVisibleValue = ref(false);
// SNS Notice ID
const snsId = ref('')
const snsId = ref("");
// 主管部门
const department = ref('')
const department = ref("");
//详细主管部门
const departmentDetail = ref("");
//网络组织
const ntwkOrg = ref("");
//卫星网络类型
const ntwkType = ref("");
// 目标名称
const targetName = ref('')
const targetName = ref("");
// 计划/非计划类型
const planType = ref('')
const planType = ref("");
// 是否为同步
const syncType = ref('')
const syncType = ref("");
// 同步位置
const syncPosition = ref('')
const syncPosition = ref("");
// 近地点
const perigee = ref('')
const perigee = ref("");
// 远地点
const apogee = ref('')
const apogee = ref("");
// 最低海拔
const lowestAltitude = ref('')
const lowestAltitude = ref("");
// 参考主体
const referenceSubject = ref('')
const referenceSubject = ref("");
// 最低频率
const lowestFrequency = ref('')
const lowestFrequency = ref("");
// 最高频率
const highestFrequency = ref('')
const highestFrequency = ref("");
// 状态
const status = ref('')
const status = ref("");
//是否为同步
const isNtcType = ref("");
// 有效期
const validityPeriod = ref('')
const validityPeriod = ref("");
// 最早使用日期
const earliestUsageDate = ref('')
const earliestUsageDate = ref("");
// 是否确认使用
const isUsed = ref('')
const isUsed = ref("");
// 是否暂停使用
const isPauseUsed = ref('')
const isPauseUsed = ref("");
// 记录时间
const recordTime = ref('')
const recordTime = ref("");
// 是否纳入国际频率总表
const IsInTheInternationalFrequencyList = ref('')
const IsInTheInternationalFrequencyList = ref("");
// 最早监管日期
const earliestRegulatoryDate = ref('')
const earliestRegulatoryDate = ref("");
// 是否恢复使用
const isRestoreUsed = ref('')
const isRestoreUsed = ref("");
// 有效期卫星网络旧名称
const validityPeriodSatelliteNetworkOldName = ref('')
const validityPeriodSatelliteNetworkOldName = ref("");
// 最新相关 BR IFIC 发布日期
const BFIFICdate = ref('')
const tableData = ref([])
const BFIFICdate = ref("");
const tableData = ref([]);
const pageObj = ref({
total: 0,
pageSize: 10,
pageNo: 1
})
total: 0,
pageSize: 10,
pageNo: 1,
});
// 查看数据详情的方法
const handleDetails = async (id: any) => {
const res = await getItuDetail({ id: id._id })
console.log(res);
snsId.value = res.data.item.ntc_id
department.value = res.data.item.adm
targetName.value = res.data.identity.sat_name
planType.value = res.data.identity.plan_type
syncType.value = res.data.identity.ntc_type
syncPosition.value = res.data.identity.long_nom === null ? '无' : res.data.identity.long_nom
perigee.value = res.data.item.minPerigee === null ? '无' : res.data.item.minPerigee
apogee.value = res.data.item.maxApog === null ? '无' : res.data.item.maxApog
lowestAltitude.value = res.data.item.minAltitude === null ? '无' : res.data.item.minAltitude
referenceSubject.value = res.data.item.ref_body === null ? '无' : res.data.item.ref_body
lowestFrequency.value = res.data.item.freq_min === null ? '无' : res.data.item.freq_min
highestFrequency.value = res.data.item.freq_max === null ? '无' : res.data.item.freq_max
status.value = res.data.regulatory_status.active_status
validityPeriod.value = res.data.regulatory_status.prd_valid
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
isPauseUsed.value = res.data.regulatory_status.resumption_list
recordTime.value = res.data.crawl_time
IsInTheInternationalFrequencyList.value = res.data.regulatory_status.mifr
earliestRegulatoryDate.value = res.data.regulatory_status.d_inuse_list
isRestoreUsed.value = res.data.regulatory_status.resumption_list
validityPeriodSatelliteNetworkOldName.value = res.data.regulatory_status.old_satellite_network_name
BFIFICdate.value = res.data.regulatory_status.d_wic === null ? '无' : res.data.regulatory_status.d_wic
detailVisibleValue.value = true
}
const res = await getItuDetail({ id: id._id });
snsId.value = res.data.item.ntc_id;
department.value = res.data.item.adm;
departmentDetail.value = res.data.item.notifying_adm_tooltip;
ntwkOrg.value = res.data.item.ntwk_org;
ntwkType.value = res.data.item.notice_type_tooltip;
targetName.value = res.data.identity.sat_name;
planType.value = res.data.identity.plan_type;
syncType.value = res.data.identity.ntc_type;
isNtcType.value = res.data.item.ntc_type;
syncPosition.value = res.data.identity.long_nom === null ? "-" : res.data.identity.long_nom;
perigee.value = res.data.item.minPerigee === null ? "-" : res.data.item.minPerigee;
apogee.value = res.data.item.maxApog === null ? "-" : res.data.item.maxApog;
lowestAltitude.value = res.data.item.minAltitude === null ? "-" : res.data.item.minAltitude;
referenceSubject.value = res.data.item.ref_body === null ? "-" : res.data.item.ref_body;
lowestFrequency.value = res.data.item.freq_min === null ? "-" : res.data.item.freq_min;
highestFrequency.value = res.data.item.freq_max === null ? "-" : res.data.item.freq_max;
status.value = res.data.regulatory_status.active_status;
validityPeriod.value = res.data.regulatory_status.prd_valid;
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;
isPauseUsed.value = res.data.regulatory_status.resumption_list;
recordTime.value = res.data.crawl_time;
IsInTheInternationalFrequencyList.value = res.data.regulatory_status.mifr;
earliestRegulatoryDate.value = res.data.regulatory_status.d_inuse_list;
isRestoreUsed.value = res.data.regulatory_status.resumption_list;
validityPeriodSatelliteNetworkOldName.value = res.data.regulatory_status.old_satellite_network_name;
BFIFICdate.value = res.data.regulatory_status.d_wic === null ? "-" : res.data.regulatory_status.d_wic;
detailVisibleValue.value = true;
};
// 获取itu数据列表的方法
const getData = async () => {
const res = await getItuList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize })
searchTargetName.value = ''
searchTargetId.value = ''
searchTimeValue.value = ''
pageObj.value.total = res.data.total
tableData.value = res.data.list
}
const res = await getItuList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize });
searchTargetName.value = "";
searchTargetId.value = "";
searchTimeValue.value = "";
pageObj.value.total = res.data.total;
tableData.value = res.data.list;
};
const handleClose = () => {
detailVisibleValue.value = false
}
detailVisibleValue.value = false;
};
const handleSearch = async () => {
if (searchTargetName.value === '' && searchTargetId.value === '' && searchTimeValue.value === '') {
ElMessage.warning('请输入搜索内容')
return
}
const res = await getItuList({ sat_name: searchTargetName.value, ntc_id: searchTargetId.value, times: searchTimeValue.value, page: pageObj.value.pageNo, size: pageObj.value.pageSize })
pageObj.value.total = res.data.total
tableData.value = res.data.list
}
if (searchTargetName.value === "" && searchTargetId.value === "" && searchTimeValue.value === "") {
ElMessage.warning("请输入搜索内容");
return;
}
const res = await getItuList({
sat_name: searchTargetName.value,
ntc_id: searchTargetId.value,
times: searchTimeValue.value,
page: pageObj.value.pageNo,
size: pageObj.value.pageSize,
});
pageObj.value.total = res.data.total;
tableData.value = res.data.list;
};
onMounted(() => {
getData()
})
getData();
});
</script>
<style scoped lang="scss">
:deep(.el-form-item__label) {
color: white;
}
// 调整表单项间距
.detailForm {
.el-dialog-title {
font-size: 180px;
}
// background-image: url("@/assets/picture/dialog1.png");
// background-size: 100% 100%;
// background-repeat: no-repeat;
.el-dialog-title {
font-size: 180px;
}
.el-form-item {
margin-bottom: 20px !important;
}
.el-form-item {
margin-bottom: 20px !important;
}
}
/* 工具栏样式 */
.toolbarStyle {
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
.itu-table {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(8px);
border: 1px solid rgba(78, 237, 255, 0.2);
box-shadow: 0 0 15px rgba(78, 237, 255, 0.1);
border-radius: 8px;
padding: 10px;
}
/* 表格样式 */
.formStyle {
display: flex;
justify-content: space-around;
padding: 3px;
margin-top: 1%;
display: flex;
justify-content: space-around;
padding: 3px;
margin-top: 1%;
}
/* 文字样式 */
.el-text {
color: #FFFFFF;
color: #ffffff;
}
.title {
color: #4edaff;
font-size: 18px;
font-weight: 500;
}
.left {
display: flex;
gap: 10px;
}
.info-item {
display: flex;
align-items: center;
margin: 10px 0;
justify-content: space-between;
}
.item-title {
color: #fff;
}
.item {
color: #eee;
}
.form-content {
display: flex;
height: 80px;
justify-content: space-between;
align-items: center;
padding: 0 30px;
}
</style>
<style>
.el-input {
--el-input-text-color: #FFFFFF;
--el-input-text-color: #ffffff;
}
/* 修改el选择器的样式 */
.el-select__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 删除el选择器选中时的边框 */
.is-hovering {
box-shadow: none !important;
box-shadow: none !important;
}
/* 修改el输入框的样式 */
.el-input__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 修改el下拉框的背景颜色 */
.el-select-dropdown {
background-color: #1d5484;
background-color: #1d5484;
}
/* 修改el下拉框选项的字体颜色 */
.el-select-dropdown__item {
color: #FFFFFF;
color: #ffffff;
}
/* 修改el下拉框选项选中时的文字颜色 */
.el-select-dropdown__item:hover {
color: #409eff;
color: #409eff;
}
/* 修改el日期选择器的边框为none */
.el-date-editor {
--el-input-border-color: none
--el-input-border-color: none;
}
.el-button:focus {
outline: none;
outline: none;
}
</style>
\ No newline at end of file
</style>
<template>
<div class="text-left p-4 toolbarStyle">
<div class="formStyle">
<el-form inline>
<el-form-item>
<el-text class="mx-1">目标名称:</el-text>
</el-form-item>
<el-form-item>
<div>
<el-input placeholder="请输入" style="width: 180px" v-model="searchTargetName" />
</div>
</el-form-item>
<el-form-item>
<el-text class="mx-1">获取时间:</el-text>
</el-form-item>
<el-form-item>
<el-config-provider :locale="zhCn">
<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: 330px" value-format="YYYY-MM-DD HH:mm:ss" />
</el-config-provider>
</el-form-item>
<el-form-item>
<el-text class="mx-1">NORAD CAT ID:</el-text>
</el-form-item>
<el-form-item>
<el-input placeholder="请输入" style="width: 170.5px" v-model="noradCatId" />
</el-form-item>
<!-- <el-form-item>
<el-space>
<el-button type="primary" @click="handleExport">导出最近</el-button>
</el-space>
</el-form-item> -->
<el-form-item>
<el-space>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button type="primary" @click="getData">重置表格</el-button>
</el-space>
</el-form-item>
</el-form>
</div>
</div>
<div class="text-left">
<table-search>
<div class="form-content">
<div class="left">
<div>
<span style="color: white">目标名称:</span>
<el-input placeholder="请输入目标名称" style="width: 180px" v-model="searchTargetName" />
</div>
<div>
<span style="color: white">时间范围:</span>
<el-config-provider :locale="zhCn">
<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: 200px"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</el-config-provider>
</div>
<div>
<span style="color: white">Norad Cat ID:</span>
<el-input placeholder="请输入ID" style="width: 170.5px" v-model="noradCatId" />
</div>
</div>
<div class="btns">
<el-button plain type="primary" @click="handleSearch">查询</el-button>
<el-button plain @click="getData">重置表格</el-button>
</div>
</div>
</table-search>
</div>
<div class="m-t-5" />
<div>
<el-table :data="tableData" style="width: 100%" border :row-style="{ height: '45.5px' }"
:header-cell-style="{ textAlign: 'center' }" :cell-style="{ textAlign: 'center' }">
<!-- <el-table-column type="selection" width="40" /> -->
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="data[0].NORAD_CAT_ID" label="Norad Cat ID" show-overflow-tooltip />
<el-table-column property="data[0].OBJECT_NAME" label="目标名称" show-overflow-tooltip />
<!-- <el-table-column property="intleds" label="INTLDES" show-overflow-tooltip /> -->
<el-table-column property="data[0].OBJECT_TYPE" label="类型" show-overflow-tooltip />
<el-table-column property="data[0].COUNTRY_CODE" label="所属国家" width="82" show-overflow-tooltip />
<!-- <el-table-column property="runningTime" label="运行时间" show-overflow-tooltip /> -->
<el-table-column property="data[0].SITE" label="SITE" show-overflow-tooltip />
<!-- <el-table-column property="failTime" label="失效时间" show-overflow-tooltip /> -->
<el-table-column property="data[0].PERIOD" label="周期" show-overflow-tooltip />
<el-table-column property="data[0].PERIAPSIS" label="近地点" show-overflow-tooltip />
<el-table-column property="data[0].APOAPSIS" label="远地点" show-overflow-tooltip />
<!-- <el-table-column property="incl" label="INCL" show-overflow-tooltip /> -->
<el-table-column property="data[0].RCS_SIZE" label="RCS" show-overflow-tooltip />
<el-table-column property="data[0].TLE_LINE0" label="TLE_LINE0" show-overflow-tooltip />
<el-table-column property="data[0].TLE_LINE1" label="TLE_LINE1" show-overflow-tooltip />
<el-table-column property="data[0].TLE_LINE2" label="TLE_LINE2" show-overflow-tooltip />
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="primary" plain link @click="handleDetails(scope.row)">
详情
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
@pagination="getData" />
</div>
</div>
<div class="m-t-5" />
<div class="table-content">
<el-table
:data="tableData"
style="width: 100%"
border
:row-style="{ height: '45.5px' }"
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
>
<!-- <el-table-column type="selection" width="40" /> -->
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="data[0].NORAD_CAT_ID" label="Norad Cat ID" show-overflow-tooltip />
<el-table-column property="data[0].OBJECT_NAME" label="目标名称" show-overflow-tooltip />
<!-- <el-table-column property="intleds" label="INTLDES" show-overflow-tooltip /> -->
<el-table-column property="data[0].OBJECT_TYPE" label="类型" show-overflow-tooltip />
<el-table-column property="data[0].COUNTRY_CODE" label="所属国家" width="82" show-overflow-tooltip />
<!-- <el-table-column property="runningTime" label="运行时间" show-overflow-tooltip /> -->
<el-table-column property="data[0].SITE" label="SITE" show-overflow-tooltip />
<!-- <el-table-column property="failTime" label="失效时间" show-overflow-tooltip /> -->
<el-table-column property="data[0].PERIOD" label="周期(min)" show-overflow-tooltip />
<el-table-column property="data[0].PERIAPSIS" label="近地点" show-overflow-tooltip />
<el-table-column property="data[0].APOAPSIS" label="远地点" show-overflow-tooltip />
<!-- <el-table-column property="incl" label="INCL" show-overflow-tooltip /> -->
<el-table-column property="data[0].RCS_SIZE" label="RCS" show-overflow-tooltip />
<el-table-column label="操作" width="60">
<template #default="scope">
<el-button type="primary" plain link @click="handleDetails(scope.row)"> 详情 </el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination
:total="pageObj.total"
v-model:page="pageObj.pageNo"
v-model:limit="pageObj.pageSize"
@pagination="getData"
/>
</div>
</div>
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="765px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-8">
详情
</div>
</template>
<el-form label-width="70px" size="small" class="px-4">
<div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="NoradCatID:" label-position="left">
<el-input v-model="NoradCatID" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="目标名称:" label-position="left">
<el-input v-model="targetName" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="周期(min):" label-position="left">
<el-input v-model="period" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型:" label-position="left">
<el-input v-model="type" />
</el-form-item>
</el-col>
</el-row>
<!-- <el-row :gutter="20">
<el-col :span="12">
<el-form-item label="运行时间:" label-position="left">
<el-input v-model="workTime" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="失效时间:" label-position="left">
<el-input v-model="failTime" />
</el-form-item>
</el-col>
</el-row> -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="记录时间:" label-position="left">
<el-input v-model="recordTime" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属国家:" label-position="left">
<el-input v-model="belongCountry" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="近地点:" label-position="left">
<el-input v-model="perigee" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="远地点:" label-position="left">
<el-input v-model="apogee" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="RCS:" label-position="left">
<el-input v-model="rcs" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="SITE:" label-position="left">
<el-input v-model="site" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="TLE:" label-position="left">
<el-input type="textarea" :rows="3" v-model="tle" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
</el-dialog>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" />
<div class="detailForm">
<el-dialog v-model="detailVisibleValue" center width="765px" align-center @close="handleClose" draggable>
<template #header>
<div class="text-center font-size-6">详情-{{ targetName }}</div>
</template>
<el-row>
<el-col>
<el-card>
<div class="title">目标信息:</div>
<el-divider style="margin: 0"></el-divider>
<el-row :gutter="50" style="display: flex; justify-content: space-between">
<el-col :span="12">
<div class="info-item">
<span class="item-title">目标名称:</span>
<span class="item">{{ targetName }}</span>
</div>
<div class="info-item">
<span class="item-title">近地点幅角:</span>
<span class="item">{{ argOfPericenter }}</span>
</div>
<div class="info-item">
<span class="item-title">带星号的弹道系数:</span>
<span class="item">{{ bStar }}</span>
</div>
<div class="info-item">
<span class="item-title">偏心率:</span>
<span class="item">{{ eccentricity }}</span>
</div>
<div class="info-item">
<span class="item-title">倾斜角:</span>
<span class="item">{{ inclination }}</span>
</div>
<div class="info-item">
<span class="item-title">发射日期:</span>
<span class="item">{{ launchDate }}</span>
</div>
<div class="info-item">
<span class="item-title">卫星站点:</span>
<span class="item">{{ site }}</span>
</div>
</el-col>
<el-col :span="12">
<div class="info-item">
<span class="item-title">升交点赤经:</span>
<span class="item">{{ raOfAscNode }}</span>
</div>
<div class="info-item">
<span class="item-title">平近点角:</span>
<span class="item">{{ meanAnomaly }}</span>
</div>
<div class="info-item">
<span class="item-title">轨道半长轴:</span>
<span class="item">{{ semimajorAxis }}</span>
</div>
<div class="info-item">
<span class="item-title">雷达截面积:</span>
<span class="item">{{ rcsSize }}</span>
</div>
</el-col>
</el-row>
<div class="title">TLE数据:</div>
<el-divider style="margin: 0"></el-divider>
<el-row>
<el-col>
<div class="info-item-tle">
<el-row>
<el-col :span="4">
<span class="item-title">TLE第一行数据:</span>
</el-col>
<el-col :span="20">
<span class="item">{{ tleLine0 }}</span>
</el-col>
</el-row>
</div>
<div class="info-item-tle">
<el-row>
<el-col :span="4">
<span class="item-title">TLE第二行数据:</span>
</el-col>
<el-col :span="20">
<span class="item">{{ tleLine1 }}</span>
</el-col>
</el-row>
</div>
<div class="info-item-tle">
<el-row>
<el-col :span="4">
<span class="item-title">TLE第三行数据:</span>
</el-col>
<el-col :span="20">
<span class="item">{{ tleLine2 }}</span>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
</el-dialog>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" />
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import exportDialog from '@/components/Export/index.vue'
import { getStList, getStDetail, deleteStData } from '@/api/spiderData'
import { ElMessage } from 'element-plus'
import { onMounted, ref } from "vue";
import Pagination from "@/components/pagination/index.vue";
import exportDialog from "@/components/Export/index.vue";
import { getStList, getStDetail } from "@/api/spiderData";
import { ElMessage } from "element-plus";
// ElConfigProvider 组件
import { ElConfigProvider } from 'element-plus';
import { ElConfigProvider } from "element-plus";
import TableSearch from "@/components/TableSearch.vue";
// 引入中文包
import zhCn from 'element-plus/es/locale/lang/zh-cn';
defineOptions({ name: 'Pagination' })
import zhCn from "element-plus/es/locale/lang/zh-cn";
defineOptions({ name: "Pagination" });
// 更改分页文字
zhCn.el.pagination.total = '共 `{total} 条`';
zhCn.el.pagination.goto = '跳至';
zhCn.el.pagination.pagesize = '条/页';
zhCn.el.pagination.pageClassifier = '页';
const searchTargetName = ref('')
const noradCatId = ref('')
const showDeleteDialog = ref(false)
const timeValue = ref('')
const detailVisibleValue = ref(false)
zhCn.el.pagination.total = "共 `{total} 条`";
zhCn.el.pagination.goto = "跳至";
zhCn.el.pagination.pagesize = "条/页";
zhCn.el.pagination.pageClassifier = "页";
const searchTargetName = ref("");
const noradCatId = ref("");
const showDeleteDialog = ref(false);
const timeValue = ref("");
const detailVisibleValue = ref(false);
// NoradCatID
const NoradCatID = ref('')
const NoradCatID = ref("");
// 目标名称
const targetName = ref('')
const targetName = ref("");
// INTLDES
const intleds = ref('')
const intleds = ref("");
// 类型
const type = ref('')
const type = ref("");
// 记录时间
const recordTime = ref('')
const recordTime = ref("");
// 所属国家
const belongCountry = ref('')
const belongCountry = ref("");
// 近地点
const perigee = ref('')
const perigee = ref("");
// 远地点
const apogee = ref('')
const apogee = ref("");
// 周期
const period = ref('')
// INCL
const incl = ref('')
const period = ref("");
// RCS
const rcs = ref('')
const rcs = ref("");
// SITE
const site = ref('')
const site = ref("");
// TLE
const tle = ref('')
const tle = ref("");
//近地点幅角
const argOfPericenter = ref("");
//弹道系数
const bStar = ref("");
//备注
const comment = ref("");
//偏心率 ECCENTRICITY
const eccentricity = ref("");
//倾斜角 INCLINATION
const inclination = ref("");
//升交点赤经 RA_OF_ASC_NODE
const raOfAscNode = ref("");
//平近点角 MEAN_ANOMALY
const meanAnomaly = ref("");
//RCS_SIZE
const rcsSize = ref("");
//LAUNCH_DATE
const launchDate = ref("");
//卫星站点
const tableData = ref([])
//半长轴SEMIMAJOR_AXIS
const semimajorAxis = ref("");
//第一行数据 TLE_LINE0
const tleLine0 = ref("");
//第二行数据 TLE_LINE0
const tleLine1 = ref("");
//第三行数据 TLE_LINE0
const tleLine2 = ref("");
const tableData = ref([]);
const pageObj = ref({
total: 10,
pageSize: 10,
pageNo: 1
})
total: 10,
pageSize: 10,
pageNo: 1,
});
// 查看数据详情的方法
const handleDetails = async (row: any) => {
const res = await getStDetail({ id: row._id })
NoradCatID.value = res.data.data[0].NORAD_CAT_ID
targetName.value = res.data.data[0].OBJECT_NAME
type.value = res.data.data[0].OBJECT_TYPE
period.value = res.data.data[0].PERIOD
intleds.value = res.data.data[0].INTLDES
recordTime.value = res.data.data[0].CREATION_DATE
belongCountry.value = res.data.data[0].COUNTRY_CODE
perigee.value = res.data.data[0].PERIAPSIS
apogee.value = res.data.data[0].APOAPSIS
rcs.value = res.data.data[0].RCS_SIZE
site.value = res.data.data[0].SITE
tle.value = `${res.data.data[0].TLE_LINE0}
const res = await getStDetail({ id: row._id });
console.log(res);
NoradCatID.value = res.data.data[0].NORAD_CAT_ID;
rcsSize.value = res.data.data[0].RCS_SIZE;
launchDate.value = res.data.data[0].LAUNCH_DATE;
semimajorAxis.value = res.data.data[0].SEMIMAJOR_AXIS;
targetName.value = res.data.data[0].OBJECT_NAME;
tleLine0.value = res.data.data[0].TLE_LINE0;
tleLine1.value = res.data.data[0].TLE_LINE1;
tleLine2.value = res.data.data[0].TLE_LINE2;
inclination.value = res.data.data[0].INCLINATION;
meanAnomaly.value = res.data.data[0].MEAN_ANOMALY;
eccentricity.value = res.data.data[0].ECCENTRICITY;
raOfAscNode.value = res.data.data[0].RA_OF_ASC_NODE;
comment.value = res.data.data[0].COMMENT;
type.value = res.data.data[0].OBJECT_TYPE;
argOfPericenter.value = res.data.data[0].ARG_OF_PERICENTER;
bStar.value = res.data.data[0].BSTAR;
period.value = res.data.data[0].PERIOD;
intleds.value = res.data.data[0].INTLDES;
recordTime.value = res.data.data[0].CREATION_DATE;
belongCountry.value = res.data.data[0].COUNTRY_CODE;
perigee.value = res.data.data[0].PERIAPSIS;
apogee.value = res.data.data[0].APOAPSIS;
rcs.value = res.data.data[0].RCS_SIZE;
site.value = res.data.data[0].SITE;
tle.value = `${res.data.data[0].TLE_LINE0}
${res.data.data[0].TLE_LINE1}
${res.data.data[0].TLE_LINE2}`
detailVisibleValue.value = true
}
${res.data.data[0].TLE_LINE2}`;
detailVisibleValue.value = true;
};
// 获取st数据列表的方法
const getData = async () => {
const res = await getStList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize })
pageObj.value.total = res.data.total
tableData.value = res.data.list
noradCatId.value = ''
searchTargetName.value = ''
timeValue.value = ''
}
const res = await getStList({ page: pageObj.value.pageNo, size: pageObj.value.pageSize });
pageObj.value.total = res.data.total;
tableData.value = res.data.list;
noradCatId.value = "";
searchTargetName.value = "";
timeValue.value = "";
};
const handleClose = () => {
detailVisibleValue.value = false
}
detailVisibleValue.value = false;
};
const handleSearch = async () => {
if (searchTargetName.value === '' && noradCatId.value === '' && timeValue.value === '') {
ElMessage.warning('请输入搜索内容')
return
}
const res = await getStList({ norad_cat_id: noradCatId.value, object_name: searchTargetName.value, times: timeValue.value, page: pageObj.value.pageNo, size: pageObj.value.pageSize })
tableData.value = res.data.list
pageObj.value.total = res.data.total
}
if (searchTargetName.value === "" && noradCatId.value === "" && timeValue.value === "") {
ElMessage.warning("请输入搜索内容");
return;
}
const res = await getStList({
norad_cat_id: noradCatId.value,
object_name: searchTargetName.value,
times: timeValue.value,
page: pageObj.value.pageNo,
size: pageObj.value.pageSize,
});
tableData.value = res.data.list;
pageObj.value.total = res.data.total;
};
onMounted(() => {
getData()
})
getData();
});
</script>
<style scoped lang="scss">
:deep(.el-form-item__label) {
color: white;
}
// 调整表单项间距
.detailForm {
.el-dialog-title {
font-size: 180px;
}
.el-dialog-title {
font-size: 180px;
}
.el-form-item {
margin-bottom: 30px !important;
}
.el-form-item {
margin-bottom: 30px !important;
}
}
/* 工具栏样式 */
.toolbarStyle {
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
/* 表格样式 */
.formStyle {
display: flex;
justify-content: space-around;
padding: 3px;
margin-top: 1%;
display: flex;
justify-content: space-around;
padding: 3px;
margin-top: 1%;
}
/* 文字样式 */
.el-text {
color: #FFFFFF;
color: #ffffff;
}
.title {
font-size: 18px;
font-weight: 500;
color: #4edaff;
}
.info-item {
display: flex;
align-items: center;
margin: 10px 0;
justify-content: space-between;
}
.info-item-tle {
margin: 10px 0;
}
.table-content {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(8px);
border: 1px solid rgba(78, 237, 255, 0.2);
box-shadow: 0 0 15px rgba(78, 237, 255, 0.1);
border-radius: 8px;
padding: 10px !important;
}
.item-title {
color: #b0dfff;
}
.item {
color: #eee;
}
.form-content {
display: flex;
height: 80px;
align-items: center;
padding: 0 30px;
justify-content: space-between;
}
.left {
display: flex;
gap: 10px;
}
</style>
<style>
.el-textarea__inner {
color: #FFFFFF;
color: #ffffff;
}
.el-input {
--el-input-text-color: #FFFFFF;
--el-input-text-color: #ffffff;
}
/* 修改el选择器的样式 */
.el-select__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 删除el选择器选中时的边框 */
.is-hovering {
box-shadow: none !important;
box-shadow: none !important;
}
/* 修改el输入框的样式 */
.el-input__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 修改el下拉框的背景颜色 */
.el-select-dropdown {
background-color: #1d5484;
background-color: #1d252c;
}
/* 修改el下拉框选项的字体颜色 */
.el-select-dropdown__item {
color: #FFFFFF;
color: #ffffff;
}
/* 修改el下拉框选项选中时的文字颜色 */
.el-select-dropdown__item:hover {
color: #409eff;
color: #409eff;
}
/* 修改el日期选择器的边框为none */
.el-date-editor {
--el-input-border-color: none
--el-input-border-color: none;
}
.el-button:focus {
outline: none;
outline: none;
}
</style>
\ No newline at end of file
.table-contet {
padding: 0 10px;
}
</style>
<template>
<div>
<div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToStatus" />
<div class="text-left p-4 ">
<div class="custom-style flex gap-4">
<el-segmented v-model="mode" :options="sizeOptions" style="margin-bottom: 1rem" size="default" />
<el-button type="primary" @click="handleExport">导出</el-button>
</div>
</div>
<!-- 综合数据页面组件 -->
<!-- <allDataTab v-if="mode === '综合数据'">
<div>
<MenuTitle title="数据展示" subtitle="Data Display" />
<div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToStatus" />
<div class="segment-content">
<div class="custom-style flex gap-4">
<el-segmented v-model="mode" :options="sizeOptions" style="margin-bottom: 1rem" size="default" />
<el-button type="primary" @click="handleExport">导出</el-button>
</div>
</div>
<!-- 综合数据页面组件 -->
<!-- <allDataTab v-if="mode === '综合数据'">
</allDataTab> -->
<!-- DSN数据页面组件 -->
<dsnDataTab v-if="mode === 'DSN数据'">
</dsnDataTab>
<!-- ITU数据页面组件 -->
<ituDataTab v-if="mode === 'ITU数据'">
</ituDataTab>
<!-- ST数据页面组件 -->
<stDataTab v-if="mode === 'ST数据'">
</stDataTab>
<!-- ESA数据页面组件 -->
<esDataTab v-if="mode === 'ESA数据'">
</esDataTab>
</div>
<exportDialog v-model:dialogVisible="showDeleteDialog" @confirm="handleExportConfirm" />
<!-- DSN数据页面组件 -->
<dsnDataTab v-if="mode === 'DSN数据'"></dsnDataTab>
<!-- ITU数据页面组件 -->
<ituDataTab v-if="mode === 'ITU数据'"></ituDataTab>
<!-- ST数据页面组件 -->
<stDataTab v-if="mode === 'ST数据'"></stDataTab>
<!-- ESA数据页面组件 -->
<esDataTab v-if="mode === 'ESA数据'"></esDataTab>
<exportDialog v-model:dialogVisible="showDeleteDialog" @confirm="handleExportConfirm" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import allDataTab from './components/allDataTab.vue'
import ituDataTab from './components/ituDataTab.vue'
import stDataTab from './components/stDataTab.vue'
import dsnDataTab from './components/dsnData/dsnTab.vue'
import esDataTab from './components/esDataTab.vue'
import exportDialog from '@/components/Export/index.vue'
import { genFileId } from 'element-plus'
import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus'
const mode = ref('DSN数据')
const showDeleteDialog = ref(false)
const sizeOptions = ['DSN数据', 'ITU数据', 'ST数据', 'ESA数据']
const route = useRoute()
const router = useRouter()
const modeValue = ref<any>('数据展示')
const upload = ref<UploadInstance>()
import { ref, onMounted, watch } from "vue";
import { useRoute } from "vue-router";
import { useRouter } from "vue-router";
import ituDataTab from "./components/ituDataTab.vue";
import stDataTab from "./components/stDataTab.vue";
import dsnDataTab from "./components/dsnData/dsnTab.vue";
import esDataTab from "./components/esDataTab.vue";
import exportDialog from "@/components/Export/index.vue";
import type { UploadInstance } from "element-plus";
import MenuTitle from "@/components/MenuTitle.vue";
const handleExceed: UploadProps['onExceed'] = (files) => {
upload.value!.clearFiles()
const file = files[0] as UploadRawFile
file.uid = genFileId()
upload.value!.handleStart(file)
}
const mode = ref(sessionStorage.getItem("dataDisplayMode") || "DSN数据");
const showDeleteDialog = ref(false);
const sizeOptions = ["DSN数据", "ITU数据", "ST数据", "ESA数据"];
const route = useRoute();
const router = useRouter();
const modeValue = ref<any>("数据展示");
const submitUpload = () => {
upload.value!.submit()
}
const goToStatus = () => {
router.push({
path: '/osStatus/list',
})
}
router.push({
path: "/osStatus/list",
});
};
const handleExport = () => {
showDeleteDialog.value = true
}
const handleExportConfirm = () => {
}
showDeleteDialog.value = true;
};
const handleExportConfirm = () => {};
onMounted(() => {
if (route.query.mode) {
modeValue.value = route.query.mode
mode.value = modeValue.value
}
console.log(mode.value)
})
if (route.query.mode) {
modeValue.value = route.query.mode;
mode.value = modeValue.value;
}
});
watch(
mode,
(newVal) => {
sessionStorage.setItem("dataDisplayMode", newVal);
modeValue.value = sessionStorage.getItem("dataDisplayMode") || "DSN数据";
},
{
immediate: true,
}
);
</script>
<style scoped lang="scss">
.el-button:focus {
outline: none;
outline: none;
}
.title {
text-align: left;
font-size: 18px;
font-weight: 500;
color: white;
}
.low-titme {
color: #ccc;
text-align: left;
margin-left: 20px;
}
.divider {
margin-top: 15px;
}
/* 文字样式 */
.el-text {
color: #FFFFFF;
color: #ffffff;
}
.backStyle {
background-image: url("@/assets/picture/back.png");
background-size: 100% 100%;
background-repeat: no-repeat;
height: 5vh;
width: 5%;
display: flex;
margin-left: 0.8%;
background-image: url("@/assets/picture/back.png");
background-size: 100% 100%;
background-repeat: no-repeat;
height: 5vh;
width: 5%;
display: flex;
margin-left: 0.8%;
}
.segment-content {
padding: 10px 10px 0 10px;
}
</style>
<template>
<div class="No-Item" :class="{ selected: isSelected }" @click="selectNo">
<!-- 新增选中标识,增强视觉反馈 -->
<span class="selected-icon" v-if="isSelected"></span>
{{ props.No }}
</div>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
const props = defineProps<{
No: string | number;
resetSelected?: boolean;
}>();
const isSelected = ref(false);
const emit = defineEmits<{
(e: "addNo", sateNo: string | number): void;
(e: "delNo", sateNo: string | number): void;
}>();
const selectNo = () => {
isSelected.value = !isSelected.value;
isSelected.value ? emit("addNo", props.No) : emit("delNo", props.No);
};
watch(
() => props.resetSelected,
(newVal) => {
if (newVal) isSelected.value = false;
},
{ immediate: true }
);
</script>
<style scoped>
.No-Item {
width: 100% !important;
letter-spacing: 6px;
background-color: #e8f4f8;
font-size: 16px;
font-weight: 600;
color: #192a3e;
height: 32px;
border-radius: 8px;
display: flex;
align-items: center;
padding: 0 16px;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
box-sizing: border-box;
user-select: none;
border: 1px solid transparent;
}
.No-Item:not(.selected):hover {
background-color: #f0f8fb;
border-color: #4299e1;
}
.selected {
background-color: #4299e1;
color: #ffffff;
box-shadow: 0 4px 12px rgba(66, 153, 225, 0.3);
border-color: #2563eb;
}
.selected-icon {
margin-right: 8px;
font-size: 14px;
font-weight: bold;
color: #ffffff;
}
</style>
<template>
<div>
<div class="mt-20" />
<div>
<el-table :data="tableData" style="width: 100%" border :header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }" :row-style="{ height: '60px' }">
<!-- <el-table-column type="selection" width="40" height="40" /> -->
<el-table-column property="number" label="序号" type="index" width="80" />
<el-table-column property="spider" label="爬虫名称" show-overflow-tooltip />
<el-table-column label="查看任务">
<template #default="scope">
<el-button type="primary" plain @click="handleDetails(scope.row)">
任务
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
@pagination="getData" />
</div>
</div>
<div>
<MenuTitle title="爬虫管理" subtitle="Spider Manager" />
<div class="table-content">
<el-table
:data="tableData"
style="width: 100%"
border
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
:row-style="{ height: '60px' }"
v-loading="tableData.length == 0"
element-loading-background="rgba(48, 65, 86, 0.7)"
>
<el-table-column property="number" label="序号" type="index" width="80" />
<el-table-column property="spider" label="爬虫代号" show-overflow-tooltip />
<el-table-column property="spider_name" label="爬虫名称" show-overflow-tooltip />
<el-table-column property="spider_info" label="任务描述" show-overflow-tooltip />
<el-table-column label="操作">
<template #default="scope">
<div class="btn-group">
<el-button type="primary" plain @click="handleDetails(scope.row)">查看任务</el-button>
<el-button type="primary" plain @click="handleEditSateId" v-if="scope.row.editable">编辑</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination
:total="pageObj.total"
v-model:page="pageObj.pageNo"
v-model:limit="pageObj.pageSize"
@pagination="getData"
/>
</div>
</div>
<el-dialog style="z-index: 999999" draggable v-model="editDialogVisible" title="指定下载以下卫星" width="400">
<div class="No-Content" ref="noContentRef">
<TransitionGroup
enter-active-class="animate__animated animate__slideInRight"
leave-active-class="animate__animated animate__slideOutRight"
enter-from-class="animate__opacity-0"
leave-to-class="animate__opacity-0"
>
<NoItem
v-for="(no, index) in sateNoList"
:key="index"
class="no-item-row"
:-no="no"
@add-no="handleSateAdd"
@del-no="handleSateDel"
:reset-selected="resetSelected"
></NoItem>
</TransitionGroup>
</div>
<div class="footer">
<div class="No">
<span style="color: white; font-weight: 500">NORAD编号:</span>
<el-input
@input="handleNumInput"
maxlength="5"
placeholder="请输入编号"
v-model="curSateNo"
style="width: 100px"
></el-input>
</div>
<div class="btn">
<el-button :disabled="curSateNo == ''" plain type="primary" @click="addNoToList">添加</el-button>
<el-popconfirm title="确定删除选中编号吗?" width="200" style="background-color: pink">
<template #reference>
<el-button :disabled="curSelSateNo.length === 0" plain type="danger">删除</el-button>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button
type="danger"
size="small"
@click="
() => {
confirm();
delNoList();
}
"
>
确定
</el-button>
</template>
</el-popconfirm>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import { useRouter } from 'vue-router'
import { getSpiderList } from '@/api/system.ts'
const router = useRouter()
const tableData = ref([])
import { ref, onMounted, nextTick } from "vue";
import Pagination from "@/components/pagination/index.vue";
import { useRouter } from "vue-router";
import { getSpiderList, addSateNo, getSateIdList } from "@/api/system.ts";
import NoItem from "./components/NoItem.vue";
import { ElMessage } from "element-plus";
import MenuTitle from "@/components/MenuTitle.vue";
const router = useRouter();
const tableData = ref([]);
const pageObj = ref({
total: 10,
pageSize: 10,
pageNo: 1
})
total: 10,
pageSize: 10,
pageNo: 1,
});
const handleDetails = (row: any) => {
// console.log(row);
router.push({
path: '/osTaskInformation/list',
query: {
jump: 'yes',
spiderType: row.spider,
page:'spiderManager'
}
})
}
router.push({
path: "/osTaskInformation/list",
query: {
jump: "yes",
spiderType: row.spider,
page: "spiderManager",
},
});
};
// 获取爬虫数据的方法
const getData = async () => {
const res = await getSpiderList({scrapydServerId:'1',project:'spiders'})
tableData.value = res.data
}
const res = await getSpiderList({ scrapydServerId: "1", project: "spiders" });
tableData.value = res.data;
console.log(res.data);
};
const editDialogVisible = ref(false);
const sateNoList = ref<string[]>([]);
const curSateNo = ref("");
const curSelSateNo = ref<(string | number)[]>([]);
const resetSelected = ref(false);
//添加选中项到当前列表
const handleSateAdd = (no: string | number) => {
curSelSateNo.value.push(padZeroTo5Digits(no));
};
//从当前列表删除选中项
const handleSateDel = (no: string | number) => {
curSelSateNo.value = curSelSateNo.value.filter((item) => item != no);
};
//添加编号到列表并整体发到后端
const addNoToList = async () => {
try {
if (sateNoList.value.includes(padZeroTo5Digits(curSateNo.value))) {
ElMessage.error("当前编号已存在,请重新输入");
curSateNo.value = "";
return;
}
sateNoList.value.push(padZeroTo5Digits(curSateNo.value));
const res = await addSateNo({ id: sateNoList.value });
if (res.code === 0) {
ElMessage.success("添加编号成功");
} else {
sateNoList.value.pop();
ElMessage.error(res.message);
}
curSateNo.value = "";
scrollToBottom();
} catch (error: any) {
ElMessage.error(error.message);
}
};
//删除选中编号
const delNoList = async () => {
try {
sateNoList.value = sateNoList.value.filter((item) => !curSelSateNo.value.includes(item));
const res = await addSateNo({ id: sateNoList.value as string[] });
if (res.code === 0) {
ElMessage.success("删除编号成功");
}
resetSelected.value = true;
curSelSateNo.value = [];
nextTick(() => {
resetSelected.value = false;
});
} catch (error: any) {
ElMessage.error(error.message);
}
};
const noContentRef = ref<HTMLDivElement | null>(null);
//新添加滚动到底部
const scrollToBottom = () => {
nextTick(() => {
const container = noContentRef.value;
if (container) {
container.scrollTop = container.scrollHeight - container.clientHeight;
}
});
};
const handleNumInput = (value: string) => {
const filtered = value.replace(/\D/g, "");
curSateNo.value = filtered.slice(0, 5);
};
//编号格式化
const padZeroTo5Digits = (num: number | string): string => {
const numStr = String(num);
const pureNumStr = numStr.replace(/\D/g, "");
return pureNumStr.padStart(5, "0").slice(-5);
};
const handleEditSateId = async () => {
editDialogVisible.value = true;
try {
const res = await getSateIdList();
if (res.code === 0) {
sateNoList.value = res.data || [];
}
console.log(res);
} catch (error: any) {
ElMessage.error(error.message);
}
};
onMounted(() => {
getData()
})
getData();
});
</script>
<style scoped>
/* 去除按钮边框 */
.el-button:focus {
outline: none;
outline: none;
}
.table-content {
padding: 10px;
margin-top: 30px;
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(8px);
border: 1px solid rgba(78, 237, 255, 0.2);
box-shadow: 0 0 15px rgba(78, 237, 255, 0.1);
border-radius: 8px;
padding: 15px;
}
.title {
text-align: left;
font-size: 18px;
font-weight: 500;
color: white;
}
.low-titme {
color: #ccc;
text-align: left;
margin-left: 20px;
}
.divider {
margin-top: 15px;
}
.No-Content {
width: 100%;
height: 200px;
background-color: #1d5484;
border: 4px solid #083b67;
display: flex;
padding: 10px;
box-sizing: border-box;
flex-direction: column;
gap: 10px;
overflow-y: auto;
overflow-x: hidden;
}
.footer {
margin-top: 20px;
display: flex;
justify-content: space-between;
}
.No {
display: flex;
align-items: center;
}
.No-Content::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.No-Content::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.No-Content::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.1);
}
.No-Content::-webkit-scrollbar-thumb:hover {
background: #999;
}
.No-Content::-webkit-scrollbar-button {
display: none;
}
.No-Content {
scrollbar-width: thin;
scrollbar-color: #c1c1c1 #f1f1f1;
}
.btn-group {
display: flex;
gap: 8px;
white-space: nowrap;
justify-content: center;
}
.btn-group .el-button {
flex-shrink: 0;
}
</style>
<template>
<div class="flex gap-10">
<span class="textStyle">数据统计</span>
<div class="dataCard" @click="goToAllDataPage">
<div class="titleStyle">
<span>数据统计</span>
</div>
<div class="wordStyle">
<span>总数据量: {{ totalDataNumber }}</span>
</div>
<div class="wordStyle">
<span>采集的页面数量: {{ totalPageNumber }}</span>
</div>
<div class="wordStyle">
<span>采集的目标数量: {{ totalTargetNumber }}</span>
</div>
</div>
<div class="dataCard" @click="goToTaskRecordPage">
<div class="titleStyle">
<span>任务执行统计</span>
</div>
<div class="wordStyle">
<span>任务执行成功统计: {{ successTask }}</span>
</div>
<div class="wordStyle">
<span>任务执行失败统计: {{ failTask }}</span>
</div>
<div class="wordStyle">
<span>任务异常数统计: {{ unusualTask }}</span>
</div>
</div>
<div class="dataCard">
<div class="titleStyle">
<span>性能统计</span>
</div>
<div class="wordStyle">
<span>平均成功率: {{ speed }}</span>
</div>
<div class="wordStyle">
<span>平均错误率: {{ errorRate }}</span>
</div>
<div class="wordStyle">
<span>平均异常率: {{ unusualRate }}</span>
</div>
</div>
</div>
<div class="flex">
<span class="textStyle" :class="{ toRight0: slideState }">数据统计</span>
<div class="dataCard" @click="goToAllDataPage" style="cursor: pointer">
<div class="titleStyle">
<span>数据统计</span>
</div>
<div class="items">
<div class="wordStyle">
<span>总数据量:</span>
<span class="total-num" v-if="totalDataNumber != null">{{ formatExactLargeNum(totalDataNumber) }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>采集的页面数量:</span>
<span class="total-num" v-if="totalPageNumber != null"> {{ formatExactLargeNum(totalPageNumber) }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>采集的目标数量:</span>
<span class="total-num" v-if="totalTargetNumber != null"> {{ formatExactLargeNum(totalTargetNumber) }}</span>
<span class="loading" v-else></span>
</div>
</div>
</div>
<div class="dataCard" @click="goToTaskRecordPage" style="cursor: pointer">
<div class="titleStyle">
<span>任务执行统计</span>
</div>
<div class="items">
<div class="wordStyle">
<span>任务执行成功统计:</span>
<span class="total-num" v-if="successTask != null">{{ formatExactLargeNum(successTask) }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>任务执行失败统计:</span>
<span class="total-num" v-if="failTask != null">{{ formatExactLargeNum(failTask) }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>任务异常数统计:</span>
<span class="total-num" v-if="unusualTask != null">{{ formatExactLargeNum(unusualTask) }}</span>
<span class="loading" v-else></span>
</div>
</div>
</div>
<div class="dataCard">
<div class="titleStyle">
<span>性能统计</span>
</div>
<div class="items">
<div class="wordStyle">
<span>平均成功率:</span>
<span class="total-num" v-if="speed != null"> {{ speed }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>平均错误率: </span>
<span class="total-num" v-if="errorRate != null">{{ errorRate }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>平均异常率:</span>
<span class="total-num" v-if="unusualRate != null">{{ unusualRate }}</span>
<span class="loading" v-else></span>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { useRouter } from 'vue-router';
import { getStatsDataList, getSpiderTaskList, getPerformanceList } from '@/api/staticData';
import { onMounted, ref } from 'vue';
const router = useRouter()
const totalDataNumber = ref('')
const totalPageNumber = ref('')
const totalTargetNumber = ref('')
const successTask = ref('')
const failTask = ref('')
const unusualTask = ref('')
const speed = ref('')
const errorRate = ref('')
const unusualRate = ref('')
import { useRouter } from "vue-router";
import { getStatsDataList, getSpiderTaskList, getPerformanceList } from "@/api/staticData";
import { onMounted, ref } from "vue";
import formatExactLargeNum from "@/utils/formatExactLargeNum";
import { useSlideStateStore } from "@/store/slideState";
import { storeToRefs } from "pinia";
const slideStateStore = useSlideStateStore();
const { slideState } = storeToRefs(slideStateStore);
const router = useRouter();
const totalDataNumber = ref(null);
const totalPageNumber = ref(null);
const totalTargetNumber = ref(null);
const successTask = ref(null);
const failTask = ref(null);
const unusualTask = ref(null);
const speed = ref(null);
const errorRate = ref(null);
const unusualRate = ref(null);
const goToAllDataPage = () => {
router.push({
path: '/osDataDisplay/list',
query: {
jump: 'yes',
mode: 'DSN数据'
}
})
}
router.push({
path: "/osDataDisplay/list",
query: {
jump: "yes",
mode: "DSN数据",
},
});
};
const goToTaskRecordPage = () => {
router.push({
path: '/osTaskRecord/list',
query: {
jump: 'yes',
mode: '状态监控'
}
})
}
router.push({
path: "/osTaskRecord/list",
query: {
jump: "yes",
mode: "状态监控",
},
});
};
// 获取数据统计数据的方法
const getData = async () => {
const staticData = await getStatsDataList({})
const spiderTask = await getSpiderTaskList({})
const performance = await getPerformanceList({})
totalDataNumber.value = staticData.data.totalData
totalPageNumber.value = staticData.data.ituPage
totalTargetNumber.value = staticData.data.spaceTrackItemCount
successTask.value = spiderTask.data.successCount
failTask.value = spiderTask.data.failCount
unusualTask.value = spiderTask.data.exceptionCount
speed.value = performance.data.success
errorRate.value = performance.data.error
unusualRate.value = performance.data.exception
}
const staticData = await getStatsDataList({});
const spiderTask = await getSpiderTaskList({});
const performance = await getPerformanceList({});
totalDataNumber.value = staticData.data.totalData;
totalPageNumber.value = staticData.data.ituPage;
totalTargetNumber.value = staticData.data.spaceTrackItemCount;
successTask.value = spiderTask.data.successCount;
failTask.value = spiderTask.data.failCount;
unusualTask.value = spiderTask.data.exceptionCount;
speed.value = performance.data.success;
errorRate.value = performance.data.error;
unusualRate.value = performance.data.exception;
};
//sidebarStatus
onMounted(() => {
getData();
})
getData();
});
</script>
<style lang="scss" scoped>
.dataCard {
background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
// background: #c6ebfc;
// border: 1.5px solid rgb(193, 188, 188);
width: 360px;
height: 100%;
border-radius: 5px;
background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
// background: #c6ebfc;
// border: 1.5px solid rgb(193, 188, 188);
width: 500px;
border-radius: 5px;
}
/* 标题区 */
.titleStyle {
font-size: 30px;
margin-top: 5%;
color: #FFFFFF;
color: #dff6ff;
font-size: 18px;
font-weight: 600;
text-align: center;
text-shadow: 0 0 8px rgba(100, 200, 255, 0.8);
letter-spacing: 2px;
margin-top: 15px;
}
.wordStyle {
font-size: 20px;
color: #FFFFFF;
margin-top: 2%;
font-size: 18px;
color: #ffffff;
margin-top: 1%;
display: flex;
margin-left: 15px;
display: flex;
justify-content: space-between;
}
.textStyle {
writing-mode: vertical-lr;
font-size: 26px;
letter-spacing: 3px;
margin-left: 0.5%;
color: #FFFFFF;
// display: flex;
writing-mode: vertical-lr;
font-size: 22px;
letter-spacing: 3px;
color: #ffffff;
font-weight: 500;
transform: translateX(-30px);
transition: 0.2s;
}
.total-num {
color: #4edaff;
font-size: 16px;
font-weight: 600;
text-shadow: 0 0 10px rgba(0, 200, 255, 0.5);
letter-spacing: 1px;
margin-right: 30px;
animation: visible 0.6s;
}
@keyframes visible {
0% {
opacity: 0;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
.toRight0 {
transform: translateX(-10px);
}
.items {
display: flex;
flex-direction: column;
padding-left: 15px;
padding-top: 20px;
}
.loading {
width: 40px;
aspect-ratio: 2;
margin-right: 30px;
--_g: no-repeat radial-gradient(circle closest-side, #4edaff 90%, #0000);
background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%;
background-size: calc(100% / 3) 50%;
animation: l3 1s infinite linear;
}
@keyframes l3 {
20% {
background-position: 0% 0%, 50% 50%, 100% 50%;
}
40% {
background-position: 0% 100%, 50% 0%, 100% 50%;
}
60% {
background-position: 0% 50%, 50% 100%, 100% 0%;
}
80% {
background-position: 0% 50%, 50% 50%, 100% 100%;
}
}
</style>
<template>
<div class="flex gap-10">
<span class="textStyle">QB数据管理</span>
<!-- <div class="dataCard" @click="goToAllDataPage">
<div class="titleStyle">
<span>综合数据</span>
</div>
<div class="iconStyle" />
</div> -->
<div class="dataCard" @click="goToDSNDataPage">
<div class="titleStyle">
<span>DSN数据</span>
</div>
<div class="iconStyle" />
</div>
<div class="dataCard" @click="goToITUDataPage">
<div class="titleStyle">
<span>ITU数据</span>
</div>
<div class="iconStyle" />
</div>
<div class="dataCard" @click="goToSTDataPage">
<div class="titleStyle">
<span>ST数据</span>
</div>
<div class="iconStyle" />
</div>
</div>
<div class="flex">
<span class="textStyle" :class="{ toRight0: !slideState }">数据管理</span>
<div class="dataCard" @click="goToDSNDataPage">
<div class="titleStyle">
<span>DSN数据</span>
</div>
<div class="iconStyle" />
</div>
<div class="dataCard" @click="goToITUDataPage">
<div class="titleStyle">
<span>ITU数据</span>
</div>
<div class="iconStyle" />
</div>
<div class="dataCard" @click="goToSTDataPage">
<div class="titleStyle">
<span>ST数据</span>
</div>
<div class="iconStyle" />
</div>
<div class="dataCard" @click="goToESADataPage">
<div class="titleStyle">
<span>ESA数据</span>
</div>
<div class="iconStyle" />
</div>
</div>
</template>
<script lang="ts" setup>
import { useRouter } from 'vue-router'
const router = useRouter()
import { useRouter } from "vue-router";
import { storeToRefs } from "pinia";
import { useSlideStateStore } from "@/store/slideState";
const slideStateStore = useSlideStateStore();
const { slideState } = storeToRefs(slideStateStore);
const router = useRouter();
defineProps({
totalDataNumber: {
type: String,
default: ''
},
totalPageNumber: {
type: String,
default: ''
},
totalTargetNumber: {
type: String,
default: ''
},
successTask: {
type: String,
default: ''
},
failTask: {
type: String,
default: ''
},
unusualTask: {
type: String,
default: ''
},
speed: {
type: String,
default: ''
},
errorRate: {
type: String,
default: ''
}
})
totalDataNumber: {
type: String,
default: "",
},
totalPageNumber: {
type: String,
default: "",
},
totalTargetNumber: {
type: String,
default: "",
},
successTask: {
type: String,
default: "",
},
failTask: {
type: String,
default: "",
},
unusualTask: {
type: String,
default: "",
},
speed: {
type: String,
default: "",
},
errorRate: {
type: String,
default: "",
},
});
const goToAllDataPage = () => {
router.push({
path: '/osDataDisplay/list',
query: {
mode: '综合数据',
jump: 'yes'
}
})
}
router.push({
path: "/osDataDisplay/list",
query: {
mode: "综合数据",
jump: "yes",
},
});
};
const goToDSNDataPage = () => {
router.push({
path: '/osDataDisplay/list',
query: {
mode: 'DSN数据',
jump: 'yes'
}
})
}
router.push({
path: "/osDataDisplay/list",
query: {
mode: "DSN数据",
jump: "yes",
},
});
};
const goToITUDataPage = () => {
router.push({
path: '/osDataDisplay/list',
query: {
mode: 'ITU数据',
jump: 'yes'
}
})
}
router.push({
path: "/osDataDisplay/list",
query: {
mode: "ITU数据",
jump: "yes",
},
});
};
const goToSTDataPage = () => {
router.push({
path: '/osDataDisplay/list',
query: {
mode: 'ST数据',
jump: 'yes'
}
})
}
router.push({
path: "/osDataDisplay/list",
query: {
mode: "ST数据",
jump: "yes",
},
});
};
const goToESADataPage = () => {
router.push({
path: "/osDataDisplay/list",
query: {
mode: "ESA数据",
jump: "yes",
},
});
};
</script>
<style lang="scss" scoped>
.iconStyle {
background-image: url("@/assets/picture/wenjianjia.png");
background-size: 100% 120%;
background-repeat: no-repeat;
margin-top: -5%;
display: flex;
// border: 1.5px solid rgb(193, 188, 188);
height: 65%;
width: 50%;
background-image: url("@/assets/picture/data-icon.svg");
background-size: 100% 100%;
background-repeat: no-repeat;
margin-top: 5%;
display: flex;
// border: 1.5px solid rgb(193, 188, 188);
height: 65%;
width: 50%;
}
.dataCard {
background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
// background: #c6ebfc;
// border: 1.5px solid rgb(193, 188, 188);
width: 360px;
height: 100%;
border-radius: 5px;
display: flex;
flex-direction: column;
// justify-content: center;
align-items: center;
cursor: pointer;
background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
// background: #c6ebfc;
// border: 1.5px solid rgb(193, 188, 188);
width: 375px;
height: 100%;
border-radius: 5px;
display: flex;
flex-direction: column;
// justify-content: center;
align-items: center;
}
.titleStyle {
font-size: 30px;
margin-top: 5%;
color: #FFFFFF;
color: #dff6ff;
font-size: 18px;
font-weight: 600;
text-align: center;
text-shadow: 0 0 8px rgba(100, 200, 255, 0.8);
letter-spacing: 2px;
margin-top: 15px;
}
.wordStyle {
font-size: 20px;
color: #FFFFFF;
margin-top: 2%;
font-size: 20px;
color: #ffffff;
margin-top: 2%;
}
.textStyle {
writing-mode: vertical-lr;
font-size: 26px;
letter-spacing: 3px;
margin-left: 0.5%;
color: #FFFFFF;
// display: flex;
writing-mode: vertical-lr;
font-size: 22px;
letter-spacing: 3px;
color: #ffffff;
font-weight: 500;
transform: translateX(-10px);
transition: 0.2s;
}
.toRight0 {
transform: translateX(-25px);
}
</style>
......@@ -18,28 +18,26 @@
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import dataCard from './dataCard.vue'
import taskCard from '@/views/os-status/components/taskCard.vue';
import qbCard from '@/views/os-status/components/qbDataMonitor.vue';
import { onMounted } from 'vue';
import dataCard from "./dataCard.vue";
import taskCard from "@/views/os-status/components/taskCard.vue";
import qbCard from "@/views/os-status/components/qbDataMonitor.vue";
import { onMounted } from "vue";
defineProps({
title: {
type: String,
default: ''
default: "",
},
desc: {
type: String,
default: ''
}
})
default: "",
},
});
onMounted(() => {
})
onMounted(() => {});
</script>
<style lang="scss" scoped>
......@@ -51,26 +49,24 @@ onMounted(() => {
align-items: center;
padding: 10px;
gap: 30px;
}
.monitoringCard {
background-image: url("@/assets/picture/box1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
height: 22.5vh;
height: 20vh;
width: 96%;
display: flex;
gap: 21.5px;
padding: 10px;
}
.taskCard {
background-image: url("@/assets/picture/box1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
height: 26.5vh;
height: 25vh;
width: 96%;
display: flex;
gap: 21.5px;
......@@ -92,7 +88,7 @@ onMounted(() => {
font-size: 26px;
letter-spacing: 3px;
margin-left: 2%;
color: #FFFFFF;
color: #ffffff;
// display: flex;
}
......@@ -102,6 +98,5 @@ onMounted(() => {
justify-content: center;
/* 水平居中 */
// gap: 20px;
}
</style>
\ No newline at end of file
</style>
<template>
<div class="flex gap-10">
<span class="textStyle">任务统计</span>
<div class="dataCard" @click="goToDSNTaskRecordPage">
<div class="titleStyle">
<span>DSN爬取任务</span>
</div>
<div class="wordStyle">
<span>DSN爬虫任务数: {{ dsnTotalTaskNumber }} </span>
</div>
<div class="wordStyle">
<span>任务执行成功统计: {{ dsnTaskSuccessNumber }} </span>
</div>
<div class="wordStyle">
<span>任务执行失败统计: {{ dsnTaskFailNumber }} </span>
</div>
<div class="wordStyle">
<span>错误率: {{ dsnErrorRate }} </span>
</div>
</div>
<div class="dataCard" @click="goToITUTaskRecordPage">
<div class="titleStyle">
<span>ITU爬取任务</span>
</div>
<div class="wordStyle">
<span>ITU爬虫任务数: {{ ituTotalTaskNumber }} </span>
</div>
<div class="wordStyle">
<span>任务执行成功统计: {{ ituTaskSuccessNumber }} </span>
</div>
<div class="wordStyle">
<span>任务执行失败统计: {{ ituTaskFailNumber }} </span>
</div>
<div class="wordStyle">
<span>错误率: {{ ituErrorRate }} </span>
</div>
</div>
<div class="dataCard" @click="goToSTTaskRecordPage">
<div class="titleStyle">
<span>ST爬取任务</span>
</div>
<div class="wordStyle">
<span>ST爬虫任务数: {{ stTotalTaskNumber }} </span>
</div>
<div class="wordStyle">
<span>任务执行成功统计: {{ stTaskSuccessNumber }} </span>
</div>
<div class="wordStyle">
<span>采集速度: {{ stTaskFailNumber }} </span>
</div>
<div class="wordStyle">
<span>错误率: {{ stErrorRate }} </span>
</div>
</div>
</div>
<div class="flex">
<span class="textStyle" :class="{ toRight0: slideState }">任务统计</span>
<div class="dataCard" @click="goToDSNTaskRecordPage">
<div class="titleStyle">
<span>DSN爬取任务</span>
</div>
<div class="items">
<div class="wordStyle">
<span>DSN爬虫任务数:</span>
<span class="total-num" v-if="dsnTotalTaskNumber != null">{{ dsnTotalTaskNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>任务执行成功统计:</span>
<span class="total-num" v-if="dsnTaskSuccessNumber != null">{{ dsnTaskSuccessNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>任务执行失败统计:</span>
<span class="total-num" v-if="dsnTaskFailNumber != null">{{ dsnTaskFailNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>错误率: {{ dsnErrorRate }} </span>
<span class="total-num" v-if="dsnErrorRate != null">{{ dsnErrorRate }}</span>
<span class="loading" v-else></span>
</div>
</div>
</div>
<div class="dataCard" @click="goToITUTaskRecordPage">
<div class="titleStyle">
<span>ITU爬取任务</span>
</div>
<div class="items">
<div class="wordStyle">
<span>ITU爬虫任务数:</span>
<span class="total-num" v-if="ituTotalTaskNumber != null">{{ ituTotalTaskNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>任务执行成功统计:</span>
<span class="total-num" v-if="ituTaskSuccessNumber != null">{{ ituTaskSuccessNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>任务执行失败统计:</span>
<span class="total-num" v-if="ituTaskFailNumber != null">{{ ituTaskFailNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>任务执行失败统计:</span>
<span class="total-num" v-if="ituTaskFailNumber != null">{{ ituTaskFailNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>错误率:</span>
<span class="total-num" v-if="ituErrorRate != null">{{ ituErrorRate }}</span>
<span class="loading" v-else></span>
</div>
</div>
</div>
<div class="dataCard" @click="goToSTTaskRecordPage">
<div class="titleStyle">
<span>ST爬取任务</span>
</div>
<div class="items">
<div class="wordStyle">
<span>ST爬虫任务数:</span>
<span class="total-num" v-if="stTotalTaskNumber != null">{{ stTotalTaskNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>任务执行成功统计:</span>
<span class="total-num" v-if="stTaskSuccessNumber != null">{{ stTaskSuccessNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>采集速度:</span>
<span class="total-num" v-if="stTaskFailNumber != null">{{ stTaskFailNumber }}</span>
<span class="loading" v-else></span>
</div>
<div class="wordStyle">
<span>错误率:</span>
<span class="total-num" v-if="stErrorRate != null">{{ stErrorRate }}</span>
<span class="loading" v-else></span>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { useRouter } from 'vue-router'
import { getAllSpiderTaskStatistics } from '@/api/staticData';
import { onMounted,ref } from 'vue';
import { getSpiderTaskList } from '@/api/spiderTask'
import { useRouter } from "vue-router";
import { getAllSpiderTaskStatistics } from "@/api/staticData";
import { onMounted, ref } from "vue";
import { getSpiderTaskList } from "@/api/spiderTask";
import { useSlideStateStore } from "@/store/slideState";
import { storeToRefs } from "pinia";
const router = useRouter()
const slideStateStore = useSlideStateStore();
const { slideState } = storeToRefs(slideStateStore);
const dsnTotalTaskNumber = ref('')
const dsnTaskSuccessNumber = ref('')
const dsnTaskFailNumber = ref('')
const dsnErrorRate = ref('')
const ituTotalTaskNumber = ref('')
const ituTaskSuccessNumber = ref('')
const ituTaskFailNumber = ref('')
const ituErrorRate = ref('')
const stTotalTaskNumber = ref('')
const stTaskSuccessNumber = ref('')
const stTaskFailNumber = ref('')
const stErrorRate = ref('')
const router = useRouter();
const dsnTotalTaskNumber = ref(null);
const dsnTaskSuccessNumber = ref(null);
const dsnTaskFailNumber = ref(null);
const dsnErrorRate = ref(null);
const ituTotalTaskNumber = ref(null);
const ituTaskSuccessNumber = ref(null);
const ituTaskFailNumber = ref(null);
const ituErrorRate = ref(null);
const stTotalTaskNumber = ref(null);
const stTaskSuccessNumber = ref(null);
const stTaskFailNumber = ref(null);
const stErrorRate = ref(null);
const goToDSNTaskRecordPage = () => {
router.push({
path: '/osTaskInformation/list',
query: {
spiderType: 'dsn_now',
jump: 'yes',
page: 'statusMonitor'
}
})
}
router.push({
path: "/osTaskInformation/list",
query: {
spiderType: "dsn_now",
jump: "yes",
page: "statusMonitor",
},
});
};
const goToITUTaskRecordPage = () => {
router.push({
path: '/osTaskInformation/list',
query: {
spiderType: 'itu_space_explorer',
jump: 'yes',
page: 'statusMonitor'
}
})
}
router.push({
path: "/osTaskInformation/list",
query: {
spiderType: "itu_space_explorer",
jump: "yes",
page: "statusMonitor",
},
});
};
const goToSTTaskRecordPage = () => {
router.push({
path: '/osTaskInformation/list',
query: {
spiderType: 'api_spider',
jump: 'yes',
page: 'statusMonitor'
}
})
}
router.push({
path: "/osTaskInformation/list",
query: {
spiderType: "api_spider",
jump: "yes",
page: "statusMonitor",
},
});
};
// 获取任务统计数据的方法
const getData = async () => {
const res = await getAllSpiderTaskStatistics({})
const dsnTask = await getSpiderTaskList({ spiders: 'dsn_now' })
const ituTask = await getSpiderTaskList({ spiders: 'itu_space_explorer' })
const stTask = await getSpiderTaskList({ spiders: 'api_spider' })
dsnTotalTaskNumber.value = dsnTask.data.length
dsnTaskSuccessNumber.value = res.data.dsn_now.successCount
dsnTaskFailNumber.value = res.data.dsn_now.failCount
dsnErrorRate.value = res.data.dsn_now.errorRate
ituTotalTaskNumber.value = ituTask.data.length
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 = stTask.data.length
stTaskSuccessNumber.value = res.data.space_track.successCount
stTaskFailNumber.value = res.data.space_track.failCount
stErrorRate.value = res.data.space_track.errorRate
}
const res = await getAllSpiderTaskStatistics({});
const dsnTask = await getSpiderTaskList({ spiders: "dsn_now" });
const ituTask = await getSpiderTaskList({ spiders: "itu_space_explorer" });
const stTask = await getSpiderTaskList({ spiders: "api_spider" });
dsnTotalTaskNumber.value = dsnTask.data.length;
dsnTaskSuccessNumber.value = res.data.dsn_now.successCount;
dsnTaskFailNumber.value = res.data.dsn_now.failCount;
dsnErrorRate.value = res.data.dsn_now.errorRate;
ituTotalTaskNumber.value = ituTask.data.length;
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 = stTask.data.length;
stTaskSuccessNumber.value = res.data.space_track.successCount;
stTaskFailNumber.value = res.data.space_track.failCount;
stErrorRate.value = res.data.space_track.errorRate;
};
onMounted(() => {
getData()
})
getData();
});
</script>
<style lang="scss" scoped>
.dataCard {
background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
// background: #c6ebfc;
// border: 1.5px solid rgb(193, 188, 188);
width: 360px;
height: 100%;
border-radius: 5px;
background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
// background: #c6ebfc;
// border: 1.5px solid rgb(193, 188, 188);
width: 500px;
height: 100%;
border-radius: 5px;
cursor: pointer;
}
.titleStyle {
font-size: 30px;
margin-top: 5%;
color: #FFFFFF;
color: #dff6ff;
font-size: 18px;
font-weight: 600;
text-align: center;
text-shadow: 0 0 8px rgba(100, 200, 255, 0.8);
letter-spacing: 2px;
margin-top: 15px;
}
.wordStyle {
font-size: 20px;
color: #FFFFFF;
margin-top: 2%;
font-size: 18px;
color: #ffffff;
margin-top: 1%;
display: flex;
margin-left: 15px;
display: flex;
justify-content: space-between;
}
.textStyle {
writing-mode: vertical-lr;
font-size: 26px;
letter-spacing: 3px;
margin-left: 0.5%;
color: #FFFFFF;
// display: flex;
writing-mode: vertical-lr;
font-size: 22px;
letter-spacing: 3px;
color: #ffffff;
font-weight: 500;
transform: translateX(-25px);
transition: 0.2s;
}
.total-num {
color: #4edaff;
font-size: 16px;
font-weight: 600;
text-shadow: 0 0 10px rgba(0, 200, 255, 0.5);
letter-spacing: 1px;
margin-right: 30px;
animation: visible 0.6s;
}
.toRight0 {
transform: translateX(-10px);
}
.items {
display: flex;
flex-direction: column;
padding-left: 15px;
padding-top: 20px;
}
.loading {
width: 40px;
aspect-ratio: 2;
margin-right: 30px;
--_g: no-repeat radial-gradient(circle closest-side, #4edaff 90%, #0000);
background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%;
background-size: calc(100% / 3) 50%;
animation: l3 1s infinite linear;
}
@keyframes l3 {
20% {
background-position: 0% 0%, 50% 50%, 100% 50%;
}
40% {
background-position: 0% 100%, 50% 0%, 100% 50%;
}
60% {
background-position: 0% 50%, 50% 100%, 100% 0%;
}
80% {
background-position: 0% 50%, 50% 50%, 100% 100%;
}
}
@keyframes visible {
0% {
opacity: 0;
}
50% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
</style>
<template>
<div>
<MenuTitle title="状态监控" subtitle="Status Monitor" />
<div>
<div class="text-left timeStyle" />
<div class="border-100">
......@@ -7,11 +8,11 @@
</div>
</div>
</div>
</template>
<script setup lang="ts">
import statusMonitor from './components/statusMonitor.vue'
import statusMonitor from "./components/statusMonitor.vue";
import MenuTitle from "@/components/MenuTitle.vue";
</script>
<style lang="scss" scoped>
......@@ -26,5 +27,18 @@ import statusMonitor from './components/statusMonitor.vue'
border: 1.5px solid rgb(193, 188, 188);
}
.title {
text-align: left;
font-size: 18px;
font-weight: 500;
color: white;
}
.low-titme {
color: #ccc;
text-align: left;
margin-left: 20px;
}
.divider {
margin-top: 15px;
}
</style>
<template>
<div>
<div class="text-left p-8">
<el-form inline>
<el-form-item>
<el-button test-element="userSystem-AddUser" type="primary" plain @click="openAddUserDialog">创建用户</el-button>
</el-form-item>
<el-form-item>
<el-button type="danger" plain @click="handleBatchDelete">批量删除</el-button>
</el-form-item>
</el-form>
</div>
<el-table :data="tableData" style="width: 100%" border :header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }" :row-style="{ height: '58px' }"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="40" />
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="username" label="用户账号" show-overflow-tooltip />
<el-table-column property="nickname" label="用户名称" show-overflow-tooltip />
<el-table-column property="create_time" label="创建时间" width="280" show-overflow-tooltip />
<el-table-column label="操作" width="220">
<template #default="scope">
<el-button type="primary" plain @click="handleEdit(scope.row)" id="editUser">
编辑
</el-button>
<el-button type="danger" plain @click="handleDelete(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
@pagination="getUserListData" />
</div>
<!-- 删除弹窗组件 -->
<deleteDialog v-model:dialogVisible="showDeleteDialog" @get-user-list="getUserListData"
:ids="userIds" :deleteMode="deleteMode" :id="userId" />
<!-- 创建用户弹窗组件 -->
<addUserDialog v-model:dialogVisible="dialogVisible" :mode="mode" :nickName="nickName" :userName="userName"
:id="userId" :userRole="userRole" :userStatus="userStatus" :userPassword="userPassword"
@get-user-list="getUserListData" />
</div>
<div class="sys-content">
<MenuTitle title="系统管理" subtitle="System Manager" />
<el-card>
<div class="btns">
<el-button test-element="userSystem-AddUser" type="primary" plain @click="openAddUserDialog"
>创建用户</el-button
>
<el-button type="danger" plain @click="handleBatchDelete">批量删除</el-button>
</div>
</el-card>
<div class="table-content">
<el-table
:data="tableData"
border
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
:row-style="{ height: '58px' }"
@selection-change="handleSelectionChange"
v-loading="tableData?.length == 0"
element-loading-background="rgba(48, 65, 86, 0.7)"
>
<el-table-column type="selection" width="40" />
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="username" label="用户账号" show-overflow-tooltip />
<el-table-column property="nickname" label="用户名称" show-overflow-tooltip />
<el-table-column property="role" label="用户角色" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.role == 1 ? "管理员" : "普通用户" }}
</template>
</el-table-column>
<el-table-column property="status" label="用户状态" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.status ? "启用" : "停用" }}
</template>
</el-table-column>
<el-table-column property="create_time" label="创建时间" width="280" show-overflow-tooltip />
<el-table-column label="操作" width="220">
<template #default="scope">
<el-button type="primary" plain @click="handleEdit(scope.row)" id="editUser"> 编辑 </el-button>
<el-button type="danger" plain @click="handleDelete(scope.row)"> 删除 </el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination
:total="pageObj.total"
v-model:page="pageObj.pageNo"
v-model:limit="pageObj.pageSize"
@pagination="getUserListData"
/>
</div>
</div>
<!-- 删除弹窗组件 -->
<deleteDialog
v-model:dialogVisible="showDeleteDialog"
@get-user-list="getUserListData"
:ids="userIds"
:deleteMode="deleteMode"
:id="userId"
/>
<!-- 创建用户弹窗组件 -->
<addUserDialog
v-model:dialogVisible="dialogVisible"
:mode="mode"
:nickName="nickName"
:userName="userName"
:id="userId"
:userRole="userRole"
:userStatus="userStatus"
:userPassword="userPassword"
@get-user-list="getUserListData"
/>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import deleteDialog from '@/components/Delete/index.vue'
import addUserDialog from './components/addUserDialog.vue'
import { getUserList } from '@/api/user.ts'
import { DeleteMode } from '@/components/Delete/enum.ts'
import { AddMode } from './components/enum.ts';
import { ElMessage } from 'element-plus'
const userId = ref<any>([])
const userIds = ref<any>()
const nickName = ref<string>('')
const userName = ref<string>('')
const userRole = ref<number>(0)
const userStatus = ref<boolean>(true)
const userPassword = ref<string>('')
const showDeleteDialog = ref(false)
const deleteMode = ref<DeleteMode>(DeleteMode.SINGLE_DELETE)
const dialogVisible = ref<boolean>(false)
const mode = ref<AddMode>(AddMode.ADD_MODE)
const tableData = ref()
import { ref, onMounted } from "vue";
import Pagination from "@/components/pagination/index.vue";
import deleteDialog from "@/components/Delete/index.vue";
import addUserDialog from "./components/addUserDialog.vue";
import { getUserList } from "@/api/user.ts";
import { DeleteMode } from "@/components/Delete/enum.ts";
import { AddMode } from "./components/enum.ts";
import { ElMessage } from "element-plus";
import MenuTitle from "@/components/MenuTitle.vue";
const userId = ref<number>(-1);
const userIds = ref<number[]>([]);
const nickName = ref<string>("");
const userName = ref<string>("");
const userRole = ref<number>(0);
const userStatus = ref<boolean>(true);
const userPassword = ref<string>("");
const showDeleteDialog = ref(false);
const deleteMode = ref<DeleteMode>(DeleteMode.SINGLE_DELETE);
const dialogVisible = ref<boolean>(false);
const mode = ref<AddMode>(AddMode.ADD_MODE);
const tableData = ref([]);
const pageObj = ref({
total: 0,
pageSize: 10,
pageNo: 1
})
total: 0,
pageSize: 10,
pageNo: 1,
});
// 编辑用户信息的方法
const handleEdit = async (row: any) => {
mode.value = AddMode.UPDATE_MODE
nickName.value = row.nickname
userName.value = row.username
userRole.value = row.role
userStatus.value = row.status
userPassword.value = row.password
dialogVisible.value = true
userId.value = row.id
}
mode.value = AddMode.UPDATE_MODE;
nickName.value = row.nickname;
userName.value = row.username;
userRole.value = row.role;
userStatus.value = row.status;
userPassword.value = row.password;
dialogVisible.value = true;
userId.value = row.id;
};
// 弹窗关闭的方法
const handleDelete = async (row: any) => {
showDeleteDialog.value = true
deleteMode.value = DeleteMode.SINGLE_DELETE
userId.value = row.id
console.log(userId.value);
}
showDeleteDialog.value = true;
deleteMode.value = DeleteMode.SINGLE_DELETE;
userId.value = row.id;
};
// 批量删除用户的方法
const handleBatchDelete = async () => {
if(userIds.value == undefined){
ElMessage({
message: '请先选择要删除的用户',
type: 'warning'
})
return
}else{
deleteMode.value = DeleteMode.BATCH_DELETE
showDeleteDialog.value = true
}
}
if (!userIds.value || userIds.value.length === 0) {
ElMessage({
message: "请先选择要删除的用户",
type: "warning",
});
return;
} else {
deleteMode.value = DeleteMode.BATCH_DELETE;
showDeleteDialog.value = true;
}
};
// 多选框改变后的方法
const handleSelectionChange = (data: any) => {
let array = []
for (let i = 0; i < data.length; i++) {
array.push(data[i].id)
}
userIds.value = array
}
let array = [];
for (let i = 0; i < data.length; i++) {
array.push(data[i].id);
}
userIds.value = array;
};
const openAddUserDialog = () => {
mode.value = AddMode.ADD_MODE
dialogVisible.value = true
}
mode.value = AddMode.ADD_MODE;
dialogVisible.value = true;
};
// 获取用户列表数据的方法
const getUserListData = async () => {
const userList = await getUserList({
page: pageObj.value.pageNo,
size: pageObj.value.pageSize
})
tableData.value = userList.data.list
pageObj.value.total = userList.data.total
console.log(userList);
}
const userList = await getUserList({
page: pageObj.value.pageNo,
size: pageObj.value.pageSize,
});
tableData.value = userList.data.list;
pageObj.value.total = userList.data.total;
};
onMounted(async () => {
getUserListData()
})
getUserListData();
});
</script>
<style scoped>
/* 去除按钮边框 */
.el-button:focus {
outline: none;
outline: none;
}
.title {
text-align: left;
font-size: 18px;
font-weight: 500;
color: white;
}
.low-titme {
color: #ccc;
text-align: left;
margin-left: 20px;
}
.divider {
margin-top: 15px;
}
.btns {
display: flex;
justify-content: end;
}
</style>
<style>
/* 修改弹窗样式 */
.el-dialog {
background-image: url("@/assets/picture/dialog1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url("@/assets/picture/dialog1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
.el-dialog__title {
color: #ffffff;
}
.el-dialog__title {
color: #ffffff;
}
}
/* 修改el输入框的样式 */
.el-input__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
.table-content {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(8px);
border: 1px solid rgba(78, 237, 255, 0.2);
box-shadow: 0 0 15px rgba(78, 237, 255, 0.1);
border-radius: 8px;
padding: 10px !important;
}
</style>
<template>
<el-dialog v-model="currentVisible" :title="currentMode === AddMode.ADD_TASK ? '新增' : '修改'" width="710" center
align-center @close="handleClose" draggable>
<el-form :model="ruleForm" :rules="rules" ref="ruleFormRef" label-width="100px">
<el-form-item label="任务名称:" v-if="currentMode === AddMode.ADD_TASK" prop="taskName">
<el-input v-model="ruleForm.taskName" placeholder="请输入任务名称" style="width: 90%" />
</el-form-item>
<el-form-item label="所属爬虫:" v-if="currentMode === AddMode.ADD_TASK" prop="spiderTypeValue">
<el-select v-model="ruleForm.spiderTypeValue" placeholder="请选择所属爬虫" style="width: 90%" >
<el-option v-for="item in spiderTypeOptions" :key="item.spider" :label="item.spider"
:value="item.spider" :id="item.spider" />
</el-select>
</el-form-item>
<el-form-item label="执行频率:" prop="cronExpression">
<Crontab v-model="ruleForm.cronExpression" style="width: 90%" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleConfirm">
确定
</el-button>
</div>
</template>
</el-dialog>
<el-dialog
v-model="currentVisible"
:title="currentMode === AddMode.ADD_TASK ? '新增' : '修改'"
width="710"
center
align-center
@close="handleClose"
draggable
>
<el-form :model="ruleForm" :rules="rules" ref="ruleFormRef" label-width="100px">
<el-form-item label="任务名称:" v-if="currentMode === AddMode.ADD_TASK" prop="taskName">
<el-input v-model="ruleForm.taskName" placeholder="请输入任务名称" style="width: 90%" />
</el-form-item>
<el-form-item label="所属爬虫:" v-if="currentMode === AddMode.ADD_TASK" prop="spiderTypeValue">
<el-select v-model="ruleForm.spiderTypeValue" placeholder="请选择所属爬虫" style="width: 90%">
<el-option
v-for="item in spiderTypeOptions"
:key="item.spider"
:label="item.spider"
:value="item.spider"
:id="item.spider"
/>
</el-select>
</el-form-item>
<el-form-item label="执行频率:">
<!-- <Crontab v-model="ruleForm.cronExpression" style="width: 90%"/> -->
<div class="gap-units">
<div class="gap-unit">
<el-input-number
v-model="exGaps.day"
class="gap-ipt"
:min="0"
:precision="0"
size="small"
></el-input-number>
<span class="unit-num"></span>
</div>
<div class="gap-unit">
<el-input-number
v-model="exGaps.hour"
class="gap-ipt"
:min="0"
:precision="0"
size="small"
></el-input-number>
<span class="unit-num">小时</span>
</div>
<div class="gap-unit">
<el-input-number
v-model="exGaps.minute"
class="gap-ipt"
:min="0"
:precision="0"
size="small"
></el-input-number>
<span class="unit-num">分钟</span>
</div>
<div class="gap-unit">
<el-input-number
v-model="exGaps.second"
class="gap-ipt"
:min="0"
:precision="2"
size="small"
></el-input-number>
<span class="unit-num"></span>
</div>
</div>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleConfirm"> 确定 </el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { defineProps } from 'vue';
import { watch } from 'vue'
import { addSpiderTask } from '@/api/spiderTask'
import { AddMode } from './enum'
import { Crontab } from '@/components/Crontab/index'
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage } from 'element-plus'
import { getSpiderList } from '@/api/system.ts'
import { onMounted, reactive, ref } from "vue";
import { defineProps } from "vue";
import { watch } from "vue";
import { addSpiderTask } from "@/api/spiderTask";
import { AddMode } from "./enum";
import type { FormInstance, FormRules } from "element-plus";
import { ElMessage } from "element-plus";
import { getSpiderList } from "@/api/system.ts";
interface RuleForm {
taskName: string
spiderTypeValue: string
cronExpression: string
taskName: string;
spiderTypeValue: string;
}
const ruleFormRef = ref<FormInstance>()
const ruleFormRef = ref<FormInstance>();
const ruleForm = ref<RuleForm>({
taskName: '',
spiderTypeValue: '',
cronExpression: '',
})
taskName: "",
spiderTypeValue: "",
});
interface addDialogPropType {
dialogVisible: boolean,
mode: AddMode,
jobId: string,
cron: string,
spiderType: string,
options: string,
dialogVisible: boolean;
mode: AddMode;
jobId: string;
exGap: number[];
spiderType: string;
options: string;
}
const props = defineProps<addDialogPropType>()
const props = defineProps<addDialogPropType>();
const rules = ref<FormRules<RuleForm>>({
taskName: [
{ required: true, message: '请输入任务名称', trigger: 'blur' },
{ min: 2, max: 50, message: '任务名称应在2-20个字符之间', trigger: 'blur' },
],
spiderTypeValue: [
{
required: true,
message: '请选择所属爬虫',
trigger: 'change',
},
],
cronExpression: [
{
required: true,
message: '请输入执行频率',
trigger: 'change',
},
{
validator: (rule, value, callback) => {
// 计算字符串中'*'的数量
const starCount = (value.match(/\//g) || []).length;
if (starCount > 1) {
callback(new Error('cron表达式最多设置一个间隔'));
}else if(starCount == 0){
callback(new Error('请设置cron表达式'));
}else {
callback();
}
},
trigger: 'blur'
}
]
})
taskName: [
{ required: true, message: "请输入任务名称", trigger: "blur" },
{ min: 2, max: 50, message: "任务名称应在2-20个字符之间", trigger: "blur" },
],
spiderTypeValue: [
{
required: true,
message: "请选择所属爬虫",
trigger: "change",
},
],
});
// 向父组件传递dialog值
const emit = defineEmits(['update:dialogVisible', 'confirm', 'update:mode', 'getTaskList'])
const emit = defineEmits(["update:dialogVisible", "confirm", "update:mode", "getTaskList"]);
// 组件的状态
const currentVisible = ref(props.dialogVisible)
const currentMode = ref(props.mode)
const spiderTypeOptions = ref()
const currentVisible = ref(props.dialogVisible);
const currentMode = ref(props.mode);
const spiderTypeOptions = ref();
const taskParams = ref({
scrapyd_server_id: '1',
schedule_type: '0',
project: 'spiders'
})
const cronExpression = ref('')
scrapyd_server_id: "1",
schedule_type: "0",
project: "spiders",
});
// 关闭的方法
const handleClose = () => {
ruleForm.value.taskName = ''
ruleForm.value.spiderTypeValue
ruleForm.value.cronExpression = ''
ruleFormRef.value?.resetFields()
currentVisible.value = false
}
ruleForm.value.taskName = "";
ruleForm.value.spiderTypeValue;
ruleFormRef.value?.resetFields();
currentVisible.value = false;
};
//间隔数据
const exGaps = reactive({
second: 0,
minute: 0,
hour: 0,
day: 0,
});
// 确定的方法
const handleConfirm = async () => {
console.log(ruleForm.value.cronExpression);
if (!ruleFormRef.value) return
await ruleFormRef.value.validate(async (valid, fields) => {
console.log('开始校验');
//验证表单内容是否通过,通过继续执行
if (valid) {
if (currentMode.value === AddMode.ADD_TASK) {
await addSpiderTask({
scrapyd_server_id: taskParams.value.scrapyd_server_id,
schedule_type: taskParams.value.schedule_type,
project: taskParams.value.project,
spider: ruleForm.value.spiderTypeValue,
cron: ruleForm.value.cronExpression,
options: JSON.stringify({ jobName: ruleForm.value.taskName })
})
currentVisible.value = false
emit('getTaskList')
ElMessage.success('添加成功')
} else if (currentMode.value === AddMode.UPDATE_TASK) {
await addSpiderTask({
scrapyd_server_id: taskParams.value.scrapyd_server_id,
schedule_type: taskParams.value.schedule_type,
project: taskParams.value.project,
spider: props.spiderType,
job_id: props.jobId,
cron: ruleForm.value.cronExpression,
options: props.options
})
currentVisible.value = false
emit('getTaskList')
ElMessage.success('修改成功')
}
} else {
console.log('校验不通过');
}
})
}
if (!ruleFormRef.value) return;
await ruleFormRef.value.validate(async (valid) => {
//验证表单内容是否通过,通过继续执行
if (valid) {
if (currentMode.value === AddMode.ADD_TASK) {
await addSpiderTask({
scrapyd_server_id: taskParams.value.scrapyd_server_id,
schedule_type: taskParams.value.schedule_type,
project: taskParams.value.project,
spider: ruleForm.value.spiderTypeValue,
options: JSON.stringify({ jobName: ruleForm.value.taskName }),
interval: [exGaps.second, exGaps.minute, exGaps.hour, exGaps.day],
});
currentVisible.value = false;
emit("getTaskList");
ElMessage.success("添加成功");
} else if (currentMode.value === AddMode.UPDATE_TASK) {
await addSpiderTask({
scrapyd_server_id: taskParams.value.scrapyd_server_id,
schedule_type: taskParams.value.schedule_type,
project: taskParams.value.project,
spider: props.spiderType,
job_id: props.jobId,
options: props.options,
interval: [exGaps.second, exGaps.minute, exGaps.hour, exGaps.day],
});
currentVisible.value = false;
emit("getTaskList");
ElMessage.success("修改成功");
}
} else {
console.log("校验不通过");
}
exGaps.second = 0;
exGaps.minute = 0;
exGaps.hour = 0;
exGaps.day = 0;
});
};
const getData = async () => {
const res = await getSpiderList({scrapydServerId:'1',project:'spiders'})
spiderTypeOptions.value = res.data
console.log(res);
}
const res = await getSpiderList({ scrapydServerId: "1", project: "spiders" });
spiderTypeOptions.value = res.data;
};
// 监听props变化,同步给组件内部
watch(() => props.dialogVisible,
(newVal) => {
currentVisible.value = newVal
}
)
watch(
() => props.dialogVisible,
(newVal) => {
currentVisible.value = newVal;
}
);
// 监听组件内部状态变化,同步给父组件,这样才能做到控制对话框组件的显隐
watch(() => currentVisible.value,
(newVal) => {
emit('update:dialogVisible', newVal)
}
)
watch(() => props.mode,
(newVal) => {
currentMode.value = newVal
}
)
watch(() => currentMode.value,
(newVal) => {
emit('update:mode', newVal)
}
)
watch(
[() => props.dialogVisible, () => props.mode, () => props.cron],
([newVisible, newMode, newCron]) => {
if (newVisible && newMode === AddMode.UPDATE_TASK) {
ruleForm.value.cronExpression = newCron;
}
if (!newVisible) {
// 清空表单
// cronExpression.value = ''
}
},
{ immediate: true }
() => currentVisible.value,
(newVal) => {
emit("update:dialogVisible", newVal);
}
);
watch(
() => props.mode,
(newVal) => {
currentMode.value = newVal;
}
);
watch(
() => currentMode.value,
(newVal) => {
emit("update:mode", newVal);
}
);
watch(
() => props.exGap,
(newVal) => {
exGaps.second = newVal[0] || 0;
exGaps.minute = newVal[1] || 0;
exGaps.hour = newVal[2] || 0;
exGaps.day = newVal[3] || 0;
},
{ immediate: true }
);
onMounted(() => {
getData()
})
getData();
});
</script>
<style>
/* 修改弹出框样式 */
.el-dialog {
background: transparent;
background-image: url("@/assets/picture/dialog1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
color: #ffffff;
.el-dialog__title {
color: #ffffff;
}
.el-input__inner {
color: #ffffff;
}
background: transparent;
background-image: url("@/assets/picture/dialog1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
color: #ffffff;
.el-dialog__title {
color: #ffffff;
}
.el-input__inner {
color: #ffffff;
}
}
/* 修改表单样式 */
.el-form {
.el-form-item__label {
color: #ffffff;
}
.el-form-item__label {
color: #ffffff;
}
}
</style>
<style scope>
.gap-unit {
display: flex;
gap: 2px;
align-items: center;
margin-right: 10px;
}
.unit-num {
color: white;
}
.gap-units {
display: flex;
}
.gap-ipt {
width: 100px;
}
</style>
<!-- 任务执行统计卡片组件 -->
<template>
<div>
<div class="m-t-2" />
<div class="text-left p-4 toolbarStyle ">
<div class="formStyle">
<el-form inline>
<el-form-item>
<el-text class="mx-1" style="color: #fff;">所属爬虫:</el-text>
</el-form-item>
<el-form-item>
<div>
<el-select v-model="searchCondition.spiders" placeholder="请选择" style="width: 220px">
<el-option v-for="item in taskSelectOptions" :key="item.spider" :label="item.spider"
:value="item.spider" />
</el-select>
</div>
</el-form-item>
<!-- <el-form-item>
<el-text class="mx-1" style="color: #fff;">任务名称:</el-text>
</el-form-item>
<el-form-item>
<el-input v-model="taskName" placeholder="请输入" style="width: 220px" />
</el-form-item> -->
<el-form-item>
<el-space>
<el-button type="primary" @Click="search">查询</el-button>
<el-button type="primary" @Click="resetData">重置列表</el-button>
<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 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">执行频率: {{ parseCronExpression(task.kwargs.cron) }} </span>
</el-space>
</el-form-item>
</div>
<div class="wordStyle">
<el-form-item class="form-item">
<el-space>
<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>
<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>
<TableSearch>
<div class="form-content">
<div class="ipt">
<span style="color: white">所属爬虫:</span>
<el-select
v-model="searchCondition.spiders"
placeholder="请选择"
style="width: 220px"
:disabled="!taskSelectOptions.length"
>
<el-option
v-for="item in taskSelectOptions || []"
:key="item?.spider"
:label="item?.spider || '未知'"
:value="item?.spider"
/>
</el-select>
</div>
<div class="btns">
<el-button plain type="primary" @click="search">查询</el-button>
<el-button @click="resetData" style="margin-right: 20px">重置</el-button>
<el-button plain type="primary" @click="openTaskDialog">新建任务</el-button>
</div>
</div>
</TableSearch>
<div class="cardStyle">
<div v-if="taskList.length === 0 && !isLoading" class="empty-tip">暂无任务数据</div>
<div
v-loading="taskList.length == 0"
element-loading-background="rgba(48, 65, 86, 0.7)"
class="taskCard p-2"
v-for="task in taskList || []"
:key="task?.id || task?.taskId"
>
<div class="header">
<span class="task-name"
>任务名称: {{ (task?.kwargs?.options && JSON.parse(task.kwargs.options).jobName) || "无名称" }}</span
>
<el-divider style="margin-top: 5px"></el-divider>
</div>
<div class="btns">
<el-button plain type="primary" @click="editTask(task)" class="editButton" :disabled="!task?.id"
>编辑</el-button
>
<el-button plain type="danger" @click="deleteTask(task)" class="deleteButton" :disabled="!task?.id"
>删除</el-button
>
</div>
<div class="info">
<div class="item">
<span class="wordStyle">启用/停止: </span>
<el-switch
v-model="task.status"
:active-value="'running'"
:inactive-value="'paused'"
@change="(newStatus: any) => changeStatus(task, newStatus)"
:disabled="!task?.id"
/>
</div>
<div class="item">
<span class="wordStyle">执行频率: </span>
<span class="wordStyle">{{ parseCronExpression(task?.kwargs?.cron) || "未设置" }} </span>
</div>
<div class="item">
<span class="wordStyle">执行次数: </span>
<span class="wordStyle">{{ formatExactLargeNum(task?.count || 0) }}</span>
</div>
</div>
</div>
</div>
<addTaskDialog
v-model:dialogVisible="showTaskDialog"
@confirm="handleEdit"
:mode="editMode"
@getTaskList="getData"
:jobId="jobId"
:exGap="frequency || []"
:spiderType="belongSpiderType || ''"
:options="taskOptions || ''"
/>
<deleteDialog v-model:dialogVisible="showDeleteDialog" @get-user-list="getData" :jobId="jobId" :disabled="!jobId" />
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch } 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 { CronExpressionParser } from 'cron-parser';
import { ElMessage } from 'element-plus'
import { getSpiderList } from '@/api/system.ts'
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 } from "element-plus";
import { getSpiderList } from "@/api/system.ts";
import formatExactLargeNum from "@/utils/formatExactLargeNum";
import TableSearch from "@/components/TableSearch.vue";
const props = defineProps({
spiderType: {
type: String,
default: ''
},
failTask: {
type: String,
default: ''
},
unusualTask: {
type: String,
default: ''
}
})
const taskSelectOptions = ref()
spiderType: {
type: String,
default: "",
},
failTask: {
type: String,
default: "",
},
unusualTask: {
type: String,
default: "",
},
});
// 所有响应式变量初始化时避免 undefined
const taskSelectOptions = ref<any[]>([]); // 初始化为空数组
const searchCondition = ref({
spiders: '',
options: ''
})
const belongSpider = ref('')
const taskName = ref('')
const taskValue = ref('')
const belongSpiderType = ref('')
const router = useRouter()
const frequency = ref()
const editMode = ref(AddMode.UPDATE_TASK)
const deleteMode = ref(DeleteMode.SINGLE_DELETE)
const showDeleteDialog = ref(false)
const showTaskDialog = ref(false)
const taskSwitch = ref(false)
const taskOptions = ref('')
const jobId = ref('')
const taskList = ref<any[]>([])
spiders: "",
options: "",
});
const taskName = ref("");
const taskValue = ref("");
const belongSpiderType = ref("");
const router = useRouter();
const frequency = ref([]); // 初始化为空字符串,解决 cron 类型错误
const editMode = ref(AddMode.UPDATE_TASK);
const deleteMode = ref(DeleteMode.SINGLE_DELETE);
const showDeleteDialog = ref(false);
const showTaskDialog = ref(false);
const taskSwitch = ref(false);
const taskOptions = ref("");
const jobId = ref("");
const taskList = ref<any[]>([]);
const isLoading = ref(false); // 新增专门的加载状态变量
// 删除任务的方法
const deleteTask = (task: any) => {
jobId.value = task.id
deleteMode.value = DeleteMode.SINGLE_DELETE
showDeleteDialog.value = true
}
if (!task?.id) return; // 避免 task 为 undefined
jobId.value = task.id;
deleteMode.value = DeleteMode.SINGLE_DELETE;
showDeleteDialog.value = true;
};
// 编辑任务的方法
const editTask = (task: any) => {
jobId.value = task.id
taskOptions.value = JSON.stringify(JSON.parse(task.kwargs.options))
belongSpiderType.value = task.kwargs.spider
frequency.value = task.kwargs.cron
editMode.value = AddMode.UPDATE_TASK
showTaskDialog.value = true
// console.log(JSON.stringify(JSON.parse(task.kwargs.options)));
if (!task?.id) return; // 避免 task 为 undefined
jobId.value = task.id;
// 安全处理 JSON 字符串,避免解析失败
try {
taskOptions.value = JSON.stringify(task?.kwargs?.options ? JSON.parse(task.kwargs.options) : {});
} catch (err) {
taskOptions.value = "{}";
}
belongSpiderType.value = task?.kwargs?.spider || "";
frequency.value = task?.kwargs?.interval || []; // 兜底空字符串
editMode.value = AddMode.UPDATE_TASK;
showTaskDialog.value = true;
};
}
const goToTaskRecord = () => {
router.push({
path: '/osTaskRecord/list',
query: {
jump: 'yes',
mode: '任务信息'
}
})
}
// 启动与停止任务的方法
const changeStatus = async (task: any, newStatus: string) => {
if (newStatus === "running") {
await resumeSpiderTask({ job_id: task.id });
} else if (newStatus === "paused") {
await pauseSpiderTask({ job_id: task.id });
}
// await getData();
if (!task?.id) return; // 避免 task 为 undefined
try {
if (newStatus === "running") {
await resumeSpiderTask({ job_id: task.id });
ElMessage.success("任务已启动");
} else if (newStatus === "paused") {
await pauseSpiderTask({ job_id: task.id });
ElMessage.success("任务已暂停");
}
} catch (err) {
ElMessage.error("状态切换失败");
console.error(err);
// 状态回滚,避免界面显示错误
task.status = newStatus === "running" ? "paused" : "running";
}
};
const handleEdit = () => {
}
const handleEdit = () => {};
// 打开新建任务弹窗
const openTaskDialog = () => {
editMode.value = AddMode.ADD_TASK
frequency.value = '* * * * * *'
showTaskDialog.value = true
}
editMode.value = AddMode.ADD_TASK;
frequency.value = [];
showTaskDialog.value = true;
};
// 获取任务列表的方法
const getData = async () => {
const res = await getSpiderTaskList({ spiders: searchCondition.value.spiders ? [searchCondition.value.spiders] : [] })
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
}
isLoading.value = true; // 开始加载
try {
const res = await getSpiderTaskList({
spiders: searchCondition.value.spiders ? [searchCondition.value.spiders] : [],
});
const resId = await getTaskCount({});
// 安全处理返回数据,避免 res.data 为 undefined
const taskData = res?.data || [];
const countData = resId?.data || {};
// 遍历赋值时兜底
taskList.value = taskData.map((item: any) => ({
...item,
count: countData[item?.id] ?? 0, // 执行次数兜底 0
status: item?.status || "paused", // 状态兜底
kwargs: item?.kwargs || {}, // kwargs 兜底空对象
}));
} catch (err) {
ElMessage.error("获取任务列表失败");
console.error(err);
taskList.value = []; // 错误时置空数组
} finally {
isLoading.value = false; // 结束加载
}
};
// 重置任务列表的方法
const resetData = async () => {
searchCondition.value.spiders = ''
const res = await getSpiderTaskList({ spiders: [], options: JSON.stringify({ jobName: taskName.value }) })
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
}
searchCondition.value.spiders = "";
isLoading.value = true;
try {
const res = await getSpiderTaskList({ spiders: [], options: JSON.stringify({ jobName: taskName.value }) });
const resId = await getTaskCount({});
const taskData = res?.data || [];
const countData = resId?.data || {};
taskList.value = taskData.map((item: any) => ({
...item,
count: countData[item?.id] ?? 0,
status: item?.status || "paused",
kwargs: item?.kwargs || {},
}));
} catch (err) {
ElMessage.error("重置任务列表失败");
console.error(err);
taskList.value = [];
} finally {
isLoading.value = false;
}
};
// 搜索任务的方法
const search = async () => {
if (searchCondition.value.spiders === '') {
ElMessage.warning('请先选择爬虫')
return
}
const res = await getSpiderTaskList({ spiders: searchCondition.value.spiders ? [searchCondition.value.spiders] : [], options: JSON.stringify({ jobName: taskName.value }) })
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
}
// 解析cron表达式的方法
const parseCronExpression = (cronExpression: string) => {
const res = cronExpression.split('*').length - 1
if (res >= 5) {
const aaa = cronExpression.split(' ')
for (let i = 0; i < aaa.length; i++) {
if (aaa[i] != '*') {
if (i == 0) {
if (aaa[i].length === 3) {
return `每${aaa[i][2]}秒执行一次`
} else {
return `每${aaa[i][2] + aaa[i][3]}秒执行一次`
}
} else if (i == 1) {
if (aaa[i].length === 3) {
return `每${aaa[i][2]}分钟执行一次`
} else {
return `每${aaa[i][2] + aaa[i][3]}分钟执行一次`
}
} else if (i == 2) {
if (aaa[i].length === 3) {
return `每${aaa[i][2]}小时执行一次`
} else {
return `每${aaa[i][2] + aaa[i][3]}小时执行一次`
}
} else if (i == 3) {
if (aaa[i].length === 3) {
return `每${aaa[i][2]}天执行一次`
} else {
return `每${aaa[i][2] + aaa[i][3]}天执行一次`
}
} else if (i == 4) {
if (aaa[i].length === 3) {
return `每${aaa[i][2]}月执行一次`
} else {
return `每${aaa[i][2] + aaa[i][3]}月执行一次`
}
}
}
}
}
}
if (searchCondition.value.spiders === "") {
ElMessage.warning("请先选择爬虫");
return;
}
isLoading.value = true;
try {
const res = await getSpiderTaskList({
spiders: [searchCondition.value.spiders],
options: JSON.stringify({ jobName: taskName.value }),
});
const resId = await getTaskCount({});
const taskData = res?.data || [];
const countData = resId?.data || {};
taskList.value = taskData.map((item: any) => ({
...item,
count: countData[item?.id] ?? 0,
status: item?.status || "paused",
kwargs: item?.kwargs || {},
}));
} catch (err) {
ElMessage.error("搜索任务失败");
console.error(err);
taskList.value = [];
} finally {
isLoading.value = false;
}
};
// 解析cron表达式的方法(修复逻辑错误,避免数组越界)
const parseCronExpression = (cronExpression?: string) => {
// 兜底:cron表达式不存在时返回默认值
if (!cronExpression) return "未设置";
const parts = cronExpression.trim().split(" ");
// 只处理标准 5/6 位 cron 表达式
if (parts.length < 5 || parts.length > 6) return "表达式格式错误";
// 遍历每个字段,找到非 * 的字段(修复数组越界问题)
for (let i = 0; i < parts.length; i++) {
const part = parts[i].trim();
if (part !== "*" && part !== "") {
// 转换为数字,避免非数字字符导致的错误
const num = parseInt(part, 10);
const validNum = isNaN(num) ? 1 : num;
switch (i) {
case 0:
return `每${validNum}秒执行一次`;
case 1:
return `每${validNum}分钟执行一次`;
case 2:
return `每${validNum}小时执行一次`;
case 3:
return `每${validNum}天执行一次`;
case 4:
return `每${validNum}月执行一次`;
case 5:
return `每${validNum}周执行一次`;
default:
return "未知频率";
}
}
}
// 全是 * 时返回默认
return "每秒执行一次";
};
// 获取爬虫类型列表
const getSpiderTypeList = async () => {
const res = await getSpiderList({ scrapydServerId: '1', project: 'spiders' })
console.log(res,8888888888888);
taskSelectOptions.value = res.data
// taskSelectOptions.value = res.data
}
try {
const res = await getSpiderList({ scrapydServerId: "1", project: "spiders" });
taskSelectOptions.value = res?.data || []; // 兜底空数组
} catch (err) {
ElMessage.error("获取爬虫列表失败");
console.error(err);
taskSelectOptions.value = [];
}
};
onMounted(() => {
if (props.spiderType !== '') {
searchCondition.value.spiders = props.spiderType
}
getData()
getSpiderTypeList()
})
// 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;
// }
// }
if (props.spiderType !== "") {
searchCondition.value.spiders = props.spiderType;
}
getData();
getSpiderTypeList();
});
</script>
<style lang="scss" scoped>
:deep(.el-form-item__label) {
color: white;
}
.cardStyle {
display: flex;
flex-wrap: wrap;
margin-top: 1.5%;
padding: 18px;
gap: 15px;
width: auto !important;
justify-content: space-between;
padding: 18px;
gap: 15px;
width: auto !important;
display: flex;
flex-wrap: wrap; // 修复卡片溢出问题
}
.taskContent {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
gap: 6px;
/* 进一步减小项目之间的间距 */
padding: 5px 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: start;
height: 100%;
gap: 6px;
padding: 5px 0;
}
.task-name {
color: #fff !important;
font-size: 18px;
font-weight: 500;
}
/* 任务卡片样式 */
.taskCard {
margin-left: 1%;
background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
margin-bottom: 10px;
width: 380px;
font-size: 20px;
min-height: 240px;
border-radius: 7px;
display: flex;
flex-direction: column;
background-image: url("@/assets/picture/box2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
font-size: 20px;
min-width: 300px;
border-radius: 7px;
}
/* 减小表单的间距 */
.form-item {
margin-bottom: 3px !important;
margin-bottom: 3px !important;
}
.taskCard .titleStyle {
font-size: 22px;
color: #FFFFFF;
display: flex;
font-size: 20px;
color: #ffffff;
}
.task-name {
color: #ccc;
}
.item {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin: 8px 0;
}
.taskCard .wordStyle {
font-size: 16px;
color: #FFFFFF;
font-size: 16px;
color: #ffffff;
}
/* 按钮样式微调 */
.editButton,
.recordButton,
.deleteButton {
margin: 0 3px !important;
margin: 0 3px !important;
}
/* 工具栏样式 */
.toolbarStyle {
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
/* 表单样式 */
.formStyle {
display: flex;
justify-content: space-around;
margin-top: 0.5%;
padding: 2px;
margin-top: 0.5%;
padding: 2px;
}
// 去除按钮边框
.el-button:focus {
outline: none;
color: #ffffff;
border: none;
/* 空数据提示 */
.empty-tip {
width: 100%;
text-align: center;
color: #fff;
padding: 50px 0;
}
</style>
<style>
/* .el-button{
color: #ffffff;
border: none;
} */
.el-input {
color: #FFFFFF;
.header {
margin-top: 10px;
}
.el-select__placeholder {
color: #FFFFFF;
.form-content {
height: 80px;
padding: 0 30px;
justify-content: space-between;
display: flex;
align-items: center;
}
</style>
\ No newline at end of file
</style>
<template>
<div>
<MenuTitle title="任务信息" subtitle="Task Information" />
<div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToTaskInformation" />
<div class="m-t-8" />
<div>
<taskCard :spiderType="spiderType" failTask="10" unusualTask="1" />
<!-- <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="getData" />
</div> -->
<taskCard :spiderType="spiderType" failTask="10" unusualTask="1" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import taskCard from './components/taskCard.vue'
import { useRouter } from 'vue-router'
import { useRoute } from 'vue-router'
import { getSpiderTaskList,getTaskData } from '@/api/spiderTask'
import { AddMode } from './components/enum'
const route = useRoute()
const router = useRouter()
const spiderType = ref<any>(route.query.spiderType)
const taskValue = ref('')
const taskList = ref([])
const taskOptions = [
{
value: 'task1',
label: 'sk网',
},
{
value: 'task2',
label: 'nasa网',
},
{
value: 'task3',
label: '网',
},
]
const pageObj = ref({
total: 10,
pageSize: 10,
pageNo: 1
})
import { ref } from "vue";
import taskCard from "./components/taskCard.vue";
import { useRouter } from "vue-router";
import { useRoute } from "vue-router";
import MenuTitle from "@/components/MenuTitle.vue";
const route = useRoute();
const router = useRouter();
const spiderType = ref<any>(route.query.spiderType);
const goToTaskInformation = () => {
if(route.query.page === 'spiderManager'){
router.push({ path: '/osSpiderManager/list' })
}else{
router.push({ path: '/osStatus/list' })
if (route.query.page === "spiderManager") {
router.push({ path: "/osSpiderManager/list" });
} else {
router.push({ path: "/osStatus/list" });
}
}
onMounted(async () => {
// if(route.query.spiderType){
// spiderType.value = route.query.spiderType
// }
})
};
</script>
<style scoped>
.title {
text-align: left;
font-size: 18px;
font-weight: 500;
color: white;
}
.low-titme {
color: #ccc;
text-align: left;
margin-left: 20px;
}
.divider {
margin-top: 15px;
}
/* 返回样式 */
.backStyle {
background-image: url("@/assets/picture/back.png");
......@@ -85,7 +68,7 @@ onMounted(async () => {
/* 文本样式 */
.el-text {
color: #FFFFFF;
color: #ffffff;
}
/* 工具栏样式 */
......@@ -129,7 +112,7 @@ onMounted(async () => {
/* 修改el下拉框选项的字体颜色 */
.el-select-dropdown__item {
color: #FFFFFF;
color: #ffffff;
}
/* 修改el下拉框选项选中时的文字颜色 */
......@@ -141,4 +124,4 @@ onMounted(async () => {
.el-button:focus {
outline: none;
}
</style>
\ No newline at end of file
</style>
<template>
<div>
<div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToStatus" />
<div class="m-t-7" />
<div class="text-left p-6 toolbarStyle">
<div class="formStyle">
<el-form inline>
<el-form-item>
<el-text class="mx-1">时间:</el-text>
</el-form-item>
<el-form-item>
<el-config-provider :locale="zhCn">
<el-date-picker v-model="timeValue" type="datetimerange" start-placeholder="开始时间"
end-placeholder="结束时间" 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-config-provider>
</el-form-item>
<el-form-item>
<el-space>
<el-button type="primary" @click="searchData">查询</el-button>
<el-button type="primary" @click="getData">重置表格</el-button>
</el-space>
</el-form-item>
</el-form>
</div>
</div>
<div class="m-t-10" />
<div>
<el-table :data="tableData" style="width: 100%" border :header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }">
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="spider" label="所属爬虫" show-overflow-tooltip />
<el-table-column property="schedule_mode" label="调度模式" show-overflow-tooltip />
<el-table-column property="run_status" label="调度状态" show-overflow-tooltip>
<template #default="scope">
{{ '已完成' }}
</template>
</el-table-column>
<el-table-column label="错误消息" show-overflow-tooltip>
<!-- 当错误消息为空时默认值为'-' -->
<template #default="scope">
{{ scope.row.message || '-' }}
</template>
</el-table-column>
<el-table-column property="run_status" label="运行状态" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.run_status === "unknown" ? '已结束' : scope.row.run_status }}
</template>
</el-table-column>
<el-table-column property="create_time" label="调度时间" width="200" show-overflow-tooltip />
</el-table>
</div>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination :total="pageObj.total" v-model:page="pageObj.pageNo" v-model:limit="pageObj.pageSize"
@pagination="getData" v-model:pagerCount="pageObj.pagerCount" />
</div>
</div>
<div>
<MenuTitle title="任务执行记录" subtitle="Task Record" />
<div class="backStyle" v-if="route.query.jump === 'yes'" @click="goToStatus" />
<div class="m-t-8" />
<table-search>
<div class="form-content">
<div class="timer">
<span style="color: white">时间:</span>
<el-config-provider :locale="zhCn">
<el-date-picker
v-model="timeValue"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
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-config-provider>
</div>
<div class="btns">
<el-button plain type="primary" @click="searchData">查询</el-button>
<el-button plain @click="getData">重置</el-button>
</div>
</div>
</table-search>
<div class="table-content">
<div>
<el-table
v-loading="tableData.length == 0"
element-loading-background="rgba(48, 65, 86, 0.7)"
:data="tableData"
style="width: 100%"
border
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
>
<el-table-column property="number" label="序号" width="55" type="index" />
<el-table-column property="spider" label="所属爬虫" show-overflow-tooltip />
<el-table-column property="schedule_mode" label="调度模式" show-overflow-tooltip />
<el-table-column property="run_status" label="调度状态" show-overflow-tooltip>
<template #default="scope">
{{ "已完成" }}
</template>
</el-table-column>
<el-table-column label="错误消息" show-overflow-tooltip>
<!-- 当错误消息为空时默认值为'-' -->
<template #default="scope">
{{ scope.row.message || "-" }}
</template>
</el-table-column>
<el-table-column property="run_status" label="运行状态" show-overflow-tooltip>
<template #default="scope">
{{ scope.row.run_status === "unknown" ? "已结束" : scope.row.run_status }}
</template>
</el-table-column>
<el-table-column property="create_time" label="调度时间" width="200" show-overflow-tooltip />
</el-table>
</div>
<div class="pagination w-full flex flex-row-reverse pr-4 m-t-4">
<Pagination
:total="pageObj.total"
v-model:page="pageObj.pageNo"
v-model:limit="pageObj.pageSize"
@pagination="getData"
v-model:pagerCount="pageObj.pagerCount"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import Pagination from '@/components/pagination/index.vue'
import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import { getSpiderTaskRecord } from '@/api/spiderTask.ts'
import { ElMessage } from 'element-plus'
import { ref, onMounted } from "vue";
import Pagination from "@/components/pagination/index.vue";
import { useRoute } from "vue-router";
import { useRouter } from "vue-router";
import { getSpiderTaskRecord } from "@/api/spiderTask.ts";
import { ElMessage } from "element-plus";
import MenuTitle from "@/components/MenuTitle.vue";
import TableSearch from "@/components/TableSearch.vue";
// ElConfigProvider 组件
import { ElConfigProvider } from 'element-plus';
import { ElConfigProvider } from "element-plus";
// 引入中文包
import zhCn from 'element-plus/es/locale/lang/zh-cn';
defineOptions({ name: 'Pagination' })
import zhCn from "element-plus/es/locale/lang/zh-cn";
defineOptions({ name: "Pagination" });
// 更改分页文字
zhCn.el.pagination.total = '共 `{total} 条`';
zhCn.el.pagination.goto = '跳至';
zhCn.el.pagination.pagesize = '条/页';
zhCn.el.pagination.pageClassifier = '页';
const route = useRoute()
const router = useRouter()
const taskValue = ref('')
const timeValue = ref('')
zhCn.el.pagination.total = "共 `{total} 条`";
zhCn.el.pagination.goto = "跳至";
zhCn.el.pagination.pagesize = "条/页";
zhCn.el.pagination.pageClassifier = "页";
const route = useRoute();
const router = useRouter();
const timeValue = ref("");
const taskOptions = [
{
value: 'task1',
label: 'sk网',
},
{
value: 'task2',
label: 'nasa网',
},
{
value: 'task3',
label: '网',
},
]
const tableData = ref([])
{
value: "task1",
label: "sk网",
},
{
value: "task2",
label: "nasa网",
},
{
value: "task3",
label: "网",
},
];
const tableData = ref([]);
const pageObj = ref({
total: 10,
pageSize: 10,
pageNo: 1,
pagerCount: 5,
})
total: 10,
pageSize: 10,
pageNo: 1,
pagerCount: 5,
});
// 前往运行日志,暂时不要
// const handleDetails = (row: any) => {
// console.log(row);
......@@ -111,113 +126,153 @@ const pageObj = ref({
// })
// }
const goToStatus = () => {
if (route.query.mode === '状态监控') {
router.push({
path: '/osStatus/list',
})
} else {
router.push({
path: '/osTaskInformation/list',
})
}
}
if (route.query.mode === "状态监控") {
router.push({
path: "/osStatus/list",
});
} else {
router.push({
path: "/osTaskInformation/list",
});
}
};
// 获取任务执行记录列表
const getData = async () => {
const res = await getSpiderTaskRecord({ page: pageObj.value.pageNo, size: pageObj.value.pageSize, status: 'total' })
pageObj.value.total = res.data.total
tableData.value = res.data.list
}
const res = await getSpiderTaskRecord({ page: pageObj.value.pageNo, size: pageObj.value.pageSize, status: "total" });
pageObj.value.total = res.data.total;
tableData.value = res.data.list;
};
// 数据的方法
const searchData = async () => {
if (!timeValue.value) {
ElMessage.warning('请先选择时间段')
return
}
let resTime = []
const startTime = timeValue.value[0]
const endTime = timeValue.value[1]
resTime.push(startTime)
resTime.push(endTime)
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
}
if (!timeValue.value) {
ElMessage.warning("请先选择时间段");
return;
}
let resTime = [];
const startTime = timeValue.value[0];
const endTime = timeValue.value[1];
resTime.push(startTime);
resTime.push(endTime);
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;
};
onMounted(() => {
getData()
})
getData();
});
</script>
<style scoped>
:deep(.el-form-item__label) {
color: white;
}
/* 工具栏样式 */
.toolbarStyle {
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-image: url("@/assets/picture/box3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
}
/* 表格样式 */
.formStyle {
display: flex;
justify-content: space-around;
padding: 3px;
padding: 3px;
}
/* 文字样式 */
.el-text {
color: #FFFFFF;
color: #ffffff;
}
.table-content {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(8px);
border: 1px solid rgba(78, 237, 255, 0.2);
box-shadow: 0 0 15px rgba(78, 237, 255, 0.1);
border-radius: 8px;
padding: 10px !important;
margin-top: 18px;
}
.backStyle {
background-image: url("@/assets/picture/back.png");
background-size: 100% 100%;
background-repeat: no-repeat;
height: 5vh;
width: 5%;
display: flex;
margin-left: 0.8%;
background-image: url("@/assets/picture/back.png");
background-size: 100% 100%;
background-repeat: no-repeat;
height: 5vh;
width: 5%;
display: flex;
margin-left: 0.8%;
}
.title {
text-align: left;
font-size: 18px;
font-weight: 500;
color: white;
}
.low-titme {
color: #ccc;
text-align: left;
margin-left: 20px;
}
.divider {
margin-top: 15px;
}
.form-content {
height: 80px;
justify-content: space-between;
display: flex;
align-items: center;
padding: 0 30px;
}
</style>
<style>
/* 修改el选择器的样式 */
.el-select__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 删除el选择器选中时的边框 */
.is-hovering {
box-shadow: none !important;
box-shadow: none !important;
}
/* 修改el输入框的样式 */
.el-input__wrapper {
background-color: #1d5484;
box-shadow: none;
background-color: #1d5484;
box-shadow: none;
}
/* 修改el下拉框的背景颜色 */
.el-select-dropdown {
background-color: #1d5484;
background-color: #1d5484;
}
/* 修改el下拉框选项的字体颜色 */
.el-select-dropdown__item {
color: #FFFFFF;
color: #ffffff;
}
/* 修改el下拉框选项选中时的文字颜色 */
.el-select-dropdown__item:hover {
color: #409eff;
color: #409eff;
}
/* 修改el按钮的边框为none */
.el-button:focus {
outline: none;
outline: none;
}
/* 修改el日期选择器的边框为none */
.el-date-editor {
--el-input-border-color: none
--el-input-border-color: none;
}
</style>
\ No newline at end of file
</style>
<template>
<h1>system index</h1>
<div>system index</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
<script setup lang="ts"></script>
</script>
<style scoped></style>
......@@ -31,7 +31,7 @@ export default defineConfig({
proxy: {
// 代理API请求,使用更精确的路径匹配
'/api': {
target: 'http://192.168.0.176:5001/',
target: 'http://192.168.3.10:5001/',
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