1、完善头像上传功能
- 上次写的头像上传功能,不能实现上传保存后立刻刷新右上角头像,这里做一个完善。
- 首先是在Manage.vue中(父),写刷新User的方法
//传一个user过去到header
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse" :user="user"></Header>
<script>
//user数据
data() {
return {
collapseBtnClass:'el-icon-s-fold' ,
isCollapse:false,
sideWidth:200 ,
logoTextShow:true,
user:{}
}
},
created(){
//从后台获取最新的User数据
this.getUser()
},
getUser(){
let username = localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")).username:""
if(username){
//从后台获取user数据
this.request.get("/user/username/"+username).then(res=>{
//重新赋值后台的最新User数据
this.user=res.data
})
}
}
</script>
Header.vue里面
props:{
collapseBtnClass:String,
collapse:Function,
user: Object
},
Person.vue里面
<script>
...
save(){
this.request.post("/user",this.form).then(res=>{
if(res.code==='200'){
this.$message.success("保存成功!")
//触发父级更新User的方法
this.$emit("refreshUser")
//更新浏览器存储的用户信息
this.getUser().then(res=>{
res.token=JSON.parse(localStorage.getItem("user")).token
localStorage.setItem("user",JSON.stringify(res))
})
}else{
this.$message.error("保存失败!")
}
})
},
</script>
- 这样就完美实现上传头像保存并能够刷新头像
完整代码:(改动过的页面的代码)
Manage.vue
<template>
<el-container style="height: 100vh; border: 1px solid #eee">
<!-- 侧边栏 -->
<el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246);height: 100%;" >
<Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow" ></Aside>
</el-aside>
<el-container>
<!-- 菜单栏 -->
<el-header style="border-bottom: 1px solid #ccc">
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse" :user="user"></Header>
</el-header>
<el-main>
<!-- 页面主体 -->
<!-- 表示当前页面的子路由(在children中设置)会在router-view里面展示 -->
<router-view @refreshUser="getUser" />
</el-main>
</el-container>
</el-container>
</template>
<script>
import Aside from '@/components/Aside.vue'
import Header from '@/components/Header.vue'
export default {
name:'Manage',
components: {Aside,Header},
data() {
return {
collapseBtnClass:'el-icon-s-fold' ,
isCollapse:false,
sideWidth:200 ,
logoTextShow:true,
user:{}
}
},
created(){
//从后台获取最新的User数据
this.getUser()
},
methods:{
collapse(){ //点击收缩按钮触发
this.isCollapse=!this.isCollapse
if(this.isCollapse){ //收缩
this.sideWidth=64
this.collapseBtnClass='el-icon-s-unfold'
this.logoTextShow=false
}else{ //展开
this.sideWidth = 200
this.collapseBtnClass='el-icon-s-fold'
this.logoTextShow=true
}
},
getUser(){
let username = localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")).username:""
if(username){
//从后台获取user数据
this.request.get("/user/username/"+username).then(res=>{
//重新赋值后台的最新User数据
this.user=res.data
})
}
}
}
}
</script>
Header.vue
<template>
<div style="font-size: 12px;line-height:60px;display: flex;">
<div style="flex:1;font-size:18px">
<span :class="collapseBtnClass" style="cursor:pointer" @click="collapse"></span>
<el-breadcrumb separator="/" style="display:inline-block;margin-left: 10px;">
<el-breadcrumb-item :to="'/'">首页</el-breadcrumb-item>
<el-breadcrumb-item>{{currentPathName}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-dropdown style="width:150px;cursor:pointer;text-align: right;" >
<div style="display:inline-block">
<img :src="user.avatarUrl" alt=""
style="width:30px;border-radius: 50%;position:relative;top: 10px; right: 5px">
<span>{{user.nickname}}</span><i class="el-icon-arrow-down" style="margin-left:5px"></i>
</div>
<el-dropdown-menu slot="dropdown" style="width:100px; text-align:center">
<el-dropdown-item style="font-size:14px;padding:5px 0">
<router-link to="/password" style="text-decoration:none">修改密码</router-link>
</el-dropdown-item>
<el-dropdown-item style="font-size:14px;padding:5px 0">
<router-link to="/person" style="text-decoration:none">个人信息</router-link>
</el-dropdown-item>
<el-dropdown-item style="font-size:14px;padding:5px 0">
<span style="text-decoration: none" @click="logout"> 退出</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
export default{
name:"Header",
props:{
collapseBtnClass:String,
collapse:Function,
user: Object
},
computed:{
currentPathName(){
return this.$store.state.currentPathName; //需要监听的数据
}
},
data(){
return{
}
},
methods:{
collapse(){
this.$emit("asideCollapse")
},
logout(){
this.$router.push("/login")
localStorage.removeItem("user")
this.$message.success("退出成功")
}
}
}
</script>
<style scoped>
</style>
Person.vue
<template>
<el-card style="width:500px;padding:20px;">
<el-form label-width="80px" size="small">
<el-upload
class="avatar-uploader"
action="http://localhost:8081/file/upload"
:show-file-list="false"
:on-success="handleAvatarSuccess">
<img v-if="form.avatarUrl" :src="form.avatarUrl" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
<el-form-item label="用户名" >
<el-input v-model="form.username" autocomplete="off" disabled ></el-input>
</el-form-item>
<el-form-item label="昵称" >
<el-input v-model="form.nickname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="邮箱" >
<el-input v-model="form.email" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="电话" >
<el-input v-model="form.phone" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="地址" >
<el-input type="textarea" v-model="form.address" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="save">确 定</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
export default{
name:"Person",
data(){
return{
form:{},
user:localStorage.getItem("user")?JSON.parse(localStorage.getItem("user")):{}
}
},
created(){
this.getUser().then(res=>{
console.log(res)
this.form=res
})
},
methods:{
async getUser(){
return (await this.request.get("/user/username/"+this.user.username)).data
},
save(){
this.request.post("/user",this.form).then(res=>{
if(res.code==='200'){
this.$message.success("保存成功!")
//触发父级更新User的方法
this.$emit("refreshUser")
//更新浏览器存储的用户信息
this.getUser().then(res=>{
res.token=JSON.parse(localStorage.getItem("user")).token
localStorage.setItem("user",JSON.stringify(res))
})
}else{
this.$message.error("保存失败!")
}
})
},
handleAvatarSuccess(res){
this.form.avatarUrl=res
}
}
}
</script>
<style>
.avatar-uploader{
text-align: center;
padding-bottom: 10px;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 138px;
height: 138px;
line-height: 138px;
text-align: center;
}
.avatar {
width: 138px;
height: 138px;
display: block;
}
</style>
示例:
2、整合使用Echarts
- Echarts就是在前端展示一些模型图,如折线图、圆柱图、饼图等等
- 安装
vue里面安装
npm i echarts -S
- 安装好后,打开官方文档,参照使用 官网: https://echarts.apache.org/examples/zh/index.html
- 我写的首页代码,直接粘贴如下
Home.vue
<template>
<div>
<el-row :gutter="10" style="margin-bottom: 60px">
<el-col :span="6">
<el-card style="color:#409EFF">
<div ><i class="el-icon-user-solid" />用户总数</div>
<div style="padding: 10px 0;text-align:center;font-weight:bold">
100
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card style="color:#F56C6C">
<div ><i class="el-icon-money" />销售总量</div>
<div style="padding: 10px 0;text-align:center;font-weight:bold">
¥1000000
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card style="color:#E6A23C">
<div><i class="el-icon-bank-card" />收益总额</div>
<div style="padding: 10px 0;text-align:center;font-weight:bold">
¥300000
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card style="color:#67C23A">
<div><i class="el-icon-s-shop" />门店总数</div>
<div style="padding: 10px 0;text-align:center;font-weight:bold">
20
</div>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<div id="main" style="width: 500px;height: 400px"></div>
</el-col>
<el-col :span="12">
<div id="pie" style="width: 500px;height: 400px"></div>
</el-col>
</el-row>
</div>
</template>
<script>
import * as echarts from 'echarts';
export default{
name:"Home",
data(){
return{
}
},
mounted(){ //页面元素渲染之后再触发
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option = {
title:{
text:'各季度用户注册人数统计',
subtext:'趋势图',
left:'center'
},
xAxis: {
type: 'category',
data: ["第一季度","第二季度","第三季度","第四季度"]
},
yAxis: {
type: 'value'
},
series: [
{
data: [],
type: 'line'
},
{
data: [],
type: 'bar'
}
]
};
this.request.get("/echarts/members").then(res=>{
//填空
option.series[0].data=res.data
option.series[1].data=res.data
//数据准备完毕再set
myChart.setOption(option);
pieOption.series[0].data=[
{name:"第一季度",value:res.data[0]},
{name:"第二季度",value:res.data[1]},
{name:"第三季度",value:res.data[2]},
{name:"第四季度",value:res.data[3]},
]
pieChart.setOption(pieOption);
})
//饼图
var pieDom = document.getElementById('pie');
var pieChart = echarts.init(pieDom);
var pieOption = {
title:{
text:'各季度用户注册人数统计',
subtext:'比例图',
left:'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
type: 'pie',
radius: '70%',
label:{//饼图图形上的文本标签
normal:{
show:true,
position:'inner',//标签位置
textStyle:{
fontWeight:300,
fontSize:16 //文件字体大小
},
formatter:'{d}%'
}
},
data: [],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
}
}
</script>
包括一个折线图+圆柱图,和一个饼图
模型图的数据都是从数据库里面查的,下面写请求的后端接口
- 写一个EchartsController
package com.xqh.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Quarter;
import com.xqh.common.Result;
import com.xqh.entity.User;
import com.xqh.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/echarts")
public class EchartsController {
@Autowired
private UserService userService;
//假数据
@GetMapping("/example")
public Result get(){
Map<String, Object> map = new HashMap<>();
map.put("x",CollUtil.newArrayList("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"));
map.put("y",CollUtil.newArrayList(150, 230, 224, 218, 135, 147, 260));
return Result.success(map);
}
//四个季度的注册的用户数据,从数据库中拿
@GetMapping("/members")
public Result members(){
List<User> list = userService.list();
int q1=0; //第一季度
int q2=0;
int q3=0;
int q4=0;
for (User user: list) {
Date createTime = user.getCreateTime();
Quarter quarter = DateUtil.quarterEnum(createTime);
switch(quarter){
case Q1:q1 +=1; break;
case Q2:q2 +=1; break;
case Q3:q3 +=1; break;
case Q4:q4 +=1; break;
default:break;
}
}
return Result.success(CollUtil.newArrayList(q1,q2,q3,q4));
}
}
- 我们需要补充一下数据库的数据,不然不好测试,因为写的是四个季度的,可以多补充一些不同创建时间的数据,我的是这样的:
- 去前端页面测试效果
- 可以根据自己的需求来搞首页。这里首页模型图里的数据都是真实从数据库中取的,可以看我的vue代码,一一对应上数据库中的数据。(首页最上面那四个框是写定的数据…那个需要根据真实业务来,我们现在还没有那么多业务)
- 可以正常展示,就完成了!