diff --git a/.workbuddy/memory/2026-08-14.md b/.workbuddy/memory/2026-08-14.md index 873fe50..1ae5fd8 100644 --- a/.workbuddy/memory/2026-08-14.md +++ b/.workbuddy/memory/2026-08-14.md @@ -28,3 +28,9 @@ - **根因**:初版状态文案 `y=172`(字号22)、大数字基线 `y=230` 且字号最大 90px,数字顶部≈165 落入状态文案区域(150~172),多位数分钟(如纯分钟 "6"→90px)直接压字。 - **修复**(仅改 `_drawSharePoster` 布局):删除顶部"平板的支撑"品牌名;删除右下角二维码及依赖它的"扫码一起打卡"引导(连带 `static/share-qr.jpg` 也删,不再引用);重排垂直节奏——卡片放大(42~358)、图标 `circleY=104`、状态文案 `y=184`(24px)、大数字基线 `y=286`(上限84px,顶部≈226,与状态文案下沿 192 间距 34 安全)、连续打卡 `y=332`;导出改为绘制完直接 `canvasToTempFilePath`,无需等图片加载。 - **结论**:海报现为"成绩卡 + 图标 + 状态 + 大数字 + 连续打卡"的极简版,无品牌名无二维码。 + +## 新增:新版本更新通知(What's New)弹窗 +- **需求**:新版本发布后用户首次进入弹一个"更新了什么"通知弹窗(纯通知,不是微信"点击更新→重启"流程)。用户澄清要的是 What's New,不是 applyUpdate 重启。 +- **实现**:复用 `ui-modal`(position:center) 居中弹窗 + `ui-btn`,不新建组件;`config.js` 加 `releaseNotes` 数组;首页 `index.js` 的 `_checkUpdateNote()` 在 `onShow` 检测 `storage.lastUpdateNoteVersion` vs `config.version`,不一致则显示并写回 storage 防重复;顶部绿色渐变徽章 + `sparkleWhite` 图标 + 版本标题 + 要点列表 + "知道了"按钮。 +- **文件**:`config.js`(releaseNotes)、`pages/index/index.{js,wxml,wxss}`。`index.json` 无需改(ui-modal/ui-btn 已注册)。 +- **发版约定**:每次发版改 `config.version` 并同步更新 `releaseNotes` 即可。前端改动不发云函数。 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 1fd6c4f..c514a35 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -28,6 +28,7 @@ ## 约定 - 页面叫法:index=训练首页,timer=训练页,leaderboard=排行榜,records=记录,settings=设置。 - 美化按"见效快优先"分批,每轮 `node --check` + grep 残留再交付。 +- **发版更新通知(What's New)**:`config.js` 维护 `version`+`releaseNotes`(数组,每条一行短句);首页 `index.js` 的 `_checkUpdateNote()` 在 `onShow` 检测 `wx.getStorageSync('lastUpdateNoteVersion')` 与 `config.version` 不一致→弹 `ui-modal`(position:center) 居中通知,并写回 storage 防重复。纯通知不重启。发版时**改 version 同步更新 releaseNotes** 即可,前端改动无需动云函数。 - **git push 须 `dangerouslyDisableSandbox:true`**(沙箱隔离致 github SSL 超时);无 SSH,仅 HTTPS remote。 - **GitHub 链路不稳**:国内环境到 `github.com:443` 常 SSL 重置/HTTP2 framing 失败(非代码问题),`git.soao.net`(soao) 国内远程稳定。策略:soao 为主远程、实时同步;`origin`(GitHub) 失败则延后推或本地代理(`127.0.0.1:7890` 等)临时 `git -C config http.proxy` 推完 `config --unset` 撤销。代码已 commit 则零丢失风险。 - **GitHub 推送有效解法(2026-08-12 实测)**:报 `LibreSSL SSL_connect: SSL_ERROR_SYSCALL` 时,若 `curl 直连 https://github.com` 能 200(慢 30s 但通),说明是 git 默认 HTTP/2 framing 问题(curl 默认 HTTP/1.1 所以通)→ 执行 `git -C config http.version HTTP/1.1` 后再 push 即可成功,推完 `config --unset http.version` 撤销。7890 端口进程可能空转(curl -x 走它返回 000),别依赖该代理。 diff --git a/config.js b/config.js index 4e40115..384b916 100644 --- a/config.js +++ b/config.js @@ -4,11 +4,24 @@ */ module.exports = { /** 应用版本号,外显在设置页「关于」 */ - version: 'v3.2', + version: 'v3.3', /** 最后更新日期,外显在设置页「关于」 */ updatedAt: '2026-08-14', + /** + * 新版本更新通知(What's New)要点。首页冷启动检测 config.version 与本地 + * 记录版本不一致时,弹一次居中通知弹窗展示这些要点。每次发版改 version + * 的同时更新本数组即可(措辞尽量短,每条一行)。 + */ + releaseNotes: [ + '循环训练分段弧优化:光点居中、与进度弧间距拉大,看得更清楚', + '暗黑模式切换后,各页面底部栏同步变暗', + '循环训练偶数组数:休息语音不再被「完成一半」提示覆盖', + '训练完成新增分享海报,成绩展示更完整', + '训练时长不足 20 秒不计入记录' + ], + /** 开发者名称 / 微信号,设置页点击可复制 */ developer: '三口一瓶', @@ -25,7 +38,7 @@ module.exports = { * 耐力榜领奖台顶部文案。哲理注脚,点出"撑得越久不一定越好"的价值观, * 与耐力榜(比谁单次撑最久)形成反差。仅耐力榜领奖台顶部显示,改这里即可。 */ - leaderboardPodiumSlogan: '平板支撑不是一场和时间的恋爱,撑得越久,不一定越好。真正重要的,是每一秒都没有辜负身体。', + leaderboardPodiumSlogan: '平板支撑不是计时器比赛,是肌肉的精细控制。宁做30秒的钢板,不做5分钟的烂泥。', /** * 语音合成(TTS)参数 - 直接改这里调整音色/音量/语速,无需改逻辑代码。 diff --git a/pages/index/index.js b/pages/index/index.js index 7c74407..9dad0b8 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -34,6 +34,12 @@ Page({ presets: [30, 60, 90, 120, 180, 300], customDuration: 60, customInput: '', + // --- 新版本更新通知(What's New) --- + showUpdateNote: false, + updateNoteVersion: '', + updateNoteItems: [], + updateNoteDate: '', + // --- Circuit (循环训练) config panel (persisted via storage.saveCircuitConfig) --- showCircuitPicker: false, cHold: 30, @@ -50,6 +56,7 @@ Page({ onShow() { themeMod.applyThemeToPage(this) + this._checkUpdateNote() try { const tb = this.getTabBar() if (tb) { @@ -92,6 +99,28 @@ Page({ } catch (e) {} }, + /** + * 新版本首次启动的 What's New 通知。复用 config.version 作为版本号, + * 用 storage 记录已提示过的版本,避免每次冷启动重复弹出。纯通知,不重启应用。 + */ + _checkUpdateNote() { + try { + const shown = wx.getStorageSync('lastUpdateNoteVersion') + if (shown === config.version) return + this.setData({ + showUpdateNote: true, + updateNoteVersion: config.version, + updateNoteItems: config.releaseNotes || [], + updateNoteDate: config.updatedAt || '' + }) + wx.setStorageSync('lastUpdateNoteVersion', config.version) + } catch (e) {} + }, + + onCloseUpdateNote() { + this.setData({ showUpdateNote: false }) + }, + onPullDownRefresh() { this.refresh() wx.stopPullDownRefresh() diff --git a/pages/index/index.wxml b/pages/index/index.wxml index dd31f30..955dcb5 100644 --- a/pages/index/index.wxml +++ b/pages/index/index.wxml @@ -179,4 +179,22 @@ > 取消 + + + + + + + + 版本更新 {{updateNoteVersion}} + 更新于 {{updateNoteDate}} + + + · + {{item}} + + + + + diff --git a/pages/index/index.wxss b/pages/index/index.wxss index 8175ce3..6a5ebc9 100644 --- a/pages/index/index.wxss +++ b/pages/index/index.wxss @@ -446,3 +446,72 @@ 0%, 100% { transform: scale(1); } 50% { transform: scale(1.02); } } + +/* ===== 新版本更新通知(What's New) ===== */ +/* slot 内容由页面 wxss 控制;ui-modal--center 的 body 已居中且用 --card-bg, + 这里只管内部排版。徽章用负 margin 上探出卡片顶,制造浮动感。 */ +.update-note { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; +} + +.update-note__badge { + width: 96rpx; + height: 96rpx; + border-radius: 50%; + margin: -76rpx auto 18rpx; + background: linear-gradient(135deg, #4CAF50, #81C784); + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 8rpx 20rpx rgba(76, 175, 80, 0.35); +} + +.update-note__icon { + width: 52rpx; + height: 52rpx; +} + +.update-note__title { + font-size: 36rpx; + font-weight: 700; + color: var(--text); + line-height: 1.4; +} + +.update-note__date { + font-size: 24rpx; + color: var(--text-secondary); + margin-top: 6rpx; +} + +.update-note__list { + width: 100%; + margin: 26rpx 0 4rpx; + text-align: left; + box-sizing: border-box; +} + +.update-note__item { + display: flex; + align-items: flex-start; + margin-bottom: 16rpx; +} + +.update-note__dot { + color: var(--primary); + font-weight: 700; + margin-right: 12rpx; + line-height: 1.5; + flex-shrink: 0; +} + +.update-note__text { + flex: 1; + font-size: 27rpx; + color: var(--text); + line-height: 1.5; + text-align: left; +}