From 62df3bcf5bea2306bc139318f7621dbbe206b770 Mon Sep 17 00:00:00 2001 From: yangxiangyuan Date: Mon, 20 Jul 2026 10:35:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E8=83=8C=E6=99=AF=E5=8A=9F=E8=83=BD=E4=B8=8E=E6=B0=91=E8=B0=A3?= =?UTF-8?q?=E6=AD=8C=E5=8D=95=EF=BC=8C=E9=87=8D=E6=9E=84=E8=83=8C=E6=99=AF?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增两个后台接口获取本地背景文件列表和随机背景 2. 重构页面背景切换系统,增加本地默认背景模式并支持本地存储配置 3. 调整背景切换按钮样式为纯图标风格,新增本地模式开关 4. 新增民谣精选歌单文件 5. 优化主题轮播逻辑,支持本地背景自动轮换 --- public/index.css | 64 ++++-- public/index.js | 137 +++++++++++-- .../zen_box/folk_mingyao_34_playlist.json | 194 ++++++++++++++++++ .../skills/email_sender/email.db-shm | Bin 32768 -> 32768 bytes .../skills/email_sender/email.db-wal | Bin 1017672 -> 1343152 bytes src/server/index.js | 24 +++ 6 files changed, 389 insertions(+), 30 deletions(-) create mode 100644 public/tools/zen_box/folk_mingyao_34_playlist.json diff --git a/public/index.css b/public/index.css index 2a4d7da..282dc99 100644 --- a/public/index.css +++ b/public/index.css @@ -12,28 +12,39 @@ --card-text-color: #f8fafc; } -/* 顶部右侧滑块(打开方式) */ +/* 顶部右侧滑块(打开方式 + 本地背景) */ .top-right-controls { position: fixed; top: 16px; right: 16px; z-index: 1000; + display: flex; + gap: 10px; + align-items: center; } .ios-switch { position: relative; - display: inline-block; + display: inline-flex; + flex-direction: column; + align-items: center; + gap: 2px; width: 52px; - height: 28px; + height: 46px; cursor: pointer; } .ios-switch input { opacity: 0; width: 0; height: 0; + position: absolute; + top: 16px; } .ios-switch .slider { position: absolute; - inset: 0; + top: 0; + left: 0; + right: 0; + height: 28px; background: linear-gradient(135deg, #334155, #0f172a); border: 1px solid rgba(255,255,255,0.15); border-radius: 999px; @@ -283,26 +294,45 @@ body { -/* 换背景按钮 */ -.change-background-btn { +/* 换背景按钮容器(按钮 + 本地模式开关) */ +.bg-btn-wrapper { position: fixed; bottom: 2rem; right: 2rem; - background: rgba(255, 255, 255, 0.2); - border: 1px solid rgba(255, 255, 255, 0.3); - border-radius: 50px; - padding: 0.75rem 1.5rem; - color: var(--text-light); - font-size: 0.9rem; - cursor: pointer; - transition: all 0.3s ease; - backdrop-filter: blur(10px); + display: flex; + align-items: center; + gap: 12px; z-index: 1000; } +/* 换背景按钮(仅图标) */ +.change-background-btn { + background: transparent; + border: none; + border-radius: 50%; + width: auto; + height: auto; + padding: 2px; + color: var(--text-light); + font-size: 1.6rem; + line-height: 1; + cursor: pointer; + transition: all 0.2s ease; + backdrop-filter: none; + display: inline-flex; + align-items: center; + justify-content: center; +} + .change-background-btn:hover { - background: rgba(255, 255, 255, 0.3); - transform: translateY(-2px); + background: rgba(255, 255, 255, 0.2); + outline: 1px solid rgba(255, 255, 255, 0.3); + backdrop-filter: blur(10px); + padding: 2px; +} + +.change-background-btn::after { + content: '🎨'; } /* 响应式设计 */ diff --git a/public/index.js b/public/index.js index a99a9e4..160c3c0 100644 --- a/public/index.js +++ b/public/index.js @@ -4,6 +4,15 @@ class ToolboxHome { constructor() { this.currentTheme = 0; this.openInModal = true; + this.localBgMode = false; + this.localBgFiles = []; + this.localBgIndex = 0; + this.localRotationInterval = null; + // 从 localStorage 恢复状态 + try { + this.localBgMode = localStorage.getItem('tb_home_local_bg') === '1'; + this.openInModal = localStorage.getItem('tb_home_open_mode') !== '0'; + } catch {} this.themes = [ { name: '夜空星轨', @@ -263,11 +272,6 @@ class ToolboxHome { tabPages.appendChild(lowToolsPage); tabPages.appendChild(bookmarksPage); - // 创建换背景按钮 - const changeBgBtn = document.createElement('button'); - changeBgBtn.className = 'change-background-btn'; - changeBgBtn.innerHTML = '🎨 换背景'; - // 组装页面 mainContainer.appendChild(header); mainContainer.appendChild(tabBar); @@ -277,7 +281,6 @@ class ToolboxHome { document.body.appendChild(backgroundContainer); document.body.appendChild(effectsContainer); document.body.appendChild(mainContainer); - document.body.appendChild(changeBgBtn); // 顶部右侧滑块(弹窗/本地切换) const controls = document.createElement('div'); controls.className = 'top-right-controls'; @@ -288,7 +291,24 @@ class ToolboxHome { `; document.body.appendChild(controls); - this.ensureBgLoaded(0, true); + // 换背景按钮容器(图标按钮 + 本地模式开关,水平排列,放底部) + const bgBtnWrapper = document.createElement('div'); + bgBtnWrapper.className = 'bg-btn-wrapper'; + bgBtnWrapper.innerHTML = ` + + + `; + document.body.appendChild(bgBtnWrapper); + // 根据 localStorage 状态初始化背景模式 + if (this.localBgMode) { + this.startLocalBgRotation(); + } else { + this.ensureBgLoaded(0, true); + this.startThemeRotation(); + } const iconPicker = document.createElement('div'); iconPicker.className = 'icon-picker'; @@ -624,7 +644,7 @@ class ToolboxHome { setupEventListeners() { // 换背景按钮事件 document.querySelector('.change-background-btn').addEventListener('click', () => { - this.ensureBgLoaded(this.currentTheme, false); + this.nextTheme(); }); // 工具卡片点击效果 + 打开方式(委托方式,支持动态加载) @@ -648,10 +668,28 @@ class ToolboxHome { }); // 滑块切换事件 - const switchEl = document.getElementById('open-mode-switch'); - if (switchEl) { - switchEl.addEventListener('change', () => { - this.openInModal = !!switchEl.checked; + const localBgSwitch = document.getElementById('local-bg-switch'); + const openModeSwitch = document.getElementById('open-mode-switch'); + if (localBgSwitch) { + localBgSwitch.checked = this.localBgMode; + localBgSwitch.addEventListener('change', () => { + this.localBgMode = !!localBgSwitch.checked; + try { localStorage.setItem('tb_home_local_bg', this.localBgMode ? '1' : '0'); } catch {} + if (this.localBgMode) { + this.stopThemeRotation(); + this.startLocalBgRotation(); + } else { + this.stopLocalBgRotation(); + this.ensureBgLoaded(this.currentTheme, true); + this.startThemeRotation(); + } + }); + } + if (openModeSwitch) { + openModeSwitch.checked = this.openInModal; + openModeSwitch.addEventListener('change', () => { + this.openInModal = !!openModeSwitch.checked; + try { localStorage.setItem('tb_home_open_mode', this.openInModal ? '1' : '0'); } catch {} }); } @@ -1264,6 +1302,10 @@ class ToolboxHome { } nextTheme() { + if (this.localBgMode) { + this.nextLocalBg(); + return; + } this.currentTheme = (this.currentTheme + 1) % this.themes.length; this.applyTheme(this.currentTheme); @@ -1417,12 +1459,81 @@ class ToolboxHome { } startBackgroundRotation() { - // 每30秒自动切换背景 + this.startThemeRotation(); + } + + startThemeRotation() { + if (this.localBgMode) return; + this.stopThemeRotation(); this.rotationInterval = setInterval(() => { this.nextTheme(); }, 30000); } + stopThemeRotation() { + if (this.rotationInterval) { + clearInterval(this.rotationInterval); + this.rotationInterval = null; + } + } + + startLocalBgRotation() { + this.loadLocalBgFiles().then(() => { + this.stopLocalBgRotation(); + this.localRotationInterval = setInterval(() => { + this.nextLocalBg(); + }, 30000); + }); + } + + stopLocalBgRotation() { + if (this.localRotationInterval) { + clearInterval(this.localRotationInterval); + this.localRotationInterval = null; + } + } + + async loadLocalBgFiles() { + if (this.localBgFiles.length > 0) return this.localBgFiles; + try { + const r = await fetch('/api/home/bg/default-list?t=' + Date.now()); + const j = await r.json(); + if (j.ok && j.files.length) { + this.localBgFiles = j.files; + this.localBgIndex = 0; + // 加载第一张 + const imgs = document.querySelectorAll('.background-image'); + if (imgs.length) { + imgs.forEach(img => { img.src = `/home-bg/default-c21f969b/${this.localBgFiles[0]}?v=${Date.now()}`; }); + } + } + } catch {} + return this.localBgFiles; + } + + async nextLocalBg() { + if (!this.localBgFiles.length) { + await this.loadLocalBgFiles(); + if (!this.localBgFiles.length) return; + } + // 随机选取,避免重复当前 + let newIndex; + if (this.localBgFiles.length > 1) { + do { + newIndex = Math.floor(Math.random() * this.localBgFiles.length); + } while (newIndex === this.localBgIndex); + } else { + newIndex = 0; + } + this.localBgIndex = newIndex; + const file = this.localBgFiles[this.localBgIndex]; + const imgs = document.querySelectorAll('.background-image'); + if (imgs.length) { + imgs.forEach(img => { img.src = `/home-bg/default-c21f969b/${file}?v=${Date.now()}`; }); + } + this.showNotification(`本地背景: ${this.localBgIndex + 1}/${this.localBgFiles.length}`); + } + showNotification(message) { // 创建通知元素 const notification = document.createElement('div'); diff --git a/public/tools/zen_box/folk_mingyao_34_playlist.json b/public/tools/zen_box/folk_mingyao_34_playlist.json new file mode 100644 index 0000000..7646b7f --- /dev/null +++ b/public/tools/zen_box/folk_mingyao_34_playlist.json @@ -0,0 +1,194 @@ +[ + { + "title": "我记得", + "artist": "赵雷", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/01.mp3", + "cover": "" + }, + { + "title": "三里屯的夜", + "artist": "赵雷", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/02.mp3", + "cover": "" + }, + { + "title": "凌晨计程车", + "artist": "赵雷", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/03.mp3", + "cover": "" + }, + { + "title": "点歌的人", + "artist": "海来阿木", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/04.mp3", + "cover": "" + }, + { + "title": "西楼儿女", + "artist": "海来阿木", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/05.mp3", + "cover": "" + }, + { + "title": "诺言", + "artist": "海来阿木", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/06.mp3", + "cover": "" + }, + { + "title": "鲜花", + "artist": "回春丹", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/07.mp3", + "cover": "" + }, + { + "title": "初恋", + "artist": "回春丹", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/08.mp3", + "cover": "" + }, + { + "title": "泸沽湖", + "artist": "麻园诗人", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/09.mp3", + "cover": "" + }, + { + "title": "现在现在", + "artist": "麻园诗人", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/10.mp3", + "cover": "" + }, + { + "title": "少女", + "artist": "赵雷", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/12.mp3", + "cover": "" + }, + { + "title": "漠河舞厅", + "artist": "柳爽", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/13.mp3", + "cover": "" + }, + { + "title": "三生三幸", + "artist": "海来阿木", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/14.mp3", + "cover": "" + }, + { + "title": "美好事物", + "artist": "房东的猫", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/15.mp3", + "cover": "" + }, + { + "title": "总有一天你会出现在我身边", + "artist": "棱镜", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/16.mp3", + "cover": "" + }, + { + "title": "踏浪", + "artist": "棱镜", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/17.mp3", + "cover": "" + }, + { + "title": "带我去找夜生活", + "artist": "告五人", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/18.mp3", + "cover": "" + }, + { + "title": "我欢喜喜欢你", + "artist": "焦迈奇", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/19.mp3", + "cover": "" + }, + { + "title": "无名的人", + "artist": "毛不易", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/20.mp3", + "cover": "" + }, + { + "title": "空空", + "artist": "陈粒", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/21.mp3", + "cover": "" + }, + { + "title": "大梦", + "artist": "陈粒", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/23.mp3", + "cover": "" + }, + { + "title": "我曾", + "artist": "隔壁老樊", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/24.mp3", + "cover": "" + }, + { + "title": "多年以后", + "artist": "大欢", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/25.mp3", + "cover": "" + }, + { + "title": "从前说", + "artist": "小阿七", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/26.mp3", + "cover": "" + }, + { + "title": "那年年少", + "artist": "小阿七", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/27.mp3", + "cover": "" + }, + { + "title": "与我无关", + "artist": "阿冗", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/28.mp3", + "cover": "" + }, + { + "title": "把回忆拼好给你", + "artist": "王贰浪", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/29.mp3", + "cover": "" + }, + { + "title": "巡光", + "artist": "就是南方凯", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/30.mp3", + "cover": "" + }, + { + "title": "沦陷", + "artist": "王靖雯", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/31.mp3", + "cover": "" + }, + { + "title": "善变", + "artist": "王靖雯", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/32.mp3", + "cover": "" + }, + { + "title": "这一生关于你的风景", + "artist": "大欢", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/33.mp3", + "cover": "" + }, + { + "title": "别知己", + "artist": "海来阿木", + "src": "https://android-o1-images.oss-accelerate.aliyuncs.com/550e8400-e29b-41d4-a716-446655442082/external_storage/folk_music_2020s/34.mp3", + "cover": "" + } +] \ No newline at end of file diff --git a/src/server/data_gateway/skills/email_sender/email.db-shm b/src/server/data_gateway/skills/email_sender/email.db-shm index 2a9389f1c3dcaa7fa72595e48bc6868debad7246..97010bfecb442b3d3a807298f9252f531827942e 100644 GIT binary patch delta 462 zcmb7=%PvD<6ovoqchI`Eb*k!iwCSFid_O!U~-~KPJx|PCK?`MgAu0o2Jv&>DInb6$dla*fTj?eW!nVFF-I22uCxs;X) znZ<}(lZ;}eJ82f8KCO%~l`f_Eww5&V;zMZIsYAz08y)l#V4N93L==~mWquYnrWwteukK2jwM!qxu?yf@os&&k{Voi yXu(G}0}M08Jj+CXxZLAb-lY`;Dn8448@1HaNGpDN7-U4<@1<>;1;WHs^5|ciXL08M delta 215 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 EAN8Z&2><{9 delta 39 ucmdn+H}FKCT|*0F3sVbo3rh=Y3tJ0&3r7oQ3s(zw3r`Dg3*Q!gk9GhjW(`IF diff --git a/src/server/index.js b/src/server/index.js index ddbeca9..086e394 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -6200,6 +6200,30 @@ app.get('/api/home/bg', async (req, res) => { } }) +app.get('/api/home/bg/default-list', (req, res) => { + try { + const baseDir = path.join(process.cwd(), 'public', 'home-bg', 'default-c21f969b') + if (!fs.existsSync(baseDir)) return res.json({ ok: true, files: [] }) + const files = fs.readdirSync(baseDir).filter(f => /\.(jpg|jpeg|png|webp)$/i.test(f)) + res.json({ ok: true, files }) + } catch (e) { + res.json({ ok: true, files: [] }) + } +}) + +app.get('/api/home/bg/default-random', (req, res) => { + try { + const baseDir = path.join(process.cwd(), 'public', 'home-bg', 'default-c21f969b') + if (!fs.existsSync(baseDir)) return res.json({ ok: false, error: 'dir not found' }) + const files = fs.readdirSync(baseDir).filter(f => /\.(jpg|jpeg|png|webp)$/i.test(f)) + if (!files.length) return res.json({ ok: false, error: 'no files' }) + const pick = files[Math.floor(Math.random() * files.length)] + res.json({ ok: true, url: `/home-bg/default-c21f969b/${pick}?v=${Date.now()}` }) + } catch (e) { + res.status(500).json({ ok: false, error: String(e.message || e) }) + } +}) + app.post('/api/home/bg/populate', async (req, res) => { try { const themes = [