瀏覽代碼

fix:添加用户修改密码功能

luoxiao 1 月之前
父節點
當前提交
db63125f92
共有 6 個文件被更改,包括 340 次插入1 次删除
  1. 23 0
      src/api/user/index.ts
  2. 10 0
      src/layout/components/header.vue
  3. 6 0
      src/router/index.ts
  4. 3 1
      src/store/modules/user.ts
  5. 282 0
      src/views/sets/changePassword.vue
  6. 16 0
      src/views/sets/users.vue

+ 23 - 0
src/api/user/index.ts

@@ -67,6 +67,16 @@ export function updateUser(id: number, data: UserForm) {
 }
 
 /**
+ * 获取用户详情
+ *
+ */
+export function getUserDetail(id: number) {
+  return request({
+    url: "/api/v1/syn/user/info/get/" + id,
+    method: "get",
+  });
+}
+/**
  * 获取用户分页列表
  *
  * @param queryParams
@@ -100,6 +110,19 @@ export function updateUserPassword(id: number, password: string) {
 }
 
 /**
+ * 修改用户密码
+ *
+ * @param id
+ * @param password
+ */
+export function updatePassword(data: any) {
+  return request({
+    url: "/api/v1/syn/user/info/update-password",
+    method: "post",
+    data: data,
+  });
+}
+/**
  * 删除用户
  *
  * @param ids

+ 10 - 0
src/layout/components/header.vue

@@ -59,6 +59,7 @@
           />
           <template #dropdown>
             <el-dropdown-menu style="width: 150px">
+              <el-dropdown-item command="change">修改密码</el-dropdown-item>
               <el-dropdown-item command="b">退出登录</el-dropdown-item>
             </el-dropdown-menu>
           </template>
@@ -107,6 +108,15 @@ const handleCommand = (command: string | number | object) => {
       userStore.$reset();
     });
   }
+  if (command === "change") {
+    router.push({
+      name: "changePassword",
+      query: {
+        redirect: route.fullPath,
+        id: userStore.user.userId,
+      },
+    });
+  }
 };
 </script>
 

+ 6 - 0
src/router/index.ts

@@ -45,6 +45,12 @@ export const constantRoutes: RouteRecordRaw[] = [
         meta: { hidden: true, back: true, title: "用户权限管理" },
       },
       {
+        path: "/user/changePassword",
+        component: () => import("@/views/sets/changePassword.vue"),
+        name: "changePassword",
+        meta: { hidden: true, back: true, title: "修改用户密码" },
+      },
+      {
         path: "/messageOrg",
         component: () => import("@/views/sets/messageOrg.vue"),
         name: "messageOrg",

+ 3 - 1
src/store/modules/user.ts

@@ -49,7 +49,9 @@ export const useUserStore = defineStore("user", () => {
             reject("Verification failed, please Login again.");
             return;
           }
-          user.value.username = data.userName;
+          user.value.userId = data.id;
+          user.value.username = data.username;
+
           user.value.avatar = data.avatar ?? "";
           isGetAuth.value = true;
 

+ 282 - 0
src/views/sets/changePassword.vue

@@ -0,0 +1,282 @@
+<template>
+  <div class="password-change-container">
+    <div class="password-change-card">
+      <!-- 左侧头像和姓名 -->
+      <div class="user-info">
+        <div class="avatar-container">
+          <img
+            v-if="form.avatar"
+            :src="baseUrl + form.avatar"
+            fit="cover"
+            style="width: 100%; height: 100%"
+          />
+          <svg-icon v-else fit="cover" style="width: 100%; height: 100%" />
+        </div>
+        <div class="user-name">{{ form.nickName }}</div>
+      </div>
+
+      <!-- 右侧表单 -->
+      <div class="form-container">
+        <form @submit.prevent="handleSubmit" class="password-form">
+          <div class="form-group">
+            <label for="currentPassword">用户编号</label>
+            <input v-model="form.employeeCode" type="input" disabled="true" />
+          </div>
+          <div class="form-group">
+            <label for="newPassword">新密码</label>
+            <input
+              v-model="form.newPassword"
+              type="password"
+              id="newPassword"
+              required
+              placeholder="请输入新密码"
+              @input="validatePassword"
+            />
+            <div v-if="passwordError" class="error-message">
+              {{ passwordError }}
+            </div>
+          </div>
+          <div class="form-group">
+            <label for="password">确认新密码</label>
+            <input
+              v-model="form.password"
+              type="password"
+              id="password"
+              required
+              placeholder="请再次输入新密码"
+              @input="validatePassword"
+            />
+            <div v-if="confirmError" class="error-message">
+              {{ confirmError }}
+            </div>
+          </div>
+          <button type="submit" class="submit-btn" :disabled="isSubmitting">
+            {{ isSubmitting ? "处理中..." : "提交" }}
+          </button>
+        </form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { reactive, ref } from "vue";
+import { getUserDetail, updatePassword } from "@/api/user/index";
+
+const route = useRoute();
+const router = useRouter();
+
+const redirectPath = route.query.redirect;
+
+const baseUrl = import.meta.env.VITE_APP_UPLOAD_URL;
+
+const form = reactive({
+  id: Number(route.query.id),
+  avatar: "",
+  nickName: "",
+  employeeCode: "",
+  newPassword: "",
+  password: "",
+});
+
+const passwordError = ref<string>("");
+const confirmError = ref<string>("");
+const isSubmitting = ref<boolean>(false);
+
+const validatePassword = (): void => {
+  // 密码强度验证
+  // if (form.newPassword.length > 0 && form.newPassword.length < 8) {
+  //   passwordError.value = "密码长度至少为8个字符";
+  // } else if (!/[A-Z]/.test(form.newPassword)) {
+  //   passwordError.value = "密码必须包含至少一个大写字母";
+  // } else if (!/[a-z]/.test(form.newPassword)) {
+  //   passwordError.value = "密码必须包含至少一个小写字母";
+  // } else if (!/[0-9]/.test(form.newPassword)) {
+  //   passwordError.value = "密码必须包含至少一个数字";
+  // } else {
+  //   passwordError.value = "";
+  // }
+
+  // 确认密码验证
+  if (form.password && form.newPassword !== form.password) {
+    confirmError.value = "两次输入的密码不一致";
+  } else {
+    confirmError.value = "";
+  }
+};
+
+const handleSubmit = async (): Promise<void> => {
+  // 验证表单
+  validatePassword();
+  if (passwordError.value || confirmError.value) {
+    return;
+  }
+  isSubmitting.value = true;
+
+  try {
+    updatePassword(form).then((res) => {
+      if (res.code !== 200) {
+        ElMessage.success("修改密码成功");
+        return;
+      }
+    });
+    // 重置表单
+  } catch (error) {
+    ElMessage.error("修改密码失败");
+  } finally {
+    isSubmitting.value = false;
+  }
+};
+
+const getUserInfo = async () => {
+  try {
+    const res = await getUserDetail(form.id);
+    form.avatar = res.data.avatar;
+    form.nickName = res.data.nickName;
+    form.employeeCode = res.data.employeeCode;
+  } catch (error) {
+    ElMessage.error("获取用户信息失败");
+  }
+};
+
+onMounted(() => {
+  getUserInfo();
+});
+</script>
+
+<style scoped>
+.password-change-container {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  min-height: 100%;
+  background-color: #f5f5f5;
+  padding: 20px;
+}
+
+.password-change-card {
+  display: flex;
+  max-width: 800px;
+  width: 100%;
+  background-color: white;
+  border-radius: 10px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  overflow: hidden;
+  transform: translateY(-20%);
+}
+
+.user-info {
+  flex: 1;
+  padding: 40px 20px;
+  background-color: #f0f2f5;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+}
+
+.avatar-container {
+  width: 150px;
+  height: 150px;
+  border-radius: 50%;
+  overflow: hidden;
+  margin-bottom: 20px;
+  border: 3px solid #fff;
+  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
+}
+
+.avatar {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.user-name {
+  font-size: 20px;
+  font-weight: bold;
+  color: #333;
+}
+
+.form-container {
+  flex: 1;
+  padding: 40px;
+}
+
+.form-title {
+  margin-bottom: 30px;
+  color: #333;
+  text-align: center;
+}
+
+.password-form {
+  display: flex;
+  flex-direction: column;
+}
+
+.form-group {
+  margin-bottom: 20px;
+}
+
+.form-group label {
+  display: block;
+  margin-bottom: 8px;
+  font-weight: 500;
+  color: #555;
+}
+
+.form-group input {
+  width: 100%;
+  padding: 10px 15px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  font-size: 16px;
+  transition: border-color 0.3s;
+}
+
+.form-group input:focus {
+  border-color: #409eff;
+  outline: none;
+}
+
+.error-message {
+  color: #f56c6c;
+  font-size: 12px;
+  margin-top: 5px;
+}
+
+.submit-btn {
+  padding: 12px;
+  background-color: #409eff;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  font-size: 16px;
+  cursor: pointer;
+  transition: background-color 0.3s;
+  margin-top: 10px;
+}
+
+.submit-btn:hover {
+  background-color: #66b1ff;
+}
+
+.submit-btn:disabled {
+  background-color: #a0cfff;
+  cursor: not-allowed;
+}
+
+@media (max-width: 768px) {
+  .password-change-card {
+    flex-direction: column;
+  }
+
+  .user-info {
+    padding: 20px;
+  }
+
+  .avatar-container {
+    width: 100px;
+    height: 100px;
+  }
+}
+</style>

+ 16 - 0
src/views/sets/users.vue

@@ -17,6 +17,9 @@
         <el-button text type="primary" @click="editPermission(row)"
           >分配角色
         </el-button>
+        <el-button text type="primary" @click="changePassword(row)"
+          >修改密码</el-button
+        >
       </template>
     </avue-crud>
 
@@ -82,6 +85,9 @@ const { checkBtnPerm, downloadTemplate, exportData } = Utils; //按钮权限等
 
 const crudRef = ref(null); //crudRef.value 获取avue-crud对象
 
+const router = useRouter(); //路由对象
+const route = useRoute();
+
 const deptList = ref([]); //部门列表
 const getDeptList = async () => {
   let res = await treeList();
@@ -241,6 +247,16 @@ const resetChecked = () => {
   treeRef.value.setCheckedKeys([], false);
 };
 
+const changePassword = (row) => {
+  router.push({
+    name: "changePassword",
+    query: {
+      redirect: route.fullPath,
+      id: row.id,
+    },
+  });
+};
+
 onMounted(() => {
   getDeptList(); //获取部门列表
   dataList();