dev
This commit is contained in:
183
domain-web/src/views/detect/DetectView.vue
Normal file
183
domain-web/src/views/detect/DetectView.vue
Normal file
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<PageCard title="检测控制" description="当前已接入真实状态读取和本地 Worker 启停,后续 Linux 版会沿用同一页接 systemd。">
|
||||
<div class="actions">
|
||||
<el-button type="primary" :loading="actionLoading === 'start'" @click="invoke('start')">启动检测</el-button>
|
||||
<el-button :loading="actionLoading === 'stop'" @click="invoke('stop')">停止检测</el-button>
|
||||
<el-button plain :loading="loading" @click="loadStatus">刷新状态</el-button>
|
||||
<el-switch v-model="autoRefresh" inline-prompt active-text="自动刷新" inactive-text="手动" />
|
||||
</div>
|
||||
|
||||
<el-alert
|
||||
v-if="lastAction.message"
|
||||
:title="`${lastAction.label}:${lastAction.message}`"
|
||||
:type="lastAction.type"
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="action-alert"
|
||||
/>
|
||||
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="Worker 在线">{{ status.worker_online ? "是" : "否" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="运行模式">{{ status.worker_mode || "windows-local" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="Worker 服务">{{ status.worker_service_name || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="API 服务">{{ status.api_service_name || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="检测进程数">{{ status.worker_process_count }}</el-descriptions-item>
|
||||
<el-descriptions-item label="线程数">{{ status.thread_count }}</el-descriptions-item>
|
||||
<el-descriptions-item label="代理启用">{{ status.proxy_enable ? "是" : "否" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="允许直连">{{ status.allow_direct ? "是" : "否" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="代理池数量">{{ status.proxy_pool_count }}</el-descriptions-item>
|
||||
<el-descriptions-item label="可用代理数">{{ status.available_proxy_count }}</el-descriptions-item>
|
||||
<el-descriptions-item label="最近 Worker 日志时间">{{ status.last_worker_log_time || "暂无" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="最近启动时间">{{ status.worker_latest_start_time || "暂无" }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-alert
|
||||
v-if="status.recent_warning"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
:title="status.recent_warning"
|
||||
style="margin-top: 16px"
|
||||
/>
|
||||
<el-alert
|
||||
v-if="status.worker_runtime_message"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
:title="status.worker_runtime_message"
|
||||
style="margin-top: 12px"
|
||||
/>
|
||||
|
||||
<el-row :gutter="12" style="margin-top: 16px">
|
||||
<el-col :xs="12" :sm="8" :md="4"><el-statistic title="待检测" :value="status.progress.pending || 0" /></el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4"><el-statistic title="检测中" :value="status.progress.running || 0" /></el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4"><el-statistic title="检测完成" :value="status.progress.completed || 0" /></el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4"><el-statistic title="黑名单" :value="status.progress.blacklisted || 0" /></el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4"><el-statistic title="检测失败" :value="status.progress.failed || 0" /></el-col>
|
||||
</el-row>
|
||||
</PageCard>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import PageCard from "@/components/PageCard.vue";
|
||||
import { detectApi } from "@/api/modules";
|
||||
|
||||
const status = ref({
|
||||
worker_online: false,
|
||||
worker_mode: "windows-local",
|
||||
worker_service_name: "",
|
||||
api_service_name: "",
|
||||
worker_process_count: 0,
|
||||
worker_latest_start_time: "",
|
||||
worker_runtime_message: "",
|
||||
thread_count: 0,
|
||||
proxy_enable: false,
|
||||
allow_direct: false,
|
||||
proxy_pool_count: 0,
|
||||
available_proxy_count: 0,
|
||||
last_worker_log_time: "",
|
||||
recent_warning: "",
|
||||
progress: {
|
||||
pending: 0,
|
||||
running: 0,
|
||||
completed: 0,
|
||||
failed: 0,
|
||||
blacklisted: 0
|
||||
}
|
||||
});
|
||||
|
||||
const autoRefresh = ref(true);
|
||||
const loading = ref(false);
|
||||
const actionLoading = ref<"" | "start" | "stop">("");
|
||||
const lastAction = ref({
|
||||
label: "",
|
||||
message: "",
|
||||
type: "success" as "success" | "warning" | "info" | "error"
|
||||
});
|
||||
let timer: number | null = null;
|
||||
|
||||
const clearRefreshTimer = () => {
|
||||
if (timer) {
|
||||
window.clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const ensureRefreshTimer = () => {
|
||||
clearRefreshTimer();
|
||||
if (autoRefresh.value) {
|
||||
timer = window.setInterval(() => {
|
||||
loadStatus(false);
|
||||
}, 10000);
|
||||
}
|
||||
};
|
||||
|
||||
const loadStatus = async (showError = true) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await detectApi.status();
|
||||
status.value = response.data;
|
||||
} catch {
|
||||
if (showError) {
|
||||
ElMessage.error("读取检测状态失败");
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const invoke = async (action: "start" | "stop") => {
|
||||
actionLoading.value = action;
|
||||
try {
|
||||
const response = action === "start" ? await detectApi.start() : await detectApi.stop();
|
||||
ElMessage.success(response.message);
|
||||
lastAction.value = {
|
||||
label: action === "start" ? "检测启动" : "检测停止",
|
||||
message: response.message,
|
||||
type: "success"
|
||||
};
|
||||
const pollDelaySeconds = Number(response.data?.poll_after_seconds || 2);
|
||||
if (response.data?.refresh_status) {
|
||||
window.setTimeout(() => {
|
||||
loadStatus(false);
|
||||
}, pollDelaySeconds * 1000);
|
||||
return;
|
||||
}
|
||||
await loadStatus(false);
|
||||
} catch (error: any) {
|
||||
const message = error?.message || `${action === "start" ? "启动" : "停止"}操作失败`;
|
||||
lastAction.value = {
|
||||
label: action === "start" ? "检测启动" : "检测停止",
|
||||
message,
|
||||
type: "error"
|
||||
};
|
||||
ElMessage.error(message);
|
||||
} finally {
|
||||
actionLoading.value = "";
|
||||
}
|
||||
};
|
||||
|
||||
watch(autoRefresh, ensureRefreshTimer);
|
||||
|
||||
onMounted(async () => {
|
||||
await loadStatus();
|
||||
ensureRefreshTimer();
|
||||
});
|
||||
|
||||
onBeforeUnmount(clearRefreshTimer);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.action-alert {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user