springboot+vite 商品管理
SpringBoot + Vue3 +MySql5.7 +JDK8
一、 SpringBoot项目搭建
1 SpringBoot概述
1.1 SpringBoot 概念
SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻 辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度 上缩短了项目周期。2014 年4 月,Spring Boot 1.0.0 发布。Spring的顶级项目之一(https://spring.io)。
1.2 Spring缺点
1.2.1 配置繁琐
虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多 XML配置。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。 Spring 3.0引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。 所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所 以编写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但它要求的回报也不少。
1.2.2 依赖繁琐
项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导 入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。
1.3 SpringBoot 功能
1.3.1 自动配置
Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定 Spring配置应该用哪个,不该用哪个。该过程是SpringBoot自动完成的。
1.3.2 起步依赖
起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖 ,这些东西加在一起即支持某项功能。 简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。
1.3.3 辅助功能
提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、安全、指标,健康检测、外部配置等。Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用Spring 的方式。
2 Springboot快速入门
2.1 案例需求
搭建SpringBoot工程,定义HelloWorldController.hello()方法,返回”Hello SpringBoot!”。
2.2 案例实现步骤
1)创建项目
2)定义Controller
3)启动测试
2.2.1 创建Maven项目
·
配置URL
https://start.aliyun.com
配置Maven仓库
2.2.2 新建HelloController测试
HelloController.java
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "Hello SpringBoot";
}
}
启动测试
浏览器测试
3 数据库
3.1 新建数据库
3.2 新建表
use hddata;
CREATE TABLE user (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID,自增长',
username VARCHAR(50) NOT NULL COMMENT '用户名',
password VARCHAR(255) NOT NULL COMMENT '用户密码',
name VARCHAR(100) NOT NULL COMMENT '姓名'
) COMMENT='用户信息表';
CREATE TABLE product (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '商品ID,自增长',
number VARCHAR(50) NOT NULL COMMENT '商品编号',
name VARCHAR(100) NOT NULL COMMENT '商品名称',
brand INT NOT NULL COMMENT '商品品牌'
) COMMENT='商品信息表';
4 项目实战
4.1 引入相关依赖
<!-- 引入MyBatis plus依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version>
</dependency>
<!--mysql驱动依赖-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
<!--hutool工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<!--validation依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.1.0</version>
</dependency>
<!--pageHelper 分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.7</version>
</dependency>
4.2 分层建包
User类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.AUTO)
private int id; // 用户ID,自增长
private String username; // 用户名
private String password; // 用户密码
private String name; // 姓名
}
4.3 数据库配置
#数据库配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/hddata?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: fp
#mybatis-plus配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath*:/mybatis/*.xml
type-aliases-package: com.hwadee.userproject.pojo
4.4 创建用户数据层
UserMapper
public interface UserMapper extends BaseMapper<User> {
}
配置mapper包扫描
@SpringBootApplication
@MapperScan("com.hwadee.userproject.mapper")
public class UserProjectApplication {
public static void main(String[] args) {
SpringApplication.run(UserProjectApplication.class, args);
}
}
mybatis-plus测试
@SpringBootTest
class UserProjectApplicationTests {
@Autowired
UserMapper userMapper;
//新增用户
@Test
void contextLoads() {
User user = new User();
user.setUsername("admin");
user.setPassword(DigestUtil.md5Hex("123456"));
user.setName("管理员");
userMapper.insert(user);
}
//查询所有用户
@Test
void contextLoads1() {
List<User> users = userMapper.selectList(null);
System.out.println("====用户数据====");
users.forEach(user -> System.out.println(user));
}
}
4.5 创建前后端交互对象
DataResult
public class DataResult<T> implements Serializable {
private static final long serialVersionUID = 1L;
private boolean success = true;
private String message = "操作成功!";
private Integer statusCode = 200;
private T data;
private long timestamp = System.currentTimeMillis();
public DataResult() {
}
public DataResult(Boolean success, Integer code, String msg, T data) {
this.success = success;
this.statusCode = code;
this.message = msg;
this.data = data;
}
//返回成功
public static DataResult success() {
return new DataResult(true,200, "操作成功!", null);
}
//返回失败 500
public static DataResult error(String message) {
return new DataResult(false,HttpStatus.INTERNAL_SERVER_ERROR.value(), message, null);
}
//返回成功并携带数据
public static <T> DataResult<T> success(T data) {
return new DataResult<T>(true,200, "操作成功!", data);
}
public boolean getSuccess() {
return this.success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public Integer getStatusCode() {
return this.statusCode;
}
public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}
public T getData() {
return this.data;
}
public void setData(T data) {
this.data = data;
}
public long getTimestamp() {
return this.timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}
4.6 数据校验
User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.AUTO)
private int id; // 用户ID,自增长
@NotNull(message = "用户名不能为空")
@Pattern(regexp = "^[\\x00-\\x7F]+$", message = "用户名不能包含汉字")
@Size(min = 3, message = "用户名长度必须大于2个字符")
private String username; // 用户名
@NotNull(message = "密码不能为空")
@Pattern(regexp = "^[\\x00-\\x7F]+$", message = "密码不能包含汉字")
@Size(min = 3, message = "密码长度必须大于2个字符")
private String password; // 用户密码
private String name; // 姓名
}
4.7 全局控制异常
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public DataResult handleException(Exception e){
e.printStackTrace();
return DataResult.error(StringUtils.hasLength(e.getMessage()) ? e.getMessage() : "操作失败");
}
}
4.8 用户注册
开启事务
@SpringBootApplication
@MapperScan("com.hwadee.userproject.mapper")
@EnableTransactionManagement//开启事务管理
public class UserProjectApplication {
public static void main(String[] args) {
SpringApplication.run(UserProjectApplication.class, args);
}
}
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserMapper userMapper;
@RequestMapping("/register")
@Transactional(rollbackFor = Exception.class) //事务控制
public DataResult register(@Validated @RequestBody User user){
if(!StringUtils.hasLength(user.getName())){
return DataResult.error("姓名不能为空");
}
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username",user.getUsername());
User user1 = userMapper.selectOne(queryWrapper);
if (Objects.isNull(user1)){
user.setPassword(DigestUtil.md5Hex(user.getPassword()));
userMapper.insert(user);
//int i = 1/0; //测试事务
return DataResult.success("注册成功");
}else {
return DataResult.error("用户名已存在");
}
}
}
PostMan测试
4.9 用户登录
/**
* 用户登录
* @param user
* @return
*/
@PostMapping("/login")
public DataResult login(@Validated @RequestBody User user) {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username", user.getUsername());
//查询用户
User user1 = userMapper.selectOne(wrapper);
if (Objects.nonNull(user1)) {
//用户存在,校验密码
if (user1.getPassword().equals(DigestUtil.md5Hex(user.getPassword()))) {
return DataResult.success("登录成功");
}
return DataResult.error("密码错误");
} else {
return DataResult.error("用户名错误");
}
}
测试
4.9 配置跨域
CorsConfig
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口
.allowCredentials(true) // 是否发送 Cookie
.allowedOriginPatterns("*") // 允许的源(Spring 5.3 及以上版本支持通配符)
.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持的方法
.allowedHeaders("*") // 允许的头部信息
.exposedHeaders("Authorization", "Content-Type"); // 暴露的头部信息
}
}
二、Vue项目搭建
必须先安装node
软件安装:nodejs16
https://nodejs.org/download/release/v16.20.0/
1 创建项目
1.1 安装vite环境
cmd进去项目目录,依次执行以下命令
#配置新淘宝镜像(防止出现下载缓慢)
npm config set registry https://registry.npmmirror.com
#查看当前的 npm 镜像地址
npm config get registry
#安装vite
npm init vite@latest
#Package name 就是项目的包名,它用于唯一标识你的项目,在项目的配置文件 package.json 中使用。
1.2 启动项目
# 安装依赖
npm i
#启动项目
npm run dev
1.3 项目结构介绍
node_modules:
通过 npm install 下载安装的项目依赖包
public:
存放静态资源公共资源,不会被压缩合并
—3DModel:存放.glb3D模型
—favicon.ico:网站图标
—index.html:首页入口.html文件
src:
项目开发主要文件夹
—api
—assets:静态文件,存放图片
—components:存放组件
—store:与vuex相关
—styles:存放样式
—utils:工具类
—views:界面组件
—App.vue:根组件
—main.js:入口文件
—router.js:存放路由,实现界面跳转
.gitignore:
用来配置那些文件不归git管理
package.json:
项目配置和包管理文件(项目依赖和技术)
package-lock.json :
锁定依赖的版本信息,确保不同的开发者在不同的时间或环境中使用相同的版本。
README.md:
说明文档,主要看项目运行的命令
vue.config.js:
项目配置信息:跨域proxy代理
2 引入相关配置
配置@全局路径设置
vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
//记得引入
import { fileURLToPath, URL } from 'node:url'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
2.1 引入静态文件
main.js
//注释默认样式
//import './style.css'
//引入公共样式
import './assets/base.css'
2.2 引入Element-plus
#安装
npm install element-plus --save
main.js
//引入ElementPlus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
//在 mount 之前调用 use 方法
createApp(App).use(ElementPlus).mount('#app')
在Hellowold.vue中测试是否引入成功
<template>
<div style="margin-top: 20px">
<el-button>Default</el-button>
<el-button type="primary">Primary</el-button>
<el-button type="success">Success</el-button>
<el-button type="info">Info</el-button>
<el-button type="warning">Warning</el-button>
<el-button type="danger">Danger</el-button>
</div>
</template>
<script setup lang='js'>
</script>
<style lang='scss' scoped>
</style>
2.3 引入router
#安装
npm install vue-router@latest
创建views/HomeView.vue
<template>
<div style="margin-top: 20px">
Home
</div>
</template>
<script setup lang='js'>
</script>
<style lang='scss' scoped>
</style>
创建router/index.js
index.js
import { createRouter,createWebHistory } from 'vue-router'
//导入组件
import Home from '@/views/home/HomeView.vue'
//定义路由关系
const routes = [
{
path: '/home',
name: 'home',
component: Home
}
]
//创建路由器
const router = createRouter({
history: createWebHistory(),
routes:routes
})
//导出路由
export default router
main.js
// @/router 如果不直接写后面的路径,默认找index.js
import router from '@/router/index.js'
//在 mount 之前调用 use 方法
createApp(App).use(router).use(ElementPlus).mount('#app')
App.vue
<template>
<!-- 全局配置组件 -->
<el-config-provider :locale="zhCn">
<RouterView />
</el-config-provider>
</template>
<script setup>
import {ElConfigProvider} from "element-plus";
import {zhCn} from "element-plus/es/locale/index";
</script>
测试路由
2.4 安装axios
npm install axios -S
创建utils/request.js
import axios from 'axios';
const URL = "http://localhost:8080";
// create an axios instance
const service = axios.create({
baseURL: URL, // url = base url + request url
timeout: 10000, // request timeout
withCredentials: true,
crossDomain: true
})
export default service
创建后端api/getData.js
import request from "@/utils/request";
/**
* 用户登录的api
* @param data
*/
export const doLogin=(data)=>{
return request({
url:'user/login', //请求url
method :'post', //请求方式
data //请求参数
})
}
3 登录页面
新建/views/login/LoginView.vue
<template>
<div class="login-container">
<el-card class="login-card">
<div class="login-header">
<h3 class="login-title">欢迎登录</h3>
<p class="login-subtitle">校园管理系统</p>
</div>
<el-form
ref="loginFormRule"
:model="loginForm"
:rules="rules"
label-width="auto"
class="loin-form" >
<el-form-item label="用户名" prop="username">
<el-input v-model="loginForm.username" autocomplete="off" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="loginForm.password" type="password" autocomplete="off" placeholder="请输入密码"/>
</el-form-item>
<el-form-item>
<el-button class="login-button" type="primary" @click="submitForm()">
登录
</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script setup>
import {ref} from "vue";
import {ElMessage} from "element-plus";
import {doLogin} from "@/api/getData.js";
import router from "@/router/index.js";
/**
* 表单绑定的数据
* @type {Ref<UnwrapRef<{password: string, username: string}>>}
*/
const loginForm = ref({
username:'',
password:'',
})
const loginFormRule = ref(null);
/**
* 提交
*/
const submitForm =()=>{
//提交前验证
loginFormRule.value.validate((valid)=>{
if(valid){
login();
}else{
ElMessage.error("请输入用户名或密码")
}
})
//跳转到首页
}
/**
* 登录方法
*/
const login = ()=>{
doLogin(loginForm.value).then(({data})=>{
if(data.statusCode == 200){
router.push("/home")
}else{
ElMessage.error(data.message)
}
})
}
/**
* 验证表单规则
* @type {Ref<any>}
*/
const rules = ref({
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 2, message: '用户名长度最小为2个字符', trigger: 'blur' },
{
pattern: /^[^\u4e00-\u9fa5]+$/,
message: '用户名不能包含汉字',
trigger: 'blur'
}
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 2, message: '密码长度最小为2个字符', trigger: 'blur' },
{
pattern: /^[^\u4e00-\u9fa5]+$/,
message: '密码不能包含汉字',
trigger: 'blur'
}
]
});
</script>
<style scoped>
.login-container{
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: linear-gradient(to right, #00b2ff, #00b2ff, #1550a8);
}
.login-card{
width: 600px;
padding: 40px;
text-align: center;
border-radius: 16px;
box-shadow: 0 4px 8px rgb(0,0,0,0.1);
}
.login-header{
margin-bottom: 40px;
}
.login-title{
font-size: 30px;
font-weight: bold;
color: #333333;
margin-bottom: 10px;
letter-spacing: 10px;
}
.login-subtitle{
font-size: 25px;
color: #666666;
letter-spacing: 20px;
}
.loin-form{
width: 100%;
}
.login-button{
width: 100%;
font-size: 16px;
}
</style>
三、商品的增删改查
1 新建表
-- 使用自己的数据库
use hddata;
CREATE TABLE product (
id INT AUTO_INCREMENT PRIMARY KEY COMMENT '商品ID,自增长',
number VARCHAR(50) NOT NULL COMMENT '商品编号',
name VARCHAR(100) NOT NULL COMMENT '商品名称',
brand VARCHAR(50) NOT NULL COMMENT '商品品牌'
) COMMENT='商品信息表';
2 后端代码
2.1 新建实体类
Product
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
@TableId(type = IdType.AUTO)
private int id;
@NotEmpty(message = "编号不能为空")
private String number;
@NotEmpty(message = "名称不能为空")
private String name;
@NotEmpty(message = "品牌不能为空")
private String brand;
}
2.2 新建数据层接口
ProductMapper
public interface ProductMapper extends BaseMapper<Product> {
}
2.3 新建控制层
商品查询
ProductController
@RestController
@RequestMapping("/product")
public class ProductController {
@Resource
private ProductMapper productMapper;
/**
* 查询所有商品
*/
@RequestMapping("/list")
public DataResult list(@RequestParam(required = false) String name) {
QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
if (StringUtils.hasLength(name)) {
queryWrapper.like("name", name);
}
List<Product> brands = productMapper.selectList(queryWrapper);
return DataResult.success(brands);
}
}
浏览器测试
商品添加
/**
* 添加商品
*/
@RequestMapping("/add")
@Transactional
public DataResult add(@Validated @RequestBody Product product) {
productMapper.insert(product);
return DataResult.success();
}
测试
编辑商品
先通过id回显数据
/**
* 通过主键查找
* @param id
* @return
*/
@RequestMapping("/getById")
public DataResult getById(@RequestParam String id){
Product product = productMapper.selectById(id);
return DataResult.success(product);
}
测试
编辑商品
/**
* 编辑商品
*/
@RequestMapping("/edit")
@Transactional
public DataResult edit(@Validated @RequestBody Product product) {
if(product.getId() == 0){
return DataResult.error("id不能为空");
}
productMapper.updateById(product);
return DataResult.success();
}
测试
删除商品
/**
* 删除商品
* @param id
* @return
*/
@RequestMapping("/delete")
@Transactional
public DataResult delete(@RequestParam String id){
if(!StringUtils.hasLength(id)){
return DataResult.error("id不能为空");
}
productMapper.deleteById(id);
return DataResult.success();
}
3 前端代码
3.1 商品列表
新建/views/product/ProductView.vue
配置路由跳转
import Product from '@/views/product/ProductView.vue'
//定义路由关系
const routes = [
{
path: '/',
name: 'login',
component: Login
},
{
path: '/home',
name: 'home',
component: Home
},
{
path: '/product',
name: 'product',
component: Product
}
]
修改登录后路由跳转到商品界面
点击登录测试
ProductView.vue
<template>
<el-card >
<template #header>
<div class="card-header">
<span>商品管理</span>
<el-button type="primary" @click="visibleDrawer=true ;drawerTile='新增商品'">新增商品</el-button>
</div>
</template>
<!-- 搜索表单-->
<el-form :inline="true" :model="searchForm" class="demo-form-inline">
<el-form-item label="名称">
<el-input v-model="searchProductName" placeholder="请输入商品名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="productList">搜索</el-button>
</el-form-item>
</el-form>
<!-- 商品显示列表-->
<el-table :data="products" style="width: 100%">
<el-table-column prop="number" label="编号" width="200" />
<el-table-column prop="name" label="名称" width="200" />
<el-table-column prop="brand" label="品牌" width="200" />
<!-- <el-table-column fixed="right" label="操作" min-width="200">
<template #default="{row}">
<el-button type="primary" size="small" @click="handleEdit(row)">
编辑
</el-button>
<el-button type="danger" size="small" @click="handleDelete(row)">
删除</el-button>
</template>
</el-table-column> -->
</el-table>
</el-card>
</template>
<script setup lang='js'>
import {ref} from "vue";
import {getProductByNameList} from "@/api/getData.js";
import {ElMessage, ElMessageBox} from "element-plus";
/**
* 定义搜索表单数据
* @type {Ref<UnwrapRef<{}>>}
*/
const searchForm = ref({})
/**
* 定义搜索字段
* @type {Ref<any>}
*/
const searchProductName = ref('');
//列表数据
const products = ref([])
/**
* 定义查询商品的方法
*/
const productList = ()=>{
getProductByNameList(searchProductName.value).then(({data})=>{
if(data.statusCode==200){
products.value = data.data
}
})
}
//查询数据
productList()
</script>
<style scoped>
.card-header{
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
添加后端接口
getData.js
/**
* 查询商品列表的api
* @param data
*/
export const getProductByNameList=(name)=>{
return request({
url:'product/list?name='+ name, //请求url
method :'post' //请求方式
})
}
测试
3.2 新增商品
<!-- 抽屉样式的编辑框-->
<el-drawer
v-model="visibleDrawer"
:title="drawerTile"
:direction="rt1"
size="30%"
>
<el-form :model="productModel" label-width="auto" style="max-width: 600px">
<el-form-item label="编号">
<el-input v-model="productModel.number" placeholder="请输入编号" />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="productModel.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="品牌">
<el-input v-model="productModel.brand" placeholder="请输入品牌" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="drawerTile == '新增商品' ? doAddProduct() : doUpdateProduct()">提交</el-button>
</el-form-item>
</el-form>
</el-drawer>
定义相关数据变量
//编辑框数据
const visibleDrawer = ref(false) //显示或者隐藏
const drawerTile = ref('') //新增或者编辑
const productModel = ref({
id: 0,
number: '',
name: '',
brand: ''
})
const clearData = ()=>{
productModel.value = {
id: 0,
number: '',
name: '',
brand: ''
}
}
//新增商品
const doAddProduct= ()=>{
addProduct(productModel.value).then(({data})=>{
if(data.statusCode==200){
ElMessage.success("添加成功")
}
clearData()
visibleDrawer.value=false;
productList();
})
}
//编辑商品
const doUpdateProduct = () => {
}
<el-button
type="primary"
@click=" visibleDrawer = true;drawerTile = '新增商品';">新增商品</el-button>
添加后端接口
/**
* 添加商品
* @param data
*/
export const addProduct=(data)=>{
return request({
url:'product/add' ,//请求url
method :'post', //请求方式
data
})
}
测试代码
3.2 编辑商品
<el-table-column fixed="right" label="操作" min-width="200">
<template #default="{row}">
<el-button type="primary" size="small" @click="handleEdit(row)">
编辑
</el-button>
<el-button type="danger" size="small" @click="handleDelete(row)">
删除</el-button>
</template>
</el-table-column>
添加编辑事件
//编辑商品
const doUpdateProduct = () => {
updateProduct(productModel.value).then((data)=>{
if(data.status==200){
ElMessage.success("编辑成功")
}
clearData()
visibleDrawer.value=false;
productList();
})
}
/**
* 打开编辑
*/
const handleEdit = (row)=>{
visibleDrawer.value=true
drawerTile.value="编辑商品"
// 数据赋值给 model
productModel.value = row;
productModel.value.id= row.id
}
添加后端接口
/**
* 编辑商品
*/
export const updateProduct=(data)=>{
return request({
url:'product/edit' ,//请求url
method :'post', //请求方式
data
})
}
测试
3.3 删除商品
/**
* 删除方法
*/
const handleDelete = (row)=>{
ElMessageBox.confirm(
'您确定删除这条数据么',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
deleteProduct(row.id).then(({data})=>{
if(data.statusCode==200){
productList();
ElMessage({
type: 'success',
message: '删除成功',
})
}
})
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消删除',
})
})
}
添加后端接口
/**
* 删除商品
*/
export const deleteProduct=(id)=>{
return request({
url:'product/delete?id='+id, //请求url
method :'post', //请求方式
})
}
测试
3.4 ProductView.vue 完整代码
<template>
<el-card>
<template #header>
<div class="card-header">
<span>商品管理</span>
<el-button
type="primary"
@click=" visibleDrawer = true;drawerTile = '新增商品';">新增商品</el-button>
</div>
</template>
<!-- 搜索表单-->
<el-form :inline="true" :model="searchForm" class="demo-form-inline">
<el-form-item label="名称">
<el-input
v-model="searchProductName"
placeholder="请输入商品名称"
clearable
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="productList">搜索</el-button>
</el-form-item>
</el-form>
<!-- 商品显示列表-->
<el-table :data="products" style="width: 100%">
<el-table-column prop="number" label="编号" width="200" />
<el-table-column prop="name" label="名称" width="200" />
<el-table-column prop="brand" label="品牌" width="200" />
<el-table-column fixed="right" label="操作" min-width="200">
<template #default="{row}">
<el-button type="primary" size="small" @click="handleEdit(row)">
编辑
</el-button>
<el-button type="danger" size="small" @click="handleDelete(row)">
删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 抽屉样式的编辑框-->
<el-drawer
v-model="visibleDrawer"
:title="drawerTile"
:direction="rt1"
size="30%"
>
<el-form :model="productModel" label-width="auto" style="max-width: 600px">
<el-form-item label="编号">
<el-input v-model="productModel.number" placeholder="请输入编号" />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="productModel.name" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="品牌">
<el-input v-model="productModel.brand" placeholder="请输入品牌" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
@click="drawerTile == '新增商品' ? doAddProduct() : doUpdateProduct()">提交</el-button>
</el-form-item>
</el-form>
</el-drawer>
</template>
<script setup lang="js">
import {ref} from "vue";
import {getProductByNameList,addProduct,updateProduct,deleteProduct} from "@/api/getData.js";
import {ElMessage, ElMessageBox} from "element-plus";
/**
* 定义搜索表单数据
* @type {Ref<UnwrapRef<{}>>}
*/
const searchForm = ref({})
/**
* 定义搜索字段
* @type {Ref<any>}
*/
const searchProductName = ref('');
//列表数据
const products = ref([])
/**
* 定义查询商品的方法
*/
const productList = ()=>{
getProductByNameList(searchProductName.value).then(({data})=>{
if(data.statusCode==200){
products.value = data.data
}
})
}
//查询数据
productList()
//编辑框数据
const visibleDrawer = ref(false) //显示或者隐藏
const drawerTile = ref('') //新增或者编辑
const productModel = ref({
id: 0,
number: '',
name: '',
brand: ''
})
const clearData = ()=>{
productModel.value = {
id: 0,
number: '',
name: '',
brand: ''
}
}
//新增商品
const doAddProduct= ()=>{
addProduct(productModel.value).then(({data})=>{
if(data.statusCode==200){
ElMessage.success("添加成功")
}
clearData()
visibleDrawer.value=false;
productList();
})
}
//编辑商品
const doUpdateProduct = () => {
updateProduct(productModel.value).then((data)=>{
if(data.status==200){
ElMessage.success("编辑成功")
}
clearData()
visibleDrawer.value=false;
productList();
})
}
/**
* 打开编辑
*/
const handleEdit = (row)=>{
visibleDrawer.value=true
drawerTile.value="编辑商品"
// 数据赋值给 model
productModel.value = row;
productModel.value.id= row.id
}
/**
* 删除方法
*/
const handleDelete = (row)=>{
ElMessageBox.confirm(
'您确定删除这条数据么',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
deleteProduct(row.id).then(({data})=>{
if(data.statusCode==200){
productList();
ElMessage({
type: 'success',
message: '删除成功',
})
}
})
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消删除',
})
})
}
</script>
<style scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>