This commit is contained in:
2026-01-12 16:09:05 +08:00
parent c889c80747
commit ec47d9011e
2 changed files with 125 additions and 10 deletions

View File

@@ -79,7 +79,7 @@ import { getToken, setToken, setUser, setUserPass, getUserPass } from '@/stores/
import { ElLoading, ElMessage } from 'element-plus'; import { ElLoading, ElMessage } from 'element-plus';
import { passToken } from '@/api/ios'; import { passToken } from '@/api/ios';
let version = ref('3.3.0'); let version = ref('3.6.0');
onMounted(() => { onMounted(() => {

View File

@@ -21,12 +21,16 @@
<el-button type="info" @click="uploadLogFile">上传日志</el-button> <el-button type="info" @click="uploadLogFile">上传日志</el-button>
<div> <div>
<!-- 监听 q.tenant.*爬虫 --> <!-- 监听 q.tenant.*爬虫 -->
<el-switch v-model="sseCrawlerEnabled" inline-prompt active-text="" inactive-text="监听爬虫" <el-switch v-model="sseCrawlerEnabled" inline-prompt active-text="监听爬虫" inactive-text="监听爬虫"
style="margin-left: 8px;" @change="onToggleCrawler" />监听爬虫 style="margin-left: 8px;" @change="onToggleCrawler" />
<el-button size="small" style="margin-left: 8px;" @click="setSseLimit('crawler')">设置</el-button>
<span style="margin-left: 4px;">剩余 {{ sseCrawlerRemaining }}/{{ sseCrawlerLimit }} </span>
<!-- 监听 b.tenant.*大哥 --> <!-- 监听 b.tenant.*大哥 -->
<el-switch v-model="sseBossEnabled" inline-prompt active-text="监听大哥" inactive-text="监听大哥" <el-switch v-model="sseBossEnabled" inline-prompt active-text="监听大哥" inactive-text="监听大哥"
style="margin-left: 8px;" @change="onToggleBoss" /> style="margin-left: 8px;" @change="onToggleBoss" />
<el-button size="small" style="margin-left: 8px;" @click="setSseLimit('boss')">设置</el-button>
<span style="margin-left: 4px;">剩余 {{ sseBossRemaining }}/{{ sseBossLimit }} </span>
</div> </div>
</div> </div>
@@ -118,7 +122,7 @@
<div style="display:flex; gap:8px; align-items:center;"> <div style="display:flex; gap:8px; align-items:center;">
<el-switch v-model="interruptEnabled" active-text="开启换号" /> <el-switch v-model="interruptEnabled" active-text="开启换号" />
<el-input-number v-model="interruptEveryMin" :min="1" :max="24" /> <el-input-number v-model="interruptEveryMin" :min="1" :max="24" />
<span>分钟换一次</span> <span>小时换一次</span>
</div> </div>
<div>联盟号</div> <div>联盟号</div>
<div style="display:flex; gap:8px; align-items:center;"> <div style="display:flex; gap:8px; align-items:center;">
@@ -287,18 +291,122 @@ const isLocked = (type) => !!runType.value && runType.value !== type
// —— SSE 开关(分别控制爬虫队列 & 大哥队列)—— // —— SSE 开关(分别控制爬虫队列 & 大哥队列)——
const sseCrawlerEnabled = ref(JSON.parse(localStorage.getItem('SSE_CRAWLER_ENABLED') ?? 'true')) // q.tenant.* const sseCrawlerEnabled = ref(JSON.parse(localStorage.getItem('SSE_CRAWLER_ENABLED') ?? 'true')) // q.tenant.*
const sseBossEnabled = ref(JSON.parse(localStorage.getItem('SSE_BOSS_ENABLED') ?? 'false')) // b.tenant.* const sseBossEnabled = ref(JSON.parse(localStorage.getItem('SSE_BOSS_ENABLED') ?? 'false')) // b.tenant.*
const sseCrawlerLimit = ref(Number(localStorage.getItem('SSE_CRAWLER_LIMIT') ?? '500'))
const sseBossLimit = ref(Number(localStorage.getItem('SSE_BOSS_LIMIT') ?? '500'))
const sseCrawlerRemaining = ref(Number(localStorage.getItem('SSE_CRAWLER_REMAIN') ?? sseCrawlerLimit.value))
const sseBossRemaining = ref(Number(localStorage.getItem('SSE_BOSS_REMAIN') ?? sseBossLimit.value))
const normalizeSseLimit = (val, fallback) => {
const n = Number(val)
if (!Number.isFinite(n) || n <= 0) return fallback
return Math.floor(n)
}
watch(sseCrawlerEnabled, v => { watch(sseCrawlerEnabled, v => {
localStorage.setItem('SSE_CRAWLER_ENABLED', JSON.stringify(v)) localStorage.setItem('SSE_CRAWLER_ENABLED', JSON.stringify(v))
if (v && sseCrawlerRemaining.value <= 0) {
sseCrawlerEnabled.value = false
ElMessage.warning('请先设置监听爬虫条数')
}
}) })
watch(sseBossEnabled, v => { watch(sseBossEnabled, v => {
localStorage.setItem('SSE_BOSS_ENABLED', JSON.stringify(v)) localStorage.setItem('SSE_BOSS_ENABLED', JSON.stringify(v))
if (v && sseBossRemaining.value <= 0) {
sseBossEnabled.value = false
ElMessage.warning('请先设置监听大哥条数')
}
})
watch(sseCrawlerLimit, v => {
const next = normalizeSseLimit(v, 500)
if (next !== v) {
sseCrawlerLimit.value = next
return
}
localStorage.setItem('SSE_CRAWLER_LIMIT', String(next))
})
watch(sseBossLimit, v => {
const next = normalizeSseLimit(v, 500)
if (next !== v) {
sseBossLimit.value = next
return
}
localStorage.setItem('SSE_BOSS_LIMIT', String(next))
})
watch(sseCrawlerRemaining, v => {
const next = normalizeSseLimit(v, 0)
if (next !== v) {
sseCrawlerRemaining.value = next
return
}
localStorage.setItem('SSE_CRAWLER_REMAIN', String(next))
})
watch(sseBossRemaining, v => {
const next = normalizeSseLimit(v, 0)
if (next !== v) {
sseBossRemaining.value = next
return
}
localStorage.setItem('SSE_BOSS_REMAIN', String(next))
}) })
// 至少有一个开着才算启用 SSE // 至少有一个开着才算启用 SSE
const sseAnyEnabled = computed(() => sseCrawlerEnabled.value || sseBossEnabled.value) const sseAnyEnabled = computed(() => sseCrawlerEnabled.value || sseBossEnabled.value)
const bumpSseCount = (type) => {
const isCrawler = type === 'crawler'
const remainingRef = isCrawler ? sseCrawlerRemaining : sseBossRemaining
if (remainingRef.value <= 0) {
if (isCrawler) {
sseCrawlerEnabled.value = false
} else {
sseBossEnabled.value = false
}
return false
}
remainingRef.value -= 1
if (remainingRef.value <= 0) {
if (isCrawler) {
sseCrawlerEnabled.value = false
} else {
sseBossEnabled.value = false
}
ElMessage.info(`监听${isCrawler ? '爬虫' : '大哥'}条数已用完,已自动关闭`)
}
return true
}
const setSseLimit = async (type) => {
const isCrawler = type === 'crawler'
const label = isCrawler ? '爬虫' : '大哥'
const limitRef = isCrawler ? sseCrawlerLimit : sseBossLimit
const remainingRef = isCrawler ? sseCrawlerRemaining : sseBossRemaining
try {
const { value } = await ElMessageBox.prompt(
`请输入监听${label}条数`,
'设置监听条数',
{
inputValue: String(limitRef.value || 0),
inputPattern: /^[1-9]\d*$/,
inputErrorMessage: '请输入正整数',
confirmButtonText: '确定',
cancelButtonText: '取消',
}
)
const next = normalizeSseLimit(value, limitRef.value || 500)
limitRef.value = next
remainingRef.value = next
} catch (e) {
// 用户取消
}
}
// 互斥按钮的样式:激活=红,锁定=半透明且禁点 // 互斥按钮的样式:激活=红,锁定=半透明且禁点
const ctrlStyle = (type) => { const ctrlStyle = (type) => {
const lockedByMode = isLocked(type) const lockedByMode = isLocked(type)
@@ -797,6 +905,11 @@ onMounted(async () => {
// 2⃣ 按开关过滤 // 2⃣ 按开关过滤
if (fromCrawler && !sseCrawlerEnabled.value) return if (fromCrawler && !sseCrawlerEnabled.value) return
if (fromBoss && !sseBossEnabled.value) return if (fromBoss && !sseBossEnabled.value) return
if (fromCrawler) {
if (!bumpSseCount('crawler')) return
} else if (fromBoss) {
if (!bumpSseCount('boss')) return
}
if (isUnknown && !sseCrawlerEnabled.value) return // 老数据当爬虫看 if (isUnknown && !sseCrawlerEnabled.value) return // 老数据当爬虫看
// 3⃣ 按来源取不同字段 // 3⃣ 按来源取不同字段
@@ -1226,8 +1339,8 @@ function startScheduleLoop() {
const now = Date.now() const now = Date.now()
if (!lastInterruptTs) lastInterruptTs = now // 首次初始化 if (!lastInterruptTs) lastInterruptTs = now // 首次初始化
// const due = now - lastInterruptTs >= interruptEveryMin.value * 60_000 * 60 const due = now - lastInterruptTs >= interruptEveryMin.value * 60_000 * 60
const due = now - lastInterruptTs >= interruptEveryMin.value * 60_000 // const due = now - lastInterruptTs >= interruptEveryMin.value * 60_000
console.log( console.log(
'due=', due, 'due=', due,
@@ -1658,11 +1771,13 @@ const markPendingForOffline = (ids) => {
}; };
const onToggleCrawler = (val) => { const onToggleCrawler = (val) => {
if (val) sseBossEnabled.value = false if (val) sseBossEnabled.value = false;
} };
const onToggleBoss = (val) => { const onToggleBoss = (val) => {
if (val) sseCrawlerEnabled.value = false if (val) sseCrawlerEnabled.value = false;
} };
function timestampToTime(timestamp_ms) { function timestampToTime(timestamp_ms) {
const date = new Date(timestamp_ms); const date = new Date(timestamp_ms);