diff --git a/modules/novel-draw/floating-panel.js b/modules/novel-draw/floating-panel.js index 1a46a97..fe273db 100644 --- a/modules/novel-draw/floating-panel.js +++ b/modules/novel-draw/floating-panel.js @@ -10,6 +10,7 @@ import { saveSettings, findLastAIMessageId, classifyError, + isGenerating, } from './novel-draw.js'; import { registerToToolbar, removeFromToolbar } from '../../widgets/message-toolbar.js'; @@ -754,6 +755,11 @@ async function handleFloorDrawClick(messageId) { const panelData = panelMap.get(messageId); if (!panelData || panelData.state !== FloatState.IDLE) return; + if (isGenerating()) { + toastr?.info?.('已有任务进行中,请等待完成'); + return; + } + try { await generateAndInsertImages({ messageId, @@ -777,8 +783,9 @@ async function handleFloorDrawClick(messageId) { }); } catch (e) { console.error('[NovelDraw]', e); - if (e.message === '已取消') { + if (e.message === '已取消' || e.message?.includes('已有任务进行中')) { setFloorState(messageId, FloatState.IDLE); + if (e.message?.includes('已有任务进行中')) toastr?.info?.(e.message); } else { setFloorState(messageId, FloatState.ERROR, { error: classifyError(e) }); } @@ -1230,6 +1237,11 @@ async function handleFloatingDrawClick() { return; } + if (isGenerating()) { + toastr?.info?.('已有任务进行中,请等待完成'); + return; + } + try { await generateAndInsertImages({ messageId, @@ -1253,8 +1265,9 @@ async function handleFloatingDrawClick() { }); } catch (e) { console.error('[NovelDraw]', e); - if (e.message === '已取消') { + if (e.message === '已取消' || e.message?.includes('已有任务进行中')) { setFloatingState(FloatState.IDLE); + if (e.message?.includes('已有任务进行中')) toastr?.info?.(e.message); } else { setFloatingState(FloatState.ERROR, { error: classifyError(e) }); } @@ -1547,4 +1560,5 @@ export { SIZE_OPTIONS, createFloatingButton, destroyFloatingButton, + setFloatingState, }; diff --git a/modules/novel-draw/novel-draw.js b/modules/novel-draw/novel-draw.js index 373b16c..9c54b3a 100644 --- a/modules/novel-draw/novel-draw.js +++ b/modules/novel-draw/novel-draw.js @@ -274,7 +274,7 @@ function abortGeneration() { } function isGenerating() { - return generationAbortController !== null; + return autoBusy || generationAbortController !== null; } // ═══════════════════════════════════════════════════════════════════════════ @@ -1723,12 +1723,16 @@ async function handleMessageModified(data) { // 多图生成 // ═══════════════════════════════════════════════════════════════════════════ -async function generateAndInsertImages({ messageId, onStateChange }) { +async function generateAndInsertImages({ messageId, onStateChange, skipLock = false }) { await loadSettings(); const ctx = getContext(); const message = ctx.chat?.[messageId]; if (!message) throw new NovelDrawError('消息不存在', ErrorType.PARSE); + if (!skipLock && isGenerating()) { + throw new NovelDrawError('已有任务进行中', ErrorType.UNKNOWN); + } + generationAbortController = new AbortController(); const signal = generationAbortController.signal; @@ -1936,7 +1940,12 @@ async function generateAndInsertImages({ messageId, onStateChange }) { async function autoGenerateForLastAI() { const s = getSettings(); - if (!isModuleEnabled() || s.mode !== 'auto' || autoBusy) return; + if (!isModuleEnabled() || s.mode !== 'auto') return; + + if (isGenerating()) { + console.log('[NovelDraw] 自动模式:已有任务进行中,跳过'); + return; + } const ctx = getContext(); const chat = ctx.chat || []; @@ -1955,34 +1964,48 @@ async function autoGenerateForLastAI() { autoBusy = true; try { - const { setStateForMessage, FloatState, ensureNovelDrawPanel } = await import('./floating-panel.js'); + const { setStateForMessage, setFloatingState, FloatState, ensureNovelDrawPanel } = await import('./floating-panel.js'); + const floatingOn = s.showFloatingButton === true; + const floorOn = s.showFloorButton !== false; + const useFloatingOnly = floatingOn && floorOn; + + const updateState = (state, data = {}) => { + if (useFloatingOnly || (floatingOn && !floorOn)) { + setFloatingState?.(state, data); + } else if (floorOn) { + setStateForMessage(lastIdx, state, data); + } + }; - // 确保面板存在 - const messageEl = document.querySelector(`.mes[mesid="${lastIdx}"]`); - if (messageEl) { - ensureNovelDrawPanel(messageEl, lastIdx, { force: true }); + if (floorOn && !useFloatingOnly) { + const messageEl = document.querySelector(`.mes[mesid="${lastIdx}"]`); + if (messageEl) { + ensureNovelDrawPanel(messageEl, lastIdx, { force: true }); + } } await generateAndInsertImages({ messageId: lastIdx, + skipLock: true, onStateChange: (state, data) => { switch (state) { case 'llm': - setStateForMessage(lastIdx, FloatState.LLM); + updateState(FloatState.LLM); break; case 'gen': case 'progress': - setStateForMessage(lastIdx, FloatState.GEN, data); + updateState(FloatState.GEN, data); break; case 'cooldown': - setStateForMessage(lastIdx, FloatState.COOLDOWN, data); + updateState(FloatState.COOLDOWN, data); break; case 'success': - setStateForMessage( - lastIdx, - data.success === data.total ? FloatState.SUCCESS : FloatState.PARTIAL, + updateState( + (data.aborted && data.success === 0) ? FloatState.IDLE + : (data.success < data.total) ? FloatState.PARTIAL + : FloatState.SUCCESS, data - ); + ); break; } } @@ -1993,8 +2016,16 @@ async function autoGenerateForLastAI() { } catch (e) { console.error('[NovelDraw] 自动配图失败:', e); try { - const { setStateForMessage, FloatState } = await import('./floating-panel.js'); - setStateForMessage(lastIdx, FloatState.ERROR, { error: classifyError(e) }); + const { setStateForMessage, setFloatingState, FloatState } = await import('./floating-panel.js'); + const floatingOn = s.showFloatingButton === true; + const floorOn = s.showFloorButton !== false; + const useFloatingOnly = floatingOn && floorOn; + + if (useFloatingOnly || (floatingOn && !floorOn)) { + setFloatingState?.(FloatState.ERROR, { error: classifyError(e) }); + } else if (floorOn) { + setStateForMessage(lastIdx, FloatState.ERROR, { error: classifyError(e) }); + } } catch {} } finally { autoBusy = false;