10
.babelrc
|
@ -1,8 +1,12 @@
|
||||||
{
|
{
|
||||||
"presets": [
|
"presets": [
|
||||||
["env", { "modules": false }],
|
["env", {
|
||||||
|
"modules": false,
|
||||||
|
"targets": {
|
||||||
|
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||||
|
}
|
||||||
|
}],
|
||||||
"stage-2"
|
"stage-2"
|
||||||
],
|
],
|
||||||
"plugins": ["transform-runtime"],
|
"plugins": ["transform-vue-jsx", "transform-runtime"]
|
||||||
"comments": false
|
|
||||||
}
|
}
|
||||||
|
|
99
.eslintrc.js
|
@ -26,25 +26,49 @@ module.exports = {
|
||||||
//it is base on https://github.com/vuejs/eslint-config-vue
|
//it is base on https://github.com/vuejs/eslint-config-vue
|
||||||
'rules': {
|
'rules': {
|
||||||
'accessor-pairs': 2,
|
'accessor-pairs': 2,
|
||||||
'arrow-spacing': [2, { 'before': true, 'after': true }],
|
'arrow-spacing': [2, {
|
||||||
|
'before': true,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
'block-spacing': [2, 'always'],
|
'block-spacing': [2, 'always'],
|
||||||
'brace-style': [2, '1tbs', { 'allowSingleLine': true }],
|
'brace-style': [2, '1tbs', {
|
||||||
'camelcase': [0, { 'properties': 'always' }],
|
'allowSingleLine': true
|
||||||
|
}],
|
||||||
|
'camelcase': [0, {
|
||||||
|
'properties': 'always'
|
||||||
|
}],
|
||||||
'comma-dangle': [2, 'never'],
|
'comma-dangle': [2, 'never'],
|
||||||
'comma-spacing': [2, { 'before': false, 'after': true }],
|
'comma-spacing': [2, {
|
||||||
|
'before': false,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
'comma-style': [2, 'last'],
|
'comma-style': [2, 'last'],
|
||||||
'constructor-super': 2,
|
'constructor-super': 2,
|
||||||
'curly': [2, 'multi-line'],
|
'curly': [2, 'multi-line'],
|
||||||
'dot-location': [2, 'property'],
|
'dot-location': [2, 'property'],
|
||||||
'eol-last': 2,
|
'eol-last': 2,
|
||||||
'eqeqeq': [2, 'allow-null'],
|
'eqeqeq': [2, 'allow-null'],
|
||||||
'generator-star-spacing': [2, { 'before': true, 'after': true }],
|
'generator-star-spacing': [2, {
|
||||||
'handle-callback-err': [2, '^(err|error)$' ],
|
'before': true,
|
||||||
'indent': [2, 2, { 'SwitchCase': 1 }],
|
'after': true
|
||||||
|
}],
|
||||||
|
'handle-callback-err': [2, '^(err|error)$'],
|
||||||
|
'indent': [2, 2, {
|
||||||
|
'SwitchCase': 1
|
||||||
|
}],
|
||||||
'jsx-quotes': [2, 'prefer-single'],
|
'jsx-quotes': [2, 'prefer-single'],
|
||||||
'key-spacing': [2, { 'beforeColon': false, 'afterColon': true }],
|
'key-spacing': [2, {
|
||||||
'keyword-spacing': [2, { 'before': true, 'after': true }],
|
'beforeColon': false,
|
||||||
'new-cap': [2, { 'newIsCap': true, 'capIsNew': false }],
|
'afterColon': true
|
||||||
|
}],
|
||||||
|
'keyword-spacing': [2, {
|
||||||
|
'before': true,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
|
'new-cap': [2, {
|
||||||
|
'newIsCap': true,
|
||||||
|
'capIsNew': false
|
||||||
|
}],
|
||||||
'new-parens': 2,
|
'new-parens': 2,
|
||||||
'no-array-constructor': 2,
|
'no-array-constructor': 2,
|
||||||
'no-caller': 2,
|
'no-caller': 2,
|
||||||
|
@ -52,7 +76,7 @@ module.exports = {
|
||||||
'no-class-assign': 2,
|
'no-class-assign': 2,
|
||||||
'no-cond-assign': 2,
|
'no-cond-assign': 2,
|
||||||
'no-const-assign': 2,
|
'no-const-assign': 2,
|
||||||
'no-control-regex': 2,
|
'no-control-regex': 0,
|
||||||
'no-delete-var': 2,
|
'no-delete-var': 2,
|
||||||
'no-dupe-args': 2,
|
'no-dupe-args': 2,
|
||||||
'no-dupe-class-members': 2,
|
'no-dupe-class-members': 2,
|
||||||
|
@ -75,12 +99,17 @@ module.exports = {
|
||||||
'no-irregular-whitespace': 2,
|
'no-irregular-whitespace': 2,
|
||||||
'no-iterator': 2,
|
'no-iterator': 2,
|
||||||
'no-label-var': 2,
|
'no-label-var': 2,
|
||||||
'no-labels': [2, { 'allowLoop': false, 'allowSwitch': false }],
|
'no-labels': [2, {
|
||||||
|
'allowLoop': false,
|
||||||
|
'allowSwitch': false
|
||||||
|
}],
|
||||||
'no-lone-blocks': 2,
|
'no-lone-blocks': 2,
|
||||||
'no-mixed-spaces-and-tabs': 2,
|
'no-mixed-spaces-and-tabs': 2,
|
||||||
'no-multi-spaces': 2,
|
'no-multi-spaces': 2,
|
||||||
'no-multi-str': 2,
|
'no-multi-str': 2,
|
||||||
'no-multiple-empty-lines': [2, { 'max': 1 }],
|
'no-multiple-empty-lines': [2, {
|
||||||
|
'max': 1
|
||||||
|
}],
|
||||||
'no-native-reassign': 2,
|
'no-native-reassign': 2,
|
||||||
'no-negated-in-lhs': 2,
|
'no-negated-in-lhs': 2,
|
||||||
'no-new-object': 2,
|
'no-new-object': 2,
|
||||||
|
@ -108,28 +137,51 @@ module.exports = {
|
||||||
'no-undef-init': 2,
|
'no-undef-init': 2,
|
||||||
'no-unexpected-multiline': 2,
|
'no-unexpected-multiline': 2,
|
||||||
'no-unmodified-loop-condition': 2,
|
'no-unmodified-loop-condition': 2,
|
||||||
'no-unneeded-ternary': [2, { 'defaultAssignment': false }],
|
'no-unneeded-ternary': [2, {
|
||||||
|
'defaultAssignment': false
|
||||||
|
}],
|
||||||
'no-unreachable': 2,
|
'no-unreachable': 2,
|
||||||
'no-unsafe-finally': 2,
|
'no-unsafe-finally': 2,
|
||||||
'no-unused-vars': [2, { 'vars': 'all', 'args': 'none' }],
|
'no-unused-vars': [2, {
|
||||||
|
'vars': 'all',
|
||||||
|
'args': 'none'
|
||||||
|
}],
|
||||||
'no-useless-call': 2,
|
'no-useless-call': 2,
|
||||||
'no-useless-computed-key': 2,
|
'no-useless-computed-key': 2,
|
||||||
'no-useless-constructor': 2,
|
'no-useless-constructor': 2,
|
||||||
'no-useless-escape': 0,
|
'no-useless-escape': 0,
|
||||||
'no-whitespace-before-property': 2,
|
'no-whitespace-before-property': 2,
|
||||||
'no-with': 2,
|
'no-with': 2,
|
||||||
'one-var': [2, { 'initialized': 'never' }],
|
'one-var': [2, {
|
||||||
'operator-linebreak': [2, 'after', { 'overrides': { '?': 'before', ':': 'before' } }],
|
'initialized': 'never'
|
||||||
|
}],
|
||||||
|
'operator-linebreak': [2, 'after', {
|
||||||
|
'overrides': {
|
||||||
|
'?': 'before',
|
||||||
|
':': 'before'
|
||||||
|
}
|
||||||
|
}],
|
||||||
'padded-blocks': [2, 'never'],
|
'padded-blocks': [2, 'never'],
|
||||||
'quotes': [2, 'single', { 'avoidEscape': true, 'allowTemplateLiterals': true }],
|
'quotes': [2, 'single', {
|
||||||
|
'avoidEscape': true,
|
||||||
|
'allowTemplateLiterals': true
|
||||||
|
}],
|
||||||
'semi': [2, 'never'],
|
'semi': [2, 'never'],
|
||||||
'semi-spacing': [2, { 'before': false, 'after': true }],
|
'semi-spacing': [2, {
|
||||||
|
'before': false,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
'space-before-blocks': [2, 'always'],
|
'space-before-blocks': [2, 'always'],
|
||||||
'space-before-function-paren': [2, 'never'],
|
'space-before-function-paren': [2, 'never'],
|
||||||
'space-in-parens': [2, 'never'],
|
'space-in-parens': [2, 'never'],
|
||||||
'space-infix-ops': 2,
|
'space-infix-ops': 2,
|
||||||
'space-unary-ops': [2, { 'words': true, 'nonwords': false }],
|
'space-unary-ops': [2, {
|
||||||
'spaced-comment': [2, 'always', { 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] }],
|
'words': true,
|
||||||
|
'nonwords': false
|
||||||
|
}],
|
||||||
|
'spaced-comment': [2, 'always', {
|
||||||
|
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
|
||||||
|
}],
|
||||||
'template-curly-spacing': [2, 'never'],
|
'template-curly-spacing': [2, 'never'],
|
||||||
'use-isnan': 2,
|
'use-isnan': 2,
|
||||||
'valid-typeof': 2,
|
'valid-typeof': 2,
|
||||||
|
@ -138,7 +190,10 @@ module.exports = {
|
||||||
'yoda': [2, 'never'],
|
'yoda': [2, 'never'],
|
||||||
'prefer-const': 2,
|
'prefer-const': 2,
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||||
'object-curly-spacing': [2, 'always', { objectsInObjects: false }],
|
'object-curly-spacing': [2, 'always', {
|
||||||
|
objectsInObjects: false
|
||||||
|
}],
|
||||||
'array-bracket-spacing': [2, 'never']
|
'array-bracket-spacing': [2, 'never']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
static/ckeditor
|
npm-debug.log*
|
||||||
gifs/
|
yarn-debug.log*
|
||||||
npm-debug.log
|
yarn-error.log*
|
||||||
|
|
||||||
test/unit/coverage
|
test/unit/coverage
|
||||||
test/e2e/reports
|
test/e2e/reports
|
||||||
selenium-debug.log
|
selenium-debug.log
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
.idea
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"plugins": {
|
"plugins": {
|
||||||
// to edit target browsers: use "browserlist" field in package.json
|
"postcss-import": {},
|
||||||
|
"postcss-url": {},
|
||||||
|
// to edit target browsers: use "browserslist" field in package.json
|
||||||
"autoprefixer": {}
|
"autoprefixer": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
language: node_js
|
||||||
|
node_js: stable
|
||||||
|
script: npm run test
|
||||||
|
notifications:
|
||||||
|
email: false
|
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 PanJiaChen
|
Copyright (c) 2017-present PanJiaChen
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
176
README-en.md
|
@ -1,176 +0,0 @@
|
||||||
## Intro
|
|
||||||
|
|
||||||
> In the past half year, I have been building a backend for management dashboard using Vue. Though the backend has contained greater than 70 pages and over 10 permissions, it still takes insignificant effort to maintain the project. So I decide to make it open source so as to share my development experience and progress on backend. The tech stack is mainly [Vue.js](https://github.com/vuejs/vue)+[Element](https://github.com/ElemeFE/element)+[axios](https://github.com/mzabriskie/axios). Since it's a personal project, all data requests are simulated with [Mock.js](https://github.com/nuysoft/Mock). **Note:** if anyone wants to modify or develop based on this project, please remove the mock files.
|
|
||||||
|
|
||||||
**Live demo:** http://panjiachen.github.io/vue-element-admin
|
|
||||||
|
|
||||||
**Note: element-ui@1.3.3 is used in the project, so vue 2.3.0+ is required.**
|
|
||||||
|
|
||||||
More tutorials incoming. Including articles on:
|
|
||||||
|
|
||||||
- How to build structure of a backend dashboard project from scratch
|
|
||||||
- How to make a complete user system (e.g. permission authentication, two-factor authentication)
|
|
||||||
- How to package components (e.g. rich text)
|
|
||||||
- How to integrate with [Qiniu](https://www.qiniu.com/)
|
|
||||||
- Other development experience on backend
|
|
||||||
|
|
||||||
Join the group on QQ 591724180.
|
|
||||||
|
|
||||||
**Tutorials:**
|
|
||||||
|
|
||||||
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
|
||||||
- [Step by step instructions on playing with backend using Vue Part 1 - Fundamentals](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
|
||||||
- [Step by step instructions on playing with backend using Vue Part 2 - Login permission](https://juejin.im/post/591aa14f570c35006961acac)
|
|
||||||
- [Step by step instructions on packaging a Vue component](https://segmentfault.com/a/1190000009090836)
|
|
||||||
|
|
||||||
**Please read the Wiki and articles above before creating any issue. Feel free to contribute by making a pull request.**
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Login/Logout
|
|
||||||
- Permission authentication
|
|
||||||
- Sidebar
|
|
||||||
- Breadcrumb
|
|
||||||
- Rich text editor
|
|
||||||
- Markdown editor
|
|
||||||
- JSON editor
|
|
||||||
- Drag & drop list
|
|
||||||
- SplitPane
|
|
||||||
- Dropzone
|
|
||||||
- Sticky
|
|
||||||
- CountTo
|
|
||||||
- ECharts
|
|
||||||
- 401, 404 error page
|
|
||||||
- Error log
|
|
||||||
- Exporting to Excel
|
|
||||||
- Table example
|
|
||||||
- Interactive table example
|
|
||||||
- Drag & drop table example
|
|
||||||
- Form example
|
|
||||||
- Multi-environments distribution
|
|
||||||
- Dashboard
|
|
||||||
- Two-factor authentication
|
|
||||||
- Collapsing sidebar (support nested routes)
|
|
||||||
- Mock data
|
|
||||||
- cache tabs example
|
|
||||||
- screenfull
|
|
||||||
- markdown2html
|
|
||||||
- views-tab
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clone project
|
|
||||||
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# Or (not recommended for cnpm due to unknown bugs, use taobao mirror instead)
|
|
||||||
npm install --registry=https://registry.npm.taobao.org
|
|
||||||
|
|
||||||
# Run local dev server
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
Visit in browser: http://localhost:9527
|
|
||||||
|
|
||||||
## Distribution
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build staged environment with webpack-bundle-analyzer
|
|
||||||
npm run build:sit-preview
|
|
||||||
|
|
||||||
# Build production environment
|
|
||||||
npm run build:prod
|
|
||||||
```
|
|
||||||
|
|
||||||
## Directory structure
|
|
||||||
|
|
||||||
```
|
|
||||||
├── build // build
|
|
||||||
├── config // config
|
|
||||||
├── src // source code
|
|
||||||
│ ├── api // all requests
|
|
||||||
│ ├── assets // static resource like themes, fonts
|
|
||||||
│ ├── components // global public components
|
|
||||||
│ ├── directive // global directive
|
|
||||||
│ ├── filters // global filters
|
|
||||||
│ ├── mock // mock data
|
|
||||||
│ ├── router // router
|
|
||||||
│ ├── store // global status management
|
|
||||||
│ ├── styles // global styles
|
|
||||||
│ ├── utils // global public functions
|
|
||||||
│ ├── view // view
|
|
||||||
│ ├── App.vue // entry view
|
|
||||||
│ └── main.js // entry for loading components, initialization
|
|
||||||
├── static // third-party libraries not packed with Webpack
|
|
||||||
│ └── Tinymce // rich text
|
|
||||||
├── .babelrc // babel-loader config
|
|
||||||
├── eslintrc.js // eslint config
|
|
||||||
├── .gitignore // gitignore
|
|
||||||
├── favicon.ico // favicon
|
|
||||||
├── index.html // html template
|
|
||||||
└── package.json // package.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
|
||||||
|
|
||||||
## State Management
|
|
||||||
|
|
||||||
Only status of user and app configuration is managed by Vuex. Other data are managed by their own business pages.
|
|
||||||
|
|
||||||
## Demo
|
|
||||||
|
|
||||||
#### Two-factor authentication, supporting WeChat and QQ
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/2login.gif)
|
|
||||||
|
|
||||||
#### Realtime switching themes
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/theme.gif)
|
|
||||||
|
|
||||||
#### tabs
|
|
||||||
|
|
||||||
![tabs](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/tabs.gif)<br />
|
|
||||||
|
|
||||||
#### Collapsing sidebar
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/leftmenu.gif)
|
|
||||||
|
|
||||||
#### Drag & drop table
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/order.gif)
|
|
||||||
|
|
||||||
#### Interactive table
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/dynamictable.gif)
|
|
||||||
|
|
||||||
#### Uploading cropped avatar
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/uploadAvatar.gif)
|
|
||||||
|
|
||||||
#### Error log
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/errorlog.gif)
|
|
||||||
|
|
||||||
#### Rich text (integrated with Qiniu, watermark and customization)
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/editor.gif)
|
|
||||||
|
|
||||||
#### Packaging table component
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/table.gif)
|
|
||||||
|
|
||||||
#### Charts
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/echarts.gif)
|
|
||||||
|
|
||||||
#### Exporting to Excel
|
|
||||||
|
|
||||||
![](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/excel.png)
|
|
||||||
|
|
||||||
#### More
|
|
||||||
|
|
||||||
http://panjiachen.github.io/vue-element-admin
|
|
266
README.md
|
@ -1,198 +1,158 @@
|
||||||
# vue-element-admin #
|
<p align="center">
|
||||||
|
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
|
||||||
|
</p>
|
||||||
|
|
||||||
[![vue](https://img.shields.io/badge/vue-2.4.2-brightgreen.svg)](https://github.com/vuejs/vue)
|
<p align="center">
|
||||||
[![element-ui](https://img.shields.io/badge/element--ui-1.4.1-brightgreen.svg)](https://github.com/ElemeFE/element)
|
<a href="https://github.com/vuejs/vue">
|
||||||
[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
<img src="https://img.shields.io/badge/vue-2.5.10-brightgreen.svg" alt="vue">
|
||||||
[![GitHub release](https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg)]()
|
</a>
|
||||||
|
<a href="https://github.com/ElemeFE/element">
|
||||||
|
<img src="https://img.shields.io/badge/element--ui-2.3.0-brightgreen.svg" alt="element-ui">
|
||||||
|
</a>
|
||||||
|
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
|
||||||
|
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
|
||||||
|
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
English | [简体中文](./README.zh-CN.md)
|
||||||
|
|
||||||
[线上地址](http://panjiachen.github.io/vue-element-admin)
|
## Introduction
|
||||||
|
|
||||||
[English Document](https://github.com/PanJiaChen/vue-element-admin/blob/master/README-en.md)
|
`vue-element-admin` is a production-ready solution for admin interfaces. Based on [Vue.js](https://github.com/vuejs/vue) and use the UI Toolkit -- [element](https://github.com/ElemeFE/element). `vue-element-admin` is a magical vue admin, it based on the newest development stack of vue, built-in i18n solution, typical templates for enterprise applications, lots of awesome features. It helps you build a large complex Single-Page Applications. I believe whatever your needs are, this project will help you.
|
||||||
|
|
||||||
[wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
- [Preview](http://panjiachen.github.io/vue-element-admin)
|
||||||
|
|
||||||
**本项目的定位是后台集成方案,不适合当基础模板来开发,模板建议使用 [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template) , 桌面端 [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)**
|
- [Documentation](https://panjiachen.github.io/vue-element-admin-site/#/)
|
||||||
|
|
||||||
|
- [Gitter](https://gitter.im/vue-element-admin/discuss)
|
||||||
|
|
||||||
|
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||||
|
|
||||||
**注意:该项目目前使用element-ui@1.4.1版本,所以最低兼容 Vue 2.3.0**
|
- [Donate](https://panjiachen.github.io/vue-element-admin-site/#/donate)
|
||||||
|
|
||||||
## 前言
|
**vue-element-admin is a admin interfaces integration solution, which is not suitable for secondary development as a base template.**
|
||||||
> 这半年来一直在用vue写管理后台,目前后台已经有百来个页面,十几种权限,但维护成本依然很低,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包。由于是个人项目,所以数据请求都是用了mockjs模拟。注意:在此项目基础上改造开发时请移除mock文件。
|
|
||||||
|
|
||||||
|
- Base template recommends using: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||||
|
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
|
|
||||||
写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目:
|
**Note: This project uses element-ui@2.3.0+ version, so the minimum compatible vue@2.5.0+**
|
||||||
|
|
||||||
- [wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
## Preparation
|
||||||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
|
||||||
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
|
|
||||||
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
|
|
||||||
- [手摸手,带你用vue撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
|
|
||||||
- [手摸手,带你封装一个vue component](https://segmentfault.com/a/1190000009090836)
|
|
||||||
|
|
||||||
相应需求,开了一个qq群 `591724180` 方便大家交流
|
You need to install [node](http://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) 和 [element-ui](https://github.com/ElemeFE/element). All data requests for this project are simulated using [Mock.js](https://github.com/nuysoft/Mock). It would be helpful if you have pre-existing knowledge on those.
|
||||||
|
|
||||||
**如有问题请先看上述文章和Wiki,若不能满足,欢迎 issue 和 pr ~**
|
**This project is not a scaffolding and is more of an integrated solution.**
|
||||||
|
|
||||||
**该项目并不是一个脚手架,更倾向于是一个集成解决方案**
|
**This project does not support low version browsers (e.g. IE). Please add polyfill yourself if you need them.**
|
||||||
|
|
||||||
**该项目不支持低版本游览器,有需求请自行添加polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
<p align="center">
|
||||||
|
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Features
|
||||||
## 功能
|
```
|
||||||
- 登录/注销
|
- Login / Logout
|
||||||
- 权限验证
|
- Permission authentication
|
||||||
- 侧边栏
|
- Multi-environment build
|
||||||
- 面包屑
|
- Dynamic sidebar (supports multi-level routing)
|
||||||
- 富文本编辑器
|
- Dynamic breadcrumb
|
||||||
- Markdown编辑器
|
- I18n
|
||||||
- JSON编辑器
|
- Customizable theme
|
||||||
- 列表拖拽
|
- Tags-view(Tab page Support right-click operation)
|
||||||
- plitPane
|
- Rich text editor
|
||||||
|
- Markdown editor
|
||||||
|
- JSON editor
|
||||||
|
- Screenfull
|
||||||
|
- Drag and drop list
|
||||||
|
- Svg Sprite
|
||||||
|
- Dashboard
|
||||||
|
- Mock data
|
||||||
|
- Echarts
|
||||||
|
- Clipboard
|
||||||
|
- 401/404 error page
|
||||||
|
- Error log
|
||||||
|
- Export excel
|
||||||
|
- Export zip
|
||||||
|
- Front-end visualization excel
|
||||||
|
- Tree Table
|
||||||
|
- Table example
|
||||||
|
- Dynamictable example
|
||||||
|
- Drag and drop table example
|
||||||
|
- Inline edit table example
|
||||||
|
- Form example
|
||||||
|
- Two-step login
|
||||||
|
- SplitPane
|
||||||
|
- Drag Dialog
|
||||||
- Dropzone
|
- Dropzone
|
||||||
- Sticky
|
- Sticky
|
||||||
- CountTo
|
- CountTo
|
||||||
- echarts图表
|
- Markdown to html
|
||||||
- 401,404错误页面
|
```
|
||||||
- 错误日志
|
|
||||||
- 导出excel
|
|
||||||
- table example
|
|
||||||
- 动态table example
|
|
||||||
- 拖拽table example
|
|
||||||
- 内联编辑table example
|
|
||||||
- form example
|
|
||||||
- 多环境发布
|
|
||||||
- dashboard
|
|
||||||
- 二次登录
|
|
||||||
- 动态侧边栏(支持多级路由)
|
|
||||||
- mock数据
|
|
||||||
- cache tabs example
|
|
||||||
- screenfull
|
|
||||||
- markdown2html
|
|
||||||
- views-tab
|
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
## 开发
|
|
||||||
```bash
|
```bash
|
||||||
# 克隆项目
|
# clone the project
|
||||||
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
||||||
|
|
||||||
# 安装依赖
|
# install dependency
|
||||||
npm install
|
npm install
|
||||||
//or # 建议不要用cnpm 安装有各种诡异的bug 可以通过如下操作解决npm速度慢的问题
|
|
||||||
npm install --registry=https://registry.npm.taobao.org
|
|
||||||
|
|
||||||
# 本地开发 开启服务
|
# develop
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
浏览器访问 http://localhost:9527
|
|
||||||
|
|
||||||
## 发布
|
This will automatically open http://localhost:9527.
|
||||||
|
|
||||||
|
## Build
|
||||||
```bash
|
```bash
|
||||||
# 发布测试环境 带webpack ananalyzer
|
# build for test environment
|
||||||
npm run build:sit-preview
|
npm run build:sit
|
||||||
|
|
||||||
# 构建生成环境
|
# build for production environment
|
||||||
npm run build:prod
|
npm run build:prod
|
||||||
```
|
```
|
||||||
|
|
||||||
## 目录结构
|
## Advanced
|
||||||
```shell
|
```bash
|
||||||
├── build // 构建相关
|
# --report to build with bundle size analytics
|
||||||
├── config // 配置相关
|
npm run build:prod --report
|
||||||
├── src // 源代码
|
|
||||||
│ ├── api // 所有请求
|
|
||||||
│ ├── assets // 主题 字体等静态资源
|
|
||||||
│ ├── components // 全局公用组件
|
|
||||||
│ ├── directive // 全局指令
|
|
||||||
│ ├── filtres // 全局filter
|
|
||||||
│ ├── mock // mock数据
|
|
||||||
│ ├── router // 路由
|
|
||||||
│ ├── store // 全局store管理
|
|
||||||
│ ├── styles // 全局样式
|
|
||||||
│ ├── utils // 全局公用方法
|
|
||||||
│ ├── view // view
|
|
||||||
│ ├── App.vue // 入口页面
|
|
||||||
│ └── main.js // 入口 加载组件 初始化等
|
|
||||||
├── static // 第三方不打包资源
|
|
||||||
│ └── Tinymce // 富文本
|
|
||||||
├── .babelrc // babel-loader 配置
|
|
||||||
├── eslintrc.js // eslint 配置项
|
|
||||||
├── .gitignore // git 忽略项
|
|
||||||
├── favicon.ico // favicon图标
|
|
||||||
├── index.html // html模板
|
|
||||||
└── package.json // package.json
|
|
||||||
|
|
||||||
|
# --preview to start a server in local to preview
|
||||||
|
npm run build:prod --preview
|
||||||
|
|
||||||
|
# lint code
|
||||||
|
npm run lint
|
||||||
|
|
||||||
|
# auto fix
|
||||||
|
npm run lint -- --fix
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/#/deploy) for more information
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||||
|
|
||||||
## 状态管理
|
## Online Demo
|
||||||
后台只有user和app配置相关状态使用vuex存在全局,其它数据都由每个业务页面自己管理。
|
[Preview](http://panjiachen.github.io/vue-element-admin)
|
||||||
|
|
||||||
|
## Donate
|
||||||
|
If you find this project useful, you can buy author a glass of juice :tropical_drink:
|
||||||
|
|
||||||
## 效果图
|
![donate](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png)
|
||||||
|
|
||||||
#### 两步验证登录 支持微信和qq
|
[Paypal Me](https://www.paypal.me/panfree23)
|
||||||
|
|
||||||
![两步验证 here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/2login.gif)
|
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
|
||||||
|
|
||||||
#### 真正的动态换肤
|
|
||||||
|
|
||||||
![真正的动态换肤](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/theme.gif)<br />
|
|
||||||
|
|
||||||
#### tabs
|
|
||||||
|
|
||||||
![tabs](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/tabs.gif)<br />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 可收起侧边栏
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/leftmenu.gif)
|
|
||||||
|
|
||||||
#### table拖拽排序
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/order.gif)
|
|
||||||
|
|
||||||
|
|
||||||
#### 动态table
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/dynamictable.gif)
|
|
||||||
|
|
||||||
|
|
||||||
#### 上传裁剪头像
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/uploadAvatar.gif)
|
|
||||||
|
|
||||||
|
|
||||||
#### 错误统计
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/errorlog.gif)
|
|
||||||
|
|
||||||
|
|
||||||
#### 富文本(整合七牛 打水印等个性化功能)
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/editor.gif)
|
|
||||||
|
|
||||||
#### 封装table组件
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/table.gif)
|
|
||||||
|
|
||||||
#### 图表
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/echarts.gif)
|
|
||||||
|
|
||||||
|
|
||||||
#### 导出excel
|
|
||||||
|
|
||||||
![enter image description here](https://github.com/PanJiaChen/vue-element-admin/blob/master/gifs/excel.png)
|
|
||||||
|
|
||||||
|
|
||||||
## [查看更多demo](http://panjiachen.github.io/vue-element-admin)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Copyright (c) 2017-present PanJiaChen
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
<p align="center">
|
||||||
|
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/vuejs/vue">
|
||||||
|
<img src="https://img.shields.io/badge/vue-2.5.10-brightgreen.svg" alt="vue">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/ElemeFE/element">
|
||||||
|
<img src="https://img.shields.io/badge/element--ui-2.3.0-brightgreen.svg" alt="element-ui">
|
||||||
|
</a>
|
||||||
|
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
|
||||||
|
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE">
|
||||||
|
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
|
||||||
|
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
简体中文 | [English](./README.md)
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
|
||||||
|
`vue-element-admin` 是一个后台集成解决方案,它基于 [Vue.js](https://github.com/vuejs/vue) 和 [element](https://github.com/ElemeFE/element)。它使用了最新的前端技术栈,内置了i18国际化解决方案,动态路由,权限验证等很多功能特性,相信不管你的需求是什么,本项目都能帮助到你。
|
||||||
|
|
||||||
|
- [在线访问](http://panjiachen.github.io/vue-element-admin)
|
||||||
|
|
||||||
|
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/#/zh-cn/)
|
||||||
|
|
||||||
|
- [Gitter讨论组](https://gitter.im/vue-element-admin/discuss)
|
||||||
|
|
||||||
|
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||||
|
|
||||||
|
- [Donate](https://panjiachen.github.io/vue-element-admin-site/#/zh-cn/donate)
|
||||||
|
|
||||||
|
**本项目的定位是后台集成方案,不适合当基础模板来开发。**
|
||||||
|
- 模板建议使用: [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template)
|
||||||
|
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
|
|
||||||
|
**注意:该项目使用 element-ui@2.3.0+ 版本,所以最低兼容 vue@2.5.0+**
|
||||||
|
|
||||||
|
## 前序准备
|
||||||
|
|
||||||
|
你的本地环境需要安装 [node](http://nodejs.org/) 和 [git](https://git-scm.com/)。我们的技术栈基于 [ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) and [element-ui](https://github.com/ElemeFE/element),所有的请求数据都使用[Mock.js](https://github.com/nuysoft/Mock)模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
|
||||||
|
|
||||||
|
同时配套一个系列的教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
|
||||||
|
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
|
||||||
|
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
|
||||||
|
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
|
||||||
|
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
|
||||||
|
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
|
||||||
|
- [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
|
||||||
|
|
||||||
|
|
||||||
|
或者加入该群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西
|
||||||
|
|
||||||
|
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
|
||||||
|
|
||||||
|
**本项目并不是一个脚手架,更倾向于是一个集成解决方案**
|
||||||
|
|
||||||
|
**该项目不支持低版本浏览器(如ie),有需求请自行添加polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
```
|
||||||
|
- 登录/注销
|
||||||
|
- 权限验证
|
||||||
|
- 多环境发布
|
||||||
|
- 动态侧边栏(支持多级路由)
|
||||||
|
- 动态面包屑
|
||||||
|
- 国际化多语言
|
||||||
|
- 多种动态换肤
|
||||||
|
- 快捷导航(标签页)
|
||||||
|
- 富文本编辑器
|
||||||
|
- Markdown编辑器
|
||||||
|
- JSON编辑器
|
||||||
|
- Screenfull全屏
|
||||||
|
- 列表拖拽
|
||||||
|
- Svg Sprite 图标
|
||||||
|
- Dashboard
|
||||||
|
- 本地mock数据
|
||||||
|
- Echarts 图表
|
||||||
|
- Clipboard(剪贴复制)
|
||||||
|
- 401/404错误页面
|
||||||
|
- 错误日志
|
||||||
|
- 导出excel
|
||||||
|
- 导出zip
|
||||||
|
- 前端可视化excel
|
||||||
|
- 树形table
|
||||||
|
- Table example
|
||||||
|
- 动态table example
|
||||||
|
- 拖拽table example
|
||||||
|
- 内联编辑table example
|
||||||
|
- Form example
|
||||||
|
- 二步登录
|
||||||
|
- SplitPane
|
||||||
|
- 拖拽 Dialog
|
||||||
|
- Dropzone
|
||||||
|
- Sticky
|
||||||
|
- CountTo
|
||||||
|
- Markdown2html
|
||||||
|
```
|
||||||
|
|
||||||
|
## 开发
|
||||||
|
```bash
|
||||||
|
# 克隆项目
|
||||||
|
git clone https://github.com/PanJiaChen/vue-element-admin.git
|
||||||
|
|
||||||
|
# 安装依赖
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 建议不要用cnpm安装 会有各种诡异的bug 可以通过如下操作解决 npm 下载速度慢的问题
|
||||||
|
npm install --registry=https://registry.npm.taobao.org
|
||||||
|
|
||||||
|
# 启动服务
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
浏览器访问 http://localhost:9527
|
||||||
|
|
||||||
|
## 发布
|
||||||
|
```bash
|
||||||
|
# 构建测试环境
|
||||||
|
npm run build:sit
|
||||||
|
|
||||||
|
# 构建生成环境
|
||||||
|
npm run build:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其它
|
||||||
|
```bash
|
||||||
|
# --report to build with bundle size analytics
|
||||||
|
npm run build:prod --report
|
||||||
|
|
||||||
|
# --preview to start a server in local to preview
|
||||||
|
npm run build:prod --preview
|
||||||
|
|
||||||
|
# lint code
|
||||||
|
npm run lint
|
||||||
|
|
||||||
|
# auto fix
|
||||||
|
npm run lint -- --fix
|
||||||
|
```
|
||||||
|
|
||||||
|
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/#/zh-cn/deploy)
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
|
||||||
|
|
||||||
|
## Online Demo
|
||||||
|
[在线 Demo](http://panjiachen.github.io/vue-element-admin)
|
||||||
|
|
||||||
|
## Donate
|
||||||
|
如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 :tropical_drink:
|
||||||
|
![donate](https://panjiachen.github.io/donate/donation.png)
|
||||||
|
|
||||||
|
[Paypal Me](https://www.paypal.me/panfree23)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Copyright (c) 2017-present PanJiaChen
|
|
@ -1,23 +1,21 @@
|
||||||
require('./check-versions')();
|
'use strict'
|
||||||
var server = require('pushstate-server');
|
require('./check-versions')()
|
||||||
var opn = require('opn')
|
|
||||||
var ora = require('ora')
|
|
||||||
var rm = require('rimraf')
|
|
||||||
var path = require('path')
|
|
||||||
var chalk = require('chalk')
|
|
||||||
var webpack = require('webpack');
|
|
||||||
var config = require('../config');
|
|
||||||
var webpackConfig = require('./webpack.prod.conf');
|
|
||||||
|
|
||||||
console.log(process.env.NODE_ENV)
|
const ora = require('ora')
|
||||||
|
const rm = require('rimraf')
|
||||||
|
const path = require('path')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const config = require('../config')
|
||||||
|
const webpackConfig = require('./webpack.prod.conf')
|
||||||
|
const server = require('pushstate-server')
|
||||||
|
|
||||||
var spinner = ora('building for ' + process.env.NODE_ENV + '...')
|
var spinner = ora('building for '+ process.env.env_config+ ' environment...' )
|
||||||
spinner.start()
|
spinner.start()
|
||||||
|
|
||||||
|
|
||||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||||
if (err) throw err
|
if (err) throw err
|
||||||
webpack(webpackConfig, function (err, stats) {
|
webpack(webpackConfig, (err, stats) => {
|
||||||
spinner.stop()
|
spinner.stop()
|
||||||
if (err) throw err
|
if (err) throw err
|
||||||
process.stdout.write(stats.toString({
|
process.stdout.write(stats.toString({
|
||||||
|
@ -28,14 +26,23 @@ rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||||
chunkModules: false
|
chunkModules: false
|
||||||
}) + '\n\n')
|
}) + '\n\n')
|
||||||
|
|
||||||
|
if (stats.hasErrors()) {
|
||||||
|
console.log(chalk.red(' Build failed with errors.\n'))
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
console.log(chalk.cyan(' Build complete.\n'))
|
console.log(chalk.cyan(' Build complete.\n'))
|
||||||
|
console.log(chalk.yellow(
|
||||||
|
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||||
|
' Opening index.html over file:// won\'t work.\n'
|
||||||
|
))
|
||||||
if(process.env.npm_config_preview){
|
if(process.env.npm_config_preview){
|
||||||
server.start({
|
server.start({
|
||||||
port: 9528,
|
port: 9526,
|
||||||
directory: './dist',
|
directory: './dist',
|
||||||
file: '/index.html'
|
file: '/index.html'
|
||||||
});
|
});
|
||||||
console.log('> Listening at ' + 'http://localhost:9528' + '\n')
|
console.log('> Listening at ' + 'http://localhost:9526' + '\n')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,28 +1,35 @@
|
||||||
var chalk = require('chalk')
|
'use strict'
|
||||||
var semver = require('semver')
|
const chalk = require('chalk')
|
||||||
var packageConfig = require('../package.json')
|
const semver = require('semver')
|
||||||
|
const packageConfig = require('../package.json')
|
||||||
|
const shell = require('shelljs')
|
||||||
|
|
||||||
function exec(cmd) {
|
function exec (cmd) {
|
||||||
return require('child_process').execSync(cmd).toString().trim()
|
return require('child_process').execSync(cmd).toString().trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
var versionRequirements = [
|
const versionRequirements = [
|
||||||
{
|
{
|
||||||
name: 'node',
|
name: 'node',
|
||||||
currentVersion: semver.clean(process.version),
|
currentVersion: semver.clean(process.version),
|
||||||
versionRequirement: packageConfig.engines.node
|
versionRequirement: packageConfig.engines.node
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'npm',
|
|
||||||
currentVersion: exec('npm --version'),
|
|
||||||
versionRequirement: packageConfig.engines.npm
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if (shell.which('npm')) {
|
||||||
|
versionRequirements.push({
|
||||||
|
name: 'npm',
|
||||||
|
currentVersion: exec('npm --version'),
|
||||||
|
versionRequirement: packageConfig.engines.npm
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
var warnings = []
|
const warnings = []
|
||||||
for (var i = 0; i < versionRequirements.length; i++) {
|
|
||||||
var mod = versionRequirements[i]
|
for (let i = 0; i < versionRequirements.length; i++) {
|
||||||
|
const mod = versionRequirements[i]
|
||||||
|
|
||||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||||
warnings.push(mod.name + ': ' +
|
warnings.push(mod.name + ': ' +
|
||||||
chalk.red(mod.currentVersion) + ' should be ' +
|
chalk.red(mod.currentVersion) + ' should be ' +
|
||||||
|
@ -35,10 +42,12 @@ module.exports = function () {
|
||||||
console.log('')
|
console.log('')
|
||||||
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
console.log(chalk.yellow('To use this template, you must update following to modules:'))
|
||||||
console.log()
|
console.log()
|
||||||
for (var i = 0; i < warnings.length; i++) {
|
|
||||||
var warning = warnings[i]
|
for (let i = 0; i < warnings.length; i++) {
|
||||||
|
const warning = warnings[i]
|
||||||
console.log(' ' + warning)
|
console.log(' ' + warning)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log()
|
console.log()
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
/* eslint-disable */
|
|
||||||
require('eventsource-polyfill')
|
|
||||||
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
|
|
||||||
|
|
||||||
hotClient.subscribe(function (event) {
|
|
||||||
if (event.action === 'reload') {
|
|
||||||
window.location.reload()
|
|
||||||
}
|
|
||||||
})
|
|
|
@ -1,84 +0,0 @@
|
||||||
require('./check-versions')(); // 检查 Node 和 npm 版本
|
|
||||||
var config = require('../config');
|
|
||||||
if (!process.env.NODE_ENV) {
|
|
||||||
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
|
|
||||||
}
|
|
||||||
|
|
||||||
var opn = require('opn')
|
|
||||||
var path = require('path');
|
|
||||||
var express = require('express');
|
|
||||||
var webpack = require('webpack');
|
|
||||||
var proxyMiddleware = require('http-proxy-middleware');
|
|
||||||
var webpackConfig = require('./webpack.dev.conf');
|
|
||||||
|
|
||||||
// default port where dev server listens for incoming traffic
|
|
||||||
var port = process.env.PORT || config.dev.port;
|
|
||||||
// automatically open browser, if not set will be false
|
|
||||||
var autoOpenBrowser = !!config.dev.autoOpenBrowser;
|
|
||||||
// Define HTTP proxies to your custom API backend
|
|
||||||
// https://github.com/chimurai/http-proxy-middleware
|
|
||||||
var proxyTable = config.dev.proxyTable;
|
|
||||||
|
|
||||||
var app = express();
|
|
||||||
var compiler = webpack(webpackConfig);
|
|
||||||
|
|
||||||
var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
|
||||||
publicPath: webpackConfig.output.publicPath,
|
|
||||||
quiet: true
|
|
||||||
});
|
|
||||||
|
|
||||||
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
|
|
||||||
log: () => {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// force page reload when html-webpack-plugin template changes
|
|
||||||
compiler.plugin('compilation', function (compilation) {
|
|
||||||
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
|
|
||||||
hotMiddleware.publish({action: 'reload'});
|
|
||||||
cb()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// compiler.apply(new DashboardPlugin());
|
|
||||||
|
|
||||||
// proxy api requests
|
|
||||||
Object.keys(proxyTable).forEach(function (context) {
|
|
||||||
var options = proxyTable[context]
|
|
||||||
if (typeof options === 'string') {
|
|
||||||
options = {target: options}
|
|
||||||
}
|
|
||||||
app.use(proxyMiddleware(options.filter || context, options))
|
|
||||||
});
|
|
||||||
|
|
||||||
// handle fallback for HTML5 history API
|
|
||||||
app.use(require('connect-history-api-fallback')());
|
|
||||||
|
|
||||||
// serve webpack bundle output
|
|
||||||
app.use(devMiddleware);
|
|
||||||
|
|
||||||
// enable hot-reload and state-preserving
|
|
||||||
// compilation error display
|
|
||||||
app.use(hotMiddleware);
|
|
||||||
|
|
||||||
// serve pure static assets
|
|
||||||
var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory);
|
|
||||||
app.use(staticPath, express.static('./static'));
|
|
||||||
|
|
||||||
var uri = 'http://localhost:' + port
|
|
||||||
|
|
||||||
devMiddleware.waitUntilValid(function () {
|
|
||||||
console.log('> Listening at ' + uri + '\n')
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = app.listen(port, function (err) {
|
|
||||||
if (err) {
|
|
||||||
console.log(err);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// when env is testing, don't need open it
|
|
||||||
if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
|
|
||||||
opn(uri)
|
|
||||||
}
|
|
||||||
});
|
|
After Width: | Height: | Size: 6.7 KiB |
|
@ -1,28 +1,38 @@
|
||||||
var path = require('path')
|
'use strict'
|
||||||
var config = require('../config')
|
const path = require('path')
|
||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
const config = require('../config')
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
|
const packageConfig = require('../package.json')
|
||||||
|
|
||||||
exports.assetsPath = function (_path) {
|
exports.assetsPath = function (_path) {
|
||||||
var assetsSubDirectory = process.env.NODE_ENV === 'production'
|
const assetsSubDirectory = process.env.NODE_ENV === 'production'
|
||||||
? config.build.assetsSubDirectory
|
? config.build.assetsSubDirectory
|
||||||
: config.dev.assetsSubDirectory
|
: config.dev.assetsSubDirectory
|
||||||
|
|
||||||
return path.posix.join(assetsSubDirectory, _path)
|
return path.posix.join(assetsSubDirectory, _path)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.cssLoaders = function (options) {
|
exports.cssLoaders = function (options) {
|
||||||
options = options || {}
|
options = options || {}
|
||||||
|
|
||||||
var cssLoader = {
|
const cssLoader = {
|
||||||
loader: 'css-loader',
|
loader: 'css-loader',
|
||||||
options: {
|
options: {
|
||||||
minimize: process.env.NODE_ENV === 'production',
|
sourceMap: options.sourceMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const postcssLoader = {
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
sourceMap: options.sourceMap
|
sourceMap: options.sourceMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate loader string to be used with extract text plugin
|
// generate loader string to be used with extract text plugin
|
||||||
function generateLoaders (loader, loaderOptions) {
|
function generateLoaders (loader, loaderOptions) {
|
||||||
var loaders = [cssLoader]
|
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
|
||||||
|
|
||||||
if (loader) {
|
if (loader) {
|
||||||
loaders.push({
|
loaders.push({
|
||||||
loader: loader + '-loader',
|
loader: loader + '-loader',
|
||||||
|
@ -58,14 +68,34 @@ exports.cssLoaders = function (options) {
|
||||||
|
|
||||||
// Generate loaders for standalone style files (outside of .vue)
|
// Generate loaders for standalone style files (outside of .vue)
|
||||||
exports.styleLoaders = function (options) {
|
exports.styleLoaders = function (options) {
|
||||||
var output = []
|
const output = []
|
||||||
var loaders = exports.cssLoaders(options)
|
const loaders = exports.cssLoaders(options)
|
||||||
for (var extension in loaders) {
|
|
||||||
var loader = loaders[extension]
|
for (const extension in loaders) {
|
||||||
|
const loader = loaders[extension]
|
||||||
output.push({
|
output.push({
|
||||||
test: new RegExp('\\.' + extension + '$'),
|
test: new RegExp('\\.' + extension + '$'),
|
||||||
use: loader
|
use: loader
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.createNotifierCallback = () => {
|
||||||
|
const notifier = require('node-notifier')
|
||||||
|
|
||||||
|
return (severity, errors) => {
|
||||||
|
if (severity !== 'error') return
|
||||||
|
|
||||||
|
const error = errors[0]
|
||||||
|
const filename = error.file && error.file.split('!').pop()
|
||||||
|
|
||||||
|
notifier.notify({
|
||||||
|
title: packageConfig.name,
|
||||||
|
message: severity + ': ' + error.name,
|
||||||
|
subtitle: filename || '',
|
||||||
|
icon: path.join(__dirname, 'logo.png')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
var utils = require('./utils')
|
'use strict'
|
||||||
var config = require('../config')
|
const utils = require('./utils')
|
||||||
var isProduction = process.env.NODE_ENV === 'production'
|
const config = require('../config')
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production'
|
||||||
|
const sourceMapEnabled = isProduction
|
||||||
|
? config.build.productionSourceMap
|
||||||
|
: config.dev.cssSourceMap
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
loaders: utils.cssLoaders({
|
loaders: utils.cssLoaders({
|
||||||
sourceMap: isProduction
|
sourceMap: sourceMapEnabled,
|
||||||
? config.build.productionSourceMap
|
|
||||||
: config.dev.cssSourceMap,
|
|
||||||
extract: isProduction
|
extract: isProduction
|
||||||
})
|
}),
|
||||||
|
cssSourceMap: sourceMapEnabled,
|
||||||
|
cacheBusting: config.dev.cacheBusting,
|
||||||
|
transformToRequire: {
|
||||||
|
video: ['src', 'poster'],
|
||||||
|
source: 'src',
|
||||||
|
img: 'src',
|
||||||
|
image: 'xlink:href'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,51 +1,46 @@
|
||||||
var path = require('path')
|
'use strict'
|
||||||
var utils = require('./utils')
|
const path = require('path')
|
||||||
var config = require('../config')
|
const utils = require('./utils')
|
||||||
var vueLoaderConfig = require('./vue-loader.conf')
|
const config = require('../config')
|
||||||
|
const vueLoaderConfig = require('./vue-loader.conf')
|
||||||
|
|
||||||
function resolve(dir) {
|
function resolve (dir) {
|
||||||
return path.join(__dirname, '..', dir)
|
return path.join(__dirname, '..', dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createLintingRule = () => ({
|
||||||
|
test: /\.(js|vue)$/,
|
||||||
|
loader: 'eslint-loader',
|
||||||
|
enforce: 'pre',
|
||||||
|
include: [resolve('src'), resolve('test')],
|
||||||
|
options: {
|
||||||
|
formatter: require('eslint-friendly-formatter'),
|
||||||
|
emitWarning: !config.dev.showEslintErrorsInOverlay
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
context: path.resolve(__dirname, '../'),
|
||||||
entry: {
|
entry: {
|
||||||
app: './src/main.js'
|
app: './src/main.js'
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: config.build.assetsRoot,
|
path: config.build.assetsRoot,
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
publicPath: process.env.NODE_ENV !== 'development' ? config.build.assetsPublicPath : config.dev.assetsPublicPath
|
publicPath: process.env.NODE_ENV === 'production'
|
||||||
|
? config.build.assetsPublicPath
|
||||||
|
: config.dev.assetsPublicPath
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.vue', '.json'],
|
extensions: ['.js', '.vue', '.json'],
|
||||||
alias: {
|
alias: {
|
||||||
'vue$': 'vue/dist/vue.esm.js',
|
'vue$': 'vue/dist/vue.esm.js',
|
||||||
'@': resolve('src'),
|
'@': resolve('src'),
|
||||||
'src': path.resolve(__dirname, '../src'),
|
|
||||||
'assets': path.resolve(__dirname, '../src/assets'),
|
|
||||||
'components': path.resolve(__dirname, '../src/components'),
|
|
||||||
'views': path.resolve(__dirname, '../src/views'),
|
|
||||||
'styles': path.resolve(__dirname, '../src/styles'),
|
|
||||||
'api': path.resolve(__dirname, '../src/api'),
|
|
||||||
'utils': path.resolve(__dirname, '../src/utils'),
|
|
||||||
'store': path.resolve(__dirname, '../src/store'),
|
|
||||||
'router': path.resolve(__dirname, '../src/router'),
|
|
||||||
'mock': path.resolve(__dirname, '../src/mock'),
|
|
||||||
'vendor': path.resolve(__dirname, '../src/vendor'),
|
|
||||||
'static': path.resolve(__dirname, '../static')
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
...(config.dev.useEslint ? [createLintingRule()] : []),
|
||||||
test: /\.(js|vue)$/,
|
|
||||||
loader: 'eslint-loader',
|
|
||||||
enforce: "pre",
|
|
||||||
include: [resolve('src'), resolve('test')],
|
|
||||||
options: {
|
|
||||||
formatter: require('eslint-friendly-formatter')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
test: /\.vue$/,
|
test: /\.vue$/,
|
||||||
loader: 'vue-loader',
|
loader: 'vue-loader',
|
||||||
|
@ -54,7 +49,7 @@ module.exports = {
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
loader: 'babel-loader?cacheDirectory',
|
loader: 'babel-loader?cacheDirectory',
|
||||||
include: [resolve('src'), resolve('test')]
|
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.svg$/,
|
test: /\.svg$/,
|
||||||
|
@ -68,25 +63,39 @@ module.exports = {
|
||||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
loader: 'url-loader',
|
loader: 'url-loader',
|
||||||
exclude: [resolve('src/icons')],
|
exclude: [resolve('src/icons')],
|
||||||
query: {
|
options: {
|
||||||
limit: 10000,
|
limit: 10000,
|
||||||
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: utils.assetsPath('media/[name].[hash:7].[ext]')
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
loader: 'url-loader',
|
loader: 'url-loader',
|
||||||
query: {
|
options: {
|
||||||
limit: 10000,
|
limit: 10000,
|
||||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
//注入全局mixin
|
node: {
|
||||||
// sassResources: path.join(__dirname, '../src/styles/mixin.scss'),
|
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||||
// sassLoader: {
|
// source contains it (although only uses it if it's native).
|
||||||
// data: path.join(__dirname, '../src/styles/index.scss')
|
setImmediate: false,
|
||||||
// },
|
// prevent webpack from injecting mocks to Node native modules
|
||||||
|
// that does not make sense for the client
|
||||||
|
dgram: 'empty',
|
||||||
|
fs: 'empty',
|
||||||
|
net: 'empty',
|
||||||
|
tls: 'empty',
|
||||||
|
child_process: 'empty'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,46 +1,88 @@
|
||||||
var utils = require('./utils')
|
'use strict'
|
||||||
var path = require('path')
|
const path = require('path')
|
||||||
var webpack = require('webpack')
|
const utils = require('./utils')
|
||||||
var config = require('../config')
|
const webpack = require('webpack')
|
||||||
var merge = require('webpack-merge')
|
const config = require('../config')
|
||||||
var baseWebpackConfig = require('./webpack.base.conf')
|
const merge = require('webpack-merge')
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin')
|
const baseWebpackConfig = require('./webpack.base.conf')
|
||||||
var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||||
|
const portfinder = require('portfinder')
|
||||||
|
|
||||||
// add hot-reload related code to entry chunks
|
function resolve (dir) {
|
||||||
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
|
return path.join(__dirname, '..', dir)
|
||||||
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
|
|
||||||
})
|
|
||||||
|
|
||||||
function resolveApp(relativePath) {
|
|
||||||
return path.resolve(relativePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = merge(baseWebpackConfig, {
|
const HOST = process.env.HOST
|
||||||
|
const PORT = process.env.PORT && Number(process.env.PORT)
|
||||||
|
|
||||||
|
const devWebpackConfig = merge(baseWebpackConfig, {
|
||||||
module: {
|
module: {
|
||||||
rules: utils.styleLoaders({
|
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
|
||||||
sourceMap: config.dev.cssSourceMap
|
},
|
||||||
})
|
// cheap-module-eval-source-map is faster for development
|
||||||
|
devtool: config.dev.devtool,
|
||||||
|
|
||||||
|
// these devServer options should be customized in /config/index.js
|
||||||
|
devServer: {
|
||||||
|
clientLogLevel: 'warning',
|
||||||
|
historyApiFallback: true,
|
||||||
|
hot: true,
|
||||||
|
compress: true,
|
||||||
|
host: HOST || config.dev.host,
|
||||||
|
port: PORT || config.dev.port,
|
||||||
|
open: config.dev.autoOpenBrowser,
|
||||||
|
overlay: config.dev.errorOverlay
|
||||||
|
? { warnings: false, errors: true }
|
||||||
|
: false,
|
||||||
|
publicPath: config.dev.assetsPublicPath,
|
||||||
|
proxy: config.dev.proxyTable,
|
||||||
|
quiet: true, // necessary for FriendlyErrorsPlugin
|
||||||
|
watchOptions: {
|
||||||
|
poll: config.dev.poll,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// cheap-source-map is faster for development
|
|
||||||
devtool: '#cheap-source-map',
|
|
||||||
cache: true,
|
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': config.dev.env
|
'process.env': require('../config/dev.env')
|
||||||
}),
|
}),
|
||||||
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
|
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
|
||||||
new webpack.NoEmitOnErrorsPlugin(),
|
new webpack.NoEmitOnErrorsPlugin(),
|
||||||
// https://github.com/ampedandwired/html-webpack-plugin
|
// https://github.com/ampedandwired/html-webpack-plugin
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: 'index.html',
|
filename: 'index.html',
|
||||||
template: 'index.html',
|
template: 'index.html',
|
||||||
favicon: resolveApp('favicon.ico'),
|
|
||||||
inject: true,
|
inject: true,
|
||||||
|
favicon: resolve('favicon.ico'),
|
||||||
|
title: 'vue-element-admin',
|
||||||
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
|
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
|
||||||
}),
|
}),
|
||||||
new FriendlyErrorsPlugin()
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
module.exports = new Promise((resolve, reject) => {
|
||||||
|
portfinder.basePort = process.env.PORT || config.dev.port
|
||||||
|
portfinder.getPort((err, port) => {
|
||||||
|
if (err) {
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
// publish the new Port, necessary for e2e tests
|
||||||
|
process.env.PORT = port
|
||||||
|
// add port to devServer config
|
||||||
|
devWebpackConfig.devServer.port = port
|
||||||
|
|
||||||
|
// Add FriendlyErrorsPlugin
|
||||||
|
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
|
||||||
|
compilationSuccessInfo: {
|
||||||
|
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
|
||||||
|
},
|
||||||
|
onErrors: config.dev.notifyOnErrors
|
||||||
|
? utils.createNotifierCallback()
|
||||||
|
: undefined
|
||||||
|
}))
|
||||||
|
|
||||||
|
resolve(devWebpackConfig)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
@ -1,82 +1,93 @@
|
||||||
var path = require('path')
|
'use strict'
|
||||||
var utils = require('./utils')
|
const path = require('path')
|
||||||
var webpack = require('webpack')
|
const utils = require('./utils')
|
||||||
var config = require('../config')
|
const webpack = require('webpack')
|
||||||
var merge = require('webpack-merge')
|
const config = require('../config')
|
||||||
var baseWebpackConfig = require('./webpack.base.conf')
|
const merge = require('webpack-merge')
|
||||||
var CopyWebpackPlugin = require('copy-webpack-plugin')
|
const baseWebpackConfig = require('./webpack.base.conf')
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin')
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
var ExtractTextPlugin = require('extract-text-webpack-plugin')
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
|
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
|
||||||
|
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||||
|
|
||||||
var env = process.env.NODE_ENV === 'production' ? config.build.prodEnv : config.build.sitEnv
|
function resolve (dir) {
|
||||||
|
return path.join(__dirname, '..', dir)
|
||||||
function resolveApp(relativePath) {
|
|
||||||
return path.resolve(relativePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var webpackConfig = merge(baseWebpackConfig, {
|
const env = require('../config/'+process.env.env_config+'.env')
|
||||||
|
|
||||||
|
const webpackConfig = merge(baseWebpackConfig, {
|
||||||
module: {
|
module: {
|
||||||
rules: utils.styleLoaders({
|
rules: utils.styleLoaders({
|
||||||
sourceMap: config.build.productionSourceMap,
|
sourceMap: config.build.productionSourceMap,
|
||||||
extract: true
|
extract: true,
|
||||||
|
usePostCSS: true
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
devtool: config.build.productionSourceMap ? '#source-map' : false,
|
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
||||||
output: {
|
output: {
|
||||||
path: config.build.assetsRoot,
|
path: config.build.assetsRoot,
|
||||||
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
|
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
||||||
publicPath: config.build.assetsPublicPath
|
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': env
|
'process.env': env
|
||||||
}),
|
}),
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
new UglifyJsPlugin({
|
||||||
|
uglifyOptions: {
|
||||||
compress: {
|
compress: {
|
||||||
warnings: false
|
warnings: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
sourceMap: true
|
sourceMap: config.build.productionSourceMap,
|
||||||
|
parallel: true
|
||||||
}),
|
}),
|
||||||
// extract css into its own file
|
// extract css into its own file
|
||||||
new ExtractTextPlugin({
|
new ExtractTextPlugin({
|
||||||
filename: utils.assetsPath('css/[name].[contenthash].css')
|
filename: utils.assetsPath('css/[name].[contenthash].css'),
|
||||||
|
// Setting the following option to `false` will not extract CSS from codesplit chunks.
|
||||||
|
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
|
||||||
|
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
|
||||||
|
allChunks: false,
|
||||||
}),
|
}),
|
||||||
// Compress extracted CSS. We are using this plugin so that possible
|
// Compress extracted CSS. We are using this plugin so that possible
|
||||||
// duplicated CSS from different components can be deduped.
|
// duplicated CSS from different components can be deduped.
|
||||||
new OptimizeCSSPlugin(),
|
new OptimizeCSSPlugin({
|
||||||
|
cssProcessorOptions: config.build.productionSourceMap
|
||||||
|
? { safe: true, map: { inline: false } }
|
||||||
|
: { safe: true }
|
||||||
|
}),
|
||||||
// generate dist index.html with correct asset hash for caching.
|
// generate dist index.html with correct asset hash for caching.
|
||||||
// you can customize output by editing /index.html
|
// you can customize output by editing /index.html
|
||||||
// see https://github.com/ampedandwired/html-webpack-plugin
|
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: 'index.html',
|
filename: config.build.index,
|
||||||
template: 'index.html',
|
template: 'index.html',
|
||||||
inject: true,
|
inject: true,
|
||||||
favicon: resolveApp('favicon.ico'),
|
favicon: resolve('favicon.ico'),
|
||||||
|
title: 'vue-element-admin',
|
||||||
|
path: config.build.assetsPublicPath + config.build.assetsSubDirectory,
|
||||||
minify: {
|
minify: {
|
||||||
removeComments: true,
|
removeComments: true,
|
||||||
collapseWhitespace: true,
|
collapseWhitespace: true,
|
||||||
removeRedundantAttributes: true,
|
removeAttributeQuotes: true
|
||||||
useShortDoctype: true,
|
// more options:
|
||||||
removeEmptyAttributes: true,
|
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||||
removeStyleLinkTypeAttributes: true,
|
|
||||||
keepClosingSlash: true,
|
|
||||||
minifyJS: true,
|
|
||||||
minifyCSS: true,
|
|
||||||
minifyURLs: true
|
|
||||||
},
|
},
|
||||||
path: config.build.assetsPublicPath + config.build.assetsSubDirectory,
|
|
||||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||||
chunksSortMode: 'dependency'
|
chunksSortMode: 'dependency'
|
||||||
}),
|
}),
|
||||||
// cache Module Identifiers
|
// keep module.id stable when vender modules does not change
|
||||||
new webpack.HashedModuleIdsPlugin(),
|
new webpack.HashedModuleIdsPlugin(),
|
||||||
|
// enable scope hoisting
|
||||||
|
new webpack.optimize.ModuleConcatenationPlugin(),
|
||||||
// split vendor js into its own file
|
// split vendor js into its own file
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
name: 'vendor',
|
name: 'vendor',
|
||||||
minChunks: function (module, count) {
|
minChunks (module) {
|
||||||
// any required modules inside node_modules are extracted to vendor
|
// any required modules inside node_modules are extracted to vendor
|
||||||
return (
|
return (
|
||||||
module.resource &&
|
module.resource &&
|
||||||
|
@ -87,6 +98,21 @@ var webpackConfig = merge(baseWebpackConfig, {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
// extract webpack runtime and module manifest to its own file in order to
|
||||||
|
// prevent vendor hash from being updated whenever app bundle is updated
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'manifest',
|
||||||
|
minChunks: Infinity
|
||||||
|
}),
|
||||||
|
// This instance extracts shared chunks from code splitted chunks and bundles them
|
||||||
|
// in a separate chunk, similar to the vendor chunk
|
||||||
|
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
name: 'app',
|
||||||
|
async: 'vendor-async',
|
||||||
|
children: true,
|
||||||
|
minChunks: 3
|
||||||
|
}),
|
||||||
// split echarts into its own file
|
// split echarts into its own file
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
async: 'echarts',
|
async: 'echarts',
|
||||||
|
@ -95,23 +121,55 @@ var webpackConfig = merge(baseWebpackConfig, {
|
||||||
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
|
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
// extract webpack runtime and module manifest to its own file in order to
|
// split xlsx into its own file
|
||||||
// prevent vendor hash from being updated whenever app bundle is updated
|
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
name: 'manifest',
|
async: 'xlsx',
|
||||||
chunks: ['vendor']
|
minChunks(module) {
|
||||||
|
var context = module.context;
|
||||||
|
return context && (context.indexOf('xlsx') >= 0);
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
|
// split codemirror into its own file
|
||||||
|
new webpack.optimize.CommonsChunkPlugin({
|
||||||
|
async: 'codemirror',
|
||||||
|
minChunks(module) {
|
||||||
|
var context = module.context;
|
||||||
|
return context && (context.indexOf('codemirror') >= 0);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
// copy custom static assets
|
// copy custom static assets
|
||||||
new CopyWebpackPlugin([{
|
new CopyWebpackPlugin([
|
||||||
|
{
|
||||||
from: path.resolve(__dirname, '../static'),
|
from: path.resolve(__dirname, '../static'),
|
||||||
to: config.build.assetsSubDirectory,
|
to: config.build.assetsSubDirectory,
|
||||||
ignore: ['.*']
|
ignore: ['.*']
|
||||||
}])
|
}
|
||||||
|
])
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (config.build.productionGzip) {
|
||||||
|
const CompressionWebpackPlugin = require('compression-webpack-plugin')
|
||||||
|
|
||||||
|
webpackConfig.plugins.push(
|
||||||
|
new CompressionWebpackPlugin({
|
||||||
|
asset: '[path].gz[query]',
|
||||||
|
algorithm: 'gzip',
|
||||||
|
test: new RegExp(
|
||||||
|
'\\.(' +
|
||||||
|
config.build.productionGzipExtensions.join('|') +
|
||||||
|
')$'
|
||||||
|
),
|
||||||
|
threshold: 10240,
|
||||||
|
minRatio: 0.8
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (config.build.bundleAnalyzerReport) {
|
if (config.build.bundleAnalyzerReport) {
|
||||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
||||||
}
|
}
|
||||||
module.exports = webpackConfig
|
|
||||||
|
|
||||||
|
module.exports = webpackConfig
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
NODE_ENV: '"development"',
|
NODE_ENV: '"development"',
|
||||||
BASE_API: '"https://api-dev"',
|
ENV_CONFIG: '"dev"',
|
||||||
APP_ORIGIN: '"https://wallstreetcn.com"'
|
BASE_API: '"https://api-dev"'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,83 @@
|
||||||
|
'use strict'
|
||||||
|
// Template version: 1.2.6
|
||||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||||
var path = require('path')
|
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
dev: {
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
assetsSubDirectory: 'static',
|
||||||
|
assetsPublicPath: '/',
|
||||||
|
proxyTable: {},
|
||||||
|
|
||||||
|
// Various Dev Server settings
|
||||||
|
host: 'localhost', // can be overwritten by process.env.HOST
|
||||||
|
port: 9527, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
||||||
|
autoOpenBrowser: true,
|
||||||
|
errorOverlay: true,
|
||||||
|
notifyOnErrors: false,
|
||||||
|
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
||||||
|
|
||||||
|
// Use Eslint Loader?
|
||||||
|
// If true, your code will be linted during bundling and
|
||||||
|
// linting errors and warnings will be shown in the console.
|
||||||
|
useEslint: true,
|
||||||
|
// If true, eslint errors and warnings will also be shown in the error overlay
|
||||||
|
// in the browser.
|
||||||
|
showEslintErrorsInOverlay: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source Maps
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://webpack.js.org/configuration/devtool/#development
|
||||||
|
devtool: '#cheap-source-map',
|
||||||
|
|
||||||
|
// If you have problems debugging vue-files in devtools,
|
||||||
|
// set this to false - it *may* help
|
||||||
|
// https://vue-loader.vuejs.org/en/options.html#cachebusting
|
||||||
|
cacheBusting: true,
|
||||||
|
|
||||||
|
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||||
|
// with this option, according to the CSS-Loader README
|
||||||
|
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||||
|
// In our experience, they generally work as expected,
|
||||||
|
// just be aware of this issue when enabling this option.
|
||||||
|
cssSourceMap: false,
|
||||||
|
},
|
||||||
|
|
||||||
build: {
|
build: {
|
||||||
sitEnv: require('./sit.env'),
|
// Template for index.html
|
||||||
prodEnv: require('./prod.env'),
|
|
||||||
index: path.resolve(__dirname, '../dist/index.html'),
|
index: path.resolve(__dirname, '../dist/index.html'),
|
||||||
|
|
||||||
|
// Paths
|
||||||
assetsRoot: path.resolve(__dirname, '../dist'),
|
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||||
assetsSubDirectory: 'static',
|
assetsSubDirectory: 'static',
|
||||||
assetsPublicPath: './', //请根据自己路径配置更改
|
|
||||||
|
// you can set by youself according to actual condition
|
||||||
|
assetsPublicPath: './',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source Maps
|
||||||
|
*/
|
||||||
|
|
||||||
productionSourceMap: false,
|
productionSourceMap: false,
|
||||||
|
// https://webpack.js.org/configuration/devtool/#production
|
||||||
|
devtool: '#source-map',
|
||||||
|
|
||||||
// Gzip off by default as many popular static hosts such as
|
// Gzip off by default as many popular static hosts such as
|
||||||
// Surge or Netlify already gzip all static assets for you.
|
// Surge or Netlify already gzip all static assets for you.
|
||||||
// Before setting to `true`, make sure to:
|
// Before setting to `true`, make sure to:
|
||||||
// npm install --save-dev compression-webpack-plugin
|
// npm install --save-dev compression-webpack-plugin
|
||||||
productionGzip: false,
|
productionGzip: false,
|
||||||
productionGzipExtensions: ['js', 'css'],
|
productionGzipExtensions: ['js', 'css'],
|
||||||
|
|
||||||
// Run the build command with an extra argument to
|
// Run the build command with an extra argument to
|
||||||
// View the bundle analyzer report after build finishes:
|
// View the bundle analyzer report after build finishes:
|
||||||
// `npm run build --report`
|
// `npm run build --report`
|
||||||
// Set to `true` or `false` to always turn it on or off
|
// Set to `true` or `false` to always turn it on or off
|
||||||
bundleAnalyzerReport: process.env.npm_config_report
|
bundleAnalyzerReport: process.env.npm_config_report
|
||||||
},
|
|
||||||
dev: {
|
|
||||||
env: require('./dev.env'),
|
|
||||||
port: 9527,
|
|
||||||
autoOpenBrowser: true,
|
|
||||||
assetsSubDirectory: 'static',
|
|
||||||
assetsPublicPath: '/',
|
|
||||||
proxyTable: {},
|
|
||||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
|
||||||
// with this option, according to the CSS-Loader README
|
|
||||||
// (https://github.com/webpack/css-loader#sourcemaps)
|
|
||||||
// In our experience, they generally work as expected,
|
|
||||||
// just be aware of this issue when enabling this option.
|
|
||||||
cssSourceMap: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
NODE_ENV: '"production"',
|
NODE_ENV: '"production"',
|
||||||
BASE_API: '"https://api-prod"',
|
ENV_CONFIG: '"prod"',
|
||||||
APP_ORIGIN: '"https://wallstreetcn.com"'
|
BASE_API: '"https://api-prod"'
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
NODE_ENV: '"production"',
|
NODE_ENV: '"production"',
|
||||||
BASE_API: '"https://api-sit"',
|
ENV_CONFIG: '"sit"',
|
||||||
APP_ORIGIN: '"https://wallstreetcn.com"'
|
BASE_API: '"https://api-sit"'
|
||||||
};
|
}
|
||||||
|
|
BIN
favicon.ico
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
BIN
gifs/2login.gif
Before Width: | Height: | Size: 275 KiB |
Before Width: | Height: | Size: 41 KiB |
BIN
gifs/echarts.gif
Before Width: | Height: | Size: 229 KiB |
BIN
gifs/editor.gif
Before Width: | Height: | Size: 435 KiB |
Before Width: | Height: | Size: 532 KiB |
BIN
gifs/excel.png
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 601 KiB |
BIN
gifs/login.png
Before Width: | Height: | Size: 51 KiB |
BIN
gifs/order.gif
Before Width: | Height: | Size: 1.1 MiB |
BIN
gifs/table.gif
Before Width: | Height: | Size: 390 KiB |
BIN
gifs/tabs.gif
Before Width: | Height: | Size: 1.2 MiB |
BIN
gifs/theme.gif
Before Width: | Height: | Size: 265 KiB |
BIN
gifs/upload1.gif
Before Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 330 KiB |
16
index.html
|
@ -1,15 +1,15 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
<title>Juicy</title>
|
<title>vue-element-admin</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src=<%= htmlWebpackPlugin.options.path %>/tinymce/tinymce.min.js></script>
|
<script src=<%= htmlWebpackPlugin.options.path %>/tinymce4.7.5/tinymce.min.js></script>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
156
package.json
|
@ -1,96 +1,112 @@
|
||||||
{
|
{
|
||||||
"name": "juicy",
|
"name": "vue-element-admin",
|
||||||
"version": "2.0.0",
|
"version": "3.6.6",
|
||||||
"description": "A Vue.js admin",
|
"description": "A magical vue admin. Typical templates for enterprise applications. Newest development stack of vue. Lots of awesome features",
|
||||||
"author": "Pan <panfree23@gmail.com>",
|
"author": "Pan <panfree23@gmail.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"private": true,
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node build/dev-server.js",
|
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
||||||
"build:prod": "cross-env NODE_ENV=production node build/build.js",
|
"build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
|
||||||
"build:sit": "cross-env NODE_ENV=sit node build/build.js",
|
"build:sit": "cross-env NODE_ENV=production env_config=sit node build/build.js",
|
||||||
"build:sit-preview": "cross-env NODE_ENV=sit npm_config_preview=true npm_config_report=true node build/build.js",
|
"lint": "eslint --ext .js,.vue src",
|
||||||
"lint": "eslint --ext .js,.vue src"
|
"test": "npm run lint"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"vue",
|
||||||
|
"element-ui",
|
||||||
|
"admin",
|
||||||
|
"management-system",
|
||||||
|
"admin-template"
|
||||||
|
],
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "0.16.2",
|
"axios": "0.17.1",
|
||||||
"codemirror": "5.26.0",
|
"clipboard": "1.7.1",
|
||||||
"dropzone": "5.1.0",
|
"codemirror": "5.32.0",
|
||||||
"echarts": "3.6.2",
|
"dropzone": "5.2.0",
|
||||||
"element-ui": "1.4.2",
|
"echarts": "3.8.5",
|
||||||
|
"element-ui": "2.3.2",
|
||||||
"file-saver": "1.3.3",
|
"file-saver": "1.3.3",
|
||||||
"js-cookie": "2.1.4",
|
"font-awesome": "4.7.0",
|
||||||
|
"js-cookie": "2.2.0",
|
||||||
"jsonlint": "1.6.2",
|
"jsonlint": "1.6.2",
|
||||||
|
"jszip": "3.1.5",
|
||||||
"mockjs": "1.0.1-beta3",
|
"mockjs": "1.0.1-beta3",
|
||||||
"normalize.css": "7.0.0",
|
"normalize.css": "7.0.0",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"screenfull": "3.2.2",
|
"screenfull": "3.3.2",
|
||||||
"showdown": "1.7.1",
|
"showdown": "1.8.5",
|
||||||
"simplemde": "1.11.2",
|
"simplemde": "1.11.2",
|
||||||
"sortablejs": "1.5.1",
|
"sortablejs": "1.7.0",
|
||||||
"vue": "2.4.2",
|
"vue": "2.5.10",
|
||||||
"vue-count-to": "1.0.5",
|
"vue-count-to": "1.0.13",
|
||||||
"vue-multiselect": "2.0.2",
|
"vue-i18n": "7.3.2",
|
||||||
"vue-router": "2.7.0",
|
"vue-multiselect": "2.0.8",
|
||||||
"vue-splitpane": "^1.0.0",
|
"vue-router": "3.0.1",
|
||||||
"vuedraggable": "2.14.1",
|
"vue-splitpane": "1.0.2",
|
||||||
"vuex": "2.3.1",
|
"vuedraggable": "^2.16.0",
|
||||||
"xlsx": "^0.10.8"
|
"vuex": "3.0.1",
|
||||||
|
"xlsx": "^0.11.16"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "7.1.1",
|
"autoprefixer": "7.2.3",
|
||||||
"babel-core": "6.25.0",
|
"babel-core": "6.26.0",
|
||||||
"babel-eslint": "7.2.3",
|
"babel-eslint": "8.0.3",
|
||||||
"babel-loader": "7.0.0",
|
"babel-helper-vue-jsx-merge-props": "2.0.3",
|
||||||
|
"babel-loader": "7.1.2",
|
||||||
|
"babel-plugin-syntax-jsx": "6.18.0",
|
||||||
"babel-plugin-transform-runtime": "6.23.0",
|
"babel-plugin-transform-runtime": "6.23.0",
|
||||||
"babel-preset-env": "1.5.2",
|
"babel-plugin-transform-vue-jsx": "3.5.0",
|
||||||
|
"babel-preset-env": "1.6.1",
|
||||||
"babel-preset-stage-2": "6.24.1",
|
"babel-preset-stage-2": "6.24.1",
|
||||||
"babel-register": "6.24.1",
|
"chalk": "2.3.0",
|
||||||
"chalk": "1.1.3",
|
"copy-webpack-plugin": "4.3.0",
|
||||||
"connect-history-api-fallback": "1.3.0",
|
"cross-env": "5.1.1",
|
||||||
"copy-webpack-plugin": "4.0.1",
|
"css-loader": "0.28.7",
|
||||||
"cross-env": "5.0.1",
|
"eslint": "4.13.1",
|
||||||
"css-loader": "0.28.4",
|
|
||||||
"eslint": "3.19.0",
|
|
||||||
"eslint-friendly-formatter": "3.0.0",
|
"eslint-friendly-formatter": "3.0.0",
|
||||||
"eslint-import-resolver-webpack": "0.8.1",
|
"eslint-loader": "1.9.0",
|
||||||
"eslint-loader": "1.7.1",
|
"eslint-plugin-html": "4.0.1",
|
||||||
"eslint-plugin-html": "3.0.0",
|
"extract-text-webpack-plugin": "3.0.2",
|
||||||
"eslint-plugin-import": "2.3.0",
|
"file-loader": "1.1.5",
|
||||||
"eventsource-polyfill": "0.9.6",
|
|
||||||
"express": "4.15.3",
|
|
||||||
"extract-text-webpack-plugin": "2.1.2",
|
|
||||||
"file-loader": "0.11.2",
|
|
||||||
"friendly-errors-webpack-plugin": "1.6.1",
|
"friendly-errors-webpack-plugin": "1.6.1",
|
||||||
"function-bind": "1.1.0",
|
"html-webpack-plugin": "2.30.1",
|
||||||
"html-webpack-plugin": "2.28.0",
|
"node-notifier": "5.1.2",
|
||||||
"http-proxy-middleware": "0.17.4",
|
"node-sass": "^4.7.2",
|
||||||
"node-sass": "^4.5.0",
|
"optimize-css-assets-webpack-plugin": "3.2.0",
|
||||||
"opn": "4.0.2",
|
"ora": "1.3.0",
|
||||||
"optimize-css-assets-webpack-plugin": "1.3.0",
|
"portfinder": "1.0.13",
|
||||||
"ora": "1.1.0",
|
"postcss-import": "11.0.0",
|
||||||
"pushstate-server": "2.1.0",
|
"postcss-loader": "2.0.9",
|
||||||
"rimraf": "2.6.0",
|
"postcss-url": "7.3.0",
|
||||||
"sass-loader": "6.0.5",
|
"pushstate-server": "3.0.1",
|
||||||
"script-loader": "0.7.0",
|
"rimraf": "2.6.2",
|
||||||
"semver": "5.3.0",
|
"sass-loader": "6.0.6",
|
||||||
"style-loader": "0.17.0",
|
"script-loader": "0.7.2",
|
||||||
"svg-sprite-loader": "3.2.4",
|
"semver": "5.4.1",
|
||||||
"url-loader": "0.5.8",
|
"shelljs": "0.7.8",
|
||||||
"vue-loader": "13.0.4",
|
"svg-sprite-loader": "3.5.2",
|
||||||
"vue-style-loader": "3.0.1",
|
"uglifyjs-webpack-plugin": "1.1.3",
|
||||||
"vue-template-compiler": "2.4.2",
|
"url-loader": "0.6.2",
|
||||||
"webpack": "2.6.1",
|
"vue-loader": "13.5.0",
|
||||||
"webpack-bundle-analyzer": "2.8.2",
|
"vue-style-loader": "3.0.3",
|
||||||
"webpack-dev-middleware": "1.10.2",
|
"vue-template-compiler": "2.5.10",
|
||||||
"webpack-hot-middleware": "2.18.0",
|
"webpack": "3.10.0",
|
||||||
"webpack-merge": "4.1.0"
|
"webpack-bundle-analyzer": "2.9.1",
|
||||||
|
"webpack-dev-server": "2.9.7",
|
||||||
|
"webpack-merge": "4.1.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4.0.0",
|
"node": ">= 4.0.0",
|
||||||
"npm": ">= 3.0.0"
|
"npm": ">= 3.0.0"
|
||||||
},
|
},
|
||||||
"browserlist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
"not ie <= 8"
|
"not ie <= 8"
|
||||||
|
|
|
@ -6,11 +6,6 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default{
|
export default{
|
||||||
name: 'APP'
|
name: 'App'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import '~normalize.css/normalize.css';// normalize.css 样式格式化
|
|
||||||
@import './styles/index.scss'; // 全局自定义的css样式
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import fetch from '@/utils/fetch'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function fetchList(query) {
|
export function fetchList(query) {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/article/list',
|
url: '/article/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
|
@ -9,17 +9,32 @@ export function fetchList(query) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchArticle() {
|
export function fetchArticle() {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/article/detail',
|
url: '/article/detail',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchPv(pv) {
|
export function fetchPv(pv) {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/article/pv',
|
url: '/article/pv',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { pv }
|
params: { pv }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createArticle(data) {
|
||||||
|
return request({
|
||||||
|
url: '/article/create',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateArticle(data) {
|
||||||
|
return request({
|
||||||
|
url: '/article/update',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import fetch from '@/utils/fetch'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function loginByUsername(username, password) {
|
export function loginByUsername(username, password) {
|
||||||
const data = {
|
const data = {
|
||||||
username,
|
username,
|
||||||
password
|
password
|
||||||
}
|
}
|
||||||
return fetch({
|
return request({
|
||||||
url: '/login/login',
|
url: '/login/login',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
|
@ -13,14 +13,14 @@ export function loginByUsername(username, password) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/login/logout',
|
url: '/login/logout',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserInfo(token) {
|
export function getUserInfo(token) {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/user/info',
|
url: '/user/info',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { token }
|
params: { token }
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import fetch from '@/utils/fetch'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function getToken() {
|
export function getToken() {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/qiniu/upload/token', // 假地址 自行替换
|
url: '/qiniu/upload/token', // 假地址 自行替换
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import fetch from '@/utils/fetch'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function userSearch(name) {
|
export function userSearch(name) {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/search/user',
|
url: '/search/user',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { name }
|
params: { name }
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function fetchList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/transaction/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<transition :name="transitionName">
|
<transition :name="transitionName">
|
||||||
<div class="back-to-top" @click="backToTop" v-show="visible" :style="customStyle">
|
<div class="back-to-ceiling" @click="backToTop" v-show="visible" :style="customStyle">
|
||||||
<svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;">
|
<svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height: 16px; width: 16px;">
|
||||||
<title>回到顶部</title>
|
<title>回到顶部</title>
|
||||||
<g>
|
<g>
|
||||||
|
@ -25,7 +25,8 @@ export default {
|
||||||
},
|
},
|
||||||
customStyle: {
|
customStyle: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {
|
default: function() {
|
||||||
|
return {
|
||||||
right: '50px',
|
right: '50px',
|
||||||
bottom: '50px',
|
bottom: '50px',
|
||||||
width: '40px',
|
width: '40px',
|
||||||
|
@ -34,6 +35,7 @@ export default {
|
||||||
'line-height': '45px',
|
'line-height': '45px',
|
||||||
background: '#e7eaf1'
|
background: '#e7eaf1'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
transitionName: {
|
transitionName: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -82,14 +84,14 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.back-to-top {
|
.back-to-ceiling {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-to-top:hover {
|
.back-to-ceiling:hover {
|
||||||
background: #d5dbe7;
|
background: #d5dbe7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +105,7 @@ export default {
|
||||||
opacity: 0
|
opacity: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-to-top .Icon {
|
.back-to-ceiling .Icon {
|
||||||
fill: #9aaabf;
|
fill: #9aaabf;
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
<template>
|
||||||
|
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||||
|
<transition-group name="breadcrumb">
|
||||||
|
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path" v-if='item.meta.title'>
|
||||||
|
<span v-if='item.redirect==="noredirect"||index==levelList.length-1' class="no-redirect">{{generateTitle(item.meta.title)}}</span>
|
||||||
|
<router-link v-else :to="item.redirect||item.path">{{generateTitle(item.meta.title)}}</router-link>
|
||||||
|
</el-breadcrumb-item>
|
||||||
|
</transition-group>
|
||||||
|
</el-breadcrumb>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { generateTitle } from '@/utils/i18n'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
created() {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
levelList: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route() {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
generateTitle,
|
||||||
|
getBreadcrumb() {
|
||||||
|
let matched = this.$route.matched.filter(item => item.name)
|
||||||
|
const first = matched[0]
|
||||||
|
if (first && first.name !== 'dashboard') {
|
||||||
|
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
|
||||||
|
}
|
||||||
|
this.levelList = matched
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.app-breadcrumb.el-breadcrumb {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 50px;
|
||||||
|
margin-left: 10px;
|
||||||
|
.no-redirect {
|
||||||
|
color: #97a8be;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -4,8 +4,10 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import echarts from 'echarts'
|
import echarts from 'echarts'
|
||||||
|
import resize from './mixins/resize'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [resize],
|
||||||
props: {
|
props: {
|
||||||
className: {
|
className: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -45,21 +47,22 @@ export default {
|
||||||
|
|
||||||
const xAxisData = []
|
const xAxisData = []
|
||||||
const data = []
|
const data = []
|
||||||
for (let i = 0; i < 30; i++) {
|
const data2 = []
|
||||||
xAxisData.push(i + '号')
|
for (let i = 0; i < 50; i++) {
|
||||||
data.push(Math.round(Math.random() * 2 + 3))
|
xAxisData.push(i)
|
||||||
|
data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
|
||||||
|
data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chart.setOption(
|
this.chart.setOption(
|
||||||
{
|
{
|
||||||
backgroundColor: '#08263a',
|
backgroundColor: '#08263a',
|
||||||
tooltip: {
|
xAxis: [{
|
||||||
trigger: 'axis'
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
show: false,
|
show: false,
|
||||||
data: xAxisData
|
data: xAxisData
|
||||||
},
|
}, {
|
||||||
|
show: false,
|
||||||
|
data: xAxisData
|
||||||
|
}],
|
||||||
visualMap: {
|
visualMap: {
|
||||||
show: false,
|
show: false,
|
||||||
min: 0,
|
min: 0,
|
||||||
|
@ -84,19 +87,56 @@ export default {
|
||||||
color: '#08263f'
|
color: '#08263f'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
axisTick: {}
|
axisTick: {
|
||||||
},
|
show: false
|
||||||
series: [{
|
|
||||||
type: 'bar',
|
|
||||||
data,
|
|
||||||
name: '撸文数',
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
barBorderRadius: 5,
|
|
||||||
shadowBlur: 10,
|
|
||||||
shadowColor: '#111'
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'back',
|
||||||
|
type: 'bar',
|
||||||
|
data: data2,
|
||||||
|
z: 1,
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
opacity: 0.4,
|
||||||
|
barBorderRadius: 5,
|
||||||
|
shadowBlur: 3,
|
||||||
|
shadowColor: '#111'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'Simulate Shadow',
|
||||||
|
type: 'line',
|
||||||
|
data,
|
||||||
|
z: 2,
|
||||||
|
showSymbol: false,
|
||||||
|
animationDelay: 0,
|
||||||
|
animationEasing: 'linear',
|
||||||
|
animationDuration: 1200,
|
||||||
|
lineStyle: {
|
||||||
|
normal: {
|
||||||
|
color: 'transparent'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#08263a',
|
||||||
|
shadowBlur: 50,
|
||||||
|
shadowColor: '#000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: 'front',
|
||||||
|
type: 'bar',
|
||||||
|
data,
|
||||||
|
xAxisIndex: 1,
|
||||||
|
z: 3,
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
barBorderRadius: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
animationEasing: 'elasticOut',
|
animationEasing: 'elasticOut',
|
||||||
animationEasingUpdate: 'elasticOut',
|
animationEasingUpdate: 'elasticOut',
|
||||||
animationDelay(idx) {
|
animationDelay(idx) {
|
||||||
|
@ -105,7 +145,6 @@ export default {
|
||||||
animationDelayUpdate(idx) {
|
animationDelayUpdate(idx) {
|
||||||
return idx * 20
|
return idx * 20
|
||||||
}
|
}
|
||||||
}]
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,150 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import echarts from 'echarts'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
className: {
|
|
||||||
type: String,
|
|
||||||
default: 'chart'
|
|
||||||
},
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: 'chart'
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: String,
|
|
||||||
default: '200px'
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: String,
|
|
||||||
default: '200px'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
chart: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.initChart()
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
if (!this.chart) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.chart.dispose()
|
|
||||||
this.chart = null
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
initChart() {
|
|
||||||
this.chart = echarts.init(document.getElementById(this.id))
|
|
||||||
|
|
||||||
const xAxisData = []
|
|
||||||
const data = []
|
|
||||||
const data2 = []
|
|
||||||
for (let i = 0; i < 50; i++) {
|
|
||||||
xAxisData.push(i)
|
|
||||||
data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
|
|
||||||
data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
|
|
||||||
}
|
|
||||||
this.chart.setOption(
|
|
||||||
{
|
|
||||||
backgroundColor: '#08263a',
|
|
||||||
xAxis: [{
|
|
||||||
show: false,
|
|
||||||
data: xAxisData
|
|
||||||
}, {
|
|
||||||
show: false,
|
|
||||||
data: xAxisData
|
|
||||||
}],
|
|
||||||
visualMap: {
|
|
||||||
show: false,
|
|
||||||
min: 0,
|
|
||||||
max: 50,
|
|
||||||
dimension: 0,
|
|
||||||
inRange: {
|
|
||||||
color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
axisLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
textStyle: {
|
|
||||||
color: '#4a657a'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
show: true,
|
|
||||||
lineStyle: {
|
|
||||||
color: '#08263f'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisTick: {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
series: [{
|
|
||||||
name: 'back',
|
|
||||||
type: 'bar',
|
|
||||||
data: data2,
|
|
||||||
z: 1,
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
opacity: 0.4,
|
|
||||||
barBorderRadius: 5,
|
|
||||||
shadowBlur: 3,
|
|
||||||
shadowColor: '#111'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
name: 'Simulate Shadow',
|
|
||||||
type: 'line',
|
|
||||||
data,
|
|
||||||
z: 2,
|
|
||||||
showSymbol: false,
|
|
||||||
animationDelay: 0,
|
|
||||||
animationEasing: 'linear',
|
|
||||||
animationDuration: 1200,
|
|
||||||
lineStyle: {
|
|
||||||
normal: {
|
|
||||||
color: 'transparent'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
areaStyle: {
|
|
||||||
normal: {
|
|
||||||
color: '#08263a',
|
|
||||||
shadowBlur: 50,
|
|
||||||
shadowColor: '#000'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
name: 'front',
|
|
||||||
type: 'bar',
|
|
||||||
data,
|
|
||||||
xAxisIndex: 1,
|
|
||||||
z: 3,
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
barBorderRadius: 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
animationEasing: 'elasticOut',
|
|
||||||
animationEasingUpdate: 'elasticOut',
|
|
||||||
animationDelay(idx) {
|
|
||||||
return idx * 20
|
|
||||||
},
|
|
||||||
animationDelayUpdate(idx) {
|
|
||||||
return idx * 20
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -4,8 +4,10 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import echarts from 'echarts'
|
import echarts from 'echarts'
|
||||||
|
import resize from './mixins/resize'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [resize],
|
||||||
props: {
|
props: {
|
||||||
className: {
|
className: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -46,13 +48,14 @@ export default {
|
||||||
this.chart.setOption({
|
this.chart.setOption({
|
||||||
backgroundColor: '#394056',
|
backgroundColor: '#394056',
|
||||||
title: {
|
title: {
|
||||||
text: '请求数',
|
top: 20,
|
||||||
|
text: 'Requests',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontWeight: 'normal',
|
fontWeight: 'normal',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: '#F1F1F3'
|
color: '#F1F1F3'
|
||||||
},
|
},
|
||||||
left: '6%'
|
left: '1%'
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
|
@ -63,11 +66,12 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
top: 20,
|
||||||
icon: 'rect',
|
icon: 'rect',
|
||||||
itemWidth: 14,
|
itemWidth: 14,
|
||||||
itemHeight: 5,
|
itemHeight: 5,
|
||||||
itemGap: 13,
|
itemGap: 13,
|
||||||
data: ['移动', '电信', '联通'],
|
data: ['CMCC', 'CTCC', 'CUCC'],
|
||||||
right: '4%',
|
right: '4%',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
|
@ -75,9 +79,10 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
|
top: 100,
|
||||||
left: '3%',
|
left: '3%',
|
||||||
right: '4%',
|
right: '4%',
|
||||||
bottom: '3%',
|
bottom: '2%',
|
||||||
containLabel: true
|
containLabel: true
|
||||||
},
|
},
|
||||||
xAxis: [{
|
xAxis: [{
|
||||||
|
@ -92,7 +97,7 @@ export default {
|
||||||
}],
|
}],
|
||||||
yAxis: [{
|
yAxis: [{
|
||||||
type: 'value',
|
type: 'value',
|
||||||
name: '单位(%)',
|
name: '(%)',
|
||||||
axisTick: {
|
axisTick: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
|
@ -114,7 +119,7 @@ export default {
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
series: [{
|
series: [{
|
||||||
name: '移动',
|
name: 'CMCC',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
smooth: true,
|
smooth: true,
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
|
@ -148,7 +153,7 @@ export default {
|
||||||
},
|
},
|
||||||
data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
|
data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
|
||||||
}, {
|
}, {
|
||||||
name: '电信',
|
name: 'CTCC',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
smooth: true,
|
smooth: true,
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
|
@ -182,7 +187,7 @@ export default {
|
||||||
},
|
},
|
||||||
data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
|
data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
|
||||||
}, {
|
}, {
|
||||||
name: '联通',
|
name: 'CUCC',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
smooth: true,
|
smooth: true,
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
|
|
|
@ -4,8 +4,10 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import echarts from 'echarts'
|
import echarts from 'echarts'
|
||||||
|
import resize from './mixins/resize'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [resize],
|
||||||
props: {
|
props: {
|
||||||
className: {
|
className: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -31,7 +33,6 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initChart()
|
this.initChart()
|
||||||
this.chart = null
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (!this.chart) {
|
if (!this.chart) {
|
||||||
|
@ -46,15 +47,16 @@ export default {
|
||||||
const xData = (function() {
|
const xData = (function() {
|
||||||
const data = []
|
const data = []
|
||||||
for (let i = 1; i < 13; i++) {
|
for (let i = 1; i < 13; i++) {
|
||||||
data.push(i + '月份')
|
data.push(i + 'month')
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}())
|
}())
|
||||||
this.chart.setOption({
|
this.chart.setOption({
|
||||||
backgroundColor: '#344b58',
|
backgroundColor: '#344b58',
|
||||||
title: {
|
title: {
|
||||||
text: '统计',
|
text: 'statistics',
|
||||||
x: '4%',
|
x: '20',
|
||||||
|
top: '20',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
fontSize: '22'
|
fontSize: '22'
|
||||||
|
@ -81,12 +83,12 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
x: '15%',
|
x: '5%',
|
||||||
top: '10%',
|
top: '10%',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: '#90979c'
|
color: '#90979c'
|
||||||
},
|
},
|
||||||
data: ['女', '男', '平均']
|
data: ['female', 'male', 'average']
|
||||||
},
|
},
|
||||||
calculable: true,
|
calculable: true,
|
||||||
xAxis: [{
|
xAxis: [{
|
||||||
|
@ -158,9 +160,9 @@ export default {
|
||||||
end: 35
|
end: 35
|
||||||
}],
|
}],
|
||||||
series: [{
|
series: [{
|
||||||
name: '女',
|
name: 'female',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack: '总量',
|
stack: 'total',
|
||||||
barMaxWidth: 35,
|
barMaxWidth: 35,
|
||||||
barGap: '10%',
|
barGap: '10%',
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
|
@ -195,9 +197,9 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: '男',
|
name: 'male',
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack: '总量',
|
stack: 'total',
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
normal: {
|
normal: {
|
||||||
color: 'rgba(0,191,183,1)',
|
color: 'rgba(0,191,183,1)',
|
||||||
|
@ -226,9 +228,9 @@ export default {
|
||||||
220
|
220
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
name: '平均',
|
name: 'average',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
stack: '总量',
|
stack: 'total',
|
||||||
symbolSize: 10,
|
symbolSize: 10,
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { debounce } from '@/utils'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted() {
|
||||||
|
this.__resizeHanlder = debounce(() => {
|
||||||
|
if (this.chart) {
|
||||||
|
this.chart.resize()
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
window.addEventListener('resize', this.__resizeHanlder)
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener('resize', this.__resizeHanlder)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="twoDndList">
|
<div class="dndList">
|
||||||
<div class="twoDndList-list" :style="{width:width1}">
|
<div class="dndList-list" :style="{width:width1}">
|
||||||
<h3>{{list1Title}}</h3>
|
<h3>{{list1Title}}</h3>
|
||||||
<draggable :list="list1" class="dragArea" :options="{group:'article'}">
|
<draggable :list="list1" class="dragArea" :options="{group:'article'}">
|
||||||
<div class="list-complete-item" v-for="element in list1" :key='element.id'>
|
<div class="list-complete-item" v-for="element in list1" :key='element.id'>
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
</div>
|
</div>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
<div class="twoDndList-list" :style="{width:width2}">
|
<div class="dndList-list" :style="{width:width2}">
|
||||||
<h3>{{list2Title}}</h3>
|
<h3>{{list2Title}}</h3>
|
||||||
<draggable :list="filterList2" class="dragArea" :options="{group:'article'}">
|
<draggable :list="filterList2" class="dragArea" :options="{group:'article'}">
|
||||||
<div class="list-complete-item" v-for="element in filterList2" :key='element.id'>
|
<div class="list-complete-item" v-for="element in filterList2" :key='element.id'>
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'twoDndList',
|
name: 'DndList',
|
||||||
components: { draggable },
|
components: { draggable },
|
||||||
computed: {
|
computed: {
|
||||||
filterList2() {
|
filterList2() {
|
||||||
|
@ -97,7 +97,7 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
.twoDndList {
|
.dndList {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
padding-bottom: 40px;
|
padding-bottom: 40px;
|
||||||
&:after {
|
&:after {
|
||||||
|
@ -105,7 +105,7 @@ export default {
|
||||||
display: table;
|
display: table;
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
.twoDndList-list {
|
.dndList-list {
|
||||||
float: left;
|
float: left;
|
||||||
padding-bottom: 30px;
|
padding-bottom: 30px;
|
||||||
&:first-of-type {
|
&:first-of-type {
|
|
@ -7,7 +7,7 @@
|
||||||
<script>
|
<script>
|
||||||
import Dropzone from 'dropzone'
|
import Dropzone from 'dropzone'
|
||||||
import 'dropzone/dist/dropzone.css'
|
import 'dropzone/dist/dropzone.css'
|
||||||
// import { getToken } from 'api/qiniu';
|
// import { getToken } from 'api/qiniu';
|
||||||
|
|
||||||
Dropzone.autoDiscover = false
|
Dropzone.autoDiscover = false
|
||||||
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<el-badge :is-dot="true" style="line-height: 30px;" @click.native="dialogTableVisible=true">
|
|
||||||
<el-button size="small" type="primary">
|
|
||||||
<svg t="1492682037685" class="bug-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1863"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
|
|
||||||
<path d="M969.142857 548.571429q0 14.848-10.861714 25.709714t-25.709714 10.861714l-128 0q0 97.718857-38.290286 165.705143l118.857143 119.442286q10.861714 10.861714 10.861714 25.709714t-10.861714 25.709714q-10.276571 10.861714-25.709714 10.861714t-25.709714-10.861714l-113.152-112.566857q-2.852571 2.852571-8.557714 7.424t-23.990857 16.274286-37.156571 20.845714-46.848 16.566857-55.442286 7.424l0-512-73.142857 0 0 512q-29.147429 0-58.002286-7.716571t-49.700571-18.870857-37.705143-22.272-24.868571-18.578286l-8.557714-8.009143-104.557714 118.272q-11.446857 11.995429-27.428571 11.995429-13.714286 0-24.576-9.142857-10.861714-10.276571-11.702857-25.417143t8.850286-26.587429l115.419429-129.718857q-33.133714-65.133714-33.133714-156.562286l-128 0q-14.848 0-25.709714-10.861714t-10.861714-25.709714 10.861714-25.709714 25.709714-10.861714l128 0 0-168.009143-98.852571-98.852571q-10.861714-10.861714-10.861714-25.709714t10.861714-25.709714 25.709714-10.861714 25.709714 10.861714l98.852571 98.852571 482.304 0 98.852571-98.852571q10.861714-10.861714 25.709714-10.861714t25.709714 10.861714 10.861714 25.709714-10.861714 25.709714l-98.852571 98.852571 0 168.009143 128 0q14.848 0 25.709714 10.861714t10.861714 25.709714zM694.857143 219.428571l-365.714286 0q0-75.995429 53.430857-129.426286t129.426286-53.430857 129.426286 53.430857 53.430857 129.426286z"
|
|
||||||
p-id="1864"></path>
|
|
||||||
</svg>
|
|
||||||
</el-button>
|
|
||||||
</el-badge>
|
|
||||||
<el-dialog title="bug日志" :visible.sync="dialogTableVisible">
|
|
||||||
<el-table :data="logsList">
|
|
||||||
<el-table-column label="message">
|
|
||||||
<template scope="scope">
|
|
||||||
<div>msg:{{ scope.row.err.message }}</div>
|
|
||||||
<br/>
|
|
||||||
<div>url: {{scope.row.url}}</div>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column label="stack">
|
|
||||||
<template scope="scope">
|
|
||||||
{{ scope.row.err.stack}}
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
</el-table>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'errLog',
|
|
||||||
props: {
|
|
||||||
logsList: {
|
|
||||||
type: Array
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dialogTableVisible: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.bug-svg {
|
|
||||||
width: 1em;
|
|
||||||
height: 1em;
|
|
||||||
vertical-align: -0.15em;
|
|
||||||
fill: currentColor;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="errorLogs.length>0">
|
||||||
|
<el-badge :is-dot="true" style="line-height: 30px;" @click.native="dialogTableVisible=true">
|
||||||
|
<el-button size="small" type="danger" class="bug-btn">
|
||||||
|
<svg t="1492682037685" class="bug-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1863"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128">
|
||||||
|
<path d="M969.142857 548.571429q0 14.848-10.861714 25.709714t-25.709714 10.861714l-128 0q0 97.718857-38.290286 165.705143l118.857143 119.442286q10.861714 10.861714 10.861714 25.709714t-10.861714 25.709714q-10.276571 10.861714-25.709714 10.861714t-25.709714-10.861714l-113.152-112.566857q-2.852571 2.852571-8.557714 7.424t-23.990857 16.274286-37.156571 20.845714-46.848 16.566857-55.442286 7.424l0-512-73.142857 0 0 512q-29.147429 0-58.002286-7.716571t-49.700571-18.870857-37.705143-22.272-24.868571-18.578286l-8.557714-8.009143-104.557714 118.272q-11.446857 11.995429-27.428571 11.995429-13.714286 0-24.576-9.142857-10.861714-10.276571-11.702857-25.417143t8.850286-26.587429l115.419429-129.718857q-33.133714-65.133714-33.133714-156.562286l-128 0q-14.848 0-25.709714-10.861714t-10.861714-25.709714 10.861714-25.709714 25.709714-10.861714l128 0 0-168.009143-98.852571-98.852571q-10.861714-10.861714-10.861714-25.709714t10.861714-25.709714 25.709714-10.861714 25.709714 10.861714l98.852571 98.852571 482.304 0 98.852571-98.852571q10.861714-10.861714 25.709714-10.861714t25.709714 10.861714 10.861714 25.709714-10.861714 25.709714l-98.852571 98.852571 0 168.009143 128 0q14.848 0 25.709714 10.861714t10.861714 25.709714zM694.857143 219.428571l-365.714286 0q0-75.995429 53.430857-129.426286t129.426286-53.430857 129.426286 53.430857 53.430857 129.426286z"
|
||||||
|
p-id="1864"></path>
|
||||||
|
</svg>
|
||||||
|
</el-button>
|
||||||
|
</el-badge>
|
||||||
|
|
||||||
|
<el-dialog title="Error Log" :visible.sync="dialogTableVisible" width="80%">
|
||||||
|
<el-table :data="errorLogs" border>
|
||||||
|
<el-table-column label="Message">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div>
|
||||||
|
<span class="message-title">Msg:</span>
|
||||||
|
<el-tag type="danger">{{ scope.row.err.message }}</el-tag>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<div>
|
||||||
|
<span class="message-title" style="padding-right: 10px;">Info: </span>
|
||||||
|
<el-tag type="warning">{{scope.row.vm.$vnode.tag}} error in {{scope.row.info}}</el-tag>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<div>
|
||||||
|
<span class="message-title" style="padding-right: 16px;">Url: </span>
|
||||||
|
<el-tag type="success">{{scope.row.url}}</el-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="Stack">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
{{ scope.row.err.stack}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'errorLog',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogTableVisible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
errorLogs() {
|
||||||
|
return this.$store.getters.errorLogs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.bug-btn.el-button--small {
|
||||||
|
padding: 9px 10px;
|
||||||
|
}
|
||||||
|
.bug-svg {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
fill: currentColor;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.message-title {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github">
|
<a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github">
|
||||||
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#4AB7BD; color:#fff; position: absolute; top: 50px; border: 0; right: 0;"
|
<svg width="80" height="80" viewBox="0 0 250 250" style="fill:#40c9c6; color:#fff; position: absolute; top: 84px; border: 0; right: 0;"
|
||||||
aria-hidden="true">
|
aria-hidden="true">
|
||||||
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
|
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
|
||||||
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
|
<path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
|
||||||
|
@ -11,3 +11,32 @@
|
||||||
</a>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.github-corner:hover .octo-arm {
|
||||||
|
animation: octocat-wave 560ms ease-in-out
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes octocat-wave {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: rotate(0)
|
||||||
|
}
|
||||||
|
20%,
|
||||||
|
60% {
|
||||||
|
transform: rotate(-25deg)
|
||||||
|
}
|
||||||
|
40%,
|
||||||
|
80% {
|
||||||
|
transform: rotate(10deg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width:500px) {
|
||||||
|
.github-corner:hover .octo-arm {
|
||||||
|
animation: none
|
||||||
|
}
|
||||||
|
.github-corner .octo-arm {
|
||||||
|
animation: octocat-wave 560ms ease-in-out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<svg t="1492500959545" @click="toggleClick" class="wscn-icon hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
|
<svg t="1492500959545" @click="toggleClick" class="hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
|
||||||
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
|
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
|
||||||
<path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
|
<path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
|
||||||
p-id="1692"></path>
|
p-id="1692"></path>
|
||||||
|
@ -34,13 +34,12 @@ export default {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
transform: rotate(0deg);
|
transform: rotate(90deg);
|
||||||
transition: .38s;
|
transition: .38s;
|
||||||
transform-origin: 50% 50%;
|
transform-origin: 50% 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hamburger.is-active {
|
.hamburger.is-active {
|
||||||
transform: rotate(90deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
<template>
|
|
||||||
<svg class="svg-icon" aria-hidden="true">
|
|
||||||
<use :xlink:href="iconName"></use>
|
|
||||||
</svg>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'icon-svg',
|
|
||||||
props: {
|
|
||||||
iconClass: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
iconName() {
|
|
||||||
return `#icon-${this.iconClass}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
|
@ -1,41 +0,0 @@
|
||||||
const langBag = {
|
|
||||||
zh: {
|
|
||||||
hint: '点击,或拖动图片至此处',
|
|
||||||
loading: '正在上传……',
|
|
||||||
noSupported: '浏览器不支持该功能,请使用IE10以上或其他现在浏览器!',
|
|
||||||
success: '上传成功',
|
|
||||||
fail: '图片上传失败',
|
|
||||||
preview: '头像预览',
|
|
||||||
btn: {
|
|
||||||
off: '取消',
|
|
||||||
close: '关闭',
|
|
||||||
back: '上一步',
|
|
||||||
save: '保存'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: '仅限图片格式',
|
|
||||||
outOfSize: '单文件大小不能超过 ',
|
|
||||||
lowestPx: '图片最低像素为(宽*高):'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
en: {
|
|
||||||
hint: 'Click, or drag the file here',
|
|
||||||
loading: 'Uploading……',
|
|
||||||
noSupported: 'Browser does not support, please use IE10+ or other browsers',
|
|
||||||
success: 'Upload success',
|
|
||||||
fail: 'Upload failed',
|
|
||||||
preview: 'Preview',
|
|
||||||
btn: {
|
|
||||||
off: 'Cancel',
|
|
||||||
close: 'Close',
|
|
||||||
back: 'Back',
|
|
||||||
save: 'Save'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
onlyImg: 'Image only',
|
|
||||||
outOfSize: 'Image exceeds size limit: ',
|
|
||||||
lowestPx: 'The lowest pixel in the image: '
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default langBag
|
|
|
@ -1,691 +0,0 @@
|
||||||
@charset "UTF-8";
|
|
||||||
@-webkit-keyframes vicp_progress {
|
|
||||||
0% {
|
|
||||||
background-position-y: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-position-y: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vicp_progress {
|
|
||||||
0% {
|
|
||||||
background-position-y: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-position-y: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes vicp {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
-webkit-transform: scale(0) translatey(-60px);
|
|
||||||
transform: scale(0) translatey(-60px);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
-webkit-transform: scale(1) translatey(0);
|
|
||||||
transform: scale(1) translatey(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes vicp {
|
|
||||||
0% {
|
|
||||||
opacity: 0;
|
|
||||||
-webkit-transform: scale(0) translatey(-60px);
|
|
||||||
transform: scale(0) translatey(-60px);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
opacity: 1;
|
|
||||||
-webkit-transform: scale(1) translatey(0);
|
|
||||||
transform: scale(1) translatey(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload {
|
|
||||||
position: fixed;
|
|
||||||
display: block;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 10000;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.65);
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
-moz-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap {
|
|
||||||
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
|
||||||
position: fixed;
|
|
||||||
display: block;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 10000;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
margin: auto;
|
|
||||||
width: 600px;
|
|
||||||
height: 330px;
|
|
||||||
padding: 25px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 2px;
|
|
||||||
-webkit-animation: vicp 0.12s ease-in;
|
|
||||||
animation: vicp 0.12s ease-in;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-close {
|
|
||||||
position: absolute;
|
|
||||||
right: -30px;
|
|
||||||
top: -30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4 {
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
cursor: pointer;
|
|
||||||
-webkit-transition: -webkit-transform 0.18s;
|
|
||||||
transition: -webkit-transform 0.18s;
|
|
||||||
transition: transform 0.18s;
|
|
||||||
transition: transform 0.18s, -webkit-transform 0.18s;
|
|
||||||
-webkit-transform: rotate(0);
|
|
||||||
-ms-transform: rotate(0);
|
|
||||||
transform: rotate(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after, .vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::before {
|
|
||||||
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 12px;
|
|
||||||
left: 4px;
|
|
||||||
width: 20px;
|
|
||||||
height: 3px;
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
-ms-transform: rotate(45deg);
|
|
||||||
transform: rotate(45deg);
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4::after {
|
|
||||||
-webkit-transform: rotate(-45deg);
|
|
||||||
-ms-transform: rotate(-45deg);
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-close .vicp-icon4:hover {
|
|
||||||
-webkit-transform: rotate(90deg);
|
|
||||||
-ms-transform: rotate(90deg);
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area {
|
|
||||||
position: relative;
|
|
||||||
padding: 35px;
|
|
||||||
height: 200px;
|
|
||||||
background-color: rgba(0, 0, 0, 0.03);
|
|
||||||
text-align: center;
|
|
||||||
border: 1px dashed rgba(0, 0, 0, 0.08);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto 6px;
|
|
||||||
width: 42px;
|
|
||||||
height: 42px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-arrow {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border-bottom: 14.7px solid rgba(0, 0, 0, 0.3);
|
|
||||||
border-left: 14.7px solid transparent;
|
|
||||||
border-right: 14.7px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-body {
|
|
||||||
display: block;
|
|
||||||
width: 12.6px;
|
|
||||||
height: 14.7px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background-color: rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-icon1 .vicp-icon1-bottom {
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: block;
|
|
||||||
height: 12.6px;
|
|
||||||
border: 6px solid rgba(0, 0, 0, 0.3);
|
|
||||||
border-top: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-hint {
|
|
||||||
display: block;
|
|
||||||
padding: 15px;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #666;
|
|
||||||
line-height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area .vicp-no-supported-hint {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
padding: 30px;
|
|
||||||
width: 100%;
|
|
||||||
height: 60px;
|
|
||||||
line-height: 30px;
|
|
||||||
background-color: #eee;
|
|
||||||
text-align: center;
|
|
||||||
color: #666;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step1 .vicp-drop-area:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
border-color: rgba(0, 0, 0, 0.1);
|
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container {
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
width: 240px;
|
|
||||||
height: 180px;
|
|
||||||
background-color: #e5e5e0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
cursor: move;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade {
|
|
||||||
-webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
|
||||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
|
||||||
position: absolute;
|
|
||||||
background-color: rgba(241, 242, 243, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade.vicp-img-shade-1 {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-img-container .vicp-img-shade.vicp-img-shade-2 {
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range {
|
|
||||||
position: relative;
|
|
||||||
margin: 30px 0;
|
|
||||||
width: 240px;
|
|
||||||
height: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5,
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6 {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
border-radius: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5:hover,
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6:hover {
|
|
||||||
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: rgba(0, 0, 0, 0.14);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5 {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon5::before {
|
|
||||||
position: absolute;
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
left: 3px;
|
|
||||||
top: 8px;
|
|
||||||
width: 12px;
|
|
||||||
height: 2px;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6 {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6::before {
|
|
||||||
position: absolute;
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
left: 3px;
|
|
||||||
top: 8px;
|
|
||||||
width: 12px;
|
|
||||||
height: 2px;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range .vicp-icon6::after {
|
|
||||||
position: absolute;
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
top: 3px;
|
|
||||||
left: 8px;
|
|
||||||
width: 2px;
|
|
||||||
height: 12px;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range] {
|
|
||||||
display: block;
|
|
||||||
padding-top: 5px;
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 180px;
|
|
||||||
height: 8px;
|
|
||||||
vertical-align: top;
|
|
||||||
background: transparent;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
-moz-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
cursor: pointer;
|
|
||||||
/* 滑块
|
|
||||||
---------------------------------------------------------------*/
|
|
||||||
/* 轨道
|
|
||||||
---------------------------------------------------------------*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-webkit-slider-thumb {
|
|
||||||
-webkit-box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
|
||||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
margin-top: -3px;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
background-color: #61c091;
|
|
||||||
border-radius: 100%;
|
|
||||||
border: none;
|
|
||||||
-webkit-transition: 0.2s;
|
|
||||||
transition: 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-moz-range-thumb {
|
|
||||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
|
||||||
-moz-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
background-color: #61c091;
|
|
||||||
border-radius: 100%;
|
|
||||||
border: none;
|
|
||||||
-webkit-transition: 0.2s;
|
|
||||||
transition: 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-thumb {
|
|
||||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.18);
|
|
||||||
appearance: none;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
background-color: #61c091;
|
|
||||||
border: none;
|
|
||||||
border-radius: 100%;
|
|
||||||
-webkit-transition: 0.2s;
|
|
||||||
transition: 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-moz-range-thumb {
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-ms-thumb {
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:active::-webkit-slider-thumb {
|
|
||||||
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.23);
|
|
||||||
margin-top: -4px;
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-webkit-slider-runnable-track {
|
|
||||||
-webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
width: 100%;
|
|
||||||
height: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 2px;
|
|
||||||
border: none;
|
|
||||||
background-color: rgba(68, 170, 119, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-moz-range-track {
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
width: 100%;
|
|
||||||
height: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 2px;
|
|
||||||
border: none;
|
|
||||||
background-color: rgba(68, 170, 119, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-track {
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
width: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
background: transparent;
|
|
||||||
border-color: transparent;
|
|
||||||
color: transparent;
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 2px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-fill-lower {
|
|
||||||
background-color: rgba(68, 170, 119, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]::-ms-fill-upper {
|
|
||||||
background-color: rgba(68, 170, 119, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-webkit-slider-runnable-track {
|
|
||||||
background-color: rgba(68, 170, 119, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-moz-range-track {
|
|
||||||
background-color: rgba(68, 170, 119, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-ms-fill-lower {
|
|
||||||
background-color: rgba(68, 170, 119, 0.45);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-left .vicp-range input[type=range]:focus::-ms-fill-upper {
|
|
||||||
background-color: rgba(68, 170, 119, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview {
|
|
||||||
height: 150px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item {
|
|
||||||
position: relative;
|
|
||||||
padding: 5px;
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
float: left;
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item span {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -30px;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #bbb;
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item img {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
margin: auto;
|
|
||||||
padding: 3px;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
|
||||||
overflow: hidden;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step2 .vicp-crop .vicp-crop-right .vicp-preview .vicp-preview-item:last-child img {
|
|
||||||
border-radius: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload {
|
|
||||||
position: relative;
|
|
||||||
padding: 35px;
|
|
||||||
height: 200px;
|
|
||||||
background-color: rgba(0, 0, 0, 0.03);
|
|
||||||
text-align: center;
|
|
||||||
border: 1px dashed #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-loading {
|
|
||||||
display: block;
|
|
||||||
padding: 15px;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #999;
|
|
||||||
line-height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap {
|
|
||||||
margin-top: 12px;
|
|
||||||
background-color: rgba(0, 0, 0, 0.08);
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap .vicp-progress {
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
height: 5px;
|
|
||||||
border-radius: 3px;
|
|
||||||
background-color: #4a7;
|
|
||||||
-webkit-box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
|
|
||||||
box-shadow: 0 2px 6px 0 rgba(68, 170, 119, 0.3);
|
|
||||||
-webkit-transition: width 0.15s linear;
|
|
||||||
transition: width 0.15s linear;
|
|
||||||
background-image: -webkit-linear-gradient(135deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
|
|
||||||
background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.2) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.2) 75%, transparent 75%, transparent);
|
|
||||||
background-size: 40px 40px;
|
|
||||||
-webkit-animation: vicp_progress 0.5s linear infinite;
|
|
||||||
animation: vicp_progress 0.5s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-progress-wrap .vicp-progress::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
top: -3px;
|
|
||||||
right: -3px;
|
|
||||||
width: 9px;
|
|
||||||
height: 9px;
|
|
||||||
border: 1px solid rgba(245, 246, 247, 0.7);
|
|
||||||
-webkit-box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
|
|
||||||
box-shadow: 0 1px 4px 0 rgba(68, 170, 119, 0.7);
|
|
||||||
border-radius: 100%;
|
|
||||||
background-color: #4a7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-error,
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-step3 .vicp-upload .vicp-success {
|
|
||||||
height: 100px;
|
|
||||||
line-height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-operate {
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-operate a {
|
|
||||||
position: relative;
|
|
||||||
float: left;
|
|
||||||
display: block;
|
|
||||||
margin-left: 10px;
|
|
||||||
width: 100px;
|
|
||||||
height: 36px;
|
|
||||||
line-height: 36px;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #4a7;
|
|
||||||
border-radius: 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-operate a:hover {
|
|
||||||
background-color: rgba(0, 0, 0, 0.03);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-error,
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-success {
|
|
||||||
display: block;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 24px;
|
|
||||||
height: 24px;
|
|
||||||
color: #d10;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-success {
|
|
||||||
color: #4a7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-icon3 {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-icon3::after {
|
|
||||||
position: absolute;
|
|
||||||
top: 3px;
|
|
||||||
left: 6px;
|
|
||||||
width: 6px;
|
|
||||||
height: 10px;
|
|
||||||
border-width: 0 2px 2px 0;
|
|
||||||
border-color: #4a7;
|
|
||||||
border-style: solid;
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
-ms-transform: rotate(45deg);
|
|
||||||
transform: rotate(45deg);
|
|
||||||
content: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-icon2 {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-icon2::after, .vue-image-crop-upload .vicp-wrap .vicp-icon2::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 9px;
|
|
||||||
left: 4px;
|
|
||||||
width: 13px;
|
|
||||||
height: 2px;
|
|
||||||
background-color: #d10;
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
-ms-transform: rotate(45deg);
|
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-image-crop-upload .vicp-wrap .vicp-icon2::after {
|
|
||||||
-webkit-transform: rotate(-45deg);
|
|
||||||
-ms-transform: rotate(-45deg);
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.e-ripple {
|
|
||||||
position: absolute;
|
|
||||||
border-radius: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.15);
|
|
||||||
background-clip: padding-box;
|
|
||||||
pointer-events: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-transform: scale(0);
|
|
||||||
-ms-transform: scale(0);
|
|
||||||
transform: scale(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.e-ripple.z-active {
|
|
||||||
opacity: 0;
|
|
||||||
-webkit-transform: scale(2);
|
|
||||||
-ms-transform: scale(2);
|
|
||||||
transform: scale(2);
|
|
||||||
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
|
|
||||||
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
|
|
||||||
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
|
|
||||||
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param e
|
|
||||||
* @param arg_opts
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function effectRipple(e, arg_opts) {
|
|
||||||
let opts = Object.assign({
|
|
||||||
ele: e.target, // 波纹作用元素
|
|
||||||
type: 'hit', // hit点击位置扩散 center中心点扩展
|
|
||||||
bgc: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
|
||||||
}, arg_opts),
|
|
||||||
target = opts.ele;
|
|
||||||
if (target) {
|
|
||||||
let rect = target.getBoundingClientRect(),
|
|
||||||
ripple = target.querySelector('.e-ripple');
|
|
||||||
if (!ripple) {
|
|
||||||
ripple = document.createElement('span');
|
|
||||||
ripple.className = 'e-ripple';
|
|
||||||
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px';
|
|
||||||
target.appendChild(ripple);
|
|
||||||
} else {
|
|
||||||
ripple.className = 'e-ripple';
|
|
||||||
}
|
|
||||||
switch (opts.type) {
|
|
||||||
case 'center':
|
|
||||||
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px';
|
|
||||||
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px';
|
|
||||||
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px';
|
|
||||||
}
|
|
||||||
ripple.style.backgroundColor = opts.bgc;
|
|
||||||
ripple.className = 'e-ripple z-active';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// database64文件格式转换为2进制
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* @param mime
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
export function data2blob(data, mime) {
|
|
||||||
// dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
|
|
||||||
data = data.split(',')[1];
|
|
||||||
data = window.atob(data);
|
|
||||||
var ia = new Uint8Array(data.length);
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
|
||||||
ia[i] = data.charCodeAt(i);
|
|
||||||
}
|
|
||||||
// canvas.toDataURL 返回的默认格式就是 image/png
|
|
||||||
return new Blob([ia], {type: mime});
|
|
||||||
};
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* database64文件格式转换为2进制
|
||||||
|
*
|
||||||
|
* @param {[String]} data dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
|
||||||
|
* @param {[String]} mime [description]
|
||||||
|
* @return {[blob]} [description]
|
||||||
|
*/
|
||||||
|
export default function(data, mime) {
|
||||||
|
data = data.split(',')[1]
|
||||||
|
data = window.atob(data)
|
||||||
|
var ia = new Uint8Array(data.length)
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
ia[i] = data.charCodeAt(i)
|
||||||
|
}
|
||||||
|
// canvas.toDataURL 返回的默认格式就是 image/png
|
||||||
|
return new Blob([ia], {
|
||||||
|
type: mime
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* 点击波纹效果
|
||||||
|
*
|
||||||
|
* @param {[event]} e [description]
|
||||||
|
* @param {[Object]} arg_opts [description]
|
||||||
|
* @return {[bollean]} [description]
|
||||||
|
*/
|
||||||
|
export default function(e, arg_opts) {
|
||||||
|
var opts = Object.assign({
|
||||||
|
ele: e.target, // 波纹作用元素
|
||||||
|
type: 'hit', // hit点击位置扩散center中心点扩展
|
||||||
|
bgc: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
||||||
|
}, arg_opts)
|
||||||
|
var target = opts.ele
|
||||||
|
if (target) {
|
||||||
|
var rect = target.getBoundingClientRect()
|
||||||
|
var ripple = target.querySelector('.e-ripple')
|
||||||
|
if (!ripple) {
|
||||||
|
ripple = document.createElement('span')
|
||||||
|
ripple.className = 'e-ripple'
|
||||||
|
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
|
||||||
|
target.appendChild(ripple)
|
||||||
|
} else {
|
||||||
|
ripple.className = 'e-ripple'
|
||||||
|
}
|
||||||
|
switch (opts.type) {
|
||||||
|
case 'center':
|
||||||
|
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
|
||||||
|
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
|
||||||
|
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
|
||||||
|
}
|
||||||
|
ripple.style.backgroundColor = opts.bgc
|
||||||
|
ripple.className = 'e-ripple z-active'
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,232 @@
|
||||||
|
export default {
|
||||||
|
zh: {
|
||||||
|
hint: '点击,或拖动图片至此处',
|
||||||
|
loading: '正在上传……',
|
||||||
|
noSupported: '浏览器不支持该功能,请使用IE10以上或其他现在浏览器!',
|
||||||
|
success: '上传成功',
|
||||||
|
fail: '图片上传失败',
|
||||||
|
preview: '头像预览',
|
||||||
|
btn: {
|
||||||
|
off: '取消',
|
||||||
|
close: '关闭',
|
||||||
|
back: '上一步',
|
||||||
|
save: '保存'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: '仅限图片格式',
|
||||||
|
outOfSize: '单文件大小不能超过 ',
|
||||||
|
lowestPx: '图片最低像素为(宽*高):'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'zh-tw': {
|
||||||
|
hint: '點擊,或拖動圖片至此處',
|
||||||
|
loading: '正在上傳……',
|
||||||
|
noSupported: '瀏覽器不支持該功能,請使用IE10以上或其他現代瀏覽器!',
|
||||||
|
success: '上傳成功',
|
||||||
|
fail: '圖片上傳失敗',
|
||||||
|
preview: '頭像預覽',
|
||||||
|
btn: {
|
||||||
|
off: '取消',
|
||||||
|
close: '關閉',
|
||||||
|
back: '上一步',
|
||||||
|
save: '保存'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: '僅限圖片格式',
|
||||||
|
outOfSize: '單文件大小不能超過 ',
|
||||||
|
lowestPx: '圖片最低像素為(寬*高):'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
hint: 'Click or drag the file here to upload',
|
||||||
|
loading: 'Uploading…',
|
||||||
|
noSupported: 'Browser is not supported, please use IE10+ or other browsers',
|
||||||
|
success: 'Upload success',
|
||||||
|
fail: 'Upload failed',
|
||||||
|
preview: 'Preview',
|
||||||
|
btn: {
|
||||||
|
off: 'Cancel',
|
||||||
|
close: 'Close',
|
||||||
|
back: 'Back',
|
||||||
|
save: 'Save'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Image only',
|
||||||
|
outOfSize: 'Image exceeds size limit: ',
|
||||||
|
lowestPx: 'Image\'s size is too low. Expected at least: '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ro: {
|
||||||
|
hint: 'Atinge sau trage fișierul aici',
|
||||||
|
loading: 'Se încarcă',
|
||||||
|
noSupported: 'Browser-ul tău nu suportă acest feature. Te rugăm încearcă cu alt browser.',
|
||||||
|
success: 'S-a încărcat cu succes',
|
||||||
|
fail: 'A apărut o problemă la încărcare',
|
||||||
|
preview: 'Previzualizează',
|
||||||
|
|
||||||
|
btn: {
|
||||||
|
off: 'Anulează',
|
||||||
|
close: 'Închide',
|
||||||
|
back: 'Înapoi',
|
||||||
|
save: 'Salvează'
|
||||||
|
},
|
||||||
|
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Doar imagini',
|
||||||
|
outOfSize: 'Imaginea depășește limita de: ',
|
||||||
|
loewstPx: 'Imaginea este prea mică; Minim: '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ru: {
|
||||||
|
hint: 'Нажмите, или перетащите файл в это окно',
|
||||||
|
loading: 'Загружаю……',
|
||||||
|
noSupported: 'Ваш браузер не поддерживается, пожалуйста, используйте IE10 + или другие браузеры',
|
||||||
|
success: 'Загрузка выполнена успешно',
|
||||||
|
fail: 'Ошибка загрузки',
|
||||||
|
preview: 'Предпросмотр',
|
||||||
|
btn: {
|
||||||
|
off: 'Отменить',
|
||||||
|
close: 'Закрыть',
|
||||||
|
back: 'Назад',
|
||||||
|
save: 'Сохранить'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Только изображения',
|
||||||
|
outOfSize: 'Изображение превышает предельный размер: ',
|
||||||
|
lowestPx: 'Минимальный размер изображения: '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'pt-br': {
|
||||||
|
hint: 'Clique ou arraste o arquivo aqui para carregar',
|
||||||
|
loading: 'Carregando…',
|
||||||
|
noSupported: 'Browser não suportado, use o IE10+ ou outro browser',
|
||||||
|
success: 'Sucesso ao carregar imagem',
|
||||||
|
fail: 'Falha ao carregar imagem',
|
||||||
|
preview: 'Pré-visualizar',
|
||||||
|
btn: {
|
||||||
|
off: 'Cancelar',
|
||||||
|
close: 'Fechar',
|
||||||
|
back: 'Voltar',
|
||||||
|
save: 'Salvar'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Apenas imagens',
|
||||||
|
outOfSize: 'A imagem excede o limite de tamanho: ',
|
||||||
|
lowestPx: 'O tamanho da imagem é muito pequeno. Tamanho mínimo: '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fr: {
|
||||||
|
hint: 'Cliquez ou glissez le fichier ici.',
|
||||||
|
loading: 'Téléchargement…',
|
||||||
|
noSupported: 'Votre navigateur n\'est pas supporté. Utilisez IE10 + ou un autre navigateur s\'il vous plaît.',
|
||||||
|
success: 'Téléchargement réussit',
|
||||||
|
fail: 'Téléchargement echoué',
|
||||||
|
preview: 'Aperçu',
|
||||||
|
btn: {
|
||||||
|
off: 'Annuler',
|
||||||
|
close: 'Fermer',
|
||||||
|
back: 'Retour',
|
||||||
|
save: 'Enregistrer'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Image uniquement',
|
||||||
|
outOfSize: 'L\'image sélectionnée dépasse la taille maximum: ',
|
||||||
|
lowestPx: 'L\'image sélectionnée est trop petite. Dimensions attendues: '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nl: {
|
||||||
|
hint: 'Klik hier of sleep een afbeelding in dit vlak',
|
||||||
|
loading: 'Uploaden…',
|
||||||
|
noSupported: 'Je browser wordt helaas niet ondersteund. Gebruik IE10+ of een andere browser.',
|
||||||
|
success: 'Upload succesvol',
|
||||||
|
fail: 'Upload mislukt',
|
||||||
|
preview: 'Voorbeeld',
|
||||||
|
btn: {
|
||||||
|
off: 'Annuleren',
|
||||||
|
close: 'Sluiten',
|
||||||
|
back: 'Terug',
|
||||||
|
save: 'Opslaan'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Alleen afbeeldingen',
|
||||||
|
outOfSize: 'De afbeelding is groter dan: ',
|
||||||
|
lowestPx: 'De afbeelding is te klein! Minimale afmetingen: '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tr: {
|
||||||
|
hint: 'Tıkla veya yüklemek istediğini buraya sürükle',
|
||||||
|
loading: 'Yükleniyor…',
|
||||||
|
noSupported: 'Tarayıcı desteklenmiyor, lütfen IE10+ veya farklı tarayıcı kullanın',
|
||||||
|
success: 'Yükleme başarılı',
|
||||||
|
fail: 'Yüklemede hata oluştu',
|
||||||
|
preview: 'Önizle',
|
||||||
|
btn: {
|
||||||
|
off: 'İptal',
|
||||||
|
close: 'Kapat',
|
||||||
|
back: 'Geri',
|
||||||
|
save: 'Kaydet'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Sadece resim',
|
||||||
|
outOfSize: 'Resim yükleme limitini aşıyor: ',
|
||||||
|
lowestPx: 'Resmin boyutu çok küçük. En az olması gereken: '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'es-MX': {
|
||||||
|
hint: 'Selecciona o arrastra una imagen',
|
||||||
|
loading: 'Subiendo...',
|
||||||
|
noSupported: 'Tu navegador no es soportado, porfavor usa IE10+ u otros navegadores mas recientes',
|
||||||
|
success: 'Subido exitosamente',
|
||||||
|
fail: 'Sucedió un error',
|
||||||
|
preview: 'Vista previa',
|
||||||
|
btn: {
|
||||||
|
off: 'Cancelar',
|
||||||
|
close: 'Cerrar',
|
||||||
|
back: 'Atras',
|
||||||
|
save: 'Guardar'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Unicamente imagenes',
|
||||||
|
outOfSize: 'La imagen excede el tamaño maximo:',
|
||||||
|
lowestPx: 'La imagen es demasiado pequeño. Se espera por lo menos:'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
hint: 'Klick hier oder zieh eine Datei hier rein zum Hochladen',
|
||||||
|
loading: 'Hochladen…',
|
||||||
|
noSupported: 'Browser wird nicht unterstützt, bitte verwende IE10+ oder andere Browser',
|
||||||
|
success: 'Upload erfolgreich',
|
||||||
|
fail: 'Upload fehlgeschlagen',
|
||||||
|
preview: 'Vorschau',
|
||||||
|
btn: {
|
||||||
|
off: 'Abbrechen',
|
||||||
|
close: 'Schließen',
|
||||||
|
back: 'Zurück',
|
||||||
|
save: 'Speichern'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: 'Nur Bilder',
|
||||||
|
outOfSize: 'Das Bild ist zu groß: ',
|
||||||
|
lowestPx: 'Das Bild ist zu klein. Mindestens: '
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ja: {
|
||||||
|
hint: 'クリック・ドラッグしてファイルをアップロード',
|
||||||
|
loading: 'アップロード中...',
|
||||||
|
noSupported: 'このブラウザは対応されていません。IE10+かその他の主要ブラウザをお使いください。',
|
||||||
|
success: 'アップロード成功',
|
||||||
|
fail: 'アップロード失敗',
|
||||||
|
preview: 'プレビュー',
|
||||||
|
btn: {
|
||||||
|
off: 'キャンセル',
|
||||||
|
close: '閉じる',
|
||||||
|
back: '戻る',
|
||||||
|
save: '保存'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
onlyImg: '画像のみ',
|
||||||
|
outOfSize: '画像サイズが上限を超えています。上限: ',
|
||||||
|
lowestPx: '画像が小さすぎます。最小サイズ: '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
export default {
|
||||||
|
'jpg': 'image/jpeg',
|
||||||
|
'png': 'image/png',
|
||||||
|
'gif': 'image/gif',
|
||||||
|
'svg': 'image/svg+xml',
|
||||||
|
'psd': 'image/photoshop'
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class='json-editor'>
|
<div class="json-editor">
|
||||||
<textarea ref='textarea'></textarea>
|
<textarea ref="textarea"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -53,12 +53,19 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style scoped>
|
||||||
.CodeMirror {
|
.json-editor{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.json-editor >>> .CodeMirror {
|
||||||
.json-editor .cm-s-rubyblue span.cm-string {
|
height: auto;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.json-editor >>> .CodeMirror-scroll{
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.json-editor >>> .cm-s-rubyblue span.cm-string {
|
||||||
color: #F08047;
|
color: #F08047;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
|
@ -0,0 +1,89 @@
|
||||||
|
<template>
|
||||||
|
<div class="board-column">
|
||||||
|
<div class="board-column-header">
|
||||||
|
{{headerText}}
|
||||||
|
</div>
|
||||||
|
<draggable
|
||||||
|
class="board-column-content"
|
||||||
|
:list="list"
|
||||||
|
:options="options">
|
||||||
|
<div class="board-item" v-for="element in list" :key="element.id">
|
||||||
|
{{element.name}} {{element.id}}
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'dragKanban-demo',
|
||||||
|
components: {
|
||||||
|
draggable
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
headerText: {
|
||||||
|
type: String,
|
||||||
|
default: 'Header'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.board-column {
|
||||||
|
min-width: 300px;
|
||||||
|
min-height: 100px;
|
||||||
|
height: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #f0f0f0;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
.board-column-header {
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0 20px;
|
||||||
|
text-align: center;
|
||||||
|
background: #333;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.board-column-content {
|
||||||
|
height: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 10px solid transparent;
|
||||||
|
min-height: 60px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.board-item {
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
height: 64px;
|
||||||
|
margin: 5px 0;
|
||||||
|
background-color: #fff;
|
||||||
|
text-align: left;
|
||||||
|
line-height: 54px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0px 1px 3px 0 rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<template>
|
||||||
|
<el-dropdown trigger="click" class='international' @command="handleSetLanguage">
|
||||||
|
<div>
|
||||||
|
<svg-icon class-name='international-icon' icon-class="language" />
|
||||||
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item command="zh" :disabled="language==='zh'">中文</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="en" :disabled="language==='en'">English</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
language() {
|
||||||
|
return this.$store.getters.language
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleSetLanguage(lang) {
|
||||||
|
this.$i18n.locale = lang
|
||||||
|
this.$store.dispatch('setLanguage', lang)
|
||||||
|
this.$message({
|
||||||
|
message: 'switch language success',
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.international-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
vertical-align: -5px!important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -1,144 +1,115 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="material-input__component" :class="computedClasses">
|
<div class="material-input__component" :class="computedClasses">
|
||||||
<input v-if="type === 'email'" type="email" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
<div :class="{iconClass:icon}">
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
|
<i class="el-input__icon material-input__icon" :class="['el-icon-' + icon]" v-if="icon"></i>
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'email'" type="email" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<input v-if="type === 'url'" type="url" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'url'" type="url" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :maxlength="maxlength"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder"
|
:step="step" :readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :minlength="minlength"
|
||||||
v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :required="required"
|
:maxlength="maxlength" :required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
|
||||||
@focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :max="max" :min="min" :required="required" @focus="handleMdFocus"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :required="required" @focus="handleMdFocus"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength"
|
@blur="handleMdBlur" @input="handleModelInput">
|
||||||
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :placeholder="fillPlaceHolder" v-model="currentValue"
|
||||||
|
:readonly="readonly" :disabled="disabled" :autoComplete="autoComplete" :minlength="minlength" :maxlength="maxlength"
|
||||||
|
:required="required" @focus="handleMdFocus" @blur="handleMdBlur" @input="handleModelInput">
|
||||||
<span class="material-input-bar"></span>
|
<span class="material-input-bar"></span>
|
||||||
|
|
||||||
<label class="material-label">
|
<label class="material-label">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</label>
|
</label>
|
||||||
<div v-if="errorMessages" class="material-errors">
|
|
||||||
<div v-for="error in computedErrors" class="material-error" :key='error'>
|
|
||||||
{{ error }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
|
// source:https://github.com/wemake-services/vue-material-input/blob/master/src/components/MaterialInput.vue
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'material-input',
|
name: 'md-input',
|
||||||
computed: {
|
|
||||||
computedErrors() {
|
|
||||||
return typeof this.errorMessages === 'string'
|
|
||||||
? [this.errorMessages] : this.errorMessages
|
|
||||||
},
|
|
||||||
computedClasses() {
|
|
||||||
return {
|
|
||||||
'material--active': this.focus,
|
|
||||||
'material--disabled': this.disabled,
|
|
||||||
'material--has-errors': Boolean(!this.valid || (this.errorMessages && this.errorMessages.length)),
|
|
||||||
'material--raised': Boolean(this.focus || this.valueCopy || // has value
|
|
||||||
(this.placeholder && !this.valueCopy)) // has placeholder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
valueCopy: null,
|
|
||||||
focus: false,
|
|
||||||
valid: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeMount() {
|
|
||||||
// Here we are following the Vue2 convention on custom v-model:
|
|
||||||
// https://github.com/vuejs/vue/issues/2873#issuecomment-223759341
|
|
||||||
this.copyValue(this.value)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleModelInput(event) {
|
|
||||||
this.$emit('input', event.target.value, event)
|
|
||||||
this.handleValidation()
|
|
||||||
},
|
|
||||||
handleFocus(focused) {
|
|
||||||
this.focus = focused
|
|
||||||
},
|
|
||||||
handleValidation() {
|
|
||||||
this.valid = this.$el ? this.$el.querySelector('.material-input').validity.valid : this.valid
|
|
||||||
},
|
|
||||||
copyValue(value) {
|
|
||||||
this.valueCopy = value
|
|
||||||
this.handleValidation()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
value(newValue) {
|
|
||||||
this.copyValue(newValue)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
id: {
|
icon: String,
|
||||||
type: String,
|
name: String,
|
||||||
default: null
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'text'
|
default: 'text'
|
||||||
},
|
},
|
||||||
value: {
|
value: [String, Number],
|
||||||
default: null
|
placeholder: String,
|
||||||
},
|
readonly: Boolean,
|
||||||
placeholder: {
|
disabled: Boolean,
|
||||||
type: String,
|
min: String,
|
||||||
default: null
|
max: String,
|
||||||
},
|
step: String,
|
||||||
readonly: {
|
minlength: Number,
|
||||||
type: Boolean,
|
maxlength: Number,
|
||||||
default: false
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
min: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
max: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
minlength: {
|
|
||||||
type: Number,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
maxlength: {
|
|
||||||
type: Number,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
required: {
|
required: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
autocomplete: {
|
autoComplete: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'off'
|
default: 'off'
|
||||||
},
|
},
|
||||||
errorMessages: {
|
validateEvent: {
|
||||||
type: [Array, String],
|
type: Boolean,
|
||||||
default: null
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
computedClasses() {
|
||||||
|
return {
|
||||||
|
'material--active': this.focus,
|
||||||
|
'material--disabled': this.disabled,
|
||||||
|
'material--raised': Boolean(this.focus || this.currentValue) // has value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(newValue) {
|
||||||
|
this.currentValue = newValue
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentValue: this.value,
|
||||||
|
focus: false,
|
||||||
|
fillPlaceHolder: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleModelInput(event) {
|
||||||
|
const value = event.target.value
|
||||||
|
this.$emit('input', value)
|
||||||
|
if (this.$parent.$options.componentName === 'ElFormItem') {
|
||||||
|
if (this.validateEvent) {
|
||||||
|
this.$parent.$emit('el.form.change', [value])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$emit('change', value)
|
||||||
|
},
|
||||||
|
handleMdFocus(event) {
|
||||||
|
this.focus = true
|
||||||
|
this.$emit('focus', event)
|
||||||
|
if (this.placeholder && this.placeholder !== '') {
|
||||||
|
this.fillPlaceHolder = this.placeholder
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleMdBlur(event) {
|
||||||
|
this.focus = false
|
||||||
|
this.$emit('blur', event)
|
||||||
|
this.fillPlaceHolder = null
|
||||||
|
if (this.$parent.$options.componentName === 'ElFormItem') {
|
||||||
|
if (this.validateEvent) {
|
||||||
|
this.$parent.$emit('el.form.blur', [this.currentValue])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,9 +121,20 @@ export default {
|
||||||
$font-size-small: 18px;
|
$font-size-small: 18px;
|
||||||
$font-size-smallest: 12px;
|
$font-size-smallest: 12px;
|
||||||
$font-weight-normal: normal;
|
$font-weight-normal: normal;
|
||||||
|
$font-weight-bold: bold;
|
||||||
|
$apixel: 1px;
|
||||||
// Utils
|
// Utils
|
||||||
$spacer: 12px;
|
$spacer: 12px;
|
||||||
$transition: 0.2s ease all;
|
$transition: 0.2s ease all;
|
||||||
|
$index: 0px;
|
||||||
|
$index-has-icon: 30px;
|
||||||
|
// Theme:
|
||||||
|
$color-white: white;
|
||||||
|
$color-grey: #9E9E9E;
|
||||||
|
$color-grey-light: #E0E0E0;
|
||||||
|
$color-blue: #2196F3;
|
||||||
|
$color-red: #F44336;
|
||||||
|
$color-black: black;
|
||||||
// Base clases:
|
// Base clases:
|
||||||
%base-bar-pseudo {
|
%base-bar-pseudo {
|
||||||
content: '';
|
content: '';
|
||||||
|
@ -165,23 +147,46 @@ export default {
|
||||||
|
|
||||||
// Mixins:
|
// Mixins:
|
||||||
@mixin slided-top() {
|
@mixin slided-top() {
|
||||||
top: -2 * $spacer;
|
top: - ($font-size-base + $spacer);
|
||||||
font-size: $font-size-small;
|
left: 0;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Component:
|
// Component:
|
||||||
.material-input__component {
|
.material-input__component {
|
||||||
/*margin-top: 30px;*/
|
margin-top: 36px;
|
||||||
position: relative;
|
position: relative;
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
.iconClass {
|
||||||
|
.material-input__icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
line-height: $font-size-base;
|
||||||
|
color: $color-blue;
|
||||||
|
top: $spacer;
|
||||||
|
width: $index-has-icon;
|
||||||
|
height: $font-size-base;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-normal;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.material-label {
|
||||||
|
left: $index-has-icon;
|
||||||
|
}
|
||||||
|
.material-input {
|
||||||
|
text-indent: $index-has-icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
.material-input {
|
.material-input {
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
padding: $spacer $spacer $spacer $spacer / 2;
|
padding: $spacer $spacer $spacer - $apixel * 10 $spacer / 2;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
|
line-height: 1;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@ -190,13 +195,13 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.material-label {
|
.material-label {
|
||||||
font-size: $font-size-base;
|
|
||||||
font-weight: $font-weight-normal;
|
font-weight: $font-weight-normal;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
left: 0;
|
left: $index;
|
||||||
top: $spacer;
|
top: 0;
|
||||||
transition: $transition;
|
transition: $transition;
|
||||||
|
font-size: $font-size-small;
|
||||||
}
|
}
|
||||||
.material-input-bar {
|
.material-input-bar {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -232,35 +237,14 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Errors:
|
|
||||||
.material-errors {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
.material-error {
|
|
||||||
font-size: $font-size-smallest;
|
|
||||||
line-height: $font-size-smallest + 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-top: 0;
|
|
||||||
padding-top: $spacer / 2;
|
|
||||||
padding-right: $spacer / 2;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Theme:
|
|
||||||
$color-white: white;
|
|
||||||
$color-grey: #9E9E9E;
|
|
||||||
$color-grey-light: #E0E0E0;
|
|
||||||
$color-blue: #2196F3;
|
|
||||||
$color-red: #F44336;
|
|
||||||
$color-black: black;
|
|
||||||
.material-input__component {
|
.material-input__component {
|
||||||
background: $color-white;
|
background: $color-white;
|
||||||
.material-input {
|
.material-input {
|
||||||
background: none;
|
background: none;
|
||||||
color: $color-black;
|
color: $color-black;
|
||||||
text-indent: 30px;
|
text-indent: $index;
|
||||||
border-bottom: 1px solid $color-grey-light;
|
border-bottom: 1px solid $color-grey-light;
|
||||||
}
|
}
|
||||||
.material-label {
|
.material-label {
|
||||||
|
@ -286,12 +270,9 @@ export default {
|
||||||
.material-input-bar {
|
.material-input-bar {
|
||||||
&:before,
|
&:before,
|
||||||
&:after {
|
&:after {
|
||||||
background: $color-red;
|
background: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.material-errors {
|
|
||||||
color: $color-red;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div class='simplemde-container' :style="{height:height+'px',zIndex:zIndex}">
|
<div class="simplemde-container" :style="{height:height+'px',zIndex:zIndex}">
|
||||||
<textarea :id='id'>
|
<textarea :id="id">
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import 'font-awesome/css/font-awesome.min.css'
|
||||||
import 'simplemde/dist/simplemde.min.css'
|
import 'simplemde/dist/simplemde.min.css'
|
||||||
import SimpleMDE from 'simplemde'
|
import SimpleMDE from 'simplemde'
|
||||||
|
|
||||||
|
@ -14,8 +15,7 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
value: String,
|
value: String,
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String
|
||||||
default: 'markdown-editor'
|
|
||||||
},
|
},
|
||||||
autofocus: {
|
autofocus: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -51,7 +51,8 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.simplemde = new SimpleMDE({
|
this.simplemde = new SimpleMDE({
|
||||||
element: document.getElementById(this.id),
|
element: document.getElementById(this.id || 'markdown-editor-' + +new Date()),
|
||||||
|
autoDownloadFontAwesome: false,
|
||||||
autofocus: this.autofocus,
|
autofocus: this.autofocus,
|
||||||
toolbar: this.toolbar,
|
toolbar: this.toolbar,
|
||||||
spellChecker: false,
|
spellChecker: false,
|
||||||
|
@ -72,43 +73,44 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
|
this.simplemde.toTextArea()
|
||||||
this.simplemde = null
|
this.simplemde = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style scoped>
|
||||||
.simplemde-container .CodeMirror {
|
.simplemde-container>>>.CodeMirror {
|
||||||
/*height: 150px;*/
|
min-height: 150px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.simplemde-container>>>.CodeMirror-scroll {
|
||||||
min-height: 150px;
|
min-height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.simplemde-container .CodeMirror-scroll {
|
.simplemde-container>>>.CodeMirror-code {
|
||||||
min-height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simplemde-container .CodeMirror-code {
|
|
||||||
padding-bottom: 40px;
|
padding-bottom: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.simplemde-container .editor-statusbar {
|
.simplemde-container>>>.editor-statusbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.simplemde-container .CodeMirror .CodeMirror-code .cm-link {
|
.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-link {
|
||||||
color: #1482F0;
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.simplemde-container .CodeMirror .CodeMirror-code .cm-string.cm-url {
|
.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-string.cm-url {
|
||||||
color: #2d3b4d;
|
color: #2d3b4d;
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.simplemde-container .CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url {
|
.simplemde-container>>>.CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url {
|
||||||
padding: 0 2px;
|
padding: 0 2px;
|
||||||
font-weight: bold;
|
|
||||||
color: #E61E1E;
|
color: #E61E1E;
|
||||||
}
|
}
|
||||||
|
.simplemde-container >>> .editor-toolbar.fullscreen,
|
||||||
|
.simplemde-container >>> .CodeMirror-fullscreen {
|
||||||
|
z-index: 1003;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ export default {
|
||||||
},
|
},
|
||||||
zIndex: {
|
zIndex: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 100
|
default: 1
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<svg @click='click' class="icon screenfull" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
<div>
|
||||||
t="1497503607356" viewBox="0 0 1024 1024" version="1.1" p-id="4109" :fill='fill' :width="width" :height="height">
|
<svg t="1508738709248" @click='click' class="screenfull-svg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||||
<path d="M604.157933 512l204.484208 204.484208 82.942037-82.942037c10.364045-10.952446 26.498514-13.83817 40.309054-8.067746 13.249769 5.742794 22.465664 18.99154 22.465664 33.977859l0 258.042008c0 20.168342-16.695241 36.863582-36.863582 36.863582L659.452283 954.357873c-14.986319 0-28.236088-9.215896-33.977859-23.025413-5.770424-13.249769-2.885723-29.384237 8.067746-39.748283l82.942037-82.942037L512 604.157933 307.515792 808.642141l82.942037 82.942037c10.952446 10.364045 13.83817 26.498514 8.067746 39.748283-5.742794 13.809517-18.99154 23.025413-33.977859 23.025413L106.504686 954.357873c-20.168342 0-36.863582-16.695241-36.863582-36.863582L69.641103 659.452283c0-14.986319 9.215896-28.236088 23.025413-33.977859 13.249769-5.770424 29.384237-2.8847 39.748283 8.067746l82.942037 82.942037 204.484208-204.484208L215.357859 307.515792l-82.942037 82.942037c-6.890944 6.918573-16.10684 10.952446-25.911136 10.952446-4.593622 0-9.804297-1.14815-13.83817-2.8847-13.809517-5.742794-23.025413-18.99154-23.025413-33.977859L69.641103 106.504686c0-20.168342 16.695241-36.863582 36.863582-36.863582L364.546693 69.641103c14.986319 0 28.236088 9.215896 33.977859 23.025413 5.770424 13.249769 2.8847 29.384237-8.067746 39.748283l-82.942037 82.942037 204.484208 204.484208L716.484208 215.357859l-82.942037-82.942037c-10.952446-10.364045-13.83817-26.498514-8.067746-39.748283 5.742794-13.809517 18.99154-23.025413 33.977859-23.025413l258.042008 0c20.168342 0 36.863582 16.695241 36.863582 36.863582l0 258.042008c0 14.986319-9.215896 28.236088-22.465664 33.977859-4.593622 1.736551-9.804297 2.8847-14.397918 2.8847-9.804297 0-19.020192-4.033873-25.911136-10.952446l-82.942037-82.942037L604.157933 512z"
|
p-id="2069" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32">
|
||||||
p-id="4110" />
|
<path d="M333.493443 428.647617 428.322206 333.832158 262.572184 168.045297 366.707916 64.444754 64.09683 64.444754 63.853283 366.570793 167.283957 262.460644Z"
|
||||||
|
p-id="2070"></path>
|
||||||
|
<path d="M854.845439 760.133334 688.61037 593.95864 593.805144 688.764889 759.554142 854.56096 655.44604 958.161503 958.055079 958.161503 958.274066 656.035464Z"
|
||||||
|
p-id="2071"></path>
|
||||||
|
<path d="M688.535669 428.550403 854.31025 262.801405 957.935352 366.921787 957.935352 64.34754 655.809313 64.081481 759.919463 167.535691 593.70793 333.731874Z"
|
||||||
|
p-id="2072"></path>
|
||||||
|
<path d="M333.590658 594.033341 167.8171 759.804852 64.218604 655.67219 64.218604 958.270996 366.342596 958.502263 262.234493 855.071589 428.421466 688.86108Z"
|
||||||
|
p-id="2073"></path>
|
||||||
</svg>
|
</svg>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import screenfull from 'screenfull'
|
import screenfull from 'screenfull'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'hamburger',
|
name: 'screenfull',
|
||||||
props: {
|
props: {
|
||||||
width: {
|
width: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -46,9 +54,12 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.screenfull {
|
.screenfull-svg {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
vertical-align: -0.15em;
|
fill: #5a5e66;;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
vertical-align: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
<template>
|
||||||
|
<div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll">
|
||||||
|
<div class="scroll-wrapper" ref="scrollWrapper" :style="{left: left + 'px'}">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const padding = 15 // tag's padding
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'scrollPane',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
left: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleScroll(e) {
|
||||||
|
const eventDelta = e.wheelDelta || -e.deltaY * 3
|
||||||
|
const $container = this.$refs.scrollContainer
|
||||||
|
const $containerWidth = $container.offsetWidth
|
||||||
|
const $wrapper = this.$refs.scrollWrapper
|
||||||
|
const $wrapperWidth = $wrapper.offsetWidth
|
||||||
|
|
||||||
|
if (eventDelta > 0) {
|
||||||
|
this.left = Math.min(0, this.left + eventDelta)
|
||||||
|
} else {
|
||||||
|
if ($containerWidth - padding < $wrapperWidth) {
|
||||||
|
if (this.left < -($wrapperWidth - $containerWidth + padding)) {
|
||||||
|
this.left = this.left
|
||||||
|
} else {
|
||||||
|
this.left = Math.max(this.left + eventDelta, $containerWidth - $wrapperWidth - padding)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.left = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
moveToTarget($target) {
|
||||||
|
const $container = this.$refs.scrollContainer
|
||||||
|
const $containerWidth = $container.offsetWidth
|
||||||
|
const $targetLeft = $target.offsetLeft
|
||||||
|
const $targetWidth = $target.offsetWidth
|
||||||
|
|
||||||
|
if ($targetLeft < -this.left) {
|
||||||
|
// tag in the left
|
||||||
|
this.left = -$targetLeft + padding
|
||||||
|
} else if ($targetLeft + padding > -this.left && $targetLeft + $targetWidth < -this.left + $containerWidth - padding) {
|
||||||
|
// tag in the current view
|
||||||
|
// eslint-disable-line
|
||||||
|
} else {
|
||||||
|
// tag in the right
|
||||||
|
this.left = -($targetLeft - ($containerWidth - $targetWidth) + padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.scroll-container {
|
||||||
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
.scroll-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,97 @@
|
||||||
|
<template>
|
||||||
|
<div class="share-dropdown-menu" :class="{active:isActive}">
|
||||||
|
<div class="share-dropdown-menu-wrapper">
|
||||||
|
<span class="share-dropdown-menu-title" @click.self="clickTitle">{{title}}</span>
|
||||||
|
<div class="share-dropdown-menu-item" v-for="(item,index) of items" :key='index'>
|
||||||
|
<a v-if="item.href" :href="item.href" target="_blank">{{item.title}}</a>
|
||||||
|
<span v-else>{{item.title}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
items: {
|
||||||
|
type: Array
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: 'vue'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isActive: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickTitle() {
|
||||||
|
this.isActive = !this.isActive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" >
|
||||||
|
$n: 6; //和items.length 相同
|
||||||
|
$t: .1s;
|
||||||
|
.share-dropdown-menu {
|
||||||
|
width: 250px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
&-title {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
height: 60px;
|
||||||
|
line-height: 60px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 2;
|
||||||
|
transform: translate3d(0,0,0);
|
||||||
|
}
|
||||||
|
&-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
&-item {
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
background: #e0e0e0;
|
||||||
|
line-height: 60px;
|
||||||
|
height: 60px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 20px;
|
||||||
|
opacity: 1;
|
||||||
|
transition: transform 0.28s ease;
|
||||||
|
&:hover {
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
@for $i from 1 through $n {
|
||||||
|
&:nth-of-type(#{$i}) {
|
||||||
|
z-index: -1;
|
||||||
|
transition-delay: $i*$t;
|
||||||
|
transform: translate3d(0, -60px, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
.share-dropdown-menu-wrapper {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.share-dropdown-menu-item {
|
||||||
|
@for $i from 1 through $n {
|
||||||
|
&:nth-of-type(#{$i}) {
|
||||||
|
transition-delay: ($n - $i)*$t;
|
||||||
|
transform: translate3d(0, ($i - 1)*60px, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,44 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="classes">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'Pane',
|
|
||||||
data() {
|
|
||||||
const classes = ['Pane', this.$parent.split, 'className']
|
|
||||||
return {
|
|
||||||
classes: classes.join(' '),
|
|
||||||
percent: 50
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.splitter-pane.vertical.splitter-paneL {
|
|
||||||
position: absolute;
|
|
||||||
left: 0px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.splitter-pane.vertical.splitter-paneR {
|
|
||||||
position: absolute;
|
|
||||||
right: 0px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.splitter-pane.horizontal.splitter-paneL {
|
|
||||||
position: absolute;
|
|
||||||
top: 0px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.splitter-pane.horizontal.splitter-paneR {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,72 +0,0 @@
|
||||||
<template>
|
|
||||||
<div :class="classes" @mousedown="onMouseDown"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
split: {
|
|
||||||
validator(value) {
|
|
||||||
return ['vertical', 'horizontal'].indexOf(value) >= 0
|
|
||||||
},
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
onMouseDown: {
|
|
||||||
type: Function,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
const classes = ['Resizer', this.split, 'className']
|
|
||||||
return {
|
|
||||||
classes: classes.join(' ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.Resizer {
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background: #000;
|
|
||||||
position: absolute;
|
|
||||||
opacity: .2;
|
|
||||||
z-index: 1;
|
|
||||||
/*-moz-background-clip: padding;*/
|
|
||||||
/*-webkit-background-clip: padding;*/
|
|
||||||
/*background-clip: padding-box;*/
|
|
||||||
}
|
|
||||||
/*.Resizer:hover {*/
|
|
||||||
/*-webkit-transition: all 2s ease;*/
|
|
||||||
/*transition: all 2s ease;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
.Resizer.horizontal {
|
|
||||||
height: 11px;
|
|
||||||
margin: -5px 0;
|
|
||||||
border-top: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
border-bottom: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
cursor: row-resize;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Resizer.horizontal:hover {
|
|
||||||
border-top: 5px solid rgba(0, 0, 0, 0.5);
|
|
||||||
border-bottom: 5px solid rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.Resizer.vertical {
|
|
||||||
width: 11px;
|
|
||||||
height: 100%;
|
|
||||||
border-left: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
border-right: 5px solid rgba(255, 255, 255, 0);
|
|
||||||
cursor: col-resize;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Resizer.vertical:hover {
|
|
||||||
border-left: 5px solid rgba(0, 0, 0, 0.5);
|
|
||||||
border-right: 5px solid rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,111 +0,0 @@
|
||||||
<template>
|
|
||||||
<div ref :style="{ cursor, userSelect}" class="vue-splitter-container clearfix" @mouseup="onMouseUp" @mousemove="onMouseMove">
|
|
||||||
<pane class="splitter-pane splitter-paneL" :split="split" :style="{ [type]: percent+'%'}">
|
|
||||||
<slot name="paneL"></slot>
|
|
||||||
</pane>
|
|
||||||
<resizer :style="{ [resizeType]: percent+'%'}" :split="split" :onMouseDown="onMouseDown" @click="onClick"></resizer>
|
|
||||||
<pane class="splitter-pane splitter-paneR" :split="split" :style="{ [type]: 100-percent+'%'}">
|
|
||||||
<slot name="paneR"></slot>
|
|
||||||
</pane>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Resizer from './Resizer'
|
|
||||||
import Pane from './Pane'
|
|
||||||
export default {
|
|
||||||
name: 'splitPane',
|
|
||||||
components: { Resizer, Pane },
|
|
||||||
props: {
|
|
||||||
margin: {
|
|
||||||
type: Number,
|
|
||||||
default: 10
|
|
||||||
},
|
|
||||||
split: {
|
|
||||||
validator(value) {
|
|
||||||
return ['vertical', 'horizontal'].indexOf(value) >= 0
|
|
||||||
},
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
active: false,
|
|
||||||
hasMoved: false,
|
|
||||||
height: null,
|
|
||||||
percent: 50,
|
|
||||||
type: this.split === 'vertical' ? 'width' : 'height',
|
|
||||||
resizeType: this.split === 'vertical' ? 'left' : 'top'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
userSelect() {
|
|
||||||
return this.active ? 'none' : ''
|
|
||||||
},
|
|
||||||
cursor() {
|
|
||||||
return this.active ? 'col-resize' : ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onClick() {
|
|
||||||
if (!this.hasMoved) {
|
|
||||||
this.percent = 50
|
|
||||||
this.$emit('resize')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onMouseDown() {
|
|
||||||
this.active = true
|
|
||||||
this.hasMoved = false
|
|
||||||
},
|
|
||||||
onMouseUp() {
|
|
||||||
this.active = false
|
|
||||||
},
|
|
||||||
onMouseMove(e) {
|
|
||||||
if (e.buttons === 0 || e.which === 0) {
|
|
||||||
this.active = false
|
|
||||||
}
|
|
||||||
if (this.active) {
|
|
||||||
let offset = 0
|
|
||||||
let target = e.currentTarget
|
|
||||||
if (this.split === 'vertical') {
|
|
||||||
while (target) {
|
|
||||||
offset += target.offsetLeft
|
|
||||||
target = target.offsetParent
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (target) {
|
|
||||||
offset += target.offsetTop
|
|
||||||
target = target.offsetParent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentPage = this.split === 'vertical' ? e.pageX : e.pageY
|
|
||||||
const targetOffset = this.split === 'vertical' ? e.currentTarget.offsetWidth : e.currentTarget.offsetHeight
|
|
||||||
const percent = Math.floor(((currentPage - offset) / targetOffset) * 10000) / 100
|
|
||||||
if (percent > this.margin && percent < 100 - this.margin) {
|
|
||||||
this.percent = percent
|
|
||||||
}
|
|
||||||
this.$emit('resize')
|
|
||||||
this.hasMoved = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.clearfix:after {
|
|
||||||
visibility: hidden;
|
|
||||||
display: block;
|
|
||||||
font-size: 0;
|
|
||||||
content: " ";
|
|
||||||
clear: both;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-splitter-container {
|
|
||||||
height: 100%;
|
|
||||||
/*display: flex;*/
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -33,9 +33,18 @@ export default {
|
||||||
height: undefined,
|
height: undefined,
|
||||||
child: null,
|
child: null,
|
||||||
stickyHeight: 0
|
stickyHeight: 0
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.height = this.$el.getBoundingClientRect().height
|
||||||
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
this.handleScroll()
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
sticky() {
|
sticky() {
|
||||||
if (this.active) {
|
if (this.active) {
|
||||||
|
@ -62,13 +71,6 @@ export default {
|
||||||
}
|
}
|
||||||
this.reset()
|
this.reset()
|
||||||
}
|
}
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.height = this.$el.getBoundingClientRect().height
|
|
||||||
window.addEventListener('scroll', this.handleScroll)
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
window.removeEventListener('scroll', this.handleScroll)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<svg :class="svgClass" aria-hidden="true">
|
||||||
|
<use :xlink:href="iconName"></use>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'svg-icon',
|
||||||
|
props: {
|
||||||
|
iconClass: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iconName() {
|
||||||
|
return `#icon-${this.iconClass}`
|
||||||
|
},
|
||||||
|
svgClass() {
|
||||||
|
if (this.className) {
|
||||||
|
return 'svg-icon ' + this.className
|
||||||
|
} else {
|
||||||
|
return 'svg-icon'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.svg-icon {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
vertical-align: -0.15em;
|
||||||
|
fill: currentColor;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,113 @@
|
||||||
|
<template>
|
||||||
|
<a class="link--mallki" :class="className" href="#">
|
||||||
|
{{text}}
|
||||||
|
<span :data-letters="text"></span>
|
||||||
|
<span :data-letters="text"></span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
className: {
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: 'vue-element-admin'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* Mallki */
|
||||||
|
.link--mallki {
|
||||||
|
font-weight: 800;
|
||||||
|
color: #4dd9d5;
|
||||||
|
font-family: 'Dosis', sans-serif;
|
||||||
|
-webkit-transition: color 0.5s 0.25s;
|
||||||
|
transition: color 0.5s 0.25s;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 1;
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki:hover {
|
||||||
|
-webkit-transition: none;
|
||||||
|
transition: none;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki::before {
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
margin: -3px 0 0 0;
|
||||||
|
background: #3888fa;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 50%;
|
||||||
|
-webkit-transform: translate3d(-100%, 0, 0);
|
||||||
|
transform: translate3d(-100%, 0, 0);
|
||||||
|
-webkit-transition: -webkit-transform 0.4s;
|
||||||
|
transition: transform 0.4s;
|
||||||
|
-webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
|
||||||
|
transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki:hover::before {
|
||||||
|
-webkit-transform: translate3d(100%, 0, 0);
|
||||||
|
transform: translate3d(100%, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki span {
|
||||||
|
position: absolute;
|
||||||
|
height: 50%;
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki span::before {
|
||||||
|
content: attr(data-letters);
|
||||||
|
color: red;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
color: #3888fa;
|
||||||
|
-webkit-transition: -webkit-transform 0.5s;
|
||||||
|
transition: transform 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki span:nth-child(2) {
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki span:first-child::before {
|
||||||
|
top: 0;
|
||||||
|
-webkit-transform: translate3d(0, 100%, 0);
|
||||||
|
transform: translate3d(0, 100%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki span:nth-child(2)::before {
|
||||||
|
bottom: 0;
|
||||||
|
-webkit-transform: translate3d(0, -100%, 0);
|
||||||
|
transform: translate3d(0, -100%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link--mallki:hover span::before {
|
||||||
|
-webkit-transition-delay: 0.3s;
|
||||||
|
transition-delay: 0.3s;
|
||||||
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
-webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
|
||||||
|
transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,144 @@
|
||||||
|
<template>
|
||||||
|
<el-color-picker
|
||||||
|
class="theme-picker"
|
||||||
|
popper-class="theme-picker-dropdown"
|
||||||
|
v-model="theme"></el-color-picker>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const version = require('element-ui/package.json').version // element-ui version from node_modules
|
||||||
|
const ORIGINAL_THEME = '#409EFF' // default color
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
chalk: '', // content of theme-chalk css
|
||||||
|
theme: ORIGINAL_THEME
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
theme(val, oldVal) {
|
||||||
|
if (typeof val !== 'string') return
|
||||||
|
const themeCluster = this.getThemeCluster(val.replace('#', ''))
|
||||||
|
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
|
||||||
|
console.log(themeCluster, originalCluster)
|
||||||
|
const getHandler = (variable, id) => {
|
||||||
|
return () => {
|
||||||
|
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
|
||||||
|
const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
|
||||||
|
|
||||||
|
let styleTag = document.getElementById(id)
|
||||||
|
if (!styleTag) {
|
||||||
|
styleTag = document.createElement('style')
|
||||||
|
styleTag.setAttribute('id', id)
|
||||||
|
document.head.appendChild(styleTag)
|
||||||
|
}
|
||||||
|
styleTag.innerText = newStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const chalkHandler = getHandler('chalk', 'chalk-style')
|
||||||
|
|
||||||
|
if (!this.chalk) {
|
||||||
|
const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
|
||||||
|
this.getCSSString(url, chalkHandler, 'chalk')
|
||||||
|
} else {
|
||||||
|
chalkHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = [].slice.call(document.querySelectorAll('style'))
|
||||||
|
.filter(style => {
|
||||||
|
const text = style.innerText
|
||||||
|
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
|
||||||
|
})
|
||||||
|
styles.forEach(style => {
|
||||||
|
const { innerText } = style
|
||||||
|
if (typeof innerText !== 'string') return
|
||||||
|
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
|
||||||
|
})
|
||||||
|
this.$message({
|
||||||
|
message: '换肤成功',
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
updateStyle(style, oldCluster, newCluster) {
|
||||||
|
let newStyle = style
|
||||||
|
oldCluster.forEach((color, index) => {
|
||||||
|
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
|
||||||
|
})
|
||||||
|
return newStyle
|
||||||
|
},
|
||||||
|
|
||||||
|
getCSSString(url, callback, variable) {
|
||||||
|
const xhr = new XMLHttpRequest()
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||||
|
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhr.open('GET', url)
|
||||||
|
xhr.send()
|
||||||
|
},
|
||||||
|
|
||||||
|
getThemeCluster(theme) {
|
||||||
|
const tintColor = (color, tint) => {
|
||||||
|
let red = parseInt(color.slice(0, 2), 16)
|
||||||
|
let green = parseInt(color.slice(2, 4), 16)
|
||||||
|
let blue = parseInt(color.slice(4, 6), 16)
|
||||||
|
|
||||||
|
if (tint === 0) { // when primary color is in its rgb space
|
||||||
|
return [red, green, blue].join(',')
|
||||||
|
} else {
|
||||||
|
red += Math.round(tint * (255 - red))
|
||||||
|
green += Math.round(tint * (255 - green))
|
||||||
|
blue += Math.round(tint * (255 - blue))
|
||||||
|
|
||||||
|
red = red.toString(16)
|
||||||
|
green = green.toString(16)
|
||||||
|
blue = blue.toString(16)
|
||||||
|
|
||||||
|
return `#${red}${green}${blue}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const shadeColor = (color, shade) => {
|
||||||
|
let red = parseInt(color.slice(0, 2), 16)
|
||||||
|
let green = parseInt(color.slice(2, 4), 16)
|
||||||
|
let blue = parseInt(color.slice(4, 6), 16)
|
||||||
|
|
||||||
|
red = Math.round((1 - shade) * red)
|
||||||
|
green = Math.round((1 - shade) * green)
|
||||||
|
blue = Math.round((1 - shade) * blue)
|
||||||
|
|
||||||
|
red = red.toString(16)
|
||||||
|
green = green.toString(16)
|
||||||
|
blue = blue.toString(16)
|
||||||
|
|
||||||
|
return `#${red}${green}${blue}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const clusters = [theme]
|
||||||
|
for (let i = 0; i <= 9; i++) {
|
||||||
|
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
|
||||||
|
}
|
||||||
|
clusters.push(shadeColor(theme, 0.1))
|
||||||
|
return clusters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.theme-picker .el-color-picker__trigger {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-picker-dropdown .el-color-dropdown__link-btn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,95 @@
|
||||||
|
<template>
|
||||||
|
<div class="upload-container">
|
||||||
|
<el-button icon='el-icon-upload' size="mini" :style="{background:color,borderColor:color}" @click=" dialogVisible=true" type="primary">上传图片
|
||||||
|
</el-button>
|
||||||
|
<el-dialog append-to-body :visible.sync="dialogVisible">
|
||||||
|
<el-upload class="editor-slide-upload" action="https://httpbin.org/post" :multiple="true" :file-list="fileList" :show-file-list="true"
|
||||||
|
list-type="picture-card" :on-remove="handleRemove" :on-success="handleSuccess" :before-upload="beforeUpload">
|
||||||
|
<el-button size="small" type="primary">点击上传</el-button>
|
||||||
|
</el-upload>
|
||||||
|
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import { getToken } from 'api/qiniu'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'editorSlideUpload',
|
||||||
|
props: {
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#1890ff'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dialogVisible: false,
|
||||||
|
listObj: {},
|
||||||
|
fileList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkAllSuccess() {
|
||||||
|
return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
|
||||||
|
},
|
||||||
|
handleSubmit() {
|
||||||
|
const arr = Object.keys(this.listObj).map(v => this.listObj[v])
|
||||||
|
if (!this.checkAllSuccess()) {
|
||||||
|
this.$message('请等待所有图片上传成功 或 出现了网络问题,请刷新页面重新上传!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log(arr)
|
||||||
|
this.$emit('successCBK', arr)
|
||||||
|
this.listObj = {}
|
||||||
|
this.fileList = []
|
||||||
|
this.dialogVisible = false
|
||||||
|
},
|
||||||
|
handleSuccess(response, file) {
|
||||||
|
const uid = file.uid
|
||||||
|
const objKeyArr = Object.keys(this.listObj)
|
||||||
|
for (let i = 0, len = objKeyArr.length; i < len; i++) {
|
||||||
|
if (this.listObj[objKeyArr[i]].uid === uid) {
|
||||||
|
this.listObj[objKeyArr[i]].url = response.files.file
|
||||||
|
this.listObj[objKeyArr[i]].hasSuccess = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleRemove(file) {
|
||||||
|
const uid = file.uid
|
||||||
|
const objKeyArr = Object.keys(this.listObj)
|
||||||
|
for (let i = 0, len = objKeyArr.length; i < len; i++) {
|
||||||
|
if (this.listObj[objKeyArr[i]].uid === uid) {
|
||||||
|
delete this.listObj[objKeyArr[i]]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeUpload(file) {
|
||||||
|
const _self = this
|
||||||
|
const _URL = window.URL || window.webkitURL
|
||||||
|
const fileName = file.uid
|
||||||
|
this.listObj[fileName] = {}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image()
|
||||||
|
img.src = _URL.createObjectURL(file)
|
||||||
|
img.onload = function() {
|
||||||
|
_self.listObj[fileName] = { hasSuccess: false, uid: file.uid, width: this.width, height: this.height }
|
||||||
|
}
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.upload-container {
|
||||||
|
.editor-slide-upload {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,16 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div class='tinymce-container editor-container'>
|
<div class="tinymce-container editor-container" :class="{fullscreen:fullscreen}">
|
||||||
<textarea class='tinymce-textarea' :id="id"></textarea>
|
<textarea class="tinymce-textarea" :id="tinymceId"></textarea>
|
||||||
|
<div class="editor-custom-btn-container">
|
||||||
|
<editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK"></editorImage>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import editorImage from './components/editorImage'
|
||||||
|
import plugins from './plugins'
|
||||||
|
import toolbar from './toolbar'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'tinymce',
|
name: 'tinymce',
|
||||||
|
components: { editorImage },
|
||||||
props: {
|
props: {
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String
|
||||||
default: 'tinymceEditor'
|
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -20,17 +27,11 @@ export default {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
default() {
|
default() {
|
||||||
return ['removeformat undo redo | bullist numlist | outdent indent | forecolor | fullscreen code', 'bold italic blockquote | h2 p media link | alignleft aligncenter alignright']
|
return []
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
hasChange: false,
|
|
||||||
hasInit: false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
menubar: {
|
menubar: {
|
||||||
default: ''
|
default: 'file edit insert view format table'
|
||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
type: Number,
|
type: Number,
|
||||||
|
@ -38,32 +39,48 @@ export default {
|
||||||
default: 360
|
default: 360
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
hasChange: false,
|
||||||
|
hasInit: false,
|
||||||
|
tinymceId: this.id || 'vue-tinymce-' + +new Date(),
|
||||||
|
fullscreen: false
|
||||||
|
}
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
value(val) {
|
value(val) {
|
||||||
if (!this.hasChange && this.hasInit) {
|
if (!this.hasChange && this.hasInit) {
|
||||||
this.$nextTick(() => window.tinymce.get(this.id).setContent(val))
|
this.$nextTick(() => window.tinymce.get(this.tinymceId).setContent(val))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.initTinymce()
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
this.initTinymce()
|
||||||
|
},
|
||||||
|
deactivated() {
|
||||||
|
this.destroyTinymce()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initTinymce() {
|
||||||
const _this = this
|
const _this = this
|
||||||
window.tinymce.init({
|
window.tinymce.init({
|
||||||
selector: `#${this.id}`,
|
selector: `#${this.tinymceId}`,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
body_class: 'panel-body ',
|
body_class: 'panel-body ',
|
||||||
object_resizing: false,
|
object_resizing: false,
|
||||||
toolbar: this.toolbar,
|
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
|
||||||
menubar: this.menubar,
|
menubar: this.menubar,
|
||||||
plugins: 'advlist,autolink,code,paste,textcolor, colorpicker,fullscreen,link,lists,media,wordcount, imagetools',
|
plugins: plugins,
|
||||||
end_container_on_empty_block: true,
|
end_container_on_empty_block: true,
|
||||||
powerpaste_word_import: 'clean',
|
powerpaste_word_import: 'clean',
|
||||||
code_dialog_height: 450,
|
code_dialog_height: 450,
|
||||||
code_dialog_width: 1000,
|
code_dialog_width: 1000,
|
||||||
advlist_bullet_styles: 'square',
|
advlist_bullet_styles: 'square',
|
||||||
advlist_number_styles: 'default',
|
advlist_number_styles: 'default',
|
||||||
block_formats: '普通标签=p;小标题=h2;',
|
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
|
||||||
imagetools_cors_hosts: ['wpimg.wallstcn.com', 'wallstreetcn.com'],
|
|
||||||
imagetools_toolbar: 'watermark',
|
|
||||||
default_link_target: '_blank',
|
default_link_target: '_blank',
|
||||||
link_title: false,
|
link_title: false,
|
||||||
init_instance_callback: editor => {
|
init_instance_callback: editor => {
|
||||||
|
@ -71,11 +88,16 @@ export default {
|
||||||
editor.setContent(_this.value)
|
editor.setContent(_this.value)
|
||||||
}
|
}
|
||||||
_this.hasInit = true
|
_this.hasInit = true
|
||||||
editor.on('NodeChange Change KeyUp', () => {
|
editor.on('NodeChange Change KeyUp SetContent', () => {
|
||||||
this.hasChange = true
|
this.hasChange = true
|
||||||
this.$emit('input', editor.getContent({ format: 'raw' }))
|
this.$emit('input', editor.getContent())
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
setup(editor) {
|
||||||
|
editor.on('FullscreenStateChanged', (e) => {
|
||||||
|
_this.fullscreen = e.state
|
||||||
|
})
|
||||||
|
}
|
||||||
// 整合七牛上传
|
// 整合七牛上传
|
||||||
// images_dataimg_filter(img) {
|
// images_dataimg_filter(img) {
|
||||||
// setTimeout(() => {
|
// setTimeout(() => {
|
||||||
|
@ -109,53 +131,54 @@ export default {
|
||||||
// console.log(err);
|
// console.log(err);
|
||||||
// });
|
// });
|
||||||
// },
|
// },
|
||||||
setup(editor) {
|
})
|
||||||
editor.addButton('h2', {
|
|
||||||
title: '小标题', // tooltip text seen on mouseover
|
|
||||||
text: '小标题',
|
|
||||||
onclick() {
|
|
||||||
editor.execCommand('mceToggleFormat', false, 'h2')
|
|
||||||
},
|
},
|
||||||
onPostRender() {
|
destroyTinymce() {
|
||||||
const btn = this
|
if (window.tinymce.get(this.tinymceId)) {
|
||||||
editor.on('init', () => {
|
window.tinymce.get(this.tinymceId).destroy()
|
||||||
editor.formatter.formatChanged('h2', state => {
|
|
||||||
btn.active(state)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
editor.addButton('p', {
|
|
||||||
title: '正文',
|
|
||||||
text: '正文',
|
|
||||||
onclick() {
|
|
||||||
editor.execCommand('mceToggleFormat', false, 'p')
|
|
||||||
},
|
},
|
||||||
onPostRender() {
|
setContent(value) {
|
||||||
const btn = this
|
window.tinymce.get(this.tinymceId).setContent(value)
|
||||||
editor.on('init', () => {
|
},
|
||||||
editor.formatter.formatChanged('p', state => {
|
getContent() {
|
||||||
btn.active(state)
|
window.tinymce.get(this.tinymceId).getContent()
|
||||||
})
|
},
|
||||||
|
imageSuccessCBK(arr) {
|
||||||
|
const _this = this
|
||||||
|
arr.forEach(v => {
|
||||||
|
window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
window.tinymce.get(this.id).destroy()
|
this.destroyTinymce()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.tinymce-container {
|
.tinymce-container {
|
||||||
position: relative
|
position: relative;
|
||||||
|
}
|
||||||
|
.tinymce-container>>>.mce-fullscreen {
|
||||||
|
z-index: 10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tinymce-textarea {
|
.tinymce-textarea {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
.editor-custom-btn-container {
|
||||||
|
position: absolute;
|
||||||
|
right: 4px;
|
||||||
|
top: 4px;
|
||||||
|
/*z-index: 2005;*/
|
||||||
|
}
|
||||||
|
.fullscreen .editor-custom-btn-container {
|
||||||
|
z-index: 10000;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
.editor-upload-btn {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Any plugins you want to use has to be imported
|
||||||
|
// Detail plugins list see https://www.tinymce.com/docs/plugins/
|
||||||
|
// Custom builds see https://www.tinymce.com/download/custom-builds/
|
||||||
|
|
||||||
|
const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime legacyoutput link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
|
||||||
|
|
||||||
|
export default plugins
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Here is a list of the toolbar
|
||||||
|
// Detail list see https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols
|
||||||
|
|
||||||
|
const toolbar = ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
|
||||||
|
|
||||||
|
export default toolbar
|
|
@ -1,318 +0,0 @@
|
||||||
.todoapp {
|
|
||||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
||||||
line-height: 1.4em;
|
|
||||||
color: #4d4d4d;
|
|
||||||
min-width: 230px;
|
|
||||||
max-width: 550px;
|
|
||||||
margin: 40PX auto 0;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
font-weight: 300;
|
|
||||||
button {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
background: none;
|
|
||||||
font-size: 100%;
|
|
||||||
vertical-align: baseline;
|
|
||||||
font-family: inherit;
|
|
||||||
font-weight: inherit;
|
|
||||||
color: inherit;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.todoapp {
|
|
||||||
background: #fff;
|
|
||||||
margin: 130px 0 40px 0;
|
|
||||||
position: relative;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
.todoapp input::-webkit-input-placeholder {
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
color: #e6e6e6;
|
|
||||||
}
|
|
||||||
.todoapp input::-moz-placeholder {
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
color: #e6e6e6;
|
|
||||||
}
|
|
||||||
.todoapp input::input-placeholder {
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
color: #e6e6e6;
|
|
||||||
}
|
|
||||||
.todoapp h1 {
|
|
||||||
position: absolute;
|
|
||||||
top: -155px;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 100px;
|
|
||||||
font-weight: 100;
|
|
||||||
text-align: center;
|
|
||||||
color: rgba(175, 47, 47, 0.15);
|
|
||||||
-webkit-text-rendering: optimizeLegibility;
|
|
||||||
-moz-text-rendering: optimizeLegibility;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
}
|
|
||||||
.new-todo,
|
|
||||||
.edit {
|
|
||||||
position: relative;
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 18px;
|
|
||||||
font-family: inherit;
|
|
||||||
font-weight: inherit;
|
|
||||||
line-height: 1.4em;
|
|
||||||
border: 0;
|
|
||||||
color: inherit;
|
|
||||||
padding: 6px;
|
|
||||||
border: 1px solid #999;
|
|
||||||
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
.new-todo {
|
|
||||||
padding: 16px 16px 16px 60px;
|
|
||||||
border: none;
|
|
||||||
background: rgba(0, 0, 0, 0.003);
|
|
||||||
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
|
|
||||||
}
|
|
||||||
.main {
|
|
||||||
position: relative;
|
|
||||||
z-index: 2;
|
|
||||||
border-top: 1px solid #e6e6e6;
|
|
||||||
}
|
|
||||||
.toggle-all {
|
|
||||||
text-align: center;
|
|
||||||
border: none;
|
|
||||||
/* Mobile Safari */
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.toggle-all+label {
|
|
||||||
width: 60px;
|
|
||||||
height: 34px;
|
|
||||||
font-size: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: -52px;
|
|
||||||
left: -13px;
|
|
||||||
-webkit-transform: rotate(90deg);
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
.toggle-all+label:before {
|
|
||||||
content: '❯';
|
|
||||||
font-size: 22px;
|
|
||||||
color: #e6e6e6;
|
|
||||||
padding: 10px 27px 10px 27px;
|
|
||||||
}
|
|
||||||
.toggle-all:checked+label:before {
|
|
||||||
color: #737373;
|
|
||||||
}
|
|
||||||
.todo-list {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.todo-list li {
|
|
||||||
position: relative;
|
|
||||||
font-size: 24px;
|
|
||||||
border-bottom: 1px solid #ededed;
|
|
||||||
}
|
|
||||||
.todo-list li:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
.todo-list li.editing {
|
|
||||||
border-bottom: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
.todo-list li.editing .edit {
|
|
||||||
display: block;
|
|
||||||
width: 506px;
|
|
||||||
padding: 12px 16px;
|
|
||||||
margin: 0 0 0 43px;
|
|
||||||
}
|
|
||||||
.todo-list li.editing .view {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.todo-list li .toggle {
|
|
||||||
text-align: center;
|
|
||||||
width: 40px;
|
|
||||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
|
||||||
height: auto;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: auto 0;
|
|
||||||
border: none;
|
|
||||||
/* Mobile Safari */
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
.todo-list li .toggle {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
.todo-list li .toggle+label {
|
|
||||||
/*
|
|
||||||
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
|
|
||||||
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
|
|
||||||
*/
|
|
||||||
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: center left;
|
|
||||||
background-size: 36px;
|
|
||||||
}
|
|
||||||
.todo-list li .toggle:checked+label {
|
|
||||||
background-size: 36px;
|
|
||||||
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
|
|
||||||
}
|
|
||||||
.todo-list li label {
|
|
||||||
word-break: break-all;
|
|
||||||
padding: 15px 15px 15px 50px;
|
|
||||||
display: block;
|
|
||||||
line-height: 1.0;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: color 0.4s;
|
|
||||||
}
|
|
||||||
.todo-list li.completed label {
|
|
||||||
color: #d9d9d9;
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
.todo-list li .destroy {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 10px;
|
|
||||||
bottom: 0;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
margin: auto 0;
|
|
||||||
font-size: 30px;
|
|
||||||
color: #cc9a9a;
|
|
||||||
transition: color 0.2s ease-out;
|
|
||||||
}
|
|
||||||
.todo-list li .destroy:hover {
|
|
||||||
color: #af5b5e;
|
|
||||||
}
|
|
||||||
.todo-list li .destroy:after {
|
|
||||||
content: '×';
|
|
||||||
}
|
|
||||||
.todo-list li:hover .destroy {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.todo-list li .edit {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.todo-list li.editing:last-child {
|
|
||||||
margin-bottom: -1px;
|
|
||||||
}
|
|
||||||
.footer {
|
|
||||||
color: #777;
|
|
||||||
position: relative;
|
|
||||||
padding: 10px 15px;
|
|
||||||
height: 40px;
|
|
||||||
text-align: center;
|
|
||||||
border-top: 1px solid #e6e6e6;
|
|
||||||
}
|
|
||||||
.footer:before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 50px;
|
|
||||||
overflow: hidden;
|
|
||||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6, 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6, 0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
.todo-count {
|
|
||||||
float: left;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.todo-count strong {
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
.filters {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
left: -20px;
|
|
||||||
}
|
|
||||||
.filters li {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
.filters li a {
|
|
||||||
color: inherit;
|
|
||||||
margin: 3px;
|
|
||||||
font-size: 12px;
|
|
||||||
padding: 3px 7px;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
.filters li a:hover {
|
|
||||||
border-color: rgba(175, 47, 47, 0.1);
|
|
||||||
}
|
|
||||||
.filters li a.selected {
|
|
||||||
border-color: rgba(175, 47, 47, 0.2);
|
|
||||||
}
|
|
||||||
.clear-completed,
|
|
||||||
html .clear-completed:active {
|
|
||||||
float: right;
|
|
||||||
position: relative;
|
|
||||||
line-height: 20px;
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.clear-completed:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
.info {
|
|
||||||
margin: 65px auto 0;
|
|
||||||
color: #bfbfbf;
|
|
||||||
font-size: 10px;
|
|
||||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.info p {
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
.info a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
.info a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
Hack to remove background from Mobile Safari.
|
|
||||||
Can't use it globally since it destroys checkboxes in Firefox
|
|
||||||
*/
|
|
||||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
|
||||||
.toggle-all,
|
|
||||||
.todo-list li .toggle {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
.todo-list li .toggle {
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 430px) {
|
|
||||||
.footer {
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
.filters {
|
|
||||||
bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
* @Author: jianglei
|
||||||
|
* @Date: 2017-10-12 12:06:49
|
||||||
|
*/
|
||||||
|
'use strict'
|
||||||
|
import Vue from 'vue'
|
||||||
|
export default function treeToArray(data, expandAll, parent = null, level = null) {
|
||||||
|
let tmp = []
|
||||||
|
Array.from(data).forEach(function(record) {
|
||||||
|
if (record._expanded === undefined) {
|
||||||
|
Vue.set(record, '_expanded', expandAll)
|
||||||
|
}
|
||||||
|
let _level = 1
|
||||||
|
if (level !== undefined && level !== null) {
|
||||||
|
_level = level + 1
|
||||||
|
}
|
||||||
|
Vue.set(record, '_level', _level)
|
||||||
|
// 如果有父元素
|
||||||
|
if (parent) {
|
||||||
|
Vue.set(record, 'parent', parent)
|
||||||
|
}
|
||||||
|
tmp.push(record)
|
||||||
|
if (record.children && record.children.length > 0) {
|
||||||
|
const children = treeToArray(record.children, expandAll, record, _level)
|
||||||
|
tmp = tmp.concat(children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return tmp
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
<template>
|
||||||
|
<el-table :data="formatData" :row-style="showRow" v-bind="$attrs">
|
||||||
|
<el-table-column v-if="columns.length===0" width="150">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-for="space in scope.row._level" class="ms-tree-space" :key="space"></span>
|
||||||
|
<span class="tree-ctrl" v-if="iconShow(0,scope.row)" @click="toggleExpanded(scope.$index)">
|
||||||
|
<i v-if="!scope.row._expanded" class="el-icon-plus"></i>
|
||||||
|
<i v-else class="el-icon-minus"></i>
|
||||||
|
</span>
|
||||||
|
{{scope.$index}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-else v-for="(column, index) in columns" :key="column.value" :label="column.text" :width="column.width">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span v-if="index === 0" v-for="space in scope.row._level" class="ms-tree-space" :key="space"></span>
|
||||||
|
<span class="tree-ctrl" v-if="iconShow(index,scope.row)" @click="toggleExpanded(scope.$index)">
|
||||||
|
<i v-if="!scope.row._expanded" class="el-icon-plus"></i>
|
||||||
|
<i v-else class="el-icon-minus"></i>
|
||||||
|
</span>
|
||||||
|
{{scope.row[column.value]}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<slot></slot>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
Auth: Lei.j1ang
|
||||||
|
Created: 2018/1/19-13:59
|
||||||
|
*/
|
||||||
|
import treeToArray from './eval'
|
||||||
|
export default {
|
||||||
|
name: 'treeTable',
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: [Array, Object],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
evalFunc: Function,
|
||||||
|
evalArgs: Array,
|
||||||
|
expandAll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 格式化数据源
|
||||||
|
formatData: function() {
|
||||||
|
let tmp
|
||||||
|
if (!Array.isArray(this.data)) {
|
||||||
|
tmp = [this.data]
|
||||||
|
} else {
|
||||||
|
tmp = this.data
|
||||||
|
}
|
||||||
|
const func = this.evalFunc || treeToArray
|
||||||
|
const args = this.evalArgs ? Array.concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll]
|
||||||
|
return func.apply(null, args)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showRow: function(row) {
|
||||||
|
const show = (row.row.parent ? (row.row.parent._expanded && row.row.parent._show) : true)
|
||||||
|
row.row._show = show
|
||||||
|
return show ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;' : 'display:none;'
|
||||||
|
},
|
||||||
|
// 切换下级是否展开
|
||||||
|
toggleExpanded: function(trIndex) {
|
||||||
|
const record = this.formatData[trIndex]
|
||||||
|
record._expanded = !record._expanded
|
||||||
|
},
|
||||||
|
// 图标显示
|
||||||
|
iconShow(index, record) {
|
||||||
|
return (index === 0 && record.children && record.children.length > 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style rel="stylesheet/css">
|
||||||
|
@keyframes treeTableShow {
|
||||||
|
from {opacity: 0;}
|
||||||
|
to {opacity: 1;}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes treeTableShow {
|
||||||
|
from {opacity: 0;}
|
||||||
|
to {opacity: 1;}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||||
|
$color-blue: #2196F3;
|
||||||
|
$space-width: 18px;
|
||||||
|
.ms-tree-space {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
display: inline-block;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1;
|
||||||
|
width: $space-width;
|
||||||
|
height: 14px;
|
||||||
|
&::before {
|
||||||
|
content: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.processContainer{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
table td {
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-ctrl{
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
color: $color-blue;
|
||||||
|
margin-left: -$space-width;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,89 @@
|
||||||
|
## 写在前面
|
||||||
|
此组件仅提供一个创建TreeTable的解决思路
|
||||||
|
|
||||||
|
## prop说明
|
||||||
|
#### *data*
|
||||||
|
**必填**
|
||||||
|
|
||||||
|
原始数据,要求是一个数组或者对象
|
||||||
|
```javascript
|
||||||
|
[{
|
||||||
|
key1: value1,
|
||||||
|
key2: value2,
|
||||||
|
children: [{
|
||||||
|
key1: value1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key1: value1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key1: value1
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
或者
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
key1: value1,
|
||||||
|
key2: value2,
|
||||||
|
children: [{
|
||||||
|
key1: value1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key1: value1
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### columns
|
||||||
|
列属性,要求是一个数组
|
||||||
|
|
||||||
|
1. text: 显示在表头的文字
|
||||||
|
2. value: 对应data的key。treeTable将显示相应的value
|
||||||
|
3. width: 每列的宽度,为一个数字(可选)
|
||||||
|
|
||||||
|
如果你想要每个字段都有自定义的样式或者嵌套其他组件,columns可不提供,直接像在el-table一样写即可,如果没有自定义内容,提供columns将更加的便捷方便
|
||||||
|
|
||||||
|
如果你有几个字段是需要自定义的,几个不需要,那么可以将不需要自定义的字段放入columns,将需要自定义的内容放入到slot中,详情见后文
|
||||||
|
```javascript
|
||||||
|
[{
|
||||||
|
value:string,
|
||||||
|
text:string,
|
||||||
|
width:number
|
||||||
|
},{
|
||||||
|
value:string,
|
||||||
|
text:string,
|
||||||
|
width:number
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### expandAll
|
||||||
|
是否默认全部展开,boolean值,默认为false
|
||||||
|
|
||||||
|
#### evalFunc
|
||||||
|
解析函数,function,非必须
|
||||||
|
|
||||||
|
如果不提供,将使用默认的[evalFunc](./eval.js)
|
||||||
|
|
||||||
|
如果提供了evalFunc,那么会用提供的evalFunc去解析data,并返回treeTable渲染所需要的值。如何编写一个evalFunc,请参考[*eval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/components/TreeTable/eval.js)或[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/example/table/treeTable/customEval.js)
|
||||||
|
|
||||||
|
#### evalArgs
|
||||||
|
解析函数的参数,是一个数组
|
||||||
|
|
||||||
|
**请注意,自定义的解析函数参数第一个为this.data,第二个参数为, this.expandAll,你不需要在evalArgs填写。一定记住,这两个参数是强制性的,并且位置不可颠倒** *this.data为需要解析的数据,this.expandAll为是否默认展开*
|
||||||
|
|
||||||
|
如你的解析函数需要的参数为`(this.data, this.expandAll,1,2,3,4)`,那么你只需要将`[1,2,3,4]`赋值给`evalArgs`就可以了
|
||||||
|
|
||||||
|
如果你的解析函数参数只有`(this.data, this.expandAll)`,那么就可以不用填写evalArgs了
|
||||||
|
|
||||||
|
具体可参考[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/example/table/treeTable/customEval.js)的函数参数和[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/example/table/treeTable/customTreeTable.vue)的`evalArgs`属性值
|
||||||
|
|
||||||
|
## slot
|
||||||
|
这是一个自定义列的插槽。
|
||||||
|
|
||||||
|
默认情况下,treeTable只有一行行展示数据的功能。但是一般情况下,我们会要给行加上一个操作按钮或者根据当行数据展示不同的样式,这时我们就需要自定义列了。请参考[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/example/table/treeTable/customTreeTable.vue),[实例效果](http://panjiachen.github.io/vue-element-admin/#/example/table/custom-tree-table)
|
||||||
|
|
||||||
|
`slot`和`columns属性`可同时存在,columns里面的数据列会在slot自定义列的左边展示
|
||||||
|
|
||||||
|
## 其他
|
||||||
|
如果有其他的需求,请参考[el-table](http://element-cn.eleme.io/#/en-US/component/table)的api自行修改index.vue
|
|
@ -7,7 +7,6 @@
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<div class="image-preview image-app-preview">
|
<div class="image-preview image-app-preview">
|
||||||
<div class="image-preview-wrapper" v-show="imageUrl.length>1">
|
<div class="image-preview-wrapper" v-show="imageUrl.length>1">
|
||||||
<div class='app-fake-conver'>  全球 付费节目单 最热 经济</div>
|
|
||||||
<img :src="imageUrl">
|
<img :src="imageUrl">
|
||||||
<div class="image-preview-action">
|
<div class="image-preview-action">
|
||||||
<i @click="rmImage" class="el-icon-delete"></i>
|
<i @click="rmImage" class="el-icon-delete"></i>
|
||||||
|
@ -29,7 +28,7 @@
|
||||||
import { getToken } from '@/api/qiniu'
|
import { getToken } from '@/api/qiniu'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'singleImageUpload',
|
name: 'singleImageUpload3',
|
||||||
props: {
|
props: {
|
||||||
value: String
|
value: String
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<input id="excel-upload-input" ref="excel-upload-input" type="file" accept=".xlsx, .xls" class="c-hide" @change="handkeFileChange">
|
||||||
|
<div id="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
|
||||||
|
Drop excel file here or
|
||||||
|
<el-button style="margin-left:16px;" size="mini" type="primary" @click="handleUpload">browse</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import XLSX from 'xlsx'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
excelData: {
|
||||||
|
header: null,
|
||||||
|
results: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
generateDate({ header, results }) {
|
||||||
|
this.excelData.header = header
|
||||||
|
this.excelData.results = results
|
||||||
|
this.$emit('on-selected-file', this.excelData)
|
||||||
|
},
|
||||||
|
handleDrop(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
const files = e.dataTransfer.files
|
||||||
|
if (files.length !== 1) {
|
||||||
|
this.$message.error('Only support uploading one file!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const itemFile = files[0] // only use files[0]
|
||||||
|
this.readerData(itemFile)
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
},
|
||||||
|
handleDragover(e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
e.dataTransfer.dropEffect = 'copy'
|
||||||
|
},
|
||||||
|
handleUpload() {
|
||||||
|
document.getElementById('excel-upload-input').click()
|
||||||
|
},
|
||||||
|
handkeFileChange(e) {
|
||||||
|
const files = e.target.files
|
||||||
|
const itemFile = files[0] // only use files[0]
|
||||||
|
if (!itemFile) return
|
||||||
|
this.readerData(itemFile)
|
||||||
|
this.$refs['excel-upload-input'].value = null // fix can't select the same excel
|
||||||
|
},
|
||||||
|
readerData(itemFile) {
|
||||||
|
const reader = new FileReader()
|
||||||
|
reader.onload = e => {
|
||||||
|
const data = e.target.result
|
||||||
|
const fixedData = this.fixdata(data)
|
||||||
|
const workbook = XLSX.read(btoa(fixedData), { type: 'base64' })
|
||||||
|
const firstSheetName = workbook.SheetNames[0]
|
||||||
|
const worksheet = workbook.Sheets[firstSheetName]
|
||||||
|
const header = this.get_header_row(worksheet)
|
||||||
|
const results = XLSX.utils.sheet_to_json(worksheet)
|
||||||
|
this.generateDate({ header, results })
|
||||||
|
}
|
||||||
|
reader.readAsArrayBuffer(itemFile)
|
||||||
|
},
|
||||||
|
fixdata(data) {
|
||||||
|
let o = ''
|
||||||
|
let l = 0
|
||||||
|
const w = 10240
|
||||||
|
for (; l < data.byteLength / w; ++l) o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w, l * w + w)))
|
||||||
|
o += String.fromCharCode.apply(null, new Uint8Array(data.slice(l * w)))
|
||||||
|
return o
|
||||||
|
},
|
||||||
|
get_header_row(sheet) {
|
||||||
|
const headers = []
|
||||||
|
const range = XLSX.utils.decode_range(sheet['!ref'])
|
||||||
|
let C
|
||||||
|
const R = range.s.r /* start in the first row */
|
||||||
|
for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
|
||||||
|
var cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })] /* find the cell in the first row */
|
||||||
|
var hdr = 'UNKNOWN ' + C // <-- replace with your desired default
|
||||||
|
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
|
||||||
|
headers.push(hdr)
|
||||||
|
}
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#excel-upload-input{
|
||||||
|
display: none;
|
||||||
|
z-index: -9999;
|
||||||
|
}
|
||||||
|
#drop{
|
||||||
|
border: 2px dashed #bbb;
|
||||||
|
width: 600px;
|
||||||
|
height: 160px;
|
||||||
|
line-height: 160px;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-size: 24px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
color: #bbb;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Inspired by https://github.com/Inndy/vue-clipboard2
|
||||||
|
const Clipboard = require('clipboard')
|
||||||
|
if (!Clipboard) {
|
||||||
|
throw new Error('you shold npm install `clipboard` --save at first ')
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
bind(el, binding) {
|
||||||
|
if (binding.arg === 'success') {
|
||||||
|
el._v_clipboard_success = binding.value
|
||||||
|
} else if (binding.arg === 'error') {
|
||||||
|
el._v_clipboard_error = binding.value
|
||||||
|
} else {
|
||||||
|
const clipboard = new Clipboard(el, {
|
||||||
|
text() { return binding.value },
|
||||||
|
action() { return binding.arg === 'cut' ? 'cut' : 'copy' }
|
||||||
|
})
|
||||||
|
clipboard.on('success', e => {
|
||||||
|
const callback = el._v_clipboard_success
|
||||||
|
callback && callback(e) // eslint-disable-line
|
||||||
|
})
|
||||||
|
clipboard.on('error', e => {
|
||||||
|
const callback = el._v_clipboard_error
|
||||||
|
callback && callback(e) // eslint-disable-line
|
||||||
|
})
|
||||||
|
el._v_clipboard = clipboard
|
||||||
|
}
|
||||||
|
},
|
||||||
|
update(el, binding) {
|
||||||
|
if (binding.arg === 'success') {
|
||||||
|
el._v_clipboard_success = binding.value
|
||||||
|
} else if (binding.arg === 'error') {
|
||||||
|
el._v_clipboard_error = binding.value
|
||||||
|
} else {
|
||||||
|
el._v_clipboard.text = function() { return binding.value }
|
||||||
|
el._v_clipboard.action = function() { return binding.arg === 'cut' ? 'cut' : 'copy' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unbind(el, binding) {
|
||||||
|
if (binding.arg === 'success') {
|
||||||
|
delete el._v_clipboard_success
|
||||||
|
} else if (binding.arg === 'error') {
|
||||||
|
delete el._v_clipboard_error
|
||||||
|
} else {
|
||||||
|
el._v_clipboard.destroy()
|
||||||
|
delete el._v_clipboard
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
import Clipboard from './clipboard'
|
||||||
|
|
||||||
|
const install = function(Vue) {
|
||||||
|
Vue.directive('Clipboard', Clipboard)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.Vue) {
|
||||||
|
window.clipboard = Clipboard
|
||||||
|
Vue.use(install); // eslint-disable-line
|
||||||
|
}
|
||||||
|
|
||||||
|
Clipboard.install = install
|
||||||
|
export default Clipboard
|
|
@ -0,0 +1,74 @@
|
||||||
|
export default{
|
||||||
|
bind(el, binding) {
|
||||||
|
const dialogHeaderEl = el.querySelector('.el-dialog__header')
|
||||||
|
const dragDom = el.querySelector('.el-dialog')
|
||||||
|
dialogHeaderEl.style.cssText += ';cursor:move;'
|
||||||
|
dragDom.style.cssText += ';top:0px;'
|
||||||
|
|
||||||
|
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
|
||||||
|
const getStyle = (function() {
|
||||||
|
if (window.document.currentStyle) {
|
||||||
|
return (dom, attr) => dom.currentStyle[attr]
|
||||||
|
} else {
|
||||||
|
return (dom, attr) => getComputedStyle(dom, false)[attr]
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
dialogHeaderEl.onmousedown = (e) => {
|
||||||
|
// 鼠标按下,计算当前元素距离可视区的距离
|
||||||
|
const disX = e.clientX - dialogHeaderEl.offsetLeft
|
||||||
|
const disY = e.clientY - dialogHeaderEl.offsetTop
|
||||||
|
|
||||||
|
const dragDomWidth = dragDom.offsetWidth
|
||||||
|
const dragDomheight = dragDom.offsetHeight
|
||||||
|
|
||||||
|
const screenWidth = document.body.clientWidth
|
||||||
|
const screenHeight = document.body.clientHeight
|
||||||
|
|
||||||
|
const minDragDomLeft = dragDom.offsetLeft
|
||||||
|
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth
|
||||||
|
|
||||||
|
const minDragDomTop = dragDom.offsetTop
|
||||||
|
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight
|
||||||
|
|
||||||
|
// 获取到的值带px 正则匹配替换
|
||||||
|
let styL = getStyle(dragDom, 'left')
|
||||||
|
let styT = getStyle(dragDom, 'top')
|
||||||
|
|
||||||
|
if (styL.includes('%')) {
|
||||||
|
styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100)
|
||||||
|
styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100)
|
||||||
|
} else {
|
||||||
|
styL = +styL.replace(/\px/g, '')
|
||||||
|
styT = +styT.replace(/\px/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
document.onmousemove = function(e) {
|
||||||
|
// 通过事件委托,计算移动的距离
|
||||||
|
let left = e.clientX - disX
|
||||||
|
let top = e.clientY - disY
|
||||||
|
|
||||||
|
// 边界处理
|
||||||
|
if (-(left) > minDragDomLeft) {
|
||||||
|
left = -minDragDomLeft
|
||||||
|
} else if (left > maxDragDomLeft) {
|
||||||
|
left = maxDragDomLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-(top) > minDragDomTop) {
|
||||||
|
top = -minDragDomTop
|
||||||
|
} else if (top > maxDragDomTop) {
|
||||||
|
top = maxDragDomTop
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动当前元素
|
||||||
|
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`
|
||||||
|
}
|
||||||
|
|
||||||
|
document.onmouseup = function(e) {
|
||||||
|
document.onmousemove = null
|
||||||
|
document.onmouseup = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|