当前位置: 首页 > news >正文

vue后台管理系统 vue3+vite+pinia+elementui+axios下

这篇文章来完成用户组件 也就是增删改查表格

用户页面信息页面由头部,表格,和弹框组成
<template><div class="user-header"><el-button type="primary" @click="handleAdd">新增</el-button><el-form :inline="true" :model="formInline"><el-form-item label="请输入"><el-input placeholder="请输入用户名" v-model="formInline.keyWord"></el-input></el-form-item><el-form-item><el-button type="primary" @click="handleSearch">搜索</el-button></el-form-item></el-form></div><div class="table"><el-table :data="tableData" style="width:100%"><el-table-columnv-for="item in tableLabel":key="item.prop":width="item.width ? item.width :125":prop="item.prop":label="item.label"></el-table-column><el-table-column fixed="right" label="Operations" min-width="150"><template #="scope"><el-button type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button><el-button type="danger" size="small" @click="handleDelete(scope.row)">删除</el-button></template></el-table-column></el-table><el-paginationclass="pager"backgroundlayout="prev, pager,next"size="small":total="config.total"@current-change="handleChange"></el-pagination></div><el-dialogv-model="dialogVisible":title="action === 'add' ? '新增用户' : '编辑用户'"width="35%":before-close="handleClose"><!--需要注意的是设置了:inline="true",会对el-select的样式造成影响,我们通过给他设置一个class=select-clearn在css进行处理--><el-form :inline="true" :model="formUser" :rules="rules" ref="userForm"><el-row><el-col :span="12"><el-form-item label="姓名" prop="name"><el-input v-model="formUser.name" placeholder="请输入姓名" /></el-form-item></el-col><el-col :span="12"><el-form-item label="年龄" prop="age"><el-input v-model.number="formUser.age" placeholder="请输入年龄" /></el-form-item></el-col></el-row><el-row><el-col :span="12"><el-form-item class="select-clearn" label="性别" prop="sex"><el-select v-model="formUser.sex" placeholder="请选择"><el-option label="男" value="1" /><el-option label="女" value="0" /></el-select></el-form-item></el-col><el-col :span="12"><el-form-item label="出生日期" prop="birth"><el-date-pickerv-model="formUser.birth"type="date"placeholder="请输入"style="width: 100%"/></el-form-item></el-col></el-row><el-row><el-form-itemlabel="地址"prop="addr"><el-input v-model="formUser.addr" placeholder="请输入地址" /></el-form-item></el-row><el-row style="justify-content: flex-end"><el-form-item><el-button type="primary" @click="handleCancel">取消</el-button><el-button type="primary" @click="onSubmit">确定</el-button></el-form-item></el-row></el-form></el-dialog></template><style lang="scss" scoped>.user-header{display:flex;justify-content: space-between;}.table{position:relative;height:520px;.pager{position:absolute;right:10px;bottom:30px;}.el-table{width:100%;height:500px;}}</style>
在api文件夹中api.js文件加入
getUserData(data){return request({url:"/home/getUserData",method:'get',data})},deleteUser(data){return request({url:"/home/deleteUser",method:'get',data})},addUser(params) {return request({url: '/user/addUser',method: 'post',data: params})},editUser(params) {return request({url: '/user/editUser',method: 'post',data: params})},
在mock.js中加入
Mock.mock(/api\/home\/getUserData/,"get",userApi.getUserList)Mock.mock(/api\/home\/deleteUser/,"get",userApi.deleteUser)Mock.mock(/api\/user\/addUser/,"post", userApi.createUser)Mock.mock(/api\/user\/editUser/, "post",userApi.updateUser)
mockData文件夹中加入user.js模拟数据
import Mock from 'mockjs'// get请求从config.url获取参数,post从config.body中获取参数function param2Obj(url) {const search = url.split('?')[1]if (!search) {return {}}return JSON.parse('{"' +decodeURIComponent(search).replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') +'"}')}let List = []const count = 200//模拟200条用户数据for (let i = 0; i < count; i++) {List.push(Mock.mock({id: Mock.Random.guid(),name: Mock.Random.cname(),addr: Mock.mock('@county(true)'),'age|18-60': 1,birth: Mock.Random.date(),sex: Mock.Random.integer(0, 1)}))}export default {/*** 获取列表* 要带参数 name, page, limt; name可以不填, page,limit有默认值。* @param name, page, limit* @return {{code: number, count: number, data: *[]}}*/getUserList: config => {//limit默认是10,因为分页器默认也是一页10个const { name, page = 1, limit = 10 } = param2Obj(config.url)const mockList = List.filter(user => {//如果name存在会,根据name筛选数据if (name && user.name.indexOf(name) === -1) return falsereturn true})//分页const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))return {code: 200,data: {list: pageList,count: mockList.length, //数据总条数需要返回}}},//在原来的export default 中添加/*** 删除用户* @param id* @return {*}*/deleteUser: config => {const { id } = param2Obj(config.url)if (!id) {return {code: -999,message: '参数不正确'}} else {List = List.filter(u => u.id !== id)return {code: 200,message: '删除成功'}}},/*** 增加用户* @param name, addr, age, birth, sex* @return {{code: number, data: {message: string}}}*/createUser: config => {const { name, addr, age, birth, sex } = JSON.parse(config.body)List.unshift({id: Mock.Random.guid(),name: name,addr: addr,age: age,birth: birth,sex: sex})return {code: 200,data: {message: '添加成功'}}},/*** 修改用户* @param id, name, addr, age, birth, sex* @return {{code: number, data: {message: string}}}*/updateUser: config => {const { id, name, addr, age, birth, sex } = JSON.parse(config.body)const sex_num = parseInt(sex)List.some(u => {if (u.id === id) {u.name = nameu.addr = addru.age = ageu.birth = birthu.sex = sex_numreturn true}})return {code: 200,data: {message: '编辑成功'}}}}
有了相应的请求数据 就可以实现增删改差以及相应的功能
<script setup>
//
import {ref,getCurrentInstance,onMounted,reactive,nextTick} from 'vue'const tableLabel = reactive([{prop:'name',label:'姓名'},{prop:'age',label:'年龄'},{prop:'sexLabel',label:'性别'},{prop:'birth',label:'出生日期',width:200},{prop:'addr',label:'地址',width:400},])const tableData =ref([])const {proxy} = getCurrentInstance()const getUserData = async () => {let data = await proxy.$api.getUserData(config)// console.log(data)tableData.value = data.list.map(item =>({...item,sexLabel: item.sex === 1 ? '男' : '女'}))config.total = data.count}const formInline = reactive({keyWord:''})const config =reactive({name:'',total:0,page:1})const handleSearch=() => {config.name = formInline.keyWordgetUserData()}const handleChange = (page) => {config.page = pagegetUserData()}const handleDelete =(val) => {ElMessageBox.confirm("你确定要删除吗?").then(async () => {await proxy.$api.deleteUser({id:val.id})ElMessage({showClose:true,message:'删除成功',type:'success'})getUserData()})}const action =ref('add')const dialogVisible = ref(false)const formUser = reactive({sex:"1"})const rules = reactive({name: [{ required: true, message: "姓名是必填项", trigger: "blur" }],age: [{ required: true, message: "年龄是必填项", trigger: "blur" },{ type: "number", message: "年龄必须是数字" },],sex: [{ required: true, message: "性别是必选项", trigger: "change" }],birth: [{ required: true, message: "出生日期是必选项" }],addr:[{ required: true, message: '地址是必填项' }]})//这个方法之前定义过const handleAdd = () => {action.value="add"//打开对话窗dialogVisible.value=true}//对话框右上角的关闭事件const handleClose = () => {//获取到表单dom,执行resetFields重置表单// proxy.$refs["userForm"].resetFields()//关闭对话框dialogVisible.value=false}//对话框右下角的取消事件const handleCancel = () => {// proxy.$refs["userForm"].resetFields()dialogVisible.value=false}//格式化日期,格式化为:1997-01-02这种const timeFormat = (time) => {var time = new Date(time);var year = time.getFullYear();var month = time.getMonth() + 1;var date = time.getDate();function add(m) {return m < 10 ? "0" + m : m;}return year + "-" + add(month) + "-" + add(date);}const onSubmit = () => {//执行userForm表单的validate进行规则校验,传入一个回调函数,回调函数会接受到一个是否校验通过的变量proxy.$refs["userForm"].validate(async (valid)=>{//如果校验成功if (valid) {//res用于接收添加用户或者编辑用户接口的返回值let res=null//这里无论是新增或者是编辑,我们都要对这个日期进行一个格式化//如果不是1997-01-02这种格式,使用timeFormat方法进行格式化formUser.birth=/^\d{4}-\d{2}-\d{2}$/.test(formUser.birth) ? formUser.birth : timeFormat(formUser.birth)//如果当前的操作是新增,则调用新增接口if (action.value == "add") {res = await proxy.$api.addUser(formUser);}else if(action.value == "edit"){res = await proxy.$api.editUser(formUser)}//如果接口调用成功if(res){//关闭对话框,重置表单,重新请求用户数据dialogVisible.value = false;proxy.$refs["userForm"].resetFields()getUserData()}//如果校验失败}else {ElMessage({showClose: true,message: "请输入正确的内容",type: "error",})}})}const handleEdit = (val) => {action.value="edit"dialogVisible.value=truenextTick(()=>{//因为在第一次显示弹窗的时候form组件没有加载出来,如果直接对formUser赋值,这个值会作为form表单的初始值//所以使用nextTick,赋值的操作在一个微任务中,这样就可以避免在from表单加载之前赋值Object.assign(formUser,{...val,sex:""+val.sex})//这里需要改变sex数据类型,是因为el-option的value有类型的校验})}onMounted(() => {getUserData()})</script>

用户表格实现完成
请添加图片描述

接下来实现面包屑组件

<template><div class="tags"><el-tagv-for="(tag,index) in tags":key="tag.name":closable="tag.name !== 'home'":effect = "route.name === tag.name ? 'dark': 'plain'"@click="handleMenu(tag)"@close="handleClose(tag,index)">{{tag.label}}</el-tag></div></template><script setup>import {ref,computed} from 'vue'import {useRoute,useRouter} from 'vue-router'import {useAllDataStore} from '../stores/index.js'const router = useRouter()const store = useAllDataStore()const tags = computed(()=>store.$state.tags)const route = useRoute()const handleMenu = (tag) => {router.push(tag.name)store.selectMenu(tag)}const handleClose = (tag,index) => {store.updateMenu(tag)if(index === store.$state.tags.length){store.selectMenu(tags.value[index-1])router.push(tags.value[index-1].name)}else{store.selectMenu(tags.value[index])router.push(tags.value[index].name)}}</script><style lang="scss" scoped>.tags{margin:20px 0 0 20px;}el-tag{margin-right:10px;}</style>
在store/index.js中添加内容
export const useAllDataStore = defineStore('allData', {state:() => {return {isCollapse: true,tags:[{path:'/home',name:'home',label:'首页',icon:'home',}],currentMenu:null,}},actions: {selectMenu(val){if(val.name === "home"){this.currentMenu =null;}else{this.currentMenu = val// console.log()let index = this.tags.findIndex((item)=> item.name === val.name);index === -1 ? this.tags.push(val) : "";}},updateMenu(tag){let index =this.tags.findIndex((item) => item.name === tag.name)this.tags.splice(index,1)},
搭建登陆页面 动态添加路由 有两个账号 账号一admin密码123456与账号二oner密码123456

请添加图片描述

请添加图片描述

<template><div class="body-login"><el-form :model="loginForm" class="login-container"><h1>欢迎登陆</h1><el-form-item><el-input type="input" placeholder="请输入账号"v-model="loginForm.username"></el-input></el-form-item><el-form-item><el-input type="input" placeholder="请输入密码"v-model="loginForm.password"></el-input></el-form-item><el-form-item><el-button type="primary" @click="handleLogin"> 登陆</el-button></el-form-item></el-form></div></template><script setup>import {reactive,getCurrentInstance} from 'vue'import {useAllDataStore} from '../stores/index.js'import {useRouter} from 'vue-router'const loginForm = reactive({username:'',password:'',})const {proxy} = getCurrentInstance()const store = useAllDataStore()const router = useRouter()const handleLogin = async () => {const res = await proxy.$api.getMenu(loginForm)store.updateMenuList(res.menuList)store.$state.token = res.tokenstore.addMenu(router)router.push('/home')}</script><style lang="scss" scoped>.body-login{width:100%;height:100%;background-image:url("../assets/images/background.png");background-size:100%;overflow:hidden;}.login-container{width:400px;background-color:#fff;border:1px solid #eaeaea;border-radius:15px;padding:35px 35px 15px 35px;box-shadow:0 0 25px #cacaca;margin:250px auto;h1{text-align:center;margin-bottom:20px;color:#505450;}:deep(.el-form-item__content){justify-content:center;}}</style>

更新store/index.js代码

import { defineStore } from 'pinia'
export const useAllDataStore = defineStore('allData', {state:() => {return {isCollapse: true,tags:[{path:'/home',name:'home',label:'首页',icon:'home',}],currentMenu:null,menuList:[],token:"",routerList:[],}},actions: {selectMenu(val){if(val.name === "home"){this.currentMenu =null;}else{this.currentMenu = val// console.log()let index = this.tags.findIndex((item)=> item.name === val.name);index === -1 ? this.tags.push(val) : "";}},updateMenu(tag){let index =this.tags.findIndex((item) => item.name === tag.name)this.tags.splice(index,1)},updateMenuList(val){this.menuList =val;},//动态添加路由addMenu(router,type){const menu = this.menuListconst module = import.meta.glob("../views/**/*.vue");const routeArr = [];menu.forEach((item)=>{if(item.children){item.children.forEach((val) => {let url = `../views/${val.url}.vue`;val.component = module[url];routeArr.push(...item.children);})}else{let url = `../views/${item.url}.vue`;item.component = module[url];routeArr.push(item)}})this.routerList= [];let routers = router.getRoutes()routers.map((item) => {if(item.name === 'Main' || item.name ==="Login"){return ;}else{router.removeRoute(item.name)}})routeArr.forEach((item) => {this.routerList.push(router.addRoute("Main",item))})// this.routerList= [];// let routers = router.getRoutes()// routers.map((item) => {// if(item.name === 'main' || item.name ==="login"){ return ;}else{// router.removeRoute(item.name)// }// })},clean(){this.routerList.forEach((item) => {if(item) item()})this.$reset()}},})

项目到此就结束了
请添加图片描述

请添加图片描述

源码地址:https://github.com/zhaimou/vue3-admin

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 接口测试框架中测试用例管理模块的优化与思考!
  • 理解ThreadLocal 变量副本,为什么不同线程的 ThreadLocalMap互不干扰
  • LSTM与GNN强强结合!全新架构带来10倍推理速度提升
  • centos7 中安装 mysql 8.x以及对数据库的管理(数据库、表的增删改查、插入删除数据)
  • Electron工作流程(2)——进程间通信
  • JavaScript青少年简明教程:面向对象编程入门
  • WEB服务器的详解与部署
  • 数学建模评价类模型—层次分析法(无数据情况下)
  • 解决VideoReader出现Thread worker: Error sending packet报错
  • Harmony-(2)-ArkTs
  • 精通Python爬虫中的XPath:从安装到实战演示
  • spring security和核心流程
  • KVM+GFS分布式存储系统构建KVM高可用
  • 【Python-MySQL】Python 代码用pool管理MySQL连接,并实现增删改查
  • Pip换源
  • 【译】JS基础算法脚本:字符串结尾
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 0x05 Python数据分析,Anaconda八斩刀
  • dva中组件的懒加载
  • ES6之路之模块详解
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • Invalidate和postInvalidate的区别
  • Linux后台研发超实用命令总结
  • Meteor的表单提交:Form
  • Mybatis初体验
  • PHP那些事儿
  • Python_网络编程
  • sessionStorage和localStorage
  • 前端知识点整理(待续)
  • 三栏布局总结
  • 设计模式(12)迭代器模式(讲解+应用)
  • 怎样选择前端框架
  • 回归生活:清理微信公众号
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • (14)Hive调优——合并小文件
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)ObjectiveC 深浅拷贝学习
  • (转)人的集合论——移山之道
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .cfg\.dat\.mak(持续补充)
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .net framework4与其client profile版本的区别
  • .Net Remoting(分离服务程序实现) - Part.3
  • .NET 材料检测系统崩溃分析
  • .net下的富文本编辑器FCKeditor的配置方法
  • /bin/rm: 参数列表过长"的解决办法
  • /tmp目录下出现system-private文件夹解决方法
  • @ComponentScan比较
  • @JSONField或@JsonProperty注解使用
  • @vue-office/excel 解决移动端预览excel文件触发软键盘
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [ 网络基础篇 ] MAP 迈普交换机常用命令详解