初始项目
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
||||
6
.env
Normal file
@@ -0,0 +1,6 @@
|
||||
# env
|
||||
NODE_ENV = 'dev' // 如果是生产环境,请记得切换为production
|
||||
|
||||
# flag
|
||||
VUE_APP_FLAG='dev'
|
||||
VUE_APP_ADMIN='http://192.168.11.119'
|
||||
6
.env.dev
Normal file
@@ -0,0 +1,6 @@
|
||||
# env
|
||||
NODE_ENV = 'dev' // 如果是生产环境,请记得切换为production
|
||||
|
||||
# flag
|
||||
VUE_APP_FLAG='dev'
|
||||
VUE_APP_ADMIN='http://192.168.11.119'
|
||||
4
.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
build/*.js
|
||||
public
|
||||
dist
|
||||
node_modules
|
||||
17
.eslintrc.js
Normal file
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true
|
||||
},
|
||||
extends: ['plugin:vue/essential', '@vue/prettier'], //需要dev依赖里安装eslint-config-prettier
|
||||
rules: {
|
||||
//'off'或'0':关闭 'warn'或'1':警告 "error"或者"2":报错
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'error',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'error',
|
||||
//下面是重要设置,错误标记
|
||||
'prettier/prettier': 'error'
|
||||
},
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
}
|
||||
}
|
||||
29
.gitignore
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
package-lock.json
|
||||
/dist
|
||||
/target
|
||||
/generate
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.settings
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw*
|
||||
*.iml
|
||||
.classpath
|
||||
.project
|
||||
*.log
|
||||
7
.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 160,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
5
.travis.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js: 10
|
||||
script: npm run test
|
||||
notifications:
|
||||
email: false
|
||||
6
Deployfile
Normal file
@@ -0,0 +1,6 @@
|
||||
[ -e /opt/ebiz/webapps/factory-front-end ] || mkdir -p /opt/ebiz/webapps/factory-front-end
|
||||
[ -e /app/deploy/temp ] || mkdir -p /app/deploy/temp
|
||||
|
||||
rm -irf /app/deploy/temp/* && cd /app/deploy/temp && $GET_ARTIFACT_CMD
|
||||
rm -irf /opt/ebiz/webapps/factory-front-end/*
|
||||
unzip -d /opt/ebiz/webapps/factory-front-end /app/deploy/temp/$ARTIFACT_NAME && chmod 777 -R /opt/ebiz/webapps/factory-front-end/*
|
||||
27
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
pipeline {
|
||||
agent any
|
||||
parameters {
|
||||
string(name: 'ROLLBACK_VERSION', defaultValue: '', description: '')
|
||||
string(name: 'UNLOCK', defaultValue: '', description: '')
|
||||
}
|
||||
stages {
|
||||
stage('pull sourcecode') {
|
||||
steps {
|
||||
git(url: 'http://gitlab.hengansl.com/ebp/ebiz-product-factory-backmanege-h5.git', branch: 'master', credentialsId: 'cicd')
|
||||
}
|
||||
}
|
||||
|
||||
stage('build') {
|
||||
steps {
|
||||
sh '/app/build.sh . 10 "12.22.6"'
|
||||
}
|
||||
}
|
||||
|
||||
stage('deploy') {
|
||||
steps {
|
||||
sh '/app/deploy.sh 2 "10.1.0.192"'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
5
Projectfile
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"groupId":"com.ebiz",
|
||||
"artifactId":"ebiz-product-factory-backmanege-h5",
|
||||
"file":"./dist"
|
||||
}
|
||||
188
README.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# vue-pc
|
||||
|
||||
## 介绍
|
||||
|
||||
- 基于 [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) 搭建的后台管理系统基础框架
|
||||
- [文档参考](https://panjiachen.github.io/vue-element-admin-site/)
|
||||
|
||||
### 技术栈
|
||||
|
||||
Vue2 + Vue-Router + Axios + Vuex + Element + Vue-Loader + Vue-Cli3.0 + ...
|
||||
|
||||
### 命名规范
|
||||
|
||||
- 组件名:大驼峰
|
||||
- 方法名:小驼峰
|
||||
- class 类名:连字符(a-b)
|
||||
- 常量(const):全大写
|
||||
- 变量(let):小驼峰
|
||||
- 文件夹命名: 一律小写(只允许小写字母、中横杠-,如:a-b)
|
||||
- Vue 文件命名: 大驼峰式命名法,即每个单词的首字母大写 CamelCase.vue
|
||||
- css,js,image 等文件命名:一律小写(css/js 文件使用中横杆-,image 使用下划线\_)第三方除外
|
||||
- 如条件允许: import 进来的变量名及 export 都采用大驼峰形式命名,如 import VueRouter from 'vue-router' 及 export default Common
|
||||
|
||||
```javascript
|
||||
//什么叫“如条件允许”:比如我们需要
|
||||
import routes from './routers/router'
|
||||
const router = new VueRouter({
|
||||
routes
|
||||
})
|
||||
//这种情况下,routes可以用小写,事实上,上面的范例可以换一种写法:
|
||||
import Routes from './routers/router'
|
||||
const router = new VueRouter({
|
||||
routes: Routes
|
||||
})
|
||||
```
|
||||
|
||||
## wiki 文档
|
||||
|
||||
[wiki 参考文档](http://114.215.252.122:8090/pages/viewpage.action?pageId=13960243)
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
.
|
||||
├── build // webpack配置文件
|
||||
├── node_modules // npm/yarn安装的项目依赖模块
|
||||
├── public // 静态资源目录
|
||||
├── src // 源码目录
|
||||
│ ├── api // 网络请求文件
|
||||
│ │ ├── app // 基础工程网络请求文件
|
||||
│ │ │ ├── user.js // 用户模块api请求
|
||||
│ │ ├── example
|
||||
│ │ │ └── table.js // 示例模块api请求
|
||||
│ ├── assets // 资源目录
|
||||
│ │ ├── fonts // 字体文件
|
||||
│ │ ├── images // 图片文件
|
||||
│ │ | ├── app // 基础工程图片
|
||||
│ │ | ├── 404_img // 404图片
|
||||
│ │ ├── js
|
||||
│ │ | ├── utils //工具类js
|
||||
│ │ | | ├── auth.js //token设置
|
||||
│ │ | | ├── get-page-title.js //获取页面title
|
||||
│ │ | | ├── get-url.js //根据设置获取请求url
|
||||
│ │ | | ├── premission.js //权限控制
|
||||
│ │ | | ├── request.js //拦截器
|
||||
│ │ | | ├── settings.js //全局设置
|
||||
│ │ | | ├── validate.js //表单校验
|
||||
│ │ | ├── vendor //第三方js
|
||||
│ │ | ├── common.js //全局js方法
|
||||
│ │ | ├── business-common.js //业务相关全局js方法
|
||||
│ │ ├── sass
|
||||
│ │ | └── common.scss // 样式出口文件
|
||||
│ │ | └── element-ui.scss // element-ui样式
|
||||
│ │ | └── minix.scss // 样式配置
|
||||
│ │ | └── sidebar.scss // 侧边栏样式
|
||||
│ │ | └── transition.scss // 动画样式
|
||||
│ │ | └── utils.scss // 工具样式
|
||||
│ │ | └── variables.scss // 变量文件
|
||||
│ ├── components // 公共组件
|
||||
│ ├── config // 配置文件
|
||||
│ | ├── index.js // 环境配置
|
||||
│ | ├── urlMap.js // api url配置
|
||||
│ ├── filters
|
||||
│ | ├── index.js // 过滤器
|
||||
│ ├── icons // svg icon
|
||||
│ ├── router
|
||||
│ | ├── app // 基础工程路由
|
||||
│ | ├── example // 示例路由
|
||||
│ | ├── index.js // 路由配置
|
||||
│ ├── store
|
||||
│ | ├── modules // 状态模块
|
||||
│ | ├── getters.js // 配置getters
|
||||
│ | ├── index.js // 引用vuex,创建store
|
||||
│ ├── views
|
||||
│ | ├── app // 基础工程页面
|
||||
│ | | ├── layout // layout:导航栏、侧边栏、主窗口等
|
||||
│ | | ├── login // 登录页面
|
||||
│ | | ├── 404.vue // 404页面
|
||||
│ | | ├── home.vue // 首页
|
||||
│ | ├── example // 示例页面,不一一列举
|
||||
│ ├── App.vue // 页面入口文件
|
||||
│ ├── main.js // 程序入口文件,加载各种公共组件
|
||||
├── tests // 测试相关文件
|
||||
├── .env.dev // 开发环境配置
|
||||
├── .env.production // 生产环境配置
|
||||
├── .env.staging // staging环境配置
|
||||
├── .eslintrc.js // eslint配置
|
||||
├── babel.config.js // 转码配置
|
||||
├── jest.config.js // 测试配置
|
||||
├── .prettierrc // prettier配置
|
||||
├── package.json // 安装包列表文件
|
||||
├── postcss.config.js // 样式配置
|
||||
├── vue.config.js // vue工程配置
|
||||
.
|
||||
```
|
||||
|
||||
## 项目运行
|
||||
|
||||
```bash
|
||||
git clone http://112.124.100.131/base/ebiz-base-vue-pc.git
|
||||
|
||||
cd ebiz-base-vue-pc
|
||||
|
||||
yarn install(推荐使用yarn)
|
||||
|
||||
yarn serve(开发环境)
|
||||
|
||||
```
|
||||
|
||||
## 项目打包
|
||||
|
||||
```bash
|
||||
# 测试环境打包
|
||||
yarn run build:envName(测试环境打包)
|
||||
|
||||
# 线上环境打包
|
||||
yarn run build:prd(线上环境打包)
|
||||
```
|
||||
|
||||
## 预发环境打包预览、文件检查等
|
||||
|
||||
```bash
|
||||
# 代码检查
|
||||
yarn run lint
|
||||
|
||||
# 代码检查修复
|
||||
yarn run lint:fix
|
||||
|
||||
#代码格式化
|
||||
yarn run format
|
||||
```
|
||||
|
||||
## 快速开始项目
|
||||
|
||||
1、src>>api 目录下创建项目所需 http 请求文件夹
|
||||
2、src>>assets 目录下创建项目所需的 js image 文件夹,以及 scss 文件
|
||||
3、src>>router 目录下创建所需路由文件夹
|
||||
4、src>>store>>modules 目录下创建所需状态管理文件
|
||||
|
||||
##### [注:项目开始前请先配置 vscode 代码检查、格式化](http://115.29.19.195:8090/pages/viewpage.action?pageId=13960404)
|
||||
|
||||
## 主要功能点介绍
|
||||
|
||||
- http 请求文件
|
||||
- 模块划分:app 为基础工程模块、其他项目需另建文件夹
|
||||
- 拦截器:超时设置、请求头加 token、统一处理异常、token 异常重新登录等
|
||||
- mock 数据
|
||||
- [工具 rap2](http://rap2.taobao.org/) 、[参考链接](http://115.29.19.195:8090/display/VUE/mock)
|
||||
- 通过 config 文件夹下 urlMap.js,配置 mock 接口请求
|
||||
- 环境配置
|
||||
- 在 config 文件夹下 index.js,通过 process.env.NODE_ENV 对环境进行配置
|
||||
- 跨域问题可通过后台解决,也可设置前端代理 proxy
|
||||
- router
|
||||
- 模块划分
|
||||
- 路由拦截
|
||||
- 路由懒加载
|
||||
- 权限控制
|
||||
- 可在 permission.js 里设置黑白名单
|
||||
|
||||
## 浏览器支持
|
||||
|
||||
Modern browsers and Internet Explorer 10+.
|
||||
|
||||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
|
||||
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
|
||||
|
||||
######搭配长附加险 例如:鼎城附加定期寿险 ######长附加险初始化规则挂载 rule041 ######搭配长附加险时如果长附加险有年龄对交费期间(保险期间)的限制规则 挂载规则 rule013 ######搭配规则是 保险期间挂载 rule039 ######限制长附加险的交费期间不能大于保险期间是 rule042 交费期间下挂载 040
|
||||
5
babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
]
|
||||
}
|
||||
24
jest.config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
|
||||
transform: {
|
||||
'^.+\\.vue$': 'vue-jest',
|
||||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
|
||||
'jest-transform-stub',
|
||||
'^.+\\.jsx?$': 'babel-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/src/$1'
|
||||
},
|
||||
snapshotSerializers: ['jest-serializer-vue'],
|
||||
testMatch: [
|
||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
|
||||
],
|
||||
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
|
||||
coverageDirectory: '<rootDir>/tests/unit/coverage',
|
||||
// 'collectCoverage': true,
|
||||
'coverageReporters': [
|
||||
'lcov',
|
||||
'text-summary'
|
||||
],
|
||||
testURL: 'http://localhost/'
|
||||
}
|
||||
77
package.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "basic-pc",
|
||||
"version": "1.0.0",
|
||||
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
|
||||
"author": "ebiz-digits",
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"build:dev": "vue-cli-service build --mode dev",
|
||||
"dev": "vue-cli-service serve --mode dev",
|
||||
"preview": "node build/index.js --preview",
|
||||
"lint": "eslint --ext .js,.vue src",
|
||||
"lint:fix": "eslint --fix --ext .js,.vue src",
|
||||
"format": "prettier --config ./.prettierrc --write \"src/**/*.js\" \"src/**/*.vue\"",
|
||||
"test:unit": "jest --clearCache && vue-cli-service test:unit",
|
||||
"test:ci": "npm run lint && npm run test:unit",
|
||||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "0.18.1",
|
||||
"crypto-js": "^4.0.0",
|
||||
"crypto.js": "^2.0.2",
|
||||
"element-ui": "2.15.4",
|
||||
"exif-js": "^2.3.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"js-cookie": "2.2.0",
|
||||
"mavon-editor": "^2.9.1",
|
||||
"node-gyp": "^8.0.0",
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"sortablejs": "^1.14.0",
|
||||
"vue": "2.6.10",
|
||||
"vue-router": "3.0.6",
|
||||
"vue2-editor": "^2.10.2",
|
||||
"vuex": "3.1.0",
|
||||
"swiper": "^5.4.5",
|
||||
"xlsx": "^0.16.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.0.0",
|
||||
"@babel/register": "7.0.0",
|
||||
"@vue/cli-plugin-babel": "3.6.0",
|
||||
"@vue/cli-plugin-eslint": "^3.9.1",
|
||||
"@vue/cli-plugin-unit-jest": "3.6.3",
|
||||
"@vue/cli-service": "3.6.0",
|
||||
"@vue/eslint-config-prettier": "^4.0.1",
|
||||
"@vue/test-utils": "1.0.0-beta.29",
|
||||
"autoprefixer": "^9.5.1",
|
||||
"babel-core": "7.0.0-bridge.0",
|
||||
"babel-eslint": "10.0.1",
|
||||
"babel-jest": "23.6.0",
|
||||
"chalk": "2.4.2",
|
||||
"connect": "3.6.6",
|
||||
"eslint": "5.15.3",
|
||||
"eslint-plugin-vue": "5.2.2",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"mockjs": "1.0.1-beta3",
|
||||
"node-sass": "^4.9.0",
|
||||
"runjs": "^4.3.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"script-ext-html-webpack-plugin": "2.1.3",
|
||||
"script-loader": "^0.7.2",
|
||||
"serve-static": "^1.13.2",
|
||||
"svg-sprite-loader": "4.1.3",
|
||||
"svgo": "1.2.2",
|
||||
"vue-template-compiler": "2.6.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
]
|
||||
}
|
||||
8
postcss.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
'plugins': {
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
'autoprefixer': {}
|
||||
}
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
21
public/index.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
|
||||
<title><%= webpackConfig.name %></title>
|
||||
<!--<script src="http://47.96.143.111:8091/validateAuth.js" type="text/javascript"></script>-->
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
||||
<!-- <script src="https://lib.baomitu.com/vue/2.6.10/vue.min.js"></script> -->
|
||||
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.0/index.js"></script> -->
|
||||
</html>
|
||||
16
src/App.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<transition name="router-fade" mode="out-in">
|
||||
<router-view />
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import 'src/assets/sass/common.scss';
|
||||
</style>
|
||||
35
src/api/app/user.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import request from '@/assets/js/utils/request'
|
||||
import getUrl from '@/assets/js/utils/get-url'
|
||||
|
||||
// 登录
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: getUrl('/user/login', 0),
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取个人信息
|
||||
export function getInfo(token) {
|
||||
return request({
|
||||
url: getUrl('/user/info', 0),
|
||||
method: 'get',
|
||||
params: { token }
|
||||
})
|
||||
}
|
||||
|
||||
// 登出
|
||||
export function logout() {
|
||||
return request({
|
||||
url: getUrl('/user/logout', 0),
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
// 测试示例
|
||||
export function indexUser() {
|
||||
return request({
|
||||
url: getUrl('/index/user', 0),
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
4
src/api/generatedApi/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
import request from '@/assets/js/utils/request'
|
||||
import getUrl from '@/assets/js/utils/get-url'
|
||||
export default {
|
||||
}
|
||||
BIN
src/assets/fonts/awesome/FontAwesome.otf
Normal file
BIN
src/assets/fonts/awesome/fontawesome-webfont.eot
Normal file
2671
src/assets/fonts/awesome/fontawesome-webfont.svg
Normal file
|
After Width: | Height: | Size: 434 KiB |
BIN
src/assets/fonts/awesome/fontawesome-webfont.ttf
Normal file
BIN
src/assets/fonts/awesome/fontawesome-webfont.woff
Normal file
BIN
src/assets/fonts/awesome/fontawesome-webfont.woff2
Normal file
BIN
src/assets/images/404_img/404.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
src/assets/images/404_img/404_cloud.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
src/assets/images/active.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/assets/images/home.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
src/assets/images/icon/u3.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
461
src/assets/js/business-common.js
Normal file
@@ -0,0 +1,461 @@
|
||||
/**
|
||||
* @desc 扩展对象继承
|
||||
* @param {Object} out 一个或多个对象
|
||||
* @return {Object} 对象
|
||||
*/
|
||||
Object.extend = function(out) {
|
||||
out = out || {}
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
if (!arguments[i]) continue
|
||||
|
||||
for (var key in arguments[i]) {
|
||||
if (arguments[i].hasOwnProperty(key)) out[key] = arguments[i][key]
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 时间格式转化
|
||||
* @param {String} format 转化格式
|
||||
* @return {String} 已转化的时间
|
||||
*/
|
||||
Date.prototype.format = function(format) {
|
||||
let args = {
|
||||
'M+': this.getMonth() + 1,
|
||||
'd+': this.getDate(),
|
||||
'h+': this.getHours(),
|
||||
'm+': this.getMinutes(),
|
||||
's+': this.getSeconds(),
|
||||
'q+': Math.floor((this.getMonth() + 3) / 3), // quarter
|
||||
S: this.getMilliseconds()
|
||||
}
|
||||
if (/(y+)/.test(format)) format = format.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
|
||||
for (var i in args) {
|
||||
var n = args[i]
|
||||
if (new RegExp('(' + i + ')').test(format)) format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? n : ('00' + n).substr(('' + n).length))
|
||||
}
|
||||
return format
|
||||
}
|
||||
|
||||
export default {
|
||||
/**
|
||||
* @desc 判断对象是否为空
|
||||
* @param {Object} o 对象
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isEmptyObject(o = {}) {
|
||||
let flag = true
|
||||
for (let k in o) {
|
||||
if (k) {
|
||||
flag = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return flag
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 去除前后空格
|
||||
* @param {String} 值
|
||||
* @return {String}
|
||||
*/
|
||||
trim(val) {
|
||||
return val.replace(/(^\s*)|(\s*$)/g, '')
|
||||
},
|
||||
|
||||
// 获取query特定参数
|
||||
getQueryParameter() {
|
||||
let activityFromApp = this.getQuery().activityFromApp
|
||||
let appUserToken = this.getQuery().appUserToken
|
||||
let env = this.getQuery().env
|
||||
let query = {}
|
||||
if (activityFromApp) {
|
||||
query.activityFromApp = activityFromApp
|
||||
}
|
||||
if (appUserToken) {
|
||||
query.appUserToken = decodeURIComponent(appUserToken.replace(/%20/g, '+'))
|
||||
}
|
||||
if (env) {
|
||||
query.env = env
|
||||
}
|
||||
return query
|
||||
},
|
||||
|
||||
/**
|
||||
z * @param {String} str 目标字符串
|
||||
* @param {String} char 字符
|
||||
* @param {Number} start 数组开始索引
|
||||
* @param {Number} end 数组结束索引
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
replaceChar(str = '', char = '*', start = 0, end) {
|
||||
let list = []
|
||||
if (str) {
|
||||
list = str.split('')
|
||||
let len = list.length
|
||||
start = start > 0 ? (start <= len ? start : len) : 0
|
||||
end = end ? (end > start ? end : start) : len
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (i >= start && i < end) {
|
||||
list[i] = char
|
||||
}
|
||||
}
|
||||
}
|
||||
return list.join('')
|
||||
},
|
||||
|
||||
addSpace(value, num = 4) {
|
||||
if (value) {
|
||||
return value.replace(/\s/g, '').replace(/(.{4})/g, '$1 ')
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
// 字符省略
|
||||
ellipsis(value = '', num = -1) {
|
||||
if (value) {
|
||||
let str = ''
|
||||
if (num > 0 && value.length > num) {
|
||||
str = '...'
|
||||
}
|
||||
return value.slice(0, num) + str
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 获取 cookie
|
||||
* @param {String}
|
||||
* @return {*}
|
||||
*/
|
||||
getCookie(name) {
|
||||
let rs = ''
|
||||
var name = name + '='
|
||||
var ca = document.cookie.split(';')
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i]
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1)
|
||||
}
|
||||
if (c.indexOf(name) != -1) {
|
||||
rs = this._string2json(c.substring(name.length, c.length))
|
||||
}
|
||||
}
|
||||
return rs
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 设置 cookie
|
||||
* @param {String} name 名称
|
||||
* @param {*} value 值
|
||||
* @param {Number} hours 时长
|
||||
*/
|
||||
setCookie(name, value, hours) {
|
||||
let str = name + '=' + this._json2string(value)
|
||||
if (hours && hours > 0) {
|
||||
var date = new Date()
|
||||
date.setTime(date.getTime() + hours * 3600 * 1000)
|
||||
str += '; expires=' + date.toUTCString()
|
||||
}
|
||||
document.cookie = str
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 清除 cookie
|
||||
* @param {String} 名称
|
||||
*/
|
||||
delCookie(name) {
|
||||
var date = new Date()
|
||||
date.setTime(date.getTime() - 10000)
|
||||
document.cookie = name + '=a; expires=' + date.toGMTString()
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 获取 localStorage 中指定的变量
|
||||
* @param {String} name 名称
|
||||
* @return {*} rs
|
||||
*/
|
||||
getStorage(name) {
|
||||
return this._string2json(window.sessionStorage[name])
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 设置或添加 localStorage 中指定的变量
|
||||
* @param {String} name 名称
|
||||
*/
|
||||
setStorage(name, value) {
|
||||
window.sessionStorage[name] = this._json2string(value)
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 删除 localStorage 中指定的变量
|
||||
* @param {String} name 名称
|
||||
*/
|
||||
delStorage(name) {
|
||||
window.sessionStorage.removeItem(name)
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc json转string
|
||||
* @param {*} value 值
|
||||
* @return {*} value 值
|
||||
*/
|
||||
_json2string(value) {
|
||||
return JSON.stringify(value)
|
||||
},
|
||||
/**
|
||||
* 获取设备类型
|
||||
*/
|
||||
device() {
|
||||
let ua = navigator.userAgent
|
||||
return {
|
||||
isChrome: ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/),
|
||||
isAndroid: ua.match(/(Android);?[\s\/]+([\d.]+)?/),
|
||||
isIphone: ua.indexOf('iPhone') != -1,
|
||||
isWeixin: ua.match(/MicroMessenger/i)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 设置title
|
||||
*/
|
||||
setTitle(title) {
|
||||
let device = this.device()
|
||||
if (device.isIphone && device.isWeixin) {
|
||||
document.title = title
|
||||
var i = document.createElement('iframe')
|
||||
i.src = '/favicon.ico'
|
||||
i.style.display = 'none'
|
||||
i.onload = function() {
|
||||
setTimeout(function() {
|
||||
i.remove()
|
||||
}, 9)
|
||||
}
|
||||
document.body.appendChild(i)
|
||||
} else {
|
||||
document.title = title
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @desc string转json
|
||||
* @param {*} value 值
|
||||
* @return {*} value 值
|
||||
*/
|
||||
_string2json(value) {
|
||||
try {
|
||||
value = JSON.parse(value)
|
||||
} catch (e) {}
|
||||
return value
|
||||
},
|
||||
/**
|
||||
*@desc 只能输入单词字符
|
||||
*@param { String } value
|
||||
*/
|
||||
character(value) {
|
||||
if (value) {
|
||||
value = value.replace(/[^A-Za-z0-9]/g, '')
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
m2km(value) {
|
||||
if (value < 1000) return value + 'm'
|
||||
else if (value >= 1000 && value <= 20000) return (value / 1000).toFixed(1) + 'km'
|
||||
else if (value >= 2000) return '>20km'
|
||||
return value
|
||||
},
|
||||
|
||||
/**
|
||||
* 除法
|
||||
* @param {Number} dividend 被除数
|
||||
* @param {Number} divisor 除数
|
||||
* @return {Number} 值
|
||||
*/
|
||||
divide(dividend, divisor = 100) {
|
||||
if (dividend && divisor) {
|
||||
dividend = Number(dividend)
|
||||
return this.toFloatFixed(dividend / divisor)
|
||||
}
|
||||
return dividend
|
||||
},
|
||||
|
||||
// 保留小数位,替代Number.toFixed()方法,针对于某些数据(16.455)不能做到四舍五入
|
||||
toFixed(value, num = 0) {
|
||||
let pos = value.toString().indexOf('.')
|
||||
let decimalPlaces = value.toString().length - pos - 1
|
||||
let intValue = value * Math.pow(10, decimalPlaces)
|
||||
let divisor1 = Math.pow(10, decimalPlaces - num)
|
||||
let divisor2 = Math.pow(10, num)
|
||||
return Math.round(intValue / divisor1) / divisor2
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取App信息
|
||||
*/
|
||||
detectApp() {
|
||||
var ua = navigator.userAgent
|
||||
//RegExp.$1; RegExp.$2; RegExp.$3;
|
||||
//var info = ua.match(/(CarmeApp)\s*[v]*(\d+\.\d+\.\d+)\s*\/\s*(IOS|Android)/i)
|
||||
ua.match(/(CarmeApp)\s*[v]*(\d+\.\d+\.\d+)\s*\/\s*(IOS|Android)/i)
|
||||
return {
|
||||
appName: RegExp.$1,
|
||||
appVersion: RegExp.$2,
|
||||
appOS: RegExp.$3
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 如果是小数则保留小数位,默认两位
|
||||
* @param {[type]} value [description]
|
||||
* @param {Number} num [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
toFloatFixed(value, num = 2) {
|
||||
let values = Number(value)
|
||||
if (values) {
|
||||
if (/^\d+\.\d+/.test(values)) {
|
||||
return this.toFixed(values, num)
|
||||
} else {
|
||||
return this.toFixed(values)
|
||||
}
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
// 获取周
|
||||
getWeek(str) {
|
||||
let rs = ''
|
||||
switch (str + '') {
|
||||
case '1':
|
||||
rs = '一'
|
||||
break
|
||||
case '2':
|
||||
rs = '二'
|
||||
break
|
||||
case '3':
|
||||
rs = '三'
|
||||
break
|
||||
case '4':
|
||||
rs = '四'
|
||||
break
|
||||
case '5':
|
||||
rs = '五'
|
||||
break
|
||||
case '6':
|
||||
rs = '六'
|
||||
break
|
||||
case '7':
|
||||
case '0':
|
||||
rs = '日'
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
return rs
|
||||
},
|
||||
|
||||
// 获取补全的时间
|
||||
getTime(str) {
|
||||
if (str < 10) {
|
||||
return '0' + str
|
||||
}
|
||||
return str
|
||||
},
|
||||
|
||||
// 数组去重
|
||||
unrepeat(arr) {
|
||||
if (arr instanceof Array) {
|
||||
let hash = {}
|
||||
let rsArr = []
|
||||
let len = arr.length
|
||||
let type = ''
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (typeof arr[i] == 'string') {
|
||||
type = 'string'
|
||||
}
|
||||
if (!hash[arr[i]]) {
|
||||
hash[arr[i]] = arr[i]
|
||||
rsArr.push(arr[i])
|
||||
}
|
||||
}
|
||||
return rsArr
|
||||
}
|
||||
},
|
||||
// 一层对象数组去重
|
||||
unrepeatObj(arr, key) {
|
||||
if (arr instanceof Array) {
|
||||
let hash = {}
|
||||
let rsArr = []
|
||||
let len = arr.length
|
||||
let type = ''
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (typeof arr[i] == 'string') {
|
||||
type = 'string'
|
||||
}
|
||||
if (!hash[arr[i][key]]) {
|
||||
hash[arr[i][key]] = arr[i]
|
||||
rsArr.push(arr[i])
|
||||
}
|
||||
}
|
||||
return rsArr
|
||||
}
|
||||
},
|
||||
/**
|
||||
@desc:只能输入整数
|
||||
@param
|
||||
value 操作数值
|
||||
max 最大值
|
||||
**/
|
||||
intOnly(value, max = Infinity, min = 0) {
|
||||
if (value) {
|
||||
let regular0 = /^0{1,}$/
|
||||
if (regular0.test(value)) {
|
||||
// 如果输入1个0以上,去除掉
|
||||
value = value.replace(/^0{1,}$/, '')
|
||||
}
|
||||
if (/[^0-9]*$/.test(value)) {
|
||||
value = value.replace(/\D/g, '')
|
||||
} else {
|
||||
if (value > max) value = value.substr(0, value.length - 1)
|
||||
if (value < min) value = min
|
||||
}
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
//解析url参数
|
||||
getQuery() {
|
||||
var query = []
|
||||
// 当url是通过传参过来的话,我们把第一个参数作为url并进行解析
|
||||
if (arguments[0]) {
|
||||
let lnk = document.createElement('a')
|
||||
lnk.href = arguments[0]
|
||||
query = this.extractQuery(lnk)
|
||||
} else {
|
||||
/*
|
||||
var query = window.location.search.split('?');
|
||||
if(query.length <= 1) query = window.location.hash.split('#');
|
||||
query = query.length > 1 ? query[1].split('&') : []
|
||||
*/
|
||||
query = this.extractQuery(window.location)
|
||||
}
|
||||
|
||||
var json = {}
|
||||
for (var i = 0, len = query.length; i < len; i++) {
|
||||
var key = query[i].split('=')[0],
|
||||
index = query[i].indexOf('='),
|
||||
value = query[i].substr(index + 1)
|
||||
json[key] = value
|
||||
}
|
||||
|
||||
return json
|
||||
},
|
||||
extractQuery(lnk) {
|
||||
var query = lnk.search.split('?')
|
||||
//url/#/repairBooking?activityFromApp=1
|
||||
if (query.length <= 1) query = lnk.hash.split('?')
|
||||
query = query.length > 1 ? query[1].split('&') : []
|
||||
|
||||
return query
|
||||
}
|
||||
}
|
||||
273
src/assets/js/common.js
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* @desc 扩展对象继承
|
||||
* @param {Object} out 一个或多个对象
|
||||
* @return {Object} 对象
|
||||
*/
|
||||
Object.extend = function(out) {
|
||||
out = out || {}
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
if (!arguments[i]) continue
|
||||
|
||||
for (var key in arguments[i]) {
|
||||
if (arguments[i].hasOwnProperty(key)) out[key] = arguments[i][key]
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
export default {
|
||||
/**
|
||||
* @desc 判断对象是否为空
|
||||
* @param {Object} o 对象
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isEmptyObject(o = {}) {
|
||||
let flag = true
|
||||
for (const k in o) {
|
||||
if (k) {
|
||||
flag = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return flag
|
||||
},
|
||||
|
||||
/**
|
||||
* @description 去除前后空格
|
||||
* @param {String} 值
|
||||
* @return {String}
|
||||
*/
|
||||
trim(val) {
|
||||
return val.replace(/(^\s*)|(\s*$)/g, '')
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 获取 cookie
|
||||
* @param {String}
|
||||
* @return {*}
|
||||
*/
|
||||
getCookie(name1) {
|
||||
let rs = ''
|
||||
var name = name1 + '='
|
||||
var ca = document.cookie.split(';')
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i]
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1)
|
||||
}
|
||||
if (c.indexOf(name) != -1) {
|
||||
rs = this._string2json(c.substring(name.length, c.length))
|
||||
}
|
||||
}
|
||||
return rs
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 设置 cookie
|
||||
* @param {String} name 名称
|
||||
* @param {*} value 值
|
||||
* @param {Number} hours 时长
|
||||
*/
|
||||
setCookie(name, value, hours) {
|
||||
let str = name + '=' + this._json2string(value)
|
||||
if (hours && hours > 0) {
|
||||
var date = new Date()
|
||||
date.setTime(date.getTime() + hours * 3600 * 1000)
|
||||
str += '; expires=' + date.toUTCString()
|
||||
}
|
||||
document.cookie = str
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 清除 cookie
|
||||
* @param {String} 名称
|
||||
*/
|
||||
delCookie(name) {
|
||||
var date = new Date()
|
||||
date.setTime(date.getTime() - 10000)
|
||||
document.cookie = name + '=a; expires=' + date.toGMTString()
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 获取 localStorage 中指定的变量
|
||||
* @param {String} name 名称
|
||||
* @return {*} rs
|
||||
*/
|
||||
getStorage(name) {
|
||||
return this._string2json(window.sessionStorage[name])
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 设置或添加 localStorage 中指定的变量
|
||||
* @param {String} name 名称
|
||||
*/
|
||||
setStorage(name, value) {
|
||||
window.sessionStorage[name] = this._json2string(value)
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc 删除 localStorage 中指定的变量
|
||||
* @param {String} name 名称
|
||||
*/
|
||||
delStorage(name) {
|
||||
window.sessionStorage.removeItem(name)
|
||||
},
|
||||
|
||||
/**
|
||||
* @desc json转string
|
||||
* @param {*} value 值
|
||||
* @return {*} value 值
|
||||
*/
|
||||
_json2string(value) {
|
||||
return JSON.stringify(value)
|
||||
},
|
||||
/**
|
||||
* @desc string转json
|
||||
* @param {*} value 值
|
||||
* @return {*} value 值
|
||||
*/
|
||||
_string2json(value) {
|
||||
try {
|
||||
value = JSON.parse(value)
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
return value
|
||||
},
|
||||
/**
|
||||
*@desc 只能输入单词字符
|
||||
*@param { String } value
|
||||
*/
|
||||
character(value) {
|
||||
if (value) {
|
||||
value = value.replace(/[^A-Za-z0-9]/g, '')
|
||||
}
|
||||
return value
|
||||
},
|
||||
// 保留小数位,替代Number.toFixed()方法,针对于某些数据(16.455)不能做到四舍五入
|
||||
toFixed(value, num = 0) {
|
||||
const pos = value.toString().indexOf('.')
|
||||
const decimalPlaces = value.toString().length - pos - 1
|
||||
const intValue = value * Math.pow(10, decimalPlaces)
|
||||
const divisor1 = Math.pow(10, decimalPlaces - num)
|
||||
const divisor2 = Math.pow(10, num)
|
||||
return Math.round(intValue / divisor1) / divisor2
|
||||
},
|
||||
|
||||
/**
|
||||
* 如果是小数则保留小数位,默认两位
|
||||
* @param {[type]} value [description]
|
||||
* @param {Number} num [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
toFloatFixed(value, num = 2) {
|
||||
const values = Number(value)
|
||||
if (values) {
|
||||
if (/^\d+\.\d+/.test(values)) {
|
||||
return this.toFixed(values, num)
|
||||
} else {
|
||||
return this.toFixed(values)
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the time to string
|
||||
* @param {(Object|string|number)} time
|
||||
* @param {string} cFormat
|
||||
* @returns {string}
|
||||
*/
|
||||
export function parseTime(time, cFormat) {
|
||||
if (arguments.length === 0) {
|
||||
return null
|
||||
}
|
||||
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
|
||||
let date
|
||||
if (typeof time === 'object') {
|
||||
date = time
|
||||
} else {
|
||||
if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
|
||||
time = parseInt(time)
|
||||
}
|
||||
if (typeof time === 'number' && time.toString().length === 10) {
|
||||
time = time * 1000
|
||||
}
|
||||
date = new Date(time)
|
||||
}
|
||||
const formatObj = {
|
||||
y: date.getFullYear(),
|
||||
m: date.getMonth() + 1,
|
||||
d: date.getDate(),
|
||||
h: date.getHours(),
|
||||
i: date.getMinutes(),
|
||||
s: date.getSeconds(),
|
||||
a: date.getDay()
|
||||
}
|
||||
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
|
||||
let value = formatObj[key]
|
||||
// Note: getDay() returns 0 on Sunday
|
||||
if (key === 'a') {
|
||||
return ['日', '一', '二', '三', '四', '五', '六'][value]
|
||||
}
|
||||
if (result.length > 0 && value < 10) {
|
||||
value = '0' + value
|
||||
}
|
||||
return value || 0
|
||||
})
|
||||
return time_str
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} time
|
||||
* @param {string} option
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatTime(time, option) {
|
||||
if (('' + time).length === 10) {
|
||||
time = parseInt(time) * 1000
|
||||
} else {
|
||||
time = +time
|
||||
}
|
||||
const d = new Date(time)
|
||||
const now = Date.now()
|
||||
|
||||
const diff = (now - d) / 1000
|
||||
|
||||
if (diff < 30) {
|
||||
return '刚刚'
|
||||
} else if (diff < 3600) {
|
||||
// less 1 hour
|
||||
return Math.ceil(diff / 60) + '分钟前'
|
||||
} else if (diff < 3600 * 24) {
|
||||
return Math.ceil(diff / 3600) + '小时前'
|
||||
} else if (diff < 3600 * 24 * 2) {
|
||||
return '1天前'
|
||||
}
|
||||
if (option) {
|
||||
return parseTime(time, option)
|
||||
} else {
|
||||
return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} url
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function param2Obj(url) {
|
||||
const search = url.split('?')[1]
|
||||
if (!search) {
|
||||
return {}
|
||||
}
|
||||
return JSON.parse(
|
||||
'{"' +
|
||||
decodeURIComponent(search)
|
||||
.replace(/"/g, '\\"')
|
||||
.replace(/&/g, '","')
|
||||
.replace(/=/g, '":"')
|
||||
.replace(/\+/g, ' ') +
|
||||
'"}'
|
||||
)
|
||||
}
|
||||
32
src/assets/js/generatedFormat/index.js
Normal file
@@ -0,0 +1,32 @@
|
||||
export default {
|
||||
formatLabelFun: (value, dir) => {
|
||||
let arr = eval(`${dir}DataMaps`)
|
||||
let filterData = arr.filter(item => item.value == value)[0]
|
||||
if (filterData) {
|
||||
return filterData.label
|
||||
} else {
|
||||
return value
|
||||
}
|
||||
},
|
||||
|
||||
formatList: (dir) => {
|
||||
let maps = {}
|
||||
return maps[dir];
|
||||
},
|
||||
|
||||
// formatOptionsFun 固定生成
|
||||
// 用于转换list 增加自己想要的字段
|
||||
formatOptionsFun: function (array = [{label: 'name', formatLabel: 'label'}], data) {
|
||||
return data.map(item => {
|
||||
array.map(format => {
|
||||
if (item[format.label]) {
|
||||
item[format.formatLabel ? format.formatLabel : 'label'] = item[format.label]
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
item.children = this.formatOptionsFun(array, item.children)
|
||||
}
|
||||
})
|
||||
return item
|
||||
})
|
||||
}
|
||||
}
|
||||
15
src/assets/js/utils/auth.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import Common from '@/assets/js/common'
|
||||
|
||||
const TokenKey = 'token'
|
||||
|
||||
export function getToken() {
|
||||
return Common.getStorage(TokenKey)
|
||||
}
|
||||
|
||||
export function setToken(token) {
|
||||
return Common.setStorage(TokenKey, token)
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
return Common.delStorage(TokenKey)
|
||||
}
|
||||
52
src/assets/js/utils/encrypt.js
Normal file
@@ -0,0 +1,52 @@
|
||||
//encrypt.js
|
||||
/**
|
||||
* 通过crypto-js实现 加解密工具
|
||||
* AES
|
||||
* @author: wmz
|
||||
*/
|
||||
import CryptoJS from 'crypto-js'
|
||||
const KP = {
|
||||
key: 'AJDBW8D2zdDq3b5U', // 秘钥 16*n:
|
||||
iv: '' // 偏移量
|
||||
}
|
||||
function getAesString(data, key, iv) {
|
||||
// 加密
|
||||
key = CryptoJS.enc.Utf8.parse(key)
|
||||
iv = CryptoJS.enc.Utf8.parse(iv)
|
||||
let encrypted = CryptoJS.AES.encrypt(data, key, {
|
||||
// iv: iv,
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
})
|
||||
return encrypted.toString() // 返回的是base64格式的密文
|
||||
}
|
||||
function getDAesString(encrypted, key, iv) {
|
||||
// 解密
|
||||
key = CryptoJS.enc.Utf8.parse(key)
|
||||
iv = CryptoJS.enc.Utf8.parse(iv)
|
||||
let decrypted = CryptoJS.AES.decrypt(encrypted, key, {
|
||||
// iv: iv,
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
})
|
||||
return decrypted.toString(CryptoJS.enc.Utf8) //
|
||||
}
|
||||
// AES 对称秘钥加密
|
||||
const aes = {
|
||||
en: data => getAesString(data, KP.key, KP.iv),
|
||||
de: data => getDAesString(data, KP.key, KP.iv)
|
||||
}
|
||||
// BASE64
|
||||
const base64 = {
|
||||
en: data => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)),
|
||||
de: data => CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8)
|
||||
}
|
||||
// SHA256
|
||||
const sha256 = data => {
|
||||
return CryptoJS.SHA256(data).toString()
|
||||
}
|
||||
// MD5
|
||||
const md5 = data => {
|
||||
return CryptoJS.MD5(data).toString()
|
||||
}
|
||||
export { aes, md5, sha256, base64 }
|
||||
10
src/assets/js/utils/get-page-title.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import defaultSettings from '@/assets/js/utils/settings'
|
||||
|
||||
const title = defaultSettings.title || 'Vue Admin Template'
|
||||
|
||||
export default function getPageTitle(pageTitle) {
|
||||
if (pageTitle) {
|
||||
return `${pageTitle} - ${title}`
|
||||
}
|
||||
return `${title}`
|
||||
}
|
||||
9
src/assets/js/utils/get-url.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import config from '@/config'
|
||||
import urlMap from '@/config/urlMap'
|
||||
|
||||
export default function getUrl(url, domainType = 'admin') {
|
||||
let domain = ''
|
||||
if (domainType === 'admin') {
|
||||
domain = config.admin
|
||||
} return domain + url
|
||||
}
|
||||
32
src/assets/js/utils/permission.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
import NProgress from 'nprogress' // progress bar
|
||||
import 'nprogress/nprogress.css' // progress bar style
|
||||
import { getToken } from '@/assets/js/utils/auth' // get token from cookie
|
||||
import getPageTitle from '@/assets/js/utils/get-page-title'
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
const whiteList = ['/authentication', '/home', '/404'] // no redirect whitelist
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
sessionStorage.setItem('token', 'MockToken')
|
||||
document.title = getPageTitle(to.meta.title)
|
||||
const hasToken = getToken()
|
||||
if (hasToken) {
|
||||
next()
|
||||
} else {
|
||||
if (to.path.indexOf('/home') !== -1) {
|
||||
next(`/authentication?redirect=${to.path}`)
|
||||
} else {
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
next()
|
||||
} else {
|
||||
next()
|
||||
NProgress.done()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
router.afterEach(() => {
|
||||
// finish progress bar
|
||||
NProgress.done()
|
||||
})
|
||||
102
src/assets/js/utils/request.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import axios from 'axios'
|
||||
import { MessageBox, Message, Loading } from 'element-ui'
|
||||
import store from '@/store'
|
||||
import { getToken } from '@/assets/js/utils/auth'
|
||||
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
baseURL: '', // url = base url + request url
|
||||
timeout: 600000 // request timeout
|
||||
})
|
||||
|
||||
let loading
|
||||
function startLoading() {
|
||||
//使用Element loading-start 方法
|
||||
loading = Loading.service({
|
||||
target: '.main-container'
|
||||
})
|
||||
}
|
||||
function endLoading() {
|
||||
//使用Element loading-close 方法
|
||||
loading.close()
|
||||
}
|
||||
|
||||
// request interceptor
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
if (store.getters.token) {
|
||||
// config.headers['sid'] = getToken()
|
||||
config.headers['sysType'] = '3'
|
||||
config.headers['auth'] = getToken()
|
||||
}
|
||||
if (loading) {
|
||||
endLoading()
|
||||
}
|
||||
//linkage 接口
|
||||
// config.type 可以从api的接口地址定义 可以不触发loading
|
||||
if (config.type != false) {
|
||||
startLoading()
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
// response interceptor
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
const res = response.data
|
||||
endLoading()
|
||||
if (response.request.responseType == 'blob' || response.request.responseType == 'Blob') {
|
||||
return response.data
|
||||
}
|
||||
if (res.content.code != '0' && res.content.result != 0) {
|
||||
//500毫秒延迟 显得过度平滑
|
||||
// token过期或失效 根据项目设置其code
|
||||
if (response.headers['content-type'] != 'application/x-zip-compressed') {
|
||||
if (res.content.code === '4001' || res.content.code === '4002') {
|
||||
MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确认退出', {
|
||||
confirmButtonText: '重新登录',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
store.dispatch('user/resetToken').then(() => {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
Message({
|
||||
message: res.content.message || 'Error',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (res.content.code == '1' || res.content.code == '') {
|
||||
Message({
|
||||
message: res.content.resultMessage ? res.content.resultMessage : res.content.message ? res.content.message : '接口错误',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return false
|
||||
} else {
|
||||
res.content.result = '0'
|
||||
res.result = String(res.result?res.result:0)
|
||||
res.code = String(res.code ? res.code: 0 )
|
||||
return res
|
||||
}
|
||||
}
|
||||
},
|
||||
error => {
|
||||
Message({
|
||||
message: error.message,
|
||||
type: 'error',
|
||||
duration: 5 * 500
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default service
|
||||
50
src/assets/js/utils/settings.js
Normal file
@@ -0,0 +1,50 @@
|
||||
module.exports = {
|
||||
/**
|
||||
* @description 网站标题
|
||||
*/
|
||||
title: '基础生成工程',
|
||||
/**
|
||||
* @description 是否显示 tagsView
|
||||
*/
|
||||
tagsView: true,
|
||||
/**
|
||||
* @description 固定头部
|
||||
*/
|
||||
fixedHeader: true,
|
||||
/**
|
||||
* @description 记住密码状态下的token在Cookie中存储的天数,默认1天
|
||||
*/
|
||||
tokenCookieExpires: 1,
|
||||
/**
|
||||
* @description 记住密码状态下的密码在Cookie中存储的天数,默认1天s
|
||||
*/
|
||||
passCookieExpires: 1,
|
||||
/**
|
||||
* @description 是否只保持一个子菜单的展开
|
||||
*/
|
||||
uniqueOpened: true,
|
||||
/**
|
||||
* @description token key
|
||||
*/
|
||||
TokenKey: 'EL-ADMIN-TOEKN',
|
||||
/**
|
||||
* @description 请求超时时间,毫秒(默认2分钟)
|
||||
*/
|
||||
timeout: 1200000,
|
||||
/**
|
||||
* @description 是否显示logo
|
||||
*/
|
||||
sidebarLogo: true,
|
||||
/**
|
||||
* 是否显示设置的底部信息
|
||||
*/
|
||||
showFooter: true,
|
||||
/**
|
||||
* 底部文字,支持html语法
|
||||
*/
|
||||
footerTxt: '© 2020 IO',
|
||||
/**
|
||||
* 备案号
|
||||
*/
|
||||
caseNumber: ''
|
||||
}
|
||||
20
src/assets/js/utils/validate.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Created by PanJiaChen on 16/11/18.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function isExternal(path) {
|
||||
return /^(https?:|mailto:|tel:)/.test(path)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
export function validUsername(str) {
|
||||
const valid_map = ['admin', 'editor']
|
||||
return valid_map.indexOf(str.trim()) >= 0
|
||||
}
|
||||
2943
src/assets/sass/common.css
Normal file
2258
src/assets/sass/common.min.css
vendored
Normal file
76
src/assets/sass/common.scss
Normal file
@@ -0,0 +1,76 @@
|
||||
@import './variables.scss';
|
||||
@import './mixin.scss';
|
||||
@import './utils.scss';
|
||||
@import './transition.scss';
|
||||
@import './element-ui.scss';
|
||||
@import './sidebar.scss';
|
||||
@import './public.scss';
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
min-width: 1024px;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a,
|
||||
a:focus,
|
||||
a:hover {
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a:focus,
|
||||
a:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a,
|
||||
a:focus,
|
||||
a:hover {
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
// 宽度设置
|
||||
@include set-width($width-list);
|
||||
// 宽度设置
|
||||
@include set-height($width-list);
|
||||
// 间距设置
|
||||
@include set-distance($distance-class-list, $distance-list);
|
||||
//圆角弧度设置
|
||||
@include set-radius($radius);
|
||||
//透明度设置
|
||||
@include set-opacity($opacity);
|
||||
31
src/assets/sass/element-ui.scss
Normal file
@@ -0,0 +1,31 @@
|
||||
// cover some element-ui styles
|
||||
|
||||
.el-breadcrumb__inner,
|
||||
.el-breadcrumb__inner a {
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
.el-upload {
|
||||
input[type="file"] {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
// refine element ui upload
|
||||
.upload-container {
|
||||
.el-upload {
|
||||
width: 100%;
|
||||
|
||||
.el-upload-dragger {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dropdown
|
||||
.el-dropdown-menu {
|
||||
a {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
210
src/assets/sass/mixin.scss
Normal file
@@ -0,0 +1,210 @@
|
||||
@mixin clearfix {
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin scrollBar {
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background: #d3dce6;
|
||||
}
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #99a9bf;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin relative {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// 设置宽度
|
||||
@mixin set-width($width-list) {
|
||||
@each $size in $width-list {
|
||||
.w#{$size} {
|
||||
width: #{$size}px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置高度
|
||||
@mixin set-height($width-list) {
|
||||
@each $size in $width-list {
|
||||
.h#{$size} {
|
||||
height: #{$size}px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置圆角弧度
|
||||
@mixin set-radius($radius) {
|
||||
@each $size in $radius {
|
||||
.radius#{$size} {
|
||||
border-radius: #{$size}px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置透明度
|
||||
@mixin set-opacity($opacity) {
|
||||
@each $size in $opacity {
|
||||
.opacity#{$size*10} {
|
||||
opacity: #{$size} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 外边距
|
||||
@mixin margin($size) {
|
||||
margin: $size !important;
|
||||
}
|
||||
|
||||
@mixin margin-vertical($size) {
|
||||
margin-top: $size !important;
|
||||
margin-bottom: $size !important;
|
||||
}
|
||||
|
||||
@mixin margin-horizontal($size) {
|
||||
margin-left: $size !important;
|
||||
margin-right: $size !important;
|
||||
}
|
||||
|
||||
@mixin margin-top($size) {
|
||||
margin-top: $size !important;
|
||||
}
|
||||
|
||||
@mixin margin-left($size) {
|
||||
margin-left: $size !important;
|
||||
}
|
||||
|
||||
@mixin margin-bottom($size) {
|
||||
margin-bottom: $size !important;
|
||||
}
|
||||
|
||||
@mixin margin-right($size) {
|
||||
margin-right: $size !important;
|
||||
}
|
||||
|
||||
// 内边距
|
||||
@mixin padding($size) {
|
||||
padding: $size !important;
|
||||
}
|
||||
|
||||
@mixin padding-vertical($size) {
|
||||
padding-top: $size !important;
|
||||
padding-bottom: $size !important;
|
||||
}
|
||||
|
||||
@mixin padding-horizontal($size) {
|
||||
padding-left: $size !important;
|
||||
padding-right: $size !important;
|
||||
}
|
||||
|
||||
@mixin padding-top($size) {
|
||||
padding-top: $size !important;
|
||||
}
|
||||
|
||||
@mixin padding-left($size) {
|
||||
padding-left: $size !important;
|
||||
}
|
||||
@mixin padding-bottom($size) {
|
||||
padding-bottom: $size !important;
|
||||
}
|
||||
|
||||
@mixin padding-right($size) {
|
||||
padding-right: $size !important;
|
||||
}
|
||||
|
||||
@mixin top($size) {
|
||||
top: $size !important;
|
||||
}
|
||||
|
||||
@mixin left($size) {
|
||||
left: $size !important;
|
||||
}
|
||||
|
||||
@mixin right($size) {
|
||||
right: $size !important;
|
||||
}
|
||||
|
||||
@mixin bottom($size) {
|
||||
bottom: $size !important;
|
||||
}
|
||||
|
||||
// 设置内外边距
|
||||
@mixin set-distance($distance-class-list, $distance-list) {
|
||||
@each $class-name in $distance-class-list {
|
||||
@each $size in $distance-list {
|
||||
.#{$class-name}#{$size} {
|
||||
@if $class-name == m {
|
||||
@include margin(#{$size}px);
|
||||
}
|
||||
@if $class-name == mv {
|
||||
@include margin-vertical(#{$size}px);
|
||||
}
|
||||
@if $class-name == mh {
|
||||
@include margin-horizontal(#{$size}px);
|
||||
}
|
||||
@if $class-name == mt {
|
||||
@include margin-top(#{$size}px);
|
||||
}
|
||||
@if $class-name == ml {
|
||||
@include margin-left(#{$size}px);
|
||||
}
|
||||
@if $class-name == mr {
|
||||
@include margin-right(#{$size}px);
|
||||
}
|
||||
@if $class-name == mb {
|
||||
@include margin-bottom(#{$size}px);
|
||||
}
|
||||
@if $class-name == p {
|
||||
@include padding(#{$size}px);
|
||||
}
|
||||
@if $class-name == pv {
|
||||
@include padding-vertical(#{$size}px);
|
||||
}
|
||||
@if $class-name == ph {
|
||||
@include padding-horizontal(#{$size}px);
|
||||
}
|
||||
@if $class-name == pt {
|
||||
@include padding-top(#{$size}px);
|
||||
}
|
||||
@if $class-name == pl {
|
||||
@include padding-left(#{$size}px);
|
||||
}
|
||||
@if $class-name == pr {
|
||||
@include padding-right(#{$size}px);
|
||||
}
|
||||
@if $class-name == pb {
|
||||
@include padding-bottom(#{$size}px);
|
||||
}
|
||||
@if $class-name == top {
|
||||
@include top(#{$size}px);
|
||||
}
|
||||
@if $class-name == left {
|
||||
@include left(#{$size}px);
|
||||
}
|
||||
@if $class-name == right {
|
||||
@include right(#{$size}px);
|
||||
}
|
||||
@if $class-name == bottom {
|
||||
@include bottom(#{$size}px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//单行省略
|
||||
@mixin text-overflow() {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
236
src/assets/sass/public.scss
Normal file
@@ -0,0 +1,236 @@
|
||||
.el-input__suffix {
|
||||
height: unset;
|
||||
}
|
||||
.el-collapse {
|
||||
border: none;
|
||||
}
|
||||
|
||||
[class*='el-col-'] {
|
||||
min-height: 1px;
|
||||
}
|
||||
#RenderTable-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#RenderTable-container,
|
||||
.el-table {
|
||||
.el-button--mini {
|
||||
padding: 5px;
|
||||
color: #409eff;
|
||||
border-color: transparent !important;
|
||||
background: transparent !important;
|
||||
//padding-left: 0;
|
||||
//padding-right: 0;
|
||||
}
|
||||
.el-button--danger.el-button--mini {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.el-button--primary.el-button--mini:focus,
|
||||
.el-button--primary.el-button--mini:hover {
|
||||
color: #b3d8ff;
|
||||
}
|
||||
.el-button--danger.el-button--mini:focus,
|
||||
.el-button--danger.el-button--mini:hover {
|
||||
color: #fbc4c4;
|
||||
}
|
||||
.el-button--primary.el-button--mini.is-disabled,
|
||||
.el-button--primary.el-button--mini.is-disabled:active,
|
||||
.el-button--primary.el-button--mini.is-disabled:focus,
|
||||
.el-button--primary.el-button--mini.is-disabled:hover {
|
||||
color: #ccc;
|
||||
}
|
||||
.el-button--danger.el-button--mini.is-disabled,
|
||||
.el-button--danger.el-button--mini.is-disabled:active,
|
||||
.el-button--danger.el-button--mini.is-disabled:focus,
|
||||
.el-button--danger.el-button--mini.is-disabled:hover {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.el-button--medium {
|
||||
padding: 8px 15px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
.el-button--danger {
|
||||
//color:#F56C6C!important;
|
||||
}
|
||||
.el-upload__input {
|
||||
display: none;
|
||||
}
|
||||
.el-dialog {
|
||||
//.el-input{
|
||||
// width: 100%!important;
|
||||
// max-width: 100%;
|
||||
//}
|
||||
}
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: white;
|
||||
padding: 15px 30px;
|
||||
z-index: 10;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
.flex {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
button {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.is-fullscreen {
|
||||
.el-dialog__header {
|
||||
//padding: unset;
|
||||
}
|
||||
.el-dialog__body {
|
||||
padding: unset;
|
||||
width: 95vw;
|
||||
margin: auto;
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.el-dialog__body {
|
||||
padding: 30px 15px;
|
||||
width: 96%;
|
||||
margin: auto;
|
||||
max-height: 55vh;
|
||||
overflow: auto;
|
||||
}
|
||||
.el-dialog__footer {
|
||||
text-align: right;
|
||||
}
|
||||
.el-dialog__header {
|
||||
font-weight: 600;
|
||||
.el-dialog__title {
|
||||
font-size: 20px;
|
||||
color: #0096fd;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-collapse-item__header.is-active {
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
// to fixed https://github.com/ElemeFE/element/issues/2461
|
||||
.el-dialog {
|
||||
border-radius: 10px;
|
||||
transform: none;
|
||||
left: 0;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.table-container {
|
||||
padding-top: 15px;
|
||||
}
|
||||
.container-title {
|
||||
height: 30px;
|
||||
//border-bottom: 2px solid #0096FD;
|
||||
//margin-bottom: 20px;
|
||||
}
|
||||
.container-title .title {
|
||||
padding: 8px 15px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
background: #0096fd;
|
||||
border-radius: 0 15px 0 0;
|
||||
}
|
||||
//[class*=" el-icon-"], [class^=el-icon-]{
|
||||
// line-height: unset;
|
||||
//}
|
||||
.lineH35 {
|
||||
line-height: 35px;
|
||||
}
|
||||
.lineH40 {
|
||||
line-height: 40px;
|
||||
}
|
||||
.search_btn_s .el-button {
|
||||
padding: 5px 8px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.el-date-editor.el-input,
|
||||
.el-input,
|
||||
.el-select,
|
||||
.el-cascader {
|
||||
width: 100%;
|
||||
//max-width: 350px;
|
||||
}
|
||||
/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
|
||||
::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
/*定义滚动条轨道 内阴影+圆角*/
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/*定义滑块 内阴影+圆角*/
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1);
|
||||
background-color: #c8c8c8;
|
||||
}
|
||||
.el-tooltip__popper {
|
||||
max-width: 500px;
|
||||
}
|
||||
body .el-collapse-item__wrap {
|
||||
padding-top: 30px !important;
|
||||
}
|
||||
.AdditionalInsurance .cell {
|
||||
color: #409eff;
|
||||
}
|
||||
.cellClassNo .cell {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.cellClassYes .cell {
|
||||
color: #409eff;
|
||||
}
|
||||
.mainInsurance .cell {
|
||||
color: #67c23a;
|
||||
}
|
||||
.el-form-item__label {
|
||||
width: 120px;
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
justify-content: flex-end;
|
||||
line-height: 20px;
|
||||
}
|
||||
.el-select__tags {
|
||||
white-space: nowrap !important;
|
||||
overflow: hidden !important;
|
||||
// text-overflow: ellipsis!important;
|
||||
display: inline-block !important;
|
||||
}
|
||||
.el-loading-mask {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.toolBox {
|
||||
display: inline-flex;
|
||||
}
|
||||
.ellipsis {
|
||||
display: inline;
|
||||
/*margin: auto;*/
|
||||
max-width: 215px;
|
||||
height: 24px;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.el-table th {
|
||||
background: #ecf5ff;
|
||||
}
|
||||
.el-form-item__content {
|
||||
line-height: 1.7692;
|
||||
}
|
||||
.el-table th > .cell {
|
||||
display: block;
|
||||
}
|
||||
.el-table th.el-table__cell {
|
||||
background: #ecf5ff;
|
||||
}
|
||||
209
src/assets/sass/sidebar.scss
Normal file
@@ -0,0 +1,209 @@
|
||||
#app {
|
||||
|
||||
.main-container {
|
||||
min-height: 100%;
|
||||
transition: margin-left .28s;
|
||||
margin-left: $sideBarWidth;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: width 0.28s;
|
||||
width: $sideBarWidth !important;
|
||||
background-color: $menuBg;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
font-size: 0px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1001;
|
||||
overflow: hidden;
|
||||
|
||||
// reset element-ui css
|
||||
.horizontal-collapse-transition {
|
||||
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
|
||||
}
|
||||
|
||||
.scrollbar-wrapper {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
.el-scrollbar__bar.is-vertical {
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.has-logo {
|
||||
.el-scrollbar {
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
|
||||
.is-horizontal {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.el-menu {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
// menu hover
|
||||
.submenu-title-noDropdown,
|
||||
.el-submenu__title {
|
||||
&:hover {
|
||||
background-color: $menuHover !important;
|
||||
}
|
||||
}
|
||||
|
||||
.is-active>.el-submenu__title {
|
||||
color: $subMenuActiveText !important;
|
||||
}
|
||||
|
||||
& .nest-menu .el-submenu>.el-submenu__title,
|
||||
& .el-submenu .el-menu-item {
|
||||
min-width: $sideBarWidth !important;
|
||||
background-color: $subMenuBg !important;
|
||||
|
||||
&:hover {
|
||||
background-color: $subMenuHover !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hideSidebar {
|
||||
.sidebar-container {
|
||||
width: 54px !important;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
margin-left: 54px;
|
||||
}
|
||||
|
||||
.submenu-title-noDropdown {
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
|
||||
.el-tooltip {
|
||||
padding: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-submenu {
|
||||
overflow: hidden;
|
||||
|
||||
&>.el-submenu__title {
|
||||
padding: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.el-submenu__icon-arrow {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--collapse {
|
||||
.el-submenu {
|
||||
&>.el-submenu__title {
|
||||
&>span {
|
||||
height: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-menu--collapse .el-menu .el-submenu {
|
||||
min-width: $sideBarWidth !important;
|
||||
}
|
||||
|
||||
// mobile responsive
|
||||
.mobile {
|
||||
.main-container {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
transition: transform .28s;
|
||||
width: $sideBarWidth !important;
|
||||
}
|
||||
|
||||
&.hideSidebar {
|
||||
.sidebar-container {
|
||||
pointer-events: none;
|
||||
transition-duration: 0.3s;
|
||||
transform: translate3d(-$sideBarWidth, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.withoutAnimation {
|
||||
|
||||
.main-container,
|
||||
.sidebar-container {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when menu collapsed
|
||||
.el-menu--vertical {
|
||||
&>.el-menu {
|
||||
.svg-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.nest-menu .el-submenu>.el-submenu__title,
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
// you can use $subMenuHover
|
||||
background-color: $menuHover !important;
|
||||
}
|
||||
}
|
||||
|
||||
// the scroll bar appears when the subMenu is too long
|
||||
>.el-menu--popup {
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background: #d3dce6;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #99a9bf;
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/assets/sass/transition.scss
Normal file
@@ -0,0 +1,48 @@
|
||||
// global transition css
|
||||
|
||||
/* fade */
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.28s;
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-active {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* fade-transform */
|
||||
.fade-transform-leave-active,
|
||||
.fade-transform-enter-active {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.fade-transform-enter {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
|
||||
.fade-transform-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
/* breadcrumb transition */
|
||||
.breadcrumb-enter-active,
|
||||
.breadcrumb-leave-active {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.breadcrumb-enter,
|
||||
.breadcrumb-leave-active {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.breadcrumb-move {
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.breadcrumb-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
271
src/assets/sass/utils.scss
Normal file
@@ -0,0 +1,271 @@
|
||||
//浮动、清除浮动
|
||||
.clearfix {
|
||||
@include clearfix;
|
||||
}
|
||||
|
||||
.fl {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.fr {
|
||||
float: right;
|
||||
}
|
||||
|
||||
//字体相关
|
||||
.fs12 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.fs14 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.fs16 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.fs18 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.fs20 {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.fs22 {
|
||||
font-size: 22px;
|
||||
}
|
||||
h1{
|
||||
font-size: 38px;
|
||||
}
|
||||
h2{
|
||||
font-size: 30px;
|
||||
}
|
||||
h3{
|
||||
font-size: 24px;
|
||||
}
|
||||
//.bg-title{
|
||||
// font-size: 20px;
|
||||
//}
|
||||
//.title{
|
||||
// font-size: 16px;
|
||||
//}
|
||||
.fw600 {
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.fwb {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
//布局定位
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.fixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.mh-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.hide {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.inline-flex {
|
||||
display: -webkit-inline-flex;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.inline-b {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
.justify-content-c {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.justify-content-a {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.justify-content-b {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.align-items-c {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// 背景色
|
||||
.bg-white {
|
||||
background-color: $white !important;
|
||||
}
|
||||
|
||||
.bg-none {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.bg-green {
|
||||
background-color: #4fc6b3 !important;
|
||||
}
|
||||
|
||||
// 文字颜色
|
||||
.c-gray-darker {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
|
||||
.app-main{
|
||||
//background: #eeeeee;
|
||||
}
|
||||
.button-container{
|
||||
margin-bottom: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
.container{
|
||||
padding: 25px 15px 50px;
|
||||
//margin: 15px;
|
||||
background: #fff;
|
||||
}
|
||||
.el-select{
|
||||
width: 100%;
|
||||
}
|
||||
.c-gray-dark {
|
||||
color: #4A4A4A;
|
||||
}
|
||||
|
||||
.c-gray-base {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.c-gray-light {
|
||||
color: #9E9E9E;
|
||||
}
|
||||
|
||||
.c-gray-lighter {
|
||||
color: #B1B1B1;
|
||||
}
|
||||
|
||||
.c-blue-base {
|
||||
color: #0069B7;
|
||||
}
|
||||
|
||||
.c-blue-light {
|
||||
color: #78A6DC;
|
||||
}
|
||||
|
||||
.c-gray {
|
||||
color: #DEDCDC;
|
||||
}
|
||||
|
||||
// 文字位置设置
|
||||
.text-left {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.text-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
// 垂直方向对齐方式
|
||||
.v-top {
|
||||
vertical-align: top !important;
|
||||
}
|
||||
|
||||
.v-middle {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
.v-bottom {
|
||||
vertical-align: bottom !important;
|
||||
}
|
||||
|
||||
.v-baseline {
|
||||
vertical-align: baseline !important;
|
||||
}
|
||||
|
||||
//单行省略
|
||||
.ellipsis {
|
||||
@include text-overflow;
|
||||
}
|
||||
|
||||
//颜色
|
||||
.green {
|
||||
color: $green !important;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: $red !important;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
color: $yellow !important;
|
||||
}
|
||||
|
||||
.gray {
|
||||
color: $gray !important;
|
||||
}
|
||||
|
||||
.white {
|
||||
color: $white !important;
|
||||
}
|
||||
|
||||
.bg-black {
|
||||
background: $black !important;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background: $white !important;
|
||||
}
|
||||
|
||||
|
||||
// 设置光标样式
|
||||
.pointer {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
.cursor-default {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
// 设置符合ui边线
|
||||
.border-ui {
|
||||
border: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
// 底部固定
|
||||
.fixed-button{
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
padding: 10px 0;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
70
src/assets/sass/variables.scss
Normal file
@@ -0,0 +1,70 @@
|
||||
//sidebar
|
||||
$menuBg: #304156;
|
||||
$subMenuBg: #1f2d3d;
|
||||
$menuHover: #001528;
|
||||
$headerBg: #23262e;
|
||||
|
||||
//颜色
|
||||
$white: #fff !default;
|
||||
$green: #5ebc75 !default;
|
||||
$red: #e96572 !default;
|
||||
$yellow: #f2c44d !default;
|
||||
$orange: #ffa0a2 !default;
|
||||
$gray: #b1b1b1 !default;
|
||||
$black: #000 !default;
|
||||
|
||||
// 宽度列表
|
||||
$width-list: 5 8 10 20 30 40 50 60 65 70 80 86 100 110 120 140 150 155 160 180 192 200 220 260 280 299 300 315 325 350 400 440 445 450 550 700 1340;
|
||||
|
||||
// 内外边距列表
|
||||
$distance-list: 0 1 2 5 6 8 9 10 12 15 20 25 30 35 40 45 50 60 80 86 90 100 120 140;
|
||||
$distance-class-list: m,
|
||||
mv,
|
||||
mh,
|
||||
mt,
|
||||
ml,
|
||||
mr,
|
||||
mb,
|
||||
p,
|
||||
pv,
|
||||
ph,
|
||||
pt,
|
||||
pl,
|
||||
pr,
|
||||
pb,
|
||||
top,
|
||||
left,
|
||||
right,
|
||||
bottom;
|
||||
|
||||
//圆角弧度
|
||||
$radius: 1 2 3 4 5 6 7 8 9 10 12 15 18 20 50 100;
|
||||
|
||||
//透明度
|
||||
$opacity: 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9;
|
||||
|
||||
// sidebar
|
||||
$menuText: #bfcbd9;
|
||||
$menuActiveText: #409eff;
|
||||
$subMenuActiveText: #f4f4f5; //https://github.com/ElemeFE/element/issues/12951
|
||||
|
||||
$menuBg: #304156;
|
||||
$menuHover: #263445;
|
||||
|
||||
$subMenuBg: #1f2d3d;
|
||||
$subMenuHover: #001528;
|
||||
|
||||
$sideBarWidth: 210px;
|
||||
|
||||
// the :export directive is the magic sauce for webpack
|
||||
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
|
||||
:export {
|
||||
menuText: $menuText;
|
||||
menuActiveText: $menuActiveText;
|
||||
subMenuActiveText: $subMenuActiveText;
|
||||
menuBg: $menuBg;
|
||||
menuHover: $menuHover;
|
||||
subMenuBg: $subMenuBg;
|
||||
subMenuHover: $subMenuHover;
|
||||
sideBarWidth: $sideBarWidth;
|
||||
}
|
||||
78
src/components/Breadcrumb/index.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<el-breadcrumb class="app-breadcrumb" separator-class="el-icon-arrow-right">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
|
||||
<span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect fs16">{{ item.meta.title }}</span>
|
||||
<span v-else>{{ item.meta.title }}</span>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
levelList: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
// only show routes with meta.title
|
||||
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
|
||||
// const first = matched[0]
|
||||
|
||||
// if (!this.isDashboard(first)) {
|
||||
// matched = [{ path: '/dashboard', meta: { title: 'Dashboard' } }].concat(matched)
|
||||
// }
|
||||
|
||||
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||
},
|
||||
isDashboard(route) {
|
||||
const name = route && route.name
|
||||
if (!name) {
|
||||
return false
|
||||
}
|
||||
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
|
||||
},
|
||||
pathCompile(path) {
|
||||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
||||
const { params } = this.$route
|
||||
var toPath = pathToRegexp.compile(path)
|
||||
return toPath(params)
|
||||
},
|
||||
handleLink(item) {
|
||||
const { redirect, path } = item
|
||||
if (redirect) {
|
||||
this.$router.push(redirect)
|
||||
return
|
||||
}
|
||||
this.$router.push(this.pathCompile(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 8px;
|
||||
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
39
src/components/Hamburger/index.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div style="padding: 0 15px;" @click="toggleClick">
|
||||
<svg :class="{ 'is-active': isActive }" class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
|
||||
<path
|
||||
d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Hamburger',
|
||||
props: {
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleClick() {
|
||||
this.$emit('toggleClick')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hamburger {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.hamburger.is-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
||||
79
src/components/MavonEditor/index.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div class="mavonEditor-index-container">
|
||||
<!-- 可视化富文本编辑器 书写代码-->
|
||||
<mavonEditor :defaultOpen="defaultOpen" ref="mavonEditor" :toolbarsFla="false" v-model="content" :toolbars="toolbars" :ishljs="true"></mavonEditor>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mavonEditor } from 'mavon-editor'
|
||||
import 'mavon-editor/dist/css/index.css'
|
||||
export default {
|
||||
name: 'mavonEditor-index',
|
||||
components: { mavonEditor },
|
||||
props: {
|
||||
value: {
|
||||
type: String
|
||||
},
|
||||
defaultOpen: {
|
||||
type: String,
|
||||
default: 'edit'
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'event1'
|
||||
},
|
||||
watch: {
|
||||
value(o) {
|
||||
this.content = o
|
||||
},
|
||||
content(o) {
|
||||
this.$emit('event1', o)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
content: '',
|
||||
toolbars: {
|
||||
bold: true, // 粗体
|
||||
italic: true, // 斜体
|
||||
header: true, // 标题
|
||||
underline: true, // 下划线
|
||||
strikethrough: true, // 中划线
|
||||
mark: true, // 标记
|
||||
superscript: true, // 上角标
|
||||
subscript: true, // 下角标
|
||||
quote: true, // 引用
|
||||
ol: true, // 有序列表
|
||||
ul: true, // 无序列表
|
||||
link: true, // 链接
|
||||
imagelink: true, // 图片链接
|
||||
code: true, // code
|
||||
table: true, // 表格
|
||||
fullscreen: true, // 全屏编辑
|
||||
readmodel: true, // 沉浸式阅读
|
||||
htmlcode: true, // 展示html源码
|
||||
help: true, // 帮助
|
||||
/* 1.3.5 */
|
||||
undo: true, // 上一步
|
||||
redo: true, // 下一步
|
||||
trash: true, // 清空
|
||||
save: true, // 保存(触发events中的save事件)
|
||||
/* 1.4.2 */
|
||||
navigation: true, // 导航目录
|
||||
/* 2.1.8 */
|
||||
alignleft: true, // 左对齐
|
||||
aligncenter: true, // 居中
|
||||
alignright: true, // 右对齐
|
||||
/* 2.2.1 */
|
||||
subfield: true, // 单双栏模式
|
||||
preview: true // 预览
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
74
src/components/RenderSwiper/index.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div class="render-swiper-container">
|
||||
<div class="swiper-container" ref="swiper">
|
||||
<div class="swiper-wrapper">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="swiper-pagination" v-if="showPagination"></div>
|
||||
<div class="swiper-button-next" v-if="showNextBtb"></div>
|
||||
<div class="swiper-button-prev" v-if="showNextBtb"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Swiper from 'swiper'
|
||||
import 'swiper/css/swiper.min.css'
|
||||
export default {
|
||||
name: 'render-swiper',
|
||||
data() {
|
||||
return {
|
||||
swiper: '',
|
||||
defaultOptions: {
|
||||
initialSlide: 0, //初始展示索引
|
||||
direction: 'horizontal', //水平/垂直展示
|
||||
speed: 300, //切换速度
|
||||
grabCursor: false, //拖动时显示手势 鼠标覆盖Swiper 时指针会变成手掌形状,拖动时指针会变成抓手形状
|
||||
watchSlidesProgress: true, // 子元素的活动进程
|
||||
setWrapperSize: false, // Swiper使用flexbox布局(display: flex),开启这个设定会在Wrapper上添加等于slides相加的宽或高,在对flexbox布局的支持不是很好的浏览器中可能需要用到。
|
||||
virtualTranslate: false, // 滑动锁定
|
||||
width: undefined, //宽度
|
||||
height: undefined, //高度
|
||||
breakpoints: '', //响应式设置
|
||||
autoHeight: false, //自动高度。设置为 true 时,wrapper 和container 会随着当前slide 的高度而发生变化。
|
||||
loop: true,
|
||||
autoplay: {
|
||||
delay: 3000
|
||||
}
|
||||
// init: false
|
||||
}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
options: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
showPagination: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showNextBtb: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
components: {},
|
||||
filters: {},
|
||||
methods: {},
|
||||
created() {
|
||||
let newOptions = Object.assign({}, this.defaultOptions, this.options)
|
||||
this.$nextTick(() => {
|
||||
newOptions.loopAdditionalSlides = newOptions.loopAdditionalSlides ? newOptions.loopAdditionalSlides : 3
|
||||
this.swiper = new Swiper(this.$refs.swiper, newOptions)
|
||||
})
|
||||
},
|
||||
mounted() {}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
#index-container {
|
||||
}
|
||||
</style>
|
||||
24
src/components/RenderTable/component/TooltipScope/index.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'index',
|
||||
props: ['scope', 'item'],
|
||||
render() {
|
||||
let { scope, item } = this
|
||||
return scope.row[item.prop] ? (
|
||||
<div class="toolBox">
|
||||
<el-tooltip content={scope.row[item.prop] && scope.row[item.prop] != '' ? scope.row[item.prop] : '2'} placement="right" effect="dark">
|
||||
<div class="ellipsis">{scope.row[item.prop]}</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
) : (
|
||||
<div class="ellipsis">{scope.row[item.prop]}</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.toolBox {
|
||||
display: inline-grid;
|
||||
}
|
||||
</style>
|
||||
37
src/components/RenderTable/component/bodySlot/index.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<script>
|
||||
// 自定义内容的组件 实现element 自带render函数
|
||||
const RenderSlot = {
|
||||
functional: true,
|
||||
props: {
|
||||
row: Object,
|
||||
render: Function,
|
||||
index: Number,
|
||||
column: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
render: (h, data) => {
|
||||
const params = {
|
||||
row: data.props.row,
|
||||
index: data.props.index
|
||||
}
|
||||
if (data.props.column) params.column = data.props.column
|
||||
return data.props.render(h, params)
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'FormSlot',
|
||||
props: ['item', 'scope'],
|
||||
components: { RenderSlot },
|
||||
render() {
|
||||
let { item, scope } = this
|
||||
return (
|
||||
// <el-form-item prop={`"${item.ruleName}"`} rules={item.rules}>
|
||||
<render-slot row={scope.row} render={item.render} index={scope.$index} column={item} />
|
||||
// </el-form-item>
|
||||
// </el-form>
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
31
src/components/RenderTable/component/headerSlot/index.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script>
|
||||
// 自定义内容的组件 实现element 自带render函数
|
||||
const RenderSlot = {
|
||||
functional: true,
|
||||
props: {
|
||||
row: Object,
|
||||
render: Function,
|
||||
index: Number,
|
||||
column: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
render: (h, data) => {
|
||||
const params = {
|
||||
index: data.props.index
|
||||
}
|
||||
if (data.props.column) params.column = data.props.column
|
||||
return data.props.render(h, params)
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'headerSlot',
|
||||
props: ['item', 'scope'],
|
||||
components: { RenderSlot },
|
||||
render() {
|
||||
let { item, scope } = this
|
||||
return <render-slot render={item.headRender} index={scope.$index} column={item} />
|
||||
}
|
||||
}
|
||||
</script>
|
||||
369
src/components/RenderTable/index.vue
Normal file
@@ -0,0 +1,369 @@
|
||||
<template>
|
||||
<div id="RenderTable-container">
|
||||
<el-form :model="model" ref="model">
|
||||
<el-table
|
||||
:class="drag ? 'dragTable' : ''"
|
||||
:data="model.data"
|
||||
row-key="id"
|
||||
lazy
|
||||
@sort-change="sortChange"
|
||||
ref="renderTable"
|
||||
:border="border"
|
||||
stripe
|
||||
:header-align="align"
|
||||
size="small"
|
||||
default-expand-all
|
||||
:max-height="maxHeight || null"
|
||||
@selection-change="handleSelectionChange"
|
||||
@row-click="handleRowClick"
|
||||
:tree-props="{ children: 'childList' }"
|
||||
>
|
||||
<template v-for="(item, index) in columns">
|
||||
<!--没有type 的模板-->
|
||||
<el-table-column
|
||||
:align="item.align"
|
||||
:row-key="item.id"
|
||||
:label="item.key"
|
||||
:type="item.type"
|
||||
:sortable="item.sortable"
|
||||
:key="index"
|
||||
:min-width="item.width ? item.width : 225"
|
||||
:fixed="item.fixed"
|
||||
v-if="!item.type"
|
||||
>
|
||||
<template #header="scope" v-if="item.headRender">
|
||||
<header-slot :item="item" :scope="scope" />
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<!--表单校验-->
|
||||
<el-form-item v-if="item.ruleCode" :prop="'data.' + scope.$index + '.' + item.ruleCode" :rules="item.ruleCode ? item.rules : []">
|
||||
<body-slot :item="item" :scope="scope" v-if="item.render" />
|
||||
</el-form-item>
|
||||
<body-slot :item="item" :scope="scope" v-if="!item.ruleCode && item.render" />
|
||||
<!--自定义render模板-->
|
||||
<!--</el-form>-->
|
||||
<!--自带的btn 不能有prop 属性-->
|
||||
<div v-if="!item.selfBtn && !item.prop && !item.type && !item.render" :fixed="item.fixed ? item.fixed : fixed">
|
||||
<el-button type="primary" size="mini" plain :disabled="disabled" @click="edit(scope.row, scope.$index)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" plain :disabled="disabled" @click="del(scope.row, scope.$index)">删除</el-button>
|
||||
</div>
|
||||
<!--如果渲染的是selfBtn-->
|
||||
<div v-if="item.selfBtn && !item.render">
|
||||
<el-button
|
||||
v-for="(btn, btnIndex) in item.selfBtn"
|
||||
:fixed="item.fixed ? item.fixed : fixed"
|
||||
:disabled="item.disabled !== undefined ? item.disabled : disabled"
|
||||
:type="btn.type ? btn.type : 'primary'"
|
||||
:size="btn.size ? btn.size : 'mini'"
|
||||
:key="btnIndex"
|
||||
@click="handlerMethods(scope.row, scope.$index, btn)"
|
||||
:label="btn.name"
|
||||
>
|
||||
{{ btn.name }}
|
||||
</el-button>
|
||||
</div>
|
||||
<!--提示框 内部判断是否给单元格提示-->
|
||||
<TooltipScope :scope="scope" :item="item" v-if="!item.type && !item.render && item.prop" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!--有设置type 的表格 type 设置的是selection 和 index-->
|
||||
<el-table-column
|
||||
:key="index"
|
||||
:row-key="item.id"
|
||||
:align="align"
|
||||
:label="item.key"
|
||||
:type="item.type"
|
||||
:width="item.width"
|
||||
v-else-if="item.type === 'index' || item.type === 'selection'"
|
||||
/>
|
||||
<el-table-column
|
||||
:key="index"
|
||||
:row-key="item.id"
|
||||
:align="align"
|
||||
:label="item.key"
|
||||
:type="item.type"
|
||||
:width="item.width"
|
||||
v-else-if="item.type === 'radio'"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-radio v-model="check" :label="scope.$index" @change="setCheck($event, scope)">{{ null }}</el-radio>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<!--自定义默认按钮 ps:增加 一行 删除一行-->
|
||||
<el-table-column v-if="deletion" :align="align" width="180" :fixed="fixed">
|
||||
<template slot-scope="scope">
|
||||
<div>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
@click="
|
||||
e => {
|
||||
addRow(scope.row, scope.$index)
|
||||
}
|
||||
"
|
||||
:disabled="disabled"
|
||||
circle
|
||||
icon="el-icon-plus"
|
||||
size="medium"
|
||||
class="tableBtn"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
@click="
|
||||
e => {
|
||||
delRow(scope.row, scope.$index)
|
||||
}
|
||||
"
|
||||
:disabled="disabled"
|
||||
circle
|
||||
size="medium"
|
||||
icon="el-icon-minus"
|
||||
class="tableBtn"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-form>
|
||||
<!--表格分页-->
|
||||
<div class="text-right" v-if="total">
|
||||
<el-pagination
|
||||
class="table-container"
|
||||
@size-change="sizeChange"
|
||||
@current-change="currentChange"
|
||||
background
|
||||
:currentPage="currentPage"
|
||||
layout="prev,sizes, pager, next,jumper"
|
||||
:page-sizes="[10, 20, 30, 40, 50]"
|
||||
:total="total"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Sortable from 'sortablejs'
|
||||
import TooltipScope from './component/TooltipScope'
|
||||
import bodySlot from './component/bodySlot'
|
||||
import HeaderSlot from './component/headerSlot'
|
||||
/* * @Author: 陈昱达 * @Date: 2020-08-27 17:40:39 * @Last Modified by: 陈昱达 * @Last Modified time: 2020-08-27 17:40:39 */
|
||||
export default {
|
||||
name: 'RenderTable',
|
||||
data() {
|
||||
return {
|
||||
fixed: 'right',
|
||||
check: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
model(v) {
|
||||
return {
|
||||
data: v.data
|
||||
}
|
||||
}
|
||||
},
|
||||
components: { HeaderSlot, TooltipScope, bodySlot },
|
||||
props: {
|
||||
//是否拖拽
|
||||
drag: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//是否展示 删减行 按钮 和新增行按钮
|
||||
deletion: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
//页码
|
||||
currentPage: {
|
||||
type: Number
|
||||
},
|
||||
//是否禁用表格自带按钮
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//表格边框 border
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否剧中 align
|
||||
align: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// table data
|
||||
data: {
|
||||
type: Array
|
||||
},
|
||||
//columns
|
||||
columns: {
|
||||
type: Array
|
||||
},
|
||||
//total
|
||||
total: {
|
||||
type: Number
|
||||
},
|
||||
maxHeight: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.drag) {
|
||||
this.rowDrop()
|
||||
// this.columnDrop()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 单选选中
|
||||
setCheck(e, scope) {
|
||||
this.check = e
|
||||
this.$emit('selectRow', { row: scope.row, index: scope.$index })
|
||||
this.$emit('select-row', { row: scope.row, index: scope.$index })
|
||||
},
|
||||
sortChange(sortData) {
|
||||
let filters = this.columns.filter(item => item.key === sortData.column.label)
|
||||
if (filters && filters.length > 0) {
|
||||
sortData.prop = filters[0].prop
|
||||
}
|
||||
this.$emit('sortChange', sortData)
|
||||
this.$emit('sort-change', sortData)
|
||||
},
|
||||
//行拖拽
|
||||
rowDrop() {
|
||||
const tbody = document.querySelector('.dragTable .el-table__body-wrapper tbody')
|
||||
Sortable.create(tbody, {
|
||||
animation: 180,
|
||||
onEnd: ({ newIndex, oldIndex }) => {
|
||||
const currRow = this.data.splice(oldIndex, 1)[0]
|
||||
this.data.splice(newIndex, 0, currRow)
|
||||
}
|
||||
})
|
||||
},
|
||||
//列拖拽 目前有问题 暂未解决
|
||||
columnDrop() {
|
||||
const wrapperTr = document.querySelector('.dragTable .el-table__header-wrapper tr')
|
||||
Sortable.create(wrapperTr, {
|
||||
animation: 180,
|
||||
filter: '.el-table-column--selection',
|
||||
delay: 0,
|
||||
onEnd: evt => {
|
||||
const oldItem = this.columns[evt.oldIndex]
|
||||
this.columns.splice(evt.oldIndex, 1)
|
||||
this.columns.splice(evt.newIndex, 0, oldItem)
|
||||
}
|
||||
})
|
||||
},
|
||||
//edit in table
|
||||
edit(row, index) {
|
||||
this.$emit('edit', row, index)
|
||||
},
|
||||
// del In Table
|
||||
del(row, index) {
|
||||
this.$emit('del', row, index)
|
||||
},
|
||||
//展示条数改变
|
||||
sizeChange(size) {
|
||||
this.$emit('sizeChange', size)
|
||||
this.$emit('size-change', size)
|
||||
},
|
||||
//页码改变
|
||||
currentChange(current) {
|
||||
this.$emit('currentChange', current)
|
||||
this.$emit('current-change', current)
|
||||
},
|
||||
//根据数据的格式去返回对应的数据结构
|
||||
getDataType(type) {
|
||||
let dataType = ''
|
||||
if (type === '[object Array]') {
|
||||
dataType = []
|
||||
} else if (type === '[object Object]') {
|
||||
dataType = {}
|
||||
}
|
||||
return dataType
|
||||
},
|
||||
//Add a new line
|
||||
addRow(row, index) {
|
||||
let newRow = JSON.parse(JSON.stringify(row))
|
||||
for (let item in newRow) {
|
||||
newRow[item] = this.getDataType(Object.prototype.toString.call(newRow[item]))
|
||||
}
|
||||
this.data.splice(index + 1, 0, newRow)
|
||||
this.$emit('buttonAdd', row, newRow)
|
||||
this.$emit('button-add', row, newRow)
|
||||
},
|
||||
//Delete row
|
||||
delRow(row, index) {
|
||||
this.$emit('buttonDel', row, index)
|
||||
this.$emit('button-del', row, index)
|
||||
let newRow = JSON.parse(JSON.stringify(row))
|
||||
this.data.splice(index, 1)
|
||||
if (this.data.length === 0) {
|
||||
for (let item in newRow) {
|
||||
newRow[item] = this.getDataType(Object.prototype.toString.call(newRow[item]))
|
||||
}
|
||||
this.data.push(newRow)
|
||||
}
|
||||
},
|
||||
//btnSelf 把当前数据提交给父组件自定义method事件中
|
||||
handlerMethods(row, index, btn) {
|
||||
this.$emit(btn.method, { row, index })
|
||||
},
|
||||
|
||||
handleRowClick(row, column, event) {
|
||||
this.$emit('row-click', row, column, event)
|
||||
},
|
||||
handleSelectionChange(row) {
|
||||
this.$emit('selection-change', row)
|
||||
},
|
||||
//具体查看element 文档
|
||||
toggleRowSelection(rows) {
|
||||
this.$nextTick(() => {
|
||||
if (rows) {
|
||||
rows.forEach(row => {
|
||||
this.$refs.renderTable.toggleRowSelection(row)
|
||||
})
|
||||
} else {
|
||||
this.$refs.multipleTable.clearSelection()
|
||||
}
|
||||
})
|
||||
},
|
||||
clearSelection() {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.renderTable.clearSelection()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.pd5 {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.tableBtn {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/deep/.el-table {
|
||||
.el-radio__label {
|
||||
padding: unset;
|
||||
}
|
||||
.el-form-item__error {
|
||||
position: unset;
|
||||
}
|
||||
.el-form-item__content {
|
||||
line-height: unset;
|
||||
}
|
||||
.el-form-item__error {
|
||||
position: unset;
|
||||
}
|
||||
.el-form-item {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
62
src/components/SvgIcon/index.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
|
||||
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
|
||||
import { isExternal } from '@/assets/js/utils/validate'
|
||||
|
||||
export default {
|
||||
name: 'SvgIcon',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isExternal() {
|
||||
return isExternal(this.iconClass)
|
||||
},
|
||||
iconName() {
|
||||
return `#icon-${this.iconClass}`
|
||||
},
|
||||
svgClass() {
|
||||
if (this.className) {
|
||||
return 'svg-icon ' + this.className
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
},
|
||||
styleExternalIcon() {
|
||||
return {
|
||||
mask: `url(${this.iconClass}) no-repeat 50% 50%`,
|
||||
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-external-icon {
|
||||
background-color: currentColor;
|
||||
mask-size: cover !important;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
62
src/components/VueEditor/index.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div id="vueEditor-container">
|
||||
<!--富文本编辑器-->
|
||||
<VueEditor v-model="content" :editorToolbar="editorToolbar" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { VueEditor } from 'vue2-editor'
|
||||
export default {
|
||||
name: 'vueEditor',
|
||||
components: { VueEditor },
|
||||
props: {
|
||||
value: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'event1'
|
||||
},
|
||||
watch: {
|
||||
value(o, v) {
|
||||
this.content = o
|
||||
},
|
||||
content(o) {
|
||||
this.$emit('event1', o)
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
content: this.value,
|
||||
editorToolbar: [
|
||||
[{ header: [false, 1, 2, 3, 4, 5, 6] }],
|
||||
['bold', 'italic', 'underline', 'strike'], // toggled buttons
|
||||
[{ align: ['', 'center', 'right', 'justify'] }],
|
||||
['blockquote'],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }, { list: 'check' }],
|
||||
[{ indent: '-1' }, { indent: '+1' }], // outdent/indent
|
||||
[{ color: [] }, { background: [] }], // dropdown with defaults from theme
|
||||
['clean','link', 'image']
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleImageAdded(file, Editor, cursorLocation, resetUploader) {
|
||||
let formData = new FormData()
|
||||
formData.append('file', file) //第一个file 后台接收的参数名
|
||||
uploadFileComponentForEditor(formData)
|
||||
.then(result => {
|
||||
let url = result.content.fileUrl // 返回给你的图片路径
|
||||
Editor.insertEmbed(cursorLocation, 'image', url)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
6
src/config/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
let envInfo = process.env
|
||||
let [admin] = [envInfo.VUE_APP_ADMIN]
|
||||
|
||||
export default {
|
||||
admin,
|
||||
}
|
||||
21
src/config/urlMap.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @desc 远程接口地址和本地mock地址映射表
|
||||
* key:接口地址
|
||||
* value:本地地址
|
||||
*/
|
||||
const mockBaseUrl = 'http://rap2api.taobao.org/app/mock'
|
||||
|
||||
// const mockBaseUrl = 'http://devops.ebiz-digits.com:8083/app/mock'
|
||||
const BaseUrl = 'http://devops.ebiz-digits.com:8083/app/mock'
|
||||
export default {
|
||||
'/user/login': mockBaseUrl + '/223948/login',
|
||||
'/user/info': mockBaseUrl + '/223948/info',
|
||||
'/user/logout': mockBaseUrl + '/223948/logout',
|
||||
'/table/list': mockBaseUrl + '/223948/table-list',
|
||||
'/index/user': mockBaseUrl + '/19/index/user',
|
||||
'/product/coverageGroup/findCoverageGroupList': BaseUrl + '/25/product/coverageGroup/findCoverageGroupList',
|
||||
'/product/coverageGroup/qureyCoverageGroup': BaseUrl + '/25/product/coverageGroup/qureyCoverageGroup',
|
||||
'/product/coverage/findCoverage': BaseUrl + '/25/product/coverage/findCoverage',
|
||||
'/product/enum/list': BaseUrl + '/25/product/enum/list',
|
||||
'/product/tariff/list': BaseUrl + '/25//product/tariff/list'
|
||||
}
|
||||
102
src/filters/index.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import Common from '../assets/js/common'
|
||||
|
||||
/*
|
||||
* 把其他filter放到index.js里面一起引入
|
||||
*/
|
||||
export default {
|
||||
m2km(value) {
|
||||
return Common.m2km(value)
|
||||
},
|
||||
|
||||
/**
|
||||
* 除法
|
||||
* @param {Number} dividend 被除数
|
||||
* @param {Number} divisor 除数
|
||||
* @return {Number} 值
|
||||
*/
|
||||
divide(dividend, divisor) {
|
||||
return Common.divide(dividend, divisor)
|
||||
},
|
||||
|
||||
/**
|
||||
* 保留小数位,替代Number.toFixed()方法,针对于某些数据(16.455)不能做到四舍五入
|
||||
* @param {[type]} value 数值
|
||||
* @param {[type]} num 几位小数
|
||||
* @return {[type]} 值
|
||||
*/
|
||||
toFixed(value, num) {
|
||||
return Common.toFixed(value, num)
|
||||
},
|
||||
|
||||
/**
|
||||
* 如果是小数则保留小数位,默认两位
|
||||
* @param {[type]} value 数值
|
||||
* @param {Number} num 几位小数
|
||||
* @return {[type]} 值
|
||||
*/
|
||||
toFloatFixed(value, num) {
|
||||
Common.toFloatFixed(value, num)
|
||||
},
|
||||
|
||||
/**
|
||||
* 转化成工作时间
|
||||
* @param {[type]} value 值
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
businessHour(value) {
|
||||
let time = ''
|
||||
if (value) {
|
||||
const arr = value.split(';')
|
||||
time =
|
||||
'星期' +
|
||||
Common.getWeek(arr[0]) +
|
||||
' ~ 星期' +
|
||||
Common.getWeek(arr[1]) +
|
||||
' ' +
|
||||
Common.getTime(arr[2]) +
|
||||
':' +
|
||||
Common.getTime(arr[3]) +
|
||||
' ~ ' +
|
||||
Common.getTime(arr[4]) +
|
||||
':' +
|
||||
Common.getTime(arr[5])
|
||||
}
|
||||
return time
|
||||
},
|
||||
|
||||
isEmptyObject(o) {
|
||||
return Common.isEmptyObject(o)
|
||||
},
|
||||
wan(value) {
|
||||
const isNumber = typeof value === 'number'
|
||||
return isNumber && value / 10000
|
||||
},
|
||||
// 除以100保留小数位
|
||||
divide100(value, num = 2, isFill) {
|
||||
let values = Number(value)
|
||||
const regular = /^\d+\.\d+/
|
||||
if (values) {
|
||||
values = values / 100
|
||||
if (regular.test(values)) {
|
||||
return Common.toFixed(values, num)
|
||||
} else {
|
||||
return Common.toFixed(values)
|
||||
}
|
||||
} else {
|
||||
if (isFill) {
|
||||
// 是否需要填充
|
||||
value = 0
|
||||
}
|
||||
}
|
||||
return value
|
||||
},
|
||||
discount(value, position = 0) {
|
||||
let ret = value.split('.')
|
||||
if (position == 0) {
|
||||
ret = ret[0]
|
||||
} else if (position == 1) {
|
||||
ret = ret[1]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
7
src/generatedComponents/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const requireComponent = require.context('./', true, /\w+\.vue$/) //遍历当前目录和子目录
|
||||
let comps = {}
|
||||
requireComponent.keys().map(fileName => {
|
||||
let comp = requireComponent(fileName).default;
|
||||
comps[comp.name] = comp
|
||||
})
|
||||
export default comps
|
||||
9
src/icons/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import Vue from 'vue'
|
||||
import SvgIcon from '@/components/SvgIcon' // svg component
|
||||
|
||||
// register globally
|
||||
Vue.component('svg-icon', SvgIcon)
|
||||
|
||||
const req = require.context('./svg', false, /\.svg$/)
|
||||
const requireAll = requireContext => requireContext.keys().map(requireContext)
|
||||
requireAll(req)
|
||||
1
src/icons/svg/dashboard.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
1
src/icons/svg/example.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>
|
||||
|
After Width: | Height: | Size: 497 B |
1
src/icons/svg/eye-open.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
src/icons/svg/eye.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>
|
||||
|
After Width: | Height: | Size: 944 B |
1
src/icons/svg/form.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.068 23.784c-1.02 0-1.877-.32-2.572-.96a8.588 8.588 0 0 1-1.738-2.237 11.524 11.524 0 0 1-1.042-2.621c-.232-.895-.348-1.641-.348-2.238V0h.278c.834 0 1.622.085 2.363.256.742.17 1.645.575 2.711 1.214 1.066.64 2.363 1.535 3.892 2.686 1.53 1.15 3.453 2.664 5.77 4.54 2.502 2.045 4.494 3.771 5.977 5.178 1.483 1.406 2.618 2.6 3.406 3.58.787.98 1.274 1.812 1.46 2.494.185.682.277 1.278.277 1.79v2.046H84.068zM127.3 84.01c.278.682.464 1.535.556 2.558.093 1.023-.37 2.003-1.39 2.94-.463.427-.88.832-1.25 1.215-.372.384-.696.704-.974.96a6.69 6.69 0 0 1-.973.767l-11.816-10.741a44.331 44.331 0 0 0 1.877-1.535 31.028 31.028 0 0 1 1.737-1.406c1.112-.938 2.317-1.343 3.615-1.215 1.297.128 2.363.405 3.197.83.927.427 1.923 1.173 2.989 2.239 1.065 1.065 1.876 2.195 2.432 3.388zM78.23 95.902c2.038 0 3.752-.511 5.143-1.534l-26.969 25.83H18.037c-1.761 0-3.684-.47-5.77-1.407a24.549 24.549 0 0 1-5.838-3.709 21.373 21.373 0 0 1-4.518-5.306c-1.204-2.003-1.807-4.07-1.807-6.202V16.495c0-1.79.44-3.665 1.32-5.626A18.41 18.41 0 0 1 5.04 5.562a21.798 21.798 0 0 1 5.213-3.964C12.198.533 14.237 0 16.37 0h53.24v15.984c0 1.62.278 3.367.834 5.242a16.704 16.704 0 0 0 2.572 5.179c1.159 1.577 2.665 2.898 4.518 3.964 1.853 1.066 4.078 1.598 6.673 1.598h20.295v42.325L85.458 92.45c1.02-1.364 1.529-2.856 1.529-4.476 0-2.216-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1c-2.409 0-4.448.789-6.116 2.366-1.668 1.577-2.502 3.474-2.502 5.69 0 2.217.834 4.092 2.502 5.626 1.668 1.535 3.707 2.302 6.117 2.302h52.13zM26.1 47.951c-2.41 0-4.449.789-6.117 2.366-1.668 1.577-2.502 3.473-2.502 5.69 0 2.216.834 4.092 2.502 5.626 1.668 1.534 3.707 2.302 6.117 2.302h52.13c2.409 0 4.47-.768 6.185-2.302 1.715-1.534 2.572-3.41 2.572-5.626 0-2.217-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1zm52.407 64.063l1.807-1.663 3.476-3.196a479.75 479.75 0 0 0 4.587-4.284 500.757 500.757 0 0 1 5.004-4.667c3.985-3.666 8.48-7.758 13.485-12.276l11.677 10.741-13.485 12.404-5.004 4.603-4.587 4.22a179.46 179.46 0 0 0-3.267 3.068c-.88.853-1.367 1.322-1.46 1.407-.463.341-.973.703-1.529 1.087-.556.383-1.112.703-1.668.959-.556.256-1.413.575-2.572.959a83.5 83.5 0 0 1-3.545 1.087 72.2 72.2 0 0 1-3.475.895c-1.112.256-1.946.426-2.502.511-1.112.17-1.854.043-2.224-.383-.371-.426-.464-1.151-.278-2.174.092-.511.278-1.279.556-2.302.278-1.023.602-2.067.973-3.132l1.042-3.005c.325-.938.58-1.577.765-1.918a10.157 10.157 0 0 1 2.224-2.941z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
1
src/icons/svg/link.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z"/><path d="M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z"/><path d="M127.893 37.982h-12.375V12.375H88.706V0h39.187z"/></svg>
|
||||
|
After Width: | Height: | Size: 285 B |
1
src/icons/svg/nested.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z"/></svg>
|
||||
|
After Width: | Height: | Size: 821 B |
1
src/icons/svg/password.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M108.8 44.322H89.6v-5.36c0-9.04-3.308-24.163-25.6-24.163-23.145 0-25.6 16.881-25.6 24.162v5.361H19.2v-5.36C19.2 15.281 36.798 0 64 0c27.202 0 44.8 15.281 44.8 38.961v5.361zm-32 39.356c0-5.44-5.763-9.832-12.8-9.832-7.037 0-12.8 4.392-12.8 9.832 0 3.682 2.567 6.808 6.407 8.477v11.205c0 2.718 2.875 4.962 6.4 4.962 3.524 0 6.4-2.244 6.4-4.962V92.155c3.833-1.669 6.393-4.795 6.393-8.477zM128 64v49.201c0 8.158-8.645 14.799-19.2 14.799H19.2C8.651 128 0 121.359 0 113.201V64c0-8.153 8.645-14.799 19.2-14.799h89.6c10.555 0 19.2 6.646 19.2 14.799z"/></svg>
|
||||
|
After Width: | Height: | Size: 623 B |
1
src/icons/svg/table.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z"/><path d="M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z"/></svg>
|
||||
|
After Width: | Height: | Size: 597 B |
1
src/icons/svg/tree.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M126.713 90.023c.858.985 1.287 2.134 1.287 3.447v29.553c0 1.423-.429 2.6-1.287 3.53-.858.93-1.907 1.395-3.146 1.395H97.824c-1.145 0-2.146-.465-3.004-1.395-.858-.93-1.287-2.107-1.287-3.53V93.47c0-.875.19-1.696.572-2.462.382-.766.906-1.368 1.573-1.806a3.84 3.84 0 0 1 2.146-.657h9.725V69.007a3.84 3.84 0 0 0-.43-1.806 3.569 3.569 0 0 0-1.143-1.313 2.714 2.714 0 0 0-1.573-.492h-36.47v23.149h9.725c1.144 0 2.145.492 3.004 1.478.858.985 1.287 2.134 1.287 3.447v29.553c0 .876-.191 1.696-.573 2.463-.38.766-.905 1.368-1.573 1.806a3.84 3.84 0 0 1-2.145.656H51.915a3.84 3.84 0 0 1-2.145-.656c-.668-.438-1.216-1.04-1.645-1.806a4.96 4.96 0 0 1-.644-2.463V93.47c0-1.313.43-2.462 1.288-3.447.858-.986 1.907-1.478 3.146-1.478h9.582v-23.15h-37.9c-.953 0-1.74.356-2.359 1.068-.62.711-.93 1.56-.93 2.544v19.538h9.726c1.239 0 2.264.492 3.074 1.478.81.985 1.216 2.134 1.216 3.447v29.553c0 1.423-.405 2.6-1.216 3.53-.81.93-1.835 1.395-3.074 1.395H4.29c-.476 0-.93-.082-1.358-.246a4.1 4.1 0 0 1-1.144-.657 4.658 4.658 0 0 1-.93-1.067 5.186 5.186 0 0 1-.643-1.395 5.566 5.566 0 0 1-.215-1.56V93.47c0-.437.048-.875.143-1.313a3.95 3.95 0 0 1 .429-1.15c.19-.328.429-.656.715-.984.286-.329.572-.602.858-.821.286-.22.62-.383 1.001-.493.382-.11.763-.164 1.144-.164h9.726V61.619c0-.985.31-1.833.93-2.544.619-.712 1.358-1.068 2.216-1.068h44.335V39.62h-9.582c-1.24 0-2.288-.492-3.146-1.477a5.09 5.09 0 0 1-1.287-3.448V5.14c0-1.423.429-2.627 1.287-3.612.858-.985 1.907-1.477 3.146-1.477h25.743c.763 0 1.478.246 2.145.739a5.17 5.17 0 0 1 1.573 1.888c.382.766.573 1.587.573 2.462v29.553c0 1.313-.43 2.463-1.287 3.448-.859.985-1.86 1.477-3.004 1.477h-9.725v18.389h42.762c.954 0 1.74.355 2.36 1.067.62.711.93 1.56.93 2.545v26.925h9.582c1.239 0 2.288.492 3.146 1.478z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
1
src/icons/svg/user.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="130" height="130" xmlns="http://www.w3.org/2000/svg"><path d="M63.444 64.996c20.633 0 37.359-14.308 37.359-31.953 0-17.649-16.726-31.952-37.359-31.952-20.631 0-37.36 14.303-37.358 31.952 0 17.645 16.727 31.953 37.359 31.953zM80.57 75.65H49.434c-26.652 0-48.26 18.477-48.26 41.27v2.664c0 9.316 21.608 9.325 48.26 9.325H80.57c26.649 0 48.256-.344 48.256-9.325v-2.663c0-22.794-21.605-41.271-48.256-41.271z" stroke="#979797"/></svg>
|
||||
|
After Width: | Height: | Size: 440 B |
22
src/icons/svgo.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
# replace default config
|
||||
|
||||
# multipass: true
|
||||
# full: true
|
||||
|
||||
plugins:
|
||||
|
||||
# - name
|
||||
#
|
||||
# or:
|
||||
# - name: false
|
||||
# - name: true
|
||||
#
|
||||
# or:
|
||||
# - name:
|
||||
# param1: 1
|
||||
# param2: 2
|
||||
|
||||
- removeAttrs:
|
||||
attrs:
|
||||
- 'fill'
|
||||
- 'fill-rule'
|
||||
54
src/main.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import Vue from 'vue'
|
||||
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
||||
import ElementUI from 'element-ui'
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
import locale from 'element-ui/lib/locale/lang/zh-CN' // lang i18n
|
||||
import App from './App'
|
||||
import store from './store'
|
||||
import router from './router'
|
||||
import Filters from './filters'
|
||||
import RenderTable from './components/RenderTable'
|
||||
import RenderSwiper from './components/RenderSwiper'
|
||||
import VueEditor from './components/VueEditor'
|
||||
import MavonEditor from './components/MavonEditor'
|
||||
import utils from '@/assets/js/common'
|
||||
// 生成的数据交互api
|
||||
import generatedApi from '@/api/generatedApi'
|
||||
import generatedFormat from '@/assets/js/generatedFormat'
|
||||
import generatedComponents from './generatedComponents'
|
||||
Vue.prototype.$generatedApi = generatedApi
|
||||
Vue.prototype.$generatedFormat = generatedFormat
|
||||
Vue.prototype.$utils = utils
|
||||
Vue.prototype.$generatedDictList = generatedFormat.formatList
|
||||
// 注册过滤器
|
||||
Object.keys(Filters).forEach(k => Vue.filter(k, Filters[k]))
|
||||
for(let item in generatedComponents){
|
||||
Vue.component(item, generatedComponents[item])
|
||||
}
|
||||
import '@/icons' // icon
|
||||
import '@/assets/js/utils/permission' // permission control
|
||||
// set ElementUI lang to EN
|
||||
Vue.use(ElementUI, { locale })
|
||||
//二次封装的el-table
|
||||
Vue.component('RTable', RenderTable)
|
||||
Vue.component('RSwiper', RenderSwiper)
|
||||
// 富文本编辑器
|
||||
Vue.component('VEditor', VueEditor)
|
||||
// 富文本编辑器 可视化代码
|
||||
Vue.component('MEditor', MavonEditor)
|
||||
Vue.prototype.$messageBox = function(isOk, message, type) {
|
||||
this.$confirm(message ? message : '是否确认删除当前数据', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: type ? type : 'error'
|
||||
}).then(() => {
|
||||
isOk('ok')
|
||||
})
|
||||
}
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
59
src/router/app/index.js
Normal file
@@ -0,0 +1,59 @@
|
||||
// 定义相关组件
|
||||
const layout = () => import('@/views/app/layout')
|
||||
const login = () => import('@/views/app/login')
|
||||
const notFound = () => import('@/views/app/404')
|
||||
const authentication = () => import('@/views/app/authentication/authentication.vue')
|
||||
const home = () => import('@/views/app/Home')
|
||||
|
||||
/**
|
||||
* Note: sub-menu only appear when route children.length >= 1
|
||||
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
|
||||
*
|
||||
* hidden: true if set true, item will not show in the sidebar(default is false)
|
||||
* alwaysShow: true if set true, will always show the root menu
|
||||
* if not set alwaysShow, when item has more than one children route,
|
||||
* it will becomes nested mode, otherwise not show the root menu
|
||||
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb
|
||||
* name:'router-name' the name is used by <keep-alive> (must set!!!)
|
||||
* meta : {
|
||||
roles: ['admin','editor'] control the page roles (you can set multiple roles)
|
||||
title: 'title' the name show in sidebar and breadcrumb (recommend set)
|
||||
icon: 'svg-name' the icon show in the sidebar
|
||||
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
|
||||
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set
|
||||
}
|
||||
*/
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/login',
|
||||
component: login,
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/authentication',
|
||||
component: authentication,
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/404',
|
||||
component: layout,
|
||||
redirect: '/404',
|
||||
hidden: true,
|
||||
children: [{ path: '/404', component: notFound }]
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: layout,
|
||||
redirect: '/home',
|
||||
name: 'home',
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: 'home',
|
||||
component: home
|
||||
}
|
||||
]
|
||||
},
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
]
|
||||
118
src/router/example/index.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// 定义相关组件
|
||||
const layout = () => import('@/views/app/layout')
|
||||
|
||||
export default [
|
||||
{
|
||||
path: '/example',
|
||||
component: layout,
|
||||
redirect: '/example/table',
|
||||
name: 'Example',
|
||||
meta: { title: 'Example', icon: 'example' },
|
||||
children: [
|
||||
{
|
||||
path: 'table',
|
||||
name: 'Table',
|
||||
component: () => import('@/views/example/table/index'),
|
||||
meta: { title: 'Table', icon: 'table' }
|
||||
},
|
||||
{
|
||||
path: 'tree',
|
||||
name: 'Tree',
|
||||
component: () => import('@/views/example/tree/index'),
|
||||
meta: { title: 'Tree', icon: 'tree' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/form',
|
||||
component: layout,
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: 'Form',
|
||||
component: () => import('@/views/example/form/index'),
|
||||
meta: { title: 'Form', icon: 'form' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/nested',
|
||||
component: layout,
|
||||
redirect: '/nested/menu1',
|
||||
name: 'Nested',
|
||||
meta: {
|
||||
title: 'Nested',
|
||||
icon: 'nested'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'menu1',
|
||||
component: () => import('@/views/example/nested/menu1/index'), // Parent router-view
|
||||
name: 'Menu1',
|
||||
meta: { title: 'Menu1' },
|
||||
children: [
|
||||
{
|
||||
path: 'menu1-1',
|
||||
component: () => import('@/views/example/nested/menu1/menu1-1'),
|
||||
name: 'Menu1-1',
|
||||
meta: { title: 'Menu1-1' }
|
||||
},
|
||||
{
|
||||
path: 'menu1-2',
|
||||
component: () => import('@/views/example/nested/menu1/menu1-2'),
|
||||
name: 'Menu1-2',
|
||||
meta: { title: 'Menu1-2' },
|
||||
children: [
|
||||
{
|
||||
path: 'menu1-2-1',
|
||||
component: () => import('@/views/example/nested/menu1/menu1-2/menu1-2-1'),
|
||||
name: 'Menu1-2-1',
|
||||
meta: { title: 'Menu1-2-1' }
|
||||
},
|
||||
{
|
||||
path: 'menu1-2-2',
|
||||
component: () => import('@/views/example/nested/menu1/menu1-2/menu1-2-2'),
|
||||
name: 'Menu1-2-2',
|
||||
meta: { title: 'Menu1-2-2' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'menu1-3',
|
||||
component: () => import('@/views/example/nested/menu1/menu1-3'),
|
||||
name: 'Menu1-3',
|
||||
meta: { title: 'Menu1-3' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'menu2',
|
||||
component: () => import('@/views/example/nested/menu2/index'),
|
||||
meta: { title: 'menu2' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/uploadImg',
|
||||
component: layout,
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
name: 'uploadImg',
|
||||
component: () => import('@/views/example/uploadImg/index'),
|
||||
meta: { title: 'uploadImg', icon: 'form' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'external-link',
|
||||
component: layout,
|
||||
children: [
|
||||
{
|
||||
path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
|
||||
meta: { title: 'External Link', icon: 'link' }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
16
src/router/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import App from './app/index'
|
||||
import generatedRouter from './generatedRouter'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export const constantRouterMap = [...App, ...generatedRouter] // 静态路由
|
||||
export default new Router({
|
||||
mode: 'hash', //路由模式
|
||||
base: process.env.BASE_URL,
|
||||
routes: [...constantRouterMap],
|
||||
scrollBehavior: () => ({
|
||||
y: 0
|
||||
})
|
||||
})
|
||||
9
src/store/getters.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const getters = {
|
||||
sidebar: state => state.app.sidebar,
|
||||
device: state => state.app.device,
|
||||
token: state => state.user.token,
|
||||
avatar: state => state.user.avatar,
|
||||
name: state => state.user.name,
|
||||
sidebarList: state => state.user.sidebarList,
|
||||
}
|
||||
export default getters
|
||||
17
src/store/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import getters from './getters'
|
||||
import app from './modules/app'
|
||||
import settings from './modules/settings'
|
||||
import user from './modules/user'
|
||||
Vue.use(Vuex)
|
||||
const store = new Vuex.Store({
|
||||
modules: {
|
||||
app,
|
||||
settings,
|
||||
user,
|
||||
},
|
||||
getters
|
||||
})
|
||||
|
||||
export default store
|
||||
55
src/store/modules/app.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
const state = {
|
||||
sidebar: {
|
||||
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
|
||||
withoutAnimation: false
|
||||
},
|
||||
device: 'desktop',
|
||||
sidebarList: []
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
TOGGLE_SIDEBAR: state => {
|
||||
state.sidebar.opened = !state.sidebar.opened
|
||||
state.sidebar.withoutAnimation = false
|
||||
if (state.sidebar.opened) {
|
||||
Cookies.set('sidebarStatus', 1)
|
||||
} else {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
}
|
||||
},
|
||||
CLOSE_SIDEBAR: (state, withoutAnimation) => {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
state.sidebar.opened = false
|
||||
state.sidebar.withoutAnimation = withoutAnimation
|
||||
},
|
||||
TOGGLE_DEVICE: (state, device) => {
|
||||
state.device = device
|
||||
},
|
||||
SET_SIDEBAR_LIST: (state, sidebar) => {
|
||||
state.sidebarList = sidebar
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
toggleSideBar({ commit }) {
|
||||
commit('TOGGLE_SIDEBAR')
|
||||
},
|
||||
closeSideBar({ commit }, { withoutAnimation }) {
|
||||
commit('CLOSE_SIDEBAR', withoutAnimation)
|
||||
},
|
||||
toggleDevice({ commit }, device) {
|
||||
commit('TOGGLE_DEVICE', device)
|
||||
},
|
||||
setSidebarList({ commit }, sidebarList) {
|
||||
commit('SET_SIDEBAR_LIST', sidebarList)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
31
src/store/modules/settings.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import defaultSettings from '@/assets/js/utils/settings'
|
||||
|
||||
const { showSettings, fixedHeader, sidebarLogo } = defaultSettings
|
||||
|
||||
const state = {
|
||||
showSettings: showSettings,
|
||||
fixedHeader: fixedHeader,
|
||||
sidebarLogo: sidebarLogo
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
CHANGE_SETTING: (state, { key, value }) => {
|
||||
console.log(state, {key, value},'23232');
|
||||
if (state.hasOwnProperty(key)) {
|
||||
state[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
changeSetting({ commit }, data) {
|
||||
commit('CHANGE_SETTING', data)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
97
src/store/modules/user.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import { login, logout, getInfo } from '@/api/app/user'
|
||||
import { getToken, setToken, removeToken } from '@/assets/js/utils/auth'
|
||||
|
||||
const state = {
|
||||
token: getToken(),
|
||||
name: '',
|
||||
avatar: ''
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
getSid({ commit }, data) {
|
||||
commit('SET_SID', data)
|
||||
},
|
||||
setGroupList({ commit }, data) {
|
||||
commit('SET_GROUPLIST', data)
|
||||
},
|
||||
setToken({ commit },data){
|
||||
commit('SET_TOKEN', data)
|
||||
},
|
||||
// user login
|
||||
login({ commit }, userInfo) {
|
||||
const { username, password } = userInfo
|
||||
return new Promise((resolve, reject) => {
|
||||
login({ username: username.trim(), password: password })
|
||||
.then(res => {
|
||||
commit('SET_TOKEN', res.token)
|
||||
setToken(res.token)
|
||||
resolve()
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// get user info
|
||||
getInfo({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo(state.token)
|
||||
.then(res => {
|
||||
if (!res) {
|
||||
reject('Verification failed, please Login again.')
|
||||
}
|
||||
|
||||
commit('SET_NAME', res.name)
|
||||
commit('SET_AVATAR', res.avatar)
|
||||
resolve(res)
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// user logout
|
||||
logout({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout(state.token)
|
||||
.then(() => {
|
||||
commit('SET_TOKEN', '')
|
||||
removeToken()
|
||||
resolve()
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// remove token
|
||||
resetToken({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
commit('SET_TOKEN', '')
|
||||
removeToken()
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
218
src/vendor/Export2Excel.js
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
/* eslint-disable */
|
||||
import { saveAs } from 'file-saver'
|
||||
import XLSX from 'xlsx'
|
||||
|
||||
function generateArray(table) {
|
||||
var out = []
|
||||
var rows = table.querySelectorAll('tr')
|
||||
var ranges = []
|
||||
for (var R = 0; R < rows.length; ++R) {
|
||||
var outRow = []
|
||||
var row = rows[R]
|
||||
var columns = row.querySelectorAll('td')
|
||||
for (var C = 0; C < columns.length; ++C) {
|
||||
var cell = columns[C]
|
||||
var colspan = cell.getAttribute('colspan')
|
||||
var rowspan = cell.getAttribute('rowspan')
|
||||
var cellValue = cell.innerText
|
||||
if (cellValue !== '' && cellValue == +cellValue) cellValue = +cellValue
|
||||
|
||||
//Skip ranges
|
||||
ranges.forEach(function(range) {
|
||||
if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
|
||||
for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null)
|
||||
}
|
||||
})
|
||||
|
||||
//Handle Row Span
|
||||
if (rowspan || colspan) {
|
||||
rowspan = rowspan || 1
|
||||
colspan = colspan || 1
|
||||
ranges.push({
|
||||
s: {
|
||||
r: R,
|
||||
c: outRow.length
|
||||
},
|
||||
e: {
|
||||
r: R + rowspan - 1,
|
||||
c: outRow.length + colspan - 1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//Handle Value
|
||||
outRow.push(cellValue !== '' ? cellValue : null)
|
||||
|
||||
//Handle Colspan
|
||||
if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null)
|
||||
}
|
||||
out.push(outRow)
|
||||
}
|
||||
return [out, ranges]
|
||||
}
|
||||
|
||||
function datenum(v, date1904) {
|
||||
if (date1904) v += 1462
|
||||
var epoch = Date.parse(v)
|
||||
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000)
|
||||
}
|
||||
|
||||
function sheet_from_array_of_arrays(data, opts) {
|
||||
var ws = {}
|
||||
var range = {
|
||||
s: {
|
||||
c: 10000000,
|
||||
r: 10000000
|
||||
},
|
||||
e: {
|
||||
c: 0,
|
||||
r: 0
|
||||
}
|
||||
}
|
||||
for (var R = 0; R != data.length; ++R) {
|
||||
for (var C = 0; C != data[R].length; ++C) {
|
||||
if (range.s.r > R) range.s.r = R
|
||||
if (range.s.c > C) range.s.c = C
|
||||
if (range.e.r < R) range.e.r = R
|
||||
if (range.e.c < C) range.e.c = C
|
||||
var cell = {
|
||||
v: data[R][C]
|
||||
}
|
||||
if (cell.v == null) continue
|
||||
var cell_ref = XLSX.utils.encode_cell({
|
||||
c: C,
|
||||
r: R
|
||||
})
|
||||
|
||||
if (typeof cell.v === 'number') cell.t = 'n'
|
||||
else if (typeof cell.v === 'boolean') cell.t = 'b'
|
||||
else if (cell.v instanceof Date) {
|
||||
cell.t = 'n'
|
||||
cell.z = XLSX.SSF._table[14]
|
||||
cell.v = datenum(cell.v)
|
||||
} else cell.t = 's'
|
||||
|
||||
ws[cell_ref] = cell
|
||||
}
|
||||
}
|
||||
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range)
|
||||
return ws
|
||||
}
|
||||
|
||||
function Workbook() {
|
||||
if (!(this instanceof Workbook)) return new Workbook()
|
||||
this.SheetNames = []
|
||||
this.Sheets = {}
|
||||
}
|
||||
|
||||
function s2ab(s) {
|
||||
var buf = new ArrayBuffer(s.length)
|
||||
var view = new Uint8Array(buf)
|
||||
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
|
||||
return buf
|
||||
}
|
||||
|
||||
export function export_table_to_excel(id) {
|
||||
var theTable = document.getElementById(id)
|
||||
var oo = generateArray(theTable)
|
||||
var ranges = oo[1]
|
||||
|
||||
/* original data */
|
||||
var data = oo[0]
|
||||
var ws_name = 'SheetJS'
|
||||
|
||||
var wb = new Workbook(),
|
||||
ws = sheet_from_array_of_arrays(data)
|
||||
|
||||
/* add ranges to worksheet */
|
||||
// ws['!cols'] = ['apple', 'banan'];
|
||||
ws['!merges'] = ranges
|
||||
|
||||
/* add worksheet to workbook */
|
||||
wb.SheetNames.push(ws_name)
|
||||
wb.Sheets[ws_name] = ws
|
||||
|
||||
var wbout = XLSX.write(wb, {
|
||||
bookType: 'xlsx',
|
||||
bookSST: false,
|
||||
type: 'binary'
|
||||
})
|
||||
|
||||
saveAs(
|
||||
new Blob([s2ab(wbout)], {
|
||||
type: 'application/octet-stream'
|
||||
}),
|
||||
'test.xlsx'
|
||||
)
|
||||
}
|
||||
|
||||
export function export_json_to_excel({ multiHeader = [], header, data, filename, merges = [], autoWidth = true, bookType = 'xlsx' } = {}) {
|
||||
/* original data */
|
||||
filename = filename || 'excel-list'
|
||||
data = [...data]
|
||||
data.unshift(header)
|
||||
|
||||
for (let i = multiHeader.length - 1; i > -1; i--) {
|
||||
data.unshift(multiHeader[i])
|
||||
}
|
||||
|
||||
var ws_name = 'SheetJS'
|
||||
var wb = new Workbook(),
|
||||
ws = sheet_from_array_of_arrays(data)
|
||||
|
||||
if (merges.length > 0) {
|
||||
if (!ws['!merges']) ws['!merges'] = []
|
||||
merges.forEach(item => {
|
||||
ws['!merges'].push(XLSX.utils.decode_range(item))
|
||||
})
|
||||
}
|
||||
|
||||
if (autoWidth) {
|
||||
/*设置worksheet每列的最大宽度*/
|
||||
const colWidth = data.map(row =>
|
||||
row.map(val => {
|
||||
/*先判断是否为null/undefined*/
|
||||
if (val == null) {
|
||||
return {
|
||||
wch: 10
|
||||
}
|
||||
} else if (val.toString().charCodeAt(0) > 255) {
|
||||
/*再判断是否为中文*/
|
||||
return {
|
||||
wch: val.toString().length * 2
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
wch: val.toString().length
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
/*以第一行为初始值*/
|
||||
let result = colWidth[0]
|
||||
for (let i = 1; i < colWidth.length; i++) {
|
||||
for (let j = 0; j < colWidth[i].length; j++) {
|
||||
if (result[j]['wch'] < colWidth[i][j]['wch']) {
|
||||
result[j]['wch'] = colWidth[i][j]['wch']
|
||||
}
|
||||
}
|
||||
}
|
||||
ws['!cols'] = result
|
||||
}
|
||||
|
||||
/* add worksheet to workbook */
|
||||
wb.SheetNames.push(ws_name)
|
||||
wb.Sheets[ws_name] = ws
|
||||
|
||||
var wbout = XLSX.write(wb, {
|
||||
bookType: bookType,
|
||||
bookSST: false,
|
||||
type: 'binary'
|
||||
})
|
||||
saveAs(
|
||||
new Blob([s2ab(wbout)], {
|
||||
type: 'application/octet-stream'
|
||||
}),
|
||||
`${filename}.${bookType}`
|
||||
)
|
||||
}
|
||||
29
src/vendor/Export2Zip.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/* eslint-disable */
|
||||
import { saveAs } from 'file-saver'
|
||||
import JSZip from 'jszip'
|
||||
|
||||
export function export_txt_to_zip(th, jsonData, txtName, zipName) {
|
||||
const zip = new JSZip()
|
||||
const txt_name = txtName || 'file'
|
||||
const zip_name = zipName || 'file'
|
||||
const data = jsonData
|
||||
let txtData = `${th}\r\n`
|
||||
data.forEach(row => {
|
||||
let tempStr = ''
|
||||
tempStr = row.toString()
|
||||
txtData += `${tempStr}\r\n`
|
||||
})
|
||||
zip.file(`${txt_name}.txt`, txtData)
|
||||
zip
|
||||
.generateAsync({
|
||||
type: 'blob'
|
||||
})
|
||||
.then(
|
||||
blob => {
|
||||
saveAs(blob, `${zip_name}.zip`)
|
||||
},
|
||||
err => {
|
||||
alert('导出失败')
|
||||
}
|
||||
)
|
||||
}
|
||||
239
src/views/app/404.vue
Normal file
@@ -0,0 +1,239 @@
|
||||
<template>
|
||||
<div class="wscn-http404-container">
|
||||
<div class="wscn-http404">
|
||||
<div class="pic-404">
|
||||
<img class="pic-404__parent" :src="img_404" alt="404" />
|
||||
<img class="pic-404__child left" :src="img_404_cloud" alt="404" />
|
||||
<img class="pic-404__child mid" :src="img_404_cloud" alt="404" />
|
||||
<img class="pic-404__child right" :src="img_404_cloud" alt="404" />
|
||||
</div>
|
||||
<div class="bullshit">
|
||||
<div class="bullshit__oops">OOPS!</div>
|
||||
<div class="bullshit__info">
|
||||
版权所有
|
||||
<a class="link-type" href="http://www.ebiz-interactive.com/" target="_blank">@易商阜极前端团队</a>
|
||||
</div>
|
||||
<div class="bullshit__headline">{{ message }}</div>
|
||||
<div class="bullshit__info">
|
||||
请检查您输入的网址是否正确,请返回上级页面或者联系网管
|
||||
</div>
|
||||
<!--<a href class="bullshit__return-home">返回首页</a>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import img_404 from '@/assets/images/404_img/404.png'
|
||||
import img_404_cloud from '@/assets/images/404_img/404_cloud.png'
|
||||
|
||||
export default {
|
||||
name: 'Page404',
|
||||
data() {
|
||||
return {
|
||||
img_404,
|
||||
img_404_cloud
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
message() {
|
||||
return '当前页面已经消失在黑洞中......'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.wscn-http404-container {
|
||||
transform: translate(-50%, -50%);
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
}
|
||||
.wscn-http404 {
|
||||
position: relative;
|
||||
width: 1200px;
|
||||
padding: 0 50px;
|
||||
overflow: hidden;
|
||||
.pic-404 {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 600px;
|
||||
overflow: hidden;
|
||||
&__parent {
|
||||
width: 100%;
|
||||
}
|
||||
&__child {
|
||||
position: absolute;
|
||||
&.left {
|
||||
width: 80px;
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
animation-name: cloudLeft;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
&.mid {
|
||||
width: 46px;
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
animation-name: cloudMid;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
&.right {
|
||||
width: 62px;
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
animation-name: cloudRight;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
@keyframes cloudLeft {
|
||||
0% {
|
||||
top: 17px;
|
||||
left: 220px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 33px;
|
||||
left: 188px;
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
top: 81px;
|
||||
left: 92px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 97px;
|
||||
left: 60px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes cloudMid {
|
||||
0% {
|
||||
top: 10px;
|
||||
left: 420px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 40px;
|
||||
left: 360px;
|
||||
opacity: 1;
|
||||
}
|
||||
70% {
|
||||
top: 130px;
|
||||
left: 180px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 160px;
|
||||
left: 120px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes cloudRight {
|
||||
0% {
|
||||
top: 100px;
|
||||
left: 500px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: 120px;
|
||||
left: 460px;
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
top: 180px;
|
||||
left: 340px;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 200px;
|
||||
left: 300px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.bullshit {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 300px;
|
||||
padding: 30px 0;
|
||||
overflow: hidden;
|
||||
&__oops {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
line-height: 40px;
|
||||
color: #1482f0;
|
||||
opacity: 0;
|
||||
margin-bottom: 20px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__headline {
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
opacity: 0;
|
||||
margin-bottom: 10px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.1s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__info {
|
||||
font-size: 13px;
|
||||
line-height: 21px;
|
||||
color: grey;
|
||||
opacity: 0;
|
||||
margin-bottom: 30px;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.2s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
&__return-home {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 110px;
|
||||
height: 36px;
|
||||
background: #1482f0;
|
||||
border-radius: 100px;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
opacity: 0;
|
||||
font-size: 14px;
|
||||
line-height: 36px;
|
||||
cursor: pointer;
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-delay: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
@keyframes slideUp {
|
||||
0% {
|
||||
transform: translateY(60px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
39
src/views/app/Home.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div class="home-container pl50 pr50 pb50 pt90 text-center">
|
||||
<!--<p>易商阜极管理系统模版,欢迎您的登入!{{ uerName }}</p>-->
|
||||
<!--<el-button @click="visable = true">测试文件</el-button>-->
|
||||
<!--<r-view :visable.sync="visable" :title="title" :filePath="filePath"> </r-view>-->
|
||||
<img class="homeImg mt60" alt="" src="../../assets/images/home.png" />
|
||||
<div class="fs20 fwb mv20">
|
||||
欢 迎 访 问
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Home',
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
created() {
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
success() {}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['name', 'sidebarLogo'])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.homeImg {
|
||||
width: 250px !important;
|
||||
}
|
||||
</style>
|
||||
21
src/views/app/authentication/authentication.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'authentication',
|
||||
methods: {
|
||||
authentication() {
|
||||
this.$loading({
|
||||
text: '没有当前页面得权限,请重新登陆'
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.authentication()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
40
src/views/app/layout/components/AppMain.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<transition name="fade-transform" mode="out-in">
|
||||
<router-view :key="key" />
|
||||
</transition>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AppMain',
|
||||
computed: {
|
||||
key() {
|
||||
return this.$route.path
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-main {
|
||||
/*50 = navbar */
|
||||
min-height: calc(100vh - 50px);
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.fixed-header + .app-main {
|
||||
padding-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
// fix css style bug in open el-dialog
|
||||
.el-popup-parent--hidden {
|
||||
.fixed-header {
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
140
src/views/app/layout/components/Navbar.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
|
||||
<breadcrumb class="breadcrumb-container" />
|
||||
|
||||
<div class="right-menu" v-if="$store.state.settings.sidebarLogo">
|
||||
<el-dropdown class="avatar-container" trigger="click">
|
||||
<div class="avatar-wrapper">
|
||||
<el-avatar :size="size" :src="circleUrl" class="user-avatar" />
|
||||
<i class="el-icon-caret-bottom" />
|
||||
</div>
|
||||
<el-dropdown-menu slot="dropdown" class="user-dropdown">
|
||||
<router-link to="/">
|
||||
<el-dropdown-item>
|
||||
首页
|
||||
</el-dropdown-item>
|
||||
</router-link>
|
||||
<a target="_blank" href="http://www.ebiz-interactive.com/">
|
||||
<el-dropdown-item>关于</el-dropdown-item>
|
||||
</a>
|
||||
<el-dropdown-item divided>
|
||||
<span style="display:block;" @click="logout">退出</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Breadcrumb from '@/components/Breadcrumb'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
import url from '@/assets/images/active.png'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Breadcrumb,
|
||||
Hamburger
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
circleUrl: url,
|
||||
size: 40
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['sidebar', 'avatar'])
|
||||
},
|
||||
methods: {
|
||||
toggleSideBar() {
|
||||
this.$store.dispatch('app/toggleSideBar')
|
||||
},
|
||||
async logout() {
|
||||
await this.$store.dispatch('user/logout')
|
||||
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
float: right;
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.right-menu-item {
|
||||
display: inline-block;
|
||||
padding: 0 8px;
|
||||
height: 100%;
|
||||
font-size: 18px;
|
||||
color: #5a5e66;
|
||||
vertical-align: text-bottom;
|
||||
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
margin-right: 30px;
|
||||
|
||||
.avatar-wrapper {
|
||||
margin-top: 5px;
|
||||
position: relative;
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.el-icon-caret-bottom {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: -20px;
|
||||
top: 25px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
26
src/views/app/layout/components/Sidebar/FixiOSBug.js
Normal file
@@ -0,0 +1,26 @@
|
||||
export default {
|
||||
computed: {
|
||||
device() {
|
||||
return this.$store.state.app.device
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
|
||||
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
|
||||
this.fixBugIniOS()
|
||||
},
|
||||
methods: {
|
||||
fixBugIniOS() {
|
||||
const $subMenu = this.$refs.subMenu
|
||||
if ($subMenu) {
|
||||
const handleMouseleave = $subMenu.handleMouseleave
|
||||
$subMenu.handleMouseleave = e => {
|
||||
if (this.device === 'mobile') {
|
||||
return
|
||||
}
|
||||
handleMouseleave(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/views/app/layout/components/Sidebar/Item.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'MenuItem',
|
||||
functional: true,
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
render(h, context) {
|
||||
const { icon, title } = context.props
|
||||
const vnodes = []
|
||||
|
||||
if (icon) {
|
||||
vnodes.push(<svg-icon icon-class={icon} />)
|
||||
}
|
||||
|
||||
if (title) {
|
||||
vnodes.push(<span slot="title">{title}</span>)
|
||||
}
|
||||
return vnodes
|
||||
}
|
||||
}
|
||||
</script>
|
||||
35
src/views/app/layout/components/Sidebar/Link.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<!-- eslint-disable vue/require-component-is -->
|
||||
<component v-bind="linkProps(to)">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isExternal } from '@/assets/js/utils/validate'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
linkProps(url) {
|
||||
if (isExternal(url)) {
|
||||
return {
|
||||
is: 'a',
|
||||
href: url,
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
}
|
||||
}
|
||||
return {
|
||||
is: 'router-link',
|
||||
to: url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
83
src/views/app/layout/components/Sidebar/Logo.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div class="sidebar-logo-container" :class="{ collapse: collapse }">
|
||||
<transition name="sidebarLogoFade">
|
||||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
||||
<h1 v-else class="sidebar-title">{{ title }}</h1>
|
||||
</router-link>
|
||||
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
||||
<!--<h1 class="sidebar-title">{{ title }}</h1>-->
|
||||
</router-link>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import u3 from '@/assets/images/icon/u3.png'
|
||||
export default {
|
||||
name: 'SidebarLogo',
|
||||
props: {
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: 'Vue Admin Template',
|
||||
logo: u3
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sidebarLogoFade-enter-active {
|
||||
transition: opacity 1.5s;
|
||||
}
|
||||
|
||||
.sidebarLogoFade-enter,
|
||||
.sidebarLogoFade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.sidebar-logo-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
line-height: 50px;
|
||||
/*background: #2b2f3a;*/
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
|
||||
& .sidebar-logo-link {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
& .sidebar-logo {
|
||||
width: 160px;
|
||||
height: 65px;
|
||||
vertical-align: middle;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
& .sidebar-title {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
line-height: 50px;
|
||||
font-size: 14px;
|
||||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&.collapse {
|
||||
.sidebar-logo {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||