diff --git a/frontend/src/components/console/ControlStrip.vue b/frontend/src/components/console/ControlStrip.vue index 34edf34..681ddb0 100644 --- a/frontend/src/components/console/ControlStrip.vue +++ b/frontend/src/components/console/ControlStrip.vue @@ -12,11 +12,15 @@ const { currentActivity } = useActivity() const isXiaodian = computed(() => currentActivity.value?.id === 'xiaodian') const { products, selectedProductId, loadProducts, selectProduct } = useProducts() const { showToast } = useToast() -const fixedKeyword = ref(localStorage.getItem('xiaodianFixedKeyword') || '') +const fixedKeyword = ref(localStorage.getItem('xiaodianFixedKeyword') || localStorage.getItem('xiaodianWatchKeyword') || '') const fixedAttempts = ref(Number(localStorage.getItem('xiaodianFixedAttempts') || 3)) const fixedDelayMs = ref(Number(localStorage.getItem('xiaodianFixedDelayMs') || 500)) +const watchStartTime = ref(localStorage.getItem('xiaodianWatchStartTime') || '00:00:00') +const watchIntervalSec = ref(Number(localStorage.getItem('xiaodianWatchIntervalSec') || 3)) const keywordWatching = ref(false) let keywordTimer: number | null = null +let keywordStartTimer: number | null = null +let keywordRefreshing = false // 从本地缓存恢复定时设置 const { savedTime } = restoreSchedule() @@ -36,55 +40,99 @@ const queryAssets = () => { const saveFixedConfig = () => { localStorage.setItem('xiaodianFixedKeyword', fixedKeyword.value.trim()) + localStorage.setItem('xiaodianWatchKeyword', fixedKeyword.value.trim()) localStorage.setItem('xiaodianFixedAttempts', String(fixedAttempts.value)) localStorage.setItem('xiaodianFixedDelayMs', String(fixedDelayMs.value)) + localStorage.setItem('xiaodianWatchStartTime', watchStartTime.value) + localStorage.setItem('xiaodianWatchIntervalSec', String(watchIntervalSec.value)) } const startFixedBuy = () => { saveFixedConfig() + if (keywordWatching.value) stopKeywordWatch() startFixed(fixedAttempts.value, fixedDelayMs.value) } +const stopKeywordWatch = () => { + keywordWatching.value = false + if (keywordTimer) { + clearInterval(keywordTimer) + keywordTimer = null + } + if (keywordStartTimer) { + clearTimeout(keywordStartTimer) + keywordStartTimer = null + } + keywordRefreshing = false +} + +const beginKeywordWatch = async () => { + if (!keywordWatching.value || !isXiaodian.value) return + await loadProducts(true) + const keyword = fixedKeyword.value.trim().toLowerCase() + const hit = products.value.find(p => p.commodityName.toLowerCase().includes(keyword)) + if (hit) { + stopKeywordWatch() + selectProduct(hit.commodityId, hit.commodityName) + await startFixed(fixedAttempts.value, fixedDelayMs.value) + return + } + const interval = Math.max(1, Math.min(600, Number(watchIntervalSec.value) || 3)) * 1000 + keywordTimer = window.setInterval(async () => { + if (!keywordWatching.value || scheduleActive.value || keywordRefreshing) return + keywordRefreshing = true + try { + await loadProducts(false) + const currentKeyword = fixedKeyword.value.trim().toLowerCase() + const currentHit = products.value.find(p => p.commodityName.toLowerCase().includes(currentKeyword)) + if (currentHit) { + stopKeywordWatch() + selectProduct(currentHit.commodityId, currentHit.commodityName) + await startFixed(fixedAttempts.value, fixedDelayMs.value) + } + } finally { + keywordRefreshing = false + } + }, interval) +} + const toggleKeywordWatch = () => { + if (keywordWatching.value) { + stopKeywordWatch() + return + } keywordWatching.value = !keywordWatching.value if (keywordWatching.value) { saveFixedConfig() if (!fixedKeyword.value.trim()) { - keywordWatching.value = false + stopKeywordWatch() showToast('请输入关键词', '设置商品关键词后再开始监控', 'warn') return } - void loadProducts(true) - keywordTimer = window.setInterval(async () => { - if (!keywordWatching.value || scheduleActive.value) return - await loadProducts(false) - const keyword = fixedKeyword.value.trim().toLowerCase() - const hit = products.value.find(p => p.commodityName.toLowerCase().includes(keyword)) - if (hit) { - keywordWatching.value = false - if (keywordTimer) clearInterval(keywordTimer) - selectProduct(hit.commodityId, hit.commodityName) - await startFixed(fixedAttempts.value, fixedDelayMs.value) - } - }, 3000) - } else if (keywordTimer) { - clearInterval(keywordTimer) - keywordTimer = null + const [hours, minutes, seconds] = watchStartTime.value.split(':').map(Number) + const target = new Date() + target.setHours(hours || 0, minutes || 0, seconds || 0, 0) + const waitMs = Math.max(0, target.getTime() - Date.now()) + if (waitMs > 0) { + showToast('监控已设置', `${watchStartTime.value} 开始监控`, 'info', 3000) + keywordStartTimer = window.setTimeout(() => { + keywordStartTimer = null + void beginKeywordWatch() + }, waitMs) + } else { + void beginKeywordWatch() + } } } watch(isXiaodian, (enabled) => { if (!enabled && keywordWatching.value) { - keywordWatching.value = false - if (keywordTimer) { - clearInterval(keywordTimer) - keywordTimer = null - } + stopKeywordWatch() } }) onUnmounted(() => { - if (keywordTimer) clearInterval(keywordTimer) + stopKeywordWatch() }) @@ -112,25 +160,38 @@ onUnmounted(() => {