Go+Vue3开发博客系统(六)
本文最后更新于 2024-08-19,文章内容距离上一次更新已经过去了很久啦,可能已经过时了,请谨慎参考喵。
前情提要
创建VUE3项目
在博客根目录的上级目录,执行:
npm create vite@latest goblog-admin-vue3
类型选择
Vue
,语言方式选择JavaScript
进入创建好的 goblog-admin-vue3
目录,执行:
npm install
然后在项目根目录下执行测试一下:
npm run dev
欧克,没什么问题,然后不需要示例页面,需要删除 /src/components/HelloWorld.vue
这个文件
然后修改 /src/App.vue
:
<template>
<router-view>
</router-view>
</template>
<script setup>
</script>
<style scoped>
</style>
继续删除 /src/assets/vue.svg
、 /src/style.css
这两个文件,修改 /index.html
:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GoBlog 运营后台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
修改 /src/main.js
:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
然后重启项目测试一下,页面是空白的,标题已被修改,图标没变,就OK了
创建目录结构:
/src/api/
/src/views/
/src/store/
/src/utils/
/src/router/
/src/permission/
安装 vue-router
依赖、element-plus
依赖:
npm install vue-router
npm install element-plus --save
处理基本结构代码
第一步修改 /src/main.js
:
import { createApp } from 'vue'
import App from './App.vue'
// router 引入
import router from './router/router.js'
// element-plus 引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// app 实列
const app = createApp(App)
app.use(router)
app.use(ElementPlus)
app.mount('#app')
下一步创建路由文件 /src/router/router.js
:
哎呀,代码丢失了(这里先空着)
创建登录页面 /src/views/login.vue
:
<template>
<div>
<el-button type="primary">测试按钮</el-button>
</div>
</template>
<script setup>
</script>
<style lang="scss">
</style>
返回 /src/router/router.js
中:
import {createRouter, createWebHistory} from 'vue-router'
/*
* 路由表
*/
const router = createRouter({
// 去掉 URL 中的 #
history: createWebHistory(),
routes:[
{path:'/login', component:()=>import('@/views/login.vue')},
]
})
export default router;
修改 /vite.config.js
:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
// 解决 @ 引入问题
resolve:{
alias:{
'@': path.resolve(__dirname, './src'),
}
},
plugins: [vue()],
})
启动项目测试一下:
构建登陆页面基本结构
修改 /src/main.js
引入 element 的 icon 组件:
import { createApp } from 'vue'
import App from './App.vue'
// router 引入
import router from './router/router.js'
// element-plus 引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// element 图标引入
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// app 实列
const app = createApp(App)
app.use(router)
app.use(ElementPlus)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.mount('#app')
然后回到 /src/views/login.vue
:
<template>
<div class="login-container">
<el-form class="login-form">
<!-- 标题 -->
<div class="title-container">GoBlog 运营后台</div>
<!-- 用户名 -->
<el-form-item style="margin-bottom: 30px">
<el-input placeholder="请输入用户名" name="username" type="text" prefix-icon="User"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item style="margin-bottom: 30px">
<el-input placeholder="请输入密码" name="password" type="text" prefix-icon="Key" suffix-icon="view"></el-input>
</el-form-item>
<!-- 登录按钮 -->
<el-button type="primary" style="width: 100%; margin-bottom: 30px">登录</el-button>
</el-form>
</div>
</template>
<script setup>
</script>
<style lang="scss">
</style>
运行测试一下:
ok,没啥问题
页面样式调整
首先安装一个 sass 依赖:(项目根目录下执行)
npm install sass sass-loader
创建 styles
目录:
/src/styles/
创建主样式文件 /src/styles/index.scss
:
html, body, #app {
height: 100%;
margin: 0;
padding: 0;
}
在全局配置 /src/main.js
中引入css样式:
import { createApp } from 'vue'
import App from './App.vue'
// router 引入
import router from './router/router.js'
// element-plus 引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// element 图标引入
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// index.scss 全局样式引入
import '@/styles/index.scss'
// app 实列
const app = createApp(App)
// 挂载路由
app.use(router)
// 挂载 element-plus
app.use(ElementPlus)
// 挂载 element-icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 挂载 vue app
app.mount('#app')
下一步在 /src/views/login.vue
中继续写样式:
<template>
<div class="login-container">
<el-form class="login-form">
<!-- 标题 -->
<div class="title-container">GoBlog 运营后台</div>
<!-- 用户名 -->
<el-form-item style="margin-bottom: 30px">
<el-input placeholder="请输入用户名" name="username" type="text" prefix-icon="User"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item style="margin-bottom: 30px">
<el-input placeholder="请输入密码" name="password" type="text" prefix-icon="Key" suffix-icon="view"></el-input>
</el-form-item>
<!-- 登录按钮 -->
<el-button type="primary" style="width: 100%; margin-bottom: 30px">登录</el-button>
</el-form>
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
.login-container{
background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
height: 100%;
.login-form{
width: 400px;
border-radius: 1px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.title-container{
font-size: 30px;
line-height: 1.5;
text-align: center;
margin-bottom: 30px;
font-weight: bold;
}
}
}
</style>
效果如图:
表单校验以及密码掩盖
还是在上一节的 /src/views/login.vue
中:
<template>
<div class="login-container">
<el-form class="login-form" :rules="rules" :model="loginForm">
<!-- 标题 -->
<div class="title-container">GoBlog 运营后台</div>
<!-- 用户名 -->
<el-form-item style="margin-bottom: 30px" prop="username">
<el-input placeholder="请输入用户名" name="username" type="text" prefix-icon="User" v-model="loginForm.username"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item style="margin-bottom: 30px" prop="password">
<el-input placeholder="请输入密码" name="password" type="text" prefix-icon="Key" suffix-icon="view" v-model="loginForm.password"></el-input>
</el-form-item>
<!-- 登录按钮 -->
<el-button type="primary" style="width: 100%; margin-bottom: 30px">登录</el-button>
</el-form>
</div>
</template>
<script setup>
import {ref} from 'vue'
// 表单验证校验
const rules = {
username: [{required: true, message: "请输入用户名", trigger: "blur"}],
password: [{required: true, message: "请输入密码", trigger: "blur"}]
}
const loginForm = ref({})
</script>
<style lang="scss" scoped>
.login-container{
background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
height: 100%;
.login-form{
width: 400px;
border-radius: 1px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.title-container{
font-size: 30px;
line-height: 1.5;
text-align: center;
margin-bottom: 30px;
font-weight: bold;
}
}
}
</style>
效果如下:
继续在 /src/views/login.vue
中:
<template>
<div class="login-container">
<el-form class="login-form" :rules="rules" :model="loginForm">
<!-- 标题 -->
<div class="title-container">GoBlog 运营后台</div>
<!-- 用户名 -->
<el-form-item style="margin-bottom: 30px" prop="username">
<el-input placeholder="请输入用户名" name="username" type="text" prefix-icon="User"
v-model="loginForm.username"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item style="margin-bottom: 30px" prop="password">
<el-input placeholder="请输入密码" name="password" :type="flagType" v-model="loginForm.password">
<template #prefix>
<el-icon>
<Key/>
</el-icon>
</template>
<template #suffix>
<span @click="changeView">
<el-icon v-if="flag === true" style="cursor: pointer">
<Hide/>
</el-icon>
<el-icon v-else-if="flag === false" style="cursor: pointer">
<View/>
</el-icon>
</span>
</template>
</el-input>
</el-form-item>
<!-- 登录按钮 -->
<el-button type="primary" style="width: 100%; margin-bottom: 30px">登录</el-button>
</el-form>
</div>
</template>
<script setup>
import {ref} from 'vue'
// 表单验证校验
const rules = {
username: [{required: true, message: "请输入用户名", trigger: "blur"}],
password: [{required: true, message: "请输入密码", trigger: "blur"}]
}
const loginForm = ref({})
// changeView 切换密码显示状态
const flagType = ref("password")
const flag = ref(true)
const changeView = () => {
flag.value = !flag.value
flagType.value = flag.value ? "password" : "text"
}
</script>
<style lang="scss" scoped>
.login-container {
background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
height: 100%;
.login-form {
width: 400px;
border-radius: 1px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.title-container {
font-size: 30px;
line-height: 1.5;
text-align: center;
margin-bottom: 30px;
font-weight: bold;
}
}
}
</style>
效果如图:
封装axios模块
首先安装 axios 依赖:(项目根目录下执行)
npm install axios@latest --save
在项目根目录下创建 /.env.development
文件:
# 名称
VITE_APP_ENV = 'development'
# BASE URL
VITE_APP_BASE_API = '/api'
再在根目录下创建测试环境的配置文件 /.env.test
:
# 名称
VITE_APP_ENV = 'test'
# BASE URL
VITE_APP_BASE_API = '/api/test'
最后还有生产环境的配置文件 /.env.production
:
# 名称
VITE_APP_ENV = 'production'
# BASE URL
VITE_APP_BASE_API = '/api/production'
创建 /src/utils/request.js
文件:
/*
* axios 封装
*/
import axios from 'axios'
// axios 创建
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 5000,
})
// request 核心函数
function request (options) {
options.method = options.method || 'get'
if (options.method.toLowerCase() === 'get') {
options.params = options.data
}
service.defaults.baseURL = import.meta.env.VITE_APP_BASE_API
return service(options)
}
export default request
修改根目录下的 package.json
,将启动模式更改为设定好的:
{
"name": "goblog-admin-vue3",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --mode development",
"test": "vite --mode test",
"production": "vite --mode production",
"build:dev": "vite build --mode development",
"build:test": "vite build --mode test",
"build:production": "vite build --mode production",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.6.8",
"element-plus": "^2.7.2",
"sass": "^1.76.0",
"sass-loader": "^14.2.1",
"vue": "^3.4.21",
"vue-router": "^4.3.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"vite": "^5.2.0"
}
}
回到 /src/main.js
中测试打印一下环境参数:
import { createApp } from 'vue'
import App from './App.vue'
// router 引入
import router from './router/router.js'
// element-plus 引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// element 图标引入
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// index.scss 全局样式引入
import '@/styles/index.scss'
// 输出运行环境
console.log("运行环境为:", import.meta.env.VITE_APP_ENV)
console.log("BASE URL:", import.meta.env.VITE_APP_BASE_API)
// app 实列
const app = createApp(App)
// 挂载路由
app.use(router)
// 挂载 element-plus
app.use(ElementPlus)
// 挂载 element-icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 挂载 vue app
app.mount('#app')
测试一下:
修改启动端口及配置代理
首先修改根目录下的 /vite.config.js
:
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
// 解决 @ 引入问题
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
}
},
plugins: [vue()],
lintOnSave: false,// 关闭校验
productionSourceMap: false,// 生产环境是否要生成 sourceMpa
publicPath: "/",//部署应用包时的基本 URL (不可以是相对路径,否则会出现 cannot get 错误)
outputDir: "dist",// build 时输出的文件目录
assetsDir: "assets",// 放置静态文件的目录
server: {
port: 5002,//运行时的端口
host: '0.0.0.0',// 运行时的域名
https: false,// 是否启用 https
open: false,// 是否直接打开浏览器
proxy: {// 配置后端代理访问的地址
"/api": {
target: 'http://127.0.0.1:5001',
changeOrigin: true,
}
},
client: {
overlay: false,
}
}
})
然后启动测试一下:
封装API及处理登录请求
创建 /src/api/index.js
:
/*
* API 接口的封装
*/
import request from "@/utils/request.js"
export default {
// 登录接口
login(params) {
return request({
url: '/sysAdmin/login',
method: 'post',
data: params
})
}
}
下一步回到 /src/main.js
中绑定这个接口:
import { createApp } from 'vue'
import App from './App.vue'
// router 引入
import router from './router/router.js'
// element-plus 引入
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// element 图标引入
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// index.scss 全局样式引入
import '@/styles/index.scss'
// API 引入
import api from './api'
// 输出运行环境
console.log("运行环境为:", import.meta.env.VITE_APP_ENV)
console.log("BASE URL:", import.meta.env.VITE_APP_BASE_API)
// app 实列
const app = createApp(App)
// 挂载路由
app.use(router)
// 挂载 element-plus
app.use(ElementPlus)
// 挂载 element-icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 调用 API
app.config.globalProperties.$api = api
// 挂载 vue app
app.mount('#app')
下一步来到 /src/views/login.vue
中绑定登录的API:
<template>
<div class="login-container">
<el-form class="login-form" :rules="rules" :model="loginForm" ref="loginFormRef">
<!-- 标题 -->
<div class="title-container">GoBlog 运营后台</div>
<!-- 用户名 -->
<el-form-item style="margin-bottom: 30px" prop="username">
<el-input placeholder="请输入用户名" name="username" type="text" prefix-icon="User"
v-model="loginForm.username"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item style="margin-bottom: 30px" prop="password">
<el-input placeholder="请输入密码" name="password" :type="flagType" v-model="loginForm.password">
<template #prefix>
<el-icon>
<Key/>
</el-icon>
</template>
<template #suffix>
<span @click="changeView">
<el-icon v-if="flag === true" style="cursor: pointer">
<Hide/>
</el-icon>
<el-icon v-else-if="flag === false" style="cursor: pointer">
<View/>
</el-icon>
</span>
</template>
</el-input>
</el-form-item>
<!-- 登录按钮 -->
<el-button type="primary" style="width: 100%; margin-bottom: 30px" @click="handleLogin">登录</el-button>
</el-form>
</div>
</template>
<script setup>
import {ref, getCurrentInstance} from 'vue'
const {proxy} = getCurrentInstance()
// 表单验证校验
const rules = {
username: [{required: true, message: "请输入用户名", trigger: "blur"}],
password: [{required: true, message: "请输入密码", trigger: "blur"}]
}
const loginForm = ref({})
// changeView 切换密码显示状态
const flagType = ref("password")
const flag = ref(true)
const changeView = () => {
flag.value = !flag.value
flagType.value = flag.value ? "password" : "text"
}
// 处理登录
const loginFormRef = ref()
const handleLogin = () => {
loginFormRef.value.validate(valid => {
if (!valid) return
proxy.$api.login(loginForm.value).then((res) => {
console.log("请求的响应数据:", res)
}).catch(err => {
console.log(err)
})
})
}
</script>
<style lang="scss" scoped>
.login-container {
background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
height: 100%;
.login-form {
width: 400px;
border-radius: 1px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.title-container {
font-size: 30px;
line-height: 1.5;
text-align: center;
margin-bottom: 30px;
font-weight: bold;
}
}
}
</style>
然后我们测试一下是否能正确打印返回的信息:
请求拦截和响应拦截
进入到 /src/utils/request.js
文件中:
/*
* axios 封装
*/
import axios from 'axios'
import router from '@/router/router.js'
import {ElMessage} from "element-plus";
// axios 创建
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 5000,
})
// 请求拦截
service.interceptors.request.use((req) => {
const headers = req.headers
const token = 'admin'
if (!headers.Authorization) {
headers.Authorization = 'Bearer ' + token
}
return req
})
// 响应拦截
service.interceptors.response.use((res) => {
const {code, data, message} = res.data
if (code == 403) {
ElMessage.error(message)
// todo
setTimeout(() => {
router.push('/login')
}, 1500)
} else if (code == 200) {
return res.data
} else {
ElMessage.error(message)
}
})
// request 核心函数
function request(options) {
options.method = options.method || 'get'
if (options.method.toLowerCase() === 'get') {
options.params = options.data
}
service.defaults.baseURL = import.meta.env.VITE_APP_BASE_API
return service(options)
}
export default request
然后启动测试一下:
本地存储方案
首先需要在环境配置中增加本地命名空间,在根目录下 .env.development
、 .env.production
、 .env.test
三个文件中加入以下配置项:
# 本地存储命名
VUE_APP_STORAGE_KEY = 'goblog-admin-vue3'
创建存储配置文件 /src/utils/storage.js
:
/*
* 本地存储
*/
export default {
// 读取储存文件
getStorage() {
return JSON.parse(localStorage.getItem(import.meta.env.VUE_APP_STORAGE_KEY) || "{}")
},
// 存储
setItem(key, val) {
let storage = this.getStorage()
storage[key] = val
localStorage.setItem(import.meta.env.VUE_APP_STORAGE_KEY, JSON.stringify(storage))
},
// 读取
getItem(key) {
return this.getStorage()[key]
},
// 清除
clearItem(key) {
let storage = this.getStorage()
delete storage[key]
localStorage.setItem(import.meta.env.VUE_APP_STORAGE_KEY, JSON.stringify(storage))
},
// 全部清除
clearAllItem() {
localStorage.clear()
}
}
下一步在 /src/main.js
中配置一下:
import { createApp } from 'vue'
import App from './App.vue'
// router 引入
import router from './router/router.js'
// element-plus 引入
import ElementPlus from 'element-plus'
// element-plus 样式引入
import 'element-plus/dist/index.css'
// element 图标引入
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// index.scss 全局样式引入
import './styles/index.scss'
// API 引入
import api from './api'
// storage 本地存储引入
import storage from "./utils/storage.js"
// 输出运行环境
console.log("运行环境为:", import.meta.env.VITE_APP_ENV)
console.log("BASE URL:", import.meta.env.VITE_APP_BASE_API)
// app 实列
const app = createApp(App)
// 挂载路由
app.use(router)
// 挂载 element-plus
app.use(ElementPlus)
// 挂载 element-icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 调用 API
app.config.globalProperties.$api = api
// 调用 storage
app.config.globalProperties.$storage = storage
// 挂载 vue app
app.mount('#app')
安装 vuex 依赖:(项目根目录下执行)
npm install vuex --save
创建 /src/stor/metations.js
文件:
/*
* store 和本地存储
*/
import storage from "@/utils/storage.js"
export default {
// token 存储
saveToken(state, token) {
state.token = token
storage.setItem('token', token)
},
// 用户信息存储
saveSysAdmin(state, sysAdmin) {
state.sysAdmin = sysAdmin
storage.setItem('sysAdmin', sysAdmin)
},
// 左侧菜单栏存储
saveLeftMenuList(state, leftMenuList) {
state.leftMenuList = leftMenuList
storage.setItem('leftMenuList', leftMenuList)
},
// 当前用户权限列表存储
savePermissionList(state, permissionList) {
state.permissionList = permissionList
storage.setItem('permissionList', permissionList)
}
}
创建 /src/store/index.js
文件:
/*
* 获取存储的方法
*/
import {createStore} from 'vuex'
import mutations from "./mutations.js"
import storage from "../utils/storage.js"
const state = {
token: "" || storage.getItem("token"),
sysAdmin: "" || storage.getItem("sysAdmin"),
leftMenuList: "" || storage.getItem("leftMenuList"),
permissionList: "" || storage.getItem("permissionList"),
}
export default createStore({
state,
mutations
})
再回到 /src/main.js
文件中:
import { createApp } from 'vue'
import App from './App.vue'
// router 引入
import router from './router/router.js'
// element-plus 引入
import ElementPlus from 'element-plus'
// element-plus 样式引入
import 'element-plus/dist/index.css'
// element 图标引入
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// index.scss 全局样式引入
import './styles/index.scss'
// API 引入
import api from './api'
// storage 本地存储引入
import storage from "./utils/storage.js"
// store 引入
import store from './store'
// 输出运行环境
console.log("运行环境为:", import.meta.env.VITE_APP_ENV)
console.log("BASE URL:", import.meta.env.VITE_APP_BASE_API)
// app 实列
const app = createApp(App)
// 挂载路由
app.use(router)
// 挂载 element-plus
app.use(ElementPlus)
// 挂载 element-icon 组件
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 调用 API
app.config.globalProperties.$api = api
// 调用 storage
app.config.globalProperties.$storage = storage
// 挂载 store
app.use(store)
// 挂载 vue app
app.mount('#app')
下一步回到登陆页面 /src/views/login.vue
继续处理:
<template>
<div class="login-container">
<el-form class="login-form" :rules="rules" :model="loginForm" ref="loginFormRef">
<!-- 标题 -->
<div class="title-container">GoBlog 运营后台</div>
<!-- 用户名 -->
<el-form-item style="margin-bottom: 30px" prop="username">
<el-input placeholder="请输入用户名" name="username" type="text" prefix-icon="User"
v-model="loginForm.username"></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item style="margin-bottom: 30px" prop="password">
<el-input placeholder="请输入密码" name="password" :type="flagType" v-model="loginForm.password">
<template #prefix>
<el-icon>
<Key/>
</el-icon>
</template>
<template #suffix>
<span @click="changeView">
<el-icon v-if="flag === true" style="cursor: pointer">
<Hide/>
</el-icon>
<el-icon v-else-if="flag === false" style="cursor: pointer">
<View/>
</el-icon>
</span>
</template>
</el-input>
</el-form-item>
<!-- 登录按钮 -->
<el-button type="primary" style="width: 100%; margin-bottom: 30px" @click="handleLogin">登录</el-button>
</el-form>
</div>
</template>
<script setup>
import {ref, getCurrentInstance} from 'vue'
import {useStore} from 'vuex'
const {proxy} = getCurrentInstance()
// 表单验证校验
const rules = {
username: [{required: true, message: "请输入用户名", trigger: "blur"}],
password: [{required: true, message: "请输入密码", trigger: "blur"}]
}
const loginForm = ref({})
// changeView 切换密码显示状态
const flagType = ref("password")
const flag = ref(true)
const changeView = () => {
flag.value = !flag.value
flagType.value = flag.value ? "password" : "text"
}
// 处理登录
const loginFormRef = ref({})
const store = useStore()
const handleLogin = () => {
loginFormRef.value.validate(valid => {
if (!valid) return
proxy.$api.login(loginForm.value).then((res) => {
// console.log("请求的响应数据:", res)
proxy.$message.success("登录成功")
store.commit("saveToken", res.data.token)
store.commit("saveSysAdmin", res.data.sysAdmin)
store.commit("saveLeftMenuList", res.data.leftMenuList)
store.commit("savePermissionList", res.data.permissionList)
}).catch(err => {
console.log(err)
})
})
}
</script>
<style lang="scss" scoped>
.login-container {
background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
height: 100%;
.login-form {
width: 400px;
border-radius: 1px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.title-container {
font-size: 30px;
line-height: 1.5;
text-align: center;
margin-bottom: 30px;
font-weight: bold;
}
}
}
</style>
测试一下:
写在半路
这个项目可能就要胎死腹中了,B站老师的教程留了一手,左侧菜单和权限列表没有数据,我也不太会写,我就是个教程的搬运工,所以后面可能就搞其他去了,完整代码我问了,需要收费,大概400元,地址: