【慧游鲁博】(2)——前端功能页面完善v1

06-01 1619阅读

【慧游鲁博】(2)——前端功能页面完善v1

登录/注册界面

说明:目前主页面导航栏(默认显示的首页)点击退出登录后无响应

【慧游鲁博】(2)——前端功能页面完善v1

增加内容:

  • 开发登录页面内容
  • 为导航栏中的选项添加功能,使其点击后能够自动跳转相应页面

    修改路由

    // 路由
    import { createRouter, createWebHistory } from 'vue-router'
    //导入组件
    import LoginVue from '@/views/Login.vue'
    import LayoutVue from '@/views/Layout.vue'
    import Dashboard from '@/views/Dashboard.vue'
    // 用户(管理员)相关组件
    import UserResetPasswordVue from '@/views/user/UserResetPassword.vue'
    // 定义路由关系
    const routes = [
        { path: '/login', component: LoginVue },
        {
            path: '/', component: LayoutVue, redirect: '/dashboard',
            children: [
                { path: 'dashboard', component: Dashboard, meta: { title: '仪表盘' } },
                { path: 'user/reset-password',component: UserResetPasswordVue,meta: { title: '重置密码' }
                }
            ]
        },
    ]
    // 创建路由器
    const router = createRouter({
        history: createWebHistory(),
        routes: routes
    })
    // 导出路由
    export default router
    

    修改Layout.vue

    导航栏右侧部分

            
    

    修改js部分

    import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
    import { useRoute,useRouter } from "vue-router";//添加useRouter
    import { useTokenStore } from '@/stores/token'; // 导入token存储
    import { useUserInfoStore } from '@/stores/userInfo'; // 导入用户信息存储
    import { ElMessage } from 'element-plus'; // 导入消息提示
    import {
      Setting,
      User,
      DataAnalysis,
      Fold,
      Expand,
      ArrowDown,
      Lock,
      SwitchButton,
      ArrowLeft,
    } from "@element-plus/icons-vue";
    const isCollapse = ref(false);
    const showUserDropdown = ref(false);
    const isMobileMenuOpen = ref(false);
    const route = useRoute();
    const router = useRouter(); // 获取路由器实例
    const tokenStore = useTokenStore(); // 获取token存储
    const userInfoStore = useUserInfoStore(); // 获取用户信息存储
    //退出登录
    const logout=()=>{
      //清除token
      tokenStore.setToken('');
      //清除用户信息
      userInfoStore.userInfoStore({});
      //清除本地存储中的相关信息
      localStorage.removeItem('token');
      //提示用户已经退出
      ElMessage({
        message:'退出登录成功',
        type:'success',
        duration:2000
      })
      //隐藏下拉菜单
      showUserDropdown.value=false;
      //跳转登录界面
      router.push('/login');
    }
    //跳转到个人信息页面
    const goToUserInfo=()=>{
      router.push('/user/info');
      showUserDropdown.value =false;
    }
    //跳转到修改密码页面
    const goToResetPassword=()=>{
      router.push('/user/reset-password');
      showUserDropdown.value=false;
    }
    const toggleSidebar = () => {
      isCollapse.value = !isCollapse.value;
      // 保存用户偏好到localStorage
      localStorage.setItem("sidebarStatus", isCollapse.value ? "1" : "0");
      // 移动设备上,切换侧边栏状态
      if (window.innerWidth  {
      isMobileMenuOpen.value = false;
    };
    const activeMenu = computed(() => {
      return route.path;
    });
    // 保留这个映射,以防其他地方需要使用
    const pathNameMap = computed(() => {
      return {
        "/admin/login": "登录",
        "/admin/user-info": "用户信息",
        "/admin/update-password": "更新密码",
        "/user/statistics": "数据统计",
        "/user/distribution": "用户角色分布",
        "/user/growth": "新用户增长趋势",
        "/user/profile": "用户画像",
        "/analysis/interaction": "多模态交互日志",
        "/analysis/guidance": "导览行为",
      };
    });
    // 使用variables.scss中的颜色变量
    const menuBgColor = computed(() => "transparent");
    const menuTextColor = computed(() => "rgba(255, 255, 255, 0.8)");
    const menuActiveTextColor = computed(() => "var(--color-accent)");
    // 点击外部关闭用户下拉菜单
    const handleClickOutside = (event) => {
      const userDropdown = document.querySelector(".navbar-user");
      if (userDropdown && !userDropdown.contains(event.target)) {
        showUserDropdown.value = false;
      }
    };
    // 监听窗口大小变化,自动处理移动设备上的侧边栏
    const handleResize = () => {
      if (window.innerWidth  {
      document.addEventListener("click", handleClickOutside);
      window.addEventListener("resize", handleResize);
      // 从localStorage读取侧边栏状态
      const sidebarStatus = localStorage.getItem("sidebarStatus");
      if (sidebarStatus) {
        isCollapse.value = sidebarStatus === "1";
      }
      // 初始化时检查窗口大小
      handleResize();
    });
    onBeforeUnmount(() => {
      document.removeEventListener("click", handleClickOutside);
      window.removeEventListener("resize", handleResize);
    });
    // 监听路由变化,在移动设备上自动关闭侧边栏
    watch(
      () => route.path,
      () => {
        if (window.innerWidth  
    

    创建登录页面 (Login.vue)

    • 提供基本的表单验证
    • 点击登录按钮时,显示成功消息并跳转回dashboard
    • 不进行实际的身份验证(之后与后端交互后再进行完善)

      后续扩展:

      • 这个简单实现可以在后端API准备好后轻松扩展
      • 可以添加token存储、验证逻辑和路由
          
        
        
        import { ref, reactive } from 'vue';
        import { useRouter } from 'vue-router';
        import { ElMessage } from 'element-plus';
        import { User, Lock } from '@element-plus/icons-vue';
        import { useTokenStore } from '@/stores/token';
        import { useUserInfoStore } from '@/stores/userInfo';
        // 获取路由器实例和存储实例
        const router = useRouter();
        const tokenStore = useTokenStore();
        const userInfoStore = useUserInfoStore();
        // 表单引用
        const loginFormRef = ref(null);
        const loading = ref(false);
        // 登录表单数据
        const loginForm = reactive({
          username: '',
          password: ''
        });
        // 表单验证规则
        const loginRules = {
          username: [
            { required: true, message: '请输入用户名', trigger: 'blur' },
            { min: 3, max: 20, message: '用户名长度应为3-20个字符', trigger: 'blur' }
          ],
          password: [
            { required: true, message: '请输入密码', trigger: 'blur' },
            { min: 6, max: 20, message: '密码长度应为6-20个字符', trigger: 'blur' }
          ]
        };
        // 处理登录 - 简化版,不做实际验证
        const handleLogin = async () => {
          // 表单验证
          await loginFormRef.value.validate(async (valid) => {
            if (!valid) return;
            
            loading.value = true;
            
            // 模拟登录延迟
            setTimeout(() => {
              // 简单提示
              ElMessage({
                message: '登录成功',
                type: 'success'
              });
              
              // 跳转到首页
              router.push('/dashboard');
              
              loading.value = false;
            }, 500);
          });
        };
        
        
        // 导入全局样式
        @import "@/styles/base/index.scss";
        
        

        创建login的styles/views/login.scss文件,以及添加到index.scss中

        /* login.scss - 布局样式 */
        @import 'src/styles/base/variables.scss';
        @import 'src/styles/base/mixins.scss';
        .login-container {
          display: flex;
          justify-content: center;
          align-items: center;
          min-height: 100vh;
          background: url('@/assets/login_bg.jpg') no-repeat center center;
          background-size: cover;
          
          &::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(0, 0, 0, 0.4);
          }
        }
        .login-box {
          position: relative;
          width: 400px;
          padding: 40px;
          background-color: rgba(255, 255, 255, 0.9);
          border-radius: var(--border-radius-md);
          box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
        }
        .login-header {
          display: flex;
          flex-direction: column;
          align-items: center;
          margin-bottom: 30px;
        }
        .login-logo {
          width: 80px;
          height: 80px;
          margin-bottom: 16px;
        }
        .login-title {
          font-family: var(--font-family-artistic);
          font-size: 28px;
          color: var(--color-primary);
          margin: 0;
        }
        .login-form {
          margin-top: 20px;
        }
        .login-btn-container {
          margin-top: 30px;
        }
        .login-btn {
          width: 100%;
          height: 44px;
          font-size: 16px;
          background-color: var(--color-primary);
          border-color: var(--color-primary);
          
          &:hover, &:focus {
            background-color: var(--color-primary-light);
            border-color: var(--color-primary-light);
          }
        }
        @media (max-width: 768px) {
          .login-box {
            width: 90%;
            padding: 30px 20px;
          }
        }
        

        index.scss

        /* 引入所有样式模块 */
        // 基础样式
        @import 'src/styles/base/variables.scss';
        @import 'src/styles/base/mixins.scss';
        @import 'src/styles/base/transitions.scss';
        // 各个页面和组件的样式
        @import '../views/layout.scss';
        @import '../views/dashboard.scss';
        @import '../views/components/navbar.scss';
        @import '../views/components/sidebar.scss';
        @import '../views/login.scss';
        

        Pinia 存储(全局状态管理)

        创建 stores/token.js

        定义了两个 Pinia 存储(store),用于在 Vue 应用中管理全局状态

        //定义store
        import {defineStore} from 'pinia'
        export const useTokenStore = defineStore('token', {
            state: () => ({
              token: localStorage.getItem('token') || ''
            }),
            actions: {
              setToken(token) {
                this.token = token;
              }
            },
            getters: {
              getToken: (state) => state.token,
              isLoggedIn: (state) => !!state.token
            },
            // 持久化配置
            persist: true
          });
        

        管理用户的认证令牌(token)

        • state:
          • token:存储用户的认证令牌,初始值会尝试从 localStorage 中获取,如果没有则为空字符串
          • actions:
            • setToken(token):设置新的令牌值
            • getters:
              • getToken:获取当前令牌值
              • isLoggedIn:检查用户是否已登录(通过判断令牌是否存在)
              • persist: true:启用持久化存储,这意味着存储的数据会被保存到浏览器的本地存储中,即使页面刷新也不会丢失

                创建stores/userInfo.js

                import { defineStore } from 'pinia';
                export const useUserInfoStore = defineStore('userInfo', {
                  state: () => ({
                    userInfo: {}
                  }),
                  actions: {
                    setUserInfo(info) {
                      this.userInfo = info;
                    }
                  },
                  getters: {
                    getUserInfo: (state) => state.userInfo,
                    getUserName: (state) => state.userInfo?.username || '未登录'
                  },
                  // 持久化配置
                  persist: true
                });
                

                管理用户的个人信息

                • state:
                  • userInfo:存储用户的详细信息,初始为空对象
                  • actions:
                    • setUserInfo(info):设置或更新用户信息
                    • getters:
                      • getUserInfo:获取完整的用户信息对象
                      • getUserName:获取用户名,如果不存在则返回"未登录"
                      • persist: true:同样启用了持久化存储

                        修改侧边栏

                        修改侧边栏功能键

                         
                            
                        

                        修改一级菜单二级菜单悬停颜色

                        让一级菜单和二级菜单悬停颜色一致,修改sidebar.scss - 侧边栏样式

                        统一使用绿色背景:

                        • 将所有菜单项的悬停和激活状态背景色从 var(--color-hover) 或 var(--color-primary-light) 改为 var(--color-primary)
                          /* sidebar.scss - 侧边栏样式 */
                          @import 'src/styles/base/variables.scss';
                          @import 'src/styles/base/mixins.scss';
                          .sidebar {
                            position: fixed;
                            top: 0;
                            left: 0;
                            bottom: 0;
                            width: var(--sidebar-width);
                            background: linear-gradient(to bottom, var(--color-primary-dark), var(--color-primary-darker));
                            color: var(--color-neutral-100);
                            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                            z-index: 1000;
                            box-shadow: 2px 0 10px var(--color-shadow);
                            display: flex;
                            flex-direction: column;
                            overflow: hidden;
                            
                            &.collapsed {
                              width: var(--sidebar-collapsed-width);
                              
                              .sidebar-logo {
                                padding: var(--spacing-2);
                                justify-content: center;
                                
                                span {
                                  opacity: 0;
                                  width: 0;
                                  margin: 0;
                                }
                                
                                img {
                                  margin-right: 0;
                                }
                              }
                              
                              .el-menu {
                                --el-menu-text-color: transparent;
                              }
                              
                              .el-menu-item, .el-sub-menu__title {
                                padding: 0 !important;
                                justify-content: center;
                                
                                .el-icon {
                                  margin: 0 !important;
                                }
                              }
                              
                              .el-sub-menu__icon-arrow {
                                display: none;
                              }
                              
                              .sidebar-menu-item {
                                padding: 0 !important;
                                justify-content: center;
                              }
                              .el-menu-item-group {
                                .sidebar-menu-item {
                                  border: 1px solid var(--color-border);
                                  border-radius: var(--border-radius-sm);
                                  margin: var(--spacing-2) var(--spacing-2);
                                  padding: var(--spacing-3) var(--spacing-4);
                                  transition: all 0.3s ease;
                                  
                                  // 添加一些阴影效果
                                  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
                                  
                                  // hover 状态 - 使用绿色背景
                                  &:hover {
                                    border-color: var(--color-primary);
                                    background-color: var(--color-primary) !important;
                                    transform: translateY(-1px);
                                    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
                                  }
                                  
                                  // 选中状态
                                  &.is-active {
                                    border-color: var(--color-primary);
                                    background-color: var(--color-primary) !important;
                                    font-weight: 600;
                                    
                                    // 可以添加左边框强调
                                    border-left: 3px solid var(--color-accent);
                                  }
                                  
                                  // 确保文字不会换行
                                  white-space: nowrap;
                                  overflow: hidden;
                                  text-overflow: ellipsis;
                                }
                                
                                // 相邻菜单项之间的间距
                                .sidebar-menu-item + .sidebar-menu-item {
                                  margin-top: var(--spacing-2);
                                }
                              }
                            }
                            
                            &-logo {
                              height: var(--header-height);
                              padding: 0 var(--spacing-4);
                              display: flex;
                              align-items: center;
                              justify-content: flex-start;
                              background-color: var(--color-primary-darker);
                              overflow: hidden;
                              transition: all 0.3s ease;
                              border-bottom: 1px solid var(--color-border);
                              
                              a {
                                display: flex;
                                align-items: center;
                                text-decoration: none;
                                width: 100%;
                                
                                img {
                                  height: 32px;
                                  width: auto;
                                  margin-right: var(--spacing-3);
                                  transition: margin 0.3s ease;
                                }
                                
                                span {
                                  color: var(--color-neutral-100);
                                  font-size: var(--font-size-max); 
                                  font-family: var(--font-family-artistic);  // 使用艺术字体
                                  font-weight: 500;  
                                  white-space: nowrap;
                                  overflow: hidden;
                                  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);  // 增强文字阴影
                                  transition: all 0.3s ease;
                                  letter-spacing: 2px;  // 增加字间距
                                  
                                  // 添加特效(可选)
                                  background: linear-gradient(45deg, var(--color-neutral-100), var(--color-accent-light));
                                  -webkit-background-clip: text;
                                  -webkit-text-fill-color: transparent;
                                  animation: shimmer 3s infinite linear;
                                }
                              }
                            }
                            
                            .el-scrollbar {
                              flex: 1;
                              height: calc(100vh - var(--header-height) - 50px); // 减去底部收缩按钮的高度
                            }
                            
                            .el-menu {
                              border-right: none;
                              background-color: var(--color-primary-dark);
                              --el-menu-bg-color: transparent !important;
                              --el-menu-text-color: rgba(255, 255, 255, 0.8);
                              --el-menu-hover-bg-color: var(--color-primary);
                              --el-menu-active-color: var(--color-neutral-100);
                              
                              &-item {
                                height: 50px;
                                line-height: 50px;
                                display: flex;
                                align-items: center;
                                transition: all 0.3s ease;
                                margin: 4px 0;
                                border-radius: 4px;
                                margin-left: 8px;
                                margin-right: 8px;
                                
                                .el-icon {
                                  margin-right: var(--spacing-3);
                                  font-size: 18px;
                                  color: rgba(255, 255, 255, 0.7);
                                  transition: all 0.3s ease;
                                }
                                
                                &.is-active {
                                  background-color: var(--color-primary) !important;
                                  color: var(--color-neutral-100) !important;
                                  font-weight: 600;
                                  
                                  .el-icon {
                                    color: var(--color-neutral-100);
                                  }
                                  
                                  &::before {
                                    content: '';
                                    position: absolute;
                                    left: 0;
                                    top: 0;
                                    height: 100%;
                                    width: 4px;
                                    background-color: var(--color-accent);
                                    border-radius: 0 2px 2px 0;
                                  }
                                }
                                
                                &:hover {
                                  background-color: var(--color-primary) !important;
                                  
                                  .el-icon {
                                    color: var(--color-neutral-100);
                                  }
                                }
                              }
                              
                              .el-sub-menu {
                                &__title {
                                  display: flex;
                                  align-items: center;
                                  transition: all 0.3s ease;
                                  margin: 4px 8px;
                                  border-radius: 4px;
                                  
                                  .el-icon {
                                    margin-right: var(--spacing-3);
                                    font-size: 18px;
                                    color: var(--color-neutral-100);
                                    transition: all 0.3s ease;
                                  }
                                  
                                  &:hover {
                                    background-color: var(--color-primary) !important;
                                    
                                    .el-icon {
                                      color: var(--color-neutral-100);
                                    }
                                  }
                                }
                                
                                &.is-active {
                                  > .el-sub-menu__title {
                                    color: var(--color-neutral-100) !important;
                                    background-color: var(--color-primary) !important;
                                    
                                    .el-icon {
                                      color: var(--color-neutral-100);
                                    }
                                  }
                                }
                                
                                // 添加二级菜单项的样式
                                .el-menu-item {
                                  &:hover {
                                    background-color: var(--color-primary) !important;
                                  }
                                  
                                  &.is-active {
                                    background-color: var(--color-primary) !important;
                                  }
                                }
                              }
                              
                              // 统一所有菜单项的悬停颜色
                              .sidebar-menu-item {
                                &:hover {
                                  background-color: var(--color-primary) !important;
                                }
                                
                                &.is-active {
                                  background-color: var(--color-primary) !important;
                                }
                              }
                            }
                            
                            // 侧边栏收缩切换按钮
                            &-toggle {
                              height: 50px;
                              display: flex;
                              align-items: center;
                              justify-content: space-between;
                              padding: 0 var(--spacing-4);
                              cursor: pointer;
                              border-top: 1px solid var(--color-border);
                              transition: all 0.3s ease;
                              background-color: var(--color-primary-darker);
                              
                              &:hover {
                                background-color: var(--color-primary);
                              }
                              
                              .toggle-text {
                                font-size: var(--font-size-sm);
                                color: var(--color-neutral-200);
                                transition: opacity 0.3s ease;
                              }
                              
                              .toggle-icon {
                                font-size: var(--font-size-md);
                                color: var(--color-accent);
                                transition: transform 0.3s ease;
                              }
                              
                              .sidebar.collapsed & {
                                justify-content: center;
                                
                                .toggle-text {
                                  display: none;
                                }
                                
                                .toggle-icon {
                                  transform: rotate(180deg);
                                }
                              }
                            }
                          }
                          

                          页面展示

                          点击退出登录即可到达登录界面

                          【慧游鲁博】(2)——前端功能页面完善v1

                          当前登录页面(后续的背景图还可能修改)

                          【慧游鲁博】(2)——前端功能页面完善v1

                          具有友好提示

                          【慧游鲁博】(2)——前端功能页面完善v1

                          【慧游鲁博】(2)——前端功能页面完善v1

                          (目前默认登录成功,后续与后端进行交互完善登录验证)

                          悬停颜色一致

                          【慧游鲁博】(2)——前端功能页面完善v1

                          【慧游鲁博】(2)——前端功能页面完善v1

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码