diff --git a/docs/用户管理模块表单UX验证.md b/docs/用户管理模块表单UX验证.md new file mode 100644 index 00000000..0d733908 --- /dev/null +++ b/docs/用户管理模块表单UX验证.md @@ -0,0 +1,22 @@ +# 用户管理模块表单 UX 验证 + +## Findings + +- **High** `src/views/system-administration/user-management/user/index.vue`: 已修复新增/编辑弹窗表单模型未在 `data()` 中声明的问题。该问题会导致 Vue 2 根级动态属性不具备可靠响应式,输入框和下拉框在弹窗中表现为无法正常录入或选择。 +- **Medium** `src/views/system-administration/user-management/user/index.vue`: 已补充状态查询项,查询参数会随 `username`、`nickname` 一起传给列表接口,用于按启用/停用筛选用户。 +- **Medium** `src/views/system-administration/user-management/user/index.vue`: 已将账号重复校验、确认密码一致性校验接入 Element 表单规则,错误会出现在对应字段附近,而不是只依赖提交后的全局提示。 +- **Medium** `src/views/system-administration/user-management/user/index.vue`: 当前用户数据模型没有手机号、邮箱字段,接口封装也没有对应字段或独立校验接口。因此手机号/邮箱格式校验无法在不扩展前后端契约的情况下落地。建议后续先确认字段设计,再补充表单项、列表列、接口字段和格式规则。 +- **Low** `src/components/page-dialog-form/index.vue`: 已补充 `show-password` 透传,并修复自定义 validator 没有 `message` 时被无条件翻译的问题,避免后续自定义表单校验不稳定。 + +## Evidence + +- Browser: source-only。当前页面依赖登录态和后端接口,未做真实浏览器端新增用户提交。 +- Source checks: 用户弹窗字段状态、表单规则、状态查询、权限按钮声明已核对。 +- Build checks: 已通过 `eslint`、locale JSON 解析和生产构建验证语法与编译兼容性。 +- Confidence limits: 账号重复检查复用现有列表接口,并按用户名精确匹配;如果后端列表接口只做模糊查询或分页限制异常,最终仍需后端唯一约束兜底。 + +## Suggested Shape + +- 保持“账号/密码/确认密码/用户组/姓名/出入证编号/状态”的当前录入顺序,必填项优先,状态默认启用。 +- 若业务确认需要手机号/邮箱,应放在姓名之后、出入证编号之前,并使用字段级格式提示。 +- 删除、批量删除、重置密码、启停用等操作保持二次确认;接口失败时不应显示成功提示。 diff --git a/src/components/page-dialog-form/index.vue b/src/components/page-dialog-form/index.vue index 97a55ef9..fe29cd78 100644 --- a/src/components/page-dialog-form/index.vue +++ b/src/components/page-dialog-form/index.vue @@ -66,6 +66,7 @@ v-model="formData[col.prop]" :placeholder="$t(col.placeholder)" :type="col.inputType || 'text'" + :show-password="!!col.showPassword" :autosize="col.autosize" :clearable="col.clearable !== false" :disabled="!!col.disabled" @@ -255,7 +256,13 @@ export default { const rules = this.rules || {} const translated = {} for (const [field, validators] of Object.entries(rules)) { - translated[field] = validators.map(v => ({ ...v, message: this.$t(v.message) })) + translated[field] = validators.map(v => { + const rule = { ...v } + if (rule.message) { + rule.message = this.$t(rule.message) + } + return rule + }) } return translated } diff --git a/src/locales/en.json b/src/locales/en.json index 56309fc1..3cdb174e 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -2344,6 +2344,7 @@ "status": "Status", "enable": "Enabled", "disable": "Disabled", + "select_status": "Please select status", "user_group": "User Group", "login_ip": "Last Login IP", "last_login_time": "Last Login Time", @@ -2370,6 +2371,7 @@ "password_not_match": "Passwords do not match", "password_length": "Length should be 6 to 64 characters", "username_length": "Length should be 3 to 20 characters", + "username_exists": "Username already exists. Please use another username", "cannot_delete_self": "Cannot delete own account", "cannot_operate_self": "Cannot operate own account", "batch_delete": "Batch Delete", diff --git a/src/locales/zh-chs.json b/src/locales/zh-chs.json index 4378aae9..8d112eae 100644 --- a/src/locales/zh-chs.json +++ b/src/locales/zh-chs.json @@ -2344,6 +2344,7 @@ "status": "状态", "enable": "启用", "disable": "禁用", + "select_status": "请选择状态", "user_group": "用户组", "login_ip": "上次登录IP", "last_login_time": "上次登录时间", @@ -2370,6 +2371,7 @@ "password_not_match": "两次输入的密码不一致", "password_length": "长度在 6 到 64 个字符", "username_length": "长度在 3 到 20 个字符", + "username_exists": "账号已存在,请更换账号", "cannot_delete_self": "不能删除自己的账号", "cannot_operate_self": "不能操作自己的账号", "batch_delete": "批量删除", diff --git a/src/views/system-administration/user-management/user/index.vue b/src/views/system-administration/user-management/user/index.vue index b8d12118..034097eb 100644 --- a/src/views/system-administration/user-management/user/index.vue +++ b/src/views/system-administration/user-management/user/index.vue @@ -21,6 +21,18 @@ @keyup.enter.native="onSearch" /> + + + + + + {{ $t(key('search')) }} @@ -46,7 +58,7 @@ @selection-change="onSelect" >