多软件区分:邮件按软件换色+图标+软件名;补提交回执邮件
用户要求:多软件并存时,用「颜色 + 图标 + 名字」三重区分,
邮件也要跟着所属软件变,一眼能看出是哪款软件的来信。
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 转义通过,
空图标兜底通过;页面顶栏、页头、选择器图标渲染正确。
This commit is contained in:
@@ -171,6 +171,20 @@ function fb_default_software() {
|
||||
return $list ? $list[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 由帖子行取它所属的软件行(邮件/页面要显示「这是对哪个软件提交的」都用它)。
|
||||
* threads 只存 software_id,这里统一解析,避免各处自己写 SQL 漏掉。
|
||||
* 取不到时回落到默认软件,保证邮件里永远有软件名可显示。
|
||||
*/
|
||||
function fb_software_of_thread(array $thread) {
|
||||
$id = isset($thread['software_id']) ? (int)$thread['software_id'] : 0;
|
||||
if ($id > 0) {
|
||||
$sw = fb_software($id);
|
||||
if ($sw) { return $sw; }
|
||||
}
|
||||
return fb_default_software();
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单回显用:如果当前值等于「出厂默认」,就返回空串。
|
||||
*
|
||||
@@ -263,6 +277,74 @@ function fb_software_colors($software) {
|
||||
return fb_color_variants($hex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化软件图标字符。
|
||||
* 只留前几个字符,去掉换行与 HTML 尖括号 —— 这个值会直接输出到页面和邮件里,
|
||||
* 放进 <span> 之间。虽然后面统一走 e() 转义,但源头收窄一层更稳。
|
||||
*/
|
||||
function fb_sw_icon_norm($s) {
|
||||
$s = trim(strip_tags((string)$s));
|
||||
$s = preg_replace('/[\x00-\x1F\x7F]+/u', '', $s);
|
||||
if ($s === null || $s === '') { return ''; }
|
||||
return mb_substr($s, 0, 4, 'UTF-8');
|
||||
}
|
||||
|
||||
/** 规范化软件的下载地址:只接受 http/https,其它一律丢空 */
|
||||
function fb_sw_url_norm($s) {
|
||||
$s = trim((string)$s);
|
||||
if ($s === '') { return ''; }
|
||||
if (!preg_match('~^https?://~i', $s)) { return ''; }
|
||||
return mb_substr($s, 0, 300, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* 某软件的图标字符(单字符:emoji / 汉字 / 字母)。
|
||||
* 没配就按软件名首字兜底 —— 多软件并存时,任何地方都不该出现「无图标」的空档。
|
||||
*/
|
||||
function fb_software_icon($software) {
|
||||
$ic = '';
|
||||
if (is_array($software)) {
|
||||
$ic = trim((string)(isset($software['icon']) ? $software['icon'] : ''));
|
||||
if ($ic === '') {
|
||||
// 兜底:取名称首字(中文取第一个字,英文取首字母大写)
|
||||
$nm = trim((string)(isset($software['name']) ? $software['name'] : ''));
|
||||
if ($nm !== '') {
|
||||
if (preg_match('/^[A-Za-z]/', $nm)) { $ic = strtoupper($nm[0]); }
|
||||
else { $ic = mb_substr($nm, 0, 1, 'UTF-8'); }
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ic === '') { $ic = '·'; }
|
||||
// 只允许极短内容,防止把整段 HTML 塞进图标位
|
||||
return mb_substr($ic, 0, 4, 'UTF-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* 图标 + 名字的组合标签(HTML)。
|
||||
* 前端所有「这是哪个软件」的地方都用它,保证视觉一致。
|
||||
*
|
||||
* @param array $sw 软件行
|
||||
* @param string $size 'sm' | 'md' | 'lg'
|
||||
*/
|
||||
function fb_software_badge($software, $size = 'md') {
|
||||
if (!is_array($software) || empty($software['name'])) { return ''; }
|
||||
list($c) = fb_software_colors($software);
|
||||
if ($c === '') { $c = '#0057B8'; }
|
||||
$icon = fb_software_icon($software);
|
||||
$name = (string)$software['name'];
|
||||
|
||||
$px = ['sm' => 20, 'md' => 26, 'lg' => 34];
|
||||
$fs = ['sm' => 11, 'md' => 14, 'lg' => 17];
|
||||
$box = isset($px[$size]) ? $px[$size] : 26;
|
||||
$fnt = isset($fs[$size]) ? $fs[$size] : 14;
|
||||
|
||||
return '<span class="sw-badge sw-badge-' . e($size) . '">'
|
||||
. '<span class="sw-badge-ic" aria-hidden="true" style="width:' . $box . 'px;height:' . $box
|
||||
. 'px;background:' . e($c) . ';font-size:' . $fnt . 'px">' . e($icon) . '</span>'
|
||||
. '<span class="sw-badge-nm">' . e($name) . '</span>'
|
||||
. '</span>';
|
||||
}
|
||||
|
||||
/** 某软件下的分类;不传软件则返回空数组 */
|
||||
function fb_categories($softwareId = null, $onlyEnabled = true) {
|
||||
if ($softwareId === null) { return []; }
|
||||
@@ -490,6 +572,7 @@ function fb_setting_keys() {
|
||||
'smtp.timeout', 'smtp.verify_ssl',
|
||||
'notify.enabled', 'notify.on_every_reply', 'notify.cooldown_seconds',
|
||||
'notify.admin_new_thread',
|
||||
'notify.receipt_enabled',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user