一套后台管理系统的入门级的增删改查(vue3组合式api+elemment-plus)

一、页面示意:

图一

图二

二、组件结构

  • 列表组件 :index.vue,对应图一
  • 添加组件:add.vue,对应图二,用抽屉效果
  • 编辑组件:edit.vue,和添加组件的效果一个。

三、代码

1、列表组件: index.vue

<template>
    <h1>增删改查案例</h1>
    <div>
        <!--查询条件  -->
        <el-form :model="searchData" label-width="40px" :inline="true">
            <el-form-item label="书号">
                <el-input v-model="searchData.id" />
            </el-form-item>
            <el-form-item label="书名">
                <el-input v-model="searchData.name" />
            </el-form-item>
            <el-form-item label="作者">
                <el-input v-model="searchData.author" />
            </el-form-item>
            <el-form-item label="价格">
                <el-input v-model="searchData.minprice" />
            </el-form-item>
            <el-form-item label="-->">
                <el-input v-model="searchData.maxprice" />
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="searchFn">查询</el-button>
                <el-button @click="showAdd">添加</el-button>
            </el-form-item>
        </el-form>
    </div>
    <div>
        <!-- 书籍列表 -->
        <el-table :data="bookData" stripe style="width: 100%">
            <el-table-column prop="id" label="书号" width="180" />
            <el-table-column prop="name" label="书名" width="180" />
            <el-table-column prop="author" label="作者" />
            <el-table-column prop="price" label="价格" />
            <el-table-column  label="类型" >
                <template #default="scope">
                    <span>{{typeObj[scope.row.type]}}</span>
                </template>
            </el-table-column>
            <el-table-column label="图片">
                <template #default="scope">
                    <img :src="scope.row.img" style="width: 100px;height: 100px" />
                </template>
            </el-table-column>

            <el-table-column fixed="right" label="操作" width="120">
                <template #default="scope">
                    <el-button link type="primary" size="small" @click="showEdit(scope.row.id)">
                        编辑
                    </el-button>
                    <el-button link type="primary" size="small" @click.prevent="deleteBook(scope.row.id)">
                        删除
                    </el-button>
                </template>
            </el-table-column>
        </el-table>
        <el-drawer v-model="drawer" title="添加书籍" direction="rtl" :before-close="handleClose">
            <AddBook @close="closeFn" @ok="okFn"></AddBook>
        </el-drawer>
        <el-drawer v-model="drawerEdit" title="修改书籍" direction="rtl" >
            <EditBook :id="editId" @ok="editOkFn" @close="editCloseFn" ></EditBook>
        </el-drawer>
    </div>
</template>

<script  setup>
import { reactive, onMounted,ref } from "vue";
import { getBooksApi, getBooksByCondationApi, deleteBookApi } from "@/api/crud";
import AddBook from "./Add.vue";
import EditBook from "./edit.vue";


const typeObj = {
    "new":"最新",
    "hot":"热卖"
}


// 书籍数据
let bookData = reactive([]);

//一、 获取书籍信息
const getBooks = () => {
    getBooksApi()
        .then(res => {
            if (res.data) {
                console.log("bookData前", bookData);
                // bookData = res.data;
                bookData.length = 0;
                bookData.push(...res.data);
                console.log("bookData后", bookData);
            }
        })
        .catch(err => {
            console.log("获取数据出错", err);
        })
}
onMounted(() => {
    getBooks();
})

// 二、查询书籍
const searchData = reactive({
    "id": "",
    "name": "",
    "author": "",
    "minprice": "",
    "maxprice": ""
})

const searchFn = () => {

    const temp = {};
    for (const key in searchData) {
        if (searchData[key] !== "") {
            temp[key] = searchData[key];
        }
    }

    if (temp["minprice"]) {
        delete temp["minprice"];
        temp["price_gte"] = searchData.minprice;
    }

    if (temp["maxprice"]) {
        delete temp["maxprice"];
        temp["price_lte"] = searchData.maxprice;
    }


    getBooksByCondationApi(temp)
        .then(res => {
            if (res.data) {
                bookData.length = 0;
                bookData.push(...res.data);
            }
        })
}


// 三、删除书籍
const deleteBook = (id) => {

    deleteBookApi(id)
        .then(res => {
            console.log("删除的返回res", res);
            // 删除成功后,重新获取数据
            getBooks();
        })
}


// 四、添加
const drawer = ref(false)

const handleClose = (done) => {
  ElMessageBox.confirm('Are you sure you want to close this?')
    .then(() => {
      done()
    })
    .catch(() => {
      // catch error
    })
}

// 显示添加页面
const showAdd=()=>{
    drawer.value=true;
}

const closeFn=()=>{
    drawer.value = false;
}

const okFn=()=>{
    closeFn();
    getBooks();
}

// 五、修改
const drawerEdit = ref(false);
const editId = ref("");//修改的书籍的id

// 显示修改页面
const showEdit=(id)=>{
    editId.value=id;
    drawerEdit.value=true;
}

const editCloseFn=()=>{
    editId.value ="";
    drawerEdit.value = false;
}

const editOkFn=()=>{
    editCloseFn();
    getBooks();
}


</script>


<style lang="css" scoped></style>

2、添加组件:add.vue

<template>
    <el-form ref="formRef" :model="newBook" label-width="120px" :rules="rules">
        <el-form-item label="书号" prop="id">
            <el-input v-model="newBook.id" />
        </el-form-item>
        <el-form-item label="书名" prop="name">
            <el-input v-model="newBook.name" />
        </el-form-item>
        <el-form-item label="作者" prop="author">
            <el-input v-model="newBook.author" />
        </el-form-item>
        <el-form-item label="价格" prop="price">
            <el-input v-model="newBook.price" />
        </el-form-item>
        <el-form-item label="图片" prop="img">
            <el-input v-model="newBook.img" />
        </el-form-item>
        <el-form-item label="类型" prop="type">
            <!-- <el-input v-model="newBook.type" /> -->
            <el-select v-model="newBook.type" class="m-2" placeholder="请选择书籍类型" size="large">
                <!-- <el-option v-for="item in booktypes" :key="item.id" :label="item.name" :value="item.value" /> -->
                <el-option label="最新" value="new" />
                <el-option label="热卖" value="hot" />
            </el-select>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="addBookFn(formRef)">添加</el-button>
            <el-button @click="cancelFn">取消</el-button>
        </el-form-item>
    </el-form>
</template>
    
<script  setup>
import { reactive, ref } from 'vue';
import { addBookApi,getBookTypeApi } from "@/api/crud"

const emit = defineEmits(['close', "ok"]);

const booktypes = reactive([]);

const getBookType = () => {
    getBookTypeApi()
    .then(res=>{
        if(res.data){
            booktypes.length=0;
            booktypes.push(...res.data);
        }
    })
}

getBookType();

const formRef = ref();
//  定义添加的书籍
const newBook = reactive({
    "id": "",
    "name": "",
    "author": "",
    "price": 0,
    "img": "",
    "type": ""
})



// 表单验证的规则
const rules = reactive({
    "id": [
        { required: true, message: '请输入书号', trigger: 'blur' }
    ],
    "name": [
        { required: true, message: '请输入书名', trigger: 'blur' }
    ],
    "author": [
        { required: true, message: '请输入作者', trigger: 'blur' }
    ],
    "price": [
        { required: true, message: '请输入价格', trigger: 'blur' }
    ],
    "img": [
        { required: true, message: '请输入图片地址', trigger: 'blur' }
    ],
    "type": [
        { required: true, message: '请输入类型', trigger: 'blur' }
    ],
})


const addBookFn = (formEl) => {
    if (!formEl) {
        return;
    }
    console.log("newBook",newBook);

    formEl.validate((isOk) => {
        if (isOk) {
            addBookApi(newBook)
                .then(res => {
                    console.log(res);
                    if (res.data) {
                        // 添加成功
                        alert("添加成功!");
                        // 关闭弹窗
                        emit("ok");
                    }
                })
                .catch(err => {

                })
        }
    })


}

const cancelFn = () => {
    emit('close');
}



</script>

3、编辑组件:edit.vue

<template>
    <el-form ref="formRef" :model="editBook" label-width="120px" :rules="rules">
        <el-form-item label="书号" prop="id">
            <el-input v-model="editBook.id" />
        </el-form-item>
        <el-form-item label="书名" prop="name">
            <el-input v-model="editBook.name" />
        </el-form-item>
        <el-form-item label="作者" prop="author">
            <el-input v-model="editBook.author" />
        </el-form-item>
        <el-form-item label="价格" prop="price">
            <el-input v-model="editBook.price" />
        </el-form-item>
        <el-form-item label="图片" prop="img">
            <el-input v-model="editBook.img" />
        </el-form-item>
        <el-form-item label="类型" prop="type">
            <el-input v-model="editBook.type" />
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="editBookFn(formRef)">修改</el-button>
            <el-button @click="cancelFn">取消</el-button>
        </el-form-item>
    </el-form>
</template>
    
<script  setup>
import { reactive, ref,watch } from 'vue';
import { getBookDetailApi,editBookApi } from '@/api/crud';

const props = defineProps(["id"]);

const formRef = ref();

//  定义修改的书籍
const editBook = reactive({
    "id": "",
    "name": "",
    "author": "",
    "price": 0,
    "img": "",
    "type": ""
})


// 获取当前修改的书籍信息
const getBookDetail = async () => {
    try {
        const res = await getBookDetailApi(props.id);
        // editBook = res.data;
        for(let key in editBook){
            editBook[key] = res.data[key];
        }

    } catch (err) {
        console.log("服务器出错",err);
    }
}

console.log("props",props);

watch(props,()=>{
    console.log("props.id变了");
    getBookDetail();
},{deep:true,immediate:true})

const emit = defineEmits(['close', "ok"]);

// 表单验证的规则
const rules = reactive({
    "id": [
        { required: true, message: '请输入书号', trigger: 'blur' }
    ],
    "name": [
        { required: true, message: '请输入书名', trigger: 'blur' }
    ],
    "author": [
        { required: true, message: '请输入作者', trigger: 'blur' }
    ],
    "price": [
        { required: true, message: '请输入价格', trigger: 'blur' }
    ],
    "img": [
        { required: true, message: '请输入图片地址', trigger: 'blur' }
    ],
    "type": [
        { required: true, message: '请输入类型', trigger: 'blur' }
    ],
})

const editBookFn = (formEl) => {
    if (!formEl) {
        return;
    }

    formEl.validate((isOk) => {
        if (isOk) {
            editBookApi(props.id,editBook)
                .then(res => {
                    console.log(res);
                    if (res.data) {
                        alert("修改成功!");
                        // 关闭弹窗
                        emit("ok");
                    }
                })
                .catch(err => {

                })
        }
    })


}

const cancelFn = () => {
    emit('close');
}


</script>

4、补充【api和axios封装】:api/crud.js;utils/serviceMock.js

api/crud.js

import service from "@/utils/serviceMock.js";


// 获取所有书籍
export const getBooksApi = ()=>service.get('/books');

// 根据编号获取书籍详情
export const getBookDetailApi = (id)=>service.get('/books/'+id);

// 查询书籍
export const getBooksByCondationApi = (params)=>service.get('/books',{params});

// 删除书籍
export const deleteBookApi = (id)=>service.delete('/books/'+id);


// 添加书籍
export const addBookApi = (data)=>service.post('/books',data);


// 修改书籍
export const editBookApi = (id,data)=>service.put('/books/'+id,data);


// 获取书籍类型
export const getBookTypeApi = ()=>service.get('/bookType');

utils/serviceMock.js
import axios from 'axios';
import store from '@/store';


const service = axios.create({
    baseURL:"http://localhost:3000"
})

// 请求拦截器:所有请求的公共业务
service.interceptors.request.use(config=>{
    store.commit("showLoading");
    return config;
})


// 响应拦截器
service.interceptors.response.use((res)=>{
    store.commit("hideLoading");
    // loading.close();
    return res;
})



export default service;

5、mock数据,用json-server

{
      "books": [
    {
      "id": "878912",
      "name": "水浒1",
      "author": "施耐庵",
      "price": 51.5,
      "img": "/src/assets/imgs/01.jpg",
      "type": "hot"
    },
    {
      "id": "878913",
      "name": "红楼梦",
      "author": "曹雪芹2",
      "price": 51.8,
      "img": "/src/assets/imgs/01.jpg",
      "type": "hot"
    },
    {
      "id": "878917",
      "name": "论语1",
      "author": "王锐1",
      "price": "5.38",
      "img": "/imgs/img3.jpg",
      "type": "new"
    },
    {
      "id": "878918",
      "name": "老子",
      "author": "李家恒",
      "price": 54.8,
      "img": "/imgs/img4.jpg",
      "type": "new"
    },
    {
      "id": "878919",
      "name": "孟子2",
      "author": "李家恒",
      "price": 54.8,
      "img": "/images/img4.jpg",
      "type": "new"
    },
    {
      "id": "878920",
      "name": "孟子3",
      "author": "李家恒",
      "price": 54.8,
      "img": "/images/img4.jpg",
      "type": "new"
    },
    {
      "id": "878921",
      "name": "孟子4",
      "author": "李家恒",
      "price": 54.8,
      "img": "/images/img4.jpg",
      "type": "new"
    },
    {
      "id": "878922",
      "name": "孟子5",
      "author": "李家恒",
      "price": 54.8,
      "img": "/images/img4.jpg",
      "type": "new"
    },
    {
      "id": "878923",
      "name": "孟子6",
      "author": "李家恒",
      "price": 54.8,
      "img": "/images/img4.jpg",
      "type": "new"
    },
    {
      "id": "01008",
      "name": "霸道总裁爱上我",
      "author": "曹宇",
      "price": "9.9",
      "img": "/src/imgs/01.jpg",
      "type": "hot"
    },
    {
      "id": "01009",
      "name": "西厢记",
      "author": "赵蕊",
      "price": "10.9",
      "img": "/src/assets/imgs/01.jpg",
      "type": "hot"
    },
    {
      "id": "01010",
      "name": "钢铁是怎样炼成的",
      "author": "奥斯特洛夫斯基",
      "price": "11.9",
      "img": "/src/assets/imgs/02.jpg",
      "type": "hot"
    },
    {
      "id": "01011",
      "name": "12",
      "author": "22",
      "price": 0,
      "img": "1",
      "type": "hot"
    },
    {
      "id": "01012",
      "name": "假如我是亿万富翁",
      "author": "金莉",
      "price": "1000",
      "img": "/src/assets/imgs/01.jpg",
      "type": "new"
    }
  ],
}                         

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【程序员的自我修养02】初识ELF文件格式

绪论 大家好&#xff0c;欢迎来到【程序员的自我修养】专栏。正如其专栏名&#xff0c;本专栏主要分享学习《程序员的自我修养——链接、装载与库》的知识点以及结合自己的工作经验以及思考。编译原理相关知识本身就比较有难度&#xff0c;我会尽自己最大的努力&#xff0c;争取…

卷积的理解,卷积与通道的关系

神经网络中的卷积操作卷积在图像领域的功能单通道卷积多通道卷积&#xff08;1个卷积核&#xff09;多通道卷积&#xff08;多个卷积核&#xff09;总结扩展 图像处理中的卷积核恒等&#xff08;Identity&#xff09;边缘检测&#xff08;Edge detection&#xff09;锐化&#…

SAP ABAP ALV Tree 的使用

在 SAP 业务系统中&#xff0c;大量地使用到了ALV Tree 对象&#xff0c;该对象在表格基础上对同类数据 进行归类&#xff0c;并对各分类能进行数据汇总&#xff0c;如图8-10 所示。 以航班表&#xff08;SPFLI&#xff09;为例&#xff1a; &#xff08;1&#xff09;按国家…

主流数据库类型总结

前言&#xff1a;随着互联网的高速发展&#xff0c;为了满足不同的应用场景&#xff0c;数据库的种类越来越多容易混淆&#xff0c;所以有必要在此总结一下。数据库根据数据结构可分为关系型数据库和非关系型数据库。非关系型数据库中根据应用场景又可分为键值&#xff08;Key-…

深度学习之十二(图像翻译AI算法--UNIT(Unified Neural Translation))

概念 UNIT(Unified Neural Translation)是一种用于图像翻译的 AI 模型。它是一种基于生成对抗网络(GAN)的框架,用于将图像从一个域转换到另一个域。在图像翻译中,这意味着将一个风格或内容的图像转换为另一个风格或内容的图像,而不改变图像的内容或语义。 UNIT 的核心…

微服务--06--Sentinel 限流、熔断

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.微服务保护雪崩问题服务保护方案1.1.请求限流1.2.线程隔离1.3.服务熔断 2.Sentinel2.1.介绍和安装官方网站&#xff1a;[https://sentinelguard.io/zh-cn/](https…

Windows安装EMQX(搭建MQTT服务)

1、EMQX介绍 EMQ X是云原生分布式物联网接入平台。 EMQ X (Erlang/Enterprise/Elastic MQTT Broker) 是基于 Erlang/OTP 平台开发的开源物联网 MQTT 消息服务器。 Erlang/OTP是出色的软实时 (Soft-Realtime)、低延时 (Low-Latency)、分布式 (Distributed)的语言平台。 MQTT 是…

自学MySql(一)

1.安装下载 下载网址 2、将mysql的bin目录添加到环境变量&#xff08;可选&#xff09; 3、使用一下命令测试

最新消息:滴滴 P0 事故原因,原因出来了

最新消息滴滴P0故障原因&#xff0c;是由于k8s集群升级导致的&#xff0c;后面又进行版本回退&#xff0c;由于现在大型互联网公司基本都是基于K8s进行部署的&#xff0c;如果K8s集群一出问题&#xff0c;上面运行的业务Pod和运维系统全部都得宕机&#xff0c;导致没法回滚。 …

深入理解网络阻塞 I/O:BIO

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

源码安装mysql

使用源码安装mysql&#xff0c;这里选择的版本是mysql5.7.35 ,系统是Centos7.6 官网下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 下载源码压缩包 [rootlocalhost ~]# cd /opt[rootlocalhost opt]# wget https://downloads.mysql.com/archives/get/…

一觉醒来!Keras 3.0史诗级更新,大一统深度学习三大后端框架【Tensorflow/PyTorch/Jax】

不知道大家入门上手机器学习项目是首先入坑的哪个深度学习框架&#xff0c;对于我来说&#xff0c;最先看到的听到的就是Tensorflow了&#xff0c;但是实际上手做项目开发的时候却发现了一个很重要的问题&#xff0c;不容易上手&#xff0c;基于原生的tf框架来直接开发模总是有…

ssh-keygen(centos)

A—免密登陆—>B (1)A 机器&#xff0c;通过命令”ssh-keygen -t rsa“, 生成id_rsa,id_rsa.pub authorized_keys:存放远程免密登录的公钥,主要通过这个文件记录多台机器的公钥 id_rsa : 生成的私钥文件 id_rsa.pub &#xff1a; 生成的公钥文件 know_hosts : 已知的主机公钥…

javaagent字节码增强浅尝

概述 javaagent 技术广泛应用于对代码的增强&#xff0c;比如统计方法执行时间、GC 信息打印、分布式链路跟踪等&#xff1b;实现方式包括 javassist 和 bytebuddy&#xff0c;bytebuddy 是对 javassist 的改进&#xff1b;类似于 spring 中的 AOP&#xff1b; Instrumentati…

SpringBoot application.yml配置文件写法

1&#xff0c;基本介绍 &#xff08;1&#xff09;YAML 是 JSON 的超集&#xff0c;简洁而强大&#xff0c;是一种专门用来书写配置文件的语言&#xff0c;可以替代 application.properties。 &#xff08;2&#xff09;在创建一个 SpringBoot 项目时&#xff0c;引入的 spri…

231129 刷题日报

本周值班第3天&#xff0c;今天终于收到二面电话&#xff0c;一度以为挂了。。加油卷&#xff01; 今天尊重下艾宾浩斯遗忘曲线&#xff0c;重复下前几天看的01背包&#xff0c;子集背包&#xff0c;完全背包。 416. 分割等和子集 518. 零钱兑换 II 38min做了一道新题&#…

OSI七层参考模型及其协议和各层设备

OSI网络模型是开放系统互联&#xff08;Open Systems Interconnection&#xff09;参考模型&#xff0c;它是由国际标准化组织&#xff08;ISO&#xff09;制定的。这个模型将网络系统划分为七个层次&#xff0c;OSI网络模型的七层是&#xff1a;物理层、数据链路层、网络层、传…

【网络奇遇之旅】:那年我与计算机网络的初相遇

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; 计算机网络 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 一. 前言二. 计算机网络的定义三. 计算机网络的功能3.1 资源共享3.2 通信功能3.3 其他功能 四. 计算机网络…

MyBatis教程之简介(一)

1、MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff0c; iBatis3.x正式更名为MyBatis。代码于2013年11月迁移到Github。 iBatis一词来源于“inter…

android framework分屏“官方”黑屏bug问题发现,你会分析吗?-千里马实战作业挑战

背景 hi&#xff0c;粉丝朋友们&#xff1a; 大家都知道马哥课程以实战为特色&#xff0c;这里的实战就是最贴近公司里面开发的实战项目。这些实战主要来自哪呢&#xff1f; 1、以前在公司的工作积累&#xff0c;自己在公司做过什么&#xff0c;这部分比较好毕竟都是搞过的 2…