瀏覽代碼

登陆后的修改密码功能

刘洋 1 年之前
父節點
當前提交
12e4581f75

+ 6 - 0
src/api/user.js

@@ -77,6 +77,12 @@ export const logout = (data) =>
     method: 'post',
     data,
   });
+export const updateMyPassword = (data) =>
+  request({
+    url: '/api/admin/common/update_password',
+    data,
+    loading: true,
+  });
 export const getMenus = () =>
   request({
     url: '/api/admin/common/get_menu', //真实接口url

+ 4 - 2
src/components/global/s-buttons/index.vue

@@ -1,8 +1,10 @@
 <template>
   <div class="s-button text-center">
-    <t-button theme="primary" @click="submitHandle">{{ confirmText }}</t-button>
+    <t-button theme="primary" @click="submitHandle">{{
+      confirmText || '确定'
+    }}</t-button>
     <t-button theme="default" class="m-l-20px" @click="cancel">{{
-      cancelText
+      cancelText || '取消'
     }}</t-button>
   </div>
 </template>

+ 0 - 1
src/config/color.js

@@ -30,7 +30,6 @@ export function generateColorMap(theme, colorPalette, mode = 'light') {
   return colorMap;
 }
 export function insertThemeStylesheet(theme, colorMap, mode = 'light') {
-  console.log(theme, colorMap);
   const isDarkMode = mode === 'dark';
   const root = !isDarkMode
     ? `:root[theme-color='${theme}']`

+ 45 - 10
src/layout/index.vue

@@ -40,7 +40,11 @@
               @click="colorChoose"
             >
               <t-button theme="default" variant="outline" shape="square">
-                <t-icon name="logo-windows-filled" size="16"
+                <t-icon
+                  name="chevron-down"
+                  size="24"
+                  color="#fff"
+                  :style="{ background: themeColor, borderRadius: '2px' }"
               /></t-button>
             </t-dropdown>
             <t-dropdown
@@ -53,6 +57,7 @@
                   <img src="../assets/imgs/user_head.png" />
                 </div>
                 <span class="real-name">{{ userStore.user?.realName }}</span>
+                <ChevronDownIcon size="16px" />
               </div>
             </t-dropdown>
           </div>
@@ -69,7 +74,7 @@
   </t-layout>
 </template>
 
-<script setup name="Layout">
+<script setup name="Layout" lang="jsx">
 import { ref, onMounted } from 'vue';
 import { useAppStore, useUserStore } from '@/store';
 import { useRouter, useRoute } from 'vue-router';
@@ -78,6 +83,7 @@ import { Color } from 'tvision-color';
 import { generateColorMap, insertThemeStylesheet } from '@/config/color';
 import { moduleMap } from '@/router/asyncRoutes';
 import { ChevronDownIcon, UserIcon } from 'tdesign-icons-vue-next';
+import { clear, cookie } from '@/utils/tool';
 
 const router = useRouter();
 const route = useRoute();
@@ -92,25 +98,54 @@ const setModuleByPath = () => {
   let curModuleName = moduleMap[firstPath];
   userStore.setCurPageModule(curModuleName);
 };
+const themeColor = ref(cookie.get('themeColor'));
 onMounted(() => {
   setModuleByPath();
+  setTheme(themeColor.value || '#0052d9');
 });
 const colorOptions = ref([
-  { content: '默认主题', value: '#0052d9' },
-  { content: '天蓝主题', value: '#2fa4e7' },
-  { content: '橙色主题', value: '#e78b24' },
-  { content: '红色主题', value: '#dd4814' },
+  {
+    content: '默认主题',
+    value: '#0052d9',
+  },
+  {
+    content: '天蓝主题',
+    value: '#2fa4e7',
+  },
+  {
+    content: '橙色主题',
+    value: '#e78b24',
+  },
+  {
+    content: '红色主题',
+    value: '#dd4814',
+  },
 ]);
-const userOptions = ref([{ content: '修改密码', value: '1' }]);
-const colorChoose = (data) => {
-  console.log('data:', data);
-  const hex = data.value;
+const userOptions = ref([
+  { content: '修改密码', value: '1' },
+  { content: '退出', value: '2' },
+]);
+const clickHandler = (data) => {
+  if (data.content === '修改密码') {
+    router.push({ name: 'PasswordModify' });
+  } else if (data.content === '退出') {
+    clear();
+    window.location.href = '/';
+  }
+};
+const setTheme = (hex) => {
   const newPalette = Color.getPaletteByGradation({
     colors: [hex],
     step: 10,
   })[0];
   const colorMap = generateColorMap(hex, newPalette);
   insertThemeStylesheet(hex, colorMap);
+  cookie.set('themeColor', hex);
+  themeColor.value = hex;
+};
+const colorChoose = (data) => {
+  const hex = data.value;
+  setTheme(hex);
 };
 </script>
 

+ 53 - 39
src/router/asyncRoutes.js

@@ -22,46 +22,60 @@ export const moduleMap = asyncRoutes.reduce((obj, item) => {
   return obj;
 }, {});
 
-export const whiteMenuList = [
+//用户得登录后才有的非菜单的路由白名单,与菜单权限无关,
+//比如依赖登录后的自我修改密码界面(点击右上角的头像下拉菜单里的“修改密码”)
+export const routesNotMenu = [
   {
-    id: 100,
-    title: '我的工作台',
-    parentId: 0,
-    url: '/my-workbenches',
-    sort: 0,
-    name: 'MyWorkbenches',
-  },
-  {
-    id: 101,
-    parentId: 100,
-    url: '/my-workbenches/workbenches',
-    title: '工作台',
-    sort: 1,
-    name: 'Workbenches',
-  },
-  {
-    id: 102,
-    parentId: 101,
-    url: '/my-workbenches/workbenches/message-reminder',
-    title: '消息提醒',
-    sort: 2,
-    name: 'MessageReminder',
-  },
-  {
-    id: 103,
-    parentId: 101,
-    url: '/my-workbenches/workbenches/my-tasks',
-    title: '待办任务',
-    sort: 3,
-    name: 'MyTasks',
-  },
-  {
-    id: 104,
-    parentId: 101,
-    url: '/my-workbenches/workbenches/notice',
-    title: '通知公告',
-    sort: 4,
-    name: 'Notice',
+    name: 'PasswordModify',
+    path: '/bootstrap/password-modify',
+    component: () => import('@/views/password-modify/index.vue'),
+    meta: {
+      title: '密码修改',
+      mount: 'Bootstrap', //需要挂载在哪个路由节点下
+    },
   },
 ];
+
+// export const whiteMenuList = [
+//   {
+//     id: 100,
+//     title: '我的工作台',
+//     parentId: 0,
+//     url: '/my-workbenches',
+//     sort: 0,
+//     name: 'MyWorkbenches',
+//   },
+//   {
+//     id: 101,
+//     parentId: 100,
+//     url: '/my-workbenches/workbenches',
+//     title: '工作台',
+//     sort: 1,
+//     name: 'Workbenches',
+//   },
+//   {
+//     id: 102,
+//     parentId: 101,
+//     url: '/my-workbenches/workbenches/message-reminder',
+//     title: '消息提醒',
+//     sort: 2,
+//     name: 'MessageReminder',
+//   },
+//   {
+//     id: 103,
+//     parentId: 101,
+//     url: '/my-workbenches/workbenches/my-tasks',
+//     title: '待办任务',
+//     sort: 3,
+//     name: 'MyTasks',
+//   },
+//   {
+//     id: 104,
+//     parentId: 101,
+//     url: '/my-workbenches/workbenches/notice',
+//     title: '通知公告',
+//     sort: 4,
+//     name: 'Notice',
+//   },
+// ];
 export default asyncRoutes;

+ 24 - 24
src/router/modules/user.js

@@ -68,29 +68,29 @@ export default {
         },
       ],
     },
-    {
-      name: 'PasswordManage',
-      path: '/user/password-manage',
-      redirect: '/user/password-manage/password-modify',
-      meta: {
-        title: '密码管理',
-        sort: 1,
-        icon: 'lock-on',
-        alias: 'pwdManage',
-      },
-      children: [
-        {
-          name: 'PasswordModify',
-          path: '/user/password-manage/password-modify',
-          component: () =>
-            import('@/views/user/password-manage/password-modify/index.vue'),
-          meta: {
-            title: '密码修改',
-            sort: 1,
-            alias: 'pwd',
-          },
-        },
-      ],
-    },
+    // {
+    //   name: 'PasswordManage',
+    //   path: '/user/password-manage',
+    //   redirect: '/user/password-manage/password-modify',
+    //   meta: {
+    //     title: '密码管理',
+    //     sort: 1,
+    //     icon: 'lock-on',
+    //     alias: 'pwdManage',
+    //   },
+    //   children: [
+    //     {
+    //       name: 'PasswordModify',
+    //       path: '/user/password-manage/password-modify',
+    //       component: () =>
+    //         import('@/views/user/password-manage/password-modify/index.vue'),
+    //       meta: {
+    //         title: '密码修改',
+    //         sort: 1,
+    //         alias: 'pwd',
+    //       },
+    //     },
+    //   ],
+    // },
   ],
 };

+ 9 - 0
src/router/routes.js

@@ -1,5 +1,14 @@
 // 系统路由
 const routes = [
+  {
+    name: 'Bootstrap',
+    path: '/bootstrap',
+    component: () => import('@/layout/empty.vue'),
+    children: [],
+    meta: {
+      title: '',
+    },
+  },
   {
     name: 'Layout',
     path: '/',

+ 4 - 2
src/store/modules/user.js

@@ -4,7 +4,7 @@ import { getMenus, logout, login } from '@/api/user';
 import router from '@/router/index';
 import asyncRoutes from '@/router/asyncRoutes';
 import { getTreeList, local, session, clear } from '@/utils/tool';
-import { whiteMenuList } from '@/router/asyncRoutes';
+import { routesNotMenu } from '@/router/asyncRoutes';
 // 路由扁平化
 const flatAsyncRoutes = (routes, breadcrumb = []) => {
   const res = [];
@@ -127,6 +127,7 @@ const useUserStore = defineStore('user', {
       const routers = flatAsyncRoutes(cloneDeep(menus));
       this.routers = routers;
       routers.map((item) => router.addRoute('Layout', item));
+      routesNotMenu.forEach((item) => router.addRoute(item.meta.mount, item));
       if (menus.length) {
         this.setHeaderMenus(menus);
         this.setCurPageModule(menus[0].name);
@@ -141,7 +142,8 @@ const useUserStore = defineStore('user', {
               router.push({ name: 'Login' });
               return;
             }
-            let allMenus = [...whiteMenuList, ...(response.privileges || [])];
+            // let allMenus = [...whiteMenuList, ...(response.privileges || [])];
+            let allMenus = [...(response.privileges || [])];
             this.setMenu(allMenus);
             resolve(allMenus);
           })

+ 2 - 2
src/utils/request.js

@@ -1,6 +1,6 @@
 import axios from 'axios';
 import { MessagePlugin as Message } from 'tdesign-vue-next';
-import { local, download } from '@/utils/tool';
+import { download, clear } from '@/utils/tool';
 import { get, isEmpty } from 'lodash';
 import qs from 'qs';
 import { h } from 'vue';
@@ -89,7 +89,7 @@ function createService() {
             break;
           case 401:
             err('登录状态已过期,需要重新登录');
-            local.clear();
+            clear();
             window.location.href = '/';
             break;
           case 403:

+ 214 - 0
src/views/password-modify/index.vue

@@ -0,0 +1,214 @@
+//点击用户头像那里的修改密码选项,依赖登录后,有登录态的情形下
+<template>
+  <div class="login flex justify-center items-center h-full">
+    <img class="logo" src="../../assets/imgs/login_logo.png" />
+    <div class="login-bg flex justify-center items-center">
+      <div class="login-bg-inner-box text-center">
+        <img src="../../assets/imgs/login_bg_inner.png" />
+        <div class="title1">欢 迎 使 用</div>
+        <div class="title2">项目质量控制管理平台</div>
+      </div>
+    </div>
+    <div class="login-box">
+      <div class="title1 flex justify-between items-center">
+        <span>修改密码</span>
+      </div>
+      <div class="title2">{{ `请输入旧密码和新密码` }}</div>
+      <t-form
+        v-show="!forgetStatus"
+        ref="form"
+        :data="formData"
+        :label-width="0"
+        class="login-form"
+        :rules="rules"
+      >
+        <t-form-item name="password">
+          <t-input
+            v-model="formData.password"
+            type="password"
+            clearable
+            placeholder="请输入旧密码"
+            size="large"
+          >
+          </t-input>
+        </t-form-item>
+
+        <t-form-item name="newPassword">
+          <t-input
+            v-model="formData.newPassword"
+            type="password"
+            clearable
+            placeholder="请输入新密码"
+            size="large"
+          >
+          </t-input>
+        </t-form-item>
+        <t-form-item name="repeatNewPassword">
+          <t-input
+            v-model="formData.repeatNewPassword"
+            type="password"
+            clearable
+            placeholder="请再次输入新密码"
+            size="large"
+          >
+          </t-input>
+        </t-form-item>
+        <div class="flex items-center justify-between">
+          <t-button theme="default" @click="router.back()">返回</t-button>
+          <t-button theme="primary" @click="submitHandler">确定</t-button>
+        </div>
+      </t-form>
+    </div>
+  </div>
+</template>
+
+<script setup name="PasswordModify">
+import { ref, reactive, computed, watch } from 'vue';
+import { DesktopIcon, LockOnIcon, RollbackIcon } from 'tdesign-icons-vue-next';
+import { useRoute, useRouter } from 'vue-router';
+import { useUserStore } from '@/store';
+import { MessagePlugin } from 'tdesign-vue-next';
+import { getBase64 } from '@/utils/crypto';
+import { updateMyPassword } from '@/api/user';
+import { clear } from '@/utils/tool';
+
+const form = ref(null);
+
+const route = useRoute();
+const router = useRouter();
+
+const formData = reactive({
+  password: '',
+  newPassword: '',
+  repeatNewPassword: '',
+});
+const rules = {
+  password: [
+    {
+      required: true,
+      message: '请输入旧密码',
+      type: 'error',
+      trigger: 'change',
+    },
+  ],
+  newPassword: [
+    {
+      required: true,
+      message: '请输入新密码',
+      type: 'error',
+      trigger: 'change',
+    },
+  ],
+  repeatNewPassword: [
+    {
+      required: true,
+      message: '请输入新密码',
+      type: 'error',
+      trigger: 'change',
+    },
+    {
+      validator: (val) => {
+        if (val !== formData.newPassword) {
+          return {
+            result: false,
+            message: '两次输入的新密码不一致',
+          };
+        }
+        return {
+          result: true,
+          type: 'success',
+        };
+      },
+    },
+  ],
+};
+
+const userStore = useUserStore();
+
+const submitHandler = () => {
+  form.value.validate().then(async (result) => {
+    if (result === true) {
+      updateMyPassword({
+        id: userStore.user.id,
+        password: getBase64(formData.password),
+        newPassword: getBase64(formData.newPassword),
+      }).then(() => {
+        MessagePlugin.success('密码修改成功,请重新登录');
+        clear();
+        window.location.href = '/';
+      });
+    }
+  });
+};
+</script>
+<style lang="less" scoped>
+.login {
+  background: linear-gradient(180deg, #f4f9ff 0%, #d7eaff 100%);
+  position: relative;
+  min-height: 550px;
+
+  .logo {
+    width: 180px;
+    z-index: 100;
+    top: 48px;
+    left: 48px;
+    position: absolute;
+  }
+  .login-bg {
+    position: absolute;
+    top: 80px;
+    bottom: 80px;
+    left: 0;
+    width: 70%;
+    z-index: 99;
+    background: url(../../assets//imgs/login_bg_grid.png) center center
+      no-repeat;
+    background-size: contain;
+    .login-bg-inner-box {
+      img {
+        height: 260px;
+        margin-bottom: 20px;
+      }
+      .title1 {
+        font-size: 32px;
+        color: #262626;
+        margin-bottom: 15px;
+        font-weight: bold;
+        line-height: 40px;
+      }
+      .title2 {
+        font-size: 20px;
+        color: #8c8c8c;
+        line-height: 28px;
+      }
+    }
+  }
+  .login-box {
+    width: 350px;
+    height: 360px;
+    background: #fff;
+    box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.08);
+    border-radius: 8px;
+    border: 1px solid #e5e6eb;
+    padding: 24px;
+    position: absolute;
+    left: 60%;
+    z-index: 101;
+    .title1 {
+      span {
+        font-size: 20px;
+        font-weight: bold;
+        color: #262626;
+        line-height: 32px;
+      }
+    }
+    .title2 {
+      font-size: 14px;
+      color: #8c8c8c;
+      line-height: 24px;
+      margin-top: 4px;
+      margin-bottom: 28px;
+    }
+  }
+}
+</style>