Compare commits
7 Commits
816d19f7da
...
a31960fc1a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a31960fc1a | ||
|
|
56635a948b | ||
|
|
2d0c6c2a2b | ||
|
|
5d4bd75b22 | ||
|
|
6d43e9af42 | ||
|
|
c2d2c2c686 | ||
|
|
a9b3da4d19 |
@@ -1 +1,20 @@
|
||||
VUE_APP_API_BASE_URL=http://dev.iczer.com
|
||||
ENV = 'development'
|
||||
|
||||
# base api
|
||||
# PRIVATE -加密 PUBLIC-不加密
|
||||
VUE_APP_ENCRYPT = 'PUBLIC'
|
||||
|
||||
VUE_APP_BASE_API = '/api'
|
||||
VUE_APP_BASE_LSM_API = '/lsm'cls
|
||||
# 文件上传
|
||||
VUE_APP_UPLOAD_URL = '/api/oil-oss/obejct/uploadFile'
|
||||
VUE_APP_UPLOAD_PRIVATE_URL = '/api/oil-dict/imageHandler/uploadProtectedImg'
|
||||
VUE_APP_DOMAIN = '127.0.0.1:38080'
|
||||
|
||||
# 开发环境,不会进行加密,会打印出数据1
|
||||
VUE_APP_ENV = 'production'
|
||||
#production
|
||||
|
||||
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||
|
||||
14
.env.production
Normal file
14
.env.production
Normal file
@@ -0,0 +1,14 @@
|
||||
ENV = 'production'
|
||||
|
||||
# base api
|
||||
VUE_APP_ENCRYPT = 'PRIVATE'
|
||||
|
||||
VUE_APP_BASE_API = '/adminapi'
|
||||
VUE_APP_BASE_LSM_API = '/lsm'
|
||||
# 文件上传
|
||||
VUE_APP_UPLOAD_URL = '/adminapi/oil-oss/obejct/uploadFile'
|
||||
VUE_APP_UPLOAD_PRIVATE_URL = '/adminapi/oil-dict/imageHandler/uploadProtectedImg'
|
||||
# 生产环境,进行加密
|
||||
VUE_APP_ENV = 'production'
|
||||
|
||||
VUE_APP_DOMAIN ='www.xingoil.com/ws'
|
||||
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,38 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
title: 首页
|
||||
home: true
|
||||
heroImage: /logo.png
|
||||
heroText: Vue Antd Admin
|
||||
tagline: 开箱即用的中台前端/设计解决方案
|
||||
actionText: 快速上手 →
|
||||
actionLink: /start/use
|
||||
features:
|
||||
- title: 简洁
|
||||
details: 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。
|
||||
- title: 优雅
|
||||
details: 享受 Vue + webpack 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题。
|
||||
- title: 自然
|
||||
details: VuePress 为每个页面预渲染生成静态的 HTML,同时在页面被加载的时候,将作为 SPA 运行。
|
||||
footer: MIT Licensed | Copyright © 2018-present iczer
|
||||
---
|
||||
@@ -31,7 +31,7 @@ permission = {
|
||||
operation: ['add', 'delete', 'edit', 'close'] //权限下的操作权限
|
||||
}
|
||||
```
|
||||
你也可以设置 role 的值为字符串,比如 permission = 'form', 它等同于:
|
||||
你也可以设置 permission 的值为字符串,比如 permission = 'form', 它等同于:
|
||||
```js
|
||||
permission = {
|
||||
id: 'form'
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
title: 108个小技巧
|
||||
lang: zn-CN
|
||||
---
|
||||
# 108个小技巧
|
||||
|
||||
## 自定义菜单icon
|
||||
## 隐藏页面标题
|
||||
## 关闭页签API
|
||||
## 权限校验PI
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 开发
|
||||
lang: zh-CN
|
||||
---
|
||||
# 开发
|
||||
@@ -1,161 +0,0 @@
|
||||
---
|
||||
title: 服务端交互
|
||||
lang: zh-CN
|
||||
---
|
||||
# 服务端交互
|
||||
数据服务是一个应用的灵魂,它驱动着应用的各个功能模块的正常运转。Vue Antd Admin 在 service 模块封装了服务端交互,通过 API 的形式可以和任何技术栈的服务端应用一起工作。
|
||||
## 服务交互流程
|
||||
在 Vue Antd Admin 中,服务端交互流程如下:
|
||||
* 组件内调用 service 服务 API
|
||||
* service 服务 API 封装请求数据,通过 request.js 发送请求
|
||||
* 组件获取 service 返回的数据,更新视图数据或触发其它行为
|
||||
|
||||
我们以登录为例,Login.vue 组件内,用户输入账号密码,点击登录,调用 services/user/login api
|
||||
```vue {5,17}
|
||||
<template>
|
||||
...
|
||||
</template>
|
||||
<script>
|
||||
import {login} from '@/services/user'
|
||||
...
|
||||
export default {
|
||||
name: 'Login',
|
||||
methods: {
|
||||
onSubmit (e) {
|
||||
e.preventDefault()
|
||||
this.form.validateFields((err) => {
|
||||
if (!err) {
|
||||
this.logging = true
|
||||
const name = this.form.getFieldValue('name')
|
||||
const password = this.form.getFieldValue('password')
|
||||
login(name, password).then(res => this.afterLogin(res))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
`services/user/login` 封装账户密码数据,通过 `request.js` 发送登录服务请求
|
||||
```js
|
||||
import {request, METHOD} from '@/utils/request'
|
||||
/**
|
||||
* 登录服务
|
||||
* @param name 账户名
|
||||
* @param password 账户密码
|
||||
* @returns {Promise<AxiosResponse<T>>}
|
||||
*/
|
||||
async function login(name, password) {
|
||||
return request(LOGIN, METHOD.POST, {
|
||||
name: name,
|
||||
password: password
|
||||
})
|
||||
}
|
||||
```
|
||||
Login.vue 获取登录服务返回的数据,进行后续操作
|
||||
```vue {14,18-23}
|
||||
<template>
|
||||
...
|
||||
</template>
|
||||
<script>
|
||||
import {login} from '@/services/user'
|
||||
...
|
||||
export default {
|
||||
name: 'Login',
|
||||
methods: {
|
||||
onSubmit (e) {
|
||||
this.form.validateFields((err) => {
|
||||
if (!err) {
|
||||
...
|
||||
login(name, password).then(res => this.afterLogin(res))
|
||||
}
|
||||
})
|
||||
},
|
||||
afterLogin(res) {
|
||||
if (res.data.code >= 0) { //登录成功
|
||||
...
|
||||
} else { //登录失败
|
||||
this.error = loginRes.message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
## 服务模块结构
|
||||
服务模块结构如下:
|
||||
```bash
|
||||
...
|
||||
├── src
|
||||
│ └── services # 数据服务模块
|
||||
│ ├── user.js # 用户数据服务
|
||||
│ ├── product.js # 产品服务
|
||||
│ ...
|
||||
│ ├── api.js # api 地址管理
|
||||
│ └── index.js # 服务模块导出
|
||||
...
|
||||
│ └── utils # 数据服务模块
|
||||
│ ├── request.js # 基于 axios 的 http 请求工具
|
||||
...
|
||||
```
|
||||
services 文件夹下, api.js 用于服务请求地址的统一管理,index.js 用于模块化导出服务,其它 *.js 文件对应各个服务模块。
|
||||
## request.js
|
||||
request.js 基于 axios 封装了一些常用的函数,如下:
|
||||
```js
|
||||
export {
|
||||
METHOD, //http method 常量
|
||||
AUTH_TYPE, //凭证认证类型 常量
|
||||
request, //http请求函数
|
||||
setAuthorization, //设置身份凭证函数
|
||||
removeAuthorization, //移除身份凭证函数
|
||||
checkAuthorization //检查身份凭证是否过期函数
|
||||
}
|
||||
```
|
||||
:::tip
|
||||
凭证认证类型默认为 [Bearer](https://www.jianshu.com/p/8f7009456abc),你可以根据自己的需要实现其它类型的认证
|
||||
:::
|
||||
## Base url 配置
|
||||
你可以在项目根目录下的环境变量文件(.env 和 .env.development)中配置你的 API 服务 base url 地址。
|
||||
|
||||
生产环境,.env 文件
|
||||
```properties
|
||||
VUE_APP_API_BASE_URL=https://www.server.com
|
||||
```
|
||||
开发环境,.env.development 文件:
|
||||
```properties
|
||||
VUE_APP_API_BASE_URL=https://localhost:8000
|
||||
```
|
||||
## 跨域设置
|
||||
在开发环境中,通常我们的Vue应用和服务应用运行在不同的地址或端口上。我们可以通过简单的设置,代理前端请求,来避免跨域问题。如下:
|
||||
|
||||
首先,在 services/api.js 文件中设置 API_PROXY_PREFIX 常量,BASE_URL 像下面这样设置:
|
||||
```js {2,4}
|
||||
//跨域代理前缀
|
||||
const API_PROXY_PREFIX='/api'
|
||||
//base url
|
||||
const BASE_URL = process.env.NODE_ENV === 'production' ? process.env.VUE_APP_API_BASE_URL : API_PROXY_PREFIX
|
||||
//导出api服务地址
|
||||
module.exports = {
|
||||
LOGIN: `${BASE_URL}/login`,
|
||||
ROUTES: `${BASE_URL}/routes`
|
||||
}
|
||||
```
|
||||
然后,在 vue.config.js 文件中配置代理:
|
||||
```js
|
||||
model.exports = {
|
||||
devServer: {
|
||||
proxy: {
|
||||
'/api': { //此处要与 /services/api.js 中的 API_PROXY_PREFIX 值保持一致
|
||||
target: process.env.VUE_APP_API_BASE_URL,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/api': ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
:::tip
|
||||
此代理配置仅适用于开发环境,生产环境的跨域代理请在自己的web服务器配置。
|
||||
:::
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 其它
|
||||
lang: zh-CN
|
||||
---
|
||||
# 其它
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
title: 社区
|
||||
lang: zh-CN
|
||||
---
|
||||
# 社区
|
||||
|
||||
## 交流学习
|
||||
### QQ群:812277510、610090280(已满)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 更新日志
|
||||
lang: zh-CN
|
||||
---
|
||||
# 更新日志
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
title: 开始
|
||||
lang: zh-CN
|
||||
---
|
||||
## 开始
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
title: 常见问题
|
||||
lang: zh-CN
|
||||
---
|
||||
# 常见问题
|
||||
### 为什么不是 Ant Design Pro Vue ?
|
||||
[Ant Design Pro Vue](https://github.com/vueComponent/ant-design-vue-pro) 是 [Ant Design Pro](https://github.com/ant-design/ant-design-pro) 的 Vue 版本,其中项目结构、组件、
|
||||
布局和使用方法等基本与 Ant Design Pro 的 react 版本保持一致。如果你比较熟悉 react 版,或者你已经在使用它,这确实是一个不错的选择。
|
||||
|
||||
[Vue Antd Admin](https://github.com/iczer/vue-antd-admin) 同样实现了 Ant Design Pro 的所有功能。与此同时,我们还根据 Vue 的特性,对 Ant Design Pro 的一些组件和布局作出了相应的修改及优化,同时不影响保持与 Ant Design Pro 的一致。
|
||||
|
||||
另外,我们还在添加一些 Ant Design Pro 没有的功能,比如全局动画、多页签模式等。
|
||||
|
||||
如果你想使用 Ant Design Pro,但又觉得它缺乏一些你想要的功能,不妨看看 [Vue Antd Admin](https://github.com/iczer/vue-antd-admin),我们会认真考虑每个用户的需求。
|
||||
|
||||
因此,如果你有一些不错的想法和建议,欢迎随时和我们交流,很可能你的想法就在我们下一个版本中实现。
|
||||
|
||||
### 如何使用 Vue Antd Admin ?
|
||||
请阅读文档 [开始使用](./use.md)。有任何疑问,欢迎在 github 上给我们提交 [issue](https://github.com/iczer/vue-antd-admin/issues/new)。
|
||||
|
||||
### 是否支持国际化 ?
|
||||
Vue Antd Admin 引入了 vue-i18n 支持。因此你可以使用 vue-i18n 的特性对项目做国际化修改,详细请查看 [国际化](../advance/i18n.md)
|
||||
@@ -2,13 +2,6 @@
|
||||
title: 使用
|
||||
lang: zh-CN
|
||||
---
|
||||
# 使用
|
||||
## 准备
|
||||
你的本地环境需要安装 yarn、node 和 git。我们的技术栈基于 ES2015+、Vue、Antd,提前学习这些知识会非常有帮助。
|
||||
## 安装
|
||||
克隆本项目到本地
|
||||
```bash
|
||||
$ git clone https://github.com/iczer/vue-antd-admin.git
|
||||
```
|
||||
安装依赖
|
||||
```bash
|
||||
@@ -16,17 +9,7 @@ $ yarn install
|
||||
or
|
||||
$ npm install
|
||||
```
|
||||
:::tip
|
||||
master 分支是 Vue Antd Admin 的标准版代码,此分支代码适合用于用于学习研究,不推荐在此分支做正式开发。
|
||||
我们在 basic 分支提供了 Vue Antd Admin 的基础版代码,正式开发请切换至此分支,以便于后续的版本更新。
|
||||
:::
|
||||
:::warning
|
||||
如果基于 `master分支` 进行开发,在版本更新时遇到的代码冲突问题请自行解决,我们不对基于 `master分支` 开发时遇到的问题提供技术支持。
|
||||
再次强调,`master分支` 仅推荐用于学习参考,正式开发请切换至 `basic` 分支!!!
|
||||
:::
|
||||
## 目录结构
|
||||
我们已经为你生成了一个完整的开发框架,提供了涵盖中后台开发的各类功能和坑位,下面是整个项目的目录结构。
|
||||
|
||||
```bash
|
||||
├── docs # 使用文档
|
||||
├── public
|
||||
@@ -59,4 +42,3 @@ $ yarn serve
|
||||
or
|
||||
$ npm run serve
|
||||
```
|
||||
启动成功后,会看到一个本地预览地址,通常是 http://localhost:8080 。接下来就可以修改代码,并实时预览修改结果啦!
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"homepage": "https://iczer.github.io/vue-antd-admin",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"dev": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"predeploy": "yarn build",
|
||||
@@ -18,12 +18,15 @@
|
||||
"animate.css": "^4.1.0",
|
||||
"ant-design-vue": "1.7.2",
|
||||
"axios": "^0.19.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"clipboard": "^2.0.6",
|
||||
"core-js": "^3.6.5",
|
||||
"crypto-js": "^4.1.1",
|
||||
"date-fns": "^2.14.0",
|
||||
"enquire.js": "^2.1.6",
|
||||
"highlight.js": "^10.2.1",
|
||||
"js-cookie": "^2.2.1",
|
||||
"js-md5": "^0.7.3",
|
||||
"mockjs": "^1.1.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"viser-vue": "^2.4.8",
|
||||
@@ -31,7 +34,8 @@
|
||||
"vue-i18n": "^8.18.2",
|
||||
"vue-router": "^3.3.4",
|
||||
"vuedraggable": "^2.23.2",
|
||||
"vuex": "^3.4.0"
|
||||
"vuex": "^3.4.0",
|
||||
"vuex-persistedstate": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ant-design/colors": "^4.0.1",
|
||||
|
||||
52
src/api/identity/customerLoginSystem.js
Normal file
52
src/api/identity/customerLoginSystem.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import request from '@/utils/request'
|
||||
var service_name = 'oil-identity'
|
||||
var group_name = 'customerLoginSystem'
|
||||
export default {
|
||||
getByPage(page) { // 分页查询
|
||||
return request({
|
||||
url: `/${service_name}/${group_name}/getByPage`,
|
||||
method: 'post',
|
||||
data: page
|
||||
})
|
||||
},
|
||||
save(oilDicMark) { // 保存
|
||||
return request({
|
||||
url: `/${service_name}/${group_name}/save`,
|
||||
method: 'post',
|
||||
data: oilDicMark
|
||||
})
|
||||
},
|
||||
get(id) { // 根据id查询
|
||||
return request({
|
||||
url: `/${service_name}/${group_name}/get/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
getUserLoginSystem(customerId) { // 所有系统以及用户登录权限
|
||||
return request({
|
||||
url: `/${service_name}/${group_name}/getUserLoginSystem/${customerId}`,
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
toggleAuth(oilDicMark) { // 修改登录授权状态
|
||||
return request({
|
||||
url: `/${service_name}/${group_name}/toggleAuth`,
|
||||
method: 'put',
|
||||
data: oilDicMark
|
||||
})
|
||||
},
|
||||
update(oilDicMark) { // 更新
|
||||
return request({
|
||||
url: `/${service_name}/${group_name}/update`,
|
||||
method: 'put',
|
||||
data: oilDicMark
|
||||
})
|
||||
},
|
||||
deleteById(id) { // 根据id删除
|
||||
return request({
|
||||
url: `/${service_name}/${group_name}/delete`,
|
||||
method: 'put',
|
||||
data: { id: id }
|
||||
})
|
||||
}
|
||||
}
|
||||
41
src/api/identity/user.js
Normal file
41
src/api/identity/user.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: '/oil-identity/operationUser/loginPwd',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function sendManagerLoginSms(phone) {
|
||||
return request({
|
||||
url: '/oil-identity/operationUser/sendManagerLoginSms',
|
||||
method: 'post',
|
||||
data: {
|
||||
phone
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function loginSms(data) {
|
||||
return request({
|
||||
url: '/oil-identity/operationUser/loginSms',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getInfo() {
|
||||
return request({
|
||||
url: '/oil-identity/unionAuth/info',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
return request({
|
||||
url: '/oil-identity/authorization/logout',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 5.2 KiB |
6
src/bootstrap.js
vendored
6
src/bootstrap.js
vendored
@@ -1,7 +1,7 @@
|
||||
import {loadRoutes, loadGuards, setAppOptions} from '@/utils/routerUtil'
|
||||
import {loadInterceptors} from '@/utils/request'
|
||||
// import {loadInterceptors} from '@/utils/request'
|
||||
import guards from '@/router/guards'
|
||||
import interceptors from '@/utils/axios-interceptors'
|
||||
// import interceptors from '@/utils/axios-interceptors'
|
||||
|
||||
/**
|
||||
* 启动引导方法
|
||||
@@ -15,7 +15,7 @@ function bootstrap({router, store, i18n, message}) {
|
||||
// 设置应用配置
|
||||
setAppOptions({router, store, i18n})
|
||||
// 加载 axios 拦截器
|
||||
loadInterceptors(interceptors, {router, store, i18n, message})
|
||||
// loadInterceptors(interceptors, {router, store, i18n, message})
|
||||
// 加载路由
|
||||
loadRoutes()
|
||||
// 加载路由守卫
|
||||
|
||||
@@ -235,7 +235,7 @@ export default {
|
||||
let matches = this.$route.matched
|
||||
const route = matches[matches.length - 1]
|
||||
let chose = this.routesMap[route.path]
|
||||
if (chose.meta && chose.meta.highlight) {
|
||||
if (chose && chose.meta && chose.meta.highlight) {
|
||||
chose = this.routesMap[chose.meta.highlight]
|
||||
const resolve = this.$router.resolve({path: chose.fullPath})
|
||||
matches = (resolve.resolved && resolve.resolved.matched) || matches
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
// 自定义配置,参考 ./default/setting.config.js,需要自定义的属性在这里配置即可
|
||||
module.exports = {
|
||||
theme: {
|
||||
color: '#13c2c2',
|
||||
color: '#1890ff',
|
||||
mode: 'dark',
|
||||
success: '#52c41a',
|
||||
warning: '#faad14',
|
||||
error: '#f5222f'
|
||||
},
|
||||
multiPage: true,
|
||||
animate: {
|
||||
name: 'lightSpeed',
|
||||
name: 'fade',
|
||||
direction: 'left'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ module.exports = {
|
||||
multiPage: false, //多页签模式,true:开启,false:不开启
|
||||
cachePage: true, //是否缓存页面数据,仅多页签模式下生效,true 缓存, false 不缓存
|
||||
hideSetting: false, //隐藏设置抽屉,true:隐藏,false:不隐藏
|
||||
systemName: 'Vue Antd Admin', //系统名称
|
||||
copyright: '2018 ICZER 工作室出品', //copyright
|
||||
systemName: '星油能源', //系统名称
|
||||
copyright: '星油能源工作室', //copyright
|
||||
asyncRoutes: false, //异步加载路由,true:开启,false:不开启
|
||||
showPageTitle: true, //是否显示页面标题(PageLayout 布局中的页面标题),true:显示,false:不显示
|
||||
filterMenu: true, //根据权限过滤菜单,true:过滤,false:不过滤
|
||||
@@ -27,9 +27,9 @@ module.exports = {
|
||||
name: 'bounce', //动画效果,支持的动画效果可参考 ./animate.config.js
|
||||
direction: 'left' //动画方向,切换页面时动画的方向,参考 ./animate.config.js
|
||||
},
|
||||
footerLinks: [ //页面底部链接,{link: '链接地址', name: '名称/显示文字', icon: '图标,支持 ant design vue 图标库'}
|
||||
{link: 'https://pro.ant.design', name: 'Pro首页'},
|
||||
{link: 'https://github.com/iczer/vue-antd-admin', icon: 'github'},
|
||||
{link: 'https://ant.design', name: 'Ant Design'}
|
||||
footerLinks: [ //页面底部链接,{link: '链接地址', name: '名称/显示文字', icon: '图标,支持 ant design vue 图标库'} 'https://pro.ant.design'
|
||||
{link: 'http://www.xingoil.com/', name: '星油官网管理平台'},
|
||||
// {link: 'https://github.com/iczer/vue-antd-admin', icon: 'github'},
|
||||
// {link: 'https://ant.design', name: 'Ant Design'}
|
||||
],
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ export default {
|
||||
padding: 32px 0;
|
||||
flex: 1;
|
||||
@media (min-width: 768px){
|
||||
|
||||
padding: 112px 0 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
</div>
|
||||
<div :class="['admin-header-right', headerTheme]">
|
||||
<header-search class="header-item" @active="val => searchActive = val" />
|
||||
<a-tooltip class="header-item" title="帮助文档" placement="bottom" >
|
||||
<!-- <a-tooltip class="header-item" title="帮助文档" placement="bottom" >
|
||||
<a href="https://iczer.gitee.io/vue-antd-admin-docs/" target="_blank">
|
||||
<a-icon type="question-circle-o" />
|
||||
</a>
|
||||
</a-tooltip>
|
||||
</a-tooltip> -->
|
||||
<header-notice class="header-item"/>
|
||||
<header-avatar class="header-item"/>
|
||||
<a-dropdown class="lang header-item">
|
||||
@@ -47,8 +47,8 @@ export default {
|
||||
return {
|
||||
langList: [
|
||||
{key: 'CN', name: '简体中文', alias: '简体'},
|
||||
{key: 'HK', name: '繁體中文', alias: '繁體'},
|
||||
{key: 'US', name: 'English', alias: 'English'}
|
||||
// {key: 'HK', name: '繁體中文', alias: '繁體'},
|
||||
// {key: 'US', name: 'English', alias: 'English'}
|
||||
],
|
||||
searchActive: false
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
<script>
|
||||
import {mapGetters} from 'vuex'
|
||||
import {logout} from '@/services/user'
|
||||
import {removeToken} from '@/utils/auth'
|
||||
|
||||
export default {
|
||||
name: 'HeaderAvatar',
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
logout() {
|
||||
logout()
|
||||
removeToken()
|
||||
this.$router.push('/login')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
<a-tabs class="dropdown-tabs" :tabBarStyle="{textAlign: 'center'}" :style="{width: '297px'}">
|
||||
<a-tab-pane tab="通知" key="1">
|
||||
<a-list class="tab-pane">
|
||||
<a-list-item>
|
||||
<!-- <a-list-item>
|
||||
<a-list-item-meta title="你收到了 14 份新周报" description="一年前">
|
||||
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"/>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
</a-list-item> -->
|
||||
<!-- <a-list-item>
|
||||
<a-list-item-meta title="你推荐的 曲妮妮 已通过第三轮面试" description="一年前">
|
||||
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png"/>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list-item> -->
|
||||
<a-list-item>
|
||||
<a-list-item-meta title="这种模板可以区分多种通知类型" description="一年前">
|
||||
<a-list-item-meta title="欢迎使用" description="1秒前">
|
||||
<a-avatar style="background-color: white" slot="avatar" src="https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png"/>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
@@ -32,7 +32,7 @@
|
||||
</a-spin>
|
||||
</div>
|
||||
<span @click="fetchNotice" class="header-notice">
|
||||
<a-badge class="notice-badge" count="12">
|
||||
<a-badge class="notice-badge" count="1">
|
||||
<a-icon :class="['header-notice-icon']" type="bell" />
|
||||
</a-badge>
|
||||
</span>
|
||||
@@ -56,9 +56,10 @@ export default {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
this.loadding = true
|
||||
if (this.show) return
|
||||
this.loading = true
|
||||
setTimeout(() => {
|
||||
this.loadding = false
|
||||
this.loading = false
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export default {
|
||||
name: 'HeaderSearch',
|
||||
data () {
|
||||
return {
|
||||
dataSource: ['选项一', '选项二'],
|
||||
dataSource: [],
|
||||
searchMode: false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2,8 +2,8 @@ import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import {initRouter} from './router'
|
||||
import './theme/index.less'
|
||||
import Antd from 'ant-design-vue'
|
||||
import Viser from 'viser-vue'
|
||||
import Antd from 'ant-design-vue' //组件库
|
||||
import Viser from 'viser-vue' //可视化数据插件
|
||||
import '@/mock'
|
||||
import store from './store'
|
||||
import 'animate.css/source/animate.css'
|
||||
@@ -11,7 +11,7 @@ import Plugins from '@/plugins'
|
||||
import {initI18n} from '@/utils/i18n'
|
||||
import bootstrap from '@/bootstrap'
|
||||
import 'moment/locale/zh-cn'
|
||||
|
||||
//初始化路由
|
||||
const router = initRouter(store.state.setting.asyncRoutes)
|
||||
const i18n = initI18n('CN', 'US')
|
||||
|
||||
@@ -19,7 +19,7 @@ Vue.use(Antd)
|
||||
Vue.config.productionTip = false
|
||||
Vue.use(Viser)
|
||||
Vue.use(Plugins)
|
||||
|
||||
//程序初始化
|
||||
bootstrap({router, store, i18n, message: Vue.prototype.$message})
|
||||
|
||||
new Vue({
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<img alt="logo" class="logo" src="@/assets/img/logo.png" />
|
||||
<span class="title">{{systemName}}</span>
|
||||
</div>
|
||||
<div class="desc">Ant Design 是西湖区最具影响力的 Web 设计规范</div>
|
||||
<div class="desc">星油官网后台管理网站</div>
|
||||
</div>
|
||||
<div class="login">
|
||||
<a-form @submit="onSubmit" :form="form">
|
||||
@@ -16,7 +16,7 @@
|
||||
<a-input
|
||||
autocomplete="autocomplete"
|
||||
size="large"
|
||||
placeholder="admin"
|
||||
placeholder="请输入账号手机号"
|
||||
v-decorator="['name', {rules: [{ required: true, message: '请输入账户名', whitespace: true}]}]"
|
||||
>
|
||||
<a-icon slot="prefix" type="user" />
|
||||
@@ -25,7 +25,7 @@
|
||||
<a-form-item>
|
||||
<a-input
|
||||
size="large"
|
||||
placeholder="888888"
|
||||
placeholder="请输入密码"
|
||||
autocomplete="autocomplete"
|
||||
type="password"
|
||||
v-decorator="['password', {rules: [{ required: true, message: '请输入密码', whitespace: true}]}]"
|
||||
@@ -34,7 +34,7 @@
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="手机号登录" key="2">
|
||||
<!-- <a-tab-pane tab="手机号登录" key="2">
|
||||
<a-form-item>
|
||||
<a-input size="large" placeholder="mobile number" >
|
||||
<a-icon slot="prefix" type="mobile" />
|
||||
@@ -52,7 +52,7 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form-item>
|
||||
</a-tab-pane>
|
||||
</a-tab-pane> -->
|
||||
</a-tabs>
|
||||
<div>
|
||||
<a-checkbox :checked="true" >自动登录</a-checkbox>
|
||||
@@ -61,13 +61,13 @@
|
||||
<a-form-item>
|
||||
<a-button :loading="logging" style="width: 100%;margin-top: 24px" size="large" htmlType="submit" type="primary">登录</a-button>
|
||||
</a-form-item>
|
||||
<div>
|
||||
<!-- <div>
|
||||
其他登录方式
|
||||
<a-icon class="icon" type="alipay-circle" />
|
||||
<a-icon class="icon" type="taobao-circle" />
|
||||
<a-icon class="icon" type="weibo-circle" />
|
||||
<router-link style="float: right" to="/dashboard/workplace" >注册账户</router-link>
|
||||
</div>
|
||||
</div> -->
|
||||
</a-form>
|
||||
</div>
|
||||
</common-layout>
|
||||
@@ -75,8 +75,8 @@
|
||||
|
||||
<script>
|
||||
import CommonLayout from '@/layouts/CommonLayout'
|
||||
import {login, getRoutesConfig} from '@/services/user'
|
||||
import {setAuthorization} from '@/utils/request'
|
||||
import {getRoutesConfig} from '@/services/user'
|
||||
// import {setAuthorization} from '@/utils/request'
|
||||
import {loadRoutes} from '@/utils/routerUtil'
|
||||
import {mapMutations} from 'vuex'
|
||||
|
||||
@@ -102,31 +102,32 @@ export default {
|
||||
this.form.validateFields( (err) => {
|
||||
if (!err) {
|
||||
this.logging = true
|
||||
const name = this.form.getFieldValue('name')
|
||||
const password = this.form.getFieldValue('password')
|
||||
login(name, password).then(this.afterLogin)
|
||||
const username = this.form.getFieldValue('name')
|
||||
const password = this.form.getFieldValue('password');
|
||||
this.$store.dispatch('user/login', {username,password}).then((result) => {(result.code==20000)&&this.$router.push('/dashboard/workplace');})
|
||||
}
|
||||
})
|
||||
},
|
||||
afterLogin(res) {
|
||||
this.logging = false
|
||||
const loginRes = res.data
|
||||
if (loginRes.code >= 0) {
|
||||
const {user, permissions, roles} = loginRes.data
|
||||
this.setUser(user)
|
||||
this.setPermissions(permissions)
|
||||
this.setRoles(roles)
|
||||
setAuthorization({token: loginRes.data.token, expireAt: new Date(loginRes.data.expireAt)})
|
||||
// 获取路由配置
|
||||
afterLogin() {
|
||||
// this.logging = false
|
||||
// const loginRes = res.data
|
||||
getRoutesConfig().then(result => {
|
||||
const routesConfig = result.data.data
|
||||
loadRoutes(routesConfig)
|
||||
this.$router.push('/dashboard/workplace')
|
||||
this.$message.success(loginRes.message, 3)
|
||||
// this.$message.success(loginRes.message, 3)
|
||||
})
|
||||
} else {
|
||||
this.error = loginRes.message
|
||||
}
|
||||
// if (loginRes.code >= 0) {
|
||||
// // const {user, permissions, roles} = loginRes.data
|
||||
// // this.setUser(user)
|
||||
// // this.setPermissions(permissions)
|
||||
// // this.setRoles(roles)
|
||||
// // setAuthorization({token: loginRes.data.token, expireAt: new Date(loginRes.data.expireAt)})
|
||||
// // 获取路由配置
|
||||
|
||||
// } else {
|
||||
// this.error = loginRes.message
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ const AuthorityPlugin = {
|
||||
this[`$${check}Failure`] = onFailure
|
||||
return this[`$${check}Failure`](check)
|
||||
} else {
|
||||
this.$message.error(`对不起,您没有操作权限:${check}`)
|
||||
this.$message.error(`对不起,您没有操作权限:${check},请联系管理员`)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -159,6 +159,7 @@ const AuthorityPlugin = {
|
||||
const role = getRouteRole(roles, this.$route)
|
||||
return auth.apply(this, [{check, type}, permission, role, permissions, roles])
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@ const options = {
|
||||
name: '首页',
|
||||
component: TabsView,
|
||||
redirect: '/login',
|
||||
meta:{
|
||||
exhibition:true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
@@ -90,9 +93,7 @@ const options = {
|
||||
{
|
||||
path: 'query',
|
||||
name: '查询表格',
|
||||
meta: {
|
||||
authority: 'queryForm',
|
||||
},
|
||||
meta: {},
|
||||
component: () => import('@/pages/list/QueryList'),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {hasAuthority} from '@/utils/authority-utils'
|
||||
import {loginIgnore} from '@/router/index'
|
||||
import {checkAuthorization} from '@/utils/request'
|
||||
import NProgress from 'nprogress'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
// import {loginIgnore} from '@/router/index'
|
||||
import NProgress from 'nprogress' //进度条组件
|
||||
NProgress.configure({ showSpinner: false })
|
||||
|
||||
/**
|
||||
@@ -26,9 +27,9 @@ const progressStart = (to, from, next) => {
|
||||
* @param next
|
||||
* @param options
|
||||
*/
|
||||
const loginGuard = (to, from, next, options) => {
|
||||
const {message} = options
|
||||
if (!loginIgnore.includes(to) && !checkAuthorization()) {
|
||||
const loginGuard = (to, from, next,) => {
|
||||
let TOKEN = getToken()
|
||||
if (!TOKEN&&to.path!=='/login') {
|
||||
message.warning('登录已失效,请重新登录')
|
||||
next({path: '/login'})
|
||||
} else {
|
||||
|
||||
@@ -24,7 +24,7 @@ const loginIgnore = {
|
||||
* @returns {VueRouter}
|
||||
*/
|
||||
function initRouter(isAsync) {
|
||||
const options = isAsync ? require('./async/config.async').default : require('./config').default
|
||||
const options = isAsync ? require('./async/config.async').default : require('./config').default;
|
||||
formatRoutes(options.routes)
|
||||
return new Router(options)
|
||||
}
|
||||
|
||||
56
src/store/getters.js
Normal file
56
src/store/getters.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import Cookies from 'js-cookie'
|
||||
const getters = {
|
||||
sidebar: state => state.app.sidebar,
|
||||
size: state => state.app.size,
|
||||
markData: state => state.global.markData,
|
||||
device: state => state.app.device,
|
||||
visitedViews: state => state.tagsView.visitedViews,
|
||||
cachedViews: state => state.tagsView.cachedViews,
|
||||
token: state => state.user.token,
|
||||
avatar: state => state.user.avatar,
|
||||
name: state => state.user.name,
|
||||
introduction: state => state.user.introduction,
|
||||
role: state => state.user.role,
|
||||
auths: state => state.user.auths,
|
||||
permission_routes: state => state.permission.routes,
|
||||
sysUserList: state => state.user.sysUserList,
|
||||
user: state => state.user.user,
|
||||
areaTree: state => state.global.areaTree,
|
||||
networkList: state => state.global.networkList,
|
||||
departmentList: state => state.global.departmentList,
|
||||
fleetList: state => state.global.fleetList,
|
||||
waybillId: state => state.global.waybillId,
|
||||
plateNumber: state => state.global.plateNumber,
|
||||
bannerInfoList: state => state.global.bannerInfoList,
|
||||
|
||||
trackCss: state => state.global.trackCss,
|
||||
|
||||
Link: state => state.global.Link,
|
||||
|
||||
helpInfo: state => state.global.helpInfo,
|
||||
drawerFixed: state => state.global.drawerFixed,
|
||||
vehicleTypeList: state => state.global.vehicleTypeList,
|
||||
largeAreaList: state => state.global.largeAreaList,
|
||||
incomeBankList: state => state.global.incomeBankList,
|
||||
currentIncomeBank: state => {
|
||||
let incomeBank = state.global.currentIncomeBank
|
||||
if (!incomeBank.incomeBankId) {
|
||||
incomeBank = Cookies.get('currentIncome')
|
||||
if (incomeBank) {
|
||||
incomeBank = JSON.parse(incomeBank)
|
||||
}
|
||||
}
|
||||
return incomeBank
|
||||
},
|
||||
autoCheckDocument: state => state.status.autoCheckDocument,
|
||||
|
||||
uploadToken: state => {
|
||||
const token = state.global.uploadToken.pop()
|
||||
return token
|
||||
},
|
||||
tokenEncrypt: state => {
|
||||
const token = state.global.tokenEncrypt.pop()
|
||||
return token
|
||||
}
|
||||
}
|
||||
export default getters
|
||||
0
src/store/global.js
Normal file
0
src/store/global.js
Normal file
@@ -1,8 +1,10 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import modules from './modules'
|
||||
import getters from './getters'
|
||||
|
||||
Vue.use(Vuex)
|
||||
const store = new Vuex.Store({modules})
|
||||
|
||||
console.log(modules,'11')
|
||||
const store = new Vuex.Store({modules,getters})
|
||||
console.log(store,'store')
|
||||
export default store
|
||||
|
||||
0
src/store/modules/global.js
Normal file
0
src/store/modules/global.js
Normal file
@@ -1,4 +1,5 @@
|
||||
import account from './account'
|
||||
import setting from './setting'
|
||||
import user from './user'
|
||||
|
||||
export default {account, setting}
|
||||
export default {account, setting,user}
|
||||
@@ -32,6 +32,7 @@ export default {
|
||||
},
|
||||
firstMenu(state, getters) {
|
||||
const {menuData} = getters
|
||||
console.log(menuData)
|
||||
if (menuData.length > 0 && !menuData[0].fullPath) {
|
||||
formatFullPath(menuData)
|
||||
}
|
||||
|
||||
114
src/store/modules/user.js
Normal file
114
src/store/modules/user.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import { login, loginSms, logout, getInfo } from '@/api/identity/user'
|
||||
import { getToken, setToken, removeToken, setUsername, setPassword, setChecked, removeChecked, removeUsername, removePassword } from '@/utils/auth'
|
||||
import md5 from 'js-md5'
|
||||
import store from "@/store";
|
||||
const state = {
|
||||
token: getToken(),
|
||||
role: null, // 角色
|
||||
auths: [], // 权限
|
||||
user: {}// 存储用户信息
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_ROLE: (state, role) => {
|
||||
state.role = role
|
||||
},
|
||||
SET_AUTHS: (state, auths) => {
|
||||
state.auths = auths
|
||||
},
|
||||
SET_USER: (state, user) => {
|
||||
state.user = user
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
login({ commit }, userInfo) {
|
||||
const { username, password, checked, verifyCode } = userInfo
|
||||
return new Promise((resolve, reject) => {
|
||||
login({ username: username.trim(), password: md5(password), verifyCode }).then(res => {
|
||||
// 存到vuex
|
||||
commit('SET_TOKEN', res.data.accessToken)
|
||||
// 存到cookie
|
||||
setToken(res.data.accessToken)
|
||||
// 将账号密码和公司存入cookie中
|
||||
if (checked) {
|
||||
setChecked(checked)
|
||||
setUsername(username.trim())
|
||||
setPassword(md5(password))
|
||||
}
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
loginSms({ commit }, userInfo) {
|
||||
console.log('666666')
|
||||
return new Promise((resolve, reject) => {
|
||||
loginSms(userInfo).then(res => {
|
||||
// 存到vuex
|
||||
commit('SET_TOKEN', res.data.accessToken)
|
||||
// 存到cookie
|
||||
setToken(res.data.accessToken)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
getInfo({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo().then( response => {
|
||||
const data = response.data
|
||||
store.dispatch('user/createWebsocket',data.id)
|
||||
commit('SET_ROLE', data.role)
|
||||
commit('SET_AUTHS', data.authList)
|
||||
commit('SET_USER', data)
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// user logout
|
||||
logout({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout().then(() => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLE', null)
|
||||
commit('SET_AUTHS', [])
|
||||
removeToken()
|
||||
removeChecked()
|
||||
removeUsername()
|
||||
removePassword()
|
||||
// websocket.closeWebSocket()
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
resetToken({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLE', null)
|
||||
commit('SET_AUTHS', [])
|
||||
commit('SET_USER', {})
|
||||
removeToken()
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
64
src/utils/auth.js
Normal file
64
src/utils/auth.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
const TokenKey = 'Authorization'
|
||||
const NetWorkId = 'networkId'
|
||||
const UserName = 'username'
|
||||
const PassWord = 'password'
|
||||
const Checked = 'checked'
|
||||
|
||||
export function getToken() {
|
||||
return Cookies.get(TokenKey)
|
||||
}
|
||||
|
||||
export function setToken(token) {
|
||||
return Cookies.set(TokenKey, token, { expires: 1 })
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return Cookies.remove(TokenKey)
|
||||
}
|
||||
|
||||
export function setNet(networkId) {
|
||||
return Cookies.set(NetWorkId, networkId, { expires: 7 })
|
||||
}
|
||||
|
||||
export function setUsername(username) {
|
||||
return Cookies.set(UserName, username, { expires: 7 })
|
||||
}
|
||||
|
||||
export function setPassword(password) {
|
||||
return Cookies.set(PassWord, password, { expires: 7 })
|
||||
}
|
||||
|
||||
export function getNet() {
|
||||
return Cookies.get(NetWorkId)
|
||||
}
|
||||
|
||||
export function getUsername() {
|
||||
return Cookies.get(UserName)
|
||||
}
|
||||
|
||||
export function getPassword() {
|
||||
return Cookies.get(PassWord)
|
||||
}
|
||||
|
||||
export function setChecked(checked) {
|
||||
return Cookies.set(Checked, checked, { expires: 7 })
|
||||
}
|
||||
|
||||
export function getChecked() {
|
||||
return Cookies.get(Checked)
|
||||
}
|
||||
|
||||
export function removeNet() {
|
||||
return Cookies.remove(NetWorkId)
|
||||
}
|
||||
export function removeChecked() {
|
||||
return Cookies.remove(Checked)
|
||||
}
|
||||
export function removeUsername() {
|
||||
return Cookies.remove(UserName)
|
||||
}
|
||||
export function removePassword() {
|
||||
return Cookies.remove(PassWord)
|
||||
}
|
||||
47
src/utils/encode.js
Normal file
47
src/utils/encode.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
import bcrypt from 'bcryptjs'
|
||||
import md5 from 'js-md5'
|
||||
var keyStr = 'qDfajQ*v@W1mCruZ'
|
||||
|
||||
export default {
|
||||
|
||||
/**
|
||||
* @param {*需要加密的字符串 注:对象转化为json字符串再加密} word
|
||||
* @param {*aes加密需要的key值,这个key值后端同学会告诉你} keyStr
|
||||
*/
|
||||
encrypt(word) { // 加密
|
||||
var key = CryptoJS.enc.Utf8.parse(keyStr)
|
||||
var srcs = CryptoJS.enc.Utf8.parse(word)
|
||||
var encrypted = CryptoJS.AES.encrypt(srcs, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }) // 加密模式为ECB,补码方式为PKCS5Padding(也就是PKCS7)
|
||||
return encrypted.toString()
|
||||
},
|
||||
decrypt(word) { // 解密
|
||||
var key = CryptoJS.enc.Utf8.parse(keyStr)
|
||||
var decrypt = CryptoJS.AES.decrypt(word, key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 })
|
||||
return CryptoJS.enc.Utf8.stringify(decrypt).toString()
|
||||
},
|
||||
md5Salt(str) { // md5盐加密
|
||||
return md5(str + 'kdq*&qflbn1gga?aDq')
|
||||
},
|
||||
md5NoSalt(str) {
|
||||
return md5(str)
|
||||
},
|
||||
uuid() { // 获取uuid
|
||||
var s = []
|
||||
var hexDigits = '0123456789abcdef'
|
||||
for (var i = 0; i < 36; i++) {
|
||||
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
|
||||
}
|
||||
s[14] = '4'
|
||||
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1)
|
||||
s[8] = s[13] = s[18] = s[23] = '-'
|
||||
|
||||
var uuid = s.join('')
|
||||
return uuid
|
||||
},
|
||||
bcrypt(str) {
|
||||
var salt = bcrypt.genSaltSync(10) // 定义密码加密的计算强度,默认10
|
||||
var hash = bcrypt.hashSync(this.md5Salt(str), salt) // 把要加密的内容带进去,变量hash就是加密后的密码
|
||||
return hash
|
||||
}
|
||||
}
|
||||
@@ -1,168 +1,167 @@
|
||||
import axios from 'axios'
|
||||
import Cookie from 'js-cookie'
|
||||
import utils from '@/utils/encode'
|
||||
import store from '@/store'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { message } from 'ant-design-vue';
|
||||
const CancelToken = axios.CancelToken;
|
||||
|
||||
// 跨域认证信息 header 名
|
||||
const xsrfHeaderName = 'Authorization'
|
||||
|
||||
axios.defaults.timeout = 5000
|
||||
axios.defaults.withCredentials= true
|
||||
axios.defaults.xsrfHeaderName= xsrfHeaderName
|
||||
axios.defaults.xsrfCookieName= xsrfHeaderName
|
||||
|
||||
// 认证类型
|
||||
const AUTH_TYPE = {
|
||||
BEARER: 'Bearer',
|
||||
BASIC: 'basic',
|
||||
AUTH1: 'auth1',
|
||||
AUTH2: 'auth2',
|
||||
}
|
||||
|
||||
// http method
|
||||
const METHOD = {
|
||||
GET: 'get',
|
||||
POST: 'post'
|
||||
}
|
||||
|
||||
/**
|
||||
* axios请求
|
||||
* @param url 请求地址
|
||||
* @param method {METHOD} http method
|
||||
* @param params 请求参数
|
||||
* @returns {Promise<AxiosResponse<T>>}
|
||||
*/
|
||||
async function request(url, method, params, config) {
|
||||
switch (method) {
|
||||
case METHOD.GET:
|
||||
return axios.get(url, {params, ...config})
|
||||
case METHOD.POST:
|
||||
return axios.post(url, params, config)
|
||||
default:
|
||||
return axios.get(url, {params, ...config})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置认证信息
|
||||
* @param auth {Object}
|
||||
* @param authType {AUTH_TYPE} 认证类型,默认:{AUTH_TYPE.BEARER}
|
||||
*/
|
||||
function setAuthorization(auth, authType = AUTH_TYPE.BEARER) {
|
||||
switch (authType) {
|
||||
case AUTH_TYPE.BEARER:
|
||||
Cookie.set(xsrfHeaderName, 'Bearer ' + auth.token, {expires: auth.expireAt})
|
||||
break
|
||||
case AUTH_TYPE.BASIC:
|
||||
case AUTH_TYPE.AUTH1:
|
||||
case AUTH_TYPE.AUTH2:
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移出认证信息
|
||||
* @param authType {AUTH_TYPE} 认证类型
|
||||
*/
|
||||
function removeAuthorization(authType = AUTH_TYPE.BEARER) {
|
||||
switch (authType) {
|
||||
case AUTH_TYPE.BEARER:
|
||||
Cookie.remove(xsrfHeaderName)
|
||||
break
|
||||
case AUTH_TYPE.BASIC:
|
||||
case AUTH_TYPE.AUTH1:
|
||||
case AUTH_TYPE.AUTH2:
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查认证信息
|
||||
* @param authType
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function checkAuthorization(authType = AUTH_TYPE.BEARER) {
|
||||
switch (authType) {
|
||||
case AUTH_TYPE.BEARER:
|
||||
if (Cookie.get(xsrfHeaderName)) {
|
||||
return true
|
||||
}
|
||||
break
|
||||
case AUTH_TYPE.BASIC:
|
||||
case AUTH_TYPE.AUTH1:
|
||||
case AUTH_TYPE.AUTH2:
|
||||
default:
|
||||
break
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载 axios 拦截器
|
||||
* @param interceptors
|
||||
* @param options
|
||||
*/
|
||||
function loadInterceptors(interceptors, options) {
|
||||
const {request, response} = interceptors
|
||||
// 加载请求拦截器
|
||||
request.forEach(item => {
|
||||
let {onFulfilled, onRejected} = item
|
||||
if (!onFulfilled || typeof onFulfilled !== 'function') {
|
||||
onFulfilled = config => config
|
||||
}
|
||||
if (!onRejected || typeof onRejected !== 'function') {
|
||||
onRejected = error => Promise.reject(error)
|
||||
}
|
||||
axios.interceptors.request.use(
|
||||
config => onFulfilled(config, options),
|
||||
error => onRejected(error, options)
|
||||
)
|
||||
const timeout = 20000
|
||||
const WhiteApiErr = ['userSavePermissionByPhone','batchEnableDisable','batchPriceEnableDisable','getPushOrderInfo']
|
||||
const service = axios.create({
|
||||
baseURL: process.env.VUE_APP_BASE_API,
|
||||
timeout: timeout // 默认请求超时时间
|
||||
})
|
||||
// 加载响应拦截器
|
||||
response.forEach(item => {
|
||||
let {onFulfilled, onRejected} = item
|
||||
if (!onFulfilled || typeof onFulfilled !== 'function') {
|
||||
onFulfilled = response => response
|
||||
const timeoutWhite = ['/oil-finance/oilOrderInfo/importExcelOrder']
|
||||
|
||||
// 加密白名单
|
||||
const encryptWhite = ['/oil-finance/oilOrderInfo/importExcelOrder']
|
||||
let a = []
|
||||
// request 拦截器
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
let source = CancelToken.source();
|
||||
config.cancelToken = source.token;
|
||||
if(a.includes(config.url)){
|
||||
source.cancel(`tooRapid`);
|
||||
return config
|
||||
}
|
||||
if (!onRejected || typeof onRejected !== 'function') {
|
||||
onRejected = error => Promise.reject(error)
|
||||
a.push(config.url)
|
||||
if ( timeoutWhite.includes(config.url)) {
|
||||
config.timeout = 0
|
||||
} else {
|
||||
config.timeout = timeout
|
||||
}
|
||||
const notEncrypt = config.notEncrypt
|
||||
config.headers['dataSources'] = 'WEB'
|
||||
if (store.getters.token) {
|
||||
config.headers['Authorization'] = getToken()
|
||||
}
|
||||
const JSESSIONID = utils.uuid()
|
||||
config.headers['JSESSIONID'] = JSESSIONID
|
||||
config.headers['token'] = utils.bcrypt(JSESSIONID)
|
||||
const env = process.env.VUE_APP_ENV
|
||||
if (env === 'test') {
|
||||
console.log('这里是测试')
|
||||
// 测试环境,加密,打印参数
|
||||
// 设置jsessionid和token
|
||||
if (!notEncrypt && encryptWhite.indexOf(config.url) < 0) {
|
||||
const data = { // 用于存储加密
|
||||
params: '' // 加密后的密文
|
||||
}
|
||||
// 要加密
|
||||
console.log('请求路径', config.url, '参数加密前', config.data)
|
||||
data.params = utils.encrypt(JSON.stringify(config.data))
|
||||
config.data = data
|
||||
}
|
||||
}
|
||||
if (env === 'development') {
|
||||
console.log('这里是测试')
|
||||
// 测试环境,不加密,打印参数
|
||||
console.log('请求路径', config.url, '参数加密前', config.data)
|
||||
}
|
||||
|
||||
if (env === 'production') {
|
||||
console.log('这里是生产')
|
||||
// 生产环境,加密,不输出任何东西
|
||||
// 设置jsessionid和token
|
||||
const JSESSIONID = utils.uuid()
|
||||
config.headers['JSESSIONID'] = JSESSIONID
|
||||
config.headers['token'] = utils.bcrypt(JSESSIONID)
|
||||
if (!notEncrypt && encryptWhite.indexOf(config.url) < 0) {
|
||||
const data = { // 用于存储加密
|
||||
params: '' // 加密后的密文
|
||||
}
|
||||
// 要加密
|
||||
data.params = utils.encrypt(JSON.stringify(config.data))
|
||||
config.data = data
|
||||
}
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
console.log(error.message,'req')
|
||||
return Promise.reject(error)
|
||||
}
|
||||
axios.interceptors.response.use(
|
||||
response => onFulfilled(response, options),
|
||||
error => onRejected(error, options)
|
||||
)
|
||||
|
||||
// response 拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
let urlIndex = a.indexOf(response.config.url)
|
||||
if(urlIndex!==-1){
|
||||
a.splice(urlIndex,1);
|
||||
console.log(a,'防抖移除')
|
||||
}
|
||||
console.log(a,response.config.url,'闭包')
|
||||
// 这里设置loading
|
||||
const res = response.data
|
||||
const env = process.env.VUE_APP_ENV
|
||||
if (response.headers['content-type'].indexOf('application/json') !== -1) {
|
||||
if (env === 'test') {
|
||||
// 测试环境,进行加密解密,打印路径和数据
|
||||
if (res.encrypt === 1) {
|
||||
// 加密的数据,需要解密
|
||||
console.log('请求路径', response.config.url, '返回结果解密前', res)
|
||||
const dataParam = JSON.parse(utils.decrypt(res.data))
|
||||
res.data = JSON.stringify(dataParam) === '{}' ? null : dataParam
|
||||
console.log('请求路径', response.config.url, '返回结果解密后', res)
|
||||
console.log('-------------------------------------------')
|
||||
} else {
|
||||
console.log('请求路径', response.config.url, '返回结果未加密', res)
|
||||
console.log('-------------------------------------------')
|
||||
}
|
||||
}
|
||||
if (env === 'production') {
|
||||
// 生产环境,进行加密解密,不输出日志
|
||||
if (res.encrypt === 1) {
|
||||
// 加密的数据,需要解密
|
||||
const dataParam = JSON.parse(utils.decrypt(res.data))
|
||||
res.data = JSON.stringify(dataParam) === '{}' ? null : dataParam
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
|
||||
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
|
||||
if (res && res.code) {
|
||||
if (res.code === 42011) {
|
||||
message.error(res.msg||'您的登录已失效,请重新登录')
|
||||
// to re-login
|
||||
// Message({
|
||||
// message: res.msg || '您的登录已失效,请重新登录',
|
||||
// type: 'error',
|
||||
// duration: 5 * 1000
|
||||
// })
|
||||
store.dispatch('user/resetToken').then(() => {
|
||||
location.reload()
|
||||
})
|
||||
// 排除自定义的车队返回结果状态码
|
||||
} else if (res.code !== 20000 && res.code !== 30001 && res.code !== 30002 && res.code !== 20001) {
|
||||
if(WhiteApiErr.includes(response.config.url.split('/')[3])){
|
||||
return res
|
||||
}else{
|
||||
message.error(res.msg||'操作失败')
|
||||
return Promise.reject(new Error(res.message || '操作失败'))
|
||||
}
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
if(error.message=='tooRapid'){
|
||||
console.log(error,'res防抖拦截')
|
||||
message.warning ('请求过于频繁!')
|
||||
}else{
|
||||
let urlIndex = a.indexOf(error.config.url)
|
||||
if(urlIndex!==-1){
|
||||
a.splice(urlIndex,1);
|
||||
}
|
||||
message.error ('操作失败!')
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* 解析 url 中的参数
|
||||
* @param url
|
||||
* @returns {Object}
|
||||
*/
|
||||
function parseUrlParams(url) {
|
||||
const params = {}
|
||||
if (!url || url === '' || typeof url !== 'string') {
|
||||
return params
|
||||
}
|
||||
const paramsStr = url.split('?')[1]
|
||||
if (!paramsStr) {
|
||||
return params
|
||||
}
|
||||
const paramsArr = paramsStr.replace(/&|=/g, ' ').split(' ')
|
||||
for (let i = 0; i < paramsArr.length / 2; i++) {
|
||||
const value = paramsArr[i * 2 + 1]
|
||||
params[paramsArr[i * 2]] = value === 'true' ? true : (value === 'false' ? false : value)
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
export {
|
||||
METHOD,
|
||||
AUTH_TYPE,
|
||||
request,
|
||||
setAuthorization,
|
||||
removeAuthorization,
|
||||
checkAuthorization,
|
||||
loadInterceptors,
|
||||
parseUrlParams
|
||||
}
|
||||
export default service
|
||||
|
||||
@@ -253,13 +253,18 @@ function getI18nKey(path) {
|
||||
* @param options
|
||||
*/
|
||||
function loadGuards(guards, options) {
|
||||
//获取参数
|
||||
const {beforeEach, afterEach} = guards
|
||||
const {router} = options
|
||||
//初始化路由配置
|
||||
beforeEach.forEach(guard => {
|
||||
// 检测配置参数
|
||||
if (guard && typeof guard === 'function') {
|
||||
//运行各种配置
|
||||
router.beforeEach((to, from, next) => guard(to, from, next, options))
|
||||
}
|
||||
})
|
||||
//同上
|
||||
afterEach.forEach(guard => {
|
||||
if (guard && typeof guard === 'function') {
|
||||
router.afterEach((to, from) => guard(to, from, options))
|
||||
|
||||
@@ -36,15 +36,32 @@ const assetsCDN = {
|
||||
|
||||
module.exports = {
|
||||
devServer: {
|
||||
// proxy: {
|
||||
// '/api': { //此处要与 /services/api.js 中的 API_PROXY_PREFIX 值保持一致
|
||||
// target: process.env.VUE_APP_API_BASE_URL,
|
||||
// changeOrigin: true,
|
||||
// pathRewrite: {
|
||||
// '^/api': ''
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
proxy: {
|
||||
[process.env.VUE_APP_BASE_API]: {
|
||||
// target: `cls`,
|
||||
// target: `http://192.168.0.65:38080`,
|
||||
// target: `https://www.xingoil.com/adminapi`,
|
||||
target: 'http://uat.xingoil.com/adminapi',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
['^' + process.env.VUE_APP_BASE_API]: ''
|
||||
}
|
||||
},
|
||||
[process.env.VUE_APP_UPLOAD_URL]: {
|
||||
target: `http://127.0.0.1:38080`,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
['^' + process.env.VUE_APP_BASE_API]: ''
|
||||
}
|
||||
},
|
||||
[process.env.VUE_APP_BASE_LSM_API]: {
|
||||
target: `http://121.41.3.91:8085`,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
['^' + process.env.VUE_APP_BASE_LSM_API]: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
pluginOptions: {
|
||||
'style-resources-loader': {
|
||||
|
||||
Reference in New Issue
Block a user