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

【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目之前端环境搭建

【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目之前端环境搭建

  • 2 前端环境搭建
    • 2.1 环境准备
    • 2.2 创建Vue3项目
    • 2.3 项目搭建准备
    • 2.4 安装Element Plus
    • 2.5 安装axios
      • 2.5.1 配置(创建实例,配置请求,响应拦截器)
      • 2.5.2 配置跨域
    • 2.6 Vue Router安装使用
    • 2.7 Pinia状态管理库
    • 2.8 搭建管理页面基础框架
      • 2.8.1 在src/api/下创建user.js,封装请求方法
      • 2.8.2 登陆页面
    • 2.9 运行展示
      • 2.9.1 启动前端
      • 2.9.2 启动后端
      • 2.9.3 测试

主要参考的博客为:

从零搭建SpringBoot3+Vue3前后端分离项目基座,中小项目可用_springboot+vue3-CSDN博客

记录一下自己的实现过程。

最终实现效果如下:

在这里插入图片描述

后端环境搭建参考博客【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目之后端环境搭建

2 前端环境搭建

2.1 环境准备

  • node安装
  • vscode安装

2.2 创建Vue3项目

在将要存放vue3项目的路径打开cmd,使用以下命令创建项目

npm init vue@latest

在这里插入图片描述

此时项目创建完成,vscode打开项目目录,在资源目录空白右键,打开终端

在这里插入图片描述

执行命令 cnpm install安装依赖,等待安装完成后执行 cnpm run dev 运行项目

在这里插入图片描述

访问路径http://localhost:5173可访问项目

在这里插入图片描述

在终端ctrl c 可停止运行项目
项目描述如图

在这里插入图片描述

2.3 项目搭建准备

项目中使用组合式API

删除components下的所有文件,将App.vue文件内容修改为如下

<script setup></script><template><router-view></router-view>
</template><style scoped></style>

2.4 安装Element Plus

  • 安装 cnpm install element-plus --save

  • cnpm install @element-plus/icons-vue

    在这里插入图片描述

2.5 安装axios

  • cnpm install axios

2.5.1 配置(创建实例,配置请求,响应拦截器)

在src目录下新建utils,并在utils下创建request.js进行axios配置

在这里插入图片描述

src/utils/request.js

// 请求配置import axios from "axios";// 定义公共前缀,创建请求实例
// const baseUrl = "http://localhost:8080";
const baseURL = '/api/';
const instance = axios.create({baseURL})import { ElMessage } from "element-plus"
import { useTokenStore } from "@/stores/token.js"
// 配置请求拦截器
instance.interceptors.request.use((config) => {// 请求前回调// 添加tokenconst tokenStore = useTokenStore()// 判断有无tokenif (tokenStore.token) {config.headers.Authorization = tokenStore.token}return config},(err) => {// 请求错误的回调Promise.reject(err)}
)import router from "@/router";
// 添加响应拦截器
instance.interceptors.response.use(result => {// 判断业务状态码if (result.data.code === 1) {return result.data;}// 操作失败ElMessage.error(result.data.message ? result.data.message : '服务异常')// 异步操作的状态转换为失败return Promise.reject(result.data)},err => {// 判断响应状态码, 401为未登录,提示登录并跳转到登录页面if (err.response.status === 401) {ElMessage.error('请先登录')router.push('/login')} else {ElMessage.error('服务异常')}// 异步操作的状态转换为失败return Promise.reject(err)  }
)export default instance

2.5.2 配置跨域

在vite.config.js中加入如下内容

在这里插入图片描述

  server: {proxy: {'/api': {   // 获取路径中包含了/api的请求target: 'http://localhost:9999',        // 服务端地址changeOrigin: true, // 修改源rewrite:(path) => path.replace(/^\/api/, '')   // api 替换为 ''}}}

2.6 Vue Router安装使用

  • 安装 cnpm install vue-router@4

  • 在src/router/index.js中创建路由器并导出。index.js文件内容如下

    // 导入vue-router
    import {createRouter, createWebHistory} from 'vue-router'// 导入组件
    import LoginVue from '@/views/Login.vue'
    import LayoutVue from '@/views/Layout.vue'
    import UserList from '@/views/user/UserList.vue'
    import EditPassword from '@/views/user/EditPassword.vue'
    import DisplayUser from '@/views/user/DisplayUser.vue'// 定义路由关系
    const routes = [{path: '/login', component: LoginVue},{path: '/', component: LayoutVue, redirect: '', children: [{path: '/user/userlist', name: "/user/userlist", component: UserList, meta: {title: "用户列表"},},{path: '/user/editpassword', name: "/user/editpassword", component: EditPassword, meta: {title: "修改密码"}},{path: '/user/displayuser', name: "/user/displayuser", component: DisplayUser, meta: {title: "个人信息"}}]}
    ]// 创建路由器 
    const router = createRouter({history: createWebHistory(),routes: routes
    })export default router
    
  • 在vue实例中使用vue-router,修改main.js文件内容为如下

import './assets/main.css'import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import router from '@/router'
import { createPinia } from 'pinia'
const pinia = createPinia()import zhLocale from 'element-plus/es/locale/lang/zh-cn'createApp(App).use(router).use(ElementPlus, {locale: zhLocale}).use(pinia).mount('#app')
  • 在app.vue中声明router-view标签,展示组件内容。app.vue文件内容如下

    
    <script setup></script><template><router-view></router-view>
    </template><style scoped></style>
    

2.7 Pinia状态管理库

  • 安装 cnpm install pinia

  • 安装persist cnpm install pinia-persistedstate-plugin

  • main.js中使用persist

    import { createPersistedState } from 'pinia-persistedstate-plugin'
    const persist = createPersistedState()
    pinia.use(persist)
    

    main.js内容整体如下:

    import './assets/main.css'import { createApp } from 'vue'
    import App from './App.vue'
    import ElementPlus from 'element-plus'
    import 'element-plus/dist/index.css'
    import router from '@/router'
    import { createPinia } from 'pinia'
    const pinia = createPinia()
    import { createPersistedState } from 'pinia-persistedstate-plugin'
    const persist = createPersistedState()
    pinia.use(persist)
    import zhLocale from 'element-plus/es/locale/lang/zh-cn'createApp(App).use(router).use(ElementPlus, {locale: zhLocale}).use(pinia).mount('#app')
  • src/stores/下定义token.js和userInfo.js来存储token和用户相关信息

token.js


// 定义 store
import { defineStore } from "pinia"
import {ref} from 'vue'
/*第一个参数:名字,唯一性第二个参数:函数,函数的内部可以定义状态的所有内容返回值: 函数*/
export const useTokenStore = defineStore('token', () => {// 响应式变量const token = ref('')// 修改token值函数const setToken = (newToken) => {token.value = newToken}// 移除token值函数const removeToke = () => {token.value = ''}return {token, setToken, removeToke}
}, 
{persist: true   // 持久化存储
}
)

userInfo.js


import { defineStore } from "pinia"
import {ref} from 'vue'const useUserInfoStore = defineStore('userInfo', () => {const info = ref({})const setInfo = (newInfo) => {info.value = newInfo}const removeInfo = () => {info.value = {}}return {info, setInfo, removeInfo}
},
{persist: true
}
)export default useUserInfoStore;

2.8 搭建管理页面基础框架

2.8.1 在src/api/下创建user.js,封装请求方法

在这里插入图片描述

import request from "@/utils/request.js"// 登录接口调用函数
export const userLoginService = (loginData) => {return request.post('/user/login', loginData)
}// 获取当前登录用户信息
export const currentUserService = () => {return request.get('/user/currentUser')
}// 获取所有用户信息
export const allUserService = () => {return request.get('/user/userList')
}// 分页查询
export const pageListService = (pageParam) => {return request.get('/user/pageList', {params: pageParam})
}// 新增用户
export const addUserService = (addData) => {return request.post('/user/add', addData)
}// 根据id获取用户信息
export const getUserById = (id) => {return request.get('/user/getuserById', {params: id})
}// 修改用户信息
export const updateUserService = (data) => {return request.put('/user/update', data)
}// 删除用户
export const deleteByIdService = (id) => {console.log("deleteRequestid:", id)return request.delete('/user/delete/' + id)
}

2.8.2 登陆页面

  • 安装 cnpm install sass -D

在src下创建vuew项目,用于存放vue页面组件

在这里插入图片描述

Header.vue

<template><div class="container"><!-- div left --><div class="left"><!-- 折叠按钮--><div @click="toggleCollapse()"><el-icon size="24" v-show="!isMenuOpen"><Fold /></el-icon><el-icon size="24" v-show="isMenuOpen"><Expand /></el-icon></div><!-- 面包屑 --><div><el-breadcrumb separator="/"><el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item><template v-for="(item, index) in breadList"><el-breadcrumb-itemv-if="item.name":key="index":to="item.path">{{ item.meta.title }}</el-breadcrumb-item></template></el-breadcrumb></div></div><!-- div right --><div class="right"><div><span >账号:{{userData.loginName}}</span></div><div><el-avatar> {{userData.name}} </el-avatar></div><div><el-dropdown><el-icon size="24"><MoreFilled /></el-icon><template #dropdown><el-dropdown-menu><el-dropdown-item><el-icon><UserFilled /></el-icon>个人信息</el-dropdown-item><el-dropdown-item><el-icon><EditPen /></el-icon>修改密码</el-dropdown-item><el-dropdown-item><el-icon><ArrowLeft /></el-icon>退出登录</el-dropdown-item></el-dropdown-menu></template></el-dropdown></div></div></div>
</template><script setup>import {Fold,Expand,MoreFilled,EditPen,ArrowLeft,UserFilled} from '@element-plus/icons-vue'import {ref, defineEmits, watch} from 'vue'// 面包屑import { useRouter,useRoute } from 'vue-router'let router = useRouter()let route = useRoute()let breadList = ref()let getMatched=()=>{console.log("route.matched:",route.matched);consolebreadList.value = route.matched.filter(item => item.meta && item.meta.title);}getMatched()watch(() => route.path, (newValue, oldValue) => { //监听路由路径是否发生变化,之后更改面包屑console.log("======")breadList.value = route.matched.filter(item => item.meta && item.meta.title);console.log("breadList.value", breadList.value)})import useUserInfoStore from '@/stores/userinfo.js'const userInfoStore = useUserInfoStore();// 用户数据模型let userData = ref({id: '',name: '',loginName: ''})import {currentUserService} from '@/api/user.js'// 获取登录用户信息const getUser = async () => {let result = await currentUserService()// console.log(result)userData.value = result.data;userInfoStore.setInfo(result.data)// console.log("userData:",userData)}getUser()// 折叠按钮处理const emits = defineEmits(["parentClick"])const isMenuOpen = ref(false)const toggleCollapse = () => {isMenuOpen.value = !isMenuOpen.valueconsole.log(isMenuOpen.value)emits("parentClick", isMenuOpen.value)}</script><style lang="scss" scope>.container {  overflow: auto; /* 清除浮动影响 */  height: 48px;padding: 10px; /* 内边距 */  border-bottom: 2px solid; /* 设置下边框宽度和样式 */  border-bottom-color: #F5F5F5; /* 设置下边框颜色为红色 */  background-color: #FFFFFF;   }  .left {  height: 48px;float: left;   display: flex;align-items: center; /* 垂直居中子项 */  justify-content: center; /* 水平居中子项(如果需要)*/ }  .left > div {  padding-right: 10px; /* 设置直接子元素的 padding */  }.right {  float: right; display: flex; align-items: center; /* 垂直居中子项 */  justify-content: center; /* 水平居中子项(如果需要)*/   }.right > div {  padding-right: 10px; /* 设置直接子元素的 padding */  }
</style>

Layout.vue

<script setup>
import LeftLayout from './LeftLayout.vue'
import Header from './Header.vue'
import MainView from './MainView.vue'import {ref} from 'vue'
const isCollapse = ref(false)
const parentClick = (isCollapseValue) => {isCollapse.value = isCollapseValue;console.log(isCollapse.value)
}
</script><template><div class="common-layout"><el-container><LeftLayout :isCollapse='isCollapse' /><el-container><el-header style="padding: 0"><Header @parentClick='parentClick'/></el-header><el-main style="padding: 16px 8px 6px 8px"><MainView/></el-main><el-footer>后台 ©2024 Created by buzhisuoyun</el-footer></el-container></el-container></div>
</template><style scoped>.el-footer {display: flex;align-items: center;justify-content: center;font-size: 14px;color: #666;height: 38px;padding: 0;background-color: #FFFFFF; }
</style>

LeftLayout.vue

<template><el-row class="tac"><el-col ><el-menudefault-active="2"class="el-menu-vertical-demo":collapse="isCollapse":router="true"><!-- 标题 --><div class="containerdiv">  <img src="../assets/favicon.ico" alt="Your Image" class="image">  <span class="text">后台管理</span>  </div><!-- 菜单 --><el-sub-menu index="1"><template #title><el-icon><Share /></el-icon><span>API管理</span></template><el-menu-item index="/api/apilist">API列表</el-menu-item><el-menu-item index="1-2">item two</el-menu-item><el-menu-item index="1-3">item three</el-menu-item><el-sub-menu index="1-4"><template #title>item four</template><el-menu-item index="1-4-1">item one</el-menu-item></el-sub-menu></el-sub-menu><el-menu-item index="2"><el-icon><icon-menu /></el-icon><span>Navigator Two</span></el-menu-item><el-menu-item index="3" disabled><el-icon><document /></el-icon><span>Navigator Three</span></el-menu-item><el-menu-item index="4"><el-icon><setting /></el-icon><span>Navigator Four</span></el-menu-item><el-sub-menu index="5"><template #title><el-icon><UserFilled /></el-icon><span>用户管理</span></template><el-menu-item index="/user/userlist">用户列表</el-menu-item><el-menu-item index="/user/displayuser">个人信息</el-menu-item><el-menu-item index="/user/editpassword">修改密码</el-menu-item></el-sub-menu></el-menu></el-col></el-row></template><script lang="ts" setup>import {Document,Menu as IconMenu,Location,Share,UserFilled,Setting,} from '@element-plus/icons-vue'import {ref, defineProps} from 'vue'type Props = {isCollapse: boolean}defineProps<Props>()</script><style scoped>.el-menu-vertical-demo {height: 100vh;}.el-menu-item {min-width: 0;}.containerdiv {  /* 你可以设置容器的样式,例如宽度、高度、背景色等 */  /* width: 300px; /* 示例宽度 */  height: 48px;  padding: 10px; /* 内边距 */  border-bottom: 2px solid; /* 设置下边框宽度和样式 */  border-bottom-color: #F5F5F5; /* 设置下边框颜色为红色 */  }  .image {  display: inline-block;  vertical-align: middle; /* 图片与文字垂直居中对齐 */  margin-right: 6px; /* 图片右边距,可选 */  width: 20px;}  .text {  display: inline-block;  vertical-align: middle; /* 文字与图片垂直居中对齐 */  font-weight: bold; /* 加粗文字 */  font-size: 14px;}</style>

Login.vue

<script setup>
import { User, Lock } from '@element-plus/icons-vue'
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
//定义数据模型
const registerData = ref({loginName: 'admin',password:'admin',rePassword: ''
})// 定义表单组件的引用
const ruleFormRef = ref(null)//定义表单校验规则
const rules = ref({loginName: [{ required: true, message: '请输入用户名', trigger: 'blur' },{ min: 5, max: 16, message: '长度为5~16位非空字符', trigger: 'blur' }],password: [{ required: true, message: '请输入密码', trigger: 'blur' },{ min: 5, max: 16, 2: '长度为5~16位非空字符', trigger: 'blur' }]
})//绑定数据,复用注册表单的数据模型
//表单数据校验
//登录函数
import {userLoginService} from '@/api/user.js'
import {useTokenStore} from '@/stores/token.js'
import {useRouter} from 'vue-router'
const router = useRouter()
const tokenStore = useTokenStore();
const login = async ()=>{// 校验表单if (!ruleFormRef.value) returnconsole.log("校验")await ruleFormRef.value.validate(async (valid) => {if (valid) {console.log("校验成功")// 调用接口,完成登录let result = await userLoginService(registerData.value);/* if(result.code===0){alert(result.msg? result.msg : '登录成功')}else{alert('登录失败')} *///alert(result.msg? result.msg : '登录成功')// ElMessage.success(result.msg ? result.msg : '登录成功')ElMessage.success(result.msg ? '登录成功': result.msg) //提示信息//token存储到pinia中tokenStore.setToken(result.data)//跳转到首页 路由完成跳转router.push('/')} else {console.log("校验失败")}})
}//定义函数,清空数据模型的数据
const clearRegisterData = ()=>{registerData.value={loginName: '',password:'',rePassword:''}
}
</script><template><el-row class="login-page"><el-col :span="12" class="bg"></el-col><el-col :span="6" :offset="3" class="form"><!-- 登录表单 --><el-form ref="ruleFormRef" :model=registerData size="large" autocomplete="off" :rules="rules"><el-form-item><h1>登录</h1></el-form-item><el-form-item prop="loginName"><el-input :prefix-icon="User" placeholder="请输入用户名" v-model="registerData.loginName"></el-input></el-form-item><el-form-item prop="password"><el-input name="password" :prefix-icon="Lock" type="password" placeholder="请输入密码" v-model="registerData.password"></el-input></el-form-item><el-form-item class="flex"><div class="flex"><el-checkbox>记住我</el-checkbox><!-- <el-link type="primary" :underline="false">忘记密码?</el-link> --></div></el-form-item><!-- 登录按钮 --><el-form-item><el-button class="button" type="primary" auto-insert-space @click="login">登录</el-button></el-form-item></el-form></el-col></el-row>
</template><style lang="scss" scoped>
/* 样式 */
.login-page {height: 100vh;background-color: #fff;.bg {background: url('@/assets/login_bg.jpg') no-repeat center / cover;border-radius: 0 20px 20px 0;}.form {display: flex;flex-direction: column;justify-content: center;user-select: none;.title {margin: 0 auto;}.button {width: 100%;}.flex {width: 100%;display: flex;justify-content: space-between;}}
}
</style>

MainView.vue

<template><div class="app-main"><!-- <transition name="fade-transfrom" mode="out-in"><router-view></router-view></transition> --><router-view v-slot="{ Component }"><transition><component :is="Component" /></transition></router-view></div>
</template><style lang="scss" scope>.app-main{width:100%;height:100%;background-color: #FFFFFF; }
</style>

user/DisplayUser.vue

<template><div><el-form :model="form" ><el-form-item label="账号" ><el-input v-model="form.loginName" :disabled="!isAdd"/></el-form-item><el-form-item label="姓名" ><el-input v-model="form.name" :disabled="!isAdd"/></el-form-item><el-form-item label="电话" ><el-input v-model="form.phone" /></el-form-item><el-form-item label="性别"><el-radio-group v-model="form.sex" :disabled="!isAdd"><el-radio value="0" checked>女</el-radio><el-radio value="1">男</el-radio></el-radio-group></el-form-item></el-form><div class="dialog-footer"><el-button @click="onDialogFormCancel">取消</el-button><el-button type="primary" @click="onDialogFormConfirm">确认</el-button></div></div>
</template>
<script setup>import {ref} from 'vue'const form = ref({loginName: '',name: '',phone: '',sex: '0'})// 重置对话框表单const restForm = () => {form.value = {sex: '0'}title.value = '添加用户'isAdd.value = true}const isAdd = ref(true)// 提交事件
const onDialogFormConfirm = async () => {}
// 取消事件
const onDialogFormCancel = () => {}
</script>

EditPassword.vue

<template><div> 修改密码</div>
</template>

UserList.vue

<script setup>
import { Plus } from "@element-plus/icons-vue";
import { ref, reactive } from "vue";
import { allUserService, pageListService, addUserService, getUserById, updateUserService, deleteByIdService } from "@/api/user.js";
import { ElMessage, ElMessageBox  } from "element-plus"// 表单数据
const searchData = ref({name: "",
});
// 表格数据
const tableData = ref([]);/** 分页 */
// 分页数据
const pageData = reactive({currentPage: 1,pageSize: 10,total: 20,
})
// 分页插件,每页条数发生改变时
const handleSizeChange = (val) => {pageData.pageSize = valgetPageList()
}
// 分页插件, 当页码发生改变时
const handleCurrentChange = (val) => {pageData.currentPage = valgetPageList()
}// // 查询所有用户
// const getAllUser = async () => {
//     const result = await allUserService()
//     tableData.value = result.data
// }
// getAllUser()// 分页查询
const getPageList = async () => {const params = {currentPage: pageData.currentPage,pageSize: pageData.pageSize,name: searchData.value.name,}//console.log("params:", params);const result = await pageListService(params);pageData.total = result.data.total;tableData.value = result.data.items;//console.log("tableData:", tableData);
}
getPageList()// 头部表单函数定义
const onSearch = () => {getPageList()
}
// 重置查询表单
const onRest = () => {searchData.value = {}getPageList()
}/** 添加修改对话框表单 */
const form = ref({loginName: '',name: '',phone: '',sex: '0'
})
// 重置对话框表单
const restForm = () => {form.value = {sex: '0'}title.value = '添加用户'isAdd.value = true
}
const title = ref('添加用户')
const isAdd = ref(true)
const dialogFormVisible = ref(false)// 提交对话框表单按钮事件
const onDialogFormConfirm = async () => {//1.验证表单if (!ruleFormRef.value) return//2.提交表单await ruleFormRef.value.validate((valid) => {if (valid) {    // 校验成功confirm()}})}
// 取消对话表单框按钮事件
const onDialogFormCancel = () => {console.log("cancel......")dialogFormVisible.value = falserestForm()
}// 添加按钮事件
const onAdd = () => {// 打开对话框title.value = '添加用户'isAdd.value = truedialogFormVisible.value = true
}// 修改按钮事件
const handleEdit = async (index, row) => {title.value = '修改用户'isAdd.value = false// 回显数据console.log("row:", row)const id = {id: row.id}let result = await getUserById(id)form.value = result.data// 控制只读属性dialogFormVisible.value = true
}// 删除按钮事件
const handleDelete = (index, row) => {ElMessageBox.confirm('确认要删除吗?','提示',{confirmButtonText: '确认',cancelButtonText: '取消',type: 'warning',}).then( async () => {// 删除console.log("delete=====")let result = await deleteByIdService(row.id)ElMessage.success(result.msg ? result.msg : '删除成功')getPageList()}).catch(() => {})
}// 提交表单
const confirm = async () => {if(isAdd.value) {// 添加try {   // 添加成功let result = await addUserService(form.value)ElMessage.success(result.msg ? result.msg : '添加成功')// 关闭弹窗,清空表单dialogFormVisible.value = falserestForm()getPageList()} catch (error) {}} else {console.log("update=======")//修改try {   // 修改成功let result = await updateUserService(form.value)ElMessage.success(result.msg ? result.msg : '修改成功')// 关闭弹窗,清空表单dialogFormVisible.value = falserestForm()getPageList()} catch (error) {}}}/** 表单校验 */
const ruleFormRef = ref(null)   // 定义表单组件的引用
// 定义表单校验规则
const rules = ref({loginName: [{ required: true, message: '请输入账号名', trigger: 'blur' }],name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],phone: [{ required: true, trigger: 'blur',  message: "请输入正确手机号", validator: checkPhone }]
})// 手机号自定义校验
var checkPhone = (rule, value, callback) => {if (!value) {return callback(new Error('手机号不能为空'))} else {const reg = /^1[3|4|5|7|8][0-9]\d{8}$/console.log(reg.test(value))if (reg.test(value)) {callback()} else {return callback(new Error('请输入正确的手机号'))}}
}</script><template><div><!-- 工具栏 --><div><el-row><el-col :span="8"><!-- 操作按钮 --><div class="operation-div"><el-button type="primary" @click="onAdd">添加</el-button></div></el-col><el-col :span="16"><!-- 条件查询 --><div class="search-div"><el-form :inline="true" :model="searchData" class="demo-form-inline"><el-form-item label="用户名:"><el-inputv-model="searchData.name"placeholder="请输入用户名"clearable/></el-form-item><el-form-item><el-button type="primary" @click="onSearch">查询</el-button><el-button type="primary" @click="onRest">重置</el-button></el-form-item></el-form></div></el-col></el-row></div><!-- 表格内容 --><div><el-table:data="tableData"borderstripestyle="width: 100%":header-cell-style="{ background: '#ECF5FF' }"><el-table-column type="index" :index="indexMethod" /><el-table-column prop="loginName" label="账号" /><el-table-column prop="name" label="姓名" /><el-table-column prop="phone" label="联系电话" /><el-table-column prop="sex" label="性别"><template #default="scope"><el-tag :type="scope.row.sex === '0'? '' : 'success'" disable-transitions>{{ scope.row.sex === '1' ? "男" : "女" }}</el-tag></template></el-table-column><el-table-column label="操作"><template #default="scope"><el-button size="small" @click="handleEdit(scope.$index, scope.row)">编辑</el-button><el-buttonsize="small"type="danger"@click="handleDelete(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table><!-- 分页 --><div style="margin-top: 20px"><el-paginationv-model:current-page="pageData.currentPage"v-model:page-size="pageData.pageSize":page-sizes="[10, 20, 50, 100]"backgroundlayout="->, jumper, total, sizes, prev, pager, next":total="pageData.total"@size-change="handleSizeChange"@current-change="handleCurrentChange"/></div></div></div><!-- 添加修改对话框表单--><el-dialog v-model="dialogFormVisible" :title="title" width="500" draggable overflow @close='onDialogFormCancel'><el-form :model="form" ref="ruleFormRef" :rules="rules"><el-form-item label="账号" prop="loginName"><el-input v-model="form.loginName" :disabled="!isAdd"/></el-form-item><el-form-item label="姓名" prop="name"><el-input v-model="form.name" :disabled="!isAdd"/></el-form-item><el-form-item label="电话" prop="phone"><el-input v-model="form.phone" /></el-form-item><el-form-item label="性别"><el-radio-group v-model="form.sex" :disabled="!isAdd"><el-radio value="0" checked>女</el-radio><el-radio value="1">男</el-radio></el-radio-group></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button @click="onDialogFormCancel">取消</el-button><el-button type="primary" @click="onDialogFormConfirm">确认</el-button></div></template></el-dialog>
</template><style scoped>
.operation-div {width: 100%;text-align: left;padding-left: 10px;padding-top: 10px;
}.search-div {width: 100%;text-align: right;padding-top: 10px;
}
</style>

2.9 运行展示

2.9.1 启动前端

  • cnpm run dev

在这里插入图片描述

进入http://localhost:5173

2.9.2 启动后端

运行后端项目

2.9.3 测试

登录界面,使用之前swagger测试时添加的用户登录即可。

在这里插入图片描述

在这里插入图片描述

http://www.lryc.cn/news/500946.html

相关文章:

  • 手写Mybatis框架源码(简写)
  • Flask返回中文Unicode编码(乱码)解决方案
  • 最大值和最小值的差
  • 如何在 IntelliJ IDEA 中为 Spring Boot 应用实现热部署
  • 探索 Java 中的 Bug 世界
  • SQL面试题——百度SQL面试题 连续签到领金币
  • easyExcel单一下拉框和级联下拉框
  • linux-安全-iptables防火墙基础笔记
  • 力扣刷题TOP101: 25.BM32合并二叉树
  • R的中文文本处理包--tmcn
  • 差异基因富集分析(R语言——GOKEGGGSEA)
  • scrapy对接rabbitmq的时候使用post请求
  • vue+elementUI+transition实现鼠标滑过div展开内容,鼠标划出收起内容,加防抖功能
  • 大模型语料库的构建过程 包括知识图谱构建 垂直知识图谱构建 输入到sql构建 输入到cypher构建 通过智能体管理数据生产组件
  • 阿里云ECS服务器域名解析
  • 牛客周赛71:A:JAVA
  • 查询产品所涉及的表有(product、product_admin_mapping)
  • 算法基础学习Day5(双指针、动态窗口)
  • docker 部署 mysql 9.0.1
  • 关于小标join大表,操作不当会导致笛卡尔积,数据倾斜
  • SpringMVC全局异常处理
  • 出海服务器可以用国内云防护吗
  • 从零开始的使用SpringBoot和WebSocket打造实时共享文档应用
  • Ant Design Pro实战--day01
  • pcl点云库离线版本构建
  • 字节高频算法面试题:小于 n 的最大数
  • ElasticSearch常见面试题汇总
  • Spring Boot如何实现防盗链
  • 工作中常用springboot启动后执行的方法
  • 力扣-图论-3【算法学习day.53】