打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
3用户信息展示

上一篇完成了AdminLTE的整合,接下来就要把页面中的逻辑一一填充进来了,先从展示用户信息开始吧。

我们需要用户点击账户信息按钮后被导航到账户信息页。所以需要给账户信息按钮添加router-link,点击时调用router进行页面跳转。

第一步:在账户信息的HTML代码处添加事件

<router-link to="/userProfile/travelCount">    <button href="#" class="btn btn-primary btn-flat ch">账户信息</button></router-link>
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

第二步:新建一个userProfile.vue和一个travelCount.vue。userProfile用来展示用户的基本信息,travelCount用来展示用户的出差记录。travelCount是被嵌套在userProfile中的。

userProfile.vue:

<template>    <!-- Main content -->    <section class="content">        <div class="row">            <div class="col-md-3">                <!-- Profile Image -->                <div class="box box-primary">                    <div class="box-body box-profile">                        <img class="profile-user-img img-responsive img-circle" src="../assets/img/avatar5.png" alt="User profile picture">                        <h3 class="profile-username text-center ch">{{displayName}}</h3>                        <p class="text-muted text-center ch">{{duty}}</p>                        <ul class="list-group list-group-unbordered">                            <li class="list-group-item">                                <b class="ch">用户名:</b> <b class="pull-right ch">{{displayName}}</b>                            </li>                            <li class="list-group-item">                                <b class="ch">登录名:</b> <b class="pull-right ch">{{name}}</b>                            </li>                            <li class="list-group-item">                                <b class="ch">邮箱地址:</b> <b class="pull-right ch">{{email}}</b>                            </li>                            <li class="list-group-item">                                <b class="ch">所属部门:</b> <b class="pull-right ch">{{department}}</b>                            </li>                            <li class="list-group-item">                                <b class="ch">职务:</b> <b class="pull-right ch">{{duty}}</b>                            </li>                            <li class="list-group-item">                                <b class="ch">办公地点:</b> <b class="pull-right ch">{{location}}</b>                            </li>                            <li class="list-group-item">                                <b class="ch">办公电话:</b> <b class="pull-right ch">{{tel}}</b>                            </li>                            <li class="list-group-item">                                <b class="ch">手机:</b> <b class="pull-right ch">{{phone}}</b>                            </li>                            <li class="list-group-item">                                <b class="ch">上级领导:</b> <b class="pull-right ch">{{superior}}</b>                            </li>                        </ul>                        <strong class="ch"><i class="fa fa-pencil margin-r-5"></i>技能标签</strong>                        <p style="padding-top:5px">                            <button v-for="skill in skills" class="label btn-primary ch" style="margin:2px; color:white">{{skill}}</button>                        </p>                    </div>                    <!-- /.box-body -->                </div>                <!-- /.box -->            </div>            <!-- /.col -->            <div class="col-md-9">                <div class="nav-tabs-custom">                    <ul class="nav nav-tabs">                        <li class="ch active" data-toggle="tab">                            <router-link to="/userProfile/travelCount">                                <span>出差统计</span>                            </router-link>                        </li>                        <li class="ch" data-toggle="tab">                            <router-link to="/userProfile/workCircle">                                <span>我的工作圈</span>                            </router-link>                        </li>                    </ul>                    <div class="tab-content">                        <router-view></router-view><!--这里是要显示travelCount内容的地方-->                    </div>                    <!-- /.content -->                </div>            </div>        </div>    </section></template><script>    export default {        data() {//这里对应用户的基本信息            return {                displayName: null,                duty: null,                name: null,                email: null,                department: null,                location: null,                tel: null,                phone: null,                superior: null,                skills: null            }        },        mounted (){//使用mounted在挂在DOM时通过restful api获取用户基本信息并填充到data中。这个之后详细说明。            this.$http.get(                'https://192.168.227.1:8443/userInfo' ,                 {                    headers: {'token' : localStorage.token}//在requestHeader中携带之前产生的token用来在后端验证用户权限。                }            )                .then(                    //success                    response => {                        this.displayName = response.data.displayName;                        this.duty = response.data.duty;                        this.name = response.data.name;                        this.email = response.data.email;                        this.department = response.data.department;                        this.location = response.data.location;                        this.tel = response.data.tel;                        this.phone = response.data.phone;                        this.superior = response.data.superior;                        this.skills = response.data.skills;                    },                     //error                    response => {                    }                )        }    }</script><style scoped>    @font-face    {        font-family: yaHeiFont;        src: url('../assets/font/yaHei.ttf')    }    .ch    {        font-family:yaHeiFont;        color: black;    }</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133

第三步,在main.js中引入userProfile.vue文件并且为userProfile添加路由。这里因为userProfile内容要显示的地方是在红框区域内,如下图:

而红框区域内的路由出口是在index.vue中定义的,所以如果想要userProfile的内容正确渲染到红框区域内,则需要把userProfile嵌套在index中,需要用到vue-router的嵌套路由。

// The Vue build version to load with the `import` command// (runtime-only or standalone) has been set in webpack.base.conf with an alias.import Vue from 'vue'import VueRouter from 'vue-router'import VueResource from 'vue-resource'import store from './store/store'//bootstrapimport 'bootstrap/dist/css/bootstrap.css'import 'bootstrap/dist/js/bootstrap.min.js'//AdminLTEimport './assets/css/skins/_all-skins.min.css'import './assets/css/AdminLTE.min.css'import './assets/js/app.min.js'//font-awesomeimport 'font-awesome/css/font-awesome.min.css'//echartsimport echarts from 'echarts'//componentsimport App from './App'import Login from './components/login'import Index from './components/index'import DeviceCatalog from './components/deviceCatalog'import UserProfile from './components/userProfile'import TravelCount from './components/travelCount'import WorkCircle from './components/workCircle'Vue.use(VueRouter)Vue.use(VueResource)//注册echarts的一种方法// Object.defineProperties(Vue.prototype, {//   $echarts: { get: () => echarts }// });//Vue-Resource提交方式设置Vue.http.options.emulateJSON = true;const routes = [  //登录页  {    path: '/login',    component : Login  },  //导航页  {    path: '/index',    component: Index,    //导航页子页面,children中的component将被渲染到之前说的红色区域内    children: [      //设备目录页      {        path: '/deviceCatalog',        component: DeviceCatalog      },      //账户信息页      {        path: '/userProfile',        component: UserProfile,        //账户信息子页面        children: [          //出差统计页          {            path: '/userProfile/travelCount',            component: TravelCount          },          //工作圈子页          {            path: '/userProfile/workCircle',            component: WorkCircle          }        ]      },    ]  },]const router = new VueRouter({  routes})//默认导航到登录页// router.push('/login')/*全局路由钩子访问资源时需要验证localStorage中是否存在token以及token是否过期验证成功可以继续跳转失败返回登录页重新登录 */router.beforeEach((to, from, next) => {  if(to.path == '/login'){    next()  }  if(localStorage.token && new Date().getTime() < localStorage.tokenExpired){    next()  }  else{    next('/login')  }})new Vue({  el: '#app',  template: '<App/>',  components: { App },  router:router,  store: store,  echarts: echarts//注册echarts的另一种方法  }})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111

做完之后点击用户信息按钮应该就可以跳转到用户信息页了,看下效果

第四步出差统计信息,这里想使用echarts图表来进行展示(这里我跳了一个坑)。首先在项目中使用npm install echarts –save将echarts下载到项目中。然后在main.js中引用,对应第三步main.js中

import echarts from 'echarts'
  • 1
  • 1

在travelCount中使用,travelCount.vue。这里有几点需要注意

1.echarts挂载的dom必须设置一个高度,否则不能显示出来。

2.echarts的配置需要放在mounted中。

3.使用echarts的resize方法配合js中onresize重绘图表以动态适应屏幕尺寸。

<template>    <div id="main" style="height:730px"></div></template><script>export default {    mounted() {        var myChart = this.$root.$options.echarts.init(document.getElementById('main'));//这里注意        var option = {            grid : {                left : '1%',                right : '2%',                bottom : '1%',                containLabel : true            },            xAxis : {                type : 'value',                boundaryGap : [ 0, 0.01 ]            },            yAxis : {                type : 'category',                axisLabel : {                    inside : true,                    textStyle : {                        fontWeight : 'bold'                    },                },                z : 100,                data : ['A国:2016-01-01至2016-02-01' , 'B国:2016-03-01至2016-04-01' , 'C国:2016-06-01至2016-06-01']            },            series : [ {                type : 'bar',                barGap : '10%',                itemStyle : {                    normal : {                        color : 'LightSkyBlue'                    }                },                data : [100 , 200 , 300]            } ]        }        myChart.setOption(option);        //窗口尺寸变化时重新绘制chart        window.onresize = () => {            myChart.resize()            }    }}</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

这里要说下我跳的坑,引入echarts时,上面的代码使用了

this.$root.$options.echarts
  • 1
  • 1

如果这样引用的话,需要在main.js的Vue根实例中注册echarts,见第三步main.js配置。还有一种方法可以使用this.$echarts的方式引用(这个方法是Vue论坛中tomi-li老师指点的,谢谢老师)。

这种方法需要使用js的Object.defineProperties将echarts手动添加到Vue对象中,见第三步main.js配置。使用这种方法时不需要在根实例中注册echarts。

Object.defineProperties(Vue.prototype, {   $echarts: { get: () => echarts }});
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

如果没有手动添加的话,在其他Vue文件中使用echarts时会报错,告诉你echarts没有定义过。

看下效果

OK,前端的部分完成了,现在出差信息是静态数据,因为来处理、记录这些数据的服务可能还要依赖其他服务,我们先用静态数据代替。但是用户基本信息是从Ldap中取出来的,之前第二步中不是使用了vur-resourse到这个地址获取用户数据么。

this.$http.get(     'https://192.168.227.1:8443/userInfo' ,       {            headers: {'token' : localStorage.token}      })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

后端处理这个请求的controller。因为在分布式架构下这个controller通过restful对外提供获取用户信息的服务,所以需要使用@CrossOrigin注解满足跨域的需求。

getUserInfo方法做这几件事情

1.拿到header中的用户token,解密后判断用户凭证是否过期、是否拥有某种权限角色。

2.如果判断没有问题,使用token中的用户名作为入参,调用SpringLdap取得用户信息,并使用EmployeeAttributesMapper 填充我们自己的POJO类。返回response信息。

3.如果判断有问题,返回403表示认证没有通过。

package an.userinfo;import static org.springframework.ldap.query.LdapQueryBuilder.query;import java.util.Date;import javax.naming.directory.Attributes;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.ldap.NamingException;import org.springframework.ldap.core.AttributesMapper;import org.springframework.ldap.core.LdapTemplate;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.RequestHeader;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.serializer.SerializerFeature;import an.entity.Employee;import io.jsonwebtoken.Jwts;@RestController("/userInfo")public class UserInfoWeb {    //jwt加密密匙    @Value("${jwt.key}")    private String jwtKey;    //ldap模板    @Autowired    private LdapTemplate ldapTemplate;    /**     * 将域用户属性通过EmployeeAttributesMapper填充到Employee类中,返回一个填充信息的Employee实例     */    private class EmployeeAttributesMapper implements AttributesMapper<Employee> {        public Employee mapFromAttributes(Attributes attrs) throws NamingException, javax.naming.NamingException {            Employee employee = new Employee();            employee.setName((String) attrs.get("sAMAccountName").get());            employee.setDisplayName((String) attrs.get("displayName").get());            employee.setEmail((String) attrs.get("userprincipalname").get());            employee.setDuty((String) attrs.get("title").get());            employee.setDepartment((String) attrs.get("department").get());            employee.setSuperior((String) attrs.get("manager").get());            employee.setLocation((String) attrs.get("physicaldeliveryofficename").get());            employee.setTel((String) attrs.get("homephone").get());            employee.setPhone((String) attrs.get("mobile").get());            String skill = (String) attrs.get("description").get();            String skills[] = skill.split(";");            employee.setSkills(skills);            return employee;        }    }    /**     * 使用用户凭证取得用户信息     * @param token 用户凭证     * @return     */    @CrossOrigin    @RequestMapping(method = RequestMethod.GET)    public ResponseEntity<String> getUserInfo(@RequestHeader("token") String token){        //解析token        String username = Jwts.parser().setSigningKey(jwtKey).parseClaimsJws(token).getBody().getSubject();        String roles = Jwts.parser().setSigningKey(jwtKey).parseClaimsJws(token).getBody().getAudience();        long expiration = Jwts.parser().setSigningKey(jwtKey).parseClaimsJws(token).getBody().getExpiration().getTime();        long current = new Date().getTime();        //验证token过期时间、用户权限        if(current > expiration || roles.indexOf("ROLE_USER") == -1) {            return new ResponseEntity<String>(HttpStatus.FORBIDDEN);        }        //查询并产生用户信息        Employee employee = ldapTemplate                .search(query().where("objectclass").is("person").and("sAMAccountName").is(username),                        new EmployeeAttributesMapper())                .get(0);        return new ResponseEntity<String>(JSON.toJSONString(employee , SerializerFeature.DisableCircularReferenceDetect) , HttpStatus.OK);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

写完收工,文字表达能力实在是差,各位费眼了。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Webpack 的异步加载原理及分包策略
Vue+Echarts构建大数据可视化展示公司品牌项目分享
在vue中引入Bootstrap4并且安装axios和vue
vue 如何写一个消息通知组件$notify,简单易懂,你上你也行!
springboot html vue.js 前后分离代码示例
移动端开发案例【4】“我的”页面开发
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服