style(user): 优化用户资料表单分栏

为用户表单增加专用响应式样式,将账号信息中的头像、登录账号和用户名称拆成三列展示,减少纵向滚动。

将密码与重复密码拆为两列,将邮箱、手机号和 QQ 联系资料拆为三列,备注仍保持独立输入区域,提升后台用户维护效率。

补充用户控制器页面测试断言,覆盖账号、密码和联系资料的新分栏类名,确保表单结构后续调整可被及时发现。
This commit is contained in:
邹景立 2026-05-21 00:16:41 +08:00
parent 7408a162b6
commit 2405afdb16
2 changed files with 80 additions and 11 deletions

View File

@ -250,6 +250,7 @@ SCRIPT),
$form->action(strval($context['actionUrl'] ?? ''))
->attrs(['id' => 'UserForm', 'data-table-id' => 'UserTable'])
->class($manageAccount ? 'system-user-form' : 'system-user-form system-user-info-form');
$form->html('<style id="SystemUserFormStyle">' . self::renderFormStyle() . '</style>');
self::buildAccountSection($form, $usernamePattern, $usernameAttrs, $manageAccount, $isEdit);
self::buildPasswordSection($form, $manageAccount, $isEdit);
@ -303,7 +304,10 @@ SCRIPT),
? ($isEdit ? '维护头像、账号标识与展示名称。登录账号创建后保持只读。' : '先创建头像、登录账号和用户名称,账号创建后即作为后台登录标识。')
: '当前页面只维护你自己的头像、展示名称与联系资料,登录账号保持只读。',
], function (FormNode $section) use ($usernamePattern, $usernameAttrs) {
$section->fields(function ($fields) use ($usernamePattern, $usernameAttrs) {
$grid = $section->div()->class('layui-row layui-col-space15 system-user-form-row system-user-cols-3');
$avatar = $grid->div()->class('layui-col-xs4 system-user-form-col system-user-account-col system-user-headimg-col');
$avatar->fields(function ($fields) {
$fields->field([
'type' => 'image',
'name' => 'headimg',
@ -314,7 +318,15 @@ SCRIPT),
'placeholder' => '请输入用户头像地址',
],
])->types('gif,png,jpg,jpeg');
});
$username = $grid->div()->class('layui-col-xs4 system-user-form-col system-user-account-col system-user-username-col');
$username->fields(function ($fields) use ($usernamePattern, $usernameAttrs) {
$fields->text('username', '登录账号', 'User Name', true, '登录账号不能少于 4 位字符,创建后不能再次修改。', $usernamePattern, $usernameAttrs);
});
$nickname = $grid->div()->class('layui-col-xs4 system-user-form-col system-user-account-col system-user-nickname-col');
$nickname->fields(function ($fields) {
$fields->text('nickname', '用户名称', 'Nick Name', true, '用于后台展示和日志区分,建议保持唯一且便于识别。', null, [
'maxlength' => 64,
'placeholder' => '请输入用户名称',
@ -324,6 +336,34 @@ SCRIPT),
});
}
private static function renderFormStyle(): string
{
return <<<'STYLE'
#UserForm .system-user-form-row {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
#UserForm .system-user-cols-2 > .system-user-form-col {
width: 50% !important;
max-width: 50%;
box-sizing: border-box;
}
#UserForm .system-user-cols-3 > .system-user-form-col {
width: 33.333333% !important;
max-width: 33.333333%;
box-sizing: border-box;
}
@media (max-width: 560px) {
#UserForm .system-user-cols-2 > .system-user-form-col,
#UserForm .system-user-cols-3 > .system-user-form-col {
width: 100% !important;
max-width: 100%;
}
}
STYLE;
}
private static function buildPasswordSection(FormNode $form, bool $manageAccount, bool $isEdit): void
{
if (!$manageAccount) {
@ -336,17 +376,24 @@ SCRIPT),
? '默认显示 6 个星号,保留星号表示不修改当前密码;输入新密码后需再次确认。'
: '可直接设置初始登录密码;如果留空,则默认使用登录账号作为初始密码。',
], function (FormNode $section) use ($isEdit) {
$section->fields(function ($fields) use ($isEdit) {
$mask = $isEdit ? password_mask() : '';
$help = $isEdit
? '保留默认星号则不修改密码,输入新密码后需再次确认。'
: '可选。留空时默认使用登录账号作为初始密码。';
$mask = $isEdit ? password_mask() : '';
$help = $isEdit
? '保留默认星号则不修改密码,输入新密码后需再次确认。'
: '可选。留空时默认使用登录账号作为初始密码。';
$grid = $section->div()->class('layui-row layui-col-space15 system-user-form-row system-user-cols-2');
$password = $grid->div()->class('layui-col-xs6 system-user-form-col system-user-password-col');
$password->fields(function ($fields) use ($isEdit, $mask, $help) {
$fields->password('password', '登录密码', 'Password', false, $help, null, [
'maxlength' => 32,
'autocomplete' => 'new-password',
'placeholder' => $isEdit ? '保留默认星号则不修改密码' : '请输入登录密码,留空则默认使用登录账号',
])->defaultValue($mask)->password('repassword', '重复密码', 'Repeat Password', false, $help, null, [
])->defaultValue($mask);
});
$repassword = $grid->div()->class('layui-col-xs6 system-user-form-col system-user-password-col');
$repassword->fields(function ($fields) use ($isEdit, $mask, $help) {
$fields->password('repassword', '重复密码', 'Repeat Password', false, $help, null, [
'maxlength' => 32,
'autocomplete' => 'new-password',
'placeholder' => $isEdit ? '保留默认星号则不修改密码' : '请再次输入登录密码',
@ -412,20 +459,37 @@ SCRIPT),
'title' => '联系资料',
'description' => '联系资料用于运维沟通和身份识别,备注可补充职责、值班说明或交接信息。',
], function (FormNode $fieldset) {
$fieldset->fields(function ($fields) {
$grid = $fieldset->div()->class('layui-row layui-col-space15 system-user-form-row system-user-cols-3');
$mail = $grid->div()->class('layui-col-xs4 system-user-form-col system-user-contact-col');
$mail->fields(function ($fields) {
$fields->text('contact_mail', '联系邮箱', 'Contact Email', false, '可选,请填写用户常用的电子邮箱。', 'email', [
'placeholder' => '请输入联系电子邮箱',
'pattern-error' => '联系邮箱格式错误!',
])->text('contact_phone', '联系手机', 'Contact Mobile', false, '可选,请填写用户常用的联系手机号。', 'phone', [
]);
});
$phone = $grid->div()->class('layui-col-xs4 system-user-form-col system-user-contact-col');
$phone->fields(function ($fields) {
$fields->text('contact_phone', '联系手机', 'Contact Mobile', false, '可选,请填写用户常用的联系手机号。', 'phone', [
'maxlength' => 11,
'placeholder' => '请输入用户联系手机',
'type' => 'tel',
'pattern-error' => '联系手机格式错误!',
])->text('contact_qq', '联系QQ', 'Contact QQ', false, '可选,请填写用户常用的联系 QQ 号。', 'qq', [
]);
});
$qq = $grid->div()->class('layui-col-xs4 system-user-form-col system-user-contact-col');
$qq->fields(function ($fields) {
$fields->text('contact_qq', '联系QQ', 'Contact QQ', false, '可选,请填写用户常用的联系 QQ 号。', 'qq', [
'maxlength' => 11,
'placeholder' => '请输入常用的联系QQ',
'pattern-error' => '联系QQ格式错误',
])->textarea('remark', '用户描述', 'User Remark', false, '可选,用于补充岗位职责、值班说明或交接备注。', [
]);
});
$fieldset->fields(function ($fields) {
$fields->textarea('remark', '用户描述', 'User Remark', false, '可选,用于补充岗位职责、值班说明或交接备注。', [
'placeholder' => '请输入用户描述',
]);
});

View File

@ -161,8 +161,11 @@ class UserControllerTest extends SqliteIntegrationTestCase
$this->assertStringContainsString('form-builder-schema', $html);
$this->assertStringContainsString('账号信息', $html);
$this->assertStringContainsString('system-user-account-col', $html);
$this->assertStringContainsString('system-user-cols-3', $html);
$this->assertStringContainsString('身份与权限', $html);
$this->assertStringContainsString('联系资料', $html);
$this->assertStringContainsString('system-user-contact-col', $html);
$this->assertStringContainsString('管理设置', $html);
$this->assertMatchesRegularExpression('/<input[^>]*name="headimg"[^>]*type="text"/', $html);
$this->assertStringContainsString('data-field="headimg"', $html);
@ -170,6 +173,8 @@ class UserControllerTest extends SqliteIntegrationTestCase
$this->assertStringContainsString('name="username"', $html);
$this->assertStringContainsString('name="nickname"', $html);
$this->assertStringContainsString('登录密码', $html);
$this->assertStringContainsString('system-user-password-col', $html);
$this->assertStringContainsString('system-user-cols-2', $html);
$this->assertStringContainsString('name="password"', $html);
$this->assertStringContainsString('name="repassword"', $html);
$this->assertStringContainsString('UserBasePluginFilter', $html);