SpringBoot3+vue3实现增删改查,分页查询,批量删除

安装axios封装前后端对接数据工具

1
npm i axios -s 

其中-s参数的作用是减少npm的输出信息,使其保持静默模式。也就是说,npm在这种模式下不会显示详细的安装过程,只会显示错误信息。所以用户可能没有看到任何输出,但实际上安装可能已经成功了。

检查是否成功:

1
dir node_modules\axios

简单测试axios

1
2
3
axios.get("http://localhost:9999/admin/selectAll").then(res => {
console.log(res)
})

跨域处理

image-20250228160939144.png

在Springboot里面设置统一的跨域处理

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
package com.yjy.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
* 跨域配置
*/
@Configuration
public class CorsConfig {

@Bean
public CorsFilter corsFilter(){
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");//1.设置访问源地址
corsConfiguration.addAllowedHeader("*");//2.设置访问源请求头
corsConfiguration.addAllowedMethod("*");//3.设置访问源请求方法
source.registerCorsConfiguration("/**",corsConfiguration);//4.对接口配置跨域设置
return new CorsFilter(source);
}
}

封装统一的请求工具request.js

在src下新建一个文件夹utils,然后新建一个文件

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
import axios from "axios";
import {ElMessage} from "element-plus";//弹窗提示
/*
这段代码的作用是 创建一个基于 axios 的 HTTP 请求客户端,并添加统一的请求/响应拦截处理 ,主要用于 Vue/Element-Plus 项目的 API 调用

*/
//(1) 创建 axios 实例
const request = axios.create({
baseURL: 'http://localhost:9999', // 服务端接口基础地址(注意:协议部分应为 http: 或 https:)
timeout: 30000 // 请求超时时间(30秒)
})

//request 拦截器
//可以自请求发送对请求做一些处理
/*
作用 :在请求发送前统一设置请求头:
强制所有请求使用 application/json 格式提交数据。
可扩展性:可在此处添加 token 认证、请求参数加密等逻辑。
*/
request.interceptors.request.use(config => {
config.headers['Content-Type']='application/json;charset=utf-8';
return config
},error => {
return Promise.reject(error)
});

//response 拦截器
//可以在接口响应后统一处理结果
/*
响应处理 :
自动解析字符串格式的响应数据为 JSON 对象。
直接返回 response.data,省去后续代码中手动获取数据的步骤。
错误处理 :
404 错误 :提示 "未找到请求接口"。
500 错误 :提示后端系统异常。
其他错误 :控制台输出错误信息,便于调试。
*/
request.interceptors.response.use(
response=>{
let res = response.data;
//兼容服务端返回的字符串数据
if(typeof res === 'string'){
res = res?JSON.parse(res):res
}
return res;
},
error => {
if(error.response.status === 404){
ElMessage.error("未找到请求接口")
}else if(error.response.status===500) {
ElMessage.error("系统异常,请查看后端控制台报错")
}else{
console.error(error.message)
}
return Promise.reject(error)
}
)

export default request

使用request工具发起一次请求

1
2
3
4
5
6
7
request.get('/admin/selectAll').then(res=>{
if(res.code==='200'){
console.log(res);
}else{
ElMessage.error(res,msg)
}
})

分页查询

分页对象

total: 总的个数

list: 返回的数据数组

pageNum: 当前的页码

pageSize: 每页展示的个数

使用PageHelper 插件

在pom.xml里添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
<!--分页插件pageHelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-starter</artifactId>
<version>1.4.6</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>

AdminController.java

1
2
3
4
5
6
7
8
9
10
11
/**
* 分页查询
* pageNum: 当前的页码
* pageSize: 每页的个数
*/
@GetMapping("/selectPage")
public Result selectPage(@RequestParam(defaultValue = "1")Integer pageNum,
@RequestParam(defaultValue = "10")Integer pageSize){
adminService.selectPage(pageNum,pageSize);
return Result.success(); //返回的是分页的对象
}

AdminService.java

1
2
3
4
5
6
public PageInfo<Admin> selectPage(Integer pageNum, Integer pageSize) {
//开启分页查询
PageHelper.startPage(pageNum,pageSize);
List<Admin> admins = adminMapper.selectAll();
return PageInfo.of(admins);
}

修改前端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--  菜单区域开始  -->
<div style="width: 240px; box-shadow: 0 0 8px rgba(0,0,0,.12)">
<!-- :default-openeds="['1']" : 默认展开 -->
<el-menu router :default-active="router.currentRoute.value.path" style="min-height: calc(100vh - 60px)">
<el-menu-item index="/manager/home">
<el-icon><House /></el-icon>
<span>Home</span>
</el-menu-item>
<el-sub-menu index="1">
<template #title>
<el-icon><location /></el-icon>
<span>User Management</span>
</template>
<el-menu-item index="/manager/admin">Administrator information
</el-menu-item>
</el-sub-menu>
</el-menu>
</div>
<!-- 菜单区域结束 -->

然后将Home.vue改为Admin.vue,然后再去创建一个新的Home.vue

1
2
3
4
5
<template>
<div>
<div class="card">泥嚎!欢迎使用本系统!</div>
</div>
</template>

修改index.js

1
2
3
4
5
6
7
8
9
10
11
12
routes: [
{path: '/',redirect: '/manager/home'},
{path: '/manager', component: import('../views/Manager.vue'),
children: [
{path: 'home', component: import('../views/Home.vue'),},
{path: 'admin', component: import('../views/Admin.vue'),},
]
},
// {path: '/manager/about', component: import('../views/About.vue'),},
{path: '/notFound', component: import('../views/404.vue'),},
{path: '/:pathMatch(.*)',redirect: '/notFound'}
],

然后可以把About.vue删除了

package.json中有一个"vite-plugin-vue-devtools"可以卸载掉 因为没啥用

1
npm uninstall vite-plugin-vue-devtools

删除vite.config.js中的这一行

image-20250301083240234.png

还有plugins中vue()下的vueDevTools()

这样能够让速度速度变快

后端返回的分页对象

image-20250301103648448.png

排查问题: 页面数据少了,不展示怎么办?

看网络请求的数据对不对,发现传输的数据没有name字段

修改Admin.vue

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
<template>
<div>
<div class="card" style="margin-bottom: 5px">
<el-input style="width: 240px;margin-right: 5px;" v-model="input" placeholder="请输入名称查询" :prefix-icon="Search"></el-input>
<el-button type="primary">查询</el-button>
</div>

<div class="card" style="margin-bottom: 5px">
<el-button type="danger">批量删除</el-button>
<el-button type="primary">新 增</el-button>
<el-button type="success">批量导入</el-button>
<el-button type="info">批量导出</el-button>
</div>

<div class="card" style="margin-bottom: 5px">
<el-table :data="data.tableData" style="width: 100%" :header-cell-style="{fontWeight: 'bold',color: '#333',backgroundColor: '#c902f6'}">
<el-table-column prop="username" label="账号"/>
<el-table-column prop="name" label="名称" />
<el-table-column prop="phone" label="电话" />
<el-table-column prop="email" label="邮箱" />
</el-table>
</div>

<!-- 分页-->
<div class="card">
<el-pagination
v-model:current-page="data.pageNum"
:page-size="data.pageSize"
layout="total, prev, pager, next"
:total="data.total"
@current-change="load"

/>
</div>
</div>

</template>

<script setup>
import {reactive} from "vue";
import {Search} from "@element-plus/icons-vue";
import axios from "axios";
import request from "@/utils/request.js";
import {ElMessage} from "element-plus";

const data = reactive({
name: null,
pageNum: 1,
pageSize: 5,
total: 0,
tableData: []
})


const load = () => {
request.get('/admin/selectPage',{
params: {
pageNum: data.pageNum,
pageSize: data.pageSize
}
}).then(res=>{
// console.log(res.data)
data.tableData = res.data.list;
data.total = res.data.total;
})
}
load()
</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
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
<template>
<div>
<div class="card" style="margin-bottom: 5px">
<el-input style="width: 240px;margin-right: 5px;" v-model="data.name" placeholder="请输入名称查询" :prefix-icon="Search"></el-input>
<el-button type="primary">查询</el-button>
</div>

<div class="card" style="margin-bottom: 5px">
<el-button type="danger">批量删除</el-button>
<el-button type="primary">新 增</el-button>
<el-button type="success">批量导入</el-button>
<el-button type="info">批量导出</el-button>
</div>

<div class="card" style="margin-bottom: 5px">
<el-table :data="data.tableData" style="width: 100%" :header-cell-style="{fontWeight: 'bold',color: '#333',backgroundColor: '#c902f6'}">
<el-table-column prop="username" label="账号"/>
<el-table-column prop="name" label="名称" />
<el-table-column prop="phone" label="电话" />
<el-table-column prop="email" label="邮箱" />
</el-table>
</div>

<!-- 分页-->
<div class="card">
<el-pagination
v-model:current-page="data.pageNum"
v-model:page-size="data.pageSize"
:page-size="data.pageSize"
layout="total,sizes, prev, pager, next,jumper"
:page-sizes="[5,10,20]"
:total="data.total"
@current-change="load"
@size-change="load"

/>
</div>
</div>

</template>

<script setup>
import {reactive} from "vue";
import {Search} from "@element-plus/icons-vue";
import axios from "axios";
import request from "@/utils/request.js";
import {ElMessage} from "element-plus";

const data = reactive({
name: null,
pageNum: 1,
pageSize: 5,
total: 0,
tableData: []
})


const load = () => {
request.get('/admin/selectPage',{
params: {
pageNum: data.pageNum,
pageSize: data.pageSize
}
}).then(res=>{
if(res.code === '200'){
data.tableData = res.data.list;
data.total = res.data.total;
}else{
ElMessage.error(res.msg);
}
})
}
load()
</script>


本节要做到下面的效果:

分页条件模糊查询

image-20250303073555314.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yjy.mapper.AdminMapper">
<select id="selectAll" resultType="com.yjy.entity.Admin">
SELECT * FROM `admin`
<where>
<if test="name != null and name != ''">
name LIKE CONCAT('%', #{name}, '%')
</if>

<if test="username != null and username != ''">
and username LIKE CONCAT('%', #{username}, '%')
</if>
</where>
ORDER BY id DESC
</select>

</mapper>

vue的调用:

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
const data = reactive({
username: null,
name: null,
pageNum: 1,
pageSize: 5,
total: 0,
tableData: [],
})


const load = () => {
request.get('/admin/selectPage',{
params: {
pageNum: data.pageNum,
pageSize: data.pageSize,
name: data.name,
username: data.username
}
}).then(res=>{
if(res.code === '200'){
data.tableData = res.data.list;
data.total = res.data.total;
}else{
ElMessage.error(res.msg);
}
})
}
load()

const reset = () => {
data.name = null
load()
}

本节课代码案例:

Admin.vue

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
<template>
<div>
<div class="card" style="margin-bottom: 5px">
<!-- 加上clearable这个属性可以快速清除也就是那个叉叉顺便刷新一下 v-model="data.name" 将输入的文字显示到输入框内-->
<el-input clearable @clear="load" style="width: 240px;margin-right: 5px;" v-model="data.name" placeholder="请输入名称查询" :prefix-icon="Search"></el-input>
<el-input clearable @clear="load" style="width: 240px;margin-right: 5px;" v-model="data.username" placeholder="请输入账号查询" :prefix-icon="Search"></el-input>
<el-button type="primary" @click="load">查 询</el-button>
<el-button @click="reset">重 置</el-button>
</div>

<div class="card" style="margin-bottom: 5px">
<el-button type="danger">批量删除</el-button>
<el-button type="primary">新 增</el-button>
<el-button type="success">批量导入</el-button>
<el-button type="info">批量导出</el-button>
</div>

<div class="card" style="margin-bottom: 5px">
<el-table :data="data.tableData" style="width: 100%" :header-cell-style="{fontWeight: 'bold',color: '#333',backgroundColor: '#c902f6'}">
<el-table-column prop="username" label="账号"/>
<el-table-column prop="name" label="名称" />
<el-table-column prop="phone" label="电话" />
<el-table-column prop="email" label="邮箱" />
</el-table>
</div>

<!-- 分页-->
<div class="card">
<el-pagination
v-model:current-page="data.pageNum"
v-model:page-size="data.pageSize"
:page-size="data.pageSize"
layout="total,sizes, prev, pager, next,jumper"
:page-sizes="[5,10,20]"
:total="data.total"
@current-change="load"
@size-change="load"

/>
</div>
</div>

</template>

<script setup>
import {reactive} from "vue";
import {Search} from "@element-plus/icons-vue";
import axios from "axios";
import request from "@/utils/request.js";
import {ElMessage} from "element-plus";

const data = reactive({
username: null,
name: null,
pageNum: 1,
pageSize: 5,
total: 0,
tableData: [],
})


const load = () => {
request.get('/admin/selectPage',{
params: {
pageNum: data.pageNum,
pageSize: data.pageSize,
name: data.name,
username: data.username
}
}).then(res=>{
if(res.code === '200'){
data.tableData = res.data.list;
data.total = res.data.total;
}else{
ElMessage.error(res.msg);
}
})
}
load()

const reset = () => {
data.name = null
load()
}
</script>

AdminController.java

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
package com.yjy.controller;

import com.github.pagehelper.PageInfo;
import com.yjy.common.Result;
import com.yjy.entity.Admin;
import com.yjy.service.AdminService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/admin")
public class AdminController {

@Resource
AdminService adminService;

@GetMapping("/selectAll")
public Result selectAll(){
List<Admin> admins = adminService.selectAll();
return Result.success(admins);
}

/**
* 分页查询
* pageNum: 当前的页码
* pageSize: 每页的个数
*/
@GetMapping("/selectPage")
public Result selectPage(@RequestParam(defaultValue = "1")Integer pageNum,
@RequestParam(defaultValue = "10")Integer pageSize,
Admin admin)
{
//@RequestParam(required = false)String name){//也可以Admin admin
PageInfo<Admin> adminPageInfo = adminService.selectPage(pageNum, pageSize,admin);
return Result.success(adminPageInfo); //返回的是分页的对象
}
}

adminService.java

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
package com.yjy.service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yjy.entity.Admin;
import com.yjy.exception.CustomerException;
import com.yjy.mapper.AdminMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class AdminService {
@Resource
AdminMapper adminMapper;

public String admin(String name) {
if("admin".equals(name)){
return "admin";
}else{
// return "账号错误";//自定义异常
throw new CustomerException("账号错误!");
}
}

public List<Admin> selectAll(){
return adminMapper.selectAll(null);
}

public PageInfo<Admin> selectPage(Integer pageNum, Integer pageSize,Admin admin) {
//开启分页查询
PageHelper.startPage(pageNum,pageSize);
List<Admin> admins = adminMapper.selectAll(admin);
return PageInfo.of(admins);
}
}

ctrl+Alt+o可以删除无效的导包

image-20250303075011812.png

解决方案 :

router/index,js

1
2
3
4
5
6
7
8
9
10
11
routes: [
{path: '/',redirect: '/manager/home'},
{path: '/manager', component:() =>import('../views/Manager.vue'),
children: [
{path: 'home',meta:{name:'主页'}, component:() =>import('../views/Home.vue'),},
{path: 'admin',meta:{name:'管理员信息'}, component:() =>import('../views/Admin.vue'),},
]
},
// {path: '/manager/about', component: import('../views/About.vue'),},
{path: '/notFound', component: import('../views/404.vue'),},
{path: '/:pathMatch(.*)',redirect: '/notFound'}

新增数据

1.在新增的按钮上加上点击事件

2.定义弹窗和表单的页面代码

3.点击触发弹窗打开 (form 对象清空)

4.弹窗里面的内容就是表单

5.表单做一下数据绑定以及表单验证

6.后台要有对应新增的接口来接受数据

7.新增的接口负责把数据插入到数据库里面

8.表达输入数据后点击确认按钮,把表单的数据传给后台接口

9.在新增之后再次加载表格的数据,关闭弹窗

Dialog弹窗

1
2
3
4
5
6
7
8
9
10
11
<el-dialog v-model="data.formVisible" title="管理员信息" width="500">

<template #footer>
<div class="dialog-footer">
<el-button @click="data.formVisible = false">Cancel</el-button>
<el-button type="primary" @click="add">
Confirm
</el-button>
</div>
</template>
</el-dialog>

Form表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<el-form :model="data.form" label-width="80px" style="padding: 20px 30px 10px 0">
<el-form-item label="账号">
<el-input v-model="data.form.username" autocomplete="off" />
</el-form-item>

<el-form-item label="名称">
<el-input v-model="data.form.name" autocomplete="off" />
</el-form-item>

<el-form-item label="电话">
<el-input v-model="data.form.phone" autocomplete="off" />
</el-form-item>

<el-form-item label="邮箱">
<el-input v-model="data.form.email" autocomplete="off" />
</el-form-item>
</el-form>

表单验证

1.在表单el-form上有三个必须的属性

1
ref = "formRef" :model="data.form" :rules="data.rules"

2.在el-form-item 上写上表单项prop

1
<el-form-item prop="username"

3.在rules里面定义验证的规则

4.定义formRef对象,作为表单的引用

5.通过formRef对象进行表单验证

destroy-on-close属性可以重置dialog

引入Java工具栏Hutool

1
2
3
4
5
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>

admin 的新增流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 public void add(Admin admin) {
// 根据新的账号查询数据库 是否存在同样账号的数据
Admin dbAdmin = adminMapper.selectByUsername(admin.getUsername());
if(dbAdmin!=null){
throw new CustomerException("账号重复");

}
// if(admin.getPassword() == null || "".equals(admin.getPassword())){
//
// }
//用hutool
//默认密码
if(StrUtil.isBlank(admin.getPassword())) {
admin.setPassword("admin");//可以不用明文存储
}
adminMapper.insert(admin);
}

新增数据

1.在编辑的按钮上加上点击事件

2.定义弹窗和表单的页面代码

3.点击触发弹窗打开 (将行对象的数据row深度拷贝给form 对象)

4.表单做一下数据绑定以及表单验证

5.后台要有对应修改的接口来接受数据

6.修改的接口负责把数据插入到数据库里面

7.表达输入数据后点击确认按钮,把表单的数据传给后台接口

8.在修改成功之后再次加载表格的数据,关闭弹窗

405 错误表示你请求的方法类型跟后端定义的方法类型不一致

比如前端是put请求,后台是post接口

兼容新增和修改

1
2
3
const save = () => {
data.form.id ? update():add()
}

删除数据

MessageBox

单个删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const del = (id)=>{
ElMessageBox.confirm('删除后无法恢复,您确认删除吗?','删除确认',{ type:"warning" }).then(res => {
request.delete('/admin/delete/'+id).then(res=>{
if(res.code === '200'){
ElMessage.success('删除成功')
load()
}else{
ElMessage.error(res.msg);
}
})
}).catch(err=>{

})
}

批量删除

table的多选事件

1
@selection-change="handleSelectionChange"

在 Element Plus 的 el-table 中,要启用多选功能,除了添加 @selection-change 事件外,还需要在表格列中显式添加 type="selection" 的列 。以下是完整的实现步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<el-table
:data="data.tableData"
style="width: 100%"
@selection-change="handleSelectionChange"
:header-cell-style="{fontWeight: 'bold', color: '#333', backgroundColor: '#c902f6'}"
>
<!-- 多选列 -->
<el-table-column
type="selection"
width="55" <!-- 可根据需要调整宽度 -->
></el-table-column>

<!-- 其他列 -->
<el-table-column prop="id" label="ID"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
</el-table>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const deleteBatch = () =>{
if(data.rows.length === 0){
ElMessage.warning('请选择数据')
return
}

ElMessageBox.confirm('删除后无法恢复,您确认删除吗?','删除确认',{ type:"warning" }).then(res => {
request.delete('/admin/deleteBatch',{data: data.rows}).then(res=>{
if(res.code === '200'){
ElMessage.success('批量删除成功')
load()
}else{
ElMessage.error(res.msg);
}
})
}).catch(err=>{

})
}

完整代码:

后端就是简单的crud

直接给前端

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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
<template>
<div>
<div class="card" style="margin-bottom: 5px">
<!-- 加上clearable这个属性可以快速清除也就是那个叉叉顺便刷新一下 v-model="data.name" 将输入的文字显示到输入框内-->
<el-input clearable @clear="load" style="width: 240px;margin-right: 5px;" v-model="data.name" placeholder="请输入名称查询" :prefix-icon="Search"></el-input>
<el-input clearable @clear="load" style="width: 240px;margin-right: 5px;" v-model="data.username" placeholder="请输入账号查询" :prefix-icon="Search"></el-input>
<el-button type="primary" @click="load">查 询</el-button>
<el-button @click="reset">重 置</el-button>
</div>

<div class="card" style="margin-bottom: 5px">
<el-button type="primary" @click="handleAdd">新 增</el-button>
<el-button type="danger" @click="deleteBatch">批量删除</el-button>
<el-button type="success">批量导入</el-button>
<el-button type="info">批量导出</el-button>
</div>

<div class="card" style="margin-bottom: 5px">
<el-table :data="data.tableData" style="width: 100%" @selection-change="handleSelectionChange" :header-cell-style="{fontWeight: 'bold',color: '#333',backgroundColor: '#c902f6'}">

<!-- 多选列 -->
<el-table-column type="selection" width="55"></el-table-column>

<el-table-column prop="username" label="账号"/>
<el-table-column prop="name" label="名称" />
<el-table-column prop="phone" label="电话" />
<el-table-column prop="email" label="邮箱" />
<el-table-column label="操作" width="100">
<template #default="scope">
<el-button type="primary" icon="Edit" circle @click="handleEdit(scope.row)"></el-button>
<el-button type="danger" icon="Delete" circle @click="del(scope.row.id)"></el-button>
</template>
</el-table-column>
</el-table>
</div>

<!-- 分页-->
<div class="card">
<el-pagination
v-model:current-page="data.pageNum"
v-model:page-size="data.pageSize"
:page-size="data.pageSize"
layout="total,sizes, prev, pager, next,jumper"
:page-sizes="[5,10,20]"
:total="data.total"
@current-change="load"
@size-change="load"

/>
</div>

<el-dialog v-model="data.formVisible" title="管理员信息" width="30%" destroy-on-close>
<el-form ref="formRef" :model="data.form" :rules="data.rules" label-width="80px" style="padding: 20px 30px 10px 0">
<el-form-item prop="username" label="账号">
<el-input v-model="data.form.username" autocomplete="off" />
</el-form-item>

<el-form-item prop="name" label="名称">
<el-input v-model="data.form.name" autocomplete="off" />
</el-form-item>

<el-form-item prop="name" label="电话">
<el-input v-model="data.form.phone" autocomplete="off" />
</el-form-item>

<el-form-item prop="name" label="邮箱">
<el-input v-model="data.form.email" autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="data.formVisible = false">Cancel</el-button>
<el-button type="primary" @click="save()">
Confirm
</el-button>
</div>
</template>
</el-dialog>
</div>

</template>

<script setup>
import {reactive, ref} from "vue";
import {Search} from "@element-plus/icons-vue";
import axios from "axios";
import request from "@/utils/request.js";
import {ElMessage, ElMessageBox} from "element-plus";

const data = reactive({
username: null,
name: null,
pageNum: 1,
pageSize: 5,
total: 0,
tableData: [],
formVisible: false,
form: {},
rules: {
username: [
{ required:true,message: '请填写账号',trigger: 'blur' }
],
name: [
{ required:true,message: '请填写名称',trigger: 'blur' }
],
phone: [
{ required:true,message: '请填写手机',trigger: 'blur' }
],
email: [
{ required:true,message: '请填写邮箱',trigger: 'blur' }
]
},
rows: []
})


const formRef = ref()

const load = () => {
request.get('/admin/selectPage',{
params: {
pageNum: data.pageNum,
pageSize: data.pageSize,
name: data.name,
username: data.username
}
}).then(res=>{
if(res.code === '200'){
data.tableData = res.data.list;
data.total = res.data.total;
}else{
ElMessage.error(res.msg);
}
})
}
load()

const reset = () => {
data.name = null
load()
}

const handleAdd = () => {
data.formVisible = true
data.form = {}
}

const add = () => {
//formRef是表单的引用
formRef.value.validate((valid) => {
if(valid){ //验证通过的情况下
request.post('/admin/add',data.form).then(res=>{
if(res.code === '200'){
data.formVisible = false
ElMessage.success('新增成功')
load()
}else{
ElMessage.error(res.msg);
}
})
}
})

}

const handleEdit = (row) => {
data.form = JSON.parse(JSON.stringify(row)) //深度拷贝数据
data.formVisible = true
}


const update = () => {
formRef.value.validate((valid) => {
if(valid){ //验证通过的情况下
request.put('/admin/update',data.form).then(res=>{
if(res.code === '200'){
data.formVisible = false
ElMessage.success('修改成功')
load()
}else{
ElMessage.error(res.msg);
}
})
}
})

}

const save = () => {
data.form.id ? update():add()
}

const del = (id)=>{
ElMessageBox.confirm('删除后无法恢复,您确认删除吗?','删除确认',{ type:"warning" }).then(res => {
request.delete('/admin/delete/'+id).then(res=>{
if(res.code === '200'){
ElMessage.success('删除成功')
load()
}else{
ElMessage.error(res.msg);
}
})
}).catch(err=>{

})
}

const handleSelectionChange = (rows) => { // rows 就是实际选择的数组
console.log(rows)
data.rows = rows
}
//逻辑删除也可以

const deleteBatch = () =>{
if(data.rows.length === 0){
ElMessage.warning('请选择数据')
return
}

ElMessageBox.confirm('删除后无法恢复,您确认删除吗?','删除确认',{ type:"warning" }).then(res => {
request.delete('/admin/deleteBatch',{data: data.rows}).then(res=>{
if(res.code === '200'){
ElMessage.success('批量删除成功')
load()
}else{
ElMessage.error(res.msg);
}
})
}).catch(err=>{

})
}

</script>