一.使用版本
- Node.js: 14.3.0
- Vue: 2.6.10
- Npm: 6.14.5
- Webpack: 4.0.0
- Node-sass: 4.14.1
- Sass-loader: 7.3.1
二.使用技术
- Vue 2.0
- vue-router 路由
- element-ui 组件
- vuex 状态存储工具
- axios 数据交互
三. 环境搭建
- 1. 安装node (node -v查询版本号)
-
node 安装 (下载地址:https://nodejs.org/en/download/)
-
2. 安装淘宝镜像
-
npm install -g cnpm --registry=https://registry.npm.taobao.org
-
3. 安装 webpack,以全局的方式安装
-
-
npm install webpack -g
-
4.全局安装vue以及脚手架vue-cli
-
npm install @vue/cli -g --unsafe-perm
-
5.创建vue项目 mall-manage-system(项目名称)
-
vue create mall-manage-system
5.1 选择使用vue版本直接回车
-
6. 运行当前项目 这个整个项目就搭建好了
npm run serve
四. 搭建项目
1. 引入组件库 - 此项目使用element - ui组件库
https://element.eleme.cn/#/zh-CN/component/installation
在main.js中引入
//新添
import ElementUI from 'element-ui'
//新增
import 'element-ui/lib/theme-chalk/index.css'
//新增
Vue.use(ElementUI)
2.创建路由 (router/index.js)
创建登录页面路由/页面路由
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'
/**
* 处理控制台的下面报错
* Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/home/list".
* 添加以下代码
*/
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
export const constantRoutes = [
// 重定向,用来指向一打开网页就跳转到哪个路由
{
path: '/',
redirect: '/login'
},
//login
{
path: '/login',
component: () => import('@/views/login/login'),
},
{
path: "/404",
component: () => import("@/views/error-page/404")
},
{
path: "/401",
component: () => import("@/views/error-page/401")
},
]
const createRouter = () => new Router({
scrollBehavior: () => ({
y: 0
}),
routes: constantRoutes
})
const router = createRouter()
export default router
3.创建登录界面
<template>
<div class="sign-in">
<el-row>
<el-col :span="12" :offset="6">
<h1>后台系统</h1>
<el-form
:model="loginForm"
:rules="loginRules"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item label="手机号:" prop="user_phone">
<el-input v-model="loginForm.user_phone"></el-input>
</el-form-item>
<el-form-item label="密码:" prop="sort">
<el-input v-model="loginForm.password" type="password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleLogin('ruleForm')">
立即登录
</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</template>
<script>
import { setBasicInfo } from "@/utils/auth";
import { Login, signIn } from "../../api/login/login";
import store from "@/store";
export default {
data() {
return {
loginForm: {
user_phone: "admin",
password: "123123",
},
loginRules: {
name: [{ required: true, message: "请输入手机号", trigger: "blur" }],
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
},
};
},
methods: {
async handleLogin(formName) {
this.$refs[formName].validate(async (valid) => {
if (valid) {
const res = await Login()
if(!res.success) return this.$message.error('错了哦!系统错误!');
const data =res.data
if(this.loginForm.user_phone === data.user_phone&&this.loginForm.password ===data.password){
// const res2 = await signIn();
const menu = await setBasicInfo()
await store.dispatch('apply/getApply')
const redirect = menu[0].path + '/' + menu[0].children[0].path
await this.$router.push(redirect);
}else{
this.$message.error('错了哦!账号密码不正确!');
}
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
},
};
</script>
<style scoped lang="scss">
.sign-in {
padding-top: 100px;
}
h1 {
text-align: center;
}
</style>
使用axios进行交互
3.1 引入axios
3.2 安装 axios
npm install axios -S
安装完成后在package.json中dependencies下可以看到安装是否成功
3.3 点击登录进行接口请求获取token,将获取到的返回信息可存储到storage中或VUEX中
3.4 设置路由守卫进行权限判断进入项目
views下创建 permission.js文件
/* eslint-disable prefer-const */
import router from './router'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import getPageTitle from '@/utils/get-page-title'
import store from '@/store'
import {getToken, toLogin, setBasicInfo} from '@/utils/auth'
//NProgress.configure({ showSpinner: false }) // NProgress Configuration
NProgress.configure({
easing: 'ease', // 动画方式
speed: 500, // 递增进度条的速度
showSpinner: false, // 是否显示加载ico
trickleSpeed: 200, // 自动递增间隔
minimum: 0.3 // 初始化时的最小百分比
})
// 白名单
const whiteList = ['/login'] // no redirect whitelist.
// 挂载路由导航守卫:to表示将要访问的路径,from表示从哪里来,next是下一个要做的操作
/**
* to: Route: 即将要进入的目标 路由对象
* from: Route: 当前导航正要离开的路由
* next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
* next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
* next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
* next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
* next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
*/
router.beforeEach(async (to, from, next) => {
NProgress.start()
document.title = getPageTitle(to.meta.title)
if (whiteList.includes(to.path)) {
next()
} else {
const token = getToken()
if (!token) {
await toLogin()
return
}
if (store.state.permission.asyncRouteFlag === '1') {
next()
} else {
try {
const menu = await setBasicInfo(token)
next({...to, replace: true})
await store.dispatch('apply/getApply')
} catch (e) {
console.log(e, 'e')
}
}
}
})
router.afterEach(() => {
NProgress.done()
})
utils/get-page-title.js
import defaultSettings from '@/settings'
const title = defaultSettings.title || 'SaaS'
export default function getPageTitle(pageTitle) {
if (pageTitle) {
return `${pageTitle} - ${title}`
}
return `${title}`
}
utils/auth.js
import Cookies from "js-cookie";
import { Message } from 'element-ui'
import router from '@/router'
import { userList } from "@/api/login/login";
import { getArea } from '@/api/common'
import store from "@/store";
import { generateRoutes } from '@/utils/generteRoute'
// 设置token
export const setToken = (token) => {
storage.setItem(tokenKey, token)
}
// 获取token
export const getToken = () => {
return storage.getItem(tokenKey) || ''
}
/**
* 删除cookie中的token
* @returns {*}
*/
export function removeToken() {
return Cookies.remove(TokenKey);
}
const storage = window.localStorage
export const tokenKey = 'token'
// 清除token
export const clearToken = () => {
storage.removeItem('swapOperationInfo')
storage.removeItem('swapOperationCompany')
store.dispatch('permission/setPreToken', '')
storage.removeItem(tokenKey)
}
// 跳转到登录页面
// 跳转到登录页面
export const toLogin = () => {
clearToken()
// if (process.env.NODE_ENV === 'development') {
// router.replace('/login')
// } else {
// setTimeout(() => {
// // window.location.replace(`${process.env.VUE_APP_LOGIN_PAGE}?active=${store.getters.app_id}`)
// window.location.replace(`${window.location.origin}/#/login`)
// }, 500)
// }
// // window.location.replace(`${process.env.VUE_APP_LOGIN_PAGE}?active=${store.getters.app_id}`)
}
/**
* 根据token获取用户和权限信息
* @param token
* @returns {Promise<unknown>}
*/
export const setBasicInfo = async (token) => {
const res = await userList(token);
return new Promise(async (resolve, reject) => {
if (res.success) {
const route = (res.data || {}).route || [];
if (!route.length) {
Message({
message: "抱歉!你没有任何页面的访问权限!",
duration: 4000,
type: "error",
});
} else {
const userInfo = {
telephone: res.data.telephone,
role_name: res.data.role_name,
role_id: res.data.role_id,
user: res.data.user_name,
};
// 获取基础数据
await getBasicData()
await store.dispatch("user/setUserInfo", userInfo);
await store.dispatch("user/setUserMenu", res.data.route || [])
const accessRoutes = await generateRoutes(res.data.route)
// 旧版本已废除 router.addRoutes
// router.addRoutes(accessRoutes)
// 新版本使用方法
for (let item of accessRoutes) {
router.addRoute(item)
}
setToken(res.data.token)
resolve(res.data.route)
}
}
})
}
// 获取基础数据-运营公司、供应商、地区, 并存入store
export const getBasicData = async () => {
try {
const areaRes = await getArea()
await store.dispatch('options/setArea', (areaRes.data || {}).children || [])
} catch (e) {
Message.error('获取地区数据失败')
}
}
utils/generteRoute.js
import Layout from '@/layout'
import store from '@/store'
// 组件路径转换成模块
export function componentRoutes(routes) {
const res = []
routes.forEach(route => {
const component = route.component === 'Layout' ? Layout : function (resolve) {
require([`@/views/${route.component}`], resolve)
}
const tmp = { ...route, component }
if (tmp.children && tmp.children.length) {
tmp.children = componentRoutes(tmp.children)
}
res.push(tmp)
})
return res
}
// 生成动态路由
export const generateRoutes = (asyncRoutes) => {
return new Promise(resolve => {
let accessedRoutes = componentRoutes(asyncRoutes)
// 标记路由是否已经生成
store.dispatch('permission/toggleRouteFlag', '1')
accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
resolve(accessedRoutes)
})
}
store内容查看下面文件夹进行下载
https://download.csdn.net/download/weixin_64374806/87854628?spm=1001.2014.3001.5503