初始化

This commit is contained in:
陈昱达
2025-06-26 17:11:50 +08:00
parent bae9039771
commit 0713c80305
177 changed files with 27014 additions and 0 deletions

14
.editorconfig Normal file
View 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
View File

@@ -0,0 +1,6 @@
# env
NODE_ENV = 'dev' // 如果是生产环境请记得切换为production
# flag
VUE_APP_FLAG='dev'
VUE_APP_ADMIN='http://1.0.0.0'

6
.env.dev Normal file
View File

@@ -0,0 +1,6 @@
# env
NODE_ENV = 'dev' // 如果是生产环境请记得切换为production
# flag
VUE_APP_FLAG='dev'
VUE_APP_ADMIN='http://1.0.0.0'

4
.eslintignore Normal file
View File

@@ -0,0 +1,4 @@
build/*.js
public
dist
node_modules

17
.eslintrc.js Normal file
View 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
View 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
View File

@@ -0,0 +1,7 @@
{
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"printWidth": 160,
"endOfLine": "auto"
}

5
.travis.yml Normal file
View File

@@ -0,0 +1,5 @@
language: node_js
node_js: 10
script: npm run test
notifications:
email: false

6
Deployfile Normal file
View 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
View 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
View File

@@ -0,0 +1,5 @@
{
"groupId":"com.ebiz",
"artifactId":"ebiz-product-factory-backmanege-h5",
"file":"./dist"
}

188
README.md
View 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
View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
}

24
jest.config.js Normal file
View 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
View 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.2.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.15.6",
"swiper": "^5.4.5",
"vue": "2.6.10",
"vue-router": "3.0.6",
"vue2-editor": "^2.10.2",
"vuex": "3.1.0",
"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.16.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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

21
public/index.html Normal file
View 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
View 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
View 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'
})
}

View File

@@ -0,0 +1,4 @@
import request from '@/assets/js/utils/request'
import getUrl from '@/assets/js/utils/get-url'
export default {
}

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
src/assets/images/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
src/assets/images/rs/t1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

BIN
src/assets/images/rs/t2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
src/assets/images/rs/t3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src/assets/images/rs/t4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
src/assets/images/rs/t5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View 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
View 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, ' ') +
'"}'
)
}

View 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
})
}
}

View 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)
}

View 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 }

View 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}`
}

View 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
}

View 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()
})

View 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

View 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: ''
}

View 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

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More