当前位置:   article > 正文

【6】【vue3+elementplus+springboot+mybatisplus】 管理系统 【前后端实践】_springboot postgresql vue3 源码

springboot postgresql vue3 源码

第一部分:

elementplus官网:一个 Vue 3 UI 框架 | Element Plus (element-plus.org)

1、安装elementplus

 npm install element-plus --save

 查看package.json中存在依赖表示成功安装

2、引入elementplus

  1. import ElementPlus from 'element-plus'
  2. import 'element-plus/dist/index.css'
  3. const app = createApp(App)
  4. app.use(ElementPlus)

注意:vue3不支持elementUI,所以选择以下搭配其中之一(这里我选的是2)

(1)vue2+elementUI

(2)vue3+elementPlus

3、使用组件设置布局

点击官网上方菜单栏的组件,点击

点击布局容器可以看到示例,我们选择使用最下面的侧边栏的示例代码

 

Container 布局容器 | Element Plus (element-plus.org)

 查看示例的代码,这里选择手动引入(elementplus还支持自动按需引入)

 代码主要分成四部分,第一部分我们需要放在template里面,第二部分是选择按需部分引入的方式,我们可以不管,第三部分是放在script里的data部分里面也就是提供页面的数据,具体填入形式如下

  1. <script >
  2. export default {
  3. name: "HomeView",
  4. data(){
  5. const item = {
  6. date: '2016-05-02',
  7. name: 'Tom',
  8. address: 'No. 189, Grove St, Los Angeles',
  9. };
  10. return {
  11. tableData : (Array.from({ length: 20 }).fill(item)),
  12. }
  13. }
  14. }
  15. </script>

第四部分是页面的样式,不重要,我们可以不使用

引入完成功编译运行后的结果:

4、在asserts文件夹里面创建一个global.css用来书写全局样式

 //global.css

  1. html,body,div{
  2. margin: 0;
  3. padding: 0;
  4. }
  5. html,body{
  6. height: 100%;
  7. }

然后再main.js里引入 (不要忘了加 ./ )

 将所有菜单的高度改成100% 这个时候滚动页面整个页面不会跟随滚动,菜单栏可以单独滚动

自行调整样式后:

第二部分

1、改变e-menu的背景颜色等一些属性

  1. <el-menu :default-openeds="['1', '3']" style="height: 100%;overflow-x:hidden"
  2. background-color="rgb(48,65,86)" //菜单背景设为藏蓝
  3. text-color="#fff" //字体设为白色
  4. active-text-color="#ffd04b" //选中后字体变成黄色
  5. :collapse-transition="false"
  6. :collapse="isCollapse" //设置初始被展开的属性为false(初始为折叠)
  7. >

效果:

 2、添加一些图标

先安装elementPlus图标:

npm install --save @element-plus/icons

到elementPlus官网图标下赋值图标标签代码

Icon 图标 | Element Plus (element-plus.org)

  1. <span>Tom
  2. <el-icon style="margin-left: 5px">
  3. <ArrowDownBold></ArrowDownBold>
  4. </el-icon>
  5. </span>

 效果:

 

编写收缩的方法

  1. methods: {
  2. collapse(){ //点击收缩按钮触发
  3. this.isCollapse=!this.isCollapse
  4. }
  5. }

此时收缩会出现问题,文字没有隐藏,宽度不对 

 所以需要将宽度设为动态的

 然后再将导航的名称都放在span标签里,就会自动收缩进去

然后更改如果收缩了,图标就改变,这里我用v-if和v-else的组合

再结合前面设置的isCollapse状态

使得图标可以切换

 效果:

     ------------------》

3、设置菜单栏标题:

  1. <div style="height: 60px;line-height: 60px;text-align: center">
  2. <img src="../assets/logo.png" alt="" style="width: 20px;position: relative;top:5px;margin-right: 5px">
  3. <b v-show="!isCollapse" style="color: white">后台管理系统</b>
  4. </div>

效果:

  ----------------------》

 linehight如果设置和垂直高度一致,就会居中,否则就会在上方或者下面

style="line-height: 60px"

效果: 

 ----------》

4、 阴影特效:

首先去掉e-menu的边框的颜色

border-right-color: transparent

再在e-side里面添加阴影属性

box-shadow: 2px 0 6px rgb(0 21 41 / 35%)

效果:

第三部分

1、设置表格页码数

 进到官网页面,pagination 

Pagination 分页 | Element Plus (element-plus.org)

 copy“完整功能”代码

黏贴在e-mian标签下的e-table下

  1. <div style="padding: 10px 0">
  2. <el-pagination
  3. v-model:current-page="currentPage4"
  4. v-model:page-size="pageSize4"
  5. :page-sizes="[100, 200, 300, 400]"
  6. :small="small"
  7. :disabled="disabled"
  8. :background="background"
  9. layout="total, sizes, prev, pager, next, jumper"
  10. :total="400"
  11. />
  12. </div>

此时可以看到底部的效果,并且还没有生效

2、设置搜索栏(一定要看script里面是否自动导入了输入框图标)

  1. <el-input style="width: 300px" type="text" placeholder="请输入名称">
  2. <template #prefix>
  3. <el-icon class="el-input__icon">
  4. <search></search>
  5. </el-icon>
  6. </template>
  7. </el-input>
  8. <el-button class="ml-5" type="" style="color: orangered">搜索</el-button>

效果:

 扩展多个输入框:

3、设置表头颜色和边框

 <el-table :data="tableData" border stripe >
  1. <style >
  2. .el-table th{
  3. background-color: beige !important
  4. }
  5. </style>

效果:

4、添加一些按钮:

增删导入导出

  1. <div style="margin: 10px 0;text-align: left">
  2. <el-button type="primary">新增
  3. <el-icon><CirclePlus></CirclePlus></el-icon>
  4. </el-button>
  5. <el-button type="danger">批量删除
  6. <el-icon><remove></remove></el-icon>
  7. </el-button>
  8. <el-button type="primary">导入
  9. <el-icon><bottom></bottom></el-icon>
  10. </el-button>
  11. <el-button type="primary">导出
  12. <el-icon><top></top></el-icon>
  13. </el-button>
  14. </div>

表格里的编辑、删除

  1. <el-table-column label="操作" >
  2. <el-table-column>
  3. <template>slot-scope="scope"</template>
  4. <el-button type="success">编辑
  5. <el-icon><edit></edit></el-icon>
  6. </el-button>
  7. <el-button type="danger">删除
  8. <el-icon><remove></remove></el-icon>
  9. </el-button>
  10. </el-table-column>
  11. </el-table-column>

最后的效果:

5、固定表头优化:

(108条消息) vue项目中table表格固定表头和首尾列_梨城毒妃的博客-CSDN博客_vue固定表头

   <el-table :data="tableData" border stripe height="500px" max-height="400px" >

 至此管理系统的前端雏形已经产生

第四部分

1、加一个页签

在官网的面包屑模块下:

Breadcrumb 面包屑 | Element Plus (element-plus.org)

  1. <div style="margin-bottom: 30px">
  2. <el-breadcrumb separator="/">
  3. <el-breadcrumb-item :to="{ path: '/' }">主页</el-breadcrumb-item>
  4. <el-breadcrumb-item :to="{path: '/new'}">用户管理</el-breadcrumb-item>
  5. <el-breadcrumb-item>promotion list</el-breadcrumb-item>
  6. <el-breadcrumb-item>promotion detail</el-breadcrumb-item>
  7. </el-breadcrumb>
  8. </div>

效果:

2、SpringBoot框架搭建

1、创建项目,引入lombok,mybatisplus,mysql等等依赖

后两个依赖在项目勾选时候可以自动导入,所以只用关注前面的

  1. <dependencies>
  2. <!-- lombok-->
  3. <dependency>
  4. <groupId>org.projectlombok</groupId>
  5. <artifactId>lombok</artifactId>
  6. <scope>provided</scope>
  7. </dependency>
  8. <!-- mybatisplus-->
  9. <dependency>
  10. <groupId>com.baomidou</groupId>
  11. <artifactId>mybatis-plus-boot-starter</artifactId>
  12. <version>3.4.1</version>
  13. </dependency>
  14. <dependency>
  15. <groupId>com.alibaba</groupId>
  16. <artifactId>druid</artifactId>
  17. <version>1.1.16</version>
  18. </dependency>
  19. <dependency>
  20. <groupId>com.mysql</groupId>
  21. <artifactId>mysql-connector-j</artifactId>
  22. <scope>runtime</scope>
  23. <version>8.0.31</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>com.baomidou</groupId>
  27. <artifactId>mybatis-plus-core</artifactId>
  28. <version>3.4.3.1</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-web</artifactId>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-starter-test</artifactId>
  37. <scope>test</scope>
  38. </dependency>
  39. </dependencies>

2、编写yml文件

  1. spring:
  2. datasource:
  3. type: com.alibaba.druid.pool.DruidDataSource
  4. driver-class-name: com.mysql.cj.jdbc.Driver
  5. url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
  6. username: root
  7. password: 123456
  8. main:
  9. banner-mode: off
  10. mybatis-plus:
  11. global-config:
  12. banner: false
  13. server:
  14. port: 8081

效果:

项目结构:

 测试springboot

3、数据库设计

建立表:sys_user

 写入数据:

建立包和实体接口

使接口继承BaseMapper,并注解为Mapper

 在写任何controller时候前面都要加一个注解:RestController

测试连接数据库

用lambdaquery来写查询

  1. @RequestMapping("/select") //访问路径
  2. public List<User> select(){
  3. LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
  4. // lqw.like(User::getUsername,'a');
  5. List<User> userList = userDao.selectList(lqw);
  6. return userList;
  7. }

结果:

4、springBoot使用MybastisPlus实现分页查询

先设置拦截器:(一定要把pom里面的所有关于mybatisplus的依赖的版本号改成一致的

 编写接口:

后来发现要加total,所以改成返回Map

  1. @GetMapping("/page")
  2. public List<User> fingPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize){
  3. pageNum = (pageNum-1)*pageSize;
  4. IPage page = new Page(pageNum,pageSize);
  5. userDao.selectPage(page, null);
  6. return page.getRecords();
  7. }

 用postman测试:(查出两条数据)

vue页面查看要传输的数据:

 编写传数据的方法:

  1. created() {
  2. //请求分页查询数据
  3. fetch("http://localhost:9090/user/page?pageNum=1&pageSize=2").then(res => res.json()).then(
  4. res =>{
  5. console.log(res)
  6. })
  7. },

查看,出现了跨域问题 (前端端口与后端端口不一致)

选择在后端处理跨域

最简单方法:在controller类名前加@CrossOrigin注解,这是最简单的处理方式

比较完善的方法:加入如下代码

(94条消息) SpringBoot解决跨域问题_程序员青戈的博客-CSDN博客_springboot解决跨域问题 青戈

 这个时候我们再次启动后台:此时控制台显示我们的数据获取成功

返回改成map后:(就分成了两组)

封装渲染时加载数据的代码为load

  1. load(){
  2. fetch("http://localhost:8081/page?pageNum="+this.pageNum+"&pageSize="+this.pageSize).then(res => res.json()).then(res => {
  3. console.log(res)
  4. this.tableData=res.data
  5. this.total=res.total
  6. })
  7. }

在created函数内调用load

  1. created() {
  2. //请求分页查询数据
  3. this.load()
  4. }

created函数:在页面刷新时,重新加载数据,在vue3中有一个setup()注意里面不能用method里的方法也不能使用this

 

 编写跟随页数更改跳转和重新渲染页面的两个方法:用于动态更改页码和显示数据数目

handleSizeChange(pageSize)
handleCurrentChange

  ​​​​​​Pagination 分页 | Element Plus (element-plus.org)

  1. handleSizeChange(pageSize){
  2. this.pageSize = pageSize
  3. this.load()
  4. },
  5. handleCurrentChange(pageNum){
  6. this.pageNum=pageNum
  7. this.load()
  8. }


效果:

至此页码的所有功能都已激活

第五部分

 绑定搜索框,返回搜索数据

增加查询的名称username关键字

  1. @GetMapping("/page")
  2. public Map<String,Object> fingPage(@RequestParam Integer pageNum,
  3. @RequestParam Integer pageSize,
  4. @RequestParam String username){
  5. pageNum = (pageNum-1)*pageSize;
  6. Page page = new Page(pageNum,pageSize);
  7. LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
  8. lqw.like(User::getUsername,username);
  9. userDao.selectPage(page, lqw);
  10. Map<String,Object> hm = new HashMap<>();
  11. hm.put("data",page.getRecords());
  12. hm.put("total",page.getTotal());
  13. return hm;
  14. // return userService.findAll();
  15. }

 我们可以看到我们写完QuerWrapper后可以直接填写到selectPage函数第二个参数里(原来为null)非常巧妙

 我们用postman输入参数尝试查询结果成功,注意此时我们并没有更改任何前端

我们成功后即可用v-model绑定前端的搜索框

 然后写入data()(默认为空),然后在fetch函数里添加username字段

 绑定前端搜索按钮事件为重新渲染数据

 第一个搜索框的功能已经激活成功

扩展多条件查询(将其它两个搜索框也激活)

总结上面一个框激活的流程:

1、在接口里增加查询的参数,并且增加querymapper对象的方法

2、用v-model绑定搜索框数据,并且绑定按钮渲染函数

3、在后端data增加参数,并且增加fectch渲染函数的参数

清楚了流程,我们做起来就事半功倍了

 

 

 至此多条件查询已激活所有搜索框

 

第六部分

激活新增,批量删除,导入,导出四个按钮 

驼峰映射是自动的,它会把下划线去掉并把下划线原来后面的字母大写

如:user_name->userName

用postman测试如果觉得复杂,可以用swaggerUI(一个接口测试文档)

(94条消息) SpringBoot集成swagger-ui以及swagger分组显示_程序员青戈的博客-CSDN博客_swagger ui 分组 第一步:

导入swagger依赖:

创建swaggerConfig类:

更改包的地址:

 我觉得还是postman好用

使用axios代替fetch (fetch太繁琐)

(94条消息) Vue项目搭建常用的配置文件,request.js和vue.config.js_程序员青戈的博客-CSDN博客_vue config.headers配置

安装axios

npm i axios -s

 新建utils文件夹,并新建js文件

 黏贴封装的request.js代码:

  1. import axios from 'axios'
  2. const request = axios.create({
  3. baseURL: '/api', // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,页面里面写接口的时候就不要加 '/api'了,否则会出现2'/api',类似 '/api/api/user'这样的报错,切记!!!
  4. timeout: 5000
  5. })
  6. // request 拦截器
  7. // 可以自请求发送前对请求做一些处理
  8. // 比如统一加token,对请求参数统一加密
  9. request.interceptors.request.use(config => {
  10. config.headers['Content-Type'] = 'application/json;charset=utf-8';
  11. // config.headers['token'] = user.token; // 设置请求头
  12. return config
  13. }, error => {
  14. return Promise.reject(error)
  15. });
  16. // response 拦截器
  17. // 可以在接口响应后统一处理结果
  18. request.interceptors.response.use(
  19. response => {
  20. let res = response.data;
  21. // 如果是返回的文件
  22. if (response.config.responseType === 'blob') {
  23. return res
  24. }
  25. // 兼容服务端返回的字符串数据
  26. if (typeof res === 'string') {
  27. res = res ? JSON.parse(res) : res
  28. }
  29. return res;
  30. },
  31. error => {
  32. console.log('err' + error) // for debug
  33. return Promise.reject(error)
  34. }
  35. )
  36. export default request

设置request为全局变量:

在vue2中用prototype设置,vue3中可以用app.config.globalProperties来代替prototype

(94条消息) vue 3.0 prototype 替代用法_寻ing的博客-CSDN博客_vue3 prototype

 我们使用axios后可以看到前后代码对比

使用前:

  1. fetch("http://localhost:8081/page?pageNum="+this.pageNum+"&pageSize="+this.pageSize+"&username="+this.username
  2. +"&email="+this.email+"&address="+this.address).then(res => res.json()).then(res => {
  3. console.log(res)
  4. this.tableData=res.data
  5. this.total=res.total
  6. })

 使用后:

  1. request.get("http://localhost:8081/page",{
  2. params:{
  3. pageNum:this.pageNum,
  4. pageSize:this.pageSize,
  5. username:this.username,
  6. email:this.email,
  7. address:this.address
  8. }
  9. }).then(res => {
  10. console.log(res)
  11. this.tableData= res.data
  12. this.total = res.total
  13. })

变得更加简洁,而且达到相同的功能效果

在查询后为了回复原来的页面,增加一个重置按钮

 编写reset方法,思路就是把表单清空,并重新渲染页面,超级简单

  1. reset(){
  2. this.username=""
  3. this.email=""
  4. this.address=""
  5. this.load()
  6. }

dialog对话框编写:

在elementplus官网黏贴代码

 Dialog 对话框 | Element Plus (element-plus.org)

  1. <el-dialog
  2. v-model="dialogVisible"
  3. title="Tips"
  4. width="30%"
  5. :before-close="handleClose"
  6. >
  7. <span>This is a message</span>
  8. <template #footer>
  9. <span class="dialog-footer">
  10. <el-button @click="dialogVisible = false">Cancel</el-button>
  11. <el-button type="primary" @click="dialogVisible = false">
  12. Confirm
  13. </el-button>
  14. </span>
  15. </template>
  16. </el-dialog>

选择下面的嵌套表单的代码

  1. <el-dialog v-model="dialogTableVisible" title="Shipping address">
  2. <el-table :data="gridData">
  3. <el-table-column property="date" label="Date" width="150" />
  4. <el-table-column property="name" label="Name" width="200" />
  5. <el-table-column property="address" label="Address" />
  6. </el-table>
  7. </el-dialog>
  8. <!-- Form -->
  9. <el-button text @click="dialogFormVisible = true">
  10. open a Form nested Dialog
  11. </el-button>
  12. <el-dialog v-model="dialogFormVisible" title="Shipping address">
  13. <el-form :model="form">
  14. <el-form-item label="Promotion name" :label-width="formLabelWidth">
  15. <el-input v-model="form.name" autocomplete="off" />
  16. </el-form-item>
  17. <el-form-item label="Zones" :label-width="formLabelWidth">
  18. <el-select v-model="form.region" placeholder="Please select a zone">
  19. <el-option label="Zone No.1" value="shanghai" />
  20. <el-option label="Zone No.2" value="beijing" />
  21. </el-select>
  22. </el-form-item>
  23. </el-form>
  24. <template #footer>
  25. <span class="dialog-footer">
  26. <el-button @click="dialogFormVisible = false">Cancel</el-button>
  27. <el-button type="primary" @click="dialogFormVisible = false">
  28. Confirm
  29. </el-button>
  30. </span>
  31. </template>
  32. </el-dialog>

 绑定新增按钮的事件handleAdd

 编写确认按钮的事件save

在这之前要先把接口写好

这里写一个业务层的save接口,然后放在controller里调用即可

 

然后我们设置id为自增规则,并且表数据为倒叙排序,此时我们新增数据功能就完成了:

注意:若想让数据按id倒叙排序,不能并列式的写LambdaQuery,要单独起一行

 我们输入数据即可在数据库中插入数据(id不是随机且自增)

 接下来我们来实现编辑按钮:

在vue3中不能使用 slot-scope 在vue3中用#相当于vue2中的slot=

(94条消息) vue3的slot插槽用法,`slot-scope` are deprecated_浩星的博客-CSDN博客_`slot-scope` are deprecated

 这个时候我们就可以打开这个数据的el-dialog 点击保存即可完成编辑

删除:

编写业务层接口:

 这里写错了,应该用RemoveById方法

编写控制层的接口:

 绑定删除按钮 注意要加id,血的教训

增加一个气泡弹出窗口用来确定是都真正删除

  1. <!-- 确认组件-->
  2. <el-popover :visible="visible" placement="top" :width="160" class="ml-5">
  3. <p>您确定删除吗?</p>
  4. <div style="text-align: right; margin: 0">
  5. <el-button size="small" text @click="visible = false">我再想想</el-button>
  6. <el-button size="small" type="primary" @click="handleDelete(scope.row.id)"
  7. >确认</el-button
  8. >
  9. </div>
  10. <template #reference>
  11. <el-button type="danger" >删除
  12. <el-icon><remove></remove></el-icon>
  13. </el-button>
  14. </template>
  15. </el-popover>

注意不要忘了在templete标签里写#reference 不然按钮会不显示  

多选: 

 

在e-table标签下加入一行代码,并且在e-table标签里写入

@selection-change="handleSelectionChange

 之后编写批量删除的接口

  1. //批量删除的接口
  2. @DeleteMapping("/del/batch")
  3. public boolean deleteBatch(@RequestBody List<Integer> ids){
  4. return userService.removeByIds(ids);
  5. }

在vue里编写delBatch方法

  1. delBatch(){
  2. let ids = this.multipleSelection.map(v => v.id)
  3. console.log(ids)//[{}.{}.{}] => [1,2,3]
  4. request.delete("http://localhost:8081/del/batch",{data:ids}).then(res => {
  5. if(res){
  6. this.$message.success("批量删除成功")
  7. }else{
  8. this.$message.error(("批量删除失败"))
  9. }
  10. this.load();
  11. })
  12. }

设置批量删除气泡弹窗,并绑定事件

  1. <!-- 确认组件-->
  2. <el-popover :visible="visible" placement="top" :width="160" class="ml-5">
  3. <p>您确定批量删除数据吗?</p>
  4. <div style="text-align: right; margin: 0">
  5. <el-button size="small" text @click="visible = false">我再想想</el-button>
  6. <el-button size="small" type="primary" @click="delBatch"
  7. >确认</el-button
  8. >
  9. </div>
  10. <template #reference>
  11. <el-button type="danger" >批量删除
  12. <el-icon><remove></remove></el-icon>
  13. </el-button>
  14. </template>
  15. </el-popover>

效果:

优化:

发现:如果不把load()重新加载数据放在最后一行,在新增操作保存后多选数据气泡窗口可能不显示

新增多选按钮,点击出现多选框,再次点击隐藏

给多选框绑定v-if

            <el-table-column v-if="letapear" type="selection" width="55" />

将letapear初始值默认为false

设置多选按钮 用双括号绑定名称

  1. <!-- 多选按钮-->
  2. <el-button type="info" @click="Apearselection">{{duoxuan}}
  3. <el-icon><CirclePlus></CirclePlus></el-icon>
  4. </el-button>

编写方法:

  1. Apearselection(){
  2. if(!this.letapear){
  3. this.letapear=true;
  4. this.duoxuan="取消多选"
  5. }else{
  6. this.letapear=false;
  7. this.duoxuan="多选"
  8. }
  9. }

效果:

---------------->

第七部分

 1、封装侧边栏

新建一个Aside.vue将以下代码(e-menu)从menage.vue移动到里面

  1. <el-menu :default-openeds="['1', '3']" style="height: 100%;overflow-x:hidden;border-right-color: transparent"
  2. background-color="rgb(48,65,86)"
  3. text-color="#fff"
  4. active-text-color="#ffd04b"
  5. :collapse-transition="false"
  6. :collapse="isCollapse"
  7. >
  8. <div style="height: 60px;line-height: 60px;text-align: center">
  9. <img src="../assets/logo.png" alt="" style="width: 20px;position: relative;top:5px;margin-right: 5px">
  10. <b v-show="!isCollapse" style="color: white">后台管理系统</b>
  11. </div>
  12. <el-sub-menu index="1">
  13. <template #title>
  14. <el-icon>
  15. <message></message>
  16. </el-icon>
  17. <span>导航一</span>
  18. </template>
  19. <el-menu-item-group>
  20. <template #title>Group 1</template>
  21. <el-menu-item index="1-1">Option 1</el-menu-item>
  22. <el-menu-item index="1-2">Option 2</el-menu-item>
  23. </el-menu-item-group>
  24. <el-menu-item-group title="Group 2">
  25. <el-menu-item index="1-3">Option 3</el-menu-item>
  26. </el-menu-item-group>
  27. <el-sub-menu index="1-4">
  28. <template #title>Option4</template>
  29. <el-menu-item index="1-4-1">Option 4-1</el-menu-item>
  30. </el-sub-menu>
  31. </el-sub-menu>
  32. <el-sub-menu index="2">
  33. <template #title>
  34. <el-icon>
  35. <Menu></Menu>
  36. </el-icon>
  37. <span>导航二</span>
  38. </template>
  39. <el-menu-item-group>
  40. <template #title>Group 1</template>
  41. <el-menu-item index="2-1">Option 1</el-menu-item>
  42. <el-menu-item index="2-2">Option 2</el-menu-item>
  43. </el-menu-item-group>
  44. <el-menu-item-group title="Group 2">
  45. <el-menu-item index="2-3">Option 3</el-menu-item>
  46. </el-menu-item-group>
  47. <el-sub-menu index="2-4">
  48. <template #title>Option 4</template>
  49. <el-menu-item index="2-4-1">Option 4-1</el-menu-item>
  50. </el-sub-menu>
  51. </el-sub-menu>
  52. <el-sub-menu index="3">
  53. <template #title>
  54. <el-icon>
  55. <Setting></Setting>
  56. </el-icon>
  57. <span>导航三</span>
  58. </template>
  59. <el-menu-item-group>
  60. <template #title>Group 1</template>
  61. <el-menu-item index="3-1">Option 1</el-menu-item>
  62. <el-menu-item index="3-2">Option 2</el-menu-item>
  63. </el-menu-item-group>
  64. <el-menu-item-group title="Group 2">
  65. <el-menu-item index="3-3">Option 3</el-menu-item>
  66. </el-menu-item-group>
  67. <el-sub-menu index="3-4">
  68. <template #title>Option 4</template>
  69. <el-menu-item index="3-4-1">Option 4-1</el-menu-item>
  70. </el-sub-menu>
  71. </el-sub-menu>
  72. </el-menu>

然后再AsideView里面编写props将用到的原来组件的参数传入进来,并且编写components将原来用到的组件传递过来

然后在原来的界面引入AsideView组件,并且使用该组件

 e-side我们就转移完毕了

 然后我们转移e-header

将e-header代码转移到HeaderView里面,然后将style样式做部分迁移,因为转移后,都放在外面不好使。

  1. <div style="text-align: left; font-size: 12px; line-height: 60px;
  2. display: flex">
  3. <div style="flex:1;font-size: 18px">
  4. <el-icon style="cursor: pointer" @click="collapse">
  5. <Fold v-if="isCollapse"></Fold>
  6. <Expand v-else></Expand>
  7. </el-icon>
  8. </div>
  9. <div class="toolbar">
  10. <el-dropdown style="width: 100px;cursor: pointer" >
  11. <span style="line-height: 60px">Tom
  12. <el-icon style="margin-left: 5px">
  13. <ArrowDownBold></ArrowDownBold>
  14. </el-icon>
  15. </span>
  16. <template #dropdown>
  17. <el-dropdown-menu>
  18. <el-dropdown-item>个人信息</el-dropdown-item>
  19. <el-dropdown-item>退出</el-dropdown-item>
  20. <el-dropdown-item>Delete</el-dropdown-item>
  21. </el-dropdown-menu>
  22. </template>
  23. </el-dropdown>
  24. </div>
  25. </div>

 然后本来collapse方法在原来的主vue里面,所以我们要定义一个方法,并且通过$emit

将本组件的请求发送过去:

 然后再在主vue引入我们的header,并且在header里面连接方法

 这样header就拆装完毕了

之后我们再把e-main拿出来单独封装

建立一个TableView.vue  

 之后将e-main里面的代码放在里面

  1. <template>
  2. <div style="margin-bottom: 30px">
  3. <el-breadcrumb separator="/">
  4. <el-breadcrumb-item :to="{ path: '/' }">主页</el-breadcrumb-item>
  5. <el-breadcrumb-item :to="{path: '/new'}">用户管理</el-breadcrumb-item>
  6. <el-breadcrumb-item>promotion list</el-breadcrumb-item>
  7. <el-breadcrumb-item>promotion detail</el-breadcrumb-item>
  8. </el-breadcrumb>
  9. </div>
  10. <div style="margin: 10px 0;text-align: left" >
  11. <!-- 名称搜索-->
  12. <el-input style="width: 200px" type="text" placeholder="请输入名称" v-model="username">
  13. <template #prefix>
  14. <el-icon class="el-input__icon">
  15. <search></search>
  16. </el-icon>
  17. </template>
  18. </el-input>
  19. <!-- 邮箱输入-->
  20. <el-input style="width: 200px" type="text" placeholder="请输入邮箱" class="ml-5" v-model="email">
  21. <template #prefix>
  22. <el-icon class="el-input__icon">
  23. <message></message>
  24. </el-icon>
  25. </template>
  26. </el-input>
  27. <!-- 地址搜索-->
  28. <el-input style="width: 200px" type="text" placeholder="请输入地址" class="ml-5" v-model="address">
  29. <template #prefix>
  30. <el-icon class="el-input__icon">
  31. <location></location>
  32. </el-icon>
  33. </template>
  34. </el-input>
  35. <!-- 搜索按钮-->
  36. <el-button class="ml-5" type="" style="color: orangered" @click="load">搜索</el-button>
  37. <el-button class="mr-5" type="warning" style="color: white" @click="reset">重置</el-button>
  38. </div>
  39. <div style="margin: 10px 0;text-align: left">
  40. <el-button type="primary" @click="handleAdd">新增
  41. <el-icon><CirclePlus></CirclePlus></el-icon>
  42. </el-button>
  43. <!-- 多选按钮-->
  44. <el-button type="info" @click="Apearselection">{{duoxuan}}
  45. <el-icon><CirclePlus></CirclePlus></el-icon>
  46. </el-button>
  47. <!-- 确认组件-->
  48. <el-popover :visible="visible" placement="top" :width="160" class="ml-5">
  49. <p>您确定批量删除数据吗?</p>
  50. <div style="text-align: right; margin: 0">
  51. <el-button size="small" text @click="visible = false">我再想想</el-button>
  52. <el-button size="small" type="primary" @click="delBatch"
  53. >确认</el-button
  54. >
  55. </div>
  56. <template #reference>
  57. <el-button type="danger" >批量删除
  58. <el-icon><remove></remove></el-icon>
  59. </el-button>
  60. </template>
  61. </el-popover>
  62. <el-button type="primary">导入
  63. <el-icon><bottom></bottom></el-icon>
  64. </el-button>
  65. <el-button type="primary">导出
  66. <el-icon><top></top></el-icon>
  67. </el-button>
  68. </div>
  69. <!-- <el-scrollbar>-->
  70. <el-table :data="tableData" border stripe height="500px" max-height="350px"
  71. @selection-change="handleSelectionChange">
  72. <!-- 多选框-->
  73. <el-table-column v-if="letapear" type="selection" width="55" />
  74. <el-table-column prop="id" label="ID" width="50" />
  75. <el-table-column prop="username" label="用户名" width="140" />
  76. <el-table-column prop="nickname" label="昵称" width="120" />
  77. <el-table-column prop="address" label="地址" />
  78. <el-table-column prop="email" label="邮箱" />
  79. <el-table-column prop="phone" label="电话" />
  80. <el-table-column label="操作" >
  81. <el-table-column>
  82. <template #default="scope">
  83. <el-button type="success" @click="handleEdit(scope.row)" >编辑
  84. <el-icon><edit></edit></el-icon>
  85. </el-button>
  86. <!-- 确认组件-->
  87. <el-popover :visible="visible" placement="top" :width="160" class="ml-5">
  88. <p>您确定删除吗?</p>
  89. <div style="text-align: right; margin: 0">
  90. <el-button size="small" text @click="visible = false">我再想想</el-button>
  91. <el-button size="small" type="primary" @click="handleDelete(scope.row.id)"
  92. >确认</el-button
  93. >
  94. </div>
  95. <template #reference>
  96. <el-button type="danger" >删除
  97. <el-icon><remove></remove></el-icon>
  98. </el-button>
  99. </template>
  100. </el-popover>
  101. </template>
  102. </el-table-column>
  103. </el-table-column>
  104. </el-table>
  105. <!-- 页尾-->
  106. <div style="padding: 10px 0">
  107. <el-pagination
  108. @size-change="handleSizeChange"
  109. @current-change="handleCurrentChange"
  110. :current-page="pageNum"
  111. :page-size="pageSize"
  112. :page-sizes="[2, 5, 10, 20]"
  113. :small="small"
  114. :disabled="disabled"
  115. :background="background"
  116. layout="total, sizes, prev, pager, next, jumper"
  117. :total="total">
  118. </el-pagination>
  119. </div>
  120. <!-- </el-scrollbar>-->
  121. <el-dialog title="用户信息" v-model="dialogFormVisible" width="30%">
  122. <el-form :model="form" label-width="80px" size="small">
  123. <el-form-item label="用户名" >
  124. <el-input v-model="form.username" autocomplete="off" />
  125. </el-form-item>
  126. <el-form-item label="昵称" >
  127. <el-input v-model="form.nickname" autocomplete="off" />
  128. </el-form-item>
  129. <el-form-item label="邮箱" >
  130. <el-input v-model="form.email" autocomplete="off" />
  131. </el-form-item>
  132. <el-form-item label="电话" >
  133. <el-input v-model="form.phone" autocomplete="off" />
  134. </el-form-item>
  135. <el-form-item label="地址" >
  136. <el-input v-model="form.address" autocomplete="off" />
  137. </el-form-item>
  138. </el-form>
  139. <template #footer>
  140. <span class="dialog-footer">
  141. <el-button @click="dialogFormVisible = false,this.load">取消</el-button>
  142. <el-button type="primary" @click="save">
  143. 确认
  144. </el-button>
  145. </span>
  146. </template>
  147. </el-dialog>
  148. </template>
  149. <script>
  150. import {Bottom, CirclePlus, Edit, Location, Message, Remove, Search, Top} from "@element-plus/icons";
  151. export default {
  152. name: "TableView",
  153. components: {
  154. Edit,
  155. Top,
  156. Bottom,
  157. Remove,
  158. CirclePlus,
  159. Location, Search,
  160. Message,
  161. },
  162. data(){
  163. // const item = {
  164. // date: '2016-05-02',
  165. // name: 'Tom',
  166. // address: 'No. 189, Grove St, Los Angeles',
  167. // };
  168. return {
  169. // tableData : (Array.from({ length: 20 }).fill(item)),
  170. tableData :[],
  171. pageNum:1,
  172. pageSize:2,
  173. total:0,
  174. username:"",
  175. email:"",
  176. address:"",
  177. isCollapse:true,
  178. sidewidth:200,
  179. dialogFormVisible:false,
  180. form:{},
  181. multipleSelection:[],
  182. letapear:false,
  183. duoxuan:"多选"
  184. }
  185. },
  186. created() {
  187. //请求分页查询数据
  188. this.load()
  189. },
  190. methods:{
  191. load(){
  192. this.request.get("http://localhost:8081/page",{
  193. params:{
  194. pageNum:this.pageNum,
  195. pageSize:this.pageSize,
  196. username:this.username,
  197. email:this.email,
  198. address:this.address
  199. }
  200. }).then(res => {
  201. console.log(res)
  202. this.tableData= res.data
  203. this.total = res.total
  204. })
  205. },
  206. save(){
  207. this.request.post("http://localhost:8081/save",this.form).then(res => {
  208. if(res){
  209. this.$message.success("保存成功")
  210. }else{
  211. this.$message.error(("保存失败"))
  212. }
  213. this.load();
  214. this.dialogFormVisible=false;
  215. })
  216. },
  217. handleSelectionChange(val){
  218. // console.log(val)
  219. this.multipleSelection = val;
  220. },
  221. handleAdd(){
  222. this.dialogFormVisible=true;
  223. this.form={}
  224. },
  225. handleEdit(row){
  226. this.dialogFormVisible=true;
  227. this.form = Object.assign({},row);
  228. },
  229. handleDelete(id){
  230. this.request.delete("http://localhost:8081/"+id).then(res => {
  231. if(res){
  232. this.$message.success("删除成功")
  233. }else{
  234. this.$message.error(("删除失败"))
  235. }
  236. this.load();
  237. })
  238. },
  239. delBatch(){
  240. let ids = this.multipleSelection.map(v => v.id)
  241. console.log(ids)//[{}.{}.{}] => [1,2,3]
  242. this.request.delete("http://localhost:8081/del/batch",{data:ids}).then(res => {
  243. if(res){
  244. this.$message.success("批量删除成功")
  245. }else{
  246. this.$message.error(("批量删除失败"))
  247. }
  248. this.load();
  249. })
  250. },
  251. Apearselection(){
  252. if(!this.letapear){
  253. this.letapear=true;
  254. this.duoxuan="取消多选"
  255. }else{
  256. this.letapear=false;
  257. this.duoxuan="多选"
  258. }
  259. },
  260. reset(){
  261. this.username=""
  262. this.email=""
  263. this.address=""
  264. this.load()
  265. },
  266. handleSizeChange(pageSize){
  267. this.pageSize = pageSize
  268. this.load()
  269. },
  270. handleCurrentChange(pageNum){
  271. this.pageNum=pageNum
  272. this.load()
  273. }
  274. }
  275. }
  276. </script>
  277. <style scoped>
  278. </style>

再把meanagor组件的大部分方法和属性和组件(除了折叠的方法,和用到的属性,其它都迁移到TableView里面)

然后把TableView放在路由里面:作为

它的子路由,这样就可以通过主路由加载子路由的方式拼装整个页面,这样侧边栏就会一直出现在页面里供我们操作 

我们也定义一个home放在里面当子路由:

 设置重定向:

 之后我们就可以通过路由入口的方式把路由入口router-view放在父组件需要加载子组件的地方

这样我们就可以通过访问子路由的方式 让整个页面加载

 

至此我们就把整个menager组件的所有功能拆分开成不同的组件,这样方便管理,方便维护更改

然后我们设置侧边栏点击可以跳转我们之前设置的两个路由界面:home,table

这个很简单我们只需要更改el-menu-item标签里的 index即可

 不过在此之前一定要记得把e-menu里面的router属性自己手动设为true ,它默认为false

 

 这样我们就实现了点击侧边栏跳转到我们设置的路由

 之后我们实现导入导出功能

这个功能要依赖于hutool,所以我们导入以下依赖

  1. <dependency>
  2. <groupId>cn.hutool</groupId>
  3. <artifactId>hutool-all</artifactId>
  4. <version>5.7.20</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.poi</groupId>
  8. <artifactId>poi-ooxml</artifactId>
  9. <version>4.1.2</version>
  10. </dependency>

hutool官网;https://www.wpsshop.cn/w/盐析白兔/article/detail/225805

推荐阅读
相关标签
  

闽ICP备14008679号