From 5f11219226785cd4d07b1071004de8505ed9a0ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=AD=90=E9=BB=98?= <925456043@qq.com> Date: Thu, 30 Jul 2026 14:17:44 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E5=B9=B6=E5=A4=8D=E5=88=B6=E9=87=8D=E7=BD=AE=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E5=AF=86=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 账号重置接口返回本次使用的默认强密码 - 管理端新增紧凑结果弹窗与复制反馈 - 补充服务测试和中英文文案 --- .../system/SysAccountController.java | 12 +- .../system/service/SysAccountService.java | 9 +- .../service/impl/SysAccountServiceImpl.java | 13 +- .../impl/SysAccountServiceImplTest.java | 59 ++++++++ .../src/locales/langs/en-US/sysAccount.json | 5 + .../src/locales/langs/zh-CN/sysAccount.json | 5 + .../system/sysAccount/SysAccountList.vue | 16 +- .../SysAccountPasswordResultModal.vue | 142 ++++++++++++++++++ 8 files changed, 253 insertions(+), 8 deletions(-) create mode 100644 easyflow-ui-admin/app/src/views/system/sysAccount/SysAccountPasswordResultModal.vue diff --git a/easyflow-api/easyflow-api-admin/src/main/java/tech/easyflow/admin/controller/system/SysAccountController.java b/easyflow-api/easyflow-api-admin/src/main/java/tech/easyflow/admin/controller/system/SysAccountController.java index 5ad45374..50b8537c 100644 --- a/easyflow-api/easyflow-api-admin/src/main/java/tech/easyflow/admin/controller/system/SysAccountController.java +++ b/easyflow-api/easyflow-api-admin/src/main/java/tech/easyflow/admin/controller/system/SysAccountController.java @@ -203,11 +203,17 @@ public class SysAccountController extends BaseCurdController resetPassword(@JsonBody(value = "id", required = true) BigInteger id) { - service.resetPassword(id, SaTokenUtil.getLoginAccount().getId()); - return Result.ok(); + public Result resetPassword(@JsonBody(value = "id", required = true) BigInteger id) { + String password = service.resetPassword(id, SaTokenUtil.getLoginAccount().getId()); + return Result.ok(password); } @PostMapping("/removeBatchWithResult") diff --git a/easyflow-modules/easyflow-module-system/src/main/java/tech/easyflow/system/service/SysAccountService.java b/easyflow-modules/easyflow-module-system/src/main/java/tech/easyflow/system/service/SysAccountService.java index 6a16c5b1..8035b6f2 100644 --- a/easyflow-modules/easyflow-module-system/src/main/java/tech/easyflow/system/service/SysAccountService.java +++ b/easyflow-modules/easyflow-module-system/src/main/java/tech/easyflow/system/service/SysAccountService.java @@ -32,7 +32,14 @@ public interface SysAccountService extends IService { SysAccount getByUsername(String userKey); - void resetPassword(BigInteger accountId, BigInteger operatorId); + /** + * 将账号密码重置为系统默认强密码。 + * + * @param accountId 账号 ID + * @param operatorId 操作人账号 ID + * @return 本次重置后使用的明文密码 + */ + String resetPassword(BigInteger accountId, BigInteger operatorId); SysAccountBatchActionResultVo removeBatchWithResult(Collection ids); diff --git a/easyflow-modules/easyflow-module-system/src/main/java/tech/easyflow/system/service/impl/SysAccountServiceImpl.java b/easyflow-modules/easyflow-module-system/src/main/java/tech/easyflow/system/service/impl/SysAccountServiceImpl.java index 48eb0433..28cf4e1b 100644 --- a/easyflow-modules/easyflow-module-system/src/main/java/tech/easyflow/system/service/impl/SysAccountServiceImpl.java +++ b/easyflow-modules/easyflow-module-system/src/main/java/tech/easyflow/system/service/impl/SysAccountServiceImpl.java @@ -231,21 +231,30 @@ public class SysAccountServiceImpl extends ServiceImpl stp = mockStatic(StpUtil.class)) { + String actualPassword = service.resetPassword(accountId, operatorId); + + assertEquals(expectedPassword, actualPassword); + ArgumentCaptor updateCaptor = ArgumentCaptor.forClass(SysAccount.class); + verify(service).updateById(updateCaptor.capture()); + SysAccount update = updateCaptor.getValue(); + assertTrue(BCrypt.checkpw(expectedPassword, update.getPassword())); + assertEquals(Boolean.TRUE, update.getPasswordResetRequired()); + assertEquals(operatorId, update.getModifiedBy()); + stp.verify(() -> StpUtil.kickout(accountId), times(1)); + } + } + + /** + * 设置测试对象的私有字段。 + * + * @param target 目标对象 + * @param fieldName 字段名 + * @param value 字段值 + * @throws Exception 字段不存在或不可访问 + */ + private void setField(Object target, String fieldName, Object value) throws Exception { + Field field = SysAccountServiceImpl.class.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(target, value); + } } diff --git a/easyflow-ui-admin/app/src/locales/langs/en-US/sysAccount.json b/easyflow-ui-admin/app/src/locales/langs/en-US/sysAccount.json index 52d6d14d..9b361a04 100644 --- a/easyflow-ui-admin/app/src/locales/langs/en-US/sysAccount.json +++ b/easyflow-ui-admin/app/src/locales/langs/en-US/sysAccount.json @@ -29,6 +29,11 @@ "resetPassword": "Reset Password", "resetPasswordConfirm": "Reset this account password to the system default strong password? The user will be required to change it on next login.", "resetPasswordSuccess": "Password has been reset to the system default strong password and must be changed on next login", + "resetPasswordResultTitle": "Password Reset Successful", + "resetPasswordResultDescription": "Copy the password and share it securely. The user must change it at the next sign-in.", + "resetPasswordResultLabel": "New Password", + "resetPasswordResultMissing": "The password was reset, but the new password was not returned. Contact an administrator.", + "copyPassword": "Copy password", "batchSelectedCount": "{count} selected", "batchToolbarHint": "Batch actions are available for selected accounts", "batchActionSelectRequired": "Please select at least one account", diff --git a/easyflow-ui-admin/app/src/locales/langs/zh-CN/sysAccount.json b/easyflow-ui-admin/app/src/locales/langs/zh-CN/sysAccount.json index 42582601..acecda0e 100644 --- a/easyflow-ui-admin/app/src/locales/langs/zh-CN/sysAccount.json +++ b/easyflow-ui-admin/app/src/locales/langs/zh-CN/sysAccount.json @@ -30,6 +30,11 @@ "resetPassword": "重置密码", "resetPasswordConfirm": "确认将该用户密码重置为系统默认强密码吗?重置后用户下次登录必须先修改密码。", "resetPasswordSuccess": "密码已重置为系统默认强密码,用户下次登录需修改密码", + "resetPasswordResultTitle": "密码重置成功", + "resetPasswordResultDescription": "请复制密码并安全地告知用户,用户下次登录时需修改密码。", + "resetPasswordResultLabel": "新密码", + "resetPasswordResultMissing": "密码已重置,但接口未返回新密码,请联系管理员", + "copyPassword": "复制密码", "batchSelectedCount": "已选择 {count} 项", "batchToolbarHint": "可对选中账号执行批量操作", "batchActionSelectRequired": "请先选择要操作的账号", diff --git a/easyflow-ui-admin/app/src/views/system/sysAccount/SysAccountList.vue b/easyflow-ui-admin/app/src/views/system/sysAccount/SysAccountList.vue index 12251e49..b2e333d4 100644 --- a/easyflow-ui-admin/app/src/views/system/sysAccount/SysAccountList.vue +++ b/easyflow-ui-admin/app/src/views/system/sysAccount/SysAccountList.vue @@ -32,6 +32,7 @@ import { useDictStore } from '#/store'; import SysAccountImportModal from './SysAccountImportModal.vue'; import SysAccountModal from './SysAccountModal.vue'; +import SysAccountPasswordResultModal from './SysAccountPasswordResultModal.vue'; onMounted(() => { initDict(); @@ -40,6 +41,7 @@ onMounted(() => { const pageDataRef = ref(); const tableRef = ref(); const importDialog = ref(); +const passwordResultDialog = ref(); const saveDialog = ref(); const selectedRows = ref([]); const batchActionLoading = ref(false); @@ -124,6 +126,7 @@ function remove(row: any) { }).catch(() => {}); } function resetPassword(row: any) { + let plainPassword = ''; ElMessageBox.confirm( $t('sysAccount.resetPasswordConfirm'), $t('message.noticeTitle'), @@ -139,7 +142,7 @@ function resetPassword(row: any) { .then((res) => { instance.confirmButtonLoading = false; if (res.errorCode === 0) { - ElMessage.success($t('sysAccount.resetPasswordSuccess')); + plainPassword = typeof res.data === 'string' ? res.data : ''; clearSelection(); done(); } @@ -152,7 +155,15 @@ function resetPassword(row: any) { } }, }, - ).catch(() => {}); + ) + .then(() => { + if (!plainPassword) { + ElMessage.error($t('sysAccount.resetPasswordResultMissing')); + return; + } + passwordResultDialog.value?.openDialog(plainPassword); + }) + .catch(() => {}); } function handleSelectionChange(rows: any[]) { selectedRows.value = rows; @@ -260,6 +271,7 @@ function isAdmin(data: any) {
+