AI生成不一定完美,有朋友手动调整过的可把修改更完美的版本发出来给大伙用用

<!doctype html><html lang="zh-CN"><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>财联社电报</title> <style> html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; background: transparent; }
* { box-sizing: border-box; }
body { font-family: "Microsoft YaHei", sans-serif; color: rgba(244, 248, 255, 0.94); -webkit-font-smoothing: antialiased; user-select: none; }
button, input { font-family: inherit; }
.card { position: relative; width: 100%; height: 100%; overflow: hidden; padding: clamp(12px, 3.7vw, 18px); border-radius: 18px; border: 1px solid rgba(130, 187, 255, 0.34); background: linear-gradient(180deg, rgba(255, 255, 255, 0.13), rgba(255, 255, 255, 0.035) 35%, rgba(255, 255, 255, 0) 64%), radial-gradient(circle at 12% 0%, rgba(34, 197, 245, 0.23), transparent 35%), radial-gradient(circle at 100% 10%, rgba(239, 68, 68, 0.18), transparent 38%), linear-gradient(145deg, #101a28 0%, #07111f 56%, #151721 100%); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.17), inset 0 -1px 0 rgba(255, 255, 255, 0.05), 0 18px 44px rgba(0, 0, 0, 0.36); display: grid; grid-template-rows: auto auto 1fr auto; gap: clamp(7px, 2vh, 11px); }
.topbar { min-width: 0; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.brand { min-width: 0; display: flex; align-items: center; gap: 10px; }
.mark { flex: 0 0 auto; width: clamp(32px, 8.2vw, 40px); height: clamp(32px, 8.2vw, 40px); border-radius: 12px; display: grid; place-items: center; overflow: hidden; background: rgba(255, 255, 255, 0.1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3), 0 10px 22px rgba(226, 61, 79, 0.24); }
.mark img { width: 100%; height: 100%; display: block; object-fit: cover; }
.mark.epdff-fixed-highlight img { width: 100%; height: 100%; object-fit: cover; }
.titlebox { min-width: 0; }
.title { margin: 0; font-size: clamp(16px, 4.2vw, 22px); line-height: 1.08; letter-spacing: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.meta { margin-top: 4px; font-size: clamp(10px, 2.5vw, 12px); line-height: 1.25; color: rgba(200, 215, 238, 0.72); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.actions { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; position: relative; }
.icon-btn, .small-btn { border: 1px solid rgba(151, 197, 255, 0.28); color: rgba(244, 248, 255, 0.93); background: rgba(255, 255, 255, 0.08); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.13); cursor: pointer; transition: transform 140ms ease, border-color 140ms ease, background 140ms ease; }
.icon-btn { width: clamp(30px, 7.8vw, 36px); height: clamp(30px, 7.8vw, 36px); padding: 0; border-radius: 12px; font-size: 16px; line-height: 1; }
.small-btn { height: 32px; border-radius: 11px; padding: 0 10px; font-size: 12px; white-space: nowrap; }
.icon-btn:hover, .small-btn:hover { border-color: rgba(174, 212, 255, 0.56); background: rgba(255, 255, 255, 0.13); }
.icon-btn:active, .small-btn:active { transform: scale(0.94); background: rgba(255, 255, 255, 0.18); }
.icon-btn:disabled { cursor: default; opacity: 0.55; transform: none; }
.settings-wrap { position: relative; }
.settings-menu { position: absolute; top: calc(100% + 8px); right: 0; width: min(214px, calc(100vw - 24px)); padding: 10px; border-radius: 14px; border: 1px solid rgba(151, 197, 255, 0.3); background: linear-gradient(180deg, rgba(255, 255, 255, 0.11), rgba(255, 255, 255, 0.04)), rgba(8, 18, 32, 0.96); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 16px 30px rgba(0, 0, 0, 0.34); display: none; grid-template-columns: 1fr; gap: 8px; z-index: 5; }
.settings-menu.is-open { display: grid; }
.setting-row { min-width: 0; display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: 8px; align-items: center; color: rgba(205, 219, 242, 0.78); font-size: 12px; line-height: 1.25; }
.controls { min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 7px; align-items: center; }
.field, .number { width: 100%; height: 32px; min-width: 0; border: 1px solid rgba(151, 197, 255, 0.22); border-radius: 11px; outline: none; color: rgba(244, 248, 255, 0.92); background: rgba(5, 12, 24, 0.34); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07); transition: border-color 140ms ease, background 140ms ease; }
.field { padding: 0 10px; font-size: 12px; }
.number { padding: 0 6px; text-align: center; font-size: 12px; font-variant-numeric: tabular-nums; }
.field::placeholder { color: rgba(199, 214, 238, 0.52); }
.field:hover, .field:focus, .number:hover, .number:focus { border-color: rgba(174, 212, 255, 0.54); background: rgba(255, 255, 255, 0.09); }
.feed { min-height: 0; overflow-y: auto; overflow-x: hidden; padding-right: 3px; display: grid; align-content: start; gap: var(--item-gap, 4px); }
.feed::-webkit-scrollbar { width: 6px; }
.feed::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.04); border-radius: 999px; }
.feed::-webkit-scrollbar-thumb { background: rgba(151, 178, 218, 0.38); border-radius: 999px; }
.item { width: 100%; min-width: 0; height: auto; display: grid; grid-template-columns: 38px minmax(0, 1fr); gap: 8px; align-items: start; min-height: calc((var(--font-size, 12px) * 1.24) + 12px); padding: 5px 7px; border: 1px solid transparent; border-radius: 10px; color: inherit; text-align: left; background: rgba(255, 255, 255, 0.035); cursor: pointer; transition: transform 140ms ease, border-color 140ms ease, background 140ms ease; }
.item.epdff-fixed-highlight { height: auto; min-height: calc((var(--font-size, 12px) * 1.24) + 12px); align-items: start; }
.item:hover { border-color: rgba(159, 200, 255, 0.25); background: rgba(255, 255, 255, 0.08); }
.item:active { transform: scale(0.987); background: rgba(255, 255, 255, 0.12); }
.time { padding-top: 1px; color: var(--time-color, #c2c2c2); font-size: var(--font-size, 12px); line-height: 1.24; font-variant-numeric: tabular-nums; white-space: nowrap; }
.headline { min-width: 0; color: var(--text-color, #ffffff); font-size: var(--font-size, 12px); line-height: 1.24; min-height: 1.24em; max-height: calc(var(--font-size, 12px) * 1.24 * var(--line-limit, 2)); display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: var(--line-limit, 2); overflow: hidden; overflow-wrap: anywhere; }
.foot { min-height: 16px; display: flex; align-items: center; justify-content: space-between; gap: 8px; color: rgba(195, 211, 236, 0.66); font-size: 11px; line-height: 1.25; }
.status, .count { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.count { flex: 0 0 auto; }
@media (max-width: 380px), (max-height: 290px) { .card { padding: 10px; gap: 7px; }
.controls { grid-template-columns: minmax(0, 1fr); }
.meta { display: none; }
.settings-menu { width: min(198px, calc(100vw - 20px)); }
.item { grid-template-columns: 36px minmax(0, 1fr); padding: 4px 6px; } } </style></head><body> <main class="card" aria-label="财联社电报浮岛组件"> <header class="topbar"> <div class="brand"> <div class="mark" aria-hidden="true"> <img src="https://image.cls.cn/share/cailianpress.png" alt=""> </div> <div class="titlebox"> <h1 class="title">财联社电报</h1> <div class="meta" id="updatedAt">本地兜底内容</div> </div> </div> <div class="actions"> <div class="settings-wrap"> <button class="icon-btn" id="settingsToggle" type="button" title="设置" aria-label="设置" aria-expanded="false">⚙</button> <div class="settings-menu" id="settingsMenu" aria-label="设置菜单"> <label class="setting-row"> <span>字体大小</span> <input class="number" id="fontSize" type="number" min="10" max="18" step="1" title="字体大小" aria-label="字体大小"> </label> <label class="setting-row"> <span>行数限制</span> <input class="number" id="lineLimit" type="number" min="1" max="5" step="1" title="行数限制" aria-label="行数限制"> </label> <button class="small-btn" id="reset" type="button">重置设置</button> </div> </div> <button class="icon-btn" id="openHome" type="button" title="打开财联社" aria-label="打开财联社">↗</button> <button class="icon-btn" id="refresh" type="button" title="刷新电报" aria-label="刷新电报">⟳</button> </div> </header>
<section class="controls" aria-label="显示设置"> <input class="field" id="exclude" type="text" autocomplete="off" placeholder="过滤关键词或正则"> </section>
<section class="feed" id="feed" aria-live="polite"></section>
<footer class="foot"> <span class="status" id="status">等待浮岛宿主初始化</span> <span class="count" id="count">0 条</span> </footer> </main>
<script> (function () { var API_URL = 'https://www.cls.cn/nodeapi/telegraphList'; var HOME_URL = 'https://m.cls.cn'; var defaults = { fontSize: 12, textColor: '#ffffff', timeColor: '#c2c2c2', lineLimit: 1, space: 4, exclude: '' }; var state = { settings: Object.assign({}, defaults), items: [ { title: '财联社电报组件已就绪', content: '财联社电报组件已就绪', ctime: Math.floor(Date.now() / 1000), shareurl: HOME_URL }, { title: '等待浮岛宿主连接后自动刷新', content: '等待浮岛宿主连接后自动刷新', ctime: Math.floor(Date.now() / 1000), shareurl: HOME_URL }, { title: '可设置过滤关键词、字号和标题行数', content: '可设置过滤关键词、字号和标题行数', ctime: Math.floor(Date.now() / 1000), shareurl: HOME_URL } ], updatedAt: '', hostReady: false, loading: false };
var feedEl = document.getElementById('feed'); var statusEl = document.getElementById('status'); var countEl = document.getElementById('count'); var updatedAtEl = document.getElementById('updatedAt'); var refreshBtn = document.getElementById('refresh'); var openHomeBtn = document.getElementById('openHome'); var settingsToggleBtn = document.getElementById('settingsToggle'); var settingsMenuEl = document.getElementById('settingsMenu'); var resetBtn = document.getElementById('reset'); var excludeInput = document.getElementById('exclude'); var fontSizeInput = document.getElementById('fontSize'); var lineLimitInput = document.getElementById('lineLimit');
function invoke(method, args) { return window.fudao.invoke(method, args || {}); }
function pad(value) { return String(value).padStart(2, '0'); }
function nowText() { var date = new Date(); return pad(date.getHours()) + ':' + pad(date.getMinutes()); }
function formatTime(value) { var number = Number(value); var date = Number.isFinite(number) && number > 0 ? new Date(number * 1000) : new Date(); return pad(date.getHours()) + ':' + pad(date.getMinutes()); }
function cleanText(value) { return String(value == null ? '' : value).replace(/\s+/g, ' ').trim(); }
function parseJSON(value, fallback) { try { if (typeof value !== 'string' || !value) return fallback; return JSON.parse(value); } catch (err) { return fallback; } }
function clampNumber(value, min, max, fallback) { var number = Number(value); if (!Number.isFinite(number)) return fallback; return Math.min(max, Math.max(min, Math.round(number))); }
function readState(key, defaultValue) { return invoke('state.read', { key: key, defaultValue: JSON.stringify(defaultValue) }).then(function (res) { return parseJSON(res, defaultValue); }); }
function writeState(key, value) { return invoke('state.write', { key: key, value: JSON.stringify(value) }).catch(function () {}); }
function normalizeSettings(input) { var next = Object.assign({}, defaults, input || {}); next.fontSize = clampNumber(next.fontSize, 10, 18, defaults.fontSize); next.lineLimit = clampNumber(next.lineLimit, 1, 5, defaults.lineLimit); next.space = clampNumber(next.space, 0, 12, defaults.space); next.exclude = cleanText(next.exclude); next.textColor = /^#[0-9a-f]{6}$/i.test(next.textColor) ? next.textColor : defaults.textColor; next.timeColor = /^#[0-9a-f]{6}$/i.test(next.timeColor) ? next.timeColor : defaults.timeColor; return next; }
function normalizeItems(payload) { var list = payload && payload.data && Array.isArray(payload.data.roll_data) ? payload.data.roll_data : []; return list.map(function (item) { var title = cleanText(item.title || item.content); if (!title) return null; return { title: title, content: cleanText(item.content || title), ctime: Number(item.ctime) || Math.floor(Date.now() / 1000), shareurl: cleanText(item.shareurl || HOME_URL) }; }).filter(Boolean); }
function filteredItems() { var list = state.items.slice(); var pattern = state.settings.exclude; if (!pattern) return list; try { var re = new RegExp(pattern, 'i'); return list.filter(function (item) { return !re.test(item.title || item.content || ''); }); } catch (err) { var keyword = pattern.toLowerCase(); return list.filter(function (item) { return (item.title || item.content || '').toLowerCase().indexOf(keyword) === -1; }); } }
function setStatus(text) { statusEl.textContent = text; }
function setSettingsMenu(open) { settingsMenuEl.classList.toggle('is-open', open); settingsToggleBtn.setAttribute('aria-expanded', open ? 'true' : 'false'); }
function applySettings() { var root = document.documentElement; root.style.setProperty('--font-size', state.settings.fontSize + 'px'); root.style.setProperty('--line-limit', state.settings.lineLimit); root.style.setProperty('--item-gap', state.settings.space + 'px'); root.style.setProperty('--text-color', state.settings.textColor); root.style.setProperty('--time-color', state.settings.timeColor); excludeInput.value = state.settings.exclude; fontSizeInput.value = state.settings.fontSize; lineLimitInput.value = state.settings.lineLimit; }
function renderList() { var items = filteredItems(); var fragment = document.createDocumentFragment(); items.forEach(function (item) { var button = document.createElement('button'); button.type = 'button'; button.className = 'item'; button.dataset.url = item.shareurl || HOME_URL; button.title = item.title;
var time = document.createElement('span'); time.className = 'time'; time.textContent = formatTime(item.ctime);
var headline = document.createElement('span'); headline.className = 'headline'; headline.textContent = item.title || item.content;
button.appendChild(time); button.appendChild(headline); fragment.appendChild(button); }); feedEl.replaceChildren(fragment); countEl.textContent = items.length + ' 条'; updatedAtEl.textContent = state.updatedAt ? '更新于 ' + state.updatedAt : '本地兜底内容'; }
function render() { applySettings(); renderList(); refreshBtn.disabled = state.loading; refreshBtn.textContent = state.loading ? '…' : '⟳'; }
function saveSettings() { state.settings = normalizeSettings(state.settings); render(); return writeState('settings', state.settings); }
function loadCachedData() { return readState('telegraphCache', null).then(function (cache) { if (cache && Array.isArray(cache.items) && cache.items.length) { state.items = cache.items; state.updatedAt = cleanText(cache.updatedAt); render(); } }); }
function refresh() { if (!state.hostReady || state.loading) return; state.loading = true; setStatus('正在刷新电报'); render();
invoke('http.get', { url: API_URL, headers: {}, timeoutMs: 10000 }).then(function (result) { if (!result || !result.ok) { var status = result && result.status ? 'HTTP ' + result.status : '请求失败'; throw new Error(status); } var json = JSON.parse(result.text || '{}'); var items = normalizeItems(json); if (!items.length) throw new Error('电报数据为空'); state.items = items; state.updatedAt = nowText(); setStatus('电报已更新'); return writeState('telegraphCache', { items: state.items, updatedAt: state.updatedAt }); }).catch(function () { setStatus(state.items.length ? '已显示上次可用数据' : '刷新失败'); }).then(function () { state.loading = false; render(); }); }
function openUrl(url) { if (!state.hostReady) return; invoke('url.open', { url: url || HOME_URL, closeAfterOpen: true }).catch(function () { setStatus('打开失败'); }); }
function bindEvents() { settingsToggleBtn.addEventListener('click', function (event) { event.stopPropagation(); setSettingsMenu(!settingsMenuEl.classList.contains('is-open')); }); settingsMenuEl.addEventListener('click', function (event) { event.stopPropagation(); }); document.addEventListener('click', function () { setSettingsMenu(false); }); refreshBtn.addEventListener('click', refresh); openHomeBtn.addEventListener('click', function () { openUrl(HOME_URL); }); feedEl.addEventListener('click', function (event) { var item = event.target.closest('.item'); if (!item) return; openUrl(item.dataset.url); }); resetBtn.addEventListener('click', function () { state.settings = Object.assign({}, defaults); saveSettings(); }); excludeInput.addEventListener('input', function () { state.settings.exclude = excludeInput.value; renderList(); }); excludeInput.addEventListener('change', saveSettings); fontSizeInput.addEventListener('change', function () { state.settings.fontSize = fontSizeInput.value; saveSettings(); }); lineLimitInput.addEventListener('change', function () { state.settings.lineLimit = lineLimitInput.value; saveSettings(); }); }
function initWhenReady() { if (!window.fudao || typeof window.fudao.invoke !== 'function') { setTimeout(initWhenReady, 120); return; }
state.hostReady = true; setStatus('浮岛宿主已连接'); Promise.all([ readState('settings', defaults), loadCachedData() ]).then(function (values) { state.settings = normalizeSettings(values[0]); render(); refresh(); }).catch(function () { setStatus('读取状态失败,使用默认设置'); render(); refresh(); }); }
bindEvents(); render(); setTimeout(initWhenReady, 0); })(); </script></body></html>