阅读工作台 生成时间:2026-08-04 03:34:50
线上正常 2329 篇 52 只盯盘 同步:准备中
选择一篇文章开始阅读、高亮和做笔记。
盯盘与笔记

今日老师信号

等待生成信号。

本文注释

本文笔记

编号笔记

导出

`; } function exportContentBlocks() { const blocks = []; const highlights = selectedId ? itemState(selectedId).highlights || [] : []; Array.from(readerContent.children).forEach((node) => { if (node.classList && node.classList.contains('reader-placeholder')) return; const text = (node.innerText || node.textContent || '').trim(); if (!text) return; const tag = node.tagName ? node.tagName.toLowerCase() : 'p'; const matched = highlights.filter((highlight) => text.includes(highlight.text)); const markdown = []; if (/^h[1-6]$/.test(tag)) markdown.push(`${'#'.repeat(Number(tag.slice(1)) + 1)} ${text}`, ''); else if (tag === 'li') markdown.push(`- ${text}`, ''); else markdown.push(text, ''); matched.forEach((highlight) => { markdown.push(`> 批注:${highlight.text}`); if (highlight.note) markdown.push(`> 笔记:${highlight.note}`); markdown.push(''); }); const htmlText = escapeHtml(text).replace(/\n/g, '
'); let html = /^h[1-6]$/.test(tag) ? `<${tag}>${htmlText}` : `

${htmlText}

`; html += matched.map((highlight) => `
批注:${escapeHtml(highlight.text)}${highlight.note ? `
笔记:${escapeHtml(highlight.note)}` : ''}
`).join(''); blocks.push({ markdown, html }); }); return blocks; } function downloadText(filename, text, type) { const blob = new Blob([text], { type }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; link.click(); URL.revokeObjectURL(url); } function escapeHtml(value) { return String(value).replace(/[&<>"']/g, (char) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[char])); } function escapeJs(value) { return String(value).replace(new RegExp('\\\\', 'g'), '\\\\').replace(new RegExp("'", 'g'), "\\'"); } document.querySelectorAll('.source-filter').forEach((button) => { button.addEventListener('click', () => { document.querySelectorAll('.source-filter').forEach((item) => item.classList.remove('active')); button.classList.add('active'); sourceFilter = button.dataset.source; render(); }); }); document.querySelectorAll('.zsxq-type-filter').forEach((button) => { button.addEventListener('click', () => { document.querySelectorAll('.zsxq-type-filter').forEach((item) => item.classList.remove('active')); button.classList.add('active'); zsxqTypeFilter = button.dataset.zsxqType || 'all'; render(); }); }); viewTabs.forEach((button) => { button.addEventListener('click', () => switchView(button.dataset.view)); }); themeToggle.addEventListener('click', () => { setTheme(document.body.dataset.theme === 'dark' ? 'light' : 'dark'); }); refreshMarket.addEventListener('click', () => refreshMarketNow(true)); if (toggleMarketManage) toggleMarketManage.addEventListener('click', toggleMarketManageMode); marketOverview.addEventListener('click', (event) => { const signalButton = event.target.closest('button[data-teacher-signal]'); if (signalButton) { event.preventDefault(); event.stopPropagation(); openTeacherSignal(signalButton.dataset.teacherSignal || ''); return; } const teacherButton = event.target.closest('[data-action="show-teacher-evidence"]'); if (teacherButton) { event.preventDefault(); event.stopPropagation(); showMarketTeacherEvidence(teacherButton.dataset.target || '', teacherButton.dataset.scope || 'sector'); return; } const button = event.target.closest('button[data-action="toggle-market-trend"]'); if (button) { marketTrendExpanded = !marketTrendExpanded; renderMarketOverview(); return; } const sectorButton = event.target.closest('button[data-action="toggle-sector-members"]'); if (sectorButton) toggleSectorMembers(sectorButton.dataset.code || ''); }); marketRows.addEventListener('click', (event) => { const signalButton = event.target.closest('button[data-teacher-signal]'); if (signalButton) { event.preventDefault(); event.stopPropagation(); openTeacherSignal(signalButton.dataset.teacherSignal || ''); return; } const hideButton = event.target.closest('[data-action="hide-market-symbol"]'); if (hideButton) { event.preventDefault(); event.stopPropagation(); hideMarketSymbol(hideButton.dataset.symbol || ''); return; } const teacherButton = event.target.closest('[data-action="show-teacher-evidence"]'); if (teacherButton) { event.preventDefault(); event.stopPropagation(); showMarketTeacherEvidence(teacherButton.dataset.target || '', teacherButton.dataset.scope || 'stock'); return; } const row = event.target.closest('.market-row'); if (!row) return; if (teacherSignalsForStock(row.dataset.symbol || '').length) { showMarketTeacherEvidence(row.dataset.symbol || '', 'stock'); return; } selectedMarketSymbol = row.dataset.symbol; renderMarket(); refreshMarketNow(false); }); function bindTeacherPanelClicks(panel) { if (!panel) return; panel.addEventListener('click', (event) => { const groupToggle = event.target.closest('button[data-action="toggle-teacher-group"]'); if (groupToggle) { const group = panel.querySelector(`[data-teacher-group="${CSS.escape(groupToggle.dataset.group || '')}"]`); if (group) { group.classList.toggle('expanded'); groupToggle.textContent = group.classList.contains('expanded') ? '收起' : (groupToggle.dataset.moreLabel || '更多'); } return; } const button = event.target.closest('button[data-teacher-signal]'); if (!button) return; openTeacherSignal(button.dataset.teacherSignal || ''); }); } bindTeacherPanelClicks(teacherSignalPanel); bindTeacherPanelClicks(marketTeacherSignalPanel); if (marketDetail) { marketDetail.addEventListener('click', (event) => { const button = event.target.closest('button[data-teacher-signal]'); if (!button) return; openTeacherSignal(button.dataset.teacherSignal || ''); }); } search.addEventListener('input', render); notes.addEventListener('input', () => { if (!selectedId) return; itemState(selectedId).note = notes.value; touchItem(selectedId); saveState(); }); function handlePossibleSelection() { const selection = window.getSelection(); if (!selection || !selection.rangeCount) return hideToolbar(); const range = selection.getRangeAt(0); if (!(readerContent.contains(range.commonAncestorContainer) || readerComments.contains(range.commonAncestorContainer))) return hideToolbar(); showToolbar(range); } readerContent.addEventListener('mouseup', handlePossibleSelection); readerComments.addEventListener('mouseup', handlePossibleSelection); readerScroll.addEventListener('scroll', () => { if (marginNotes.contains(document.activeElement)) { restoreReaderScrollSoon(lastReaderScrollTop); return; } const current = readerScroll.scrollTop; if (readerScrollHistory[readerScrollHistory.length - 1] !== current) { readerScrollHistory.push(current); if (readerScrollHistory.length > 5) readerScrollHistory.shift(); } lastReaderScrollTop = current; }); document.addEventListener('mouseup', () => setTimeout(handlePossibleSelection, 0)); document.addEventListener('selectionchange', () => { const selection = window.getSelection(); if (!selection || !selection.rangeCount || !String(selection).trim()) return; const range = selection.getRangeAt(0); if (readerContent.contains(range.commonAncestorContainer) || readerComments.contains(range.commonAncestorContainer)) showToolbar(range); }); [readerContent, readerComments].forEach((root) => root.addEventListener('click', (event) => { const term = event.target.closest('.term-chip[data-glossary-term]'); if (term) { focusGlossaryTerm(term.dataset.glossaryTerm || term.textContent || ''); return; } const mark = event.target.closest('.reader-highlight'); if (!mark) return; const note = marginNotes.querySelector(`textarea[data-highlight-note="${CSS.escape(mark.dataset.highlightId)}"]`) || annotationNotesPanel.querySelector(`textarea[data-annotation-note="${CSS.escape(mark.dataset.highlightId)}"]`); if (note) focusWithoutScroll(note); })); annotationToolbar.addEventListener('click', (event) => { const button = event.target.closest('button[data-action]'); if (!button) return; addHighlight(); }); marginNotes.addEventListener('input', (event) => { const textarea = event.target.closest('textarea[data-highlight-note]'); if (!textarea) return; const top = lastReaderScrollTop; updateHighlightNote(textarea.dataset.highlightNote, textarea.value, false); restoreReaderScrollSoon(top); }); annotationNotesPanel.addEventListener('input', (event) => { const textarea = event.target.closest('textarea[data-annotation-note]'); if (!textarea) return; updateHighlightNote(textarea.dataset.annotationNote, textarea.value, false); }); marginNotes.addEventListener('focusin', (event) => { if (!event.target.closest('textarea[data-highlight-note]')) return; const current = readerScroll.scrollTop; const previous = readerScrollHistory.length > 1 ? readerScrollHistory[readerScrollHistory.length - 2] : lastReaderScrollTop; restoreReaderScrollSoon(current !== previous ? previous : lastReaderScrollTop); }); window.addEventListener('resize', () => requestAnimationFrame(positionMarginNotes)); toggleNotebookPanel.addEventListener('click', () => { const collapsed = notebookPanel.classList.toggle('collapsed'); shell.classList.toggle('notebook-collapsed', collapsed); toggleNotebookPanel.textContent = collapsed ? '笔记' : '‹'; requestAnimationFrame(positionMarginNotes); }); exportArticle.addEventListener('click', () => { const item = currentItem(); if (!item) return; if (exportFormat.value === 'word') { downloadText(`${item.title}-阅读笔记.doc`, exportArticleWordHtml(), 'application/msword;charset=utf-8'); } else { downloadText(`${item.title}-阅读笔记.md`, exportArticleMarkdown(), 'text/markdown;charset=utf-8'); } }); setTheme(loadTheme()); render(); renderTeacherSignalPanel(); pullCloudState(); const initialItem = items.find(matches); if (initialItem) { openReader(initialItem.id); } window.openReader = openReader; window.selectNote = selectNote; window.deleteHighlightById = deleteHighlightById; window.exportArticleMarkdown = exportArticleMarkdown; window.exportArticleWordHtml = exportArticleWordHtml; window.addSelectionHighlight = addHighlight; window.refreshMarketNow = refreshMarketNow; window.applyPeOverride = applyPeOverride; window.clearPeOverride = clearPeOverride; window.openTeacherSignal = openTeacherSignal; window.focusTeacherEvidence = focusTeacherEvidence; window.showMarketTeacherEvidence = showMarketTeacherEvidence; window.toggleMarketManageMode = toggleMarketManageMode; window.hideMarketSymbol = hideMarketSymbol;