laoyang
|
338a35cacd
|
主题色改为完整色板:画布 342x200,加明度条,删除右侧预设圆点
用户:「还是不对呀,需要一个完整的色板,右侧那些默认颜色就不要了。」
两个改动:
1. 删掉右侧那排 12 个预设圆点($presets 变量、CSS、JS 同步逻辑一并删)。
色板本身能取任意颜色,再摆一排样例是重复,还挤占横向空间。
2. 色板做成「完整」的:
面板 248×246 → 372×357
画布 226×150 → 342×200(太小拖着不好定位颜色)
新增明度条,底色随当前色相实时刷新 ——
否则永远是灰阶,用户看不出拖到那里会得到什么颜色
面板加标题「选择颜色」,按钮文案「确定」→「完成」
顺带简化光标定位:
原来 cursor 挂在 .cp 里,要靠两个 getBoundingClientRect 相减算偏移;
现在改挂到 .cp-sv-wrap(与 canvas 同级),坐标直接相对 canvas 算,
少一层偏移、少一个坑。
验证(浏览器实测):
.color-preset 残留 0 个、.color-presets 容器 0 个
面板 372×357、画布 342×200,完整在视口内
色相 200° → 明度条背景 linear-gradient(#000, rgb(0,170,255)),确实跟着变
画布 80%/20% 处取色 → #2996cc,光标落在画布范围内
明度拖到 50% → #1a5e80(同色相压暗,符合预期)
手输 #2E7D5B → 隐藏字段 #2e7d5b,点完成关闭
4 个路由 200
|
2026-11-04 18:57:18 +08:00 |
|
laoyang
|
ad1b0eedf4
|
主题色改为自绘取色面板(任意取色);图标上传加即时预览与状态提示
一、颜色不够丰富 → 点击弹取色面板
用户:「还是不行,颜色还是不够丰富。让用户选择吧:点击之后弹出一个颜色选择器。」
原来只有一个原生 <input type=color> 小方块,用户不知道能点,
而且系统面板各浏览器样式不一、只能取纯色。
改成自绘面板:
色相/饱和度渐变板(Canvas)+ 明度滑块 + 十六进制输入 + 确定
12 个预设圆点降级为快捷方式,真正的能力是任意取色
交互:点色块弹出(下方空间不够自动翻上方)、板内拖动实时更新、
十六进制可手输、点确定或面板外关闭、Esc 关闭
⚠️ 光标定位踩了两个坑,都写进注释了:
① 不能用 canvas.offsetLeft(相对 offsetParent,受父级 padding 影响,
实测算出 236px 超出画布宽度 226px);要用两个 getBoundingClientRect 相减
② canvas 显示尺寸受 CSS width:100% 影响,≠ 内部像素 220×150,
必须用 rect.width 而不是 canvas.width
二、图标上传没反馈
用户:「上传的图标没有显示,也没有上传成功、失败之类的提示信息。」
后端逻辑完整(格式/大小/尺寸/存储模式都校验了),问题在**前端零反馈**:
裸 <input type=file>,选完文件什么都不发生,而提示条在页面顶部容易被错过。
加了 bindIconUpload():
① 选中文件立刻 FileReader 本地预览,不等提交
② 显示文件名 + 尺寸 + 大小,让用户确认选对了
③ 选之前就拦掉明显不合格的(格式/超 2MB/小于 32×32/空文件)
④ 非正方形给出警告(显示时会被裁切)
⚠️ 前端校验只是体验优化,绝不能当安全边界 ——
真正的校验仍在 PHP 的 fb_icon_store_upload() 里。
验证(用独立测试页 + 浏览器实测,不登录后台、不动数据):
面板初始隐藏 → 点击后 248×246 出现
Canvas 四角像素分别为灰白/蓝/黑 → 渐变确实画出来了
板上取色 → 隐藏字段 #2178d9 同步到按钮文字/十六进制框/预览色
点预设 → #2B822E;手输 → #a020f0;色相滑条 120° → #20f020
光标中心 (238,54) 落在画布区域 (11..237, 11..161) 内
4 个路由 200
|
2026-11-04 18:52:45 +08:00 |
|
laoyang
|
a00e2221c4
|
调色板从 8 色扩到 12 色(按色相环重排);后台预设改为共用同一份
用户:「不同的软件要有不同的颜色,现在颜色有点少,快不够分了,
至少应该有 10 个左右的颜色。」
调研发现的问题比「数量少」更严重:
🔴 调色板有两份独立硬编码 —— util.php 一份、admin_taxonomy.php 又一份,
两边的色值还不一样,早就不同步了。用户在后台只能从 8 个里选,
而实际分配用的却是另一批色值。
改法:
- 新增 fb_color_palette() 作为唯一出口,12 色
- fb_color_default_for() 改为调用它
- 后台 也改为调用它 —— 从此只有一处需要维护
12 色设计(360° 切 12 段,逐色验证,不是随手挑的):
色相:2/32/62/92/122/152/178/200/232/266/293/330,**最小相邻间距 22°**
对比度:白底全部落在 4.76~6.19,既都够看清(WCAG AA 需 ≥4.5),
又不会某个颜色特别深显得突兀
压制项:黄/黄绿饱和 50%(再高就荧光)、蓝/靛蓝压到 62%/50%
避开项:纯红纯绿会与「待处理/已解决」状态色撞,所以红取 2°、绿取 122°
中途踩过的坑(记录下来避免重犯):
第一版直接往原 8 色后面追加 6 个,实测发现 8 对颜色几乎同色 ——
因为原调色板里 185°/212°/217° 三个蓝本就挤在一起。
「塞进缝隙」这个思路是错的,必须重排整个色相环。
现有 5 个软件颜色**未改动**(实测仍是 #0057b8/#b4553c/#6a4c93/#0e7c86/#3a5a8c):
它们的色相分布本就合理(2°12°185°212°265°),没必要让已发布链接的配色突变。
新调色板只影响「新添加且未指定颜色」的软件。
验证:12 色无重复、对比度全 ≥4.5、最小色相间距 22°、
后台已改为调用 fb_color_palette() 且旧硬编码数组已消失、6 个路由 200。
|
2026-11-04 17:54:39 +08:00 |
|
laoyang
|
872baf4153
|
修复:图标存储未跟随后台配置,本地模式下图标显示不出来
用户指出图标应当与附件同一套逻辑:管理员在后台配 local 就存本机、
配 oss 就存 OSS,前台都一样走 media.php 代理。
原实现把图标键硬编码成 icons/…(不带存储前缀),导致:
- fb_attach_is_local() 恒为 false
- 本机模式下文件确实写进了 uploads/icons/,
但 media.php 把它当 OSS 对象去读 → 503,图标完全显示不出来
修法:图标键与附件完全同规则,只是路径里多一段 icons/
local 模式 → local/icons/YYYY/MM/<hex>.<ext> 落 uploads/icons/
oss 模式 → <oss.prefix>/icons/YYYY/MM/<hex>.<ext> 落私有桶
前台地址两种模式一致(media.php?k=…),换存储方式旧图标不会失效。
同时:
- fb_icon_is_key/ok 改为同时识别两种前缀
- fb_icon_allowed_ext 移到 attach.php(media.php 与校验都会用,
不能依赖 admin_taxonomy.php 被加载)
- 写入时加断言:键前缀必须与当前存储模式一致,脱钩就报错,
不再静默存到错误位置
验证(线上真实环境,两种模式各跑一遍):
- local:键带 local/icons/ 前缀、写入 uploads/icons/ 成功、
media.php 读回 200 image/png 501B、PNG 魔数正确、删除后 404
- oss:键带 fb/icons/ 前缀、is_local=false、URL 拼接正确
- 旧 bug 形态(icons/… 无前缀)现在被明确拒绝 400,不再误判成 OSS
- 测试后配置已复原为 oss,临时文件与诊断入口全部清理
|
2026-11-03 08:19:17 +08:00 |
|
laoyang
|
835c8c05da
|
软件图标支持上传图片:存 OSS/本机,media.php 代理读取
用户要求图标可以自己上传一张真实图片,而不是只能填一个字符。
设计:字符和图片并存,图片优先
- software 加 icon_key(图片对象键),icon(字符)保留作兜底
- 有图片用图片,删掉图片自动退回字符,任何时刻都不会没有图标
- 前端 badge 与邮件头部同一套判断,页面和邮件永远一致
存储与读取
- 图标走独立键空间 icons/YYYY/MM/<16hex>.<ext>
不复用附件那套:附件必须挂在 thread 下才给读,图标不属于任何帖子
- 写:仅管理员(后台动作链)+ finfo 真实类型校验 + 尺寸下限 + 2MB 上限
- 读:media.php 对 icons/ 只校验键形状与文件存在(图标本就公开),
写入侧仍然严格,不会让本站变成能读整个桶的开放代理
- 优先用 media.php?k= 代理;OSS 下顺便借图片处理缩放,省下行
顺手修掉两个真实安全问题
1. fb_icon_key_ok 原来用 [a-z0-9]{2,5} 匹配扩展名,.php 正好能过
(3 个字母)—— 测试反向验证时发现,已改为图片扩展名白名单
2. fb_upload_key_ok 有同样的问题,附件键也能构造出 .php
虽然真上传还有 finfo 兜底,但键本身就不该长这样,一并收紧
3. fb_icon_delete 原来用 @ 吞掉错误,删除失败仍返回「已保存」,
用户会以为旧图清了、实际留了个可访问的孤儿图。改为返回 bool 并如实提示
验证:键校验 7 类非法输入全拒;图标写入 OSS 成功、media.php 读回 200 image/png、
PNG 魔数正确、缩放生效;越权读取(穿越/.php/未入库附件/不存在)全部按预期拒绝;
表单 enctype/文件框/accept/预览渲染齐全;仿真 PHP 伪图与 SVG 均被拒;
16x16 小图被拒。
|
2026-11-03 08:13:21 +08:00 |
|
laoyang
|
738c6c09ff
|
多软件区分:邮件按软件换色+图标+软件名;补提交回执邮件
用户要求:多软件并存时,用「颜色 + 图标 + 名字」三重区分,
邮件也要跟着所属软件变,一眼能看出是哪款软件的来信。
1. software 表加 icon / download_url 字段(幂等迁移)
- icon 存单个字符(emoji / 汉字 / 字母),不存图片路径:
前端与邮件用同一个字符渲染,天然一致,不用再管一套上传与权限
- 没配 icon 时取名首字兜底,任何地方都不出现空图标
- 后台软件编辑加图标快选(12 个常用 emoji)
2. 邮件配色改为跟随软件(fb_mail_brand 取 fb_software_colors)
- 头部色条、按钮、引用块色条、徽标全部跟着软件走
- 邮件头部改为「图标色块 + 软件名」,下面再小字标站点名
- 主题行统一加【软件名】前缀,不点开就能分辨
3. 新增 receipt 事件:提交后立即给提问人发「已收到、待审核、请耐心等待」
- 独立开关 notify.receipt_enabled(与「回复通知」是两件事)
- 新增 7 处调用前的静默 return 也一并写日志
4. reply 邮件补上下文:原提问摘要 + 本次回复,像博客评论通知
5. status=resolved 文案改为「已完成并上线」,配了下载地址时给下载按钮
验证:多软件配色/图标/前缀全部通过(含反向验证),XSS 转义通过,
空图标兜底通过;页面顶栏、页头、选择器图标渲染正确。
|
2026-11-03 08:00:50 +08:00 |
|
laoyang
|
f1a81cbaa1
|
RAM 角色自动探测 + 邮件配置界面 + 每个软件独立主题色 (#1 #2)
## 1. ECS RAM 角色改为自动探测
原先要用户去阿里云控制台查「实例 RAM 角色名」再手填,纯属多余 ——
机器自己知道答案。
新增 fb_oss_detect_instance_role():读元数据
GET /latest/meta-data/ram/security-credentials/(末尾带斜杠)拿到角色名列表。
- 兼容单行 / 多行 / JSON 数组三种返回
- 未配置角色时 fb_oss_instance_creds() 自动探测,不再报「未配置」
- 后台改成只读展示「已绑定:xxx」,手填入口收进「高级」折叠里
- 保存时留空 = 自动探测后写入,不存空值
- 探测失败给出可操作原因(没绑角色 / 不在 ECS 上 / 元数据被禁用)
## 2. 邮件配置界面(原先完全缺失)
lib/mailer.php 有完整 SMTP 实现,但后台一个输入框都没有,
只能改 config.php —— 用户装完根本找不到地方配。
根因有两层:
- fb_setting_keys() 白名单里没有任何 smtp.* / notify.* 键,
就算加了表单,fb_set_setting() 也会把值全部丢弃
- 设置页只有「站点信息」「附件存储」两个区块
补上:白名单 15 个键 + 后台「邮件通知」区块
- SMTP 服务器/端口/加密方式(SSL/STARTTLS/不加密)
- 登录账号/密码(留空不修改,避免每次重填)
- 发件地址/显示名、超时、SSL 校验
- 通知规则:回复通知、每次回复都通知、新反馈通知管理员、发信冷却
- 「发送测试邮件」按钮,AJAX 发完就地显示成功或失败原因,
不用保存再靠猜
## 3. 每个软件一个主题色
需求:从短链接进不同软件,颜色不同,一眼区分。
- software 表加 color 字段(幂等迁移)
- 全站配色靠 --brand / --brand-600 / --brand-soft 三个变量,
按软件覆写这三个即可,不用为每个软件写一套 CSS
- fb_color_variants() 由主色推出深一档(×0.85)与浅一档(往白混 88%)
- 未配色的软件按 id 从 8 色调色板取默认色,保证同站不撞色
- 后台:颜色选择器(原生取色 + 8 个预设 + 用默认)
- 前台:index / new / thread 都按当前软件注入主题色,
meta theme-color 也跟着变
验证:三功能专项 30/30;新旧回归全过
(全新安装 33/33、老基线 25/25、附件 22/22、安装向导 60/60、约束检查 20/20)
|
2026-11-01 16:39:09 +08:00 |
|
laoyang
|
1434a6dfb6
|
修复:英文标识留空真能自动生成;表单必填前端就地提示不刷新 (#1)
## 问题 1:文案说「留空自动生成」,实际却报错
界面上英文标识写的是「留空自动生成」,且不带红星;但纯中文名
(如「同步日历」)经 slugify 过滤后是空串,服务端照旧报「请填写英文标识」。
文案与行为自相矛盾,用户不明所以。
根因:fb_sw_slugify() 只保留 ASCII,中文全被过滤掉。
修法(不靠加红星了事):给 slugify 加兜底前缀 + 序号
- 软件:中文名 → sw<序号>(如 sw2)
- 分类:中文名 → cat<序号>
- 编辑时留空 = 保持原标识,不因改名把已有网址打散
- 纯英文名行为不变(FeedLite → feedlite)
实测:同步日历 → sw1 / 我的软件 → sw2 / FeedLite → feedlite
## 问题 2:必填项没填,整页刷新才看到错误
原先完全靠服务端校验:提交 → POST → 整页重刷 → 页面顶部弹一条错误。
用户视角就是「什么都没填,页面闪了一下」。
新增 bindInlineValidate()(assets/app.js):
- 给 form 加 data-validate 即启用,零配置
- 就地校验:字段下方显示红框 + 原因,聚焦并滚到可见
- 用户一改动立刻撤掉提示,不一直红着
- 规则取自原生 required / minlength / pattern / type=email
🔴 关键实现细节:用**捕获阶段**监听,并调 stopImmediatePropagation()。
因为 bindNoDoubleSubmit 会在 submit 时禁用按钮 5 秒,若校验排在它之后,
被拦下的表单按钮会被锁住,用户以为点坏了。所以校验必须先跑且拦住它。
## 服务端仍保留兜底
JS 被绕过(禁用脚本、直接构造请求)时,后端照样拒绝空用户名、短口令。
## 顺带收敛资源版本
app.js?v=5 与 style.css?v=N 原先各自写死,已统一到 FB_ASSET_V(升到 11)。
加上前一轮的 layout.php / install.php,现在全站只有 bootstrap.php 一处定义。
验证:
- 标识生成与前端校验专项 21/21
- 全新安装 33/33、老基线 25/25、附件专项 22/22
- 安装向导 60/60、后台管理 30/30
|
2026-11-01 15:21:27 +08:00 |
|
laoyang
|
55d2dfa46b
|
后台管理界面:软件/分类/状态可配,反馈可改挂归属 (#1)
## 新增 lib/admin_taxonomy.php
- 软件:增删改、排序、启停;新增时自动预置 Bug/功能建议/其他 三个分类
- 分类:在选定软件下增删改、排序、启停
- 状态:改名、改「给用户看的话」、排序、启停;标识不可改(历史数据靠它对应)
- 反馈改挂:th_move,可把反馈移到别的软件/分类,跨软件的非法分类会被拒
## 安全与边界
- 所有动作走 CSRF 校验(沿用现有机制)
- 不能删最后一个软件 / 没有分类的软件至少要留一个启用分类
- 有反馈挂着的软件或分类不能删,提示改为停用(停用后前台消失、数据保留)
- th_move 加入 fb_admin_is_taxonomy_act 白名单,否则会被「问题不存在」静默吞掉
## admin.php 接线
- 引入模块 + 动作分发 + tab 白名单加 taxonomy/statuses + 导航两项
- 前置检查放行不依赖 $t 的动作(否则新增软件报「问题不存在」)
- 全部问题列表:加软件筛选、分类跟着软件走;修掉三处仍在用旧
fb_statuses()/fb_categories() 的遍历(那会渲染出错)
- 详情页加「归属」表单,软件徽章可显示
## 其他文件
- api.php:状态/分类改数据库;新增 ?sw= / ?software_id= / ?cid= 过滤,
老的 ?category=<slug> 仍可用(在所属软件内解析)
- thread.php:详情页显示软件与分类徽章
- config.example.php:移除 categories / statuses,改由数据库管理
## 修掉两个真实 bug
1. 移除配置后出厂分类兜底只剩 4 个,漏了「同步问题」—— 建库后核对数量才发现
2. th_move 不在白名单,POST 后返回 200 却静默不生效
验证:后台 e2e 29/29;改挂与联动 13/13;PHP 8.5 全部入口 0 弃用;
19 个 PHP 文件语法全过。
|
2026-11-01 12:03:11 +08:00 |
|