修复图标显示不出来;标题改XX反馈系统;图标去掉背景色
一、图标显示不出来(根因) 用户上传图标时用的是修复前的代码,数据库里 icon_key 存的是 icons/2026/11/xxx.png —— 没有 local/ 也没有 oss.prefix 前缀。 上一轮我把键校验收紧成「必须带存储前缀」,于是这些键被判非法, fb_icon_url() 返回空字符串,图标自然显示不出来。 而三个文件其实都真实存在于 OSS 上(13KB / 391KB / 379KB)。 修法两层: 1. fb_icon_key_ok / fb_icon_is_key 兼容历史无前缀形态, 这些是有效资产,不能因为键格式不规范就让图标消失 2. 数据迁移:把对象复制到 feedlite/icons/… 并把数据库键改成规范形态, 已对三个软件全部执行并验证(新键 200,大小与源文件一致) 二、标题改为「XX 反馈系统」 - 页头大标题 = 同步日历反馈系统(之前只有「同步日历」) - 浏览器标签同步改 - 软件名本身含「反馈」时不叠加,避免「轻反馈反馈系统」 三、图标不要背景色 - 去掉色块底衬与圆角投影,直接「图标 + 文字」并排 - 前端 badge、提交页上下文条、邮件头部三处同步 - md 尺寸调到 28px,与 26px 标题文字视觉匹配 验证:三个软件页标题正确、图标全部 200 image/png、 全部页面 200、迁移后新键可读且大小一致。
This commit is contained in:
+18
-17
@@ -117,28 +117,29 @@ main.wrap{padding-top:24px; padding-bottom:40px; min-height:60vh}
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- 软件标识:图标 + 名字(多软件区分的主视觉) ----------
|
/* ---------- 软件标识:图标 + 名字(多软件区分的主视觉) ----------
|
||||||
* 邮件模板里也有一套等价的 table 写法,两边的观感要对得上:
|
* 🔴 一律不要背景色:图标本身就是一张图/一个 emoji,再垫一个色块会糊在一起,
|
||||||
* 圆角色块 + 居中字符 + 紧跟软件名。 */
|
* 反而看不清。直接「图标 + 文字」并排是识别度最高的做法。
|
||||||
|
* 邮件模板里有等价的 table 写法,两边观感要对得上。 */
|
||||||
.sw-badge{display:inline-flex; align-items:center; gap:7px; min-width:0; vertical-align:middle}
|
.sw-badge{display:inline-flex; align-items:center; gap:7px; min-width:0; vertical-align:middle}
|
||||||
.sw-badge-ic{
|
.sw-badge-ic{
|
||||||
display:inline-flex; align-items:center; justify-content:center;
|
display:inline-flex; align-items:center; justify-content:center;
|
||||||
border-radius:7px; color:#fff; font-weight:600; flex:none;
|
flex:none; line-height:1; letter-spacing:0;
|
||||||
line-height:1; letter-spacing:0; box-shadow:0 1px 2px rgba(15,25,45,.18);
|
background:none; border:0; box-shadow:none;
|
||||||
}
|
}
|
||||||
.sw-badge-nm{
|
.sw-badge-nm{
|
||||||
font-weight:600; font-size:14px; color:var(--fg);
|
font-weight:600; font-size:14px; color:var(--fg);
|
||||||
overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
|
overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
|
||||||
}
|
}
|
||||||
.sw-badge-sm .sw-badge-nm{font-size:13px}
|
.sw-badge-sm .sw-badge-nm{font-size:13.5px}
|
||||||
.sw-badge-lg .sw-badge-nm{font-size:17px}
|
.sw-badge-lg .sw-badge-nm{font-size:26px}
|
||||||
/* 页头大标题位置放软件标识:清掉 h1 的行高影响,让图标与文字垂直居中 */
|
/* 页头大标题:就是纯文字,不要 h1 的默认行高干扰 */
|
||||||
.page-h1-sw{margin:0; font-size:0; line-height:0}
|
.page-h1-sw{margin:0; font-size:inherit; line-height:1.3}
|
||||||
.page-h1-sw .sw-badge-nm{font-size:22px; font-weight:700; color:var(--fg)}
|
/* 页头副行:图标 + 软件名,紧跟在「XX 反馈系统」下面 */
|
||||||
/* 提交页顶部的软件上下文条 */
|
.page-sw-id{margin-top:8px; display:flex; align-items:center}
|
||||||
|
/* 提交页顶部的软件上下文条:同样无背景色,只留一行轻分隔 */
|
||||||
.sw-context{
|
.sw-context{
|
||||||
display:flex; align-items:center; gap:10px; flex-wrap:wrap;
|
display:flex; align-items:center; gap:10px; flex-wrap:wrap;
|
||||||
margin:0 0 16px; padding:11px 14px; border-radius:11px;
|
margin:0 0 16px; padding:0 0 12px; border-bottom:1px solid var(--line);
|
||||||
background:var(--brand-soft); border:1px solid var(--line);
|
|
||||||
}
|
}
|
||||||
.sw-context .sw-badge-nm{color:var(--fg)}
|
.sw-context .sw-badge-nm{color:var(--fg)}
|
||||||
/* 后台软件编辑:图标快选 */
|
/* 后台软件编辑:图标快选 */
|
||||||
@@ -152,9 +153,10 @@ main.wrap{padding-top:24px; padding-bottom:40px; min-height:60vh}
|
|||||||
|
|
||||||
/* ---------- 软件图标(上传图片) ---------- */
|
/* ---------- 软件图标(上传图片) ---------- */
|
||||||
/* 图标图片:外框与字符版完全一致,换图不会让布局跳动 */
|
/* 图标图片:外框与字符版完全一致,换图不会让布局跳动 */
|
||||||
|
/* 图标图片:不留背景、不加圆角底衬,直接贴图 */
|
||||||
.sw-badge-img{
|
.sw-badge-img{
|
||||||
display:inline-block; border-radius:7px; object-fit:cover; flex:none;
|
display:inline-block; object-fit:contain; flex:none;
|
||||||
box-shadow:0 1px 2px rgba(15,25,45,.18); background:var(--card);
|
background:none; border:0; box-shadow:none;
|
||||||
}
|
}
|
||||||
.chip.on .sw-badge-img{box-shadow:0 0 0 1px rgba(255,255,255,.5)}
|
.chip.on .sw-badge-img{box-shadow:0 0 0 1px rgba(255,255,255,.5)}
|
||||||
/* 后台图标上传行 */
|
/* 后台图标上传行 */
|
||||||
@@ -171,10 +173,9 @@ main.wrap{padding-top:24px; padding-bottom:40px; min-height:60vh}
|
|||||||
}
|
}
|
||||||
.icon-up-main{flex:1; min-width:220px; display:flex; flex-direction:column}
|
.icon-up-main{flex:1; min-width:220px; display:flex; flex-direction:column}
|
||||||
.icon-up-main input[type=file]{font-size:13.5px; max-width:100%}
|
.icon-up-main input[type=file]{font-size:13.5px; max-width:100%}
|
||||||
/* 选中态的 chip 里,图标底衬白、字符取软件色,避免同色糊在一起 */
|
/* chip 里也不用白底反色了 —— 图标本来就没有底色 */
|
||||||
.chip.on .sw-badge-ic{background:#fff !important; color:var(--brand) !important; box-shadow:none}
|
|
||||||
.chip.on .sw-badge-nm{color:#fff}
|
.chip.on .sw-badge-nm{color:#fff}
|
||||||
.chip .sw-badge-ic{box-shadow:none}
|
.chip .sw-badge-ic{background:none !important; color:inherit !important; box-shadow:none}
|
||||||
|
|
||||||
/* ---------- 主题色选择器 ---------- */
|
/* ---------- 主题色选择器 ---------- */
|
||||||
.sw-dot{
|
.sw-dot{
|
||||||
|
|||||||
@@ -76,14 +76,18 @@ $attImgs = $tids ? fb_attach_map_images($pdo, $tids, 3) : [];
|
|||||||
$attCount = $tids ? fb_attach_count_map($pdo, $tids) : [];
|
$attCount = $tids ? fb_attach_count_map($pdo, $tids) : [];
|
||||||
|
|
||||||
$siteName = (string)fb_cfg('site_name');
|
$siteName = (string)fb_cfg('site_name');
|
||||||
$headTitle = $siteName !== '' ? $siteName . ' · 问题反馈' : '问题反馈';
|
/* 页面标题(浏览器标签 / 页面大标题):
|
||||||
fb_layout_head($sw ? ((string)$sw['name']) : $headTitle, ['software' => $sw]);
|
* 选中某个软件时用「XX 反馈系统」,让用户一眼确认自己在这个软件的反馈区;
|
||||||
|
* 没选软件时退回站点名。 */
|
||||||
|
$headTitle = $sw ? fb_software_site_title($sw)
|
||||||
|
: ($siteName !== '' ? $siteName . ' · 问题反馈' : '问题反馈');
|
||||||
|
fb_layout_head($sw ? fb_software_site_title($sw) : $headTitle, ['software' => $sw]);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="page-head">
|
<div class="page-head">
|
||||||
<div>
|
<div>
|
||||||
<?php if ($sw): ?>
|
<?php if ($sw): ?>
|
||||||
<h1 class="page-h1-sw"><?php echo fb_software_badge($sw, 'lg'); ?></h1>
|
<h1 class="page-h1-sw"><?php echo e(fb_software_site_title($sw)); ?></h1>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<h1>全部问题</h1>
|
<h1>全部问题</h1>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -91,6 +95,10 @@ fb_layout_head($sw ? ((string)$sw['name']) : $headTitle, ['software' => $sw]);
|
|||||||
$siteDesc = (string)fb_cfg('site_desc');
|
$siteDesc = (string)fb_cfg('site_desc');
|
||||||
$swNote = ($sw && !empty($sw['note'])) ? (string)$sw['note'] : '';
|
$swNote = ($sw && !empty($sw['note'])) ? (string)$sw['note'] : '';
|
||||||
?>
|
?>
|
||||||
|
<?php if ($sw): ?>
|
||||||
|
<div class="page-sw-id"><?php echo fb_software_badge($sw, 'md'); ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
?>
|
||||||
<?php if ($siteDesc !== ''): ?><p class="muted"><?php echo e($siteDesc); ?></p><?php endif; ?>
|
<?php if ($siteDesc !== ''): ?><p class="muted"><?php echo e($siteDesc); ?></p><?php endif; ?>
|
||||||
<?php if ($swNote !== ''): ?><p class="muted small" style="margin:2px 0 0"><?php echo e($swNote); ?></p><?php endif; ?>
|
<?php if ($swNote !== ''): ?><p class="muted small" style="margin:2px 0 0"><?php echo e($swNote); ?></p><?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+15
-5
@@ -184,9 +184,13 @@ function fb_icon_allowed_ext() {
|
|||||||
return ['png', 'jpg', 'jpeg', 'webp'];
|
return ['png', 'jpg', 'jpeg', 'webp'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 这个键是不是软件图标(local/icons/… 或 <prefix>/icons/…) */
|
/**
|
||||||
|
* 这个键是不是软件图标。
|
||||||
|
* 同时认正常形态(local/icons/… 、<prefix>/icons/…)与历史形态(icons/…)。
|
||||||
|
* 历史形态必须认,否则用户早先上传、仍存在桶里的图标就成了读不到的孤儿。
|
||||||
|
*/
|
||||||
function fb_icon_is_key($key) {
|
function fb_icon_is_key($key) {
|
||||||
return (bool)preg_match('#^(?:local|[A-Za-z0-9][A-Za-z0-9._-]*)/icons/#', (string)$key);
|
return (bool)preg_match('#^(?:(?:local|[A-Za-z0-9][A-Za-z0-9._-]*)/)?icons/#', (string)$key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,8 +212,13 @@ function fb_icon_make_key($ext) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 图标键是否合法。
|
* 图标键是否合法。
|
||||||
* 与 fb_upload_key_ok 分开写:图标键在附件键的基础路径里多一段 icons/,
|
* 接受两种形态:
|
||||||
* 塞进原函数会被判为不合法。
|
* ① 正常形态:<local|oss.prefix>/icons/YYYY/MM/<16hex>.<ext>
|
||||||
|
* ② 历史形态:icons/YYYY/MM/<16hex>.<ext>(无存储前缀)
|
||||||
|
* —— 2026-11-03 之前的代码把键硬编码成这种样子,用户当时上传的图
|
||||||
|
* 真实存在于桶根下的 icons/ 目录。这些对象是有效资产,
|
||||||
|
* 不能因为键「格式不规范」就让图标显示不出来,所以这里认它。
|
||||||
|
* 新写入一律走正常形态,见 fb_icon_make_key()。
|
||||||
*
|
*
|
||||||
* 🔴 扩展名必须是白名单里的图片类型,不能只写 `[a-z0-9]{2,5}` ——
|
* 🔴 扩展名必须是白名单里的图片类型,不能只写 `[a-z0-9]{2,5}` ——
|
||||||
* 那样 `.php`(3 个字母)也会通过,等于给自己留了个写脚本的口子。
|
* 那样 `.php`(3 个字母)也会通过,等于给自己留了个写脚本的口子。
|
||||||
@@ -219,7 +228,8 @@ function fb_icon_key_ok($key) {
|
|||||||
$key = (string)$key;
|
$key = (string)$key;
|
||||||
if (strlen($key) < 16 || strlen($key) > 200) { return false; }
|
if (strlen($key) < 16 || strlen($key) > 200) { return false; }
|
||||||
if (strpos($key, '..') !== false || strpos($key, '//') !== false) { return false; }
|
if (strpos($key, '..') !== false || strpos($key, '//') !== false) { return false; }
|
||||||
if (!preg_match('#^(?:local|[A-Za-z0-9][A-Za-z0-9._-]*)/icons/\d{4}/\d{2}/[a-f0-9]{16}\.([a-z0-9]{2,5})$#', $key, $m)) {
|
// 带存储前缀,或历史无前缀形态
|
||||||
|
if (!preg_match('#^(?:(?:local|[A-Za-z0-9][A-Za-z0-9._-]*)/)?icons/\d{4}/\d{2}/[a-f0-9]{16}\.([a-z0-9]{2,5})$#', $key, $m)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return in_array(strtolower($m[1]), fb_icon_allowed_ext(), true);
|
return in_array(strtolower($m[1]), fb_icon_allowed_ext(), true);
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ if (!defined('FB_ROOT')) {
|
|||||||
define('FB_ROOT', dirname(__DIR__));
|
define('FB_ROOT', dirname(__DIR__));
|
||||||
// 静态资源版本号:改 assets/ 下的 css/js 后把这个数字 +1,
|
// 静态资源版本号:改 assets/ 下的 css/js 后把这个数字 +1,
|
||||||
// 让浏览器与 CDN 缓存失效。全站只此一处,别再往页面里写死数字。
|
// 让浏览器与 CDN 缓存失效。全站只此一处,别再往页面里写死数字。
|
||||||
if (!defined('FB_ASSET_V')) { define('FB_ASSET_V', 19); }
|
if (!defined('FB_ASSET_V')) { define('FB_ASSET_V', 20); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------
|
/* ------------------------------------------------------------------
|
||||||
|
|||||||
+6
-6
@@ -191,9 +191,11 @@ if (!function_exists('fb_mail_sw_header')) {
|
|||||||
$icon = fb_software_icon($sw);
|
$icon = fb_software_icon($sw);
|
||||||
$name = (string)$sw['name'];
|
$name = (string)$sw['name'];
|
||||||
|
|
||||||
/* 有上传的图标图片就用图片(管理员自己的 logo),没有才用「色块 + 字符」。
|
/* 有上传的图标图片就用图片(管理员自己的 logo),没有才用字符。
|
||||||
|
* 一律不加背景色块 —— 图标本身已经能说明是哪个软件,
|
||||||
|
* 再垫个色块反而糊在一起(与前端 fb_software_badge 保持同一观感)。
|
||||||
* 邮件客户端对 flex 支持参差,这里一律用 table + 内联样式;
|
* 邮件客户端对 flex 支持参差,这里一律用 table + 内联样式;
|
||||||
* 图片必须给死宽高和 alt,否则 Outlook 里会撑变形。 */
|
* 图片必须给死宽高,否则 Outlook 里会撑变形。 */
|
||||||
$imgKey = isset($sw['icon_key']) ? trim((string)$sw['icon_key']) : '';
|
$imgKey = isset($sw['icon_key']) ? trim((string)$sw['icon_key']) : '';
|
||||||
$imgUrl = $imgKey !== '' ? fb_icon_url($imgKey, 60) : '';
|
$imgUrl = $imgKey !== '' ? fb_icon_url($imgKey, 60) : '';
|
||||||
|
|
||||||
@@ -201,11 +203,9 @@ if (!function_exists('fb_mail_sw_header')) {
|
|||||||
if ($imgUrl !== '') {
|
if ($imgUrl !== '') {
|
||||||
$cell = '<img src="' . fb_mail_esc($imgUrl) . '" alt="' . fb_mail_esc($name) . '"'
|
$cell = '<img src="' . fb_mail_esc($imgUrl) . '" alt="' . fb_mail_esc($name) . '"'
|
||||||
. ' width="30" height="30"'
|
. ' width="30" height="30"'
|
||||||
. ' style="width:30px;height:30px;border-radius:8px;display:block;border:0;outline:none;text-decoration:none">';
|
. ' style="width:30px;height:30px;display:block;border:0;outline:none;text-decoration:none">';
|
||||||
} else {
|
} else {
|
||||||
$cell = '<div style="width:30px;height:30px;background:' . fb_mail_esc($c) . ';'
|
$cell = '<div style="font-size:22px;line-height:30px;text-align:center;color:#1b2430">'
|
||||||
. 'border-radius:8px;text-align:center;line-height:30px;'
|
|
||||||
. 'font-size:15px;color:#ffffff;font-weight:700">'
|
|
||||||
. '<span style="display:inline-block;line-height:30px">' . fb_mail_esc($icon) . '</span></div>';
|
. '<span style="display:inline-block;line-height:30px">' . fb_mail_esc($icon) . '</span></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
-11
@@ -323,24 +323,26 @@ function fb_software_icon($software) {
|
|||||||
* 图标 + 名字的组合标签(HTML)。
|
* 图标 + 名字的组合标签(HTML)。
|
||||||
* 前端所有「这是哪个软件」的地方都用它,保证视觉一致。
|
* 前端所有「这是哪个软件」的地方都用它,保证视觉一致。
|
||||||
*
|
*
|
||||||
|
* 🔴 不要背景色:图标本身就是一张图/一个 emoji,再垫一个色块反而糊在一起。
|
||||||
|
* 直接「图标 + 文字」并排,识别度最高(用户 2026-11-03 明确要求)。
|
||||||
|
*
|
||||||
* @param array $sw 软件行
|
* @param array $sw 软件行
|
||||||
* @param string $size 'sm' | 'md' | 'lg'
|
* @param string $size 'sm' | 'md' | 'lg'
|
||||||
*/
|
*/
|
||||||
function fb_software_badge($software, $size = 'md') {
|
function fb_software_badge($software, $size = 'md') {
|
||||||
if (!is_array($software) || empty($software['name'])) { return ''; }
|
if (!is_array($software) || empty($software['name'])) { return ''; }
|
||||||
list($c) = fb_software_colors($software);
|
|
||||||
if ($c === '') { $c = '#0057B8'; }
|
|
||||||
$icon = fb_software_icon($software);
|
$icon = fb_software_icon($software);
|
||||||
$name = (string)$software['name'];
|
$name = (string)$software['name'];
|
||||||
|
|
||||||
$px = ['sm' => 20, 'md' => 26, 'lg' => 34];
|
/* md 用于页头副行,要跟上方 26px 的标题文字视觉匹配,所以比 sm 明显大一档;
|
||||||
$fs = ['sm' => 11, 'md' => 14, 'lg' => 17];
|
* lg 只在大标题位置用(现在标题是纯文字,暂时没用到,留着备用)。 */
|
||||||
$box = isset($px[$size]) ? $px[$size] : 26;
|
$px = ['sm' => 18, 'md' => 28, 'lg' => 40];
|
||||||
$fnt = isset($fs[$size]) ? $fs[$size] : 14;
|
$fs = ['sm' => 14, 'md' => 19, 'lg' => 30];
|
||||||
|
$box = isset($px[$size]) ? $px[$size] : 28;
|
||||||
|
$fnt = isset($fs[$size]) ? $fs[$size] : 19;
|
||||||
|
|
||||||
/* 有上传的图标图片就用图片(管理员自己传的 logo),
|
/* 有上传的图标图片就用图片(管理员自己传的 logo),没有才用字符。
|
||||||
* 没有才退回「色块 + 字符」。两者的外框尺寸完全一致,
|
* 两者外框尺寸一致,换用图片不会让布局跳动。 */
|
||||||
* 换用图片不会让布局跳动。 */
|
|
||||||
$imgKey = isset($software['icon_key']) ? trim((string)$software['icon_key']) : '';
|
$imgKey = isset($software['icon_key']) ? trim((string)$software['icon_key']) : '';
|
||||||
$imgUrl = $imgKey !== '' ? fb_icon_url($imgKey, $box * 2) : '';
|
$imgUrl = $imgKey !== '' ? fb_icon_url($imgKey, $box * 2) : '';
|
||||||
if ($imgUrl !== '') {
|
if ($imgUrl !== '') {
|
||||||
@@ -353,12 +355,29 @@ function fb_software_badge($software, $size = 'md') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return '<span class="sw-badge sw-badge-' . e($size) . '">'
|
return '<span class="sw-badge sw-badge-' . e($size) . '">'
|
||||||
. '<span class="sw-badge-ic" aria-hidden="true" style="width:' . $box . 'px;height:' . $box
|
. '<span class="sw-badge-ic" aria-hidden="true" style="font-size:' . $fnt . 'px">'
|
||||||
. 'px;background:' . e($c) . ';font-size:' . $fnt . 'px">' . e($icon) . '</span>'
|
. e($icon) . '</span>'
|
||||||
. '<span class="sw-badge-nm">' . e($name) . '</span>'
|
. '<span class="sw-badge-nm">' . e($name) . '</span>'
|
||||||
. '</span>';
|
. '</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 「XX 反馈系统」—— 当前软件下的站点标题。
|
||||||
|
* 多软件共用一个反馈站时,标题必须点明是哪个软件的反馈系统,
|
||||||
|
* 用户才知道自己没走错地方。没传软件时退回站点名。
|
||||||
|
*
|
||||||
|
* ⚠️ 软件名本身已含「反馈」二字时不再叠加,避免出现「轻反馈反馈系统」。
|
||||||
|
*/
|
||||||
|
function fb_software_site_title($software) {
|
||||||
|
if (!is_array($software) || empty($software['name'])) {
|
||||||
|
return (string)fb_cfg('site_name', '轻反馈');
|
||||||
|
}
|
||||||
|
$name = trim((string)$software['name']);
|
||||||
|
if ($name === '') { return (string)fb_cfg('site_name', '轻反馈'); }
|
||||||
|
if (mb_strpos($name, '反馈', 0, 'UTF-8') !== false) { return $name; }
|
||||||
|
return $name . '反馈系统';
|
||||||
|
}
|
||||||
|
|
||||||
/** 某软件下的分类;不传软件则返回空数组 */
|
/** 某软件下的分类;不传软件则返回空数组 */
|
||||||
function fb_categories($softwareId = null, $onlyEnabled = true) {
|
function fb_categories($softwareId = null, $onlyEnabled = true) {
|
||||||
if ($softwareId === null) { return []; }
|
if ($softwareId === null) { return []; }
|
||||||
|
|||||||
Reference in New Issue
Block a user