SpringBoot2+Vue2实战(十三)用户前台页面设计与实现

news2024/11/14 20:04:21

Front.vue

<template>
  <div>
    <!--头部-->
    <div style="display: flex; height: 60px;line-height: 60px;border-bottom: 1px solid #ccc">
      <div style="width: 300px;display: flex;padding-left: 30px">
        <div style="width: 60px">
          <img src="../../assets/logo1.png" alt="" style="width: 50px;position: relative;top: 5px;right: 0">
        </div>
        <span style="flex: 1">欢迎来到xx系统</span>
      </div>


      <div style="flex: 1">
        
        <el-menu :default-active="'1'" class="el-menu-demo" mode="horizontal">
          <el-menu-item index="1">处理中心</el-menu-item>
          <el-submenu index="2">
            <template slot="title">我的工作台</template>
            <el-menu-item index="2-1">选项1</el-menu-item>
            <el-menu-item index="2-2">选项2</el-menu-item>
            <el-menu-item index="2-3">选项3</el-menu-item>
            <el-submenu index="2-4">
              <template slot="title">选项4</template>
              <el-menu-item index="2-4-1">选项1</el-menu-item>
              <el-menu-item index="2-4-2">选项2</el-menu-item>
              <el-menu-item index="2-4-3">选项3</el-menu-item>
            </el-submenu>
          </el-submenu>
          <el-menu-item index="3" disabled>消息中心</el-menu-item>
          <el-menu-item index="4">订单管理</el-menu-item>
        </el-menu>
      </div>


      <div style="width: 200px">
        <div v-if="!user.username" style="text-align: right;padding-right: 30px">
          <el-button @click="$router.push('/login')">登录</el-button>
          <el-button @click="$router.push('/register')">注册</el-button>
        </div>
        <div v-else>
          <el-dropdown trigger="click" style="width: 150px; cursor: pointer;text-align:right">
            <div style="display: inline-block">
              <img :src="user.avatarUrl" referrerpolicy="no-referrer" 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="/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>
      </div>
    </div>


   <div style="width: 1000px;margin: 0 auto">
     <router-view/>
   </div>


  </div>
</template>

<script>
export default {
  name: "Front",
  data() {
    return {
      user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
    }
  },
  created() {
  },
  methods: {
    logout() {
      this.$store.commit("logout")
      this.$message.success("退出成功")
    }
  }
}
</script>

<style>

.item {
  display: inline-block;
  width: 100px;
  color: #1E90FF;
  text-align: center;
  cursor: pointer;
}

.item:hover {
  background-color: LightPink;
}

.item a {
  color: #1E90FF;
}
</style>

Front/Home.vue

<template>
  <div>
    <div style="margin: 10px  0 ">
      <el-carousel height="450px" :interval="10000">
        <el-carousel-item v-for="item in imgs " :key="item">
          <img :src="item" alt="" style="width: 100%">
        </el-carousel-item>
      </el-carousel>
    </div>

    <div style="margin: 10px 0">
      <el-row :gutter="10">
        <el-col :span="6">

        </el-col>
        <el-col :span="6">

        </el-col>
        <el-col :span="6">

        </el-col>
        <el-col :span="6">

        </el-col>
      </el-row>
    </div>


  </div>
</template>

<script>
export default {
  name: "FrontHome",
  data() {
    return {
      imgs: [
        'https://img.zcool.cn/community/01a3ac554552c80000019ae94606ed.jpg?x-oss-process=image/auto-orient,1/resize,m_lfit,w_1280,limit_1/sharpen,100',
        'https://img0.baidu.com/it/u=4046160075,3620795722&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1688835600&t=1e123cac27815414376ce5c302027d8b'
      ]
    }
  }
}
</script>

<style scoped>

</style>

router/index.js

{
        path: '/front',
        name: 'Front',
        component: () => import('../views/front/Front.vue'),
        children:[
            {
                path: 'home',
                name: 'FrontHome',
                component: () => import('../views/front/Home.vue')
            },
        ]
    },

Login.vue

使得学生只能访问前台页面

login() {
      this.$refs['userForm'].validate((valid) => {
        if (valid) {  // 表单校验合法
          this.request.post("/user/login", this.user).then(res => {
            if (res.code === '200') {
              //存储用户信息到浏览器
              localStorage.setItem("user", JSON.stringify(res.data))
              localStorage.setItem("menus", JSON.stringify(res.data.menus))
              //动态设置当前用户的路由
              setRoutes()
              this.$message.success("登录成功")

              if (res.data.role === 'ROLE_STUDENT') {
                this.$router.push("/front/home")
              } else {
                this.$router.push("/")
              }
            } else {
              this.$message.error(res.msg)
            }
          })
        }
      });
    }

一、接口放开

第一种方法 

jwt拦截

InterceptorConfig
//放行
                .excludePathPatterns("/user/login","/user/register","/**/export","/**/import","/file/**");

FileController 

@GetMapping("/find/all")
    public Result frontAll(){
        return Result.success(fileMapper.selectList(null));
    }

 

 第二种方法

 自定义注解

AuthAccess

package com.example.springboot.config;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthAccess {


}

EchartsController

@Resource
    private FileMapper fileMapper;




@AuthAccess
    @GetMapping("/file/front/all")
    public Result frontAll(){
        return Result.success(fileMapper.selectList(null));
    }
JwtInterceptor进行判断是否加了注解,加了就放行
if (!(handler instanceof  HandlerMethod)){
            return true;
        }else {
            HandlerMethod h  = (HandlerMethod) handler;
            AuthAccess authAccess = h.getMethodAnnotation(AuthAccess.class);
            if (authAccess != null){
                return true;
            }
        }

front/Home.vue

<div>
    <div style="margin: 10px  0 ">
      <el-carousel height="450px" :interval="10000">
        <el-carousel-item v-for="item in imgs " :key="item">
          <img :src="item" alt="" style="width: 100%">
        </el-carousel-item>
      </el-carousel>
    </div>

    <div style="margin: 10px 0">
      <el-row :gutter="10">
        <el-col :span="6" v-for="item in files" :key="item.id" style="margin-bottom: 10px">

          <div style="padding-bottom: 10px;border: 1px solid #ccc">
            <img :src="item.url" alt="" style="width: 200px ;height: 200px">
            <div style="color: #666;padding: 10px">{{ item.name }}</div>
            <div style="padding: 10px">
              <el-button type="primary">购买</el-button>
            </div>
          </div>
        </el-col>
      </el-row>
    </div>


  </div>
</template>

<script>
export default {
  name: "FrontHome",
  data() {
    return {
      imgs: [
        'https://img.zcool.cn/community/01a3ac554552c80000019ae94606ed.jpg?x-oss-process=image/auto-orient,1/resize,m_lfit,w_1280,limit_1/sharpen,100',
        'https://img0.baidu.com/it/u=4046160075,3620795722&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1688835600&t=1e123cac27815414376ce5c302027d8b'
      ],
      files: []
    }
  },
  created() {
    this.request.get("/echarts/file/front/all").then(res => {
      this.files = res.data.filter(v => v.type === 'png' || v.type === 'jpg' || v.type === 'webp')
    })
  },
  methods: {}
}
</script>

<style scoped>

</style>

添加一个个人信息界面

Front.vue

<el-dropdown-item style="font-size: 14px; padding: 5px 0">
                <router-link to="/front/person" style="text-decoration: none">个人信息</router-link>
              </el-dropdown-item>

front/Person.vue

<template>
  <el-card style="width: 500px;">
    <el-form label-width="80px" size="small">
      <el-upload

          class="avatar-uploader"
          action="http://localhost:9090/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" disabled autocomplete="off"></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: "FrontPerson",
  data() {
    return {
      form: {},
      user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}
    }
  },
  created() {
    this.getUser().then(res => {
      this.form = res
    })
  },
  methods: {
    async getUser() {
      return (await this.request.get("/user/findUserName/" + this.user.username)).data
    },
    save() {
      this.request.post("/user/saveUser", 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>

router/index.js

{
                path: 'person',
                name: 'FrontPerson',
                component: () => import('../views/front/Person.vue')
            },

处理更新头像后不刷新问题

Front.vue

<div style="width: 1000px;margin: 0 auto">
     <router-view @refreshUser="getUser"/>
   </div>




created() {
    this.getUser()
  },




getUser() {
      let username = localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")).username : ""
      //从后台获取数据
      this.request.get("user/findUserName/" + username).then(res => {
        //重新赋值后台的最新数据
        this.user = res.data
      })
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/728329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CENTOS上的网络安全工具(二十七)SPARK+NetSA Security Tools容器化部署(3)

上回说到在我们搭好的YAF3环境上使用yaf处理pcap文件得到silk flow&#xff0c;再使用super mediator工具转为ipfix&#xff0c;继而在spark中导入mothra&#xff0c;就可以开始数据分析了。然而在我们粗粗一用之下&#xff0c;却发现DPI信息在ipfix文件中找不到&#xff0c;到…

【Excel】csv乱码

原因 CSV用UTF-8编码 Excel用ANSI编码 解决 1 创建一个新的Excel 2 数据 > 从文本/CSV 3 选择文件 4 选择 文件原始格式 和 分隔符 &#xff08;根据自己文件进行选择&#xff0c;如果不知道编码&#xff0c;可以一个一个的试&#xff0c;直到不出现乱码&#xff09;

【Go|第5期】Lorca无法正常运行的解决方案

日期&#xff1a;2023年7月5日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xff…

奇怪的SQL问题+1

我的 VIP 用户又抛给我一个 SQL 问题&#xff0c;我很激动&#xff0c;因为素材又来了&#xff1a; 我一看&#xff0c;这个表没什么花头&#xff0c;不就是没设置主键吗&#xff0c;MySQL 会默认生成一个主键&#xff0c;这跟 delete 不掉数据好像也没啥关系。 然后他说&…

事件监听及DOM操作

1.页面内容实现 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>常见事件案例</title> </head> <body><img id"light" src"img/off.gif"> <br><…

红黑树的介绍

红黑树 1.红黑树的概念2. 红黑树的性质3. 红黑树的结点定义4. 红黑树的插入操作情况一: cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u存在且为红情况二: cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u不存在/u存在且为黑情况三: cur为红&#xff0c;p为…

Distributional Graphormer:从分子结构预测到平衡分布预测

编者按&#xff1a;近年来&#xff0c;深度学习技术在分子微观结构预测中取得了巨大的进展。然而&#xff0c;分子的宏观属性和功能往往取决于分子结构在平衡态下的分布&#xff0c;仅了解分子的微观结构还远远不够。在传统的统计力学中&#xff0c;分子动力学模拟或增强采样等…

【计算机视觉 | 目标检测】arxiv 计算机视觉关于目标检测的学术速递(7 月 6 日论文合集)

文章目录 一、检测相关(16篇)1.1 Large-scale Detection of Marine Debris in Coastal Areas with Sentinel-21.2 Unbalanced Optimal Transport: A Unified Framework for Object Detection1.3 Detecting Images Generated by Deep Diffusion Models using their Local Intrin…

Oracle单行函数(字符,数值,日期,转换)

Oracle单行函数&#xff08;字符&#xff0c;数值&#xff0c;日期&#xff0c;转换&#xff09; 前言 1、字符函数 1.1大小写转换函数 1.2连接字符串X和concat(X,Y) 1.3ASCII码与字符转换 1.4返回字符串索引位置&#xff1a;instr(x,str) 1.5返回字符串长度&#xff1a;length…

使用Plotly创建自定义指标图表

大家好&#xff0c;使用Plotly可以创建和自定义指标图表&#xff0c;本文中将介绍如何使用Plotly库创建指标图表的具体操作步骤。 Plotly简介 Plotly是一个强大的数据可视化工具&#xff0c;允许我们使用Python创建各种交互式绘图和图表。在Plotly提供的无数类型的图表中&…

【MySQL】MySQL里程碑

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️MySQL】 文章目录 时间表从产品特性的角度梳理其发展过程中了解MySQL里程碑事件 时间表 从产品特性的角度梳理其发展过程中了解MySQL里程碑事件 1995年&#xff0c;MySQL 1.0发布&#xff0c;仅供内…

【LeetCode周赛】2022上半年题目精选集——贪心

文章目录 2136. 全部开花的最早一天&#xff08;贪心&#xff09;⭐⭐⭐⭐⭐思路代码语法解析&#xff1a;Integer[] id IntStream.range(0, plantTime.length).boxed().toArray(Integer[]::new); 2141. 同时运行 N 台电脑的最长时间&#xff08;贪心&#xff09;⭐⭐⭐⭐⭐解…

一分钟带你创建百万测试数据,玩转软件测试

准备测试数据是软件测试中非常重要的一个环节&#xff0c;无论是手工测试、动化测试还是性能测试&#xff0c;生成大量测试数据以评估性能是一项重要任务。 然而&#xff0c;寻找合适的测试数据并确保其质量常常是一项繁琐且耗时的工作。 先来看一下准备测试数据常见的四类方法…

Vue 实时显示时间

Vue 实时显示时间 getNowTime() {setInterval(() > {const date new Date();var year date.getFullYear();var month (date.getMonth() 1).toString().padStart(2, "0");var day date.getDate().toString().padStart(2, "0");var hours date.ge…

人工智能商业变现途径,并介绍详细公司案列

目录 1. 推荐系统&#xff1a;2. 智能广告和营销&#xff1a;3. 聊天机器人和虚拟助手&#xff1a;4. 自动化和机器人化&#xff1a;5. 数据分析和预测&#xff1a;6. 机器视觉和图像识别&#xff1a;7. 金融科技&#xff08;FinTech&#xff09;&#xff1a;8. 医疗诊断和健康…

【成长之路】nginx配置https遇到的一系列问题

问题一&#xff1a;拿到手的文件并没有网上说的crt和key&#xff0c;而是一个cer、key和csr 按照网上说的&#xff0c;将cer转成pem文件&#xff0c;配置之后确实好使了 server {listen 443 ssl;ssl_certificate /opt/nginx/conf/域名.cer;ssl_certificate_key /opt/nginx/co…

诚迈科技董事长、统信软件董事长王继平出席全球数字经济大会

7月5日&#xff0c;2023全球数字经济大会“数字未来新一代软件产业高质量发展论坛”在北京大兴隆重举行。论坛以“数字新高地&#xff0c;数创兴未来”为主题&#xff0c;共同探讨产业升级新路径&#xff0c;凝聚数字经济合作新共识&#xff0c;构建数字产业集聚发展新高地。诚…

python接口自动化之DDT数据驱动测试

一、简单介绍 DDT&#xff08;Date Driver Test&#xff09;&#xff0c;所谓数据驱动测试&#xff0c;简单来说就是由数据的改变从而驱动自动化测试的执行&#xff0c;最终引起测试结果的改变。通过使用数据驱动测试的方法&#xff0c;可以在需要验证多组数据测试场景中&…

YApi-高效、易用、功能强大的可视化接口管理平台——(二)YApi 分组权限

YApi 分组权限 认识 YApi角色划分项目权限分组权限分组操作创建分组项目列表添加成员分组删除 认识 YApi YApi 是一个开源的接口管理平台&#xff0c;可以方便地管理和测试 API 接口&#xff0c;支持接口文档自动生成、Mock 数据生成、接口测试和接口监控等功能。YApi 支持多人…

TCP 协议报文

TCP 提供面向连接的通信传输&#xff0c;面向连接是指在传送数据之前必须先建立连接&#xff0c;数据传送完成后要释放连接。无论哪一方向另一方发送数据之前&#xff0c;都必须先在双方之间建立一条连接。在TCP/IP协议中&#xff0c;TCP协议提供可靠的连接服务&#xff0c;连接…