可修改线程
This commit is contained in:
Generated
+3
-21
@@ -64,27 +64,6 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
|
||||
"integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.1",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
|
||||
"integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/wasi-threads": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
||||
@@ -1483,6 +1462,7 @@
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -1622,6 +1602,7 @@
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.7.tgz",
|
||||
"integrity": "sha512-P1PbweD+2/udplnThz3btF4cf6AgPky7kk23RtHUkJIU5BIxwPprhRGmOAHs6FTI7UiGbTNrgNP6jSYD6JaRnw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
@@ -1699,6 +1680,7 @@
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.32.tgz",
|
||||
"integrity": "sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.32",
|
||||
"@vue/compiler-sfc": "3.5.32",
|
||||
|
||||
+14
@@ -47,3 +47,17 @@ export async function flushIndex() {
|
||||
return data
|
||||
}
|
||||
|
||||
export async function fetchWorkers() {
|
||||
const { data } = await axios.get(`${BASE}/admin/workers`, {
|
||||
timeout: 10000,
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
export async function setWorkers(n) {
|
||||
const { data } = await axios.post(`${BASE}/admin/workers`, { workers: n }, {
|
||||
timeout: 10000,
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
+88
-4
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { fetchStats, flushIndex } from '../api.js'
|
||||
import { fetchStats, flushIndex, fetchWorkers, setWorkers } from '../api.js'
|
||||
|
||||
const stats = ref(null)
|
||||
const loading = ref(true)
|
||||
@@ -8,10 +8,18 @@ const flushing = ref(false)
|
||||
const error = ref(null)
|
||||
let refreshInterval = null
|
||||
|
||||
// Workers 相关状态
|
||||
const configuredWorkers = ref(0) // 设定线程数
|
||||
const activeWorkers = ref(0) // 实际运行中的 goroutine 数
|
||||
const workersInput = ref(0)
|
||||
const workersSaving = ref(false)
|
||||
|
||||
onMounted(async () => {
|
||||
await loadStats()
|
||||
// 每5秒自动刷新
|
||||
refreshInterval = setInterval(loadStats, 5000)
|
||||
await Promise.all([loadStats(), loadWorkers()])
|
||||
refreshInterval = setInterval(() => {
|
||||
loadStats()
|
||||
loadWorkers()
|
||||
}, 5000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -32,6 +40,35 @@ async function loadStats() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadWorkers() {
|
||||
try {
|
||||
const res = await fetchWorkers()
|
||||
configuredWorkers.value = res.configured
|
||||
activeWorkers.value = res.active
|
||||
workersInput.value = res.configured
|
||||
} catch (e) {
|
||||
console.error('Failed to load workers:', e)
|
||||
}
|
||||
}
|
||||
|
||||
async function saveWorkers() {
|
||||
const n = parseInt(workersInput.value, 10)
|
||||
if (isNaN(n) || n < 1 || n > 500) {
|
||||
error.value = '线程数必须在 1~500 之间'
|
||||
return
|
||||
}
|
||||
workersSaving.value = true
|
||||
try {
|
||||
await setWorkers(n)
|
||||
configuredWorkers.value = n
|
||||
error.value = null
|
||||
} catch (e) {
|
||||
error.value = '修改线程数失败: ' + e.message
|
||||
} finally {
|
||||
workersSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function doFlush() {
|
||||
flushing.value = true
|
||||
try {
|
||||
@@ -105,6 +142,53 @@ function langColor(lang) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Workers Control -->
|
||||
<div class="bg-gray-900 border border-gray-800 rounded-xl p-4 md:p-5 mb-6 md:mb-8">
|
||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="text-sm font-semibold text-gray-300 uppercase tracking-wider mb-2">爬虫线程数</h2>
|
||||
<div class="flex items-baseline gap-4">
|
||||
<div>
|
||||
<div class="text-xs text-gray-500 mb-0.5">实际运行</div>
|
||||
<div class="text-3xl font-bold" :class="activeWorkers > 0 ? 'text-green-400' : 'text-gray-500'">{{ activeWorkers }}</div>
|
||||
</div>
|
||||
<div class="text-gray-700 text-xl">/</div>
|
||||
<div>
|
||||
<div class="text-xs text-gray-500 mb-0.5">设定上限</div>
|
||||
<div class="text-3xl font-bold text-white">{{ configuredWorkers }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
class="w-9 h-9 flex items-center justify-center rounded-lg bg-gray-800 hover:bg-gray-700 text-gray-300 hover:text-white text-lg font-bold transition-colors cursor-pointer"
|
||||
@click="workersInput = Math.max(1, workersInput - 1)"
|
||||
:disabled="workersSaving"
|
||||
>−</button>
|
||||
<input
|
||||
type="number"
|
||||
v-model.number="workersInput"
|
||||
min="1"
|
||||
max="500"
|
||||
class="w-20 h-9 text-center bg-gray-800 border border-gray-700 rounded-lg text-white text-sm focus:outline-none focus:border-blue-500 transition-colors [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
|
||||
@keyup.enter="saveWorkers"
|
||||
/>
|
||||
<button
|
||||
class="w-9 h-9 flex items-center justify-center rounded-lg bg-gray-800 hover:bg-gray-700 text-gray-300 hover:text-white text-lg font-bold transition-colors cursor-pointer"
|
||||
@click="workersInput = Math.min(500, workersInput + 1)"
|
||||
:disabled="workersSaving"
|
||||
>+</button>
|
||||
<button
|
||||
class="h-9 px-4 bg-blue-700 hover:bg-blue-600 disabled:bg-gray-700 disabled:text-gray-500 text-white text-sm font-medium rounded-lg transition-colors cursor-pointer"
|
||||
:disabled="workersSaving || workersInput === configuredWorkers"
|
||||
@click="saveWorkers"
|
||||
>
|
||||
{{ workersSaving ? '保存中...' : '应用' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-5">
|
||||
<!-- Domain Distribution -->
|
||||
<div class="bg-gray-900 border border-gray-800 rounded-xl p-4 md:p-5">
|
||||
|
||||
@@ -4,4 +4,8 @@ import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue(), tailwindcss()],
|
||||
build: {
|
||||
outDir: '../dist',
|
||||
emptyOutDir: true,
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user