Henry_Du
|
dc2565da34
|
fix(微信订阅): 字段名按微信真实模板校准,不再靠猜编号;phrase 只截断不补齐
|
2026-10-24 10:18:57 +08:00 |
|
Henry_Du
|
d1b643bd93
|
refactor(微信订阅): 重写订阅消息链路,每一步失败都可见
把「微信订阅消息」这套代码按验收标准推翻重写:用户能自己看懂为什么收不到,
任何一步失败都必须看得见。对外函数名不变,notificationService / test-subscribe
等调用点无需改动。
新增 server/utils/wechatSubscribeTemplates.ts(纯函数,零依赖):
- 模板登记表唯一来源(内置 SONG_SELECTED / SONG_REJECTED),服务层不再自己写死
- parseSubscribeTemplates 如实报告环境变量覆盖情况:坏 JSON 只报告不抛、
只给 id 时沿用内置字段映射、缺 id 的项记进 unknownKeys 并忽略
- findEmptyFields / findEmptyDataFields 发出前自查空字段(微信空值整条 47003)
- explainWechatErrcode 把 43101/47003/40003/40037/40001/45009 翻成人话
重写 server/services/wechatSubscribeService.ts:
- sendWechatSubscribe 返回 SendOutcome,用 stage 明确「卡在哪一步」:
no-template / disabled-by-user / no-wechat-openid / no-access-token /
empty-field / no-grant / rejected-no-quota / rejected-bad-field / rejected-other
- 每一次返回都写一行日志,不再有静默跳过(这是「发不出去全靠猜」的根因)
- inspectWechatSubscribe 只读体检:不发消息、不消耗额度,返回逐项 verdict + actions
- grantWechatSubscribe 依靠新增的 WechatSubscribeGrant 表记账:微信没有查询
剩余授权的接口,只能自己数(用户点允许 +1、发送成功 -1)
- 记账表不可用时失败开放(fail-open):额度预检关闭、照常发送,避免通知整体哑掉
- access_token 显式 responseType: json 并做字符串兜底解析
新增接口:
- GET /api/user/wechat-subscribe-status 小程序显示「还能收到几条 / 为什么收不到」
- POST /api/user/wechat-subscribe-grant 小程序授权成功后上报 accept 的模板
- GET /api/admin/wechat/diagnose 重写:人话结论 + actions,?send=1 真发一次
其他:新增 WechatSubscribeGrant 表(schema + 手写迁移)、.env.example 说明 JSON 覆盖
写法、.gitattributes 补 *.sql eol=lf。
测试:新增 test/wechatSubscribeTemplates.test.mjs(13 个用例,可直接 import .ts,
不依赖 Nuxt 别名),npm test 里订阅相关 25/25 通过。
|
2026-10-11 16:02:33 +08:00 |
|
Henry_Du
|
3eff710d5d
|
feat(微信订阅): 接入歌曲排期模板并加固部署流程
订阅消息(小程序侧唯一能主动触达用户的通道):
- 新增 server/utils/wechatSubscribeFields.ts:按微信字段类型裁剪值(thing≤20、
phrase 必须 5 个汉字、time/date/character_string 各自上限),空白压成一行,
北京时间 time 由 playTime 的开始时间生成,解析不出退化为当天 00:00。
- wechatSubscribeService 内置 SONG_SELECTED 模板(站长新给的那个模板 ID),
并转发上述纯函数;notificationService.createSongSelectedNotification 现在会带上
playDate/playTime/sequence,三个排期接口(schedule / publish / bulk-publish)补传 sequence。
- 新增 test/wechatSubscribeFields.test.mjs(10 例,node --test 全绿)。
- test-subscribe 管理接口支持 vars 覆盖并返回真实发送值,方便站长核对字段名。
部署流程(Gitea Actions 容器里没有 buildx 插件,旧流程在此硬失败):
- 每个 job 各自安装/探测 docker-buildx(v0.19.3,走 gh-proxy 再退直连),
不把 `buildx version` 当唯一依据;装不上时降级为普通 `docker build` 继续发布,
不再因为缺插件整条流水线失败。
注意:SONG_SELECTED 的字段名(thing2/date4/time1/character_string3/phrase5)是按常见
命名推断的,需在公众平台后台核对;不一致时用环境变量覆盖,模板 ID 变更后老用户需重新授权。
|
2026-10-11 00:04:14 +08:00 |
|
Henry_Du
|
ebf1c3a127
|
perf(auth): 登录去掉一次冗余查库 + 缓存 2FA 查询 + 修掉 session_key 进日志
登录实测约 232ms,其中 bcrypt 约 72ms、网络往返约 80ms 是不可省的计算/物理成本,
剩下的都是我们自己的开销。这次把能省的两处省掉(实测约 40ms,占登录耗时约 19%):
1. 去掉「数据库连接检查」的冗余预检
原来每次登录先 await db.select().from(users).limit(1) 只为"测连接",
紧接着又会真的查用户,连不上一样会报错 —— 纯粹多一次数据库往返。
现在把那次真实查询包进 try,只有它失败才回报 503「数据库服务暂时不可用」,
错误码与文案完全不变。
2. 缓存「这个账号有没有开 2FA」
登录每次都查 userIdentities 找 TOTP,但绝大多数账号根本没开 2FA。
新增 server/utils/totp-cache.ts:
· 查到**没有** TOTP → 缓存 10 分钟,后续登录直接跳过查询
· 查到**有** TOTP → **不缓存**(安全优先:绝不能因为缓存而让刚开 2FA 的人被跳过验证)
开启/关闭 2FA 的接口必须调用 invalidateTotpCache(userId),已在
server/api/user/2fa/{enable,disable}.post.ts 接上 —— 否则会有最长 10 分钟的验证空窗。
该缓存不参与密码校验,最坏情况只是多查一次库。
3. lastLogin / lastLoginIp 的 UPDATE 不再阻塞响应
登录时间与登录 IP 是审计信息,晚写几十毫秒、甚至这次写失败,
都不影响用户能否登录。改为不 await(保留 .catch,避免 unhandledRejection)。
4. 安全修复:微信登录不再把 session_key 打进日志
server/api/auth/wechat/login.post.ts 原来打印整个 jscode2session 响应前 500 字,
而该响应含 { session_key, openid, unionid }。
session_key 是敏感凭据(可解密用户数据、配合其他接口换取手机号),
长期落在服务端日志里等于凭据落盘。
现在只打印:顶层键名、errcode/errmsg、以及 openid/session_key/unionid 的
存在性与长度(不打印值);仅在"响应根本不是对象"时才打印截断原文
(那种情况它不可能是合法凭据,且是排查被代理拦成 HTML 的唯一线索)。
已验证:
- 缓存逻辑用假 db 真跑过 5 个场景(命中缓存省下查询、失效后立刻重查、
有 2FA 不缓存、多用户互不干扰、只失效指定用户)
- 4 个改动文件的相对 import 路径均存在;totp-cache 的导出与两处 import 对得上
- login.post.ts 抽走 TOTP 查询后已清理不再使用的 userIdentities / and 导入
- 文件编码 UTF-8 无 BOM、无乱码、括号平衡
|
2026-10-01 21:04:02 +08:00 |
|
Henry_Du
|
cd6e235848
|
fix(users): 状态大小写不敏感 + 彻底修掉「无法编辑其它用户」
站长反馈仍然无法编辑其它用户。上一版只把**小程序端**的状态改成小写,
但如果小程序没重新编译(或用的还是旧版本),发上来的仍是 `ACTIVE`,
服务端 `['active','withdrawn','graduate'].includes(status)` 依旧不通过 → 400
「用户状态只能是 active, withdrawn 或 graduate」——编辑任何用户都会失败。
这版把容忍度放到**服务端**,与客户端版本解耦:
- 新增 server/utils/user-status.ts:
· USER_STATUSES = ['active','withdrawn','graduate']
· normalizeUserStatus() 大小写不敏感('ACTIVE' / ' Active ' → 'active'),认不出返回 null
· USER_STATUS_RULE_MESSAGE 统一文案
- [id].put.ts:状态改用归一化值;另修正"自己只能改姓名"里的状态比较也忽略大小写
- [id]/status.put.ts、batch-status.put.ts:同样归一化;
并修掉一个我自己引入的隐患(把归一化结果赋回 const 变量 → TypeError),
batch-status 之前被误写成不存在的 statusesRaw,一并改正
效果:无论小程序是否重新编译,管理员都能编辑其它用户(含历史拼音账号只改年级)。
|
2026-09-30 23:49:40 +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
|
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 |
|
DeepSeek Harness
|
9db42861e1
|
fix(server): 补上 DatabaseManager 缺失的连接池与性能方法
DatabaseManager 类从未定义 getConnectionPoolStatus / getPerformanceMetrics,
但有 4 个接口直接调用它们,导致运行时 TypeError 并返回 500:
GET /api/admin/database/pool-status
GET /api/admin/database/performance
GET /api/system/status
POST /api/system/reconnect
两个函数本就实现在 utils/database-health.ts(getConnectionPoolStatus /
getDatabaseMetrics),这里补上委托方法,调用点无需改动。
验证:用项目的 .nuxt/tsconfig.server.json 做 A/B 类型检查,
改动前有 4 处 'Property does not exist on type DatabaseManager',
改动后全部消失(总报错数 682 -> 678)。
|
2026-09-26 16:21:28 +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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
4ce4649aaf
|
初次提交
Build VoiceHub FPK / build-fpk (push) Failing after 56m5s
Build and Push Docker Image / build-and-push (push) Canceled after 1h9m35s
|
2026-09-06 08:19:02 +08:00 |
|