前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >9. CMDB前端开发(上)

9. CMDB前端开发(上)

作者头像
alexhuiwang
发布2023-05-07 21:00:48
1.8K0
发布2023-05-07 21:00:48
举报
文章被收录于专栏:运维博客运维博客

CMDB前端开发(上)

大纲

  • 登录页面
  • 后台基本布局

登录页面

仪表盘占位页面开发

  1. 创建视图: devops_web/src/views/dashboard/Dashboard.vue
代码语言:javascript
复制
<template>
    这是仪表盘
</template>

<script>
    export default {
        name: "Dashboard"
    }
</script>

<style scoped>

</style>
  1. dashboard路由处理: devops_web/src/router/index.js
代码语言:javascript
复制
...
const routes = [
  {
    path: '/',
    name: '首页',
    icon: 'Monitor',
    component: Layout,
    redirect: '/dashboard',
    children: [
      {
         path: '/dashboard',
         name: '仪表盘',
         component: () => import('../views/dashboard/Dashboard.vue')
      }
    ]
  },
  ....
  1. Layout页面修改(将默认的首页设置为dashboard,并且是一级菜单): devops_web/src/views/Layout.vue
代码语言:javascript
复制
<template>
  <div class="common-layout">
    <el-container>
      <el-aside :width="isCollapse ? '64px' : '200px'">
        <el-menu
        default-active="2"
        background-color="#304156"
        text-color="#FFFFFF"
        active-text-color="#ffd04b"
        class="el-menu"
        @open="handleOpen"
        @close="handleClose"
        :collapse="isCollapse"
        :collapse-transition="false"
        router
      >
            <div class="logo">
              <img src="../assets/logo.png" alt="">
            </div>
            <template v-for="menu in this.$router.options.routes" :key="menu">
              <!-- 单独处理仪表盘的菜单-->
              <el-menu-item v-if="menu.path == '/'" :index="menu.children[0].path">
                <el-icon><component :is="menu.children[0].icon" /></el-icon>
                <span>{{menu.name}}</span>
              </el-menu-item>
              <!--  处理有子路由的菜单   -->
              <el-sub-menu v-else :index="menu.path">
                <template #title>
                  <el-icon><component :is="menu.icon" /></el-icon>
                  <span>{{menu.children[0].name}}</span>
                </template>
                <el-menu-item v-for="child in menu.children" :key="child" :index="child.path">{{child.name}}</el-menu-item>
              </el-sub-menu>
            </template>
          </el-menu>
        </el-aside>
      <el-container>
        <el-header>
          <!-- 导航栏折叠-->
          <div class="toggleCollapse">
            <el-icon :size="25" @click="toggleCollapse"><Fold /></el-icon>
          </div>
          <!-- 头像-->
          <el-dropdown>
            <span class="el-dropdown-link">
              <img src="../assets/avatar.png" alt="">
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item>密码修改</el-dropdown-item>
                <el-dropdown-item>退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </el-header>
        <el-main>
          <!-- 占位符,显示路由跳转后加载的内容-->
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>


<script>
  export default {
    name: 'Layout',
    data() {
      return {
        isCollapse: false
      }
    },
    methods: {
      toggleCollapse() {
        this.isCollapse = !this.isCollapse
      }
    }

  }
</script>
<style>
  .common-layout, .el-container, .el-menu {
    height: 100%;
  }
  .el-header {
    border-bottom: 1px lightgrey solid;
  }
  .el-aside {
    background: grey;
  }
  .el-main {
    background: #FFFFF;
  }
  .collapse-transition {
    cursor: pointer;
  }
  .logo img {
    width: 200px;
    height: 60px;
    /*margin-left: 10px;*/
  }
  .el-dropdown-link img {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    flex: auto;
  }
  .el-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
</style>
  1. 页面测试

登录页面大体布局和数据提交

静态页面布局
  1. 登录页面准备独立页面:devops_web/src/views/Login.vue
代码语言:javascript
复制
<template>
    <div class="main">
        <div class="login_box">
            <div class="title">
                欢迎访问DevOps运维平台
            </div>
            <div class="login_form">
                <el-form label-width="30px">
                    <el-form-item>
                        <el-input
                                :prefix-icon="User"
                                placeholder="用户名"
                                v-model="form.username"
                        ></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-input
                                :prefix-icon="Lock"
                                placeholder="密码"
                                type="password"
                                v-model="form.password"
                                show-password
                        ></el-input>
                    </el-form-item>
                    <el-form-item class="btn">
                       <el-button type="primary" @click="onSubmit" >登录</el-button>
                    </el-form-item>
                </el-form>

            </div>
        </div>
    </div>
</template>
<script>
    // input里加图标必须单独按需导入
    import { User, Lock } from "@element-plus/icons-vue";
    export default {
        name: 'Login',
        data() {
            return {
                form: {
                    username: '',
                    password: ''
                }
            }
        },
        methods: {
            onSubmit() {
                console.log("aaa")
            }
        },
        // 需要用setup导入
        setup() {
            return {
                User,Lock
            }
        }
    }
</script>

<style scoped>
    .main {
        background-image: url("../assets/img/login_background.jpeg");
        background-size: 100% 100%;
        height: 100%;
    }
    .login_box {
        width: 400px;
        height: 300px;
        background-color: #FFFFFF;
        box-shadow: 0 5px 20px 0 #e8e8e8;
        border-radius: 20px;
        position: absolute;
        top: 0;
        bottom: 0;
        right: 0;
        left: 0;
        margin: auto;
    }
    .title {
        font-size: 20px;
        font-weight: bold;
        color: #409eff;
        text-align: center;
        margin-top: 30px;
    }
    .login_form {
        margin-top: 40px;
        margin-right: 30px;
    }
    .btn {
        margin-left: 36%;
    }
    .btn .el-button {
        width: 140px;
    }
</style>
  1. 登录页面路由: devops_web/src/router/index.js
代码语言:javascript
复制
...
const routes = [
  {
    path: '/login',
    name: '登录',
    component: () => import('../views/Login.vue')
  },
  {
    path: '/',
    name: '首页',
    component: Layout,
    redirect: '/dashboard',
    children: [
      {
         path: '/dashboard',
         name: '仪表盘',
         icon: 'Monitor',
         component: () => import('../views/dashboard/Dashboard.vue')
      }
    ]
  },
  ....
  1. 页面测试:
数据提交
  1. 项目安装axios
代码语言:javascript
复制
cd devops_web
npm install axios
  1. 配置axios: devops_web/src/api/http.js
代码语言:javascript
复制
import  axios from "axios"
import {ElMessage} from "element-plus"

const instance = axios.create({
    baseURL: 'http://127.0.0.1:8000/api',
    timeout: 5000
})
//请求拦截器
instance.interceptors.request.use(config => {
    //在请求api之前携带token
    const token = window.sessionStorage.getItem('token')
    if (token) {
        config.headers = {
            'Authorization': 'Token ' + token
        }
    }
    return config;
}, error => {
    return Promise.reject(error)
})
//响应拦截器
instance.interceptors.response.use(response => {
    //处理响应数据
    if (response.data.code != 200 ) {
        ElMessage.error(response.data.msg)
    }
    return response
}, error => {
    //处理catch的地方
    ElMessage('连接服务器失败,请稍后再试!!')
    return Promise.reject(error)
})

export default instance
  1. 全局注册axios: devops_web/src/main.js
代码语言:javascript
复制
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import * as ElIconModules from '@element-plus/icons-vue'
//导入axios, 重新封装的axios
import axios from "./api/http";

const app = createApp(App)

app.use(ElementPlus)
for(let iconName in ElIconModules) {
    app.component(iconName,ElIconModules[iconName])
}
app.config.globalProperties.$http = axios;
app.use(router).mount('#app')
  1. 登录提交函数: devops_web/src/views/Login.vue
代码语言:javascript
复制
<template>
    <div class="main">
        <div class="login_box">
            <div class="title">
                欢迎访问DevOps运维平台
            </div>
            <div class="login_form">
                <el-form :model="form" ref="form" :rules="rules" label-width="30px">
                    <el-form-item prop="username">
                        <el-input
                                :prefix-icon="User"
                                placeholder="用户名"
                                v-model="form.username"
                        ></el-input>
                    </el-form-item>
                    <el-form-item prop="password">
                        <el-input
                                :prefix-icon="Lock"
                                placeholder="密码"
                                type="password"
                                v-model="form.password"
                                show-password
                        ></el-input>
                    </el-form-item>
                    <el-form-item class="btn">
                       <el-button type="primary" @click="onSubmit" >登录</el-button>
                    </el-form-item>
                </el-form>

            </div>
        </div>
    </div>
</template>
<script>
    // input里加图标必须单独按需导入
    import { User, Lock } from "@element-plus/icons-vue";
    export default {
        name: 'Login',
        data() {
            return {
                form: {
                    username: '',
                    password: ''
                },
                rules: {
                  username: [
                    {required: true, message: '请输入用户名', trigger: 'blur'},
                    {min: 3, message: '用户名长度应不小于3个字符', trigger: 'blur'}
                  ],
                  password: [
                    {required: true, message: '请输入密码', trigger: 'blur'},
                    {min: 6, message: '用户名长度应不小于6个字符', trigger: 'blur'}
                  ]
                }
            }
        },
        methods: {
            onSubmit() {
                // 提交前预验证
               this.$refs.form.validate((valid) => {  //回调函数中valid布尔值
                  if (valid) {
                    // 登陆成功并给消息提示
                    this.$http.post('/login/', this.form)
                    .then(res => {
                      if (res.data.code == 200) {
                        this.$message.success('登录成功');
                        // 保存token
                        window.sessionStorage.setItem("token", res.data.token);
                        this.$router.push('/dashboard/')
                      }
                })
                  } else {
                    this.$message.warning('用户名或密码格式错误!')
                  }
                })
            }
        },
        // 需要用setup导入
        setup() {
            return {
                User,Lock
            }
        }
    }
</script>

<style scoped>
    .main {
        background-image: url("../assets/img/login_background.jpeg");
        background-size: 100% 100%;
        height: 100%;
    }
    .login_box {
        width: 400px;
        height: 300px;
        background-color: #FFFFFF;
        box-shadow: 0 5px 20px 0 #e8e8e8;
        border-radius: 20px;
        position: absolute;
        top: 0;
        bottom: 0;
        right: 0;
        left: 0;
        margin: auto;
    }
    .title {
        font-size: 20px;
        font-weight: bold;
        color: #409eff;
        text-align: center;
        margin-top: 30px;
    }
    .login_form {
        margin-top: 40px;
        margin-right: 30px;
    }
    .btn {
        margin-left: 36%;
    }
    .btn .el-button {
        width: 140px;
    }
</style>
  1. 配置Layout隐藏没有子路由的项目:devops_web/src/views/Layout.vue
代码语言:javascript
复制
<template>
  <div class="common-layout">
    <el-container>
      <el-aside :width="isCollapse ? '64px' : '200px'">
        <el-menu
        default-active="2"
        background-color="#304156"
        text-color="#FFFFFF"
        active-text-color="#ffd04b"
        class="el-menu"
        @open="handleOpen"
        @close="handleClose"
        :collapse="isCollapse"
        :collapse-transition="false"
        router
      >
            <div class="logo">
              <img src="../assets/logo.png" alt="">
            </div>
            <template v-for="menu in this.$router.options.routes" :key="menu">
            <!-- 一级菜单 没有子路由的菜单-->
             <!--  <el-menu-item v-if="!menu.children" :index="menu.path">-->
             <!--    <el-icon><component :is="menu.icon" /></el-icon>-->
             <!--    <span>{{menu.name}}</span>-->
             <!--  </el-menu-item>-->
              <!-- 单独处理仪表盘的菜单-->
              <el-menu-item v-if="menu.path == '/'" :index="menu.children[0].path">
                <el-icon><component :is="menu.children[0].icon" /></el-icon>
                <span>{{menu.children[0].name}}</span>
              </el-menu-item>
              <!--  处理有子路由的菜单   -->
              <el-sub-menu v-else-if="menu.children" :index="menu.path">
                <template #title>
                  <el-icon><component :is="menu.icon" /></el-icon>
                  <span>{{menu.name}}</span>
                </template>
                <el-menu-item v-for="child in menu.children" :key="child" :index="child.path">{{child.name}}</el-menu-item>
              </el-sub-menu>
            </template>
          </el-menu>
        </el-aside>
      <el-container>
        <el-header>
          <!-- 导航栏折叠-->
          <div class="toggleCollapse">
            <el-icon :size="25" @click="toggleCollapse"><Fold /></el-icon>
          </div>
          <!-- 头像-->
          <el-dropdown>
            <span class="el-dropdown-link">
              <img src="../assets/avatar.png" alt="">
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item>密码修改</el-dropdown-item>
                <el-dropdown-item>退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </el-header>
        <el-main>
          <!-- 占位符,显示路由跳转后加载的内容-->
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>


<script>
  export default {
    name: 'Layout',
    data() {
      return {
        isCollapse: false
      }
    },
    methods: {
      toggleCollapse() {
        this.isCollapse = !this.isCollapse
      }
    }

  }
</script>
<style>
  .common-layout, .el-container, .el-menu {
    height: 100%;
  }
  .el-header {
    border-bottom: 1px lightgrey solid;
  }
  .el-aside {
    background: grey;
  }
  .el-main {
    background: #FFFFF;
  }
  .collapse-transition {
    cursor: pointer;
  }
  .logo img {
    width: 200px;
    height: 60px;
    /*margin-left: 10px;*/
  }
  .el-dropdown-link img {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    flex: auto;
  }
  .el-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
</style>
  1. 解决后端跨域问题: 安装django-cors-headers
代码语言:javascript
复制
pip3 install django-cors-headers
  1. 配置后端跨域app: devops_api/devops_api/settings.py
代码语言:javascript
复制
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework.authtoken',
    'rest_framework_swagger',
    'django_filters',
    'cmdb',
    'system_config',
    'corsheaders'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'corsheaders.middleware.CorsMiddleware'
]
CORS_ORIGIN_ALLOW_ALL = True

配置导航守卫,控制访问权限

目前虽然已经实现登录功能,即使没有登录情况下直接访问任何页面都还可以访问的,我们希望如果用户没有登录情况下,访问任何页面都重新导航到登录页面

  1. 退出登录功能完善: devops_web/src/views/Layout.vue
代码语言:javascript
复制
<template>
  <div class="common-layout">
    <el-container>
      <el-aside :width="isCollapse ? '64px' : '200px'">
        <el-menu
        default-active="2"
        background-color="#304156"
        text-color="#FFFFFF"
        active-text-color="#ffd04b"
        class="el-menu"
        @open="handleOpen"
        @close="handleClose"
        :collapse="isCollapse"
        :collapse-transition="false"
        router
      >
            <div class="logo">
              <img src="../assets/logo.png" alt="">
            </div>
            <template v-for="menu in this.$router.options.routes" :key="menu">
            <!-- 一级菜单 没有子路由的菜单-->
             <!--  <el-menu-item v-if="!menu.children" :index="menu.path">-->
             <!--    <el-icon><component :is="menu.icon" /></el-icon>-->
             <!--    <span>{{menu.name}}</span>-->
             <!--  </el-menu-item>-->
              <!-- 单独处理仪表盘的菜单-->
              <el-menu-item v-if="menu.path == '/'" :index="menu.children[0].path">
                <el-icon><component :is="menu.children[0].icon" /></el-icon>
                <span>{{menu.children[0].name}}</span>
              </el-menu-item>
              <!--  处理有子路由的菜单   -->
              <el-sub-menu v-else-if="menu.children" :index="menu.path">
                <template #title>
                  <el-icon><component :is="menu.icon" /></el-icon>
                  <span>{{menu.name}}</span>
                </template>
                <el-menu-item v-for="child in menu.children" :key="child" :index="child.path">{{child.name}}</el-menu-item>
              </el-sub-menu>
            </template>
          </el-menu>
        </el-aside>
      <el-container>
        <el-header>
          <!-- 导航栏折叠-->
          <div class="toggleCollapse">
            <el-icon :size="25" @click="toggleCollapse"><Fold /></el-icon>
          </div>
          <!-- 头像-->
          <el-dropdown>
            <span class="el-dropdown-link">
              <img src="../assets/avatar.png" alt="">
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item>密码修改</el-dropdown-item>
                <el-dropdown-item @click="logout">退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </el-header>
        <el-main>
          <!-- 占位符,显示路由跳转后加载的内容-->
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>


<script>
  export default {
    name: 'Layout',
    data() {
      return {
        isCollapse: false
      }
    },
    methods: {
      toggleCollapse() {
        this.isCollapse = !this.isCollapse
      },
      //退出登录函数
      logout() {
        window.sessionStorage.clear()
        this.$router.push('/login')
      }
    }

  }
</script>
<style>
  .common-layout, .el-container, .el-menu {
    height: 100%;
  }
  .el-header {
    border-bottom: 1px lightgrey solid;
  }
  .el-aside {
    background: grey;
  }
  .el-main {
    background: #FFFFF;
  }
  .collapse-transition {
    cursor: pointer;
  }
  .logo img {
    width: 200px;
    height: 60px;
    /*margin-left: 10px;*/
  }
  .el-dropdown-link img {
    width: 50px;
    height: 50px;
    border-radius: 50%;
    flex: auto;
  }
  .el-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
</style>
  1. 配置导航守卫,登录token获取才能查看页面,否则不能正常访问页面: devops_web/src/router/index.js
代码语言:javascript
复制
...
const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

// 添加导航守卫
router.beforeEach((to, from, next) => {
  // 如果用户访问登录页,直接放行
  if(to.path == '/login') {
    return next()
  }
  // 从sessionStorage获取token值
  const token = window.sessionStorage.getItem('token');
  // 如果没有获取到token值,跳转到登录页
  if (!token) {
    return next('/login')
  }
  // 正常跳转
  next()
});

export default router
  1. 页面token检查

后台基本布局

显示用户名

  1. 上述例子已经在保存token的时候保存了username
  2. 只需要在头像旁边配置username显示即可: devops_web/src/views/Layout.vue
代码语言:javascript
复制
<template>
  <div class="common-layout">
    <el-container>
      <el-aside :width="isCollapse ? '64px' : '200px'">
        <el-menu
        default-active="2"
        background-color="#304156"
        text-color="#FFFFFF"
        active-text-color="#ffd04b"
        class="el-menu"
        @open="handleOpen"
        @close="handleClose"
        :collapse="isCollapse"
        :collapse-transition="false"
        router
      >
            <div class="logo">
              <img src="../assets/logo.png" alt="">
            </div>
            <template v-for="menu in this.$router.options.routes" :key="menu">
            <!-- 一级菜单 没有子路由的菜单-->
             <!--  <el-menu-item v-if="!menu.children" :index="menu.path">-->
             <!--    <el-icon><component :is="menu.icon" /></el-icon>-->
             <!--    <span>{{menu.name}}</span>-->
             <!--  </el-menu-item>-->
              <!-- 单独处理仪表盘的菜单-->
              <el-menu-item v-if="menu.path == '/'" :index="menu.children[0].path">
                <el-icon><component :is="menu.children[0].icon" /></el-icon>
                <span>{{menu.children[0].name}}</span>
              </el-menu-item>
              <!--  处理有子路由的菜单   -->
              <el-sub-menu v-else-if="menu.children" :index="menu.path">
                <template #title>
                  <el-icon><component :is="menu.icon" /></el-icon>
                  <span>{{menu.name}}</span>
                </template>
                <el-menu-item v-for="child in menu.children" :key="child" :index="child.path">{{child.name}}</el-menu-item>
              </el-sub-menu>
            </template>
          </el-menu>
        </el-aside>
      <el-container>
        <el-header>
          <!-- 导航栏折叠-->
          <div class="toggleCollapse">
            <el-icon :size="25" @click="toggleCollapse"><Fold /></el-icon>
          </div>
          <!-- 头像-->
          <el-dropdown>
            <span class="el-dropdown-link">
              <img src="../assets/avatar.png" alt="">
              <span>{{username}}</span>
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item>密码修改</el-dropdown-item>
                <el-dropdown-item @click="logout">退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </el-header>
        <el-main>
          <!-- 占位符,显示路由跳转后加载的内容-->
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>


<script>
  export default {
    name: 'Layout',
    data() {
      return {
        isCollapse: false,
        username: window.sessionStorage.getItem('username')
      }
    },
    methods: {
      toggleCollapse() {
        this.isCollapse = !this.isCollapse
      },
      logout() {
        window.sessionStorage.clear()
        this.$router.push('/login')
      }
    }

  }
</script>
<style>
  .common-layout, .el-container, .el-menu {
    height: 100%;
  }
  .el-header {
    border-bottom: 1px lightgrey solid;
  }
  .el-aside {
    background: grey;
  }
  .el-main {
    background: #FFFFF;
  }
  .collapse-transition {
    cursor: pointer;
  }
  .logo img {
    width: 200px;
    height: 60px;
    /*margin-left: 10px;*/
  }
  //头像和用户名显示并排操作,需要username跟头像在两个不同的元素中才行
  .el-dropdown-link {
    display: flex;
    align-items: center;
  }
  //缩小头像比例
  .el-dropdown-link img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    flex: auto;
  }
  .el-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
</style>
  1. 效果展示

修改密码

  1. 修改密码后端接口
  1. 前端需要使用的dialog对话框: https://element-plus.gitee.io/zh-CN/component/dialog.html
  2. 修改密码对话框添加: devops_web/src/views/Layout.vue
代码语言:javascript
复制
<template>
  <div class="common-layout">
    <el-container>
      <el-aside :width="isCollapse ? '64px' : '200px'">
        <el-menu
        default-active="2"
        background-color="#304156"
        text-color="#FFFFFF"
        active-text-color="#ffd04b"
        class="el-menu"
        @open="handleOpen"
        @close="handleClose"
        :collapse="isCollapse"
        :collapse-transition="false"
        router
      >
            <div class="logo">
              <img src="../assets/logo.png" alt="">
            </div>
            <template v-for="menu in this.$router.options.routes" :key="menu">
            <!-- 一级菜单 没有子路由的菜单-->
             <!--  <el-menu-item v-if="!menu.children" :index="menu.path">-->
             <!--    <el-icon><component :is="menu.icon" /></el-icon>-->
             <!--    <span>{{menu.name}}</span>-->
             <!--  </el-menu-item>-->
              <!-- 单独处理仪表盘的菜单-->
              <el-menu-item v-if="menu.path == '/'" :index="menu.children[0].path">
                <el-icon><component :is="menu.children[0].icon" /></el-icon>
                <span>{{menu.children[0].name}}</span>
              </el-menu-item>
              <!--  处理有子路由的菜单   -->
              <el-sub-menu v-else-if="menu.children" :index="menu.path">
                <template #title>
                  <el-icon><component :is="menu.icon" /></el-icon>
                  <span>{{menu.name}}</span>
                </template>
                <el-menu-item v-for="child in menu.children" :key="child" :index="child.path">{{child.name}}</el-menu-item>
              </el-sub-menu>
            </template>
          </el-menu>
        </el-aside>
      <el-container>
        <el-header>
          <!-- 导航栏折叠-->
          <div class="toggleCollapse">
            <el-icon :size="25" @click="toggleCollapse"><Fold /></el-icon>
          </div>
          <!-- 头像-->
          <el-dropdown>
            <span class="el-dropdown-link">
              <img src="../assets/avatar.png" alt="">
              <span>{{username}}</span>
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item @click="dialogVisible=true">密码修改</el-dropdown-item>
                <el-dropdown-item @click="logout">退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </el-header>
        <el-main>
          <!-- 占位符,显示路由跳转后加载的内容-->
          <router-view></router-view>
        </el-main>
      </el-container>
    </el-container>
  </div>
  <!--  修改密码对话框 dialogVisible 在修改密码按钮处有click事件调起-->
  <el-dialog
    v-model="dialogVisible"
    title="修改密码"
    width="30%"
  >
    <el-form :model="UserPasswordForm" label-position="right" label-width="100px" :rules="rules" ref="UserPasswordForm">
      <el-form-item label="原密码:" prop="old_password">
        <el-input
          v-model="UserPasswordForm.old_password"
          type="password"
          show-password
        ></el-input>
      </el-form-item>
      <el-form-item label="新密码:" prop="new_password">
        <el-input
            v-model="UserPasswordForm.new_password"
            type="password"
            show-password
        ></el-input>
      </el-form-item>
      <el-form-item label="再次确认:" prop="confirm_password">
        <el-input
            v-model="UserPasswordForm.confirm_password"
            type="password"
            show-password
        ></el-input>
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="changePasswordSubmit">确定</el-button>
      </span>
    </template>
  </el-dialog>

</template>


<script>
  export default {
    name: 'Layout',
    data() {
      // 新旧密码校验规则
      const checkNewOldPassword = (rule, value, callback) => {
        if (value == this.UserPasswordForm.old_password) {
            callback(new Error('新密码不能与旧密码一样!'))
        } else {
           return callback()
        }
      };
      const checkNewPassword = (rule, value, callback) => {
        if (value != this.UserPasswordForm.new_password) {
            callback(new Error('两次输入密码不一致!'))
        } else {
          return callback()
        }
      };
      return {
        isCollapse: false,
        username: window.sessionStorage.getItem('username'),
        dialogVisible: false,
        UserPasswordForm: {
          old_password: '',
          new_password: '',
          confirm_password: ''
        },
        rules: {
          old_password: [
              {required: true, message: '请输入原密码', trigger: 'blur'},
              {min: 6, message: '用户名长度应不小于6个字符', trigger: 'blur'}
          ],
          new_password: [
              {required: true, message: '请输入新密码', trigger: 'blur'},
              {min: 6, message: '用户名长度应不小于6个字符', trigger: 'blur'},
              {validator: checkNewOldPassword, trigger: 'blur'}
          ],
          confirm_password: [
              {required: true, message: '请确认新密码', trigger: 'blur'},
              {min: 6, message: '用户名长度应不小于6个字符', trigger: 'blur'},
              {validator: checkNewPassword, trigger: 'blur'}
          ]
        }
      }
    },
    methods: {
      toggleCollapse() {
        this.isCollapse = !this.isCollapse
      },
      logout() {
        window.sessionStorage.clear()
        this.$router.push('/login')
      },
      changePasswordSubmit() {
        // 提交前预验证
        this.$refs.UserPasswordForm.validate((valid) => {
        // 回调函数中valid布尔值
        console.log(this.UserPasswordForm)
        if (valid) {
            //获取用户名
            const username = window.sessionStorage.getItem('username')
            this.UserPasswordForm['username'] = username
            this.$http.post('/change_password/', this.UserPasswordForm)
            .then(res => {
                if (res.data.code == 200) {
                    this.$message.success(res.data.msg);
                    this.dialogVisible = false
                }
            })
          }
        })
      }
    }
  }
</script>
<style>
  .common-layout, .el-container, .el-menu {
    height: 100%;
  }
  .el-header {
    border-bottom: 1px lightgrey solid;
  }
  .el-aside {
    background: grey;
  }
  .el-main {
    background: #FFFFF;
  }
  .collapse-transition {
    cursor: pointer;
  }
  .logo img {
    width: 200px;
    height: 60px;
    /*margin-left: 10px;*/
  }
  .el-dropdown-link {
    display: flex;
    align-items: center;
  }
  .el-dropdown-link img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    flex: auto;
    margin-right: 10px;
  }
  .el-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
</style>
  1. 测试密码修改功能
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CMDB前端开发(上)
    • 大纲
      • 登录页面
        • 仪表盘占位页面开发
        • 登录页面大体布局和数据提交
        • 配置导航守卫,控制访问权限
      • 后台基本布局
        • 显示用户名
        • 修改密码
    相关产品与服务
    CODING DevOps
    CODING DevOps 一站式研发管理平台,包括代码托管、项目管理、测试管理、持续集成、制品库等多款产品和服务,涵盖软件开发从构想到交付的一切所需,使研发团队在云端高效协同,实践敏捷开发与 DevOps,提升软件交付质量与速度。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档