1、vue介绍
Vue.js - 渐进式 JavaScript 框架 | Vue.js
2、node等环境安装
node安装参考博文:
Node.js安装与配置(详细步骤)_node安装_普通网友的博客-CSDN博客
npm install -g cnpm --registry=https://registry.npm.taobao.org
注意:需要把路径放在环境变量中
cnpm i yarn -g
3、项目创建
vue create flask_works_li_front
添加上面一行代码,可以避免每编译修改代码实时启动审查!
HomeView.vue:
<template>
<h1> Hello World </h1>
<p v-text="name"></p>
<!-- v-text的简写 -->
<p>{
{name}}</p>
</template>
<script>
import {reactive,toRefs} from "vue"
export default {
name: "home",
setup() {
// beforeCreate和created 两个生命周期
const data = reactive(
{
name: "小红",
age: 25
}
)
return {
...toRefs(data)
}
}
}
</script>
4、模板语法 Trim
HomeView.vue:
<template>
<h1> Hello World </h1>
<p v-text="name"></p>
<!-- v-text的简写 -->
<p>{
{name}}</p>
<!-- v-html -->
<p>{
{info}}</P>
<p v-html="info"></p>
<!-- v-bind:属性名="变量名" 绑定动态的标签属性 简写: :属性名="变量名"-->
<p v-bind:data="dataVul">我有属性data</p>
<!-- class类名绑定 -->
<p :class="{'red': isRed}">我是红色</p>
<p :class="{'red': !isRed}">我是红色</p>
<!-- class类名绑定 可以叠加使用-->
<p class="text" :class="{'red': isRed}">我是红色</p>
<!-- 判断语句 v-if false的时候 是元素未渲染在页面-->
<!-- v-show :false的时候 是样式上的隐藏-->
<p v-if="isTrue">我是if存在</p>
<p v-show="isTrue">我是show展示</p>
<p v-if="isFalse">我是if存在</p>
<p v-show="isFalse">我是show展示</p>
<p v-if="isFalse">if</p>
<p v-else>else</p>
</template>
<script>
import {reactive,toRefs} from "vue"
export default {
name: "home",
setup() {
// beforeCreate和created 两个生命周期
const data = reactive(
{
name: "小红",
age: 25,
info: "<i>我是斜体字</i>",
dataVul: 2,
isRed: true,
isTrue: true,
isFalse: false
}
)
return {
...toRefs(data)
}
}
}
</script>
<style>
.red{
color: red
}
</style>
5、for循环
HomeView.vue:
<template>
<h1> Hello World </h1>
<p v-text="name"></p>
<!-- v-text的简写 -->
<p>{
{name}}</p>
<!-- v-html -->
<p>{
{info}}</P>
<p v-html="info"></p>
<!-- v-bind:属性名="变量名" 绑定动态的标签属性 简写: :属性名="变量名"-->
<p v-bind:data="dataVul">我有属性data</p>
<!-- class类名绑定 -->
<p :class="{'red': isRed}">我是红色</p>
<p :class="{'red': !isRed}">我是红色</p>
<!-- class类名绑定 可以叠加使用-->
<p class="text" :class="{'red': isRed}">我是红色</p>
<!-- 判断语句 v-if false的时候 是元素未渲染在页面-->
<!-- v-show :false的时候 是样式上的隐藏-->
<p v-if="isTrue">我是if存在</p>
<p v-show="isTrue">我是show展示</p>
<p v-if="isFalse">我是if存在</p>
<p v-show="isFalse">我是show展示</p>
<p v-if="isFalse">if</p>
<p v-else>else</p>
<!-- for循环 -->
<ul>
<!-- 循环此数组userList -->
<!-- v-for="(每一个对象的变量, 下标) in 数组" -->
<li v-for="(item, index) in userList" :key="index" >
学生姓名:{
{item.username}}
学生年龄:{
{item.userage}}
</li>
</ul>
</template>
<script>
import {reactive,toRefs} from "vue"
export default {
name: "home",
setup() {
// beforeCreate和created 两个生命周期
const data = reactive(
{
name: "小红",
age: 25,
info: "<i>我是斜体字</i>",
dataVul: 2,
isRed: true,
isTrue: true,
isFalse: false,
userList:[
{
username: "小红",
userage:15
},
{
username: "小花",
userage:16
},
{
username: "小文",
userage:17
}
]
}
)
return {
...toRefs(data)
}
}
}
</script>
<style>
.red{
color: red
}
</style>
6、生命周期
AboutView.vue
<template>
<div>
<h1>vue3的生命周期</h1>
<div id="dom">{
{msg}}--{
{num}}</div>
</div>
</template>
<script>
import {reactive,toRefs, onBeforeMount, onMounted, onBeforeUpdate, onUpdated} from "vue"
export default {
name: "about",
setup() {
const data = reactive(
{
msg: "您好!",
msg2: "hello",
num: 0
}
)
// 数据渲染前
onBeforeMount(()=>{
console.log("onBeforeMount", document.querySelector("#dom"))
})
// 数据渲染后
onMounted(()=>{
console.log("onMounted", document.querySelector("#dom"))
setTimeout(()=>{
data.msg="hello world"
//data.msg2="hello world"
}, 2000)
})
// dom更新前
onBeforeUpdate(()=>{
console.log("onBeforeUpdate")
})
// dom更新前
onUpdated(()=>{
console.log("onUpdated")
//data.num += 1 // 触发死循环
})
return {
...toRefs(data)
}
}
}
</script>
7、事件绑定
AboutView.vue:
<template>
<div>
<h1>vue3的生命周期</h1>
<div id="dom">{
{msg}}--{
{num}}</div>
<!-- v-on:事件名="事件方法" 绑定事件 简写@:事件名="事件方法" -->
<!-- 事件及方法直接声明在 setup内 -->
<button v-on:click="handleClick">click me</button>
<hr>
<!-- v-model 双向绑定 -->
<!-- input:输入事件
blur:失去焦点
focus:获取焦点
change:内容更改
-->
<input type="text" placeholder="请输入姓名" v-model="userName"><br/>
<input type="text" placeholder="请输入电话" v-model="userPhone" @focus="handleFocus" @blur="handleBlur" @input="handleInput"><br/>
<textarea placeholder="请输入您的建议" cols="30" rows="10" v-model="userInput"></textarea>
<p>{
{userName}}--{
{userInput}}</P>
<button @click="submit">提交</button>
</div>
</template>
<script>
import {reactive,toRefs, onBeforeMount, onMounted, onBeforeUpdate, onUpdated} from "vue"
export default {
name: "about",
setup() {
const data = reactive(
{
msg: "您好!",
msg2: "hello",
num: 0,
userName: "",
userInput: "",
userPhone: ""
}
)
// 数据渲染前
onBeforeMount(()=>{
console.log("onBeforeMount", document.querySelector("#dom"))
})
// 数据渲染后
onMounted(()=>{
console.log("onMounted", document.querySelector("#dom"))
setTimeout(()=>{
data.msg="hello world"
//data.msg2="hello world"
}, 2000)
})
// dom更新前
onBeforeUpdate(()=>{
console.log("onBeforeUpdate")
})
// dom更新前
onUpdated(()=>{
console.log("onUpdated")
//data.num += 1 // 触发死循环
})
//事件及方法
const handleClick=()=>{
alert("您好")
}
const submit=()=>{
alert(`${data.userName}的建议是${data.userInput}`) //注意:这儿不是单引号,是Tab键上面的符号
}
const handleFocus=()=>{
console.log("获取焦点了")
}
const handleBlur=()=>{
console.log("失去焦点了")
if(!data.userPhone){
alert("手机号必填!")
}
}
const handleInput=()=>{
//正则验证手机号
if(!/^[1][3,4,5,6,7,8][0-9]{9}$/.test(data.userPhone)){
console.log("不符合手机号!")
}
}
return {
...toRefs(data),
handleClick, //所有的事件及方法都需要return,否则捕捉不到
submit,
handleFocus,
handleBlur,
handleInput
}
}
}
</script>
8、路由配置
createWebHistory模式:
createWebHashHistory模式:
index.js:
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import ABC from '../views/ABC.vue'
// 哈希路由和历史路由
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/abc', //路由地址
name: 'ABC', //路由名字
//component: ABC //页面组件
component: () => import('../views/ABC.vue') //建议使用懒加载的模式,大量路由下可以提交效率
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
ABC.vue:
<template>
<div>
<h1>路由ABC测试</h1>
</div>
</template>
<script>
import {reactive,toRefs} from "vue"
export default {
name: "abc"
}
</script>
App.vue:
<template>
<nav>
<!-- 相当于a标签,to="路由path" -->
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
<!-- router-view:展示路由对应的组件内容 -->
<router-view/>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>
9、LayOut
router.index.js:
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
//import ABC from '../views/ABC.vue'
// 哈希路由和历史路由
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/index', //路由地址
name: 'layOut', //路由名字
//component: layOut //页面组件
component: () => import('../views/LayOut/LayOut.vue') //建议使用懒加载的模式,大量路由下可以提交效率
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
APP.vue:
<template>
<!--
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
-->
<!-- router-view:展示路由对应的组件内容 -->
<router-view/>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
/* flex布局类名 */
.flex-float{
display: flex;
justify-content: space-between;
align-items: center;
}
.flex{
display: flex;
align-items: center;
}
</style>
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App)
// element icon注册
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(store).use(router).use(ElementPlus).mount('#app')
router.index.js
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
//import ABC from '../views/ABC.vue'
// 哈希路由和历史路由
const routes = [
/* {
path: '/',
name: 'home',
component: HomeView
}, */
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/', //路由地址
name: 'layout', //路由名字
redirect: '/users',
//component: LayOut //页面组件
component: () => import('../views/LayOut/LayOut.vue'), //建议使用懒加载的模式,大量路由下可以提交效率
// 子路由|嵌套路由
children: [
{
path: '/users',
name: 'users',
component:()=>import("../views/pages/usersList.vue")
},
{
path: "/roles",
name: "roles",
component:()=>import("../views/pages/rolesList.vue")
}
]
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
LayOut.vue:
<template>
<div class="common-layout">
<el-container>
<el-header class="common-header flex-float">
<div class="flex">
<img class="logo" src="../../assets/logo.png" alt />
<h1 class="title">后台管理系统</h1>
</div>
<el-button type="danger">退出</el-button>
</el-header>
<el-container>
<el-aside class="common-aside" width="200px">
<el-menu
background-color="none"
text-color="#fff"
:router="true"
>
<el-sub-menu index="1">
<template #title>
<el-icon><Avatar /></el-icon>
<span>账号管理</span>
</template>
<el-menu-item-group>
<el-menu-item index="/users">账号列表</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><UserFilled /></el-icon>
<span>角色管理</span>
</template>
<el-menu-item-group>
<el-menu-item index="/roles">角色列表</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
import { reactive, toRefs } from "vue";
export default {
name: "layout"
};
</script>
<style>
.el-container {
height: 100vh;
overflow: hidden;
}
.common-header {
background: rgb(26, 30, 36);
display: flex;
}
.common-aside {
background: rgb(59, 117, 199);
}
.logo {
width: 80px;
}
.title {
color: #ffffff;
}
</style>
usersList.vue:
<template>
<div>
<h1>用户列表</h1>
</div>
</template>
<script>
export default {
name: "users"
}
</script>
rolesList.vue:
<template>
<div>
<h1>角色列表</h1>
</div>
</template>
<script>
export default {
name: "roles"
}
</script>
10、登录框页面
router.index.js
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
//import ABC from '../views/ABC.vue'
// 哈希路由和历史路由
const routes = [
// 登录页面
{
path: '/login',
name: 'login',
component: () => import("../views/pages/login.vue")
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/page', //路由地址
name: 'layout', //路由名字
// redirect: '/users',
//component: LayOut //页面组件
component: () => import('../views/LayOut/LayOut.vue'), //建议使用懒加载的模式,大量路由下可以提交效率
// 子路由|嵌套路由
children: [
{
path: '/users',
name: 'users',
component:()=>import("../views/pages/usersList.vue")
},
{
path: "/roles",
name: "roles",
component:()=>import("../views/pages/rolesList.vue")
}
]
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
login.vue:
<template>
<div class="login_wrap">
<div class="form_wrap">
<el-form ref="formRef" :model="loginData" label-width="80px" class="demo-dynamic">
<el-form-item
prop="username"
label="用户名"
:rules="[
{
required: true,
message: '此项为必填项',
trigger: 'blur',
},
]"
>
<el-input v-model="loginData.username" />
</el-form-item>
<el-form-item
prop="password"
label="密码"
:rules="[
{
required: true,
message: '此项为必填项',
trigger: 'blur',
},
]"
>
<el-input type="password" v-model="loginData.password" />
</el-form-item>
</el-form>
<el-button type="primary" class="login_btn">登录</el-button>
<el-button type="primary" class="reset_btn">重置</el-button>
</div>
</div>
</template>
<script>
import { reactive, toRefs } from "vue";
export default {
name: "login",
setup() {
const data = reactive({
loginData: {
username: "",
password: ""
}
});
return {
...toRefs(data)
};
}
};
</script>
<style scoped>
.login_wrap {
width: 100%;
height: 100vh;
background: rgb(75, 187, 187);
position: relative;
}
.form_wrap {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #ffffff;
padding: 30px 50px;
border-radius: 5px;
}
.login_btn{
display: inline-block;
/* margin: 10px auto; */
}
.reset_btn{
display: inline-block;
/* margin: 10px auto; */
margin-right: 10px;
}
</style>>
11、vuex
store.index.js:
import { createStore } from 'vuex'
import number from "./state/num.state.js"
export default createStore({
// 数据比较多时,分模块
modules: {
number
}
})
store.state.num.state.js:
export default {
namespaced: true,
// 全局的状态初始值
state: {
count: 1,
},
// 计算state,获取对应的值
getters: {
countStatus(status) {
return status.count <= 1
}
},
// 更新状态的方法-更新state的唯一方法,commit mutations
mutations: {
setCount(state, num) {
state.count = num
}
},
// 可以异步操作,可以返回promise,更改数据还是传递到mutations去更改
actions: {
setCountPromise(context, num) {
return new Promise((resolve, reject) => {
if (num > 100) {
reject("值不能大于100")
} else {
context.commit("setCount", num)
resolve()
}
})
}
},
}
views.page.login.vue:
<template>
<div class="login_wrap">
<div class="form_wrap">
<el-form ref="formRef" :model="loginData" label-width="80px" class="demo-dynamic">
<el-form-item
prop="username"
label="用户名"
:rules="[
{
required: true,
message: '此项为必填项',
trigger: 'blur',
},
]"
>
<el-input v-model="loginData.username" />
</el-form-item>
<el-form-item
prop="password"
label="密码"
:rules="[
{
required: true,
message: '此项为必填项',
trigger: 'blur',
},
]"
>
<el-input type="password" v-model="loginData.password" />
</el-form-item>
</el-form>
<el-button type="primary" class="login_btn" @click="handleLogin">登录</el-button>
<el-button type="primary" class="reset_btn">重置</el-button>
<p>{
{num}}</p>
</div>
</div>
</template>
<script>
import { reactive, toRefs } from "vue";
import {useStore } from "vuex";
export default {
name: "login",
setup() {
const store = useStore()
const count = store.state.count
const data = reactive({
loginData: {
username: "",
password: ""
},
num: count,
numStatus: store.getters.countStatus
});
console.log("修改前getters:", store.getters['number/countStatus']) // 变量不符合语法时,使用中括号就可以了
const handleLogin=()=>{
// store.commit('number/setCount', 100);
store.dispatch("number/setCountPromise", 101).then(res=>{
alert("修改成功")
}).catch(err=>{
alert(err)
})
console.log(store.state.number.count)
console.log("修改后getters:", store.getters['number/countStatus']) // 变量不符合语法时,使用中括号就可以了
}
return {
...toRefs(data),
handleLogin
};
}
};
</script>
<style scoped>
.login_wrap {
width: 100%;
height: 100vh;
background: rgb(75, 187, 187);
position: relative;
}
.form_wrap {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #ffffff;
padding: 30px 50px;
border-radius: 5px;
}
.login_btn{
display: inline-block;
/* margin: 10px auto; */
}
.reset_btn{
display: inline-block;
/* margin: 10px auto; */
margin-right: 10px;
}
</style>>
12、路由守卫及登录状态存储
store.index.js:
import { createStore } from 'vuex'
import number from "./state/num.state.js"
import uInfo from "./state/userinfo.state.js"
export default createStore({
// 数据比较多时,分模块
modules: {
number,
uInfo
}
})
router.index.js:
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import store from "../store/index.js"
//import ABC from '../views/ABC.vue'
// 哈希路由和历史路由
const routes = [
// 登录页面
{
path: '/login',
name: 'login',
component: () => import("../views/pages/login.vue")
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/page', //路由地址
name: 'layout', //路由名字
// redirect: '/users',
//component: LayOut //页面组件
component: () => import('../views/LayOut/LayOut.vue'), //建议使用懒加载的模式,大量路由下可以提交效率
// 子路由|嵌套路由
children: [
{
path: '/users',
name: 'users',
component:()=>import("../views/pages/usersList.vue")
},
{
path: "/roles",
name: "roles",
component:()=>import("../views/pages/rolesList.vue")
}
]
}
]
// 生成历史路由
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to,from,next)=>{
/**
* to:从哪个页面
* from:到哪个页面
* next:只有执行next()页面才会进行跳转
*/
// 判断用户是否登录
console.log("store", store.state.uInfo)
const uInfo = store.state.uInfo.userInfo
if(!uInfo.username){
// 未登录,跳转到login
if(to.path=="/login"){
next()
return
}
next("/login")
}else{
next()
}
})
// 暴露路由对象
export default router
views.LayOut.LayOut.vue:
<template>
<div class="common-layout">
<el-container>
<el-header class="common-header flex-float">
<div class="flex">
<img class="logo" src="../../assets/logo.png" alt />
<h1 class="title">后台管理系统</h1>
</div>
<el-button type="danger" @click="loginOut">退出</el-button>
</el-header>
<el-container>
<el-aside class="common-aside" width="200px">
<el-menu
background-color="none"
text-color="#fff"
:router="true"
>
<el-sub-menu index="1">
<template #title>
<el-icon><Avatar /></el-icon>
<span>账号管理</span>
</template>
<el-menu-item-group>
<el-menu-item index="/users">账号列表</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><UserFilled /></el-icon>
<span>角色管理</span>
</template>
<el-menu-item-group>
<el-menu-item index="/roles">角色列表</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
// import { reactive, toRefs } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router"
export default {
name: "layout",
setup(){
const store = useStore()
const router = useRouter()
const loginOut=()=>{
localStorage.removeItem("loginData")
store.commit("setUserInfo", {});
router.push({
path:"/login"
})
}
return{
loginOut
}
}
};
</script>
<style>
.el-container {
height: 100vh;
overflow: hidden;
}
.common-header {
background: rgb(26, 30, 36);
display: flex;
}
.common-aside {
background: rgb(59, 117, 199);
}
.logo {
width: 80px;
}
.title {
color: #ffffff;
}
</style>
views.pages.login.vue:
<template>
<div class="login_wrap">
<div class="form_wrap">
<el-form ref="formRef" :model="loginData" label-width="80px" class="demo-dynamic">
<el-form-item
prop="username"
label="用户名"
:rules="[
{
required: true,
message: '此项为必填项',
trigger: 'blur',
},
]"
>
<el-input v-model="loginData.username" />
</el-form-item>
<el-form-item
prop="password"
label="密码"
:rules="[
{
required: true,
message: '此项为必填项',
trigger: 'blur',
},
]"
>
<el-input type="password" v-model="loginData.password" />
</el-form-item>
</el-form>
<el-button type="primary" class="login_btn" @click="handleLogin">登录</el-button>
<el-button type="primary" class="reset_btn">重置</el-button>
<!-- <p>{
{num}}</p> -->
</div>
</div>
</template>
<script>
import { reactive, toRefs } from "vue";
import {useStore } from "vuex";
import {useRouter} from "vue-router"
export default {
name: "login",
setup() {
const store = useStore()
const router = useRouter()
const count = store.state.count
const data = reactive({
loginData: {
username: "",
password: ""
},
num: count,
});
const handleLogin=()=>{
store.commit('setUserInfo', data.loginData)
localStorage.setItem("loginData", JSON.stringify(data.loginData))
// 跳转/user
router.push({
path:"/users"
})
}
// vuex 修改语法
// console.log("修改前getters:", store.getters['number/countStatus']) // 变量不符合语法时,使用中括号就可以了
// const handleLogin=()=>{
// // store.commit('number/setCount', 100);
// store.dispatch("number/setCountPromise", 101).then(res=>{
// alert("修改成功")
// }).catch(err=>{
// alert(err)
// })
// console.log(store.state.number.count)
// console.log("修改后getters:", store.getters['number/countStatus']) // 变量不符合语法时,使用中括号就可以了
// }
return {
...toRefs(data),
handleLogin
};
}
};
</script>
<style scoped>
.login_wrap {
width: 100%;
height: 100vh;
background: rgb(75, 187, 187);
position: relative;
}
.form_wrap {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #ffffff;
padding: 30px 50px;
border-radius: 5px;
}
.login_btn{
display: inline-block;
/* margin: 10px auto; */
}
.reset_btn{
display: inline-block;
/* margin: 10px auto; */
margin-right: 10px;
}
</style>>
store.state.userinfo.state.js:
export default{
state:{
// userInfo:{}
userInfo:(localStorage.getItem("loginData")&&JSON.parse(localStorage.getItem("loginData")))||{}
},
mutations:{
setUserInfo(state,uInfo){
state.userInfo=uInfo
}
}
}
13、axios封装
新建:
utils.service.js:
import axios from "axios"
import { ElLoading } from "element-plus"
import { ElMessage } from "element-plus"
// 使用create创建axios实例
let loadingObj = null
const Service = axios.create({
timeout: 8000,
baseURL: "http://XXX",
headers:{
"Content-type": "application/json;charset=utf-8"
}
})
// 请求拦截-增加loading,对请求做统一处理
Service.interceptors.request.use(config=>{
loadingObj=ElLoading.service({
lock: true,
text: "Loading",
background: "rgba(0, 0, 0, 0.7)",
})
return config
})
// 响应拦截-对返回值做统一处理
Service.interceptors.response.use(response=>{
loadingObj.close()
return response.data
},error=>{
loadingObj.close()
ElMessage({
message: "服务器错误",
type: "error",
duration: "2000"
})
})
14、登录接口及用户列表展示
utils.service.js:
import axios from "axios"
import { ElLoading } from "element-plus"
import { ElMessage } from "element-plus"
import store from "../store/index.js"
// 使用create创建axios实例
let loadingObj = null
const Service = axios.create({
timeout: 8000,
baseURL: "http://127.0.0.1:5000/",
headers:{
"Content-type": "application/json;charset=utf-8",
// "Authorization": store.state.uInfo.userInfo.token
"Authorization": "token"
}
})
// 请求拦截-增加loading,对请求做统一处理
Service.interceptors.request.use(config=>{
loadingObj=ElLoading.service({
lock: true,
text: "Loading",
background: "rgba(0, 0, 0, 0.7)",
})
return config
})
// 响应拦截-对返回值做统一处理
Service.interceptors.response.use(response=>{
loadingObj.close()
const data = response.data
if(!data.data){
// 请求出错
ElMessage.error(data.meta.msg || "服务器出错")
return data
}
return data
},error=>{
loadingObj.close()
ElMessage({
message: "服务器错误",
type: "error",
duration: "2000"
})
})
// post请求
export const post=config=>{
return Service({
...config,
method: "post",
data: config.data
})
}
// get请求
export const get=config=>{
return Service({
...config,
method: "get",
params: config.data
})
}
views.pages.index.vue:
<template>
<div>
<h1>欢迎来到用户管理系统</h1>
</div>
</template>
<script>
export default {
name: "index"
}
</script>
router.index.js:
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import store from "../store/index.js"
//import ABC from '../views/ABC.vue'
// 哈希路由和历史路由
const routes = [
// 登录页面
{
path: '/login',
name: 'login',
component: () => import("../views/pages/login.vue")
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
},
{
path: '/', //路由地址
name: 'layout', //路由名字
redirect: '/index',
//component: LayOut //页面组件
component: () => import('../views/LayOut/LayOut.vue'), //建议使用懒加载的模式,大量路由下可以提交效率
// 子路由|嵌套路由
children: [
{
path: '/index',
name: 'index',
component:()=>import("../views/pages/index.vue")
},
{
path: '/users',
name: 'users',
component:()=>import("../views/pages/usersList.vue")
},
{
path: "/roles",
name: "roles",
component:()=>import("../views/pages/rolesList.vue")
}
]
}
]
// 生成历史路由
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to,from,next)=>{
/**
* to:从哪个页面
* from:到哪个页面
* next:只有执行next()页面才会进行跳转
*/
// 判断用户是否登录
console.log("store", store.state.uInfo)
const uInfo = store.state.uInfo.userInfo
if(!uInfo.username){
// 未登录,跳转到login
if(to.path=="/login"){
next()
return
}
next("/login")
}else{
next()
}
})
// 暴露路由对象
export default router
views.pages.userList.vue:
<template>
<div>
<!-- 面包屑-->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">账号管理</el-breadcrumb-item>
<el-breadcrumb-item>
<a href="/">账号列表</a>
</el-breadcrumb-item>
</el-breadcrumb>
<!-- 白色内容区域 -->
<div class="page_content">
<div class="input_box">
<div class="flex">
<el-input v-model="keyWord" placeholder="搜索关键字" class="input-with-select">
<template #append>
<el-button @click="searchList">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary" @click="addUser">新建用户</el-button>
</div>
</div>
<!-- 表格 -->
<!--
el-table 的 data:要展示的数据数组
el-table-column: 列 prop每条数据的对应属性
label: 列标题
scope.row:相当于一条数据
-->
<el-table :data="userList" style="width: 100%">
<el-table-column prop="username" label="姓名" width="180" />
<el-table-column prop="role_name" label="角色" width="180" />
<el-table-column prop="age" label="年龄" width="180" />
<el-table-column prop="email" label="邮箱" width="180" />
<el-table-column prop="mobile" label="手机号" />
<el-table-column prop="ms_state" label="状态">
<template #default="scope">
<el-switch v-model="scope.row.ms_state" />
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary">编辑</el-button>
<el-button type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import { toRefs, reactive } from "vue";
import { userListApi } from "@/utils/request.js";
export default {
name: "users",
setup() {
const data = reactive({
keyWord: "",
searchParams: {
query: "",
pagesize: 5,
pagenum: 1
},
userList: []
});
const searchList = () => {
userListApi(data.searchParams).then(res => {
if (res.data) {
//
// console.log("用户数据", res);
data.userList = res.data.users;
}
});
};
const addUser = () => {};
// 方法初始化
searchList();
return {
...toRefs(data),
searchList,
addUser
};
}
};
</script>
<style scoped>
.input_box {
width: 250px;
margin-right: 15x;
}
</style>
views.pages.roleList.vue:
<template>
<div>
<!-- 面包屑-->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">角色管理</el-breadcrumb-item>
<el-breadcrumb-item>
<a href="/">角色列表</a>
</el-breadcrumb-item>
</el-breadcrumb>
<!-- 白色内容区域 -->
<div class="page_content">
<div class="input_box">
<div class="flex">
<el-input v-model="input3" placeholder="搜索关键字" class="input-with-select">
<template #append>
<el-button>
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary">新建角色</el-button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "roles"
};
</script>
<style scoped>
.input_box {
width: 280px;
margin-right: 15px;
}
</style>
views.pages.login.vue:
<template>
<div class="login_wrap">
<div class="form_wrap">
<el-form ref="formRef" :model="loginData" label-width="80px" class="demo-dynamic">
<el-form-item
prop="username"
label="用户名"
:rules="[
{
required: true,
message: '此项为必填项',
trigger: 'blur',
},
]"
>
<el-input v-model="loginData.username" />
</el-form-item>
<el-form-item
prop="password"
label="密码"
:rules="[
{
required: true,
message: '此项为必填项',
trigger: 'blur',
},
]"
>
<el-input type="password" v-model="loginData.password" />
</el-form-item>
</el-form>
<el-button type="primary" class="login_btn" @click="handleLogin">登录</el-button>
<el-button type="primary" class="reset_btn">重置</el-button>
<!-- <p>{
{num}}</p> -->
</div>
</div>
</template>
<script>
import { reactive, toRefs } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { loginApi } from "@/utils/request.js";
export default {
name: "login",
setup() {
const store = useStore();
const router = useRouter();
const count = store.state.count;
const data = reactive({
loginData: {
username: "",
password: ""
},
num: count
});
const handleLogin=()=> {
// 请求后台接口
loginApi(data.loginData).then(res => {
if(res.data) {
store.commit("setUserInfo", res.data);
localStorage.setItem("loginData", JSON.stringify(data.loginData));
// 跳转/user
router.push({
path: "/index"
});
}
});
};
// vuex 修改语法
// console.log("修改前getters:", store.getters['number/countStatus']) // 变量不符合语法时,使用中括号就可以了
// const handleLogin=()=>{
// // store.commit('number/setCount', 100);
// store.dispatch("number/setCountPromise", 101).then(res=>{
// alert("修改成功")
// }).catch(err=>{
// alert(err)
// })
// console.log(store.state.number.count)
// console.log("修改后getters:", store.getters['number/countStatus']) // 变量不符合语法时,使用中括号就可以了
// }
return {
...toRefs(data),
handleLogin
};
}
};
</script>
<style scoped>
.login_wrap {
width: 100%;
height: 100vh;
background: rgb(75, 187, 187);
position: relative;
}
.form_wrap {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #ffffff;
padding: 30px 50px;
border-radius: 5px;
}
.login_btn {
display: inline-block;
/* margin: 10px auto; */
}
.reset_btn {
display: inline-block;
/* margin: 10px auto; */
margin-right: 10px;
}
</style>>
utils.request.js:
import { post, get } from "./service"
export const loginApi=data=>{
return post({
url: "/login",
data
})
}
// 获取用户列表
export const userListApi=data=>{
return get({
url: "/users",
data
})
}
App.vue:
<template>
<!--
<nav>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</nav>
-->
<!-- router-view:展示路由对应的组件内容 -->
<router-view/>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
/* flex布局类名 */
.flex-float{
display: flex;
justify-content: space-between;
align-items: center;
}
.flex{
display: flex;
align-items: center;
}
.page_content{
box-sizing: border-box;
display: block;
width: 100%;
padding: 20px;
background: #ffffff;
margin-top: 30px;
}
</style>
views.LayOut.LayOut.vue:
<template>
<div class="common-layout">
<el-container>
<el-header class="common-header flex-float">
<div class="flex">
<img class="logo" src="../../assets/logo.png" alt />
<h1 class="title">后台管理系统</h1>
</div>
<el-button type="danger" @click="loginOut">退出</el-button>
</el-header>
<el-container>
<el-aside class="common-aside" width="200px">
<el-menu
background-color="none"
text-color="#fff"
:router="true"
>
<el-sub-menu index="1">
<template #title>
<el-icon><Avatar /></el-icon>
<span>账号管理</span>
</template>
<el-menu-item-group>
<el-menu-item index="/users">账号列表</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><UserFilled /></el-icon>
<span>角色管理</span>
</template>
<el-menu-item-group>
<el-menu-item index="/roles">角色列表</el-menu-item>
</el-menu-item-group>
</el-sub-menu>
</el-menu>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
// import { reactive, toRefs } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router"
export default {
name: "layout",
setup(){
const store = useStore()
const router = useRouter()
const loginOut=()=>{
localStorage.removeItem("loginData")
store.commit("setUserInfo", {});
router.push({
path:"/login"
})
}
return{
loginOut
}
}
};
</script>
<style>
.el-container {
height: 100vh;
overflow: hidden;
}
.common-header {
background: rgb(26, 30, 36);
display: flex;
}
.common-aside {
background: rgb(59, 117, 199);
}
.logo {
width: 80px;
}
.title {
color: #ffffff;
}
.el-main{
background: #efefef;
}
</style>
15、新建用户表单及正则验证
utils.request.js:
import { post, get } from "./service"
export const loginApi=data=>{
return post({
url: "/login",
data
})
}
// 获取用户列表
export const userListApi=data=>{
return get({
url: "/users",
data
})
}
// 新增用户
export const userAddApi=data=>{
return post({
url: "/users",
data
})
}
views.pages.userList.vue:
<template>
<div>
<!-- 面包屑-->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">账号管理</el-breadcrumb-item>
<el-breadcrumb-item>
<a href="/">账号列表</a>
</el-breadcrumb-item>
</el-breadcrumb>
<!-- 白色内容区域 -->
<div class="page_content">
<div class="input_box">
<div class="flex">
<el-input v-model="keyWord" placeholder="搜索关键字" class="input-with-select">
<template #append>
<el-button @click="searchList">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary" @click="addUser">新建用户</el-button>
</div>
</div>
<!-- 表格 -->
<!--
el-table 的 data:要展示的数据数组
el-table-column: 列 prop每条数据的对应属性
label: 列标题
scope.row:相当于一条数据
-->
<el-table :data="userList" style="width: 100%">
<el-table-column prop="username" label="姓名" width="180" />
<el-table-column prop="role_name" label="角色" width="180" />
<el-table-column prop="age" label="年龄" width="180" />
<el-table-column prop="email" label="邮箱" width="180" />
<el-table-column prop="mobile" label="手机号" />
<el-table-column prop="ms_state" label="状态">
<template #default="scope">
<el-switch v-model="scope.row.ms_state" />
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary">编辑</el-button>
<el-button type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 弹窗 -->
<el-dialog v-model="dialogFormVisible" title="新建用户">
<!-- 表单 -->
<el-form ref="userForm" :model="formData" :rules="rules">
<el-form-item label="用户名称" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="formData.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitForm(userForm)">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { toRefs, reactive, ref } from "vue";
import { userListApi, userAddApi } from "@/utils/request.js";
export default {
name: "users",
setup() {
const data = reactive({
keyWord: "",
searchParams: {
query: "",
pagesize: 5,
pagenum: 1
},
userList: [],
dialogFormVisible: false,
formData: {
username: "",
password: "",
email: "",
mobile: ""
},
rules: {
username: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
password: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
email: [
{
required: false,
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
message: "请填写正确的邮箱",
trigger: "blur"
}
],
mobile: [
{
required: false,
pattern: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
message: "请填写正确的手机号",
trigger: "blur"
}
]
}
});
const searchList = () => {
userListApi(data.searchParams).then(res => {
if (res.data) {
//
// console.log("用户数据", res);
data.userList = res.data.users;
}
});
};
const addUser = () => {
data.dialogFormVisible = true;
};
const submitForm = formEl => {
// validate
formEl.validate(res => {
if (!res) {
return;
}
// 表单验证通过请求接口
// alert("通过")
userAddApi(data.formData).then(res => {
if (res.data) {
// 隐藏弹框
data.dialogFormVisible = false;
// 清空弹框数据
data.formData = {
username: "",
password: "",
email: "",
mobile: ""
};
// 重新更新列表
searchList()
}
});
});
};
// 方法初始化
searchList();
const userForm = ref();
return {
...toRefs(data),
searchList,
addUser,
submitForm,
userForm
};
}
};
</script>
<style scoped>
.input_box {
width: 250px;
margin-right: 15x;
}
</style>
16、用户列表分页
userList.vue:
<template>
<div>
<!-- 面包屑-->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">账号管理</el-breadcrumb-item>
<el-breadcrumb-item>
<a href="/">账号列表</a>
</el-breadcrumb-item>
</el-breadcrumb>
<!-- 白色内容区域 -->
<div class="page_content">
<div class="input_box">
<div class="flex">
<el-input v-model="keyWord" placeholder="搜索关键字" class="input-with-select">
<template #append>
<el-button @click="searchList">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary" @click="addUser">新建用户</el-button>
</div>
</div>
<!-- 表格 -->
<!--
el-table 的 data:要展示的数据数组
el-table-column: 列 prop每条数据的对应属性
label: 列标题
scope.row:相当于一条数据
-->
<el-table :data="userList" style="width: 100%">
<el-table-column prop="username" label="姓名" width="180" />
<el-table-column prop="role_name" label="角色" width="180" />
<el-table-column prop="age" label="年龄" width="180" />
<el-table-column prop="email" label="邮箱" width="180" />
<el-table-column prop="mobile" label="手机号" />
<el-table-column prop="ms_state" label="状态">
<template #default="scope">
<el-switch v-model="scope.row.ms_state" />
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary">编辑</el-button>
<el-button type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
background
layout="prev, pager, sizes, next, jumper, ->, total"
v-model:currentPage="searchParams.pagenum"
v-model:page-size="searchParams.pagesize"
:page-sizes="[2,3,5,10,20]"
:total="total"
@size-change="searchList"
@current-change="searchList"
/>
</div>
<!-- 弹窗 -->
<el-dialog v-model="dialogFormVisible" title="新建用户">
<!-- 表单 -->
<el-form ref="userForm" :model="formData" :rules="rules">
<el-form-item label="用户名称" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="formData.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitForm(userForm)">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { toRefs, reactive, ref } from "vue";
import { userListApi, userAddApi } from "@/utils/request.js";
export default {
name: "users",
setup() {
const data = reactive({
keyWord: "",
searchParams: {
query: "",
pagesize: 5,
pagenum: 2
},
total: 0,
userList: [],
dialogFormVisible: false,
formData: {
username: "",
password: "",
email: "",
mobile: ""
},
rules: {
username: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
password: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
email: [
{
required: false,
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
message: "请填写正确的邮箱",
trigger: "blur"
}
],
mobile: [
{
required: false,
pattern: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
message: "请填写正确的手机号",
trigger: "blur"
}
]
}
});
const searchList = () => {
userListApi(data.searchParams).then(res => {
if (res.data) {
//
// console.log("用户数据", res);
data.userList = res.data.users;
data.total = res.data.total
}
});
};
const addUser = () => {
data.dialogFormVisible = true;
};
const submitForm = formEl => {
// validate
formEl.validate(res => {
if (!res) {
return;
}
// 表单验证通过请求接口
// alert("通过")
userAddApi(data.formData).then(res => {
if (res.data) {
// 隐藏弹框
data.dialogFormVisible = false;
// 清空弹框数据
data.formData = {
username: "",
password: "",
email: "",
mobile: ""
};
// 重新更新列表
searchList()
}
});
});
};
// 方法初始化
searchList();
const userForm = ref();
return {
...toRefs(data),
searchList,
addUser,
submitForm,
userForm
};
}
};
</script>
<style scoped>
.input_box {
width: 250px;
margin-right: 15x;
}
</style>
17、用户状态更改
utils.service.js:
import axios from "axios"
import { ElLoading } from "element-plus"
import { ElMessage } from "element-plus"
import store from "../store/index.js"
// 使用create创建axios实例
let loadingObj = null
const Service = axios.create({
timeout: 8000,
baseURL: "http://127.0.0.1:5000/",
headers:{
"Content-type": "application/json;charset=utf-8",
// "Authorization": store.state.uInfo.userInfo.token
"Authorization": "token"
}
})
// 请求拦截-增加loading,对请求做统一处理
Service.interceptors.request.use(config=>{
loadingObj=ElLoading.service({
lock: true,
text: "Loading",
background: "rgba(0, 0, 0, 0.7)",
})
return config
})
// 响应拦截-对返回值做统一处理
Service.interceptors.response.use(response=>{
loadingObj.close()
const data = response.data
if(!data.data){
// 请求出错
ElMessage.error(data.meta.msg || "服务器出错")
return data
}
return data
},error=>{
loadingObj.close()
ElMessage({
message: "服务器错误",
type: "error",
duration: "2000"
})
})
// post请求
export const post=config=>{
return Service({
...config,
method: "post",
data: config.data
})
}
// get请求
export const get=config=>{
return Service({
...config,
method: "get",
params: config.data
})
}
// put请求
export const put=config=>{
return Service({
...config,
method: "put",
data: config.data
})
}
utils.request.js:
import { post, get, put } from "./service"
export const loginApi=data=>{
return post({
url: "/login",
data
})
}
// 获取用户列表
export const userListApi=data=>{
return get({
url: "/users",
data
})
}
// 新增用户
export const userAddApi=data=>{
return post({
url: "/users",
data
})
}
// 更改用户状态
export const userChangeStateApi=data=>{
return put({
url: `/users/${data.id}/state?mg_state=${data.mg_state}`,
data
})
}
views.pages.userList.vue:
<template>
<div>
<!-- 面包屑-->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">账号管理</el-breadcrumb-item>
<el-breadcrumb-item>
<a href="/">账号列表</a>
</el-breadcrumb-item>
</el-breadcrumb>
<!-- 白色内容区域 -->
<div class="page_content">
<div class="input_box">
<div class="flex">
<el-input v-model="keyWord" placeholder="搜索关键字" class="input-with-select">
<template #append>
<el-button @click="searchList">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary" @click="addUser">新建用户</el-button>
</div>
</div>
<!-- 表格 -->
<!--
el-table 的 data:要展示的数据数组
el-table-column: 列 prop每条数据的对应属性
label: 列标题
scope.row:相当于一条数据
-->
<el-table :data="userList" style="width: 100%">
<el-table-column prop="username" label="姓名" width="180" />
<el-table-column prop="role_name" label="角色" width="180" />
<el-table-column prop="age" label="年龄" width="180" />
<el-table-column prop="email" label="邮箱" width="180" />
<el-table-column prop="mobile" label="手机号" />
<el-table-column prop="mg_state" label="状态">
<template #default="scope">
<el-switch v-model="scope.row.mg_state" @change="swichChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary">编辑</el-button>
<el-button type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
background
layout="prev, pager, sizes, next, jumper, ->, total"
v-model:currentPage="searchParams.pagenum"
v-model:page-size="searchParams.pagesize"
:page-sizes="[2,3,5,10,20]"
:total="total"
@size-change="searchList"
@current-change="searchList"
/>
</div>
<!-- 弹窗 -->
<el-dialog v-model="dialogFormVisible" title="新建用户">
<!-- 表单 -->
<el-form ref="userForm" :model="formData" :rules="rules">
<el-form-item label="用户名称" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="formData.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitForm(userForm)">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { toRefs, reactive, ref } from "vue";
import {
userListApi,
userAddApi,
userChangeStateApi
} from "@/utils/request.js";
export default {
name: "users",
setup() {
const data = reactive({
keyWord: "",
searchParams: {
query: "",
pagesize: 5,
pagenum: 2
},
total: 0,
userList: [],
dialogFormVisible: false,
formData: {
username: "",
password: "",
email: "",
mobile: ""
},
rules: {
username: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
password: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
email: [
{
required: false,
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
message: "请填写正确的邮箱",
trigger: "blur"
}
],
mobile: [
{
required: false,
pattern: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
message: "请填写正确的手机号",
trigger: "blur"
}
]
}
});
const searchList = () => {
userListApi(data.searchParams).then(res => {
if (res.data) {
//
// console.log("用户数据", res);
data.userList = res.data.users;
data.total = res.data.total;
}
});
};
const addUser = () => {
data.dialogFormVisible = true;
};
const submitForm = formEl => {
// validate
formEl.validate(res => {
if (!res) {
return;
}
// 表单验证通过请求接口
// alert("通过")
userAddApi(data.formData).then(res => {
if (res.data) {
// 隐藏弹框
data.dialogFormVisible = false;
// 清空弹框数据
data.formData = {
username: "",
password: "",
email: "",
mobile: ""
};
// 重新更新列表
searchList();
}
});
});
};
// 状态更改
const swichChange = row => {
console.log("操作的那个数据是:", row);
userChangeStateApi(row).then(res => {
if (res.data) {
searchList()
}
});
};
// 方法初始化
searchList();
const userForm = ref();
return {
...toRefs(data),
searchList,
addUser,
submitForm,
userForm,
swichChange
};
}
};
</script>
<style scoped>
.input_box {
width: 250px;
margin-right: 15x;
}
</style>
17、用户修改
views.pages.userList.vue:
<template>
<div>
<!-- 面包屑-->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">账号管理</el-breadcrumb-item>
<el-breadcrumb-item>
<a href="/">账号列表</a>
</el-breadcrumb-item>
</el-breadcrumb>
<!-- 白色内容区域 -->
<div class="page_content">
<div class="input_box">
<div class="flex">
<el-input v-model="searchParams.query" placeholder="搜索关键字" class="input-with-select">
<template #append>
<el-button @click="searchList">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary" @click="addUser">新建用户</el-button>
</div>
</div>
<!-- 表格 -->
<!--
el-table 的 data:要展示的数据数组
el-table-column: 列 prop每条数据的对应属性
label: 列标题
scope.row:相当于一条数据
-->
<el-table :data="userList" style="width: 100%">
<el-table-column prop="username" label="姓名" width="180" />
<el-table-column prop="role_name" label="角色" width="180" />
<el-table-column prop="age" label="年龄" width="180" />
<el-table-column prop="email" label="邮箱" width="180" />
<el-table-column prop="mobile" label="手机号" />
<el-table-column prop="mg_state" label="状态">
<template #default="scope">
<el-switch v-model="scope.row.mg_state" @change="swichChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" @click="editRow(scope.row)">编辑</el-button>
<el-button type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
background
layout="prev, pager, sizes, next, jumper, ->, total"
v-model:currentPage="searchParams.pagenum"
v-model:page-size="searchParams.pagesize"
:page-sizes="[2,3,5,10,20]"
:total="total"
@size-change="searchList"
@current-change="searchList"
/>
</div>
<!-- 新增弹窗 -->
<el-dialog v-model="dialogFormVisible" title="新建用户">
<!-- 表单 -->
<el-form ref="userForm" :model="formData" :rules="rules">
<el-form-item label="用户名称" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="formData.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitForm(userForm)">确定</el-button>
</div>
</template>
</el-dialog>
<!-- 编辑弹窗 -->
<el-dialog v-model="dialogFormEVisible" title="编辑用户">
<!-- 表单 -->
<el-form ref="userForm2" :model="formData2" :rules="rules2">
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData2.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData2.mobile" placeholder="请输入手机号" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitEForm(userForm2)">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { toRefs, reactive, ref } from "vue";
import {
userListApi,
userAddApi,
userChangeStateApi,
userChangeInfoApi
} from "@/utils/request.js";
export default {
name: "users",
setup() {
const data = reactive({
keyWord: "",
searchParams: {
query: "",
pagesize: 5,
pagenum: 2
},
total: 0,
userList: [],
dialogFormVisible: false,
dialogFormEVisible: false,
formData: {
username: "",
password: "",
email: "",
mobile: ""
},
formData2: {
id: "",
email: "",
mobile: ""
},
rules: {
username: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
password: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
email: [
{
required: false,
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
message: "请填写正确的邮箱",
trigger: "blur"
}
],
mobile: [
{
required: false,
pattern: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
message: "请填写正确的手机号",
trigger: "blur"
}
]
},
rules2: {
email: [
{
required: false,
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
message: "请填写正确的邮箱",
trigger: "blur"
}
],
mobile: [
{
required: false,
pattern: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
message: "请填写正确的手机号",
trigger: "blur"
}
]
}
});
const searchList = () => {
userListApi(data.searchParams).then(res => {
if (res.data) {
//
// console.log("用户数据", res);
data.userList = res.data.users;
data.total = res.data.total;
}
});
};
const addUser = () => {
data.dialogFormVisible = true;
};
// 新增提交
const submitForm = formEl => {
// validate
formEl.validate(res => {
if (!res) {
return;
}
// 表单验证通过请求接口
// alert("通过")
userAddApi(data.formData).then(res => {
if (res.data) {
// 隐藏弹框
data.dialogFormVisible = false;
// 清空弹框数据
data.formData = {
username: "",
password: "",
email: "",
mobile: ""
};
// 重新更新列表
searchList();
}
});
});
};
// 修改提交
const submitEForm = formEl => {
formEl.validate(res => {
if (!res) {
return;
}
// 修改提交
userChangeInfoApi(data.formData2).then(res => {
if (res.data) {
data.dialogFormEVisible=false;
searchList();
}
});
});
};
// 状态更改
const swichChange = row => {
console.log("操作的那个数据是:", row);
userChangeStateApi(row).then(res => {
if (res.data) {
searchList();
}
});
};
// 用户信息编辑
const editRow = row => {
console.log("编辑的那个数据是:", row);
// 展示编辑表单
const { email, mobile, id } = row;
data.dialogFormEVisible = true;
data.formData2.id = id;
data.formData2.email = email;
data.formData2.mobile = mobile;
// data.formData2.email=row.email
// data.formData2.mobile=row.mobile
// userChangeStateApi(row).then(res => {
// if (res.data) {
// searchList()
// }
// });
};
// 方法初始化
searchList();
const userForm = ref();
const userForm2 = ref();
return {
...toRefs(data),
searchList,
addUser,
submitForm,
submitEForm,
userForm,
userForm2,
swichChange,
editRow
};
}
};
</script>
<style scoped>
.input_box {
width: 250px;
margin-right: 15x;
}
</style>
utils.request.js:
import { post, get, put } from "./service"
export const loginApi=data=>{
return post({
url: "/login",
data
})
}
// 获取用户列表
export const userListApi=data=>{
return get({
url: "/users",
data
})
}
// 新增用户
export const userAddApi=data=>{
return post({
url: "/users",
data
})
}
// 更改用户状态
export const userChangeStateApi=data=>{
return put({
url: `/users/${data.id}/state?mg_state=${data.mg_state}`,
data
})
}
// 编辑用户信息
export const userChangeInfoApi=data=>{
return put({
url: `/users/${data.id}`,
data
})
}
utils.service.js:
import axios from "axios"
import { ElLoading } from "element-plus"
import { ElMessage } from "element-plus"
import store from "../store/index.js"
// 使用create创建axios实例
let loadingObj = null
const Service = axios.create({
timeout: 8000,
baseURL: "http://127.0.0.1:5000/",
headers:{
"Content-type": "application/json;charset=utf-8",
// "Authorization": store.state.uInfo.userInfo.token
"Authorization": "token"
}
})
// 请求拦截-增加loading,对请求做统一处理
Service.interceptors.request.use(config=>{
loadingObj=ElLoading.service({
lock: true,
text: "Loading",
background: "rgba(0, 0, 0, 0.7)",
})
return config
})
// 响应拦截-对返回值做统一处理
Service.interceptors.response.use(response=>{
loadingObj.close()
const data = response.data
if(!data.data){
// 请求出错
ElMessage.error(data.meta.msg || "服务器出错")
return data
}
return data
},error=>{
loadingObj.close()
ElMessage({
message: "服务器错误",
type: "error",
duration: "2000"
})
})
// post请求
export const post=config=>{
return Service({
...config,
method: "post",
data: config.data
})
}
// get请求
export const get=config=>{
return Service({
...config,
method: "get",
params: config.data
})
}
// put请求
export const put=config=>{
return Service({
...config,
method: "put",
data: config.data
})
}
18、用户删除
utils.service.js:
import axios from "axios"
import { ElLoading } from "element-plus"
import { ElMessage } from "element-plus"
import store from "../store/index.js"
// 使用create创建axios实例
let loadingObj = null
const Service = axios.create({
timeout: 8000,
baseURL: "http://127.0.0.1:5000/",
headers:{
"Content-type": "application/json;charset=utf-8",
// "Authorization": store.state.uInfo.userInfo.token
"Authorization": "token"
}
})
// 请求拦截-增加loading,对请求做统一处理
Service.interceptors.request.use(config=>{
loadingObj=ElLoading.service({
lock: true,
text: "Loading",
background: "rgba(0, 0, 0, 0.7)",
})
return config
})
// 响应拦截-对返回值做统一处理
Service.interceptors.response.use(response=>{
loadingObj.close()
const data = response.data
if(data.meta.status!=200){
// 请求出错
ElMessage.error(data.meta.msg || "服务器出错")
return data
}
return data
},error=>{
loadingObj.close()
ElMessage({
message: "服务器错误",
type: "error",
duration: "2000"
})
})
// post请求
export const post=config=>{
return Service({
...config,
method: "post",
data: config.data
})
}
// get请求
export const get=config=>{
return Service({
...config,
method: "get",
params: config.data
})
}
// put请求
export const put=config=>{
return Service({
...config,
method: "put",
data: config.data
})
}
// delete请求
export const del=config=>{
return Service({
...config,
method: "delete"
})
}
utils.request.js
import { post, get, put, del } from "./service"
export const loginApi=data=>{
return post({
url: "/login",
data
})
}
// 获取用户列表
export const userListApi=data=>{
return get({
url: "/users",
data
})
}
// 新增用户
export const userAddApi=data=>{
return post({
url: "/users",
data
})
}
// 更改用户状态
export const userChangeStateApi=data=>{
return put({
url: `/users/${data.id}/state?mg_state=${data.mg_state}`,
data
})
}
// 编辑用户信息
export const userChangeInfoApi=data=>{
return put({
url: `/users/${data.id}`,
data
})
}
// 删除用户信息
export const userDeleteApi=data=>{
return del({
url: `/users/${data.id}`
})
}
views.pages.userList.vue
<template>
<div>
<!-- 面包屑-->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">账号管理</el-breadcrumb-item>
<el-breadcrumb-item>
<a href="/">账号列表</a>
</el-breadcrumb-item>
</el-breadcrumb>
<!-- 白色内容区域 -->
<div class="page_content">
<div class="input_box">
<div class="flex">
<el-input v-model="searchParams.query" placeholder="搜索关键字" class="input-with-select">
<template #append>
<el-button @click="searchList">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary" @click="addUser">新建用户</el-button>
</div>
</div>
<!-- 表格 -->
<!--
el-table 的 data:要展示的数据数组
el-table-column: 列 prop每条数据的对应属性
label: 列标题
scope.row:相当于一条数据
-->
<el-table :data="userList" style="width: 100%">
<el-table-column prop="username" label="姓名" width="180" />
<el-table-column prop="role_name" label="角色" width="180" />
<el-table-column prop="age" label="年龄" width="180" />
<el-table-column prop="email" label="邮箱" width="180" />
<el-table-column prop="mobile" label="手机号" />
<el-table-column prop="mg_state" label="状态">
<template #default="scope">
<el-switch v-model="scope.row.mg_state" @change="swichChange(scope.row)" />
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" @click="editRow(scope.row)">编辑</el-button>
<el-button type="danger" @click="deleteRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
background
layout="prev, pager, sizes, next, jumper, ->, total"
v-model:currentPage="searchParams.pagenum"
v-model:page-size="searchParams.pagesize"
:page-sizes="[2,3,5,10,20]"
:total="total"
@size-change="searchList"
@current-change="searchList"
/>
</div>
<!-- 新增弹窗 -->
<el-dialog v-model="dialogFormVisible" title="新建用户">
<!-- 表单 -->
<el-form ref="userForm" :model="formData" :rules="rules">
<el-form-item label="用户名称" prop="username">
<el-input v-model="formData.username" placeholder="请输入用户名" />
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" v-model="formData.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitForm(userForm)">确定</el-button>
</div>
</template>
</el-dialog>
<!-- 编辑弹窗 -->
<el-dialog v-model="dialogFormEVisible" title="编辑用户">
<!-- 表单 -->
<el-form ref="userForm2" :model="formData2" :rules="rules2">
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData2.email" placeholder="请输入邮箱" />
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData2.mobile" placeholder="请输入手机号" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitEForm(userForm2)">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { toRefs, reactive, ref } from "vue";
import {
userListApi,
userAddApi,
userChangeStateApi,
userChangeInfoApi,
userDeleteApi
} from "@/utils/request.js";
export default {
name: "users",
setup() {
const data = reactive({
keyWord: "",
searchParams: {
query: "",
pagesize: 5,
pagenum: 2
},
total: 0,
userList: [],
dialogFormVisible: false,
dialogFormEVisible: false,
formData: {
username: "",
password: "",
email: "",
mobile: ""
},
formData2: {
id: "",
email: "",
mobile: ""
},
rules: {
username: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
password: [
{ required: true, message: "此项为必填项", trigger: "blur" }
],
email: [
{
required: false,
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
message: "请填写正确的邮箱",
trigger: "blur"
}
],
mobile: [
{
required: false,
pattern: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
message: "请填写正确的手机号",
trigger: "blur"
}
]
},
rules2: {
email: [
{
required: false,
pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/,
message: "请填写正确的邮箱",
trigger: "blur"
}
],
mobile: [
{
required: false,
pattern: /^[1][3,4,5,6,7,8,9][0-9]{9}$/,
message: "请填写正确的手机号",
trigger: "blur"
}
]
}
});
const searchList = () => {
userListApi(data.searchParams).then(res => {
if (res.data) {
//
// console.log("用户数据", res);
data.userList = res.data.users;
data.total = res.data.total;
}
});
};
const addUser = () => {
data.dialogFormVisible = true;
};
// 新增提交
const submitForm = formEl => {
// validate
formEl.validate(res => {
if (!res) {
return;
}
// 表单验证通过请求接口
// alert("通过")
userAddApi(data.formData).then(res => {
if (res.data) {
// 隐藏弹框
data.dialogFormVisible = false;
// 清空弹框数据
data.formData = {
username: "",
password: "",
email: "",
mobile: ""
};
// 重新更新列表
searchList();
}
});
});
};
// 修改提交
const submitEForm = formEl => {
formEl.validate(res => {
if (!res) {
return;
}
// 修改提交
userChangeInfoApi(data.formData2).then(res => {
if (res.data) {
data.dialogFormEVisible=false;
searchList();
}
});
});
};
// 状态更改
const swichChange = row => {
console.log("操作的那个数据是:", row);
userChangeStateApi(row).then(res => {
if (res.data) {
searchList();
}
});
};
// 用户信息编辑
const editRow = row => {
console.log("编辑的那个数据是:", row);
// 展示编辑表单
const { email, mobile, id } = row;
data.dialogFormEVisible = true;
data.formData2.id = id;
data.formData2.email = email;
data.formData2.mobile = mobile;
// data.formData2.email=row.email
// data.formData2.mobile=row.mobile
// userChangeStateApi(row).then(res => {
// if (res.data) {
// searchList()
// }
// });
};
// 删除数据
const deleteRow = row => {
console.log("删除的那个数据是:", row);
userDeleteApi(row).then(res=>{
if(res.data){
searchList()
}
})
};
// 方法初始化
searchList();
const userForm = ref();
const userForm2 = ref();
return {
...toRefs(data),
searchList,
addUser,
submitForm,
submitEForm,
userForm,
userForm2,
swichChange,
editRow,
deleteRow
};
}
};
</script>
<style scoped>
.input_box {
width: 250px;
margin-right: 15x;
}
</style>
19、角色列表
utils.service.js
import axios from "axios"
import { ElLoading } from "element-plus"
import { ElMessage } from "element-plus"
import store from "../store/index.js"
// 使用create创建axios实例
let loadingObj = null
const Service = axios.create({
timeout: 8000,
baseURL: "http://127.0.0.1:5000/",
headers:{
"Content-type": "application/json;charset=utf-8",
// "Authorization": store.state.uInfo.userInfo.token
"Authorization": "token"
}
})
// 请求拦截-增加loading,对请求做统一处理
Service.interceptors.request.use(config=>{
loadingObj=ElLoading.service({
lock: true,
text: "Loading",
background: "rgba(0, 0, 0, 0.7)",
})
return config
})
// 响应拦截-对返回值做统一处理
Service.interceptors.response.use(response=>{
loadingObj.close()
const data = response.data
if(data.meta.status!=200 && data.data.status!=201){
// 请求出错
ElMessage.error(data.meta.msg || "服务器出错")
return data
}
return data
},error=>{
loadingObj.close()
ElMessage({
message: "服务器错误",
type: "error",
duration: "2000"
})
})
// post请求
export const post=config=>{
return Service({
...config,
method: "post",
data: config.data
})
}
// get请求
export const get=config=>{
return Service({
...config,
method: "get",
params: config.data
})
}
// put请求
export const put=config=>{
return Service({
...config,
method: "put",
data: config.data
})
}
// delete请求
export const del=config=>{
return Service({
...config,
method: "delete"
})
}
utils.request.js:
import { post, get, put, del } from "./service"
export const loginApi=data=>{
return post({
url: "/login",
data
})
}
// 获取用户列表
export const userListApi=data=>{
return get({
url: "/users",
data
})
}
// 新增用户
export const userAddApi=data=>{
return post({
url: "/users",
data
})
}
// 更改用户状态
export const userChangeStateApi=data=>{
return put({
url: `/users/${data.id}/state?mg_state=${data.mg_state}`,
data
})
}
// 编辑用户信息
export const userChangeInfoApi=data=>{
return put({
url: `/users/${data.id}`,
data
})
}
// 删除用户信息
export const userDeleteApi=data=>{
return del({
url: `/users/${data.id}`
})
}
// 获取角色列表
export const getRolesApi=data=>{
return get({
url: "/roles",
data
})
}
// 新建用户角色
export const addRolesApi=data=>{
return post({
url: "/roles",
data
})
}
// 编辑用户角色
export const editRolesApi=data=>{
return put({
url: `/roles/${data.id}`,
data
})
}
// 删除角色信息
export const roleDeleteApi=data=>{
return del({
url: `/roles/${data.id}`
})
}
views.pages.roleList.vue:
<template>
<div>
<!-- 面包屑-->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">角色管理</el-breadcrumb-item>
<el-breadcrumb-item>
<a href="/">角色列表</a>
</el-breadcrumb-item>
</el-breadcrumb>
<!-- 白色内容区域 -->
<div class="page_content">
<div class="input_box">
<div class="flex">
<el-input v-model="searchParams.query" placeholder="搜索关键字" class="input-with-select">
<template #append>
<el-button @click="searchList">
<el-icon>
<Search />
</el-icon>
</el-button>
</template>
</el-input>
<el-button type="primary" @click="addRole">新建角色</el-button>
</div>
</div>
<!-- 表格 -->
<!--
el-table 的 data:要展示的数据数组
el-table-column: 列 prop每条数据的对应属性
label: 列标题
scope.row:相当于一条数据
-->
<el-table :data="rolesList" style="width: 100%">
<el-table-column prop="rolename" label="角色名" width="180" />
<el-table-column prop="roledes" label="角色描述" width="180" />
<el-table-column label="操作">
<template #default="scope">
<el-button type="primary" @click="editRow(scope.row)">编辑</el-button>
<el-button type="danger" @click="deleteRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
background
layout="prev, pager, sizes, next, jumper, ->, total"
v-model:currentPage="searchParams.pagenum"
v-model:page-size="searchParams.pagesize"
:page-sizes="[2,3,5,10,20]"
:total="total"
@size-change="getList"
@current-change="getList"
/>
</div>
<!-- 新增弹窗 -->
<el-dialog v-model="dialogFormVisible" @close="clearForm" :title="editRow.id?'编辑角色':'新建角色'">
<!-- 表单 -->
<el-form ref="roleForm" :model="formData" :rules="rules">
<el-form-item label="角色名" prop="rolename">
<el-input v-model="formData.rolename" placeholder="请输入角色名" />
</el-form-item>
<el-form-item label="角色描述" prop="roledes">
<el-input v-model="formData.roledes" placeholder="请输入角色描述" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitForm(roleForm)">确定</el-button>
</div>
</template>
</el-dialog>
<!-- 编辑弹窗 -->
<!-- <el-dialog v-model="dialogFormEVisible" title="编辑角色"> -->
<!-- 表单 -->
<!-- <el-form ref="roleForm2" :model="formData2" :rules="rules">
<el-form-item label="角色名" prop="rolename">
<el-input v-model="formData2.rolename" placeholder="请输入角色名" />
</el-form-item>
<el-form-item label="角色描述" prop="roledes">
<el-input v-model="formData2.roledes" placeholder="请输入角色描述" />
</el-form-item>
</el-form>
<template #footer>
<div>
<el-button>取消</el-button>
<el-button type="primary" @click="submitEForm(roleForm2)">确定</el-button>
</div>
</template>
</el-dialog> -->
</div>
</template>
<script>
import { reactive, toRefs, ref } from "vue";
import { getRolesApi, addRolesApi, editRolesApi, roleDeleteApi } from "@/utils/request.js";
export default {
name: "roles",
setup() {
const data = reactive({
searchParams: {
query: "",
pagesize: 5,
pagenum: 1
},
total: 0,
rolesList: [],
dialogFormVisible: false,
formData: {
id:"",
rolename: "",
roledes: ""
},
formData2: {
id: "",
rolename: "",
roledes: ""
},
rules: {
rolename: {
required: true,
message: "此项必填",
trigger: "blur"
}
}
});
// 此时没有分页,不需要传参数
const getList = () => {
getRolesApi(data.searchParams).then(res => {
console.log("用户数据", res.data);
if (res.data) {
data.rolesList = res.data.roles;
data.total = res.data.total
}
});
};
// 新建角色
const addRole = () => {
data.dialogFormVisible = true;
};
// 新增提交
const submitForm = formEl => {
// validate
formEl.validate(res => {
if (!res) {
return;
}
// 提交表单
// 表单验证通过请求接口
// alert("通过")
if(data.formData.id){
editRolesApi(data.formData).then(res => {
if (res.data) {
// 隐藏弹框
data.dialogFormVisible = false;
// // 清空弹框数据
// data.formData = {
// rolename: "",
// roledes: ""
// };
// 重新更新列表
getList();
}
});
}else{
addRolesApi(data.formData).then(res => {
if (res.data) {
// 隐藏弹框
data.dialogFormVisible = false;
// // 清空弹框数据
// data.formData = {
// rolename: "",
// roledes: ""
// };
// 重新更新列表
getList();
}
});
}
});
};
const editRow = row => {
data.dialogFormVisible=true;
const { rolename, roledes, id } = row
data.formData={
id,
rolename,
roledes
}
};
const deleteRow = row => {
roleDeleteApi(row).then(res=>{
getList()
})
};
// 清除表单
const clearForm=()=>{
data.formData={
rolename:"",
roledes:""
}
}
// 初始化
getList();
const roleForm = ref();
// const roleForm2 = ref();
return {
...toRefs(data),
getList,
editRow,
deleteRow,
addRole,
roleForm,
submitForm,
clearForm
};
}
};
</script>
<style scoped>
.input_box {
width: 280px;
margin-right: 15px;
}
</style>