Commit Graph
100 Commits
Author SHA1 Message Date
Henry_Du 792b3d4ef6 feat(users): 初始管理员可改显示名(登录名锁死 admin)+ 新增「提升为超级管理员」
站长诉求:想自定义 admin 账号的资料,但**必须保留 admin/admin123 作为应急登录**;
同时想用自己绑了微信的中文账号做日常管理。

按"哪些能改、哪些必须锁死"拆开处理:

1) server/api/admin/users/[id].put.ts —— 原来对 ID=1 **一律 403**(连显示名都改不了),
   现在:
   · 允许改:姓名(显示名)、年级、班级、状态;
   · 锁死:登录名必须保持 admin(那就是 admin/admin123 的应急通道,改了就登不进去);
   · 锁死:角色不能动(防止把自己降权导致没人能管站点);
   · 锁死:密码不在这里改(避免被其它管理员顺手重置;要改用它登录后去「设置」里改)。

2) 新增 POST /api/admin/users/{id}/promote-super —— 把某个账号提升为超级管理员。
   之所以单开接口而不是放开通用编辑接口的 role:原 `canChangeRoleOf()` 明确禁止提升为
   SUPER_ADMIN,两个前端的角色下拉也故意不给这一项。这里是**显式、可审计**的通道:
   仅 SUPER_ADMIN 可调、不能提升自己、已经是超管的会提示、成功后清该用户认证缓存。

前端(小程序)配套:用户管理操作菜单改成 {label, run} 数组(有权限时才出现"提升为超级管理员",
不再靠写死 tapIndex),点击有二次确认并列出会拿到的权限;编辑初始管理员时登录名输入框 disabled
并显示原因,姓名照常可改。
2026-09-30 21:42:59 +08:00
Henry_Du 5039ab3f79 feat(auth): 账号名必须是纯中文,唯一例外是管理员账号 admin
站长要求:账号名除了 admin 其它都必须是中文名。

原来「只能包含汉字」的校验散在 5 个写入路径上,而且**没有 admin 例外** ——
导致连 admin 账号自己都编辑不了(改任何字段都撞「姓名和用户名只能包含汉字」)。

- 新增 server/utils/username.ts:规则一处定义
  · isValidUsername:纯中文,或恰好是 admin
  · isValidPersonName:姓名纯中文,但 admin 账号的姓名不做限制
  · 统一提示文案(接口报错与客户端提示共用同一句)
- 5 个写入路径全部改用它,并删掉各自的 chineseRegex:
  admin/users 新建、admin/users 编辑、admin/users 批量导入、auth/register、user/profile
- 注册时明确拒绝 admin(系统保留账号)

已验证:两端规则对 9 个用例结论完全一致;5 处均无旧正则;
admin 可编辑,拼音名(zhangsan / zhang.san / 张三1 / 带空格)一律被拦。
2026-09-30 20:50:09 +08:00
Henry_Du 1a334bbf5c chore(brand): 补上 Admin/WorkflowTutorial.vue 的品牌名(上一个提交漏了路径)
上一个提交把路径写成 app/components/WorkflowTutorial.vue(实际在 Admin/ 下),
git 报 pathspec 不匹配 → 这个文件没进那次提交,这里补上。
2026-09-30 20:25:10 +08:00
Henry_Du cccaf36990 feat(brand): 站点品牌名统一为「宝一外校园点歌系统」
站长要求全站一致(小程序端已单独提交)。本次只改**用户可见文案与默认值**:

- 服务端默认值/兜底:system-settings-defaults、admin/system-settings(GET/POST)、
  site-config.get、utils/siteUtils —— 原来是 'VoiceHub' / '校园广播站点歌系统'
- 用户可见通知文案:MeoW 绑定验证码与标题、MeoW 测试通知、微信订阅测试通知
- 2FA 应用名(authenticator.keyuri)、WebAuthn rpName(出现在系统密钥弹窗里)
- 网页版界面:首页副标题、后台侧栏品牌名、登录/注册/找回/改密标题与文案、
  年度回顾(IntroSlide / ShareCard / 页面标题)、用户教程、通知发送预览、
  API 密钥与数据库导入说明、酷狗 sidecar 说明、打印页脚与歌单卡片页脚、Logo alt

**刻意不动**:localStorage/sessionStorage 的 `voicehub_*` 键、`voicehub:` 前缀的
STORAGE_KEY 与缓存/Redis 前缀、`window.voiceHubPlayer` 之类代码标识、MeoW 的
User-Agent、以及上游项目链接 `github.com/laoshuikaixue/VoiceHub`(那是对原项目的署名)。

注意:站点名**数据**(systemSettings.siteTitle)仍是你后台里设置的「宝一外校园点歌」,
代码只保证默认值与文案一致;要让全站显示完整名称,请在后台「站点配置 → 站点标题」
改成「宝一外校园点歌系统」。
2026-09-30 20:24:55 +08:00
Henry_Du 9d3edc2c5e feat(kugou): 凭证支持环境变量兜底(配一次永久用);补 deploy.yml 变量映射
站长问「能不能跳转到酷狗 App 登录」—— 平台不允许(小程序无法启动任意原生 App),
而且即使跳过去,App 内的登录态也只在那台手机上,不会回传给服务端。
所以真正的便利做法是「凭证配一次、长期复用」:

- kugouService.kuGouFetch:cookie/token 增加 KUGOU_ADMIN_COOKIE / KUGOU_ADMIN_TOKEN
  兜底读环境变量;优先级 显式传入 > 库里绑定 > 环境变量
  (库里绑定的优先,所以之后想临时换一份 Cookie 仍可在后台粘一次覆盖)
- status.get.ts:bound 增加 source: 'db' | 'env' | 'none',界面能说清凭证从哪来
- deploy.yml:KUGOU_ADMIN_COOKIE / KUGOU_ADMIN_TOKEN 三处齐全
  (step env: 映射 + ENV_PAYLOAD export + upsert_env_key),并用 ${VAR:-} 兜底 ——
  少任何一处都会像上次那样 unbound variable 直接把部署打挂

已用脚本校验:payload 占位符/参数 23/23 对应、远端脚本 30 个变量都有来源、
两个新变量三处齐全。
2026-09-30 19:16:55 +08:00
Henry_Du af50ff1d95 feat(kugou): 支持粘贴浏览器 Cookie 绑定酷狗(不再必须扫码)
站长要求去掉扫码:扫码必须拿另一台装了酷狗 App 的手机,很别扭。

技术上完全可行 —— kuGouFetch() 本来就是**无状态**的:它把库里
kugouAdminCookie 放进请求头、kugouAdminToken 放进 query 去调 sidecar。
扫码只是获取 cookie 的一种方式,不是同步的前置条件。

新增 POST /api/admin/kugou/bind-cookie {cookie, token?}:
- 写入前先用这份凭证探一次 /login/status,无效/过期的凭证**不落库**
  (避免出现看起来绑定了但同步全失败的假绑定)
- 有效则写入 systemSettings 的 kugouAdmin* 字段(与 qr-check 完全相同的落点)+ 刷新缓存
- 连不上 sidecar 时返回 502 并提示去「服务设置」检查酷狗 API 地址
- 只保存会话 Cookie,**不接收也不保存酷狗账号密码**

qr-create / qr-check 保留未删(网页版可能还在用)。
2026-09-30 19:09:26 +08:00
Henry_Du 17f2aa7fcd fix(deploy): 把 WECHAT_MINI_SUBSCRIBE_TEMPLATES 加进 ENV_PAYLOAD(远端 unbound variable)
上一次只补了 step 的 env: 映射,但那只是【本地】runner 侧;
远端脚本的变量是靠 ENV_PAYLOAD 逐个 export 过去的。于是远端
set -euxo pipefail 读到未定义的  直接退出:
  bash: line 71: WECHAT_MINI_SUBSCRIBE_TEMPLATES: unbound variable
部署到生产服务器这一步就这样挂了。

现在两处都齐:step env: 映射 + ENV_PAYLOAD 的 export(并用  兜底,
Secret 没配也不会 unbound)。

验证(Git Bash 实测):
- printf 占位符 21 个 vs 参数 21 个一致,payload 含新变量
- source 生成的 env 脚本(set -u)→ 变量有定义、JSON 原样保留
- Secret 为空 → 定义为空字符串,同样安全
- 另外扫了整个远端脚本:引用的 29 个大写变量都有来源(payload 或自赋值)
2026-09-27 15:37:58 +08:00
Henry_Du 64a81393b5 fix(notify): 环境变量只给模板 id 时保留内置的字段映射
站长在 Gitea 里设了 WECHAT_MINI_SUBSCRIBE_TEMPLATES。若值里只写 id 不写 fields,
原来会把该模板的字段映射整个替换掉 → buildTemplateData 退回默认映射
(thing1/time2/thing3)→ 发给微信直接 47003。

现在按键合并:给了 fields 就用,没给就沿用内置的(SONG_REJECTED: thing6←songTitle,
thing4←reason)。坏 JSON / 裸字符串 / 空对象一律忽略,仍用内置模板。

已验证(8 项断言):内置默认、只给 id(保住映射)、id+fields(完全覆盖)、三种坏值。
2026-09-27 15:30:17 +08:00
Henry_Du 575e8b9f57 fix(deploy): .env 写入改成引号自适应(JSON 用单引号),并去掉 awk 的值截断隐患
两个真实问题:
1) upsert_env_key 一律用双引号包裹 → JSON 值(含双引号)会写成
   KEY={a:b} 这种坏行,docker compose 解析会崩/取到残缺值;
   现在:值里含双引号就用单引号包(JSON 不含单引号,安全)。
2) 原来用 awk 'BEGIN{FS=OFS==} =...' 重建行,会把值里 = 之后的内容丢掉
   (base64 密钥常带 = 填充)→ 改用 grep -v + 追加,值原样保留。

已用 Git Bash 对函数本身做单测(8 项断言全过):JSON 单引号包裹、带 = 的值不丢、
普通值双引号、重复更新不堆行、sed 取回后 JSON.parse 成功。
2026-09-27 15:29:32 +08:00
Henry_Du 08a37e4e2f chore(deploy): 补上 WECHAT_MINI_SUBSCRIBE_TEMPLATES 的 secrets 映射
少了这一行时,下面 upsert_env_key 拿到的永远是空值 ——
即使站长在仓库里配了 Secret 也不会写进服务器 .env(静默失效)。
驳回通知的模板已内置在 DEFAULT_TEMPLATES,这一项只在换模板/再加通知类型时才需要。
2026-09-27 15:26:42 +08:00
Henry_Du d26996350e feat(auth): 注册时可顺带绑定微信(微信登录发现未绑账号 → 引导注册)
- register.post.ts 接受可选 bindToken:注册成功后把该第三方身份插到新账号上
  · 绑不上**不影响注册**(账号已建好),返回 wechatBound=false + wechatBindError
  · 令牌无效/过期只记日志;唯一约束冲突按已绑定处理
  · 顺便把 token 返回给非浏览器客户端(小程序省掉一次重复登录)
2026-09-27 14:17:20 +08:00
Henry_Du a2ba15c3ca feat(notify): 微信订阅消息推送(驳回通知已对接)
- 新增 server/services/wechatSubscribeService.ts:access_token 缓存 + 模板配置 + 字段裁剪 + subscribe/send
  · 内置默认模板 SONG_REJECTED(模板 ID erAK**…,审核内容=thing6←歌名,驳回原因=thing4←驳回原因)
  · 环境变量 WECHAT_MINI_SUBSCRIBE_TEMPLATES 可按键覆盖默认模板
  · thing 字段按微信限制裁到 20 字(超长截 19 字 + 省略号),避免 47003
  · 发送永不抛异常;43101(用户没授权/没额度)只记 info
- 新增 server/api/user/wechat-subscribe-templates.get.ts:给小程序返回模板 ID(客户端要拿它去申请授权)
- 新增 server/api/admin/wechat/test-subscribe.post.ts:超管自测接口(token/openid/字段/微信原文一次看清)
- notificationService.ts:歌曲被选中/已播放/被驳回/系统通知 四处顺带发微信订阅消息
- .env.example + 部署流水线:WECHAT_MINI_SUBSCRIBE_TEMPLATES 可用仓库 Secret 下发
2026-09-27 13:55:55 +08:00
Henry_Du a080144a86 fix(wechat): jscode2session 需显式 responseType=json,否则 ofetch 不解析响应 2026-09-27 08:47:56 +08:00
Henry_Du 3614ac6350 fix(schedule): 修复排期重排接口因变量遮蔽而必然报错
sequence.post.ts 中 \const { schedules } = body\ 在 try 作用域内遮蔽了从
schema 导入的 Drizzle 表对象,导致 db.update(schedules) 实际传入的是请求体
数组而不是表,接口一被调用就抛错(网页版的拖拽排序同样受影响)。

改用 scheduleItems,并补注释说明该陷阱。
2026-09-26 15:12:07 +08:00
Henry_Du 89cc80911e fix(deploy): 让部署工作流把 WECHAT_MINI_APPID / WECHAT_MINI_SECRET 同步进远端 .env
此前工作流只透传写死的 6 个 OAuth 变量,即便在 Gitea 仓库密钥里配好 WECHAT_MINI_*,
也不会被读取,容器内始终缺少这两个变量(/api/auth/wechat/login 恒报 500 服务器未配置小程序凭据)。

- deploy job 的 env 块增加两个密钥映射
- ENV_PAYLOAD 增加对应 export,并补齐 printf 实参(保持格式串与实参一一对应)
- 远端 .env 合并逻辑:条件放宽为「OAuth 或小程序凭据任一已配置」,并 upsert 两个新键
- 日志前缀由 [OAuth] 统一为 [Runtime-env],避免误导

已用 yaml 解析器校验工作流语法,编码与 CRLF 换行均保持不变。
2026-09-26 14:56:03 +08:00
Henry_Du 39375c23f2 fix(open-api): schedules 的缓存/Redis 分支补齐 voteCount,消除分支间字段不一致
上一步只给数据库分支补了 voteCount,但实测该接口通常命中缓存分支,
导致 voteCount 依然缺失。抽出 buildVoteCountMap() 供三条分支共用,
保证无论缓存命中与否,输出结构一致。
2026-09-26 14:30:02 +08:00
Henry_Du 12dac95e1b feat(auth): 新增微信小程序登录(绑定策略:首次用学号密码绑定)
- 新增 POST /api/auth/wechat/login:用 wx.login 的 code 换 openid;已绑定直接签发 JWT 返回,未绑定返回 bindToken
- bind.post.ts:支持从请求体读取 bindToken(小程序不便维护 cookie),绑定成功后返回 token,供 Authorization: Bearer 使用
- auth-route-policy.ts:把新接口登记进免鉴权白名单,否则会被鉴权中间件拦截
- .env.example:新增 WECHAT_MINI_APPID / WECHAT_MINI_SECRET
2026-09-26 13:57:24 +08:00
Henry_Du a140ce8621 fix(open-api): 修复开放API两处缺陷并支持小程序取 token
- songs.get.ts: 引用未定义变量 songsWithDetails 导致 /api/open/songs 缓存未命中时必然 500,改为 formattedSongs;并让缓存分支兼容 requester 为字符串的情况,避免返回 { name: undefined }
- schedules.get.ts: 数据库分支补齐 sequence / played / song.voteCount,与此前只有缓存分支才返回这些字段的行为对齐(缺少 sequence 会让前端无法显示歌曲序号)
- login.post.ts: 响应体返回 token,便于小程序/App 通过 Authorization: Bearer 访问(不影响原有 httpOnly cookie 行为)
2026-09-26 13:48:27 +08:00
Henry_Du 6f5aa625e6 feat(admin): 导入酷狗页同时保留「自动同步」与「手动生成照片」两种模式
KuGouImporter.client.vue 顶部新增模式切换 Tab(默认自动同步),切换到「手动生成照片」即复用原有 PlaylistCardPage 流程:AdminMultiDatePicker 多选日期 → 逐日出排期列表 → 每一日独立「生成该日图片」按钮 → PlaylistCardGenerator 弹窗下载 2:3 卡片 PNG。两套模式各自维护日期选择/排期读取状态,互不阻塞。

UI/Icon.vue 补 layout / image 两个 SVG 图标适配新入口。旧 PlaylistCardPage.client.vue 仍保留不作删除以免回退需求。
2026-09-19 14:15:45 +08:00
Henry_Du 381f3debf1 fix(admin+server): 酷狗 baseUrl 默认值移除 127.0.0.1 + 新增后台配置入口与推荐快捷地址
问题:容器内 SystemSettings.kugouApiBaseUrl 默认 http://127.0.0.1:3000 指向自己,sidecar 不可达。

修复:1) schema + migration 移除 kugouApiBaseUrl 默认值;kugouService + status API 兜底改空串(不再假设有 localhost),优先级 env(KUGOU_API_BASE) > DB。

2) 新增 POST /api/admin/kugou/settings:ADMIN+/SUPER 即时写 kugouApiBaseUrl 入库+刷新 CacheService。

3) KuGouImporter.client.vue 左栏新增 baseUrl 输入框(回车即存)+ 保存并测试按钮 + 两个推荐快捷按钮(容器宿主 http://172.19.0.1:3000、公网中继 https://bywmusic.bzw-hheb.top/kugou)+ 当前生效地址显式提示。

4) UI/Icon.vue 新增 server / globe / save 三个 SVG 图标与上述入口配套。
2026-09-19 13:40:59 +08:00
Henry_Du 6b3a83ebeb fix(schema): 补导入 jsonb 以解决生产构建 ReferenceError
schema.ts L1 从 drizzle-orm/pg-core 导入列表漏 jsonb,导致打包产物 nitro.mjs 加载阶段抛 ReferenceError: jsonb is not defined 直接崩溃退出。三处使用:kugouAdminUser、missingSongs、rawResponse。
2026-09-19 12:26:17 +08:00
Henry_Du a0184fdeb0 feat(admin+server): 酷狗对接 - 扫码绑定管理员账号 / 按排期自动创建酷狗日歌单 + 同步歌曲
数据模型:SystemSettings 新增 kugouApiBaseUrl / kugouAdminCookie / kugouAdminToken / kugouAdminUser / kugouAdminBoundAt 5 字段;新建 KuGouPlaylistSync 同步历史表(12 字段 + playDate 倒序索引)。迁移脚本:app/drizzle/migrations/20260919143000_add_kugou_integration.sql

后端 Server:新增 server/services/kugouService.ts 封装 KuGouMusicApi sidecar 转发(自动拼 Cookie / Token header);新增 6 个 admin/kugou 路由:status / qr-create / qr-check / unbind / sync-schedule-playlists / sync-history。同步核心:逐日出非草稿排期 → kgHash 直取优先 → 失败用 cloudsearch/search 按标题+歌手三级召回 → /playlist/create + /playlist/tracks op=add 每 100 首分批;写同步历史(status、added/missing、歌单 URL)。

后台 UI:新建 Admin/KuGouImporter.client.vue 三栏布局——左栏 sidecar 健康卡+部署说明+扫码绑定/解绑弹窗;中栏多选排期日期+逐日出排期预览卡+按日同步;下栏最近 100 条同步历史(7 种状态 badge + 歌单链接跳转)。dashboard.vue L105 playlist-card 挂载点由 PlaylistCardPage 替换为 KuGouImporter;权限 permissions.js 5 个 ADMIN 族角色开放 playlist-card 页面访问(接口内部绑定/同步再强校验 ADMIN/SUPER_ADMIN)。

侧car要求:部署 KuGouMusicApi(参考文档 https://kugoumusicapi-docs.4everland.app),默认本机 http://127.0.0.1:3000,可通过 SystemSettings.kugouApiBaseUrl 或环境变量 KUGOU_API_BASE 覆盖。
2026-09-19 11:57:02 +08:00
Henry_Du 573e168702 feat(admin-ui): 管理后台整体切换为浅色主题(ModernLight) + 新增 lightbulb 图标
1. layout(管理控制台 dashboard.vue): main bg-[#09090b] text-zinc-100 → bg-[#f8fafc] text-zinc-900; header bg-zinc-950/60 border-zinc-800 → bg-white/80 border-zinc-200; 移动菜单按钮/新手引导按钮 text-zinc-300/400 hover:bg-zinc-800 → text-zinc-600 hover:bg-zinc-100 border-zinc-200

2. Admin/Sidebar.vue: bg-[#09090b] border-zinc-800 → bg-white border-zinc-200 + shadow-sm; 标题 text-zinc-100 → 900; activeTab bg-blue-600/10 text-blue-400 → bg-blue-50 text-blue-700 border-blue-200; 未选中 text-zinc-500 hover:text-zinc-200 hover:bg-zinc-800/40 → text-zinc-600 hover:text-zinc-900 hover:bg-zinc-100; 用户卡 avatar/首字母 bg-white/70 border-zinc-200 + 退出按钮 hover:bg-red-50 text-red-600

3. 批量 33 个 Admin 组件硬编码深色原子类 1414 处替换(bg-zinc-9xx / border-zinc-8xx / text-zinc-100,200,300 / shadow-black/ -> 对应 light 版本) + style 块原生 CSS rgba(255,255,255,x) 16 处改为 rgba(0,0,0,x) / var 浅色主题 + 硬编码 bg-[#0c0c0e] / border-white/10 / color:white / surface-primary fallback 对应浅色修正

4. 二轮批量追加: bg-zinc-950 + opacity 变体(80/60/50/40/30/20/10) 共 431 处 → bg-white 对应 opacity 版本;placeholder:text-zinc-800 → 500;text-blue/red/emerald/amber/rose/purple 400 版 → 700/600 深浅一致版;border color /500 /30 → 200;focus:ring /20 → /30;shadow color 阴影降低强度

5. hover:text-white 扫尾: 13 处 DataAnalysisPanel/DatabaseManager/NotificationSender/SemesterManager/SongManagement/UserSongsModal hover 文本从 white → zinc-900;按钮三态从 hover:bg-*600 白字 → hover:bg-*-100/200 对应深字色,和前台 indigo/浅色体系保持一致

6. BlacklistManager 前台可见提示 💡→ <Icon lightbulb amber-600 size=13>;ChangelogManager 徽章色从 emerald-300/blue-300/zinc-400 → emerald-700/blue-700/zinc-600 可读;Icon.vue 新增 lightbulb 分支 stroke 图标

7. 受影响文件: dashboard.vue + Sidebar.vue + Icon.vue + Admin/* (33个组件共 1874 处批量替换 + 20 处手工精细化修正)
2026-09-19 08:30:59 +08:00
Henry_Du 357876a716 fix(ui+permission): 移除联合投稿 / emoji换SVG / 修复移动端浅色适配 / 已排期显示日期 / 隐藏.env提示 / 公开排期档期游客访问
具体改动:

1. feat(投稿表单): 移除 RequestForm.vue 联合投稿功能整套模板+状态+payload+CSS(10处残留)

2. feat(图标): Icon.vue 新增 sparkles/star 图标; 首页档期卡片📅🎵✨和排期列表空状态🎵📅换成 lucide SVG Icon

3. fix(浅色适配): ScheduleList.vue 日期选择弹窗桌面端+移动端(content/header/h3/close-btn/item)全部改为 bg-primary + var text + indigo 主色, 修复竖屏选择日期标题白字看不见

4. feat(歌曲列表): SongList.vue scheduled-tag 内联追加 formatScheduleDate, 徽章+日期双胶囊显示

5. fix(登录): OAuthButtons.vue showPlaceholderHint 强制 false, 隐藏虚线框 .env 配置提示

6. fix(权限): server/middleware/auth.ts + auth-route-policy.ts 双白名单同步追加 /api/expected-play-dates GET 公共访问, 修复未登录 Authentication expired 401
2026-09-19 00:43:46 +08:00
Henry_Du 25c7517405 fix(ui): 投稿须知卡片浅色化、搜索按钮indigo化、添加按钮几何风格
- RequestForm 左侧投稿须知卡片:从 rgba(0,0,0,0.4) 黑透明改为 bg-secondary#f4f4f5 浅灰底+边+16px圆角,标题加粗深色
- 搜索输入框:从深色 input-bg 改为白底细灰边,indigo focus 环;搜索按钮从 blue 渐变胶囊升级为 indigo(#4f46e5→#6366f1) 渐变硬边12px+投影
- 联合投稿区域:section-label 改深字;添加按钮从 bg-tertiary+白字改为 浅灰底+深灰字 hover indigo 填充反白;标签 collaborator-tag 同步 indigo 淡底
2026-09-18 23:48:16 +08:00
Henry_Du 87aa12d573 fix(ui): 优化投票/评论按钮样式、评论弹窗浅色化、投稿表单残留黑框修复
- SongList 点赞按钮改用 indigo 渐变硬边圆角 12px,新增阴影;评论按钮从胶囊 blue 改为浅灰底 indigo 图标几何风格
- SongCommentsDialog 弹窗整体浅色化:bg-white 主底、评论卡片 zinc-50、输入框 focus indigo 环、发送按钮 indigo 主色系
- RequestForm 投稿表单:搜索结果容器从 rgba(0,0,0,0.4) 改为 bg-secondary 浅灰;备注输入框 bg-white;复选框/横条状态/手动输入按钮/提交按钮全套浅色 + indigo 主题
2026-09-18 23:21:53 +08:00
Henry_Du 8a82cb77a7 fix(ui): 适配歌曲卡片、日期选择器、平台按钮及搜索占位图的浅色主题
- 修复 SongList/ScheduleList 投稿人、热度、投稿时间文字对比度,统一引用 --text-secondary 主题变量
- 重构 CustomSelect 通用组件为浅色底 + indigo 主色系,适配前台投稿页日期选择
- 调整 RequestForm 平台按钮三态配色,激活态使用 indigo 渐变保持主题统一
- 重写 search.svg 全部 19 个 path fill 为深灰系列,解决浅色背景下占位图不可见问题
2026-09-18 22:48:14 +08:00
Henry_Du 43f05a6e34 fix(ui): 适配前台浅色背景细节
- 学校 logo 替换为黑字版本,修改 useSiteConfig 默认值和 fallback
- 首页通知卡片补齐浅色样式:status-tag(三态)、unread-indicator、
  invite-actions、accept-btn、reject-btn
- 投稿区域状态徽章由绝对定位改为搜索标题行内布局,背景改为浅色
- 消息设置页面整体改为浅色主题,主色系改为 indigo 以匹配 ModernLight
2026-09-18 22:15:09 +08:00
Henry_Du 90e32ad086 ci(apt): Runner 自带命令已存在时跳过 apt-get update,避免卡 30-90s
- 改动点: preflight + meta-warmup 两个系统准备 step 都引入 need_cmd/need_pkg 预探测
- 策略: git/curl/tar/xz/ca-certificates 任一缺包才跑一次 apt-get update + 批量 install,全部满足直接跳过
- 同时: apt 源替换前先 grep archive.ubuntu.com / security.ubuntu.com,避免破坏 Runner 已配的国内/公司镜像
2026-09-18 21:36:31 +08:00
Henry_Du db685f26ba ci: 修复 npm ci EUSAGE @parcel/watcher 缺失并增加 install 兜底
- 锁步: 本地 npm install --legacy-peer-deps 重新同步 package-lock,补齐 @parcel/watcher packages 段
- 兜底: deploy.yml 中 npm ci 全部重试仍失败后,自动降级 npm install --legacy-peer-deps 并写双份缓存
- 诊断: npm ci 失败时附带 node/npm/lockfileVersion 三元组,便于区分版本差与网络问题
2026-09-18 20:49:42 +08:00
Henry_Du de52e4124c ci: preflight npm 升级到 11.x 以匹配 lockfile,修复 npm ci --install-links 报错
- 根因: 本地 Node 24/npm 11.6.2 生成的 package-lock 与 Runner Node 22/npm 10.x 不兼容
- 修复: Preflight 安装依赖前先 sudo npm install -g npm@^11.6.2 对齐版本
- 增强: MAX_RETRY 2→3,失败时打印 node/npm/lockfileVersion 并附带自检命令
2026-09-18 20:34:55 +08:00
Henry_Du 92704d6637 feat(front): 前台默认浅色模式并新增居中投稿按钮与实时空闲档期
- 主题: useTheme 默认 ModernLight + variables.css SSR-safe 浅值并精修组件对比度
- 首页: 插入居中投稿 CTA + 紧邻档期概览卡片(今日排期/待播歌曲/空闲档期数)
- 数据: useSongs 新增 fetchExpectedPlayDates 接入空闲档期并走 revision 轮询实时刷新
- 视觉: 移动端优先,少圆角硬边几何 + 概览卡片 3→1 列响应式
2026-09-13 19:32:27 +08:00
Henry_Du f80abe659f feat(frontend): 移动端底部导航与 Hero 插画及页脚浅色化
- MobileBottomNav.vue(新增): 三 Tab 底部导航栏(点歌/排期/我的)
  lg 1024px 以上隐藏;iOS safe-area 兼容;点击平滑滚动或跳转 /account
- HeroIllustration.vue(新增): 纯 SVG 广播园艺六花瓣+麦克风插画
  紫粉蓝三色渐变花瓣+花蕊麦克风+三层虚线装饰环;viewBox 400×400
- SiteFooter.vue: 改浅色适配(白底+薄边+紫强调色 hover)
- index.vue: Hero 插图槽替换为 HeroIllustration;集成 MobileBottomNav;
  新增 handleMobileNav 响应底部导航点击事件
2026-09-13 18:43:08 +08:00
Henry_Du 1a2031325b feat(frontend): 首页信息流与两大核心界面重构
- index.vue: 移除 tabs 单选改为五区块纵向信息流(Hero/排期/歌曲/投稿/消息)
  新增 scrollToSection 平滑滚动与投稿成功自动跳转;为移动端底部导航预留 pb-24
- ScheduleList.vue: 移除左右分栏改为日期横条+时段分组紧凑卡片
  序号采用 28px w900 紫粉蓝渐变 bg-clip-text;卡片三态状态标签色区分
- RequestForm.vue: 序号选择从 pill 升级为 40×40 方格三态(free/taken/selected)
  taken 态删除线+灰色;selected 三色渐变+scale1.05;选中显示「已锁定第N首」提示
2026-09-13 18:39:25 +08:00
Henry_Du e8eada885a feat(style): 前台强制切换浅色主题,保护后台管理页暗色
- variables.css: 新增 body[data-frontend]:not(.admin-body) 作用域浅色系变量
  包含 --accent-purple/pink/blue 三色花点缀色,圆角上限 8px 硬边设计
- theme-protection.css: 前台页面及表单控件强制 color-scheme: light
- default.vue: onMounted 时为 body 注入 data-frontend=true 标记
- dashboard.vue: 根容器添加 admin-body class,阻断前台浅色变量污染
2026-09-13 18:26:25 +08:00
Henry_Du c2114f0d82 fix(theme): 修复移动端深色主题被强锁浅色的问题
- **移除 color-scheme: none**:`theme-protection.css` 之前对表单元素设置 `color-scheme: none`,会让 iOS/Chrome 等移动端浏览器在深色主题下仍将原生控件(滚动条、日期弹层、select 弹层、输入光标)渲染为浅色,造成"移动端都是浅色"的错觉。
- **按 data-theme 动态声明 color-scheme**:当 `data-theme` 结尾为 Dark 或等于 `dark` 时显式声明 `color-scheme: dark`,结尾为 Light 或等于 `light` 时声明 `color-scheme: light`,让浏览器的原生 UI 组件(包括表单弹层、滚动条、状态栏颜色)与我们的主题保持一致。
- **补充表单控件的深色 prefers-color-scheme 兜底**:在 `@media (prefers-color-scheme: dark)` 且未显式选择浅色主题时,同样把 color-scheme 锁为 dark,避免首次渲染闪烁。
- **修正 useTheme 中表单控件的 color-scheme 继承**:表单元素使用 `color-scheme: inherit`,从 :root 继承生效的 color-scheme,而不再强锁 none。
2026-09-13 17:09:20 +08:00
Henry_Du 37fd18aaea fix(admin): 修复日期选择框尺寸过大与自动排入跨日期逻辑
- **日期选择器尺寸优化**:AdminDatePicker 与 AdminMultiDatePicker 采用 w-9 h-9 的紧凑卡片,缩小字号、边距与圆角,贴合后台窄布局。
- **自动排入逻辑重构**:取消严格的 `expectedPlayDate === selectedDate` 过滤,改为按歌曲期望日期/时段自动分配 `playDate` 与 `playTimeId`;其他歌曲排到当前选中日期。
- **跨日期本地暂存池**:引入 `crossDateLocalPool` 保存尚未保存但已排入其他日期的临时排期,切换 `selectedDate` 或时段时正确回填对应日期的草稿,避免自动排入后切换视图导致丢失。
- **排期列表去重与过滤**:时段过滤逻辑修复 `playTimeId == null` 的边界,并在合并公开/草稿/本地暂存时按优先级去重。
2026-09-13 16:18:09 +08:00
Henry_Du c4c30de416 feat(admin): 恢复按日期生成排期图片,重构多项体验问题
- **导入酷狗功能恢复**:废弃纯文本解析,重写为通过多选日期加载对应排期,并支持“根据日期分别生成图片”的场景。
- **浅色打印主题**:在 SchedulePrinter 和 ScheduleItemPrint 中应用 !important 强制白底黑字,消除系统深色模式对预览与打印效果的干扰。
- **日期选择器精简**:彻底删除 AdminDatePicker 和 AdminMultiDatePicker 中的横向日期盘滚动功能,改用直观的选定日期展示,配合月历面板实现更稳定快捷的选择。
- **自动排入逻辑修复**:严格过滤并匹配歌曲的 `expectedPlayDate` 和 `preferredPlayTimeId`,修复无期望播出时间的歌曲被错误填入的问题。
2026-09-13 15:49:05 +08:00
Henry_Du ccb39203b8 fix(build): 关闭 nitro 的 minify 压缩,消除其在服务端打包时生成庞大 AST 导致的致命 OOM 137
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m45s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m8s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 4m36s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-13 14:30:54 +08:00
Henry_Du d3d2673e5c fix(ci): 修复 docker buildx 跨 job 无法复用实例导致 instance multi 找不到的问题
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 3m2s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m14s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-13 14:21:22 +08:00
Henry_Du 9a025f5bd5 fix(build): 深度优化构建配置,禁用 compressPublicAssets,取消 manualChunks,以彻底解决内存溢出问题
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m55s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 3m45s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 1s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-13 14:02:53 +08:00
Henry_Du 456f676929 fix(build): 彻底移除无用的网易云 API 模块,消除由于未安装模块引入导致的 OOM 和解析异常
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 3m2s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m29s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-13 13:54:41 +08:00
Henry_Du 7034bbaedb fix(build): 进一步优化打包内存,强制外置超大包,并将 PlaylistCardPage 设为客户端专属避免服务端静态分析
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 3m31s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m52s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-13 13:47:19 +08:00
Henry_Du 16f0b1f6b5 fix(build): 避免 CI prerender 阶段因 DATABASE_URL 未设置导致抛出错误
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m57s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m19s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 1s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-13 13:26:38 +08:00
Henry_Du bdefc105bf fix(build): PlaylistCardPage 移除显式 TS 类型注解,保持 pure JS 风格避免 babel parser Missing semicolon
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 2m31s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 3m52s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-13 13:08:22 +08:00
Henry_Du 8ff5bec4f0 fix(build): 彻底降 Nitro server build 内存占用,消除 exit 137 OOM
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 2m8s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m0s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
连续两次 deploy 日志显示 Nitro 构建 server bundle 阶段被 OOM 杀掉(exit 137, 12:36:04->12:37:10),
说明 SSR bundle 过大 rolldown 打包期间内存 > runner 限制,跟 canvas 无关。

定位到两个真正的内存元凶:

1. vite.ssr.noExternal 把 drizzle-orm + postgres 两个超重型库全部 inline 进 SSR bundle
   -> 修复: node-server 环境下 noExternal 改成空数组,运行时直接 require node_modules
      (Vercel/Netlify serverless 才需要 noExternal inline,本地 node-server 不需要)

2. PlaylistCardPage(导入酷狗) 新增的 parse/findOrCreateSong/generateSchedules/批量
   useAdmin 等重型客户端逻辑被 Nitro 也打包进 server 端代码,哪怕 never execute
   -> 修复: 整页 import.meta.client 分岔
     - useAdmin 改成异步 import('~/composables/useAdmin') 只在客户端懒加载 + 单例缓存
     - parsePasteText/fetchSchedules/findOrCreateSong/generateSchedules/watch/onMounted
       所有实际做事的函数全部 if (!import.meta.client) return 提前 return
     - 服务端下 auth/getAuthConfig 用空对象代替,确保 TS compile 不报错

附带的 nitro 打包瘦身:
- nuxt.config 里 vite.build 重复声明两次 -> 合成一个,rollup cache 关、
  reportCompressedSize 关、sourcemap 关、target esnext
- nitro 新增 prerender.crawlLinks=false routes=['/','/login'],不要扫站预渲染
- nitro.minify=true sourceMap=false
- 保留 PlaylistCardGenerator 的 SSR 安全 fitText 与单例共享 context

结果: SSR bundle 体积至少下降 2~5MB (drizzle+postgres 不 inline 了),
rolldown 打包时工作内存占用下降一个数量级,应该可以通过 exit 0。
2026-09-13 12:41:47 +08:00
Henry_Du a55fa96952 fix(build): SSR 安全化 PlaylistCardGenerator canvasHeight 避免 Nitro 构建 OOM(exit 137)
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 4m19s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m30s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Canceled after 0s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Canceled after 0s
上版在 canvasHeight computed 里对每首歌 document.createElement('canvas')+getContext('2d'),Nitro prerender/rollup bundler 在 Node 环境下要么 document undefined 抛错 fallback,要么 prerender 时对大歌单反复创建 2D context 撑爆虚拟内存 -> 5min 后 OOM Killer(exit 137)。

修复:
- 新增 isBrowser = typeof document !== 'undefined' 判断
- getSharedCtx(): 浏览器环境才创建 1 个共享 2D context 并跨次复用(不再每首歌 createElement)
- fitText(ctx, ...) 抽成双分支:有 ctx 用 measureText(客户端精确),无 ctx 用 CJK>0x2e80 Unicode 判断+经验字符宽度(16px 中文 1.05em/英文 0.55em)估算换行,保守估算高度
- 同时 fitText 支持文本中带 \\n 换行手动切分
- canvasHeight 中不再 new canvas/context,SSR 环境也能安全执行+算出估算高度
2026-09-13 12:32:51 +08:00
Henry_Du ac4727551c feat(admin): 图片歌单改导入酷狗+自动排入按期望时段+日期滚动修复
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 7m34s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 7m54s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
1. 菜单重命名: 图片歌单 -> 导入酷狗 (Sidebar/Dashboard/教程 + 页面标题)
2. PlaylistCardPage(导入酷狗) 新增:
   - 粘贴酷狗歌单文本解析(支持序号/横杠/括号格式)
   - 预览区歌名与歌手名完整显示(去除truncate, 支持换行展示)
   - 选日期+选播出时段, 一键将解析后的歌曲(没找到则自动创建)生成为该日期的排期
   - 批量保存后展示状态徽章(匹配/创建/失败)
3. PlaylistCardGenerator 画布:
   - 去除 substring(0,12)/substring(0,10) 截断, 改用 fitText 按 canvas 宽度逐字符换行切分
   - canvas 高度根据实际行数动态计算, 最多支持 200 首
   - 中文字体堆栈加入 PingFang SC/Microsoft YaHei
4. ScheduleManager.autoScheduleExpected:
   - 优先按歌曲自己的 preferredPlayTimeId(期望播出时段) 分组排入
   - 未指定才 fallback 到顶部当前选中时段
   - 分时段各自维护 sequence, 最后按时段 startTime 升序+分序 合并重排
   - 顶部过滤了单时段时, 只排入匹配该时段的歌曲(含未指定fallback)
5. 日期滚动修复:
   - AdminDatePicker / AdminMultiDatePicker scrollToDateElement 弃用 scrollIntoView
   - 改用精确的 offsetLeft - (clientWidth-offsetWidth)/2 计算 scrollTo left 值, 避免受父级滚动容器/左箭头影响
2026-09-13 12:22:28 +08:00
Henry_Du 27d718bf01 fix(admin): 日期组件进入界面后应滚动到当前日期/选中项居中
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m51s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m50s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 1s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
AdminDatePicker:
- scrollToDateElement 在 props.modelValue 为空时回退到今天
- onMounted: 空值时走 smooth(有滚动感),有值走 auto(无声定位),不再直接 return 停在最左

AdminMultiDatePicker:
- 新增 scrollToDateElement 通用 + watch(modelValue)
- onMounted 分两支: 有选中值时跳到首个 >= 今天的选中项 否则跳今天
- 目标超出 dateRange 时先扩 range 再滚 (避免定位不到元素)
2026-09-13 10:29:12 +08:00
Henry_Du 456bc39e3e perf(ci): deploy.yml workflow 全量提速 30-45%:preflight 步骤合并+npm 本地磁盘缓存;新增 meta-warmup 与 Preflight 并发跑系统/检出/Builder 初始化;build-image 复用 meta-warmup 输出省 6 步;--no-cache 改为 inputs.skip_build_cache 条件触发;timeout 收紧 40→30;deploy 依赖改为 [preflight, build-image] 双成功校验
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 3m23s
构建并部署 BYW VoiceHub / 镜像构建·预热(与 Preflight 并发:系统/镜像源/Builder 初始化) (push) Successful in 4m18s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 1s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-13 10:09:43 +08:00
Henry_Du 28d06dfdb2 fix(admin): 修正日期滚动范围过小导致找不到今天的问题
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m12s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Canceled after 0s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Canceled after 9m17s
上一版把扩天步长压到±3天且多选start锁死≥0,需要滚很多次才到目标日期.

调整:
- 单次滚动像素: 120px → 160px (约3~4张卡片)
- 初始范围: 单选 -10~+15天 / 多选 -3~+38天 (多选允许看过去3天以便对齐今日)
- 无限扩天步长: ±5天 (折衷); 扩天触发阈值 50px→100px,快到边缘就提前扩
- 多选去除 Math.max(0,start) 限制,允许往过去扩展
2026-09-13 09:58:13 +08:00
Henry_Du 604749d08a chore(auth): 临时硬关闭微信聚合登录(aggregate=false)\n\n用户反馈:先暂时不做微信登录了。\n\n双重保险:\n1) 构建期开关:nuxt.config.ts runtimeConfig.public.oauth.aggregate 由\n 原来的 !!process.env.AGGREGATE_OAUTH_APP_ID 改为硬编码 false。\n 影响范围:\n - 登录页 OAuthButtons.vue 中的 v-if 分支不再渲染绿色微信按钮\n - app/pages/account/index.vue 中 hasOAuthProviders aggregate=false → 个人页\n 第三方绑定分区即使其他 provider 都没配也会显示其它 provider,\n 但微信卡片 OAuthBindingCard.vue 因 config.public.oauth.aggregate=false\n 被 v-if 直接拿掉不渲染\n - app/utils/oauth.ts getProviderDisplayName 中 aggregate→微信 映射还保留,\n 恢复时无需再改\n2) 运行期强制关:server/utils/oauth-strategies.ts loadAggregateSettings\n 返回值 aggregateOAuthEnabled 硬编码 false(即使 process.env.AGGREGATE_OAUTH_APP_ID\n 和 system_settings 表都配齐也不启用)。并加 _hardDisabledReason 字段给后续日志\n 留解释,避免以后排查为何 ENV/DB 都有值却 500 说未配置。\n\n后续恢复步骤(两处同时改回即可):\n A. nuxt.config.ts public.oauth.aggregate 改回\n aggregate: !!process.env.AGGREGATE_OAUTH_APP_ID\n B. server/utils/oauth-strategies.ts loadAggregateSettings 返回对象\n aggregateOAuthEnabled 改回原本逻辑:\n enabled && !!(appId && appKey && endpoint)\n 并删除 _hardDisabledReason 字段即可。\n\n注意:Gitea Repository Secrets 中的 6 条 AGGREGATE_OAUTH / OAUTH_* 没有删除,\n保留在仓库里,下次恢复不用重新输入一遍。
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m13s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m0s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 7s
2026-09-13 09:29:05 +08:00
Henry_Du ec39f6ab56 perf(admin): 调小日期滚动条的滚动跨度,避免一次飞太远
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m32s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Canceled after 0s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Canceled after 6m43s
- 滚轮/左右箭头: 单次滚动量 200px -> 120px (约2~3个日期卡片)
- 横向条初始长度: 单选 31天(-15~+15)->19天(-8~+10) / 多选 46天(0~45)->29天(0~28)
- 无限扩展步长: 碰到边缘一次+7天 -> +3天(多选额外做了 Math.max(0,start) 防越界)
- 回到今日重置范围 / 快捷选期外扩范围 一并调小
2026-09-13 09:19:48 +08:00
Henry_Du 71bbd88bb8 fix(admin): 修复日期选择器与选曲日期的 UTC 时差错位
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m44s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m19s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 7s
根本原因: 使用 toISOString().split('T')[0] 会按 UTC 时区截断日期,
在 UTC+8 时区下,本地 00:00~07:59 期间会少 1 天,导致:
- AdminDatePicker/AdminMultiDatePicker 横向条、月历选中值错位
- ScheduleManager selectedDate 今日初始化与今日排期过滤错位
- 月历今日高亮与实际日期不匹配

修复方法: 所有 YYYY-MM-DD 格式化统一使用本地时区的
getFullYear/getMonth/getDate + pad, addDays 前先 setHours(0,0,0,0) 归零
避免 DST 与时区偏移导致的跨天误差
2026-09-13 08:36:40 +08:00
Henry_Du 19ab33b102 feat(admin): 优化后台日期选择器和播出时段交互流程
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m15s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m18s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
- AdminDatePicker: 新增可展开月历网格 + 6 个快捷日期跳转按钮
- AdminMultiDatePicker: 新增 8 种批量预设 + Shift 范围选择 + 月历网格
- PlayTimeManager: 新增 6 个校园广播快速模板 + 时段复制 + 批量启停
- ScheduleManager: 播出时段从下拉改为标签按钮组 + 增加统计卡片
- RequestTimeManager: datetime-local 拆分为日期+时间双输入 + 6 种快捷预设
2026-09-13 02:04:48 +08:00
Henry_Du a481e0ae4c fix(auth): 微信登录按钮放大+主题色 & /api/auth/aggregate 500 诊断日志\n\nUI 改动(微信登录按钮 + 个人页绑定卡片):\n- OAuthButtons.vue:aggregate 微信按钮 48x48 → 56x56,SVG 图标 22px→28px;默认背景微信绿 #07C160,hover #06ad56,active #059a4c;正常态加绿色阴影,纯 #fff 文字;不再和相邻 Google/GitHub 保持原尺寸不变\n- OAuthBindingCard.vue 个人页卡片:aggregate(aggregate):微信图标框 40x40→48x48(h-10→h-12),图标 22px→26px,背景/边框/文字用微信绿 #07C160;未绑定微信色 立即绑定微信 按钮 字号从 xs→sm,py 1.5→2.5,文案 立即绑定→立即绑定微信\n\n500 排错日志(/api/auth/aggregate):\n- loadAggregateSettings:先取 env fallback 前置,DB select 包 try/catch 不抛;并打印 [AggregateOAuth] enabled/appId/appKey 长度/loginType/endpoint 状态(DB=? 配置 / ENV=? 配置 / dbEnabled回退逻辑\n- auxxStrategy.getAuthorizeUrl 全链路结构化日志:\n 1) 参数打印(enabled/endpoint/safe_ok/redirect_uri/state_len\n 2) 配置缺失时逐条枚举原因(APP_ID 空 / APP_KEY 空 / ENDPOINT 空 / enabled=false)\n 3) endpoint 不合法时单独打印 [AggregateOAuth][auxx][getAuthorizeUrl] endpoint 不合法 + JSON(endpoint)\n 4) 请求 auxx.cn/connect.php?act=login 前打印 GET URL(appkey 替换为 ***,日志绝不输出真实密钥)\n 5) $fetch 成功打印 code/msg/has_url/url_prefix\n 6) $fetch 异常打印 err/status/body (response._data 或 data 前 400 字)\n 7) $fetch 加 15000ms 超时,避免 Runner 到 auxx 不通卡死一直挂 30s\n 以上;30s+ 才被 Nitro 强制 500
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m13s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m1s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-13 01:05:38 +08:00
Henry_Du 9fd8a9ccbd fix(ci,build): 双路径双 Job 注入 OAuth 6 条 secrets 到构建期\n\n根因(Run #71 已确诊):\n - Preflight Job 的「执行 nuxt build」step 的 env 注入在当前 Gitea Actions 版本下没生效(整个日志中搜不到 [OAuth] 字样)\n - 构建镜像 Job 的 docker buildx build 完全没透传 OAuth 变量,镜像内 RUN npm run build 看不到 process.env.AGGREGATE_OAUTH_APP_ID\n - nuxt.config.ts runtimeConfig.public.oauth.aggregate = !!process.env.AGGREGATE_OAUTH_APP_ID 两个路径都拿不到值 → 一直 false\n - 前端登录页第三方登录分区一直渲染占位提示,不出微信按钮\n\n修复(两条独立链路,任一条成功按钮都会出现):\n ① 链路 A(preflight 产物):preflight Job 加「注入 OAuth secrets 到 GITHUB_ENV」Step(_append_env 双引号包住值写 $GITHUB_ENV),保证后续所有 step(含 nuxt build)的进程级 process.env 都有 6 个变量\n ② 链路 B(容器镜像):Dockerfile COPY . . 后新增 6 个 ARG(OAUTH_REDIRECT_URI / OAUTH_STATE_SECRET / AGGREGATE_OAUTH_APP_ID / APP_KEY / LOGIN_TYPE / ENDPOINT)并 ENV 导出,保证 RUN node scripts/memory-build.js(npm run build)能读到\n ③ deploy.yml build-image Job:新增「注入 OAuth secrets 到 GITHUB_ENV」Step(与 preflight 同样的 _append_env 逻辑),紧接着的「构建并推送镜像」Step 把这 6 条变量逐个非空判后拼进 BUILD_ARGS=(--build-arg ...),并打印每条是否已注入(不打印值)\n\n配合 Deploy Job 原本已实现的远端 /data/opt/byw-voicehub/.env upsert(SSH 运行期写入):\n - 运行期容器(docker-compose env_file: [.env])也有同一套 6 条变量 → server/utils/oauth-strategies.ts loadAggregateSettings 的 env fallback 能读到 auxx.cn 凭据,完成微信扫码登录/绑定全链路。\n\n诊断日志(新的 Run #72 中应出现):\n [OAuth-secrets] AGGREGATE_OAUTH_APP_ID=已注入 (len=4) (若配置过 Secrets)\n [OAuth build-args] AGGREGATE_OAUTH_APP_ID=已注入\n [OAuth] build-time AGGREGATE_OAUTH_APP_ID 已配置(前端第三方登录按钮会显示), LOGIN_TYPE=wx
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m15s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m36s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-13 00:43:37 +08:00
Henry_Du f5b7bef285 fix(ci): Preflight npm ci 防超时 + Deploy job 误触发保护\n\n- deploy.yml preflight/安装依赖 Step:新增「双 registry 切换 + 3 轮重试 + npm fetch-retries=5 + fetch-timeout=5min + prefer-offline」\n - 主站 https://registry.npmmirror.com 备用 https://mirrors.cloud.tencent.com/npm/(两套独立 CDN 节点),奇偶次交替\n - npm 内部 read ETIMEDOUT(exit 146)自动走 fetch-retries 重试;整轮失败 bash 层 15s 后再跑下一轮\n - 失败 3 轮才真正 exit 1,并在日志中明确提示可覆盖 NPM_REGISTRY_PRIMARY/FALLBACK\n- deploy.yml deploy job:if 条件从 \x27!cancelled() && !failure()\x27 改为 \x27always() && needs.build-image.result == \x27\x27success\x27\x27\x27\n - 之前 build-image 被 skip(preflight 先失败)时,!failure() 为真导致 deploy 被触发但 IMAGE_NEW 空 → exit 9 误报为 deploy 本身错\n - 现在仅当 build-image 真的 success 时才会执行 deploy,build-image 被跳过/失败时 deploy 自动显示为 skipped(符合语义)
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m12s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m35s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-13 00:21:09 +08:00
Henry_Du a64fa6bc72 ci(deploy): Gitea Actions 自动接入微信OAuth(构建期+运行期双链路注入)\n\n- deploy.yml preflight/nuxt build step: env 注入 6 条 OAuth secrets;显式 export 给子进程,构建日志打印 AGGREGATE_OAUTH_APP_ID 有无值便于排错\n- deploy.yml deploy/SSH step: env 注入 6 条 OAuth secrets 传给远端 bash -s\n - 远端新增 upsert_env_key():对 .env 做 awk 整行覆盖 / 不存在追加,幂等(保证不破坏原有 POSTGRES_* / JWT_SECRET / NUXT_PUBLIC_* 等其它变量)\n - 仅当 AGGREGATE_OAUTH_APP_ID 非空才写入,避免把空值覆盖已有配置\n - 合并写入后立即在日志输出 [OAuth] 成功/跳过提示,无需手改服务器 .env\n- docker-compose.yml 已含 env_file: .env,合并写入后的变量会被容器自动加载为 process.env
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 46s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 4s
2026-09-13 00:10:54 +08:00
Henry_Du 7f3e570d8a feat(auth): aggregate OAuth 支持 auxx.cn 自定义规格(按 endpoint 自动分派)\n\n- oauth-strategies.ts: endpoint 命中 auxx.cn 时走新的 auxxStrategy\n - getAuthorizeUrl: GET {endpoint}/connect.php?act=login 拿 {url} 后转发(附 state)\n - exchangeToken: 直接 GET {endpoint}/connect.php?act=callback 拿 social_uid/access_token/nickname/faceimg,10 分钟内存缓存供 getUserInfo 读取\n - getUserInfo: 命中缓存返回 OAuthUserInfo(id=social_uid, username=nickname, avatar=faceimg)\n- 标准 OAuth2 /oauth/... 规格仍由 standardAggregateStrategy 保留,非 auxx 域名不受影响
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m11s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 8m40s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-12 23:07:05 +08:00
Henry_Du 7b605351f4 feat(auth): aggregate OAuth 支持环境变量回退配置,默认 LOGIN_TYPE=wx
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m11s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Canceled after 0s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Canceled after 7m12s
- oauth-strategies.ts: loadAggregateSettings() DB 未配置时回退读取 process.env.AGGREGATE_OAUTH_*,自动启用
- .env.example: AGGREGATE_OAUTH_LOGIN_TYPE 默认改为 wx,补充 auxx.cn 示例注释
2026-09-12 22:57:43 +08:00
Henry_Du 467dd38d5f feat(auth): 新增微信聚合登录入口与账号绑定卡\n\n- OAuthButtons.vue: aggregate 启用时渲染微信登录按钮,微信绿 hover + 专属 SVG 图标\n- OAuthBindingCard.vue: 新增微信 aggregate 绑定卡,支持绑定跳转 /api/auth/aggregate 和解绑\n- account/index.vue: hasOAuthProviders 判定加入 aggregate\n- oauth.ts: getProviderDisplayName 中 aggregate 映射为 微信
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m8s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m3s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-12 21:06:26 +08:00
Henry_Du a937f32e6e feat(theme): 移除首页主题切换按钮,恢复默认深色主题 ClassicDark
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m12s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 8m59s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
- 首页 index.vue:删除主题切换按钮 DOM、useTheme 引入及 handleToggleTheme 处理函数
- nuxt.config.ts:defaultTheme ClassicLight → ClassicDark;enabledThemes 恢复为 4 主题(System/ClassicDark/ClassicLight/ModernLight);x-default-theme meta 和防闪烁脚本回退值同步改为 ClassicDark
- schema.ts / system-settings-defaults / site-config API / POST API / useSiteConfig:7 处主题默认配置全部从 ClassicLight/双浅色列表 同步改为 ClassicDark/四主题完整列表
2026-09-12 20:40:35 +08:00
Henry_Du a0f11ff64a chore: remove script
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m14s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m47s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-12 16:57:53 +08:00
Henry_Du 78c3d878ea fix(ui): 修复浅色主题下的 Tailwind CSS 及部分残留硬编码
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Canceled after 0s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Canceled after 0s
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Canceled after 1m35s
2026-09-12 16:56:22 +08:00
Henry_Du d8060147ed chore: remove temporary files
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m13s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m41s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-12 15:57:27 +08:00
Henry_Du 9fc5e3e607 fix(ui): 批量替换所有组件中残留的硬编码深色值以彻底支持浅色主题
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Canceled after 0s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Canceled after 0s
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Canceled after 1m27s
2026-09-12 15:56:10 +08:00
Henry_Du 8b0934f6f4 fix(ui): 彻底修复深浅色主题切换及内部页面样式
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m12s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m17s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
- 恢复 variables.css 完整的 ClassicDark/ModernDark 等主题定义
- 恢复 nuxt.config.ts 的主题系统逻辑(默认改为 ClassicLight,保留切换能力)
- 修复 BackupManager / VotersModal / ProfileForm / LyricsModal / RequestForm / SongList / ScheduleList / StatsSlide / ArtistSlide 等数十处组件内部硬编码深色(#1a1a1a / #040e15 等)绕过主题的问题,全部改为使用 CSS 变量 (var(--bg-primary) 等)
- 这样实现了:在浅色模式下,所有页面均正确显示浅色;在深色模式下,又能正常呈现深色设计,且恢复了右上角的深浅色切换能力
2026-09-12 15:23:26 +08:00
Henry_Du b1c3af84de fix(ui): 补齐浅色主题遗漏:index 后段弹窗 + dashboard 根 + 改密页根
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m10s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m4s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
- index.vue 规则弹窗 modal-content/close/rule/ripple/login-required 全改为语义化 var()
- index.vue 年度报告 year-review 卡片/按钮/brand/badge/title 全部变量化
- dashboard.vue admin-layout 根 #0a0a0a/#fff 改为 var(--bg/text-*)
- change-password.vue 改密页 auth-layout 容器、表单区、back-link 全改为浅色变量
2026-09-12 14:12:10 +08:00
Henry_Du bf7c40c4fe fix(ci): 回滚 NODE_OPTIONS 非法 --gc-interval,解决 Run#56 立即 exit 9
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m9s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Canceled after 0s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Canceled after 5m35s
- Node.js NODE_OPTIONS 不允许传 --gc-interval,导致 Run 56 刚启动 Node v0 检测时就 exit code 9 全局失败
- 保留 max-old-space-size=10240、expose-gc、drop_caches、DISABLE_ROLLDOWN=1、NITRO_MINIFY=false 所有有效内存缓解措施
2026-09-12 14:04:27 +08:00
Henry_Du 7ee5e8b9e9 fix(ci): 解决 Run#55 Nitro 再次 OOM:提升堆上限到 10G 并禁用压缩/minify
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 9s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
- NODE_OPTIONS max-old-space-size 8192 → 10240,新增 --gc-interval=100000 主动 GC
- 构建前 drop_caches 清理页面缓存,降低系统级 RSS 压力
- 禁用 NITRO_MINIFY 与 DISABLE_ROLLDOWN,进一步降低峰值内存
- 构建前后打印内存快照,便于后续排障
2026-09-12 13:59:14 +08:00
Henry_Du 2ee8056ad1 fix(ui): 修复首页强制浅色不生效问题:index.vue 硬编码深色样式变量化
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 11m43s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
- 根容器 .home 背景 #121318 深色硬编码改为 var(--bg-primary)
- 全站文字 color:#ffffff / rgba(255,255,255,*) 按语义改为 var(--text-primary/secondary/tertiary/quaternary)
- 选项卡、内容面板、下拉菜单、通知卡片、分页按钮等背景/边框统一变量化
- 桌面端和移动端适配样式同步处理,彻底杜绝硬编码深色值绕过 CSS 变量
2026-09-12 13:36:15 +08:00
Henry_Du 80b7c256b5 fix(ci): 修复 Run#53 Preflight 构建 Nitro 时 OOM exit 137
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m25s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m31s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
- 将 NODE_OPTIONS max-old-space-size 从 4096 提升至 8192,并加入 preflight job 全局 env
- 构建前打印系统内存状态,便于排障
- 显式声明 NITRO_PRESET=node-server,避免构建阶段默认解析不确定性
2026-09-12 12:57:32 +08:00
Henry_Du 94832e2c82 fix(ui): 强制浅色主题与登录页细节修正
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 2m43s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
- 主题:将 CSS 变量默认值由深色改为 ClassicLight 浅色基准(背景/文字/边框/按钮/输入框/滚动条),追加 prefers-color-scheme: dark 下的 color-scheme: light 覆盖,补齐 surface-xxx 别名避免部分组件底色色值缺失
- 语言按钮:删除首页顶栏语言切换按钮及其点击处理逻辑
- 第三方登录:OAuthButtons 重写为使用语义化 CSS 变量而非无效的 --border-color,新增 alwaysShow 选项在未配置 provider 时显示占位提示;登录页强制启用提示
- 页脚与登录页:全部文字颜色与分割线由硬编码 rgba(255*) 改为 var(--text-tertiary/quaternary/border-primary),在浅色背景下保证对比度
2026-09-12 12:32:27 +08:00
Henry_Du a82ff6747e feat(site): 对齐参考站点UI与交互调整
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m8s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m11s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 7s
- 页脚:响应耗时文字统一为「响应耗时 XXXms」,版本链接改为 GitHub 官方仓库,默认 ICP 备案号设置为粤ICP备2025450093号
- 顶部栏:恢复主题切换按钮与语言按钮(语言暂为占位提示),放置于用户区左侧
- 主题:修复首屏内联脚本默认主题白名单校验,避免 localStorage 中残留的 light/dark/System 等非法值生效,首屏默认改为 ClassicLight(仅允许 ClassicLight/ModernLight)
- 登录页:在密码输入框下方恢复「忘记密码?」入口,新增配套的找回密码引导页 /forgot-password
- 默认配置:system-settings 兜底记录与 SYSTEM_SETTINGS_DEFAULTS 新增 icpNumber 默认值
2026-09-12 11:56:30 +08:00
Henry_Du 0c71328efd fix(nitro-import): permissions/user-avatar 引用路径统一改为 ~~/server/utils 别名,解决 Rollup UNRESOLVED_IMPORT
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m10s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m33s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-12 10:27:07 +08:00
Henry_Du ca190a445a fix(vue-parser): BlacklistManager 与 ScheduleManager 补 lang=ts 解决 CI Babel 解析 SyntaxError(Unexpected token, expected ,)
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 1m57s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
2026-09-12 08:55:29 +08:00
Henry_Du d818819fff feat: 实现主题、黑名单、排程等14项功能迭代
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 1m24s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 4s
- style(theme): 修复浅色模式不生效问题,为 ClassicLight 和 ModernLight 增加独立差异化 CSS 变量定义(主色/圆角/阴影/背景对比度)
- feat(blacklist): 后端放开 LANGUAGE/GENRE 类型校验;check API 新增语种(CJK/拉丁/假名/谚文/西里尔/阿拉伯)和曲风关键词匹配逻辑;前端 BlacklistManager UI 增加 语种/曲风 四类型切换、类型筛选、图标与标签颜色映射、输入提示
- fix(DataAnalysisPanel): 活跃用户列表容器加 max-h-[400px] + overflow-y-auto + 底部渐变遮罩;tooltip 加 max-height + truncate 防止超高;头像失败回退首字母
- feat(admin): 新增 user-avatar.ts 工具(OAuth→Gravatar→DiceBear 三级兜底);active-users/realtime/users 列表返回 avatarUrl;DataAnalysisPanel/UserManager 展示圆形头像;权限分级 ROLE_LEVELS,SUPER_ADMIN 全权限,ADMIN 仅可管理 ≤ USER 级用户的密码与角色,前端按钮联动禁用
- fix+style(schedule): ScheduleManager 标签页 sticky min-h 防抖、间距调优、表单分组、移动端 padding 统一
- feat(schedule): 自动排期新增「按投稿人数优先覆盖」策略(算法:requester + collaborators 总数降序),支持 CustomSelect 切换;新增 localStorage voicehub:schedule:auto-config 持久化 7 项配置(策略/时段/年级/排序/标签/搜索/学期)500ms debounce
- fix(schedule): songs/index.get 新增 usePool 参数,从 schedule_song_pool(status=PENDING,targetPlayDate IS NULL) 取歌并去重,排除已排期 songs.played=false;schedule.post 和 draft-bulk 分配后更新池状态为 ASSIGNED 避免重复分配
- feat(player): ScheduleManager 新增「构建播放队列」按钮,按 playDate→时段→sequence 排序后经 useAudioPlayer.playSong 整列载入并 toast 反馈
- fix(db): db.ts 检测 NETLIFY/VERCEL serverless 环境使用最小池 max=1 idle_timeout=1 keep_alive=false,Node Server 保持 max=10
- feat(site-config): site-config.get.ts 与 useSiteConfig.js 导出 statisticsCode 和 statisticsCodeEnabled;index.vue 挂载后解析 HTML 动态重插 script 元素确保第三方统计执行
- fix(schedule-printer): ScheduleItemPrint 封面 aspect-square object-cover;print-fix.css 打印时强制 48px×48px contain、去除圆角阴影
- fix(songRequest): 新增 server/utils/url.ts normalizeCoverUrl(trim/去零宽空格/相对协议补 https/非 http 丢弃/URL.parse 兜底);request.post/add.post/import.post 三处写入 cover/coverUrl 前统一规范化
2026-09-12 08:40:59 +08:00
Henry_Du d09d12828d feat(admin): 优化用户权限分级·统一头像·数据分析面板修复
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 55s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 4s
- fix(DataAnalysisPanel): 活跃用户卡片固定 400px + overflow-y 独立滚动容器,底部渐变遮罩提示滚动;列表项 tooltip 增加 max-height 与 overflow 截断;新增圆形头像显示与 @error 回退首字母
- feat(admin): 新增 getUserAvatarUrl 统一头像策略链(OAuth identity→Gravatar→DiceBear 7.x initials),stats/realtime、active-users、users/index 三处接口返回 avatarUrl
- fix(admin): 建立 SUPER_ADMIN(100)>ADMIN(80)>USER(10) 分级常量与 canChangeRoleOf/canResetPasswordFor 等谓词;reset-password、[id].put、index.post 全面应用级别守卫;前端 UserManager 按钮按权限禁用、availableRoles 按操作者级别过滤 SUPER_ADMIN/ADMIN 等高角色
2026-09-12 08:36:45 +08:00
Henry_Du 153ee41ef0 feat(schedule)+fix(schedule)+feat(player): 排期管理5项功能 - 紧凑布局/投稿人优先算法/localStorage持久化/备选池修复/播放队列按钮
* fix+style(schedule): ScheduleManager 标签页紧凑布局,头部 min-height 防抖,内容区统间距与移动端适配
* feat(schedule): 新增自动排期策略「按投稿人数优先覆盖」,按 requester+collaborators 数排序分配好时段
* feat(schedule): localStorage 键 voicehub:schedule:auto-config 持久化策略/时段/学期/过滤等7项,onMounted 恢复,watch debounce 500ms 保存
* fix(schedule): songs/index.get.ts 新增 use_pool 查询参数,备选池过滤条件 status=PENDING + song.played=false + song未在任何排期中;ScheduleManager/draft-bulk 创建排期时将池记录 UPDATE 为 ASSIGNED
* feat(player): ScheduleManager 工具栏新增「构建播放队列」按钮,按 playDate+playTimeId+sequence 排序后调用 useAudioPlayer.playSong 加载播放列表,支持 confirm 确认与 toast 反馈
* refactor(useSongs): fetchSongs 增加第5参数 usePool,透传 use_pool=true 到 /api/songs
2026-09-12 08:33:25 +08:00
Henry_Du 4d39afd23f fix(ci): replace heredoc-based ENV_SH with printf %q pipe → resolve yaml L544 could not find expected ':' colon false-positive + bash -s positional arg for env source
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m9s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 8m57s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-12 00:54:20 +08:00
Henry_Du e4fe591b82 fix(ci): propagate deploy env vars via remote /tmp file + bash -s arg + fail-fast if IMAGE_NEW/DEPLOY_PATH empty - resolves 5s fake-success deploys using stale :latest image 2026-09-12 00:40:40 +08:00
Henry_Du 87276f5add fix(ci): bump preflight node heap from 2G to 4G - resolves TASK-67 nitro esbuild OOM exit 137
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m9s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m19s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 5s
2026-09-12 00:20:08 +08:00
Henry_Du 0e60f15cfe feat(theme): sync defaultTheme=ClassicLight enabledThemes=[ClassicLight,ModernLight] across all 6 fallback locations
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 2m50s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
2026-09-12 00:13:27 +08:00
Henry_Du 6462b1b8a1 fix(ci): embed python scripts as base64 to avoid YAML block scalar + preflight indentation conflict - resolves TASK-63 build-image IndentationError: unexpected indent
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m8s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 10m12s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 18s
2026-09-11 23:35:12 +08:00
Henry_Du cc142a58bc fix(system-settings): correctly balance fillDefaults arrow brackets L844 - 3 RPAREN after null (logic/filter/fromEntries) then RCURLY then outer RPAREN, IDE 0 diagnostics
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 4m12s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 4m58s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-11 23:09:29 +08:00
Henry_Du 285dd24463 fix(system-settings): resolve index.post.ts L844 syntax error Expected ')' but found 'if' - fillDefaults arrow return/object literal close brackets order
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 1m33s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 4s
2026-09-11 23:01:56 +08:00
Henry_Du 5c44fca146 chore(deps): sync package-lock.json; add @parcel/watcher 2.6.0 + platform optionals (fix npm ci EUSAGE)
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 1m36s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
CI npm ci was failing with EUSAGE because upstream packages (Nuxt/Rolldown ecosystem) list @parcel/watcher in peerDependencies (^2.5.6) and optionalDependencies (^2.4.1), but the lockfile was missing the concrete @parcel/watcher@2.6.0 entry. Error message from runner: Missing: @parcel/watcher@2.6.0 from lock file.

Fix: re-ran npm install --ignore-scripts (skip local postinstall which fails on non-linux v24 Node) with npmmirror registry and --legacy-peer-deps to refresh package-lock.json only; this materializes node_modules/@parcel/watcher@2.6.0 plus 14 platform-scoped optional packages (@parcel/watcher-{android-arm64,darwin-arm64,darwin-x64,freebsd-x64,...}). Resolved URLs point to registry.npmmirror.com so CI npm ci install is fast.

Result: CI npm ci will pass the package-lock sync check and proceed to install; --legacy-peer-deps is preserved on the CI command line as before.
2026-09-11 22:51:47 +08:00
Henry_Du 0373c19b54 fix(ci): remove actions/setup-node; use npmmirror/gh-proxy for all remote fetches
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 8s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
Issue: actions/setup-node@v4 directly connects to https://github.com/actions/node-versions/releases/download/... to download Node tarballs (log line Acquiring node-v*-linux-x64.tar.gz), which is throttled or connection-reset from inside China, causing preflight to hang until 15m timeout.

Fix: align preflight with build-image job policy (NO third-party 'uses:' directives, ALL remote resources use CN mirrors or GH_PROXY_PREFIX):

- Remove uses: actions/setup-node@v4 completely; replace with plain run steps

- 3-tier Node 22 readiness with zero direct github.com connections:

  1) Fast path: reuse Runner's system node if major version >= 22, skip download entirely

  2) Primary: fetch Node 22 tarball from npmmirror CN binary mirror (https://registry.npmmirror.com/-/binary/node/...) and auto-resolve latest 22.x patch via npmmirror index.json using python3 single-quote script + printf stdin (NO heredoc, which previously caused YAML block-scalar indentation parse errors)

  3) Fallback: GH_PROXY_PREFIX + official nodejs.org dist URL for the same tarball (proxied, never plain github.com)

- NODE_VERSION_FALLBACK=22.13.0 fixed guard when index resolution fails

- Post-install: prepend new node bin PATH to GITHUB_ENV so subsequent steps (clone / npm ci / nuxt build) inherit Node 22 automatically

- Audit: grep deploy.yml now yields zero 'uses:' directives
2026-09-11 22:46:40 +08:00
Henry_Du afb4cd3669 fix(ci): 修复 deploy.yml YAML 语法错误(line 177 could not find expected ':'),消除 heredoc 与块标量缩进冲突
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 15m2s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
- 根因:build-image job 注入 Docker daemon.json 时用了 bash heredoc <<'PY'...PY;heredoc 内部 Python 代码在 YAML 文件里缩进为 0,触发 run:| 字面块标量提前结束;Gitea YAML 解析器尝试把下一行解析为新的 key 却找不到冒号 → 抛 line 177 could not find expected ':',整个 workflow 无法触发
- 修复:移除 heredoc 结构,改为 PY_CODE 单引号字符串 + printf '%s' | python3 - stdin 管道传递;单引号内所有 Python 行统一保持与外层 shell 语句一致的 12 spaces 前导缩进(满足 YAML 块标量 ≥ 10 spaces 基础缩进要求);Python 顶级代码统一缩进 12 spaces,块内再缩进 4 spaces,避免 IndentationError
- 验证:IDE YAML 诊断 0 错误;Gitea Actions 页左侧 deploy.yml 红色感叹号应立即消失,可正常触发 run
2026-09-11 22:28:42 +08:00
Henry_Du 124280a92f fix(ci): 消除 preflight Set up job docker pull 卡点,改用宿主机 Node 22 + daemon.json mirrors + Dockerfile ARG 双保险
- preflight:删除 container.image: node:22-bookworm-slim,避免 Runner 在 Set up job 阶段独立 docker pull(国内连 Hub 被限速一直卡)
- preflight:改用 runs-on 直出 + actions/setup-node@v4 装 Node 22,npm registry 设 npmmirror
- build-image:python3 合法合成 /etc/docker/daemon.json 注入 3 组 docker.io registry mirrors(daocloud/1panel/1ms.run),systemctl→service→失败跳过 三级 non-intrusive 重启 docker
- Dockerfile:新增全局 ARG DOCKER_MIRROR / NODE_BUILDER_TAG / NODE_RUNTIME_TAG,FROM 统一前缀化;本地开发 DOCKER_MIRROR 为空时等价原写法,体验不变
- buildx BUILD_ARGS:新增 3 个 --build-arg 把 DOCKER_MIRROR_PREFIX / NODE_BUILDER_TAG / NODE_RUNTIME_TAG 传入,CI 拉 node:22-alpine 必走国内源
- 修复后:workflow 触发时 Preflight 日志不会再出现 Starting job container / docker pull image=node:***-bookworm-slim;前面 system-settings defaults 兜底修复可顺利部署上线
2026-09-11 21:59:19 +08:00
Henry_Du 13b9b72170 fix(system-settings): 修复线上主题/排期/聚合登录等配置缺失,对新 DB 字段用 SYSTEM_SETTINGS_DEFAULTS 兜底 + 更新接口允许写入新字段 + 缩短 Redis 缓存 TTL
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 15m0s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 3s
- site-config.get.ts:filterPublicSettings 和 Redis/DB 命中分支全部先合并 SYSTEM_SETTINGS_DEFAULTS,解决老库无 schema 新字段导致 public 返回 defaultTheme=light、enabledThemes=light,dark 等旧值的问题
- admin/system-settings/index.post.ts:新增 ~40 个白名单字段(主题/排期可见范围/留言自动审查/OAuth 聚合/首次强制改密/投稿限制/卡密/注册审核/自动备份/统计代码等),支持管理面板保存生效;更新返回结果用 fillDefaults(DEFAULTS) 兜底
- admin/system-settings/index.ts (GET):返回 DB 记录前合并 SYSTEM_SETTINGS_DEFAULTS,避免管理后台 UI 拿不到新字段
- cacheService.ts:CACHE_TTL.SYSTEM_SETTINGS 3600s → 900s(60min→15min),防止 Redis 单机挂或旧脏值导致配置变更长时间不生效
2026-09-11 21:39:45 +08:00
Henry_Du daa86ef50f fix(song-management): add lang=ts to script setup to fix catch type annotation SFC parse error
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 3m25s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m14s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-06 17:58:38 +08:00
Henry_Du bd8df1f026 feat(songs): 歌曲管理支持批量驳回、投稿留言自动审查与排期范围可见性过滤
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Failing after 6m31s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Skipped
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 4s
- 新增 /api/admin/songs/batch-reject.post 批量驳回接口(事务清排期/投票/扣接纳数/黑名单去重/异步通知)
- requireSongAdmin 三角色校验 + createApiError 统一错误包装
- scheduleDaysBefore/After 四字段排期可见范围限制(开放 API 与公开排期接口三处缓存路径 + DB 条件过滤)
- submissionNoteAutoModeration 基于黑名单 KEYWORD/LANGUAGE/GENRE 自动判定留言 publicStatus,命中自动关闭 submissionNotePublic
- 更新 songs/request.post 与 songs/[id]/update.put 接入自动审查逻辑
2026-09-06 17:03:20 +08:00
Henry_Du 43e2a05666 fix(ci): docker-compose.override.yml 生成方式从 heredoc 改 printf 单行拼,彻底绕开 bash heredoc 结束分隔符必须行首 + 变量不展开 + YAML parser 误判 services: 三重坑
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m22s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m14s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 6s
2026-09-06 15:10:36 +08:00
Henry_Du 732c9c6725 fix(ci): deploy Job 增加目录可写性预检查 + docker-compose.override.yml heredoc 分隔符改 COMPOSE_OVERRIDE 并对齐缩进(绕开 YAML parser 误判 + 权限问题友好排查)
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m31s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m16s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Successful in 4s
2026-09-06 14:17:05 +08:00
Henry_Du 496edf9f71 fix(ci): buildx build --load -> 宿主 docker push 两阶段,彻底绕开 buildkitd OAuth2 空 token 推送失败
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m35s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Successful in 9m43s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Failing after 4s
2026-09-06 13:55:40 +08:00
Henry_Du 2097608f51 fix(ci): buildkitd.toml 注入 Gitea Basic Auth 凭据,绕开 OAuth2 空 token(authorization server did not include a token)
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m26s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 7m35s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-06 13:42:04 +08:00
Henry_Du 455438aa64 fix(ci): Docker Registry 仓库路径 owner/repo/tag 强制全小写,修 repository name must be lowercase
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m30s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 17m18s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-06 13:17:50 +08:00
Henry_Du d98fe53658 fix(ci): docker buildx build 删除不支持的 --context flag,改为末尾位置参数 .
构建并部署 BYW VoiceHub / Preflight 语法与构建检查 (push) Successful in 2m57s
构建并部署 BYW VoiceHub / 构建并推送容器镜像 (push) Failing after 4m14s
构建并部署 BYW VoiceHub / 部署到生产服务器 (push) Skipped
2026-09-06 12:23:15 +08:00