统一全部表单控件尺寸与外观;删除下载地址字段
用户:「输入框、按钮、下拉框特别丑,一点设计感都没有,高度太随意,
全面检查一下。还有那个下载链接要它干什么?」
一、表单控件(这是主要工作量)
原来样式散在 6 处(.field / .filter-row / .filters / .mail-test / .admin 各一套),
padding 有 8/9/12px 三种,select 与 input 高度不等,并排放参差不齐。
改成一套体系:
- CSS 变量统一尺度:--ctl-h 38px / --ctl-h-sm 32px / --ctl-h-lg 42px,
统一圆角 9px、统一左右内边距 12px、统一边框与阴影
- 高度用「固定 height + line-height 居中」而不是 padding 撑
- 🔴 选择器必须**宽松**(按 type 通吃,不用 .field 之类限定)。
第一版限制了容器,导致后台零散布局里的裸 select/input 只有 19/21px,
和旁边 38px 按钮并排,正是用户说的高度随意。
放开后实测:19px → 38px,全部一致
- 下拉框自绘箭头(内联 SVG),不再用各平台不一的原生箭头,右侧留 34px
- 搜索框加左侧放大镜图标,并去掉 Chrome 自带清除按钮
- 聚焦统一 brand 光晕,悬停边框加深
- 按钮也改固定 height(原来 padding 撑出 38.3px,与输入框差 0.3px)
- .btn.sm 必须显式改 height,否则 padding 被 height 吃掉、小按钮还是 38px
文件选择按钮:原生控件重做成真按钮
<label class=file-btn> 包住 input[type=file]
input 用 clip 视觉隐藏(不能用 display:none,那样点不到也聚焦不了)
按钮内显示「选择图片」+ 图标 + 选中后的文件名
二、删除「下载地址」字段
它唯一用途:状态改为「已解决」时把邮件按钮换成「下载最新版本」。
收益小、维护成本高(每个软件都要填一条 URL)。
- 后台表单项删除
- mailer 里对应的判断分支也删掉,按钮统一「查看详情」
- ⚠️ 数据库 download_url 列**保留不删**:删列不可逆,万一要恢复还得迁一次
验证(用控件总览测试页 + 真实页面实测):
10 类控件高度全部 38px(文本/数字/下拉/搜索/文件按钮/主按钮/小按钮…),
文本域 110px,同一行垂直中心完全一致(935.3)
裸 select/input 从 19/21px 修正到 38px
下拉箭头 SVG 生效、右内边距 34px;搜索框放大镜生效、左内边距 36px
真实三个页面(提交页/列表页/详情页)逐一检查:
没有 checkbox/radio/file 被误改,所有可见控件高度收敛为 38(文本域 110)
下载地址字段:admin.php 输出与源码中均无 download_url 表单项
5 个路由 200
This commit is contained in:
+19
-5
@@ -993,21 +993,29 @@
|
||||
var wrap = input.closest('.icon-up');
|
||||
if (!wrap) { return; }
|
||||
var prev = wrap.querySelector('.icon-prev');
|
||||
// 按钮上的文件名(可选,新样式才有)
|
||||
var nameEl = wrap.querySelector('[data-file-name]');
|
||||
|
||||
// 状态条:放在文件输入框下面,比页面顶部的提示显眼得多
|
||||
/* 状态条插在**整个文件按钮之后**(不是 input 之后)。
|
||||
* input 现在被包在 <label class="file-btn"> 里,如果插到 input.nextSibling
|
||||
* 会跑到 label 内部,跟按钮文字挤在一起。 */
|
||||
var btn = input.closest('.file-btn') || input;
|
||||
var tip = document.createElement('span');
|
||||
tip.className = 'icon-up-tip';
|
||||
tip.setAttribute('role', 'status');
|
||||
input.parentNode.insertBefore(tip, input.nextSibling);
|
||||
if (btn.parentNode) { btn.parentNode.insertBefore(tip, btn.nextSibling); }
|
||||
|
||||
function setTip(msg, kind) {
|
||||
tip.textContent = msg || '';
|
||||
tip.className = 'icon-up-tip' + (kind ? ' is-' + kind : '');
|
||||
}
|
||||
function setName(txt) {
|
||||
if (nameEl) { nameEl.textContent = txt || ''; }
|
||||
}
|
||||
|
||||
input.addEventListener('change', function () {
|
||||
var f = this.files && this.files[0];
|
||||
if (!f) { setTip(''); return; }
|
||||
if (!f) { setTip(''); setName(''); return; }
|
||||
|
||||
var KB = Math.round(f.size / 1024);
|
||||
var sizeTxt = KB >= 1024 ? (KB / 1024).toFixed(1) + ' MB' : KB + ' KB';
|
||||
@@ -1016,17 +1024,20 @@
|
||||
var okType = /^image\/(png|jpeg|webp)$/.test(f.type);
|
||||
if (!okType) {
|
||||
setTip('✕ 只能选 PNG / JPG / WEBP 图片,当前是「' + (f.type || '未知类型') + '」', 'err');
|
||||
setName('');
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
// ② 大小(后端限 2MB)
|
||||
if (f.size > 2 * 1024 * 1024) {
|
||||
setTip('✕ 图片 ' + sizeTxt + ',超过 2 MB 上限,请压缩后再传', 'err');
|
||||
setName('');
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
if (f.size <= 0) {
|
||||
setTip('✕ 这是个空文件', 'err');
|
||||
setName('');
|
||||
this.value = '';
|
||||
return;
|
||||
}
|
||||
@@ -1038,6 +1049,7 @@
|
||||
img.onload = function () {
|
||||
if (img.width < 32 || img.height < 32) {
|
||||
setTip('✕ 图片只有 ' + img.width + '×' + img.height + ',至少 32×32', 'err');
|
||||
setName('');
|
||||
input.value = '';
|
||||
return;
|
||||
}
|
||||
@@ -1050,16 +1062,18 @@
|
||||
prev.appendChild(el);
|
||||
}
|
||||
var warn = (img.width !== img.height) ? ' ⚠ 不是正方形,显示时会被裁切' : '';
|
||||
setTip('✓ 已选择:' + f.name + '(' + img.width + '×' + img.height + ',' + sizeTxt + ')'
|
||||
setName(f.name);
|
||||
setTip('✓ ' + img.width + '×' + img.height + ',' + sizeTxt
|
||||
+ warn + ' 保存后生效', 'ok');
|
||||
};
|
||||
img.onerror = function () {
|
||||
setTip('✕ 这张图读不出来,可能已损坏', 'err');
|
||||
setName('');
|
||||
input.value = '';
|
||||
};
|
||||
img.src = ev.target.result;
|
||||
};
|
||||
fr.onerror = function () { setTip('✕ 读取文件失败', 'err'); };
|
||||
fr.onerror = function () { setTip('✕ 读取文件失败', 'err'); setName(''); };
|
||||
fr.readAsDataURL(f);
|
||||
});
|
||||
})(inputs[i]);
|
||||
|
||||
Reference in New Issue
Block a user