NewLife/cube-front

FLAG:user页面修改密码/清空密码功能暂时禁用,搜 edit1111
Yann authored at 2025-08-01 23:26:56
4c856bb
Tree
1 Parent(s) 668c132
Summary: 4 changed files with 169 additions and 21 deletions.
Modified +156 -18
Modified +1 -0
Modified +1 -0
Modified +11 -3
Modified +156 -18
diff --git a/apps/cube-admin/src/pages/admin/user/index.vue b/apps/cube-admin/src/pages/admin/user/index.vue
index 6b33a0b..827e63b 100644
--- a/apps/cube-admin/src/pages/admin/user/index.vue
+++ b/apps/cube-admin/src/pages/admin/user/index.vue
@@ -105,8 +105,43 @@
         </el-form-item>
       </el-form>
       <template #footer>
-        <el-button @click="dialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="submitForm">确定</el-button>
+        <div style="display: flex; justify-content: space-between; align-items: center;">
+          <!-- 左侧:密码操作按钮,仅在编辑模式下显示 -->
+          <div v-if="formType === 'edit1111'">
+            <el-button type="warning" size="small" @click="handleChangePasswordInEdit">修改密码</el-button>
+            <el-button type="info" size="small" @click="handleClearPasswordInEdit">清空密码</el-button>
+          </div>
+          <div v-else></div>
+
+          <!-- 右侧:主要操作按钮 -->
+          <div>
+            <el-button @click="dialogVisible = false">取消</el-button>
+            <el-button type="primary" @click="submitForm">确定</el-button>
+          </div>
+        </div>
+      </template>
+    </el-dialog>
+
+    <!-- 修改密码对话框 -->
+    <el-dialog v-model="changePasswordDialogVisible" title="修改密码" width="400px">
+      <el-form ref="changePasswordFormRef" :model="changePasswordForm" :rules="changePasswordFormRules"
+        label-width="100px">
+        <el-form-item label="用户名">
+          <el-input v-model="changePasswordForm.name" :disabled="true" />
+        </el-form-item>
+        <el-form-item label="旧密码" prop="oldPassword">
+          <el-input v-model="changePasswordForm.oldPassword" type="password" placeholder="请输入旧密码" show-password />
+        </el-form-item>
+        <el-form-item label="新密码" prop="newPassword">
+          <el-input v-model="changePasswordForm.newPassword" type="password" placeholder="请输入新密码" show-password />
+        </el-form-item>
+        <el-form-item label="确认密码" prop="newPassword2">
+          <el-input v-model="changePasswordForm.newPassword2" type="password" placeholder="请再次输入新密码" show-password />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="changePasswordDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitChangePassword">确定</el-button>
       </template>
     </el-dialog>
   </div>
@@ -115,6 +150,7 @@
 <script setup lang="ts">
 import { ref, reactive, onMounted } from 'vue';
 import type { FormInstance, FormRules } from 'element-plus';
+import { ElMessage, ElMessageBox } from 'element-plus';
 import { request } from '@core/utils/request';
 import { apiDataToList, apiDataToSingle, handleDeleteOperation, handleFormSubmit } from '@core/utils/api-helpers';
 import CubeListToolbarSearch from '@core/components/CubeListToolbarSearch.vue';
@@ -152,6 +188,18 @@ interface User extends BaseEntity, EnableStatus {
   departmentName?: string;
 }
 
+// 定义修改密码表单接口
+interface ChangePasswordForm {
+  /** 用户名 */
+  name: string;
+  /** 旧密码 */
+  oldPassword: string;
+  /** 新密码 */
+  newPassword: string;
+  /** 确认密码 */
+  newPassword2: string;
+}
+
 // 定义初始用户表单数据
 const initialUserForm: User = {
   id: 0,
@@ -183,6 +231,16 @@ const formType = ref<'add' | 'edit'>('add');
 const userFormRef = ref<FormInstance | null>(null);
 const userForm = reactive<User>({ ...initialUserForm });
 
+// 修改密码相关
+const changePasswordDialogVisible = ref(false);
+const changePasswordFormRef = ref<FormInstance | null>(null);
+const changePasswordForm = reactive<ChangePasswordForm>({
+  name: '',
+  oldPassword: '',
+  newPassword: '',
+  newPassword2: '',
+});
+
 // 角色选项数据
 const roleOptions = ref<SelectOption[]>([]);
 const roleOptionsLoaded = ref(false); // 标记角色数据是否已加载
@@ -228,7 +286,7 @@ const userFormRules = reactive<FormRules>({
   ],
   password: [
     { required: formType.value === 'add', message: '请输入密码', trigger: 'blur' },
-    { min: 6, max: 200, message: '长度在 6 到 200 个字符', trigger: 'blur' }
+    { min: 8, max: 200, message: '长度在 8 到 200 个字符', trigger: 'blur' }
   ],
   sex: [
     { required: true, message: '请选择性别', trigger: 'change' }
@@ -264,6 +322,30 @@ const userFormRules = reactive<FormRules>({
   ]
 });
 
+// 修改密码表单验证规则
+const changePasswordFormRules = reactive<FormRules>({
+  oldPassword: [
+    { required: true, message: '请输入旧密码', trigger: 'blur' }
+  ],
+  newPassword: [
+    { required: true, message: '请输入新密码', trigger: 'blur' },
+    { min: 8, max: 200, message: '长度在 8 到 200 个字符', trigger: 'blur' }
+  ],
+  newPassword2: [
+    { required: true, message: '请再次输入新密码', trigger: 'blur' },
+    {
+      validator: (_rule: unknown, value: string, callback: (error?: Error) => void) => {
+        if (value !== changePasswordForm.newPassword) {
+          callback(new Error('两次输入的密码不一致'));
+        } else {
+          callback();
+        }
+      },
+      trigger: 'blur'
+    }
+  ]
+});
+
 // 获取头像完整URL
 const getAvatarUrl = (avatar: string): string => {
   if (!avatar) return '';
@@ -321,20 +403,20 @@ const handleAdd = () => {
 // 编辑用户 - 演示如何使用fetchSingleData获取单个用户详情
 const handleEdit = async (row: User) => {
   formType.value = 'edit';
- // // 方式1:直接使用传入的row数据
-    // Object.assign(userForm, {
-    //   id: row.id,
-    //   name: row.name,
-    //   displayName: row.displayName,
-    //   mail: row.mail,
-    //   mobile: row.mobile,
-    //   enable: row.enable,
-    //   sex: row.sex,
-    //   avatar: row.avatar,
-    //   roleID: row.roleID,
-    //   departmentID: row.departmentID,
-    //   remark: row.remark
-    // });
+  // // 方式1:直接使用传入的row数据
+  // Object.assign(userForm, {
+  //   id: row.id,
+  //   name: row.name,
+  //   displayName: row.displayName,
+  //   mail: row.mail,
+  //   mobile: row.mobile,
+  //   enable: row.enable,
+  //   sex: row.sex,
+  //   avatar: row.avatar,
+  //   roleID: row.roleID,
+  //   departmentID: row.departmentID,
+  //   remark: row.remark
+  // });
 
   try {
     // 方式2:请求最新数据
@@ -349,6 +431,39 @@ const handleEdit = async (row: User) => {
   }
 };
 
+// 修改密码 - 在编辑弹窗中使用
+const handleChangePasswordInEdit = () => {
+  changePasswordForm.name = userForm.name;
+  changePasswordForm.oldPassword = '';
+  changePasswordForm.newPassword = '';
+  changePasswordForm.newPassword2 = '';
+  changePasswordDialogVisible.value = true;
+};
+
+// 清空密码 - 在编辑弹窗中使用
+const handleClearPasswordInEdit = () => {
+  ElMessageBox.confirm(
+    `确认清空用户 [${userForm.displayName || userForm.name}] 的密码吗?清空后该用户将无法使用密码登录。`,
+    '确认清空密码',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  ).then(async () => {
+    try {
+      await request.post('/Admin/User/ClearPassword', null, { params: { id: userForm.id } });
+      ElMessage.success('密码清空成功');
+      dialogVisible.value = false; // 关闭用户编辑对话框
+    } catch (error) {
+      console.error('清空密码失败:', error);
+      ElMessage.error('清空密码失败');
+    }
+  }).catch(() => {
+    // 用户取消操作
+  });
+};
+
 // 删除用户
 const handleDelete = (row: User) => {
   handleDeleteOperation(
@@ -377,7 +492,7 @@ const submitForm = async () => {
         remark: userForm.remark,
       };
       await request.post('/Admin/User', userData);
-    } else {
+    } else if (formType.value === 'edit') {
       await request.put('/Admin/User', userForm);
     }
   };
@@ -390,6 +505,29 @@ const submitForm = async () => {
   await handleFormSubmit(userFormRef.value, apiCall, onSuccess);
 };
 
+// 提交修改密码表单
+const submitChangePassword = async () => {
+  const apiCall = async () => {
+    await request.post('/Admin/User/ChangePassword', {
+      name: changePasswordForm.name,
+      oldPassword: changePasswordForm.oldPassword,
+      newPassword: changePasswordForm.newPassword,
+      newPassword2: changePasswordForm.newPassword2,
+    });
+  };
+
+  const onSuccess = () => {
+    changePasswordDialogVisible.value = false;// 关闭修改密码对话框
+    ElMessage.success('密码修改成功');
+    // 重置表单
+    changePasswordForm.oldPassword = '';
+    changePasswordForm.newPassword = '';
+    changePasswordForm.newPassword2 = '';
+  };
+
+  await handleFormSubmit(changePasswordFormRef.value, apiCall, onSuccess);
+};
+
 // 初始化加载数据
 onMounted(() => {
   queryUser();
Modified +1 -0
diff --git a/auto-imports.d.ts b/auto-imports.d.ts
index 6a26f7c..aa08566 100644
--- a/auto-imports.d.ts
+++ b/auto-imports.d.ts
@@ -7,6 +7,7 @@
 export {}
 declare global {
   const EffectScope: typeof import('vue')['EffectScope']
+  const ElMessage: typeof import('element-plus/es')['ElMessage']
   const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
   const computed: typeof import('vue')['computed']
   const createApp: typeof import('vue')['createApp']
Modified +1 -0
diff --git a/components.d.ts b/components.d.ts
index e5c8a5b..59e4c7c 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -28,6 +28,7 @@ declare module 'vue' {
     ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
     ElOption: typeof import('element-plus/es')['ElOption']
     ElPagination: typeof import('element-plus/es')['ElPagination']
+    ElPopover: typeof import('element-plus/es')['ElPopover']
     ElRadio: typeof import('element-plus/es')['ElRadio']
     ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
     ElRow: typeof import('element-plus/es')['ElRow']
Modified +11 -3
diff --git a/core/utils/request.ts b/core/utils/request.ts
index 2b5b742..8675625 100644
--- a/core/utils/request.ts
+++ b/core/utils/request.ts
@@ -28,7 +28,7 @@ const INDEX_ROUTE_PATH = '/';
  * @param {Object} options - 配置选项
  * @param {string} options.loginPageUrl - 可选的登录页URL
  */
-export function redirectToLogin({ loginPageUrl }: { loginPageUrl?: string; } = {}) {
+export function redirectToLogin({ loginPageUrl }: { loginPageUrl?: string } = {}) {
   removeAccessToken();
   removeAllCookie();
 
@@ -288,7 +288,7 @@ function handleResponseSuccess(response: AxiosResponse) {
         return {
           data: apiResponse.data,
           page: apiResponse.page,
-          stat: apiResponse.stat
+          stat: apiResponse.stat,
         };
       }
 
@@ -296,7 +296,15 @@ function handleResponseSuccess(response: AxiosResponse) {
       return apiResponse.data;
     } else {
       // 失败:自动显示错误提示
-      const errorMessage = apiResponse.message || '操作失败';
+      let errorMessage: string;
+      if (apiResponse.message) {
+        errorMessage = apiResponse.message;
+      } else if (apiResponse.data && typeof apiResponse.data === 'string') {
+        errorMessage = apiResponse.data;
+      } else {
+        errorMessage = '操作失败';
+      }
+
       notification.error({ message: errorMessage });
 
       // 抛出错误,让业务代码能够在catch中处理