Compare commits
591 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
20f6150741 | ||
|
7703005013 | ||
|
9a5c404ef8 | ||
|
9d975b5eff | ||
|
331173ffee | ||
|
f890685d8d | ||
|
fb30079477 | ||
|
3100d0cff4 | ||
|
ae6bbf7858 | ||
|
63dba8b7d8 | ||
|
ccb227fbec | ||
|
715fe3e684 | ||
|
abb1d91a9e | ||
|
d1f32a05a8 | ||
|
e601da38d0 | ||
|
b8d47bd847 | ||
|
8d242a002f | ||
|
763b31d915 | ||
|
c963f56686 | ||
|
17f0d84b35 | ||
|
f38d5810d9 | ||
|
cf48ed218b | ||
|
9574643e92 | ||
|
8edf209498 | ||
|
698df4942d | ||
|
1e2fc52ac9 | ||
|
3e92814f13 | ||
|
5ca6f79836 | ||
|
dc6030bce6 | ||
|
fc9e7249e7 | ||
|
9677406002 | ||
|
1e06f1da67 | ||
|
aa2eb7d40f | ||
|
6255f54f41 | ||
|
c2495545a5 | ||
|
fc277c75ee | ||
|
e544c01e63 | ||
|
c0f378e50a | ||
|
6b88c41ffc | ||
|
2e89ef444b | ||
|
fe950801c9 | ||
|
070a3343f2 | ||
|
48e47e86f1 | ||
|
4e0559833f | ||
|
8c18c000d4 | ||
|
9ed5db044f | ||
|
0fed69f367 | ||
|
a1d6ad3453 | ||
|
c71f3110fb | ||
|
fe381503eb | ||
|
24ee761809 | ||
|
0b6e7515ce | ||
|
dd9fb09a29 | ||
|
6e42b4c896 | ||
|
3b9abde89a | ||
|
4b3a41c535 | ||
|
b44000c9de | ||
|
727c1a45dd | ||
|
9daeb1cb34 | ||
|
3153a1b10b | ||
|
23055c9b2c | ||
|
8ef6c7ee7d | ||
|
eb1d3381f4 | ||
|
8cf279fbe1 | ||
|
ac8eddf3d7 | ||
|
6234db924e | ||
|
d84a17688d | ||
|
f767fab4cc | ||
|
77a40745bb | ||
|
109c393cc6 | ||
|
c54e99d0a9 | ||
|
5ea614fe5d | ||
|
1bb9283edd | ||
|
9cea3c3abe | ||
|
68a19d55de | ||
|
3dd29ab07a | ||
|
c98d578757 | ||
|
311796a14b | ||
|
cc7572820e | ||
|
deb6840174 | ||
|
07c3211989 | ||
|
afdb893dcd | ||
|
90ee05df93 | ||
|
6f1db28ea2 | ||
|
a56145509d | ||
|
1b394ae417 | ||
|
c2a2fec067 | ||
|
999ea3a443 | ||
|
46d6f455af | ||
|
4d6e9a5358 | ||
|
c68e68897b | ||
|
b37a789f63 | ||
|
54dc9ddfaa | ||
|
c6843f9646 | ||
|
ea60729c0a | ||
|
4a07432468 | ||
|
a51d72f42e | ||
|
c13b574794 | ||
|
9df740bcf1 | ||
|
4a7b50ed46 | ||
|
a0862ca547 | ||
|
9f1552d98f | ||
|
a25c63a580 | ||
|
1701fcce5d | ||
|
1d684b7632 | ||
|
cbdad9cb1b | ||
|
1a345a7c65 | ||
|
ec58373a52 | ||
|
bf2629ffba | ||
|
baa7172a70 | ||
|
bc003fd78b | ||
|
41a5615ee5 | ||
|
df23405bde | ||
|
f94aa1aca3 | ||
|
96bda5515c | ||
|
0f6d830c19 | ||
|
e8ab82c2c1 | ||
|
a284c1f007 | ||
|
323408f8d9 | ||
|
90d3e314c0 | ||
|
4780ac334f | ||
|
b0bd91cd0f | ||
|
ae2754a568 | ||
|
6e07d18b1d | ||
|
f58db95be5 | ||
|
616b65c238 | ||
|
68cd051bb6 | ||
|
935d9aaba8 | ||
|
616f173aab | ||
|
d1cceb69b7 | ||
|
ff13ee1f27 | ||
|
dc84e7b9fb | ||
|
b82e8e860d | ||
|
98a8277a37 | ||
|
63ff44f8e5 | ||
|
dd5646ffbc | ||
|
371c8504c2 | ||
|
87b319d96a | ||
|
4c49259c92 | ||
|
83516aeb17 | ||
|
24602755cd | ||
|
11163146c0 | ||
|
3277343804 | ||
|
0740bb36f7 | ||
|
9c03dd3514 | ||
|
fbb3641406 | ||
|
f85b044ff8 | ||
|
ed4427243d | ||
|
9c5352ecd6 | ||
|
62fb5d1e14 | ||
|
14e693339c | ||
|
c58bce603b | ||
|
fa54b927f7 | ||
|
ba6bf3e217 | ||
|
6ecf8b820a | ||
|
a5dd905b46 | ||
|
676aaf3485 | ||
|
44e4bddc21 | ||
|
a03d1edac6 | ||
|
2938e33d0e | ||
|
2fb26525fa | ||
|
d0d1addba8 | ||
|
0fe3f181ad | ||
|
68de01e828 | ||
|
6e569c4f4a | ||
|
0fbda3c8c7 | ||
|
5bbb4abe21 | ||
|
1e50d4a93b | ||
|
ccf1791fca | ||
|
325120b653 | ||
|
2e1f36fe00 | ||
|
00d292f67e | ||
|
0e75dcc42a | ||
|
189e645b23 | ||
|
d5a8fb1e71 | ||
|
b2570f891d | ||
|
4035bf58f2 | ||
|
e5d4290938 | ||
|
8f58baf617 | ||
|
fded36c990 | ||
|
53f3e7d5e6 | ||
|
93e01b64d4 | ||
|
a871e147d6 | ||
|
378ca2c217 | ||
|
1df59cc4b6 | ||
|
312a2ca8ed | ||
|
f3733c0b37 | ||
|
0ef14ff5c6 | ||
|
c57c6045c9 | ||
|
fe190b6188 | ||
|
48a966fe1c | ||
|
63d39727ac | ||
|
1e0b9c0055 | ||
|
5f20bfc780 | ||
|
8851a68066 | ||
|
878628b0ed | ||
|
e254fc6c1a | ||
|
513eb66d97 | ||
|
62e1c851c8 | ||
|
f0a01f0fd1 | ||
|
aa7eab58f9 | ||
|
77cb6b1f43 | ||
|
5fbf1cf5da | ||
|
6a5197ad51 | ||
|
9b7a9a64e5 | ||
|
89ce53e185 | ||
|
9e04f58163 | ||
|
d98c5032f8 | ||
|
a575670cef | ||
|
44fa96f142 | ||
|
e4481a9d34 | ||
|
572a2d9c34 | ||
|
5070e20dea | ||
|
59789d92cf | ||
|
775f6f5f3a | ||
|
2687b2eb3c | ||
|
76327a8f26 | ||
|
03b708870b | ||
|
bdc31cea1a | ||
|
ae2ca072f5 | ||
|
d995cdb332 | ||
|
cbc3ddd827 | ||
|
9cf00fd63a | ||
|
03691739e1 | ||
|
3f479664b6 | ||
|
cbee7b6f20 | ||
|
2a590a2087 | ||
|
c93fcefe54 | ||
|
9f8ac37497 | ||
|
8c685cc4c6 | ||
|
e40fd27775 | ||
|
f3ccd9f04e | ||
|
914a4ec62c | ||
|
739aef4387 | ||
|
a7942636c6 | ||
|
31d9da8b9f | ||
|
600e75d0a2 | ||
|
9ba1ea6933 | ||
|
320e941d9a | ||
|
d0f6d3f1f6 | ||
|
0375542009 | ||
|
03e5f762b3 | ||
|
bd0227feed | ||
|
20aad46416 | ||
|
4fc25241fe | ||
|
6327869106 | ||
|
c861dd10cf | ||
|
0a196f79ba | ||
|
d2d323bb02 | ||
|
66613f0373 | ||
|
6795c26d02 | ||
|
597df4844a | ||
|
1e103cf151 | ||
|
99d53ee0ca | ||
|
f9d510ea78 | ||
|
9fbb028124 | ||
|
9b5f0160af | ||
|
0e4ea0871c | ||
|
88429bd809 | ||
|
62a9565f86 | ||
|
f663b23b29 | ||
|
afd255d5ba | ||
|
b7c8079350 | ||
|
543a9928cf | ||
|
8f37950589 | ||
|
6821eac35b | ||
|
cc5e62d5f5 | ||
|
0cccc636b8 | ||
|
563ce873bd | ||
|
44e94b2d16 | ||
|
a160848367 | ||
|
7099e6a3eb | ||
|
14fee27a92 | ||
|
7003a79ef6 | ||
|
c5faa63ee5 | ||
|
d29a9486a2 | ||
|
01442ce4d7 | ||
|
f28a7149fb | ||
|
51ad902d8f | ||
|
3cff6dcf4c | ||
|
afe975b3c2 | ||
|
d0eebf83c4 | ||
|
a55b149b27 | ||
|
fc19121311 | ||
|
de06619266 | ||
|
88c28f5d7e | ||
|
26b84847dd | ||
|
3cc3e134c2 | ||
|
2afb1dfabb | ||
|
5fe3d70246 | ||
|
4aa9345d90 | ||
|
0fcbf4b53b | ||
|
8142c06a99 | ||
|
c398ee0ddc | ||
|
a633729215 | ||
|
f9c4dd7af3 | ||
|
5f4ce7fc71 | ||
|
01928cd4ec | ||
|
27effcc54c | ||
|
7cacd5a4ac | ||
|
31b7fa6f55 | ||
|
2cb6211cd6 | ||
|
ebb0b4a0ff | ||
|
c356695f2e | ||
|
112e3b977c | ||
|
ae41459cb1 | ||
|
aa592cfb69 | ||
|
9205a85c2d | ||
|
6938dd3caf | ||
|
398d59d78a | ||
|
dc35d1ae92 | ||
|
2f411b870c | ||
|
305d659431 | ||
|
55c08ab666 | ||
|
09e613b33a | ||
|
c0ed44932e | ||
|
a48a1bd8be | ||
|
55e8cd5306 | ||
|
dc9e27e4b1 | ||
|
d754eae662 | ||
|
94ae1f8719 | ||
|
48070e5abf | ||
|
eef99d3d14 | ||
|
6f2a7ce804 | ||
|
2e0d3fd0e4 | ||
|
bc01171466 | ||
|
4e65890b6a | ||
|
79c5cb4fcd | ||
|
0d47e3454e | ||
|
3253a91a7e | ||
|
fea6e5feee | ||
|
1610945813 | ||
|
840eda6e27 | ||
|
700e08b795 | ||
|
3c0696d1a9 | ||
|
76a6eb12e7 | ||
|
2c147649ba | ||
|
de3b29b5f3 | ||
|
54acf1e0d5 | ||
|
de08e49f19 | ||
|
2472107768 | ||
|
d18902dfee | ||
|
9ba2648689 | ||
|
1d0b26cec8 | ||
|
ea7e139696 | ||
|
deac95da1b | ||
|
2b51b987be | ||
|
45fef9b431 | ||
|
83e56488d8 | ||
|
f3bfaa0f2b | ||
|
e261fbcbfb | ||
|
471c297f13 | ||
|
093475ee50 | ||
|
cb3578e5c3 | ||
|
fe25c4d96b | ||
|
7fef8568c2 | ||
|
0dfa56c73e | ||
|
642d48e372 | ||
|
021c147b31 | ||
|
04d9b849dd | ||
|
2e74f0d782 | ||
|
dc162093cc | ||
|
8fd786c4ed | ||
|
54e7ce2b76 | ||
|
f5563b4eed | ||
|
0c80fba84c | ||
|
4d3bbae183 | ||
|
b6d97f1806 | ||
|
a68413cb8f | ||
|
f9aaaa9091 | ||
|
85492f148f | ||
|
b7ca786751 | ||
|
c32bd73b42 | ||
|
3aacd3cccd | ||
|
e7f626f015 | ||
|
b53d0945ab | ||
|
ca75f7bcbc | ||
|
b7939165d1 | ||
|
ebc2ac08b7 | ||
|
a9d2978c31 | ||
|
a4597887ac | ||
|
44b180a7b3 | ||
|
acebaeae0c | ||
|
d09923ff4f | ||
|
fc1a13d10b | ||
|
705b9ccefd | ||
|
c84964d77c | ||
|
8f9de5c641 | ||
|
96a7035b1d | ||
|
7f2bd58035 | ||
|
b4b9d166c4 | ||
|
da24d61008 | ||
|
8ce571b61d | ||
|
38192b828d | ||
|
72f653dcc7 | ||
|
4dfa878fc6 | ||
|
cef1f11931 | ||
|
443c7aed3c | ||
|
0f5304112c | ||
|
dd3e22d5a1 | ||
|
d99cb068aa | ||
|
394f366aac | ||
|
e5ed2a39a5 | ||
|
39d26068ec | ||
|
d68d464142 | ||
|
d476e32032 | ||
|
8f2b0c94ba | ||
|
e00f2aedc7 | ||
|
df28ad7078 | ||
|
4feb89c94e | ||
|
a56d6f0cbd | ||
|
bee26561aa | ||
|
2ec9fe74a8 | ||
|
dec160fd1e | ||
|
c06baffb17 | ||
|
f876b9b678 | ||
|
061fa1f2a5 | ||
|
e0b8f09a9e | ||
|
ede541e2f5 | ||
|
e0f6248d0e | ||
|
1c4c3380e6 | ||
|
073b7219ff | ||
|
98604af104 | ||
|
3cb1e321d3 | ||
|
f2fcdee815 | ||
|
497b96f931 | ||
|
ed34ea3e07 | ||
|
47a373803e | ||
|
e8ad1f835c | ||
|
43a51148fe | ||
|
3f9df15c30 | ||
|
a9363ce541 | ||
|
690c779c64 | ||
|
f6279077de | ||
|
6b9e89055d | ||
|
6b13ffce66 | ||
|
d20585a3f9 | ||
|
46b4f74969 | ||
|
8c204b9837 | ||
|
339d760771 | ||
|
6d6a9df5b8 | ||
|
1286324214 | ||
|
372c4489f0 | ||
|
1511fe3778 | ||
|
122f7cafa6 | ||
|
6d1059f6a8 | ||
|
1d4f12187f | ||
|
925dbeb045 | ||
|
35055c5e51 | ||
|
e0a1e249ee | ||
|
a0d83e2ffc | ||
|
53059d5ccf | ||
|
fa5e6d9ecf | ||
|
4e25a17bff | ||
|
61095a9f2c | ||
|
61deec548c | ||
|
5eda0685ed | ||
|
11beefdb44 | ||
|
7e1ba16d12 | ||
|
7451ed6299 | ||
|
71aa416d71 | ||
|
4723a02a4b | ||
|
e05da2650b | ||
|
bb1d939a94 | ||
|
ac5d087ea4 | ||
|
c53fb7fbb1 | ||
|
660ff765f5 | ||
|
aaf24b4654 | ||
|
8211016078 | ||
|
374fd3ffeb | ||
|
e8b34bbc0d | ||
|
74cbb26209 | ||
|
fe31c88193 | ||
|
3b89cde53a | ||
|
59e240eb9a | ||
|
98d5f9a247 | ||
|
3666148ddc | ||
|
d56831679e | ||
|
2c868f47d9 | ||
|
1ae31fdd45 | ||
|
a932272b8f | ||
|
577e4dc17e | ||
|
0d9188b206 | ||
|
5b3b8b87d1 | ||
|
2c82d0a28e | ||
|
913f6c8bec | ||
|
76f4017470 | ||
|
feb6785654 | ||
|
59073fb013 | ||
|
c82ed3fcbf | ||
|
f99b97d9f1 | ||
|
99417081ed | ||
|
88d1338f29 | ||
|
3ded46cf23 | ||
|
5857db3393 | ||
|
a465652be6 | ||
|
a8459fa572 | ||
|
cddace507d | ||
|
e762056e80 | ||
|
18ec63d238 | ||
|
ccddfe87bc | ||
|
87a44ae7f5 | ||
|
1c852db0ef | ||
|
9463c50e06 | ||
|
658abf664d | ||
|
4940dd4040 | ||
|
91bd31e1e2 | ||
|
a8602e78f0 | ||
|
516897b97a | ||
|
2725285d26 | ||
|
a842a4b451 | ||
|
be0606ebbc | ||
|
a10de2e8d8 | ||
|
2282135b44 | ||
|
329f3b3714 | ||
|
065eaa93a2 | ||
|
4f2f136dd0 | ||
|
8d53ae1259 | ||
|
a185412446 | ||
|
3cf048e80b | ||
|
fcf7c0ba50 | ||
|
807aa548b2 | ||
|
db61251d89 | ||
|
582c6f4ae4 | ||
|
9c2a7e9485 | ||
|
fde12e8ef9 | ||
|
8945476c22 | ||
|
14ff09a414 | ||
|
a14547aaf9 | ||
|
b1311322ad | ||
|
ffec6b6df7 | ||
|
f0afbf7ea5 | ||
|
a4f8e0b805 | ||
|
2d72df3605 | ||
|
e9f92a7d3d | ||
|
ee362f22b2 | ||
|
11426c8494 | ||
|
fa5f5e9d26 | ||
|
cda292dec1 | ||
|
877b73cd67 | ||
|
53d7243316 | ||
|
5379510013 | ||
|
f712d4682e | ||
|
cb0e889829 | ||
|
6a8a02f839 | ||
|
d56cd59474 | ||
|
a10cfcc837 | ||
|
c8e632f0c3 | ||
|
c182a119e1 | ||
|
90fd4328b7 | ||
|
97570fa612 | ||
|
bae698c9ad | ||
|
f7aee3b5a3 | ||
|
b98860ace1 | ||
|
3c05519a09 | ||
|
385ec5a762 | ||
|
33a4369cd7 | ||
|
8fa2364a3b | ||
|
551e911eb4 | ||
|
b8ecda19d8 | ||
|
62d2f62bff | ||
|
0094f44910 | ||
|
d06d476b50 | ||
|
aa5f9059b3 | ||
|
9768305166 | ||
|
e912cea26a | ||
|
eac12e3ac0 | ||
|
c32fc58a3a | ||
|
bf0f2e7ee3 | ||
|
2e9a3a849b | ||
|
cdebb5c012 | ||
|
00a83d1e5a | ||
|
17ada3c65e | ||
|
391e7703ed | ||
|
97e94c067d | ||
|
a3b1dd81fd | ||
|
c96bdeb99d | ||
|
630d06bf76 | ||
|
8c9ebd7345 | ||
|
89c72d277e | ||
|
108b380d20 | ||
|
69fc52d4e9 | ||
|
d78b49803d | ||
|
dd9ef5145d | ||
|
ae44d0b8ca | ||
|
6ad03ac5f0 | ||
|
553ef477ef | ||
|
1083a17386 | ||
|
535fe083e5 | ||
|
83e8dfc494 | ||
|
77ff823037 |
15
.babelrc
@@ -1,8 +1,17 @@
|
|||||||
{
|
{
|
||||||
"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
|
"env": {
|
||||||
|
"development":{
|
||||||
|
"plugins": ["dynamic-import-node"]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
491
.eslintrc.js
@@ -1,318 +1,197 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
root: true,
|
root: true,
|
||||||
parser: 'babel-eslint',
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
|
parser: 'babel-eslint',
|
||||||
sourceType: 'module'
|
sourceType: 'module'
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
node: true
|
node: true,
|
||||||
},
|
es6: true,
|
||||||
extends: 'eslint:recommended',
|
|
||||||
// required to lint *.vue files
|
|
||||||
plugins: [
|
|
||||||
'html'
|
|
||||||
],
|
|
||||||
// check if imports actually resolve
|
|
||||||
'settings': {
|
|
||||||
'import/resolver': {
|
|
||||||
'webpack': {
|
|
||||||
'config': 'build/webpack.base.conf.js'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
extends: ['plugin:vue/recommended', 'eslint:recommended'],
|
||||||
|
|
||||||
// add your custom rules here
|
// add your custom rules here
|
||||||
'rules': {
|
//it is base on https://github.com/vuejs/eslint-config-vue
|
||||||
// don't require .vue extension when importing
|
rules: {
|
||||||
// 'import/extensions': ['error', 'always', {
|
"vue/max-attributes-per-line": [2, {
|
||||||
// 'js': 'never',
|
"singleline": 10,
|
||||||
// 'vue': 'never'
|
"multiline": {
|
||||||
// }],
|
"max": 1,
|
||||||
// allow debugger during development
|
"allowFirstLine": false
|
||||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
}
|
||||||
/*
|
}],
|
||||||
* Possible Errors
|
"vue/singleline-html-element-content-newline": "off",
|
||||||
*/
|
"vue/multiline-html-element-content-newline":"off",
|
||||||
|
"vue/name-property-casing": ["error", "PascalCase"],
|
||||||
// disallow unnecessary parentheses
|
'accessor-pairs': 2,
|
||||||
'no-extra-parens': ['error', 'all', {'nestedBinaryExpressions': false}],
|
'arrow-spacing': [2, {
|
||||||
|
'before': true,
|
||||||
// disallow negating the left operand of relational operators
|
'after': true
|
||||||
'no-unsafe-negation': 'error',
|
}],
|
||||||
|
'block-spacing': [2, 'always'],
|
||||||
// enforce valid JSDoc comments
|
'brace-style': [2, '1tbs', {
|
||||||
'valid-jsdoc': 'off',
|
'allowSingleLine': true
|
||||||
|
}],
|
||||||
/*
|
'camelcase': [0, {
|
||||||
* Best Practices
|
'properties': 'always'
|
||||||
*/
|
}],
|
||||||
|
'comma-dangle': [2, 'never'],
|
||||||
// enforce return statements in callbacks of array methods
|
'comma-spacing': [2, {
|
||||||
'array-callback-return': 'error',
|
'before': false,
|
||||||
|
'after': true
|
||||||
// enforce consistent brace style for all control statements
|
}],
|
||||||
curly: ['error', 'multi-line'],
|
'comma-style': [2, 'last'],
|
||||||
|
'constructor-super': 2,
|
||||||
// enforce consistent newlines before and after dots
|
'curly': [2, 'multi-line'],
|
||||||
'dot-location': ['error', 'property'],
|
'dot-location': [2, 'property'],
|
||||||
|
'eol-last': 2,
|
||||||
// enforce dot notation whenever possible
|
'eqeqeq': [2, 'allow-null'],
|
||||||
'dot-notation': 'error',
|
'generator-star-spacing': [2, {
|
||||||
|
'before': true,
|
||||||
// require the use of === and !==
|
'after': true
|
||||||
'eqeqeq': ['error', 'smart'],
|
}],
|
||||||
|
'handle-callback-err': [2, '^(err|error)$'],
|
||||||
// disallow the use of arguments.caller or arguments.callee
|
'indent': [2, 2, {
|
||||||
'no-caller': 'error',
|
'SwitchCase': 1
|
||||||
|
}],
|
||||||
// disallow empty functions
|
'jsx-quotes': [2, 'prefer-single'],
|
||||||
'no-empty-function': 'error',
|
'key-spacing': [2, {
|
||||||
|
'beforeColon': false,
|
||||||
// disallow unnecessary calls to .bind()
|
'afterColon': true
|
||||||
'no-extra-bind': 'error',
|
}],
|
||||||
|
'keyword-spacing': [2, {
|
||||||
// disallow unnecessary labels
|
'before': true,
|
||||||
'no-extra-label': 'error',
|
'after': true
|
||||||
|
}],
|
||||||
// disallow leading or trailing decimal points in numeric literals
|
'new-cap': [2, {
|
||||||
'no-floating-decimal': 'error',
|
'newIsCap': true,
|
||||||
|
'capIsNew': false
|
||||||
// disallow assignments to native objects or read-only global variables
|
}],
|
||||||
'no-global-assign': 'error',
|
'new-parens': 2,
|
||||||
|
'no-array-constructor': 2,
|
||||||
// disallow the use of eval()-like methods
|
'no-caller': 2,
|
||||||
'no-implied-eval': 'error',
|
|
||||||
|
|
||||||
// disallow the use of the __iterator__ property
|
|
||||||
'no-iterator': 'error',
|
|
||||||
|
|
||||||
// disallow unnecessary nested blocks
|
|
||||||
'no-lone-blocks': 'error',
|
|
||||||
|
|
||||||
// disallow multiple spaces
|
|
||||||
'no-multi-spaces': 'error',
|
|
||||||
|
|
||||||
// disallow new operators with the String, Number, and Boolean objects
|
|
||||||
'no-new-wrappers': 'error',
|
|
||||||
|
|
||||||
// disallow octal escape sequences in string literals
|
|
||||||
'no-octal-escape': 'error',
|
|
||||||
|
|
||||||
// disallow the use of the __proto__ property
|
|
||||||
'no-proto': 'error',
|
|
||||||
|
|
||||||
// disallow comparisons where both sides are exactly the same
|
|
||||||
'no-self-compare': 'error',
|
|
||||||
|
|
||||||
// disallow throwing literals as exceptions
|
|
||||||
'no-throw-literal': 'error',
|
|
||||||
|
|
||||||
// disallow unused expressions
|
|
||||||
'no-unused-expressions': 'error',
|
|
||||||
|
|
||||||
// disallow unnecessary calls to .call() and .apply()
|
|
||||||
'no-useless-call': 'error',
|
|
||||||
|
|
||||||
// disallow unnecessary concatenation of literals or template literals
|
|
||||||
'no-useless-concat': 'error',
|
|
||||||
|
|
||||||
// disallow unnecessary escape characters
|
|
||||||
'no-useless-escape': 'error',
|
|
||||||
|
|
||||||
// disallow void operators
|
|
||||||
'no-void': 'error',
|
|
||||||
|
|
||||||
// require parentheses around immediate function invocations
|
|
||||||
'wrap-iife': 'error',
|
|
||||||
|
|
||||||
// require or disallow “Yoda” conditions
|
|
||||||
yoda: 'error',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Variables
|
|
||||||
*/
|
|
||||||
|
|
||||||
// disallow labels that share a name with a variable
|
|
||||||
'no-label-var': 'error',
|
|
||||||
|
|
||||||
// disallow initializing variables to undefined
|
|
||||||
'no-undef-init': 'error',
|
|
||||||
'no-undef': 'off',
|
|
||||||
// disallow the use of variables before they are defined
|
|
||||||
'no-use-before-define': 'error',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Node.js and CommonJS
|
|
||||||
*/
|
|
||||||
|
|
||||||
// disallow new operators with calls to require
|
|
||||||
'no-new-require': 'error',
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Stylistic Issues
|
|
||||||
*/
|
|
||||||
|
|
||||||
// enforce consistent spacing inside array brackets
|
|
||||||
'array-bracket-spacing': 'error',
|
|
||||||
|
|
||||||
// enforce consistent spacing inside single-line blocks
|
|
||||||
'block-spacing': 'error',
|
|
||||||
|
|
||||||
// enforce consistent brace style for blocks
|
|
||||||
'brace-style': ['error', '1tbs', {'allowSingleLine': true}],
|
|
||||||
|
|
||||||
// require or disallow trailing commas
|
|
||||||
'comma-dangle': 'error',
|
|
||||||
|
|
||||||
// enforce consistent spacing before and after commas
|
|
||||||
'comma-spacing': 'error',
|
|
||||||
|
|
||||||
// enforce consistent comma style
|
|
||||||
'comma-style': 'error',
|
|
||||||
|
|
||||||
// enforce consistent spacing inside computed property brackets
|
|
||||||
'computed-property-spacing': 'error',
|
|
||||||
|
|
||||||
// require or disallow spacing between function identifiers and their invocations
|
|
||||||
'func-call-spacing': 'error',
|
|
||||||
|
|
||||||
// enforce consistent indentation
|
|
||||||
indent: ['error', 2, {SwitchCase: 1}],
|
|
||||||
|
|
||||||
// enforce the consistent use of either double or single quotes in JSX attributes
|
|
||||||
'jsx-quotes': 'error',
|
|
||||||
|
|
||||||
// enforce consistent spacing between keys and values in object literal properties
|
|
||||||
'key-spacing': 'error',
|
|
||||||
|
|
||||||
// enforce consistent spacing before and after keywords
|
|
||||||
'keyword-spacing': 'error',
|
|
||||||
|
|
||||||
// enforce consistent linebreak style
|
|
||||||
'linebreak-style': 'error',
|
|
||||||
|
|
||||||
// require or disallow newlines around directives
|
|
||||||
'lines-around-directive': 'error',
|
|
||||||
|
|
||||||
// require constructor names to begin with a capital letter
|
|
||||||
'new-cap': 'off',
|
|
||||||
|
|
||||||
// require parentheses when invoking a constructor with no arguments
|
|
||||||
'new-parens': 'error',
|
|
||||||
|
|
||||||
// disallow Array constructors
|
|
||||||
'no-array-constructor': 'error',
|
|
||||||
|
|
||||||
// disallow Object constructors
|
|
||||||
'no-new-object': 'error',
|
|
||||||
|
|
||||||
// disallow trailing whitespace at the end of lines
|
|
||||||
'no-trailing-spaces': 'error',
|
|
||||||
|
|
||||||
// disallow ternary operators when simpler alternatives exist
|
|
||||||
'no-unneeded-ternary': 'error',
|
|
||||||
|
|
||||||
// disallow whitespace before properties
|
|
||||||
'no-whitespace-before-property': 'error',
|
|
||||||
|
|
||||||
// enforce consistent spacing inside braces
|
|
||||||
'object-curly-spacing': ['error', 'always'],
|
|
||||||
|
|
||||||
// require or disallow padding within blocks
|
|
||||||
'padded-blocks': ['error', 'never'],
|
|
||||||
|
|
||||||
// require quotes around object literal property names
|
|
||||||
'quote-props': ['error', 'as-needed'],
|
|
||||||
|
|
||||||
// enforce the consistent use of either backticks, double, or single quotes
|
|
||||||
quotes: ['error', 'single'],
|
|
||||||
|
|
||||||
// enforce consistent spacing before and after semicolons
|
|
||||||
'semi-spacing': 'error',
|
|
||||||
|
|
||||||
// require or disallow semicolons instead of ASI
|
|
||||||
// semi: ['error', 'never'],
|
|
||||||
|
|
||||||
// enforce consistent spacing before blocks
|
|
||||||
'space-before-blocks': 'error',
|
|
||||||
|
|
||||||
'no-console': 'off',
|
'no-console': 'off',
|
||||||
|
'no-class-assign': 2,
|
||||||
// enforce consistent spacing before function definition opening parenthesis
|
'no-cond-assign': 2,
|
||||||
'space-before-function-paren': ['error', 'never'],
|
'no-const-assign': 2,
|
||||||
|
'no-control-regex': 0,
|
||||||
// enforce consistent spacing inside parentheses
|
'no-delete-var': 2,
|
||||||
'space-in-parens': 'error',
|
'no-dupe-args': 2,
|
||||||
|
'no-dupe-class-members': 2,
|
||||||
// require spacing around infix operators
|
'no-dupe-keys': 2,
|
||||||
'space-infix-ops': 'error',
|
'no-duplicate-case': 2,
|
||||||
|
'no-empty-character-class': 2,
|
||||||
// enforce consistent spacing before or after unary operators
|
'no-empty-pattern': 2,
|
||||||
'space-unary-ops': 'error',
|
'no-eval': 2,
|
||||||
|
'no-ex-assign': 2,
|
||||||
// enforce consistent spacing after the // or /* in a comment
|
'no-extend-native': 2,
|
||||||
'spaced-comment': 'error',
|
'no-extra-bind': 2,
|
||||||
|
'no-extra-boolean-cast': 2,
|
||||||
// require or disallow Unicode byte order mark (BOM)
|
'no-extra-parens': [2, 'functions'],
|
||||||
'unicode-bom': 'error',
|
'no-fallthrough': 2,
|
||||||
|
'no-floating-decimal': 2,
|
||||||
|
'no-func-assign': 2,
|
||||||
/*
|
'no-implied-eval': 2,
|
||||||
* ECMAScript 6
|
'no-inner-declarations': [2, 'functions'],
|
||||||
*/
|
'no-invalid-regexp': 2,
|
||||||
|
'no-irregular-whitespace': 2,
|
||||||
// require braces around arrow function bodies
|
'no-iterator': 2,
|
||||||
'arrow-body-style': 'error',
|
'no-label-var': 2,
|
||||||
|
'no-labels': [2, {
|
||||||
// require parentheses around arrow function arguments
|
'allowLoop': false,
|
||||||
'arrow-parens': ['error', 'as-needed'],
|
'allowSwitch': false
|
||||||
|
}],
|
||||||
// enforce consistent spacing before and after the arrow in arrow functions
|
'no-lone-blocks': 2,
|
||||||
'arrow-spacing': 'error',
|
'no-mixed-spaces-and-tabs': 2,
|
||||||
|
'no-multi-spaces': 2,
|
||||||
// enforce consistent spacing around * operators in generator functions
|
'no-multi-str': 2,
|
||||||
'generator-star-spacing': ['error', 'after'],
|
'no-multiple-empty-lines': [2, {
|
||||||
|
'max': 1
|
||||||
// disallow duplicate module imports
|
}],
|
||||||
'no-duplicate-imports': 'error',
|
'no-native-reassign': 2,
|
||||||
|
'no-negated-in-lhs': 2,
|
||||||
// disallow unnecessary computed property keys in object literals
|
'no-new-object': 2,
|
||||||
'no-useless-computed-key': 'error',
|
'no-new-require': 2,
|
||||||
|
'no-new-symbol': 2,
|
||||||
// disallow unnecessary constructors
|
'no-new-wrappers': 2,
|
||||||
'no-useless-constructor': 'error',
|
'no-obj-calls': 2,
|
||||||
|
'no-octal': 2,
|
||||||
// disallow renaming import, export, and destructured assignments to the same name
|
'no-octal-escape': 2,
|
||||||
'no-useless-rename': 'error',
|
'no-path-concat': 2,
|
||||||
|
'no-proto': 2,
|
||||||
// require let or const instead of var
|
'no-redeclare': 2,
|
||||||
'no-var': 'error',
|
'no-regex-spaces': 2,
|
||||||
|
'no-return-assign': [2, 'except-parens'],
|
||||||
// require or disallow method and property shorthand syntax for object literals
|
'no-self-assign': 2,
|
||||||
'object-shorthand': 'error',
|
'no-self-compare': 2,
|
||||||
|
'no-sequences': 2,
|
||||||
// require arrow functions as callbacks
|
'no-shadow-restricted-names': 2,
|
||||||
'prefer-arrow-callback': 'error',
|
'no-spaced-func': 2,
|
||||||
|
'no-sparse-arrays': 2,
|
||||||
// require const declarations for variables that are never reassigned after declared
|
'no-this-before-super': 2,
|
||||||
'prefer-const': 'error',
|
'no-throw-literal': 2,
|
||||||
|
'no-trailing-spaces': 2,
|
||||||
// disallow parseInt() in favor of binary, octal, and hexadecimal literals
|
'no-undef': 2,
|
||||||
'prefer-numeric-literals': 'error',
|
'no-undef-init': 2,
|
||||||
|
'no-unexpected-multiline': 2,
|
||||||
// require rest parameters instead of arguments
|
'no-unmodified-loop-condition': 2,
|
||||||
'prefer-rest-params': 'error',
|
'no-unneeded-ternary': [2, {
|
||||||
|
'defaultAssignment': false
|
||||||
// require spread operators instead of .apply()
|
}],
|
||||||
'prefer-spread': 'error',
|
'no-unreachable': 2,
|
||||||
|
'no-unsafe-finally': 2,
|
||||||
// enforce spacing between rest and spread operators and their expressions
|
'no-unused-vars': [2, {
|
||||||
'rest-spread-spacing': 'error',
|
'vars': 'all',
|
||||||
|
'args': 'none'
|
||||||
// require or disallow spacing around embedded expressions of template strings
|
}],
|
||||||
'template-curly-spacing': 'error',
|
'no-useless-call': 2,
|
||||||
|
'no-useless-computed-key': 2,
|
||||||
// require or disallow spacing around the * in yield* expressions
|
'no-useless-constructor': 2,
|
||||||
'yield-star-spacing': 'error'
|
'no-useless-escape': 0,
|
||||||
|
'no-whitespace-before-property': 2,
|
||||||
|
'no-with': 2,
|
||||||
|
'one-var': [2, {
|
||||||
|
'initialized': 'never'
|
||||||
|
}],
|
||||||
|
'operator-linebreak': [2, 'after', {
|
||||||
|
'overrides': {
|
||||||
|
'?': 'before',
|
||||||
|
':': 'before'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
'padded-blocks': [2, 'never'],
|
||||||
|
'quotes': [2, 'single', {
|
||||||
|
'avoidEscape': true,
|
||||||
|
'allowTemplateLiterals': true
|
||||||
|
}],
|
||||||
|
'semi': [2, 'never'],
|
||||||
|
'semi-spacing': [2, {
|
||||||
|
'before': false,
|
||||||
|
'after': true
|
||||||
|
}],
|
||||||
|
'space-before-blocks': [2, 'always'],
|
||||||
|
'space-before-function-paren': [2, 'never'],
|
||||||
|
'space-in-parens': [2, 'never'],
|
||||||
|
'space-infix-ops': 2,
|
||||||
|
'space-unary-ops': [2, {
|
||||||
|
'words': true,
|
||||||
|
'nonwords': false
|
||||||
|
}],
|
||||||
|
'spaced-comment': [2, 'always', {
|
||||||
|
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
|
||||||
|
}],
|
||||||
|
'template-curly-spacing': [2, 'never'],
|
||||||
|
'use-isnan': 2,
|
||||||
|
'valid-typeof': 2,
|
||||||
|
'wrap-iife': [2, 'any'],
|
||||||
|
'yield-star-spacing': [2, 'both'],
|
||||||
|
'yoda': [2, 'never'],
|
||||||
|
'prefer-const': 2,
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||||
|
'object-curly-spacing': [2, 'always', {
|
||||||
|
objectsInObjects: false
|
||||||
|
}],
|
||||||
|
'array-bracket-spacing': [2, 'never']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
.gitignore
vendored
@@ -1,10 +1,21 @@
|
|||||||
.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*
|
||||||
|
**/*.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": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
.travis.yml
Executable file
@@ -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
|
||||||
|
177
README-en.md
@@ -1,177 +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
|
|
||||||
│ ├── jquery
|
|
||||||
│ └── 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
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Realtime switching themes
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### tabs
|
|
||||||
|
|
||||||
<br />
|
|
||||||
|
|
||||||
#### Collapsing sidebar
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Drag & drop table
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Interactive table
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Uploading cropped avatar
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Error log
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Rich text (integrated with Qiniu, watermark and customization)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Packaging table component
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Charts
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Exporting to Excel
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### More
|
|
||||||
|
|
||||||
http://panjiachen.github.io/vue-element-admin
|
|
309
README.md
@@ -1,192 +1,221 @@
|
|||||||
# vue-element-admin #
|
<p align="center">
|
||||||
[线上地址](http://panjiachen.github.io/vue-element-admin)
|
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
|
||||||
|
</p>
|
||||||
|
|
||||||
[English Document](https://github.com/PanJiaChen/vue-element-admin/blob/master/README-en.md)
|
<p align="center">
|
||||||
|
<a href="https://github.com/vuejs/vue">
|
||||||
|
<img src="https://img.shields.io/badge/vue-2.5.17-brightgreen.svg" alt="vue">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/ElemeFE/element">
|
||||||
|
<img src="https://img.shields.io/badge/element--ui-2.4.11-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>
|
||||||
|
<a href="https://gitter.im/vue-element-admin/discuss">
|
||||||
|
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="gitter">
|
||||||
|
</a>
|
||||||
|
<a href="https://panjiachen.github.io/vue-element-admin-site/donate">
|
||||||
|
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
[wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
English | [简体中文](./README.zh-CN.md)
|
||||||
|
|
||||||
**本项目的定位是后台集成方案,不适合当基础模板来开发,模板建议使用 [vueAdmin-template](https://github.com/PanJiaChen/vueAdmin-template) , 桌面端 [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)**
|
## Introduction
|
||||||
|
|
||||||
|
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) is a front-end management background integration solution. It based on [vue](https://github.com/vuejs/vue) and use the UI Toolkit [element](https://github.com/ElemeFE/element).
|
||||||
|
|
||||||
|
It is a magical vue admin 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.
|
||||||
|
|
||||||
**注意:该项目目前使用element-ui@1.3.3版本,所以最低兼容 Vue 2.3.0**
|
**[v4.0](https://github.com/PanJiaChen/vue-element-admin/tree/v4.0) has in beta. It built on vue-cli@3, optimized a lot of code and added a lot of new features. Welcome to use and make suggestions.**
|
||||||
|
|
||||||
## 前言
|
- [Preview](http://panjiachen.github.io/vue-element-admin)
|
||||||
> 这半年来一直在用vue写管理后台,目前后台已经有百来个页面,十几种权限,但维护成本依然很低,所以准备开源分享一下后台开发的经验和成果。目前的技术栈主要的采用vue+element+axios由webpack2打包。由于是个人项目,所以数据请求都是用了mockjs模拟。注意:在此项目基础上改造开发时请移除mock文件。
|
|
||||||
|
|
||||||
|
- [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)
|
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||||
- [手摸手,带你用 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` 方便大家交流
|
- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/)
|
||||||
|
|
||||||
**如有问题请先看上述文章和Wiki,若不能满足,欢迎 issue 和 pr ~**
|
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
|
||||||
|
|
||||||
**该项目并不是一个脚手架,更倾向于是一个集成解决方案**
|
**This project is positioned as a background integration solution and is not suitable for secondary development as a basic template.**
|
||||||
|
|
||||||
**该项目不支持低版本游览器,有需求请自行添加polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
- Base template recommends using: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
|
||||||
|
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
|
- Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
|
||||||
|
|
||||||
|
**This project does not support low version browsers (e.g. IE). Please add polyfill yourself if you need them.**
|
||||||
|
|
||||||
## 功能
|
**Note: This project uses element-ui@2.3.0+ version, so the minimum compatible vue@2.5.0+**
|
||||||
- 登录/注销
|
|
||||||
- 权限验证
|
**Start using `webpack4` from `v3.8.0`. If you still want to continue using `webpack3`, please use this branch [webpack3](https://github.com/PanJiaChen/vue-element-admin/tree/webpack3)**
|
||||||
- 侧边栏
|
|
||||||
- 面包屑
|
## Preparation
|
||||||
- 富文本编辑器
|
|
||||||
- Markdown编辑器
|
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/), [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock).
|
||||||
- JSON编辑器
|
Understanding and learning this knowledge in advance will greatly help the use of this project.
|
||||||
- 列表拖拽
|
|
||||||
- plitPane
|
---
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Sponsors
|
||||||
|
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen)
|
||||||
|
|
||||||
|
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p>
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
```
|
||||||
|
- Login / Logout
|
||||||
|
|
||||||
|
- Permission Authentication
|
||||||
|
- Page permission
|
||||||
|
- Directive permission
|
||||||
|
- Two-step login
|
||||||
|
|
||||||
|
- Multi-environment build
|
||||||
|
- dev sit stage prod
|
||||||
|
|
||||||
|
- Global Features
|
||||||
|
- I18n
|
||||||
|
- Multiple dynamic themes
|
||||||
|
- Dynamic sidebar (supports multi-level routing)
|
||||||
|
- Dynamic breadcrumb
|
||||||
|
- Tags-view (Tab page Support right-click operation)
|
||||||
|
- Svg Sprite
|
||||||
|
- Mock data
|
||||||
|
- Screenfull
|
||||||
|
- Responsive Sidebar
|
||||||
|
|
||||||
|
- Editor
|
||||||
|
- Rich Text Editor
|
||||||
|
- Markdown Editor
|
||||||
|
- JSON Editor
|
||||||
|
|
||||||
|
- Excel
|
||||||
|
- Export Excel
|
||||||
|
- Export zip
|
||||||
|
- Upload Excel
|
||||||
|
- Visualization Excel
|
||||||
|
|
||||||
|
- Table
|
||||||
|
- Dynamic Table
|
||||||
|
- Drag And Drop Table
|
||||||
|
- Tree Table
|
||||||
|
- Inline Edit Table
|
||||||
|
|
||||||
|
- Error Page
|
||||||
|
- 401
|
||||||
|
- 404
|
||||||
|
|
||||||
|
- Components
|
||||||
|
- Avatar Upload
|
||||||
|
- Back To Top
|
||||||
|
- Drag Dialog
|
||||||
|
- Drag Select
|
||||||
|
- Drag Kanban
|
||||||
|
- Drag List
|
||||||
|
- SplitPane
|
||||||
- Dropzone
|
- Dropzone
|
||||||
- Sticky
|
- Sticky
|
||||||
- CountTo
|
- CountTo
|
||||||
- echarts图表
|
|
||||||
- 401,401错误页面
|
|
||||||
- 错误日志
|
|
||||||
- 导出excel
|
|
||||||
- table example
|
|
||||||
- 动态table example
|
|
||||||
- 拖拽table example
|
|
||||||
- 内联编辑table example
|
|
||||||
- form example
|
|
||||||
- 多环境发布
|
|
||||||
- dashboard
|
|
||||||
- 二次登录
|
|
||||||
- 动态侧边栏(支持多级路由)
|
|
||||||
- mock数据
|
|
||||||
- cache tabs example
|
|
||||||
- screenfull
|
|
||||||
- markdown2html
|
|
||||||
- views-tab
|
|
||||||
|
|
||||||
|
- Advanced Example
|
||||||
|
- Error Log
|
||||||
|
- Dashboard
|
||||||
|
- Guide Page
|
||||||
|
- ECharts
|
||||||
|
- Clipboard
|
||||||
|
- Markdown to html
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
|
||||||
├── build // 构建相关
|
|
||||||
├── config // 配置相关
|
|
||||||
├── src // 源代码
|
|
||||||
│ ├── api // 所有请求
|
|
||||||
│ ├── assets // 主题 字体等静态资源
|
|
||||||
│ ├── components // 全局公用组件
|
|
||||||
│ ├── directive // 全局指令
|
|
||||||
│ ├── filtres // 全局filter
|
|
||||||
│ ├── mock // mock数据
|
|
||||||
│ ├── router // 路由
|
|
||||||
│ ├── store // 全局store管理
|
|
||||||
│ ├── styles // 全局样式
|
|
||||||
│ ├── utils // 全局公用方法
|
|
||||||
│ ├── view // view
|
|
||||||
│ ├── App.vue // 入口页面
|
|
||||||
│ └── main.js // 入口 加载组件 初始化等
|
|
||||||
├── static // 第三方不打包资源
|
|
||||||
│ ├── jquery
|
|
||||||
│ └── Tinymce // 富文本
|
|
||||||
├── .babelrc // babel-loader 配置
|
|
||||||
├── eslintrc.js // eslint 配置项
|
|
||||||
├── .gitignore // git 忽略项
|
|
||||||
├── favicon.ico // favicon图标
|
|
||||||
├── index.html // html模板
|
|
||||||
└── package.json // package.json
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# --report to build with bundle size analytics
|
||||||
|
npm run build:prod --report
|
||||||
|
|
||||||
|
# --generate a bundle size analytics. default: bundle-report.html
|
||||||
|
npm run build:prod --generate_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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) 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
|
||||||
|
|
||||||
#### 两步验证登录 支持微信和qq
|
If you find this project useful, you can buy author a glass of juice :tropical_drink:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### 真正的动态换肤
|
[Paypal Me](https://www.paypal.me/panfree23)
|
||||||
|
|
||||||
<br />
|
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
|
||||||
|
|
||||||
#### tabs
|
## Browsers support
|
||||||
|
|
||||||
<br />
|
Modern browsers and Internet Explorer 10+.
|
||||||
|
|
||||||
|
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
|
||||||
|
| --------- | --------- | --------- | --------- |
|
||||||
#### 可收起侧边栏
|
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### table拖拽排序
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
#### 动态table
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
#### 上传裁剪头像
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
#### 错误统计
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
#### 富文本(整合七牛 打水印等个性化功能)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 封装table组件
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 图表
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
#### 导出excel
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## [查看更多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
|
||||||
|
235
README.zh-CN.md
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
<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.4.11-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>
|
||||||
|
<a href="https://gitter.im/vue-element-admin/discuss">
|
||||||
|
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="gitter">
|
||||||
|
</a>
|
||||||
|
<a href="https://panjiachen.gitee.io/vue-element-admin-site/zh/donate">
|
||||||
|
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
简体中文 | [English](./README.md)
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
|
||||||
|
[vue-element-admin](http://panjiachen.github.io/vue-element-admin) 是一个后台集成解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element](https://github.com/ElemeFE/element)。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
|
||||||
|
|
||||||
|
**[v4.0](https://github.com/PanJiaChen/vue-element-admin/tree/v4.0) 已经进入 beta 测试阶段。 它基于 vue-cli@3 进行构建,优化了大量代码(尤其是权限和 mock),并且增加了不少新特性。欢迎使用并提出建议。**
|
||||||
|
|
||||||
|
- [在线访问](http://panjiachen.github.io/vue-element-admin)
|
||||||
|
|
||||||
|
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
|
||||||
|
|
||||||
|
- [Gitter 讨论组](https://gitter.im/vue-element-admin/discuss)
|
||||||
|
|
||||||
|
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
|
||||||
|
|
||||||
|
- [Donate](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
|
||||||
|
|
||||||
|
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
|
||||||
|
|
||||||
|
- [国内访问文档](https://panjiachen.gitee.io/vue-element-admin-site/zh/) 方便没翻墙的用户查看文档
|
||||||
|
|
||||||
|
**本项目的定位是后台集成方案,不适合当基础模板来开发。**
|
||||||
|
|
||||||
|
- 模板建议使用: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
|
||||||
|
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
|
||||||
|
- Typescript版: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (鸣谢: [@Armour](https://github.com/Armour))
|
||||||
|
|
||||||
|
群主 **[圈子](https://jianshiapp.com/circles/1209)** 楼主会经常分享一些技术相关的东西,或者加入[qq 群](https://github.com/PanJiaChen/vue-element-admin/issues/602)或者关注[微博](https://weibo.com/u/3423485724?is_all=1)
|
||||||
|
|
||||||
|
**注意:该项目使用 element-ui@2.3.0+ 版本,所以最低兼容 vue@2.5.0+**
|
||||||
|
|
||||||
|
**从`v3.8.0`开始使用`webpack4`。所以若还想使用`webpack3`开发,请使用该分支[webpack3](https://github.com/PanJiaChen/vue-element-admin/tree/webpack3)**
|
||||||
|
|
||||||
|
**该项目不支持低版本浏览器(如 ie),有需求请自行添加 polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
|
||||||
|
|
||||||
|
## 前序准备
|
||||||
|
|
||||||
|
你需要在本地安装 [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/) 、[axios](https://github.com/axios/axios) 和 [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)
|
||||||
|
- [手摸手,带你用合理的姿势使用 webpack4(上)](https://juejin.im/post/5b56909a518825195f499806)
|
||||||
|
- [手摸手,带你用合理的姿势使用 webpack4(下)](https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc)
|
||||||
|
|
||||||
|
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
|
## Sponsors
|
||||||
|
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen)
|
||||||
|
|
||||||
|
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p>
|
||||||
|
|
||||||
|
## 功能
|
||||||
|
|
||||||
|
```
|
||||||
|
- 登录 / 注销
|
||||||
|
|
||||||
|
- 权限验证
|
||||||
|
- 页面权限
|
||||||
|
- 指令权限
|
||||||
|
- 二步登录
|
||||||
|
|
||||||
|
- 多环境发布
|
||||||
|
- dev sit stage prod
|
||||||
|
|
||||||
|
- 全局功能
|
||||||
|
- 国际化多语言
|
||||||
|
- 多种动态换肤
|
||||||
|
- 动态侧边栏(支持多级路由嵌套)
|
||||||
|
- 动态面包屑
|
||||||
|
- 快捷导航(标签页)
|
||||||
|
- Svg Sprite 图标
|
||||||
|
- 本地mock数据
|
||||||
|
- Screenfull全屏
|
||||||
|
- 自适应收缩侧边栏
|
||||||
|
|
||||||
|
- 编辑器
|
||||||
|
- 富文本
|
||||||
|
- Markdown
|
||||||
|
- JSON 等多格式
|
||||||
|
|
||||||
|
- Excel
|
||||||
|
- 导出excel
|
||||||
|
- 导出zip
|
||||||
|
- 导入excel
|
||||||
|
- 前端可视化excel
|
||||||
|
|
||||||
|
- 表格
|
||||||
|
- 动态表格
|
||||||
|
- 拖拽表格
|
||||||
|
- 树形表格
|
||||||
|
- 内联编辑
|
||||||
|
|
||||||
|
- 错误页面
|
||||||
|
- 401
|
||||||
|
- 404
|
||||||
|
|
||||||
|
- 組件
|
||||||
|
- 头像上传
|
||||||
|
- 返回顶部
|
||||||
|
- 拖拽Dialog
|
||||||
|
- 拖拽Select
|
||||||
|
- 拖拽看板
|
||||||
|
- 列表拖拽
|
||||||
|
- SplitPane
|
||||||
|
- Dropzone
|
||||||
|
- Sticky
|
||||||
|
- CountTo
|
||||||
|
|
||||||
|
- 综合实例
|
||||||
|
- 错误日志
|
||||||
|
- Dashboard
|
||||||
|
- 引导页
|
||||||
|
- ECharts 图表
|
||||||
|
- Clipboard(剪贴复制)
|
||||||
|
- 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
|
||||||
|
|
||||||
|
# --generate a bundle size analytics. default: bundle-report.html
|
||||||
|
npm run build:prod --generate_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/)
|
||||||
|
|
||||||
|
## 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:
|
||||||
|

|
||||||
|
|
||||||
|
[更多捐赠方式](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
|
||||||
|
|
||||||
|
[Paypal Me](https://www.paypal.me/panfree23)
|
||||||
|
|
||||||
|
## Browsers support
|
||||||
|
|
||||||
|
Modern browsers and Internet Explorer 10+.
|
||||||
|
|
||||||
|
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari |
|
||||||
|
| --------- | --------- | --------- | --------- |
|
||||||
|
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
|
||||||
|
|
||||||
|
Copyright (c) 2017-present PanJiaChen
|
@@ -1,41 +1,67 @@
|
|||||||
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')
|
||||||
|
var connect = require('connect')
|
||||||
|
var serveStatic = require('serve-static')
|
||||||
|
|
||||||
var spinner = ora('building for ' + process.env.NODE_ENV + '...')
|
const 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({
|
||||||
colors: true,
|
colors: true,
|
||||||
modules: false,
|
modules: false,
|
||||||
children: false,
|
children: false,
|
||||||
chunks: false,
|
chunks: false,
|
||||||
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({
|
const port = 9526
|
||||||
port: 9528,
|
const host = 'http://localhost:' + port
|
||||||
directory: './dist',
|
const basePath = config.build.assetsPublicPath
|
||||||
file: '/index.html'
|
const app = connect()
|
||||||
});
|
|
||||||
console.log('> Listening at ' + 'http://localhost:9528' + '\n')
|
app.use(
|
||||||
|
basePath,
|
||||||
|
serveStatic('./dist', {
|
||||||
|
index: ['index.html', '/']
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
app.listen(port, function() {
|
||||||
|
console.log(
|
||||||
|
chalk.green(`> Listening at http://localhost:${port}${basePath}`)
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@@ -1,31 +1,44 @@
|
|||||||
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(
|
||||||
chalk.red(mod.currentVersion) + ' should be ' +
|
mod.name +
|
||||||
|
': ' +
|
||||||
|
chalk.red(mod.currentVersion) +
|
||||||
|
' should be ' +
|
||||||
chalk.green(mod.versionRequirement)
|
chalk.green(mod.versionRequirement)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -33,12 +46,18 @@ module.exports = function () {
|
|||||||
|
|
||||||
if (warnings.length) {
|
if (warnings.length) {
|
||||||
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)
|
|
||||||
}
|
|
||||||
});
|
|
BIN
build/logo.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
@@ -1,28 +1,53 @@
|
|||||||
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 MiniCssExtractPlugin = require('mini-css-extract-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 = []
|
||||||
|
|
||||||
|
// Extract CSS when that option is specified
|
||||||
|
// (which is the case during production build)
|
||||||
|
if (options.extract) {
|
||||||
|
loaders.push(MiniCssExtractPlugin.loader)
|
||||||
|
} else {
|
||||||
|
loaders.push('vue-style-loader')
|
||||||
|
}
|
||||||
|
|
||||||
|
loaders.push(cssLoader)
|
||||||
|
|
||||||
|
if (options.usePostCSS) {
|
||||||
|
loaders.push(postcssLoader)
|
||||||
|
}
|
||||||
|
|
||||||
if (loader) {
|
if (loader) {
|
||||||
loaders.push({
|
loaders.push({
|
||||||
loader: loader + '-loader',
|
loader: loader + '-loader',
|
||||||
@@ -32,24 +57,16 @@ exports.cssLoaders = function (options) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract CSS when that option is specified
|
return loaders
|
||||||
// (which is the case during production build)
|
|
||||||
if (options.extract) {
|
|
||||||
return ExtractTextPlugin.extract({
|
|
||||||
use: loaders,
|
|
||||||
fallback: 'vue-style-loader'
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
return ['vue-style-loader'].concat(loaders)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
||||||
return {
|
return {
|
||||||
css: generateLoaders(),
|
css: generateLoaders(),
|
||||||
postcss: generateLoaders(),
|
postcss: generateLoaders(),
|
||||||
less: generateLoaders('less'),
|
less: generateLoaders('less'),
|
||||||
sass: generateLoaders('sass', { indentedSyntax: true }),
|
sass: generateLoaders('sass', {
|
||||||
|
indentedSyntax: true
|
||||||
|
}),
|
||||||
scss: generateLoaders('sass'),
|
scss: generateLoaders('sass'),
|
||||||
stylus: generateLoaders('stylus'),
|
stylus: generateLoaders('stylus'),
|
||||||
styl: generateLoaders('stylus')
|
styl: generateLoaders('stylus')
|
||||||
@@ -58,14 +75,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,5 @@
|
|||||||
var utils = require('./utils')
|
'use strict'
|
||||||
var config = require('../config')
|
|
||||||
var isProduction = process.env.NODE_ENV === 'production'
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
loaders: utils.cssLoaders({
|
//You can set the vue-loader configuration by yourself.
|
||||||
sourceMap: isProduction
|
|
||||||
? config.build.productionSourceMap
|
|
||||||
: config.dev.cssSourceMap,
|
|
||||||
extract: isProduction
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@@ -1,85 +1,107 @@
|
|||||||
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 { VueLoaderPlugin } = require('vue-loader')
|
||||||
|
const vueLoaderConfig = require('./vue-loader.conf')
|
||||||
|
|
||||||
function resolve(dir) {
|
function resolve(dir) {
|
||||||
return path.join(__dirname, '..', dir)
|
return path.join(__dirname, '..', dir)
|
||||||
}
|
}
|
||||||
var src = path.resolve(__dirname, '../src');
|
|
||||||
|
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',
|
'@': 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')
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
externals: {
|
|
||||||
jquery: 'jQuery'
|
|
||||||
},
|
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
// {
|
...(config.dev.useEslint ? [createLintingRule()] : []),
|
||||||
// test: /\.(js|vue)$/,
|
{
|
||||||
// loader: 'eslint-loader',
|
test: /\.vue$/,
|
||||||
// enforce: "pre",
|
|
||||||
// include: [resolve('src'), resolve('test')],
|
|
||||||
// options: {
|
|
||||||
// formatter: require('eslint-friendly-formatter')
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
{ test: /\.vue$/,
|
|
||||||
loader: 'vue-loader',
|
loader: 'vue-loader',
|
||||||
options: vueLoaderConfig
|
options: vueLoaderConfig
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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$/,
|
||||||
|
loader: 'svg-sprite-loader',
|
||||||
|
include: [resolve('src/icons')],
|
||||||
|
options: {
|
||||||
|
symbolId: 'icon-[name]'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
loader: 'url-loader',
|
loader: 'url-loader',
|
||||||
query: {
|
exclude: [resolve('src/icons')],
|
||||||
|
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
|
plugins: [new VueLoaderPlugin()],
|
||||||
// sassResources: path.join(__dirname, '../src/styles/mixin.scss'),
|
node: {
|
||||||
// sassLoader: {
|
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||||
// data: path.join(__dirname, '../src/styles/index.scss')
|
// source contains it (although only uses it if it's native).
|
||||||
// },
|
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,47 +1,98 @@
|
|||||||
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, {
|
||||||
|
mode: 'development',
|
||||||
module: {
|
module: {
|
||||||
rules: utils.styleLoaders({sourceMap: config.dev.cssSourceMap})
|
rules: utils.styleLoaders({
|
||||||
|
sourceMap: config.dev.cssSourceMap,
|
||||||
|
usePostCSS: true
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 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')
|
||||||
}),
|
}),
|
||||||
new webpack.ProvidePlugin({
|
|
||||||
$: 'jquery',
|
|
||||||
'jQuery': 'jquery'
|
|
||||||
}),
|
|
||||||
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
|
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
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,
|
||||||
path:config.dev.staticPath
|
favicon: resolve('favicon.ico'),
|
||||||
|
title: 'vue-element-admin',
|
||||||
|
templateParameters: {
|
||||||
|
BASE_URL: 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,105 +1,98 @@
|
|||||||
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 ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||||
|
const OptimizeCSSAssetsPlugin = 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')
|
||||||
|
|
||||||
|
// For NamedChunksPlugin
|
||||||
|
const seen = new Set()
|
||||||
|
const nameLength = 4
|
||||||
|
|
||||||
|
const webpackConfig = merge(baseWebpackConfig, {
|
||||||
|
mode: 'production',
|
||||||
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:8].js'),
|
||||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
|
chunkFilename: utils.assetsPath('js/[name].[chunkhash:8].js')
|
||||||
},
|
},
|
||||||
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({
|
|
||||||
compress: {
|
|
||||||
warnings: false
|
|
||||||
},
|
|
||||||
sourceMap: true
|
|
||||||
}),
|
|
||||||
// extract css into its own file
|
// extract css into its own file
|
||||||
new ExtractTextPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: utils.assetsPath('css/[name].[contenthash].css')
|
filename: utils.assetsPath('css/[name].[contenthash:8].css'),
|
||||||
|
chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
|
||||||
}),
|
}),
|
||||||
// Compress extracted CSS. We are using this plugin so that possible
|
|
||||||
// duplicated CSS from different components can be deduped.
|
|
||||||
new OptimizeCSSPlugin(),
|
|
||||||
// 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: process.env.NODE_ENV === 'testing'
|
filename: config.build.index,
|
||||||
? 'index.html'
|
|
||||||
: 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',
|
||||||
|
templateParameters: {
|
||||||
|
BASE_URL: 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,
|
// default sort mode uses toposort which cannot handle cyclic deps
|
||||||
minifyJS: true,
|
// in certain cases, and in webpack 4, chunk order in HTML doesn't
|
||||||
minifyCSS: true,
|
// matter anyway
|
||||||
minifyURLs: true
|
|
||||||
},
|
|
||||||
path:config.build.staticPath,
|
|
||||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
|
||||||
chunksSortMode: 'dependency'
|
|
||||||
}),
|
}),
|
||||||
// split vendor js into its own file
|
new ScriptExtHtmlWebpackPlugin({
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
//`runtime` must same as runtimeChunk name. default is `runtime`
|
||||||
name: 'vendor',
|
inline: /runtime\..*\.js$/
|
||||||
minChunks: function (module, count) {
|
}),
|
||||||
// any required modules inside node_modules are extracted to vendor
|
// keep chunk.id stable when chunk has no name
|
||||||
return (
|
new webpack.NamedChunksPlugin(chunk => {
|
||||||
module.resource &&
|
if (chunk.name) {
|
||||||
/\.js$/.test(module.resource) &&
|
return chunk.name
|
||||||
module.resource.indexOf(
|
}
|
||||||
path.join(__dirname, '../node_modules')
|
const modules = Array.from(chunk.modulesIterable)
|
||||||
) === 0
|
if (modules.length > 1) {
|
||||||
)
|
const hash = require('hash-sum')
|
||||||
|
const joinedHash = hash(modules.map(m => m.id).join('_'))
|
||||||
|
let len = nameLength
|
||||||
|
while (seen.has(joinedHash.substr(0, len))) len++
|
||||||
|
seen.add(joinedHash.substr(0, len))
|
||||||
|
return `chunk-${joinedHash.substr(0, len)}`
|
||||||
|
} else {
|
||||||
|
return modules[0].id
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
// split echarts into its own file
|
// keep module.id stable when vender modules does not change
|
||||||
new webpack.optimize.CommonsChunkPlugin({
|
new webpack.HashedModuleIdsPlugin(),
|
||||||
async:'echarts',
|
|
||||||
minChunks(module) {
|
|
||||||
var context = module.context;
|
|
||||||
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
// 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',
|
|
||||||
chunks: ['vendor']
|
|
||||||
}),
|
|
||||||
// copy custom static assets
|
// copy custom static assets
|
||||||
new CopyWebpackPlugin([
|
new CopyWebpackPlugin([
|
||||||
{
|
{
|
||||||
@@ -107,15 +100,88 @@ var webpackConfig = merge(baseWebpackConfig, {
|
|||||||
to: config.build.assetsSubDirectory,
|
to: config.build.assetsSubDirectory,
|
||||||
ignore: ['.*']
|
ignore: ['.*']
|
||||||
}
|
}
|
||||||
]),
|
])
|
||||||
new webpack.ProvidePlugin({
|
],
|
||||||
$: 'jquery',
|
optimization: {
|
||||||
'jQuery': 'jquery'
|
splitChunks: {
|
||||||
})
|
chunks: 'all',
|
||||||
]
|
cacheGroups: {
|
||||||
})
|
libs: {
|
||||||
if (config.build.bundleAnalyzerReport) {
|
name: 'chunk-libs',
|
||||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
test: /[\\/]node_modules[\\/]/,
|
||||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
priority: 10,
|
||||||
|
chunks: 'initial' // 只打包初始时依赖的第三方
|
||||||
|
},
|
||||||
|
elementUI: {
|
||||||
|
name: 'chunk-elementUI', // 单独将 elementUI 拆包
|
||||||
|
priority: 20, // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
|
||||||
|
test: /[\\/]node_modules[\\/]element-ui[\\/]/
|
||||||
|
},
|
||||||
|
commons: {
|
||||||
|
name: 'chunk-commons',
|
||||||
|
test: resolve('src/components'), // 可自定义拓展你的规则
|
||||||
|
minChunks: 3, // 最小公用次数
|
||||||
|
priority: 5,
|
||||||
|
reuseExistingChunk: true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
runtimeChunk: 'single',
|
||||||
|
minimizer: [
|
||||||
|
new UglifyJsPlugin({
|
||||||
|
uglifyOptions: {
|
||||||
|
mangle: {
|
||||||
|
safari10: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sourceMap: config.build.productionSourceMap,
|
||||||
|
cache: true,
|
||||||
|
parallel: true
|
||||||
|
}),
|
||||||
|
// Compress extracted CSS. We are using this plugin so that possible
|
||||||
|
// duplicated CSS from different components can be deduped.
|
||||||
|
new OptimizeCSSAssetsPlugin()
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (config.build.productionGzip) {
|
||||||
|
const CompressionWebpackPlugin = require('compression-webpack-plugin')
|
||||||
|
|
||||||
|
webpackConfig.plugins.push(
|
||||||
|
new CompressionWebpackPlugin({
|
||||||
|
algorithm: 'gzip',
|
||||||
|
test: new RegExp(
|
||||||
|
'\\.(' + config.build.productionGzipExtensions.join('|') + ')$'
|
||||||
|
),
|
||||||
|
threshold: 10240,
|
||||||
|
minRatio: 0.8
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.build.generateAnalyzerReport || config.build.bundleAnalyzerReport) {
|
||||||
|
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
||||||
|
.BundleAnalyzerPlugin
|
||||||
|
|
||||||
|
if (config.build.bundleAnalyzerReport) {
|
||||||
|
webpackConfig.plugins.push(
|
||||||
|
new BundleAnalyzerPlugin({
|
||||||
|
analyzerPort: 8080,
|
||||||
|
generateStatsFile: false
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.build.generateAnalyzerReport) {
|
||||||
|
webpackConfig.plugins.push(
|
||||||
|
new BundleAnalyzerPlugin({
|
||||||
|
analyzerMode: 'static',
|
||||||
|
reportFilename: 'bundle-report.html',
|
||||||
|
openAnalyzer: false
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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,41 +1,88 @@
|
|||||||
|
'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 = {
|
||||||
build: {
|
|
||||||
sitEnv: require('./sit.env'),
|
|
||||||
prodEnv: require('./prod.env'),
|
|
||||||
index: path.resolve(__dirname, '../dist/index.html'),
|
|
||||||
assetsRoot: path.resolve(__dirname, '../dist'),
|
|
||||||
assetsSubDirectory: 'static',
|
|
||||||
assetsPublicPath: './', //请根据自己路径配置更改
|
|
||||||
staticPath:'./static/', //请根据自己路径配置更改
|
|
||||||
productionSourceMap: true,
|
|
||||||
// Gzip off by default as many popular static hosts such as
|
|
||||||
// Surge or Netlify already gzip all static assets for you.
|
|
||||||
// Before setting to `true`, make sure to:
|
|
||||||
// npm install --save-dev compression-webpack-plugin
|
|
||||||
productionGzip: false,
|
|
||||||
productionGzipExtensions: ['js', 'css'],
|
|
||||||
// Run the build command with an extra argument to
|
|
||||||
// View the bundle analyzer report after build finishes:
|
|
||||||
// `npm run build --report`
|
|
||||||
// Set to `true` or `false` to always turn it on or off
|
|
||||||
bundleAnalyzerReport: process.env.npm_config_report
|
|
||||||
},
|
|
||||||
dev: {
|
dev: {
|
||||||
env: require('./dev.env'),
|
// Paths
|
||||||
port: 9527,
|
|
||||||
autoOpenBrowser: true,
|
|
||||||
assetsSubDirectory: 'static',
|
assetsSubDirectory: 'static',
|
||||||
assetsPublicPath: '/',
|
assetsPublicPath: '/',
|
||||||
staticPath:'/static/',
|
|
||||||
proxyTable: {},
|
proxyTable: {},
|
||||||
|
|
||||||
|
// Various Dev Server settings
|
||||||
|
|
||||||
|
// can be overwritten by process.env.HOST
|
||||||
|
// if you want dev by ip, please set host: '0.0.0.0'
|
||||||
|
host: 'localhost',
|
||||||
|
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',
|
||||||
|
|
||||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||||
// with this option, according to the CSS-Loader README
|
// with this option, according to the CSS-Loader README
|
||||||
// (https://github.com/webpack/css-loader#sourcemaps)
|
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||||
// In our experience, they generally work as expected,
|
// In our experience, they generally work as expected,
|
||||||
// just be aware of this issue when enabling this option.
|
// just be aware of this issue when enabling this option.
|
||||||
cssSourceMap: false
|
cssSourceMap: false
|
||||||
|
},
|
||||||
|
|
||||||
|
build: {
|
||||||
|
// Template for index.html
|
||||||
|
index: path.resolve(__dirname, '../dist/index.html'),
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||||
|
assetsSubDirectory: 'static',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You can set by youself according to actual condition
|
||||||
|
* You will need to set this if you plan to deploy your site under a sub path,
|
||||||
|
* for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/,
|
||||||
|
* then assetsPublicPath should be set to "/bar/".
|
||||||
|
* In most cases please use '/' !!!
|
||||||
|
*/
|
||||||
|
assetsPublicPath: '/',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source Maps
|
||||||
|
*/
|
||||||
|
productionSourceMap: false,
|
||||||
|
// https://webpack.js.org/configuration/devtool/#production
|
||||||
|
devtool: 'source-map',
|
||||||
|
|
||||||
|
// Gzip off by default as many popular static hosts such as
|
||||||
|
// Surge or Netlify already gzip all static assets for you.
|
||||||
|
// Before setting to `true`, make sure to:
|
||||||
|
// npm install --save-dev compression-webpack-plugin
|
||||||
|
productionGzip: false,
|
||||||
|
productionGzipExtensions: ['js', 'css'],
|
||||||
|
|
||||||
|
// Run the build command with an extra argument to
|
||||||
|
// View the bundle analyzer report after build finishes:
|
||||||
|
// `npm run build:prod --report`
|
||||||
|
// Set to `true` or `false` to always turn it on or off
|
||||||
|
bundleAnalyzerReport: process.env.npm_config_report || false,
|
||||||
|
|
||||||
|
// `npm run build:prod --generate_report`
|
||||||
|
generateAnalyzerReport: process.env.npm_config_generate_report || 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"'
|
||||||
};
|
}
|
||||||
|
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 117 KiB |
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 |
@@ -5,13 +5,11 @@
|
|||||||
<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 %>jquery.min.js></script>
|
<script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script>
|
||||||
<script src=<%= htmlWebpackPlugin.options.path %>tinymce/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>
|
||||||
|
187
package.json
@@ -1,95 +1,130 @@
|
|||||||
{
|
{
|
||||||
"name": "juicy",
|
"name": "vue-element-admin",
|
||||||
"version": "1.1.1",
|
"version": "3.11.0",
|
||||||
"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": "cross-env BABEL_ENV=development 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",
|
||||||
|
"precommit": "lint-staged",
|
||||||
|
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"src/**/*.{js,vue}": [
|
||||||
|
"eslint --fix",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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.18.0",
|
||||||
"codemirror": "5.26.0",
|
"clipboard": "1.7.1",
|
||||||
"dropzone": "5.1.0",
|
"codemirror": "5.39.2",
|
||||||
"echarts": "3.6.1",
|
"driver.js": "0.8.1",
|
||||||
"element-ui": "1.3.6",
|
"dropzone": "5.2.0",
|
||||||
"file-saver": "1.3.3",
|
"echarts": "4.1.0",
|
||||||
"jquery": "3.1.1",
|
"element-ui": "2.4.11",
|
||||||
"js-cookie": "2.1.4",
|
"file-saver": "1.3.8",
|
||||||
"jsonlint": "1.6.2",
|
"fuse.js": "3.4.2",
|
||||||
|
"js-cookie": "2.2.0",
|
||||||
|
"jsonlint": "1.6.3",
|
||||||
|
"jszip": "3.1.5",
|
||||||
"mockjs": "1.0.1-beta3",
|
"mockjs": "1.0.1-beta3",
|
||||||
"normalize.css": "3.0.2",
|
"normalize.css": "7.0.0",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"screenfull": "3.2.2",
|
"screenfull": "4.0.0",
|
||||||
"showdown": "1.7.1",
|
"showdown": "1.8.6",
|
||||||
"simplemde": "1.11.2",
|
"sortablejs": "1.7.0",
|
||||||
"sortablejs": "1.5.1",
|
"tui-editor": "1.2.7",
|
||||||
"vue": "2.3.3",
|
"vue": "2.5.17",
|
||||||
"vue-count-to": "1.0.5",
|
"vue-count-to": "1.0.13",
|
||||||
"vue-multiselect": "2.0.0-beta.15",
|
"vue-i18n": "7.3.2",
|
||||||
"vue-router": "2.5.3",
|
"vue-router": "3.0.2",
|
||||||
"vuedraggable": "2.13.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": "8.5.0",
|
||||||
"babel-core": "6.25.0",
|
"babel-core": "6.26.3",
|
||||||
"babel-eslint": "7.2.3",
|
"babel-eslint": "8.2.6",
|
||||||
"babel-loader": "7.0.0",
|
"babel-helper-vue-jsx-merge-props": "2.0.3",
|
||||||
|
"babel-loader": "7.1.5",
|
||||||
|
"babel-plugin-dynamic-import-node": "2.0.0",
|
||||||
|
"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.7.0",
|
||||||
|
"babel-preset-env": "1.7.0",
|
||||||
"babel-preset-stage-2": "6.24.1",
|
"babel-preset-stage-2": "6.24.1",
|
||||||
"babel-register": "6.24.1",
|
"chalk": "2.4.1",
|
||||||
"chalk": "1.1.3",
|
"compression-webpack-plugin": "2.0.0",
|
||||||
"connect-history-api-fallback": "1.3.0",
|
"connect": "3.6.6",
|
||||||
"copy-webpack-plugin": "4.0.1",
|
"copy-webpack-plugin": "4.5.2",
|
||||||
"cross-env": "5.0.1",
|
"cross-env": "5.2.0",
|
||||||
"css-loader": "0.28.4",
|
"css-loader": "1.0.0",
|
||||||
"eslint": "3.19.0",
|
"eslint": "5.15.2",
|
||||||
"eslint-friendly-formatter": "3.0.0",
|
"eslint-friendly-formatter": "4.0.1",
|
||||||
"eslint-import-resolver-webpack": "0.8.1",
|
"eslint-loader": "2.1.2",
|
||||||
"eslint-loader": "1.7.1",
|
"eslint-plugin-vue": "5.2.2",
|
||||||
"eslint-plugin-html": "3.0.0",
|
"file-loader": "1.1.11",
|
||||||
"eslint-plugin-import": "2.3.0",
|
"friendly-errors-webpack-plugin": "1.7.0",
|
||||||
"eventsource-polyfill": "0.9.6",
|
"hash-sum": "1.0.2",
|
||||||
"express": "4.15.3",
|
"html-webpack-plugin": "4.0.0-alpha",
|
||||||
"extract-text-webpack-plugin": "2.1.2",
|
"husky": "0.14.3",
|
||||||
"file-loader": "0.11.2",
|
"lint-staged": "7.2.2",
|
||||||
"friendly-errors-webpack-plugin": "1.6.1",
|
"mini-css-extract-plugin": "0.4.1",
|
||||||
"function-bind": "1.1.0",
|
"node-notifier": "5.2.1",
|
||||||
"html-webpack-plugin": "2.28.0",
|
"node-sass": "^4.7.2",
|
||||||
"http-proxy-middleware": "0.17.4",
|
"optimize-css-assets-webpack-plugin": "5.0.0",
|
||||||
"node-sass": "^4.5.0",
|
"ora": "3.0.0",
|
||||||
"opn": "4.0.2",
|
"path-to-regexp": "2.4.0",
|
||||||
"optimize-css-assets-webpack-plugin": "1.3.0",
|
"portfinder": "1.0.13",
|
||||||
"ora": "1.1.0",
|
"postcss-import": "11.1.0",
|
||||||
"pushstate-server": "2.1.0",
|
"postcss-loader": "2.1.6",
|
||||||
"rimraf": "2.6.0",
|
"postcss-url": "7.3.2",
|
||||||
"sass-loader": "6.0.5",
|
"rimraf": "2.6.2",
|
||||||
"script-loader": "0.7.0",
|
"sass-loader": "7.0.3",
|
||||||
"semver": "5.3.0",
|
"script-ext-html-webpack-plugin": "2.0.1",
|
||||||
"style-loader": "0.17.0",
|
"script-loader": "0.7.2",
|
||||||
"url-loader": "0.5.8",
|
"semver": "5.5.0",
|
||||||
"vue-loader": "12.2.1",
|
"serve-static": "1.13.2",
|
||||||
"vue-style-loader": "3.0.1",
|
"shelljs": "0.8.2",
|
||||||
"vue-template-compiler": "2.3.3",
|
"svg-sprite-loader": "3.8.0",
|
||||||
"webpack": "2.6.1",
|
"svgo": "1.0.5",
|
||||||
"webpack-bundle-analyzer": "2.8.2",
|
"uglifyjs-webpack-plugin": "1.2.7",
|
||||||
"webpack-dev-middleware": "1.10.2",
|
"url-loader": "1.0.1",
|
||||||
"webpack-hot-middleware": "2.18.0",
|
"vue-loader": "15.3.0",
|
||||||
"webpack-merge": "4.1.0"
|
"vue-style-loader": "4.1.2",
|
||||||
|
"vue-template-compiler": "2.5.17",
|
||||||
|
"webpack": "4.16.5",
|
||||||
|
"webpack-bundle-analyzer": "2.13.1",
|
||||||
|
"webpack-cli": "3.1.0",
|
||||||
|
"webpack-dev-server": "3.1.14",
|
||||||
|
"webpack-merge": "4.1.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4.0.0",
|
"node": ">= 6.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"
|
||||||
|
@@ -1,15 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<router-view></router-view>
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'APP'
|
name: 'App'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import './styles/index.scss'; // 全局自定义的css样式
|
|
||||||
</style>
|
|
||||||
|
@@ -1,16 +1,41 @@
|
|||||||
import fetch from 'utils/fetch';
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function getList() {
|
export function fetchList(query) {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/article/list',
|
url: '/article/list',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
});
|
params: query
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getArticle() {
|
export function fetchArticle(id) {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/article/detail',
|
url: '/article/detail',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
});
|
params: { id }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchPv(pv) {
|
||||||
|
return request({
|
||||||
|
url: '/article/pv',
|
||||||
|
method: 'get',
|
||||||
|
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,17 +0,0 @@
|
|||||||
import fetch from 'utils/fetch';
|
|
||||||
|
|
||||||
export function fetchList(query) {
|
|
||||||
return fetch({
|
|
||||||
url: '/article_table/list',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchPv(pv) {
|
|
||||||
return fetch({
|
|
||||||
url: '/article_table/pv',
|
|
||||||
method: 'get',
|
|
||||||
params: { pv }
|
|
||||||
});
|
|
||||||
}
|
|
@@ -1,29 +1,29 @@
|
|||||||
import fetch from 'utils/fetch';
|
import request from '@/utils/request'
|
||||||
|
|
||||||
export function loginByEmail(email, password) {
|
export function loginByUsername(username, password) {
|
||||||
const data = {
|
const data = {
|
||||||
email,
|
username,
|
||||||
password
|
password
|
||||||
};
|
}
|
||||||
return fetch({
|
return request({
|
||||||
url: '/login/loginbyemail',
|
url: '/login/login',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/login/logout',
|
url: '/login/logout',
|
||||||
method: 'post'
|
method: 'post'
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getInfo(token) {
|
export function getUserInfo(token) {
|
||||||
return fetch({
|
return request({
|
||||||
url: '/user/info',
|
url: '/user/info',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: { token }
|
params: { token }
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
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,9 +1,9 @@
|
|||||||
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 }
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
38
src/api/role.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getRoutes() {
|
||||||
|
return request({
|
||||||
|
url: '/routes',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoles() {
|
||||||
|
return request({
|
||||||
|
url: '/roles',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteRole(id) {
|
||||||
|
return request({
|
||||||
|
url: `/roles/${id}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addRole(data) {
|
||||||
|
return request({
|
||||||
|
url: '/roles',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateRole(key, data) {
|
||||||
|
return request({
|
||||||
|
url: `/roles/${key}`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
9
src/api/transaction.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function fetchList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/transaction/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
@@ -1,199 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
(function (root, factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module.
|
|
||||||
define(['exports', 'echarts'], factory);
|
|
||||||
} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
|
|
||||||
// CommonJS
|
|
||||||
factory(exports, require('echarts'));
|
|
||||||
} else {
|
|
||||||
// Browser globals
|
|
||||||
factory({}, root.echarts);
|
|
||||||
}
|
|
||||||
}(this, function (exports, echarts) {
|
|
||||||
var log = function (msg) {
|
|
||||||
if (typeof console !== 'undefined') {
|
|
||||||
console && console.error && console.error(msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (!echarts) {
|
|
||||||
log('ECharts is not Loaded');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var colorPalette = [
|
|
||||||
'#2ec7c9','#b6a2de','#5ab1ef','#ffb980','#d87a80',
|
|
||||||
'#8d98b3','#e5cf0d','#97b552','#95706d','#dc69aa',
|
|
||||||
'#07a2a4','#9a7fd1','#588dd5','#f5994e','#c05050',
|
|
||||||
'#59678c','#c9ab00','#7eb00a','#6f5553','#c14089'
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
var theme = {
|
|
||||||
color: colorPalette,
|
|
||||||
|
|
||||||
title: {
|
|
||||||
textStyle: {
|
|
||||||
fontWeight: 'normal',
|
|
||||||
color: '#008acd'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
visualMap: {
|
|
||||||
itemWidth: 15,
|
|
||||||
color: ['#5ab1ef','#e0ffff']
|
|
||||||
},
|
|
||||||
|
|
||||||
toolbox: {
|
|
||||||
iconStyle: {
|
|
||||||
normal: {
|
|
||||||
borderColor: colorPalette[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
tooltip: {
|
|
||||||
backgroundColor: 'rgba(50,50,50,0.5)',
|
|
||||||
axisPointer : {
|
|
||||||
type : 'line',
|
|
||||||
lineStyle : {
|
|
||||||
color: '#008acd'
|
|
||||||
},
|
|
||||||
crossStyle: {
|
|
||||||
color: '#008acd'
|
|
||||||
},
|
|
||||||
shadowStyle : {
|
|
||||||
color: 'rgba(200,200,200,0.2)'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
dataZoom: {
|
|
||||||
dataBackgroundColor: '#efefff',
|
|
||||||
fillerColor: 'rgba(182,162,222,0.2)',
|
|
||||||
handleColor: '#008acd'
|
|
||||||
},
|
|
||||||
|
|
||||||
grid: {
|
|
||||||
borderColor: '#eee'
|
|
||||||
},
|
|
||||||
|
|
||||||
categoryAxis: {
|
|
||||||
axisLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: '#008acd'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: ['#eee']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
valueAxis: {
|
|
||||||
axisLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: '#008acd'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
splitArea : {
|
|
||||||
show : true,
|
|
||||||
areaStyle : {
|
|
||||||
color: ['rgba(250,250,250,0.1)','rgba(200,200,200,0.1)']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: ['#eee']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
timeline : {
|
|
||||||
lineStyle : {
|
|
||||||
color : '#008acd'
|
|
||||||
},
|
|
||||||
controlStyle : {
|
|
||||||
normal : { color : '#008acd'},
|
|
||||||
emphasis : { color : '#008acd'}
|
|
||||||
},
|
|
||||||
symbol : 'emptyCircle',
|
|
||||||
symbolSize : 3
|
|
||||||
},
|
|
||||||
|
|
||||||
line: {
|
|
||||||
smooth : true,
|
|
||||||
symbol: 'emptyCircle',
|
|
||||||
symbolSize: 3
|
|
||||||
},
|
|
||||||
|
|
||||||
candlestick: {
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
color: '#d87a80',
|
|
||||||
color0: '#2ec7c9',
|
|
||||||
lineStyle: {
|
|
||||||
color: '#d87a80',
|
|
||||||
color0: '#2ec7c9'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
scatter: {
|
|
||||||
symbol: 'circle',
|
|
||||||
symbolSize: 4
|
|
||||||
},
|
|
||||||
|
|
||||||
map: {
|
|
||||||
label: {
|
|
||||||
normal: {
|
|
||||||
textStyle: {
|
|
||||||
color: '#d87a80'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
borderColor: '#eee',
|
|
||||||
areaColor: '#ddd'
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
areaColor: '#fe994e'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
graph: {
|
|
||||||
color: colorPalette
|
|
||||||
},
|
|
||||||
|
|
||||||
gauge : {
|
|
||||||
axisLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: [[0.2, '#2ec7c9'],[0.8, '#5ab1ef'],[1, '#d87a80']],
|
|
||||||
width: 10
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisTick: {
|
|
||||||
splitNumber: 10,
|
|
||||||
length :15,
|
|
||||||
lineStyle: {
|
|
||||||
color: 'auto'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
length :22,
|
|
||||||
lineStyle: {
|
|
||||||
color: 'auto'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
pointer : {
|
|
||||||
width : 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
echarts.registerTheme('macarons', theme);
|
|
||||||
}));
|
|
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition :name="transitionName">
|
<transition :name="transitionName">
|
||||||
<div class="back-to-top" @click="backToTop" v-show="visible" :style="customStyle">
|
<div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
|
||||||
<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>
|
||||||
<path d="M12.036 15.59c0 .55-.453.995-.997.995H5.032c-.55 0-.997-.445-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29c.39-.39 1.026-.385 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" fill-rule="evenodd"></path>
|
<path d="M12.036 15.59c0 .55-.453.995-.997.995H5.032c-.55 0-.997-.445-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29c.39-.39 1.026-.385 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" fill-rule="evenodd" />
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,7 +25,8 @@
|
|||||||
},
|
},
|
||||||
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 @@
|
|||||||
'line-height': '45px',
|
'line-height': '45px',
|
||||||
background: '#e7eaf1'
|
background: '#e7eaf1'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
transitionName: {
|
transitionName: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -43,53 +45,57 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visible: false,
|
visible: false,
|
||||||
interval: null
|
interval: null,
|
||||||
|
isMoving: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
window.addEventListener('scroll', this.handleScroll);
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
window.removeEventListener('scroll', this.handleScroll);
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
if (this.interval) {
|
if (this.interval) {
|
||||||
clearInterval(this.interval);
|
clearInterval(this.interval)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleScroll() {
|
handleScroll() {
|
||||||
this.visible = window.pageYOffset > this.visibilityHeight;
|
this.visible = window.pageYOffset > this.visibilityHeight
|
||||||
},
|
},
|
||||||
backToTop() {
|
backToTop() {
|
||||||
const start = window.pageYOffset;
|
if (this.isMoving) return
|
||||||
let i = 0;
|
const start = window.pageYOffset
|
||||||
|
let i = 0
|
||||||
|
this.isMoving = true
|
||||||
this.interval = setInterval(() => {
|
this.interval = setInterval(() => {
|
||||||
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500));
|
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
|
||||||
if (next <= this.backPosition) {
|
if (next <= this.backPosition) {
|
||||||
window.scrollTo(0, this.backPosition);
|
window.scrollTo(0, this.backPosition)
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval)
|
||||||
|
this.isMoving = false
|
||||||
} else {
|
} else {
|
||||||
window.scrollTo(0, next);
|
window.scrollTo(0, next)
|
||||||
}
|
}
|
||||||
i++;
|
i++
|
||||||
}, 16.7)
|
}, 16.7)
|
||||||
},
|
},
|
||||||
easeInOutQuad(t, b, c, d) {
|
easeInOutQuad(t, b, c, d) {
|
||||||
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
|
if ((t /= d / 2) < 1) return c / 2 * t * t + b
|
||||||
return -c / 2 * (--t * (t - 2) - 1) + b;
|
return -c / 2 * (--t * (t - 2) - 1) + b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</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 +109,7 @@
|
|||||||
opacity: 0
|
opacity: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-to-top .Icon {
|
.back-to-ceiling .Icon {
|
||||||
fill: #9aaabf;
|
fill: #9aaabf;
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
73
src/components/Breadcrumb/index.vue
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||||
|
<transition-group name="breadcrumb">
|
||||||
|
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
|
||||||
|
<span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">
|
||||||
|
{{ generateTitle(item.meta.title) }}
|
||||||
|
</span>
|
||||||
|
<a v-else @click.prevent="handleLink(item)">{{ generateTitle(item.meta.title) }}</a>
|
||||||
|
</el-breadcrumb-item>
|
||||||
|
</transition-group>
|
||||||
|
</el-breadcrumb>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { generateTitle } from '@/utils/i18n'
|
||||||
|
import pathToRegexp from 'path-to-regexp'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
levelList: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
$route() {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getBreadcrumb()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
generateTitle,
|
||||||
|
getBreadcrumb() {
|
||||||
|
let matched = this.$route.matched.filter(item => item.name)
|
||||||
|
|
||||||
|
const first = matched[0]
|
||||||
|
if (first && first.name.trim().toLocaleLowerCase() !== 'Dashboard'.toLocaleLowerCase()) {
|
||||||
|
matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
|
||||||
|
},
|
||||||
|
pathCompile(path) {
|
||||||
|
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
||||||
|
const { params } = this.$route
|
||||||
|
var toPath = pathToRegexp.compile(path)
|
||||||
|
return toPath(params)
|
||||||
|
},
|
||||||
|
handleLink(item) {
|
||||||
|
const { redirect, path } = item
|
||||||
|
if (redirect) {
|
||||||
|
this.$router.push(redirect)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$router.push(this.pathCompile(path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.app-breadcrumb.el-breadcrumb {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 50px;
|
||||||
|
margin-left: 8px;
|
||||||
|
.no-redirect {
|
||||||
|
color: #97a8be;
|
||||||
|
cursor: text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,11 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
|
<div :id="id" :class="className" :style="{height:height,width:width}" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<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,
|
||||||
@@ -27,39 +29,44 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
chart: null
|
chart: null
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initChart();
|
this.initChart()
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (!this.chart) {
|
if (!this.chart) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.chart.dispose();
|
this.chart.dispose()
|
||||||
this.chart = null;
|
this.chart = null
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initChart() {
|
initChart() {
|
||||||
this.chart = echarts.init(document.getElementById(this.id));
|
this.chart = echarts.init(document.getElementById(this.id))
|
||||||
|
|
||||||
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: {
|
grid: {
|
||||||
trigger: 'axis'
|
left: '5%',
|
||||||
|
right: '5%'
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: [{
|
||||||
show: false,
|
show: false,
|
||||||
data: xAxisData
|
data: xAxisData
|
||||||
},
|
}, {
|
||||||
|
show: false,
|
||||||
|
data: xAxisData
|
||||||
|
}],
|
||||||
visualMap: {
|
visualMap: {
|
||||||
show: false,
|
show: false,
|
||||||
min: 0,
|
min: 0,
|
||||||
@@ -84,28 +91,64 @@
|
|||||||
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) {
|
||||||
return idx * 20;
|
return idx * 20
|
||||||
},
|
},
|
||||||
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>
|
|
@@ -1,11 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
|
<div :id="id" :class="className" :style="{height:height,width:width}" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<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,
|
||||||
@@ -27,32 +29,33 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
chart: null
|
chart: null
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initChart();
|
this.initChart()
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (!this.chart) {
|
if (!this.chart) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.chart.dispose();
|
this.chart.dispose()
|
||||||
this.chart = null;
|
this.chart = null
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initChart() {
|
initChart() {
|
||||||
this.chart = echarts.init(document.getElementById(this.id));
|
this.chart = echarts.init(document.getElementById(this.id))
|
||||||
|
|
||||||
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 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
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 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: '3%',
|
top: 100,
|
||||||
right: '4%',
|
left: '2%',
|
||||||
bottom: '3%',
|
right: '2%',
|
||||||
|
bottom: '2%',
|
||||||
containLabel: true
|
containLabel: true
|
||||||
},
|
},
|
||||||
xAxis: [{
|
xAxis: [{
|
||||||
@@ -92,7 +97,7 @@
|
|||||||
}],
|
}],
|
||||||
yAxis: [{
|
yAxis: [{
|
||||||
type: 'value',
|
type: 'value',
|
||||||
name: '单位(%)',
|
name: '(%)',
|
||||||
axisTick: {
|
axisTick: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
@@ -114,7 +119,7 @@
|
|||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
series: [{
|
series: [{
|
||||||
name: '移动',
|
name: 'CMCC',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
smooth: true,
|
smooth: true,
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
@@ -148,7 +153,7 @@
|
|||||||
},
|
},
|
||||||
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 @@
|
|||||||
},
|
},
|
||||||
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',
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="className" :id="id" :style="{height:height,width:width}"></div>
|
<div :id="id" :class="className" :style="{height:height,width:width}" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<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,
|
||||||
@@ -27,34 +29,34 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
chart: null
|
chart: null
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.initChart();
|
this.initChart()
|
||||||
this.chart = null;
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (!this.chart) {
|
if (!this.chart) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.chart.dispose();
|
this.chart.dispose()
|
||||||
this.chart = null;
|
this.chart = null
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initChart() {
|
initChart() {
|
||||||
this.chart = echarts.init(document.getElementById(this.id));
|
this.chart = echarts.init(document.getElementById(this.id))
|
||||||
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'
|
||||||
@@ -73,20 +75,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
|
left: '5%',
|
||||||
|
right: '5%',
|
||||||
borderWidth: 0,
|
borderWidth: 0,
|
||||||
top: 110,
|
top: 150,
|
||||||
bottom: 95,
|
bottom: 95,
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: '#fff'
|
color: '#fff'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
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: [{
|
||||||
@@ -150,7 +154,6 @@
|
|||||||
color: '#fff' },
|
color: '#fff' },
|
||||||
borderColor: '#90979c'
|
borderColor: '#90979c'
|
||||||
|
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
type: 'inside',
|
type: 'inside',
|
||||||
show: true,
|
show: true,
|
||||||
@@ -159,9 +162,9 @@
|
|||||||
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: {
|
||||||
@@ -174,7 +177,7 @@
|
|||||||
},
|
},
|
||||||
position: 'insideTop',
|
position: 'insideTop',
|
||||||
formatter(p) {
|
formatter(p) {
|
||||||
return p.value > 0 ? p.value : '';
|
return p.value > 0 ? p.value : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,9 +199,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
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)',
|
||||||
@@ -207,7 +210,7 @@
|
|||||||
show: true,
|
show: true,
|
||||||
position: 'top',
|
position: 'top',
|
||||||
formatter(p) {
|
formatter(p) {
|
||||||
return p.value > 0 ? p.value : '';
|
return p.value > 0 ? p.value : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,9 +230,9 @@
|
|||||||
220
|
220
|
||||||
]
|
]
|
||||||
}, {
|
}, {
|
||||||
name: '平均',
|
name: 'average',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
stack: '总量',
|
stack: 'total',
|
||||||
symbolSize: 10,
|
symbolSize: 10,
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
@@ -240,7 +243,7 @@
|
|||||||
show: true,
|
show: true,
|
||||||
position: 'top',
|
position: 'top',
|
||||||
formatter(p) {
|
formatter(p) {
|
||||||
return p.value > 0 ? p.value : '';
|
return p.value > 0 ? p.value : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
src/components/Charts/mixins/resize.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { debounce } from '@/utils'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sidebarElm: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.__resizeHandler = debounce(() => {
|
||||||
|
if (this.chart) {
|
||||||
|
this.chart.resize()
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
window.addEventListener('resize', this.__resizeHandler)
|
||||||
|
|
||||||
|
this.sidebarElm = document.getElementsByClassName('sidebar-container')[0]
|
||||||
|
this.sidebarElm && this.sidebarElm.addEventListener('transitionend', this.sidebarResizeHandler)
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener('resize', this.__resizeHandler)
|
||||||
|
|
||||||
|
this.sidebarElm && this.sidebarElm.removeEventListener('transitionend', this.sidebarResizeHandler)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
sidebarResizeHandler(e) {
|
||||||
|
if (e.propertyName === 'width') {
|
||||||
|
this.__resizeHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
157
src/components/DndList/index.vue
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dndList">
|
||||||
|
<div :style="{width:width1}" class="dndList-list">
|
||||||
|
<h3>{{ list1Title }}</h3>
|
||||||
|
<draggable :list="list1" :options="{group:'article'}" class="dragArea">
|
||||||
|
<div v-for="element in list1" :key="element.id" class="list-complete-item">
|
||||||
|
<div class="list-complete-item-handle">{{ element.id }}[{{ element.author }}] {{ element.title }}</div>
|
||||||
|
<div style="position:absolute;right:0px;">
|
||||||
|
<span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)">
|
||||||
|
<i style="color:#ff4949" class="el-icon-delete" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
<div :style="{width:width2}" class="dndList-list">
|
||||||
|
<h3>{{ list2Title }}</h3>
|
||||||
|
<draggable :list="list2" :options="{group:'article'}" class="dragArea">
|
||||||
|
<div v-for="element in list2" :key="element.id" class="list-complete-item">
|
||||||
|
<div class="list-complete-item-handle2" @click="pushEle(element)">{{ element.id }} [{{ element.author }}] {{ element.title }}</div>
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DndList',
|
||||||
|
components: { draggable },
|
||||||
|
props: {
|
||||||
|
list1: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
list2: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
list1Title: {
|
||||||
|
type: String,
|
||||||
|
default: 'list1'
|
||||||
|
},
|
||||||
|
list2Title: {
|
||||||
|
type: String,
|
||||||
|
default: 'list2'
|
||||||
|
},
|
||||||
|
width1: {
|
||||||
|
type: String,
|
||||||
|
default: '48%'
|
||||||
|
},
|
||||||
|
width2: {
|
||||||
|
type: String,
|
||||||
|
default: '48%'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
isNotInList1(v) {
|
||||||
|
return this.list1.every(k => v.id !== k.id)
|
||||||
|
},
|
||||||
|
isNotInList2(v) {
|
||||||
|
return this.list2.every(k => v.id !== k.id)
|
||||||
|
},
|
||||||
|
deleteEle(ele) {
|
||||||
|
for (const item of this.list1) {
|
||||||
|
if (item.id === ele.id) {
|
||||||
|
const index = this.list1.indexOf(item)
|
||||||
|
this.list1.splice(index, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.isNotInList2(ele)) {
|
||||||
|
this.list2.unshift(ele)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pushEle(ele) {
|
||||||
|
for (const item of this.list2) {
|
||||||
|
if (item.id === ele.id) {
|
||||||
|
const index = this.list2.indexOf(item)
|
||||||
|
this.list2.splice(index, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.isNotInList1(ele)) {
|
||||||
|
this.list1.push(ele)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||||
|
.dndList {
|
||||||
|
background: #fff;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
.dndList-list {
|
||||||
|
float: left;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
&:first-of-type {
|
||||||
|
margin-right: 2%;
|
||||||
|
}
|
||||||
|
.dragArea {
|
||||||
|
margin-top: 15px;
|
||||||
|
min-height: 50px;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item {
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 5px 12px;
|
||||||
|
margin-top: 4px;
|
||||||
|
border: 1px solid #bfcbd9;
|
||||||
|
transition: all 1s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item-handle {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item-handle2 {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item.sortable-chosen {
|
||||||
|
background: #4AB7BD;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-item.sortable-ghost {
|
||||||
|
background: #30B08F;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-complete-enter,
|
||||||
|
.list-complete-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
61
src/components/DragSelect/index.vue
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<el-select ref="dragSelect" v-model="selectVal" v-bind="$attrs" class="drag-select" multiple v-on="$listeners">
|
||||||
|
<slot />
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Sortable from 'sortablejs'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DragSelect',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selectVal: {
|
||||||
|
get() {
|
||||||
|
return [...this.value]
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('input', [...val])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.setSort()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setSort() {
|
||||||
|
const el = this.$refs.dragSelect.$el.querySelectorAll('.el-select__tags > span')[0]
|
||||||
|
this.sortable = Sortable.create(el, {
|
||||||
|
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
|
||||||
|
setData: function(dataTransfer) {
|
||||||
|
dataTransfer.setData('Text', '')
|
||||||
|
// to avoid Firefox bug
|
||||||
|
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
|
||||||
|
},
|
||||||
|
onEnd: evt => {
|
||||||
|
const targetRow = this.value.splice(evt.oldIndex, 1)[0]
|
||||||
|
this.value.splice(evt.newIndex, 0, targetRow)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.drag-select >>> .sortable-ghost{
|
||||||
|
opacity: .8;
|
||||||
|
color: #fff!important;
|
||||||
|
background: #42b983!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-select >>> .el-tag{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,151 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :ref="id" :action="url" class="dropzone" :id="id">
|
<div :id="id" :ref="id" :action="url" class="dropzone">
|
||||||
<input type="file" name="file">
|
<input type="file" name="file">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<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
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dropzone: '',
|
|
||||||
initOnce: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
const element = document.getElementById(this.id);
|
|
||||||
const vm = this;
|
|
||||||
this.dropzone = new Dropzone(element, {
|
|
||||||
clickable: this.clickable,
|
|
||||||
thumbnailWidth: this.thumbnailWidth,
|
|
||||||
thumbnailHeight: this.thumbnailHeight,
|
|
||||||
maxFiles: this.maxFiles,
|
|
||||||
maxFilesize: this.maxFilesize,
|
|
||||||
dictRemoveFile: 'Remove',
|
|
||||||
addRemoveLinks: this.showRemoveLink,
|
|
||||||
acceptedFiles: this.acceptedFiles,
|
|
||||||
autoProcessQueue: this.autoProcessQueue,
|
|
||||||
dictDefaultMessage: '<i style="margin-top: 3em;display: inline-block" class="material-icons">' + this.defaultMsg + '</i><br>Drop files here to upload',
|
|
||||||
dictMaxFilesExceeded: '只能一个图',
|
|
||||||
previewTemplate: '<div class="dz-preview dz-file-preview"> <div class="dz-image" style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" ><img style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" data-dz-thumbnail /></div> <div class="dz-details"><div class="dz-size"><span data-dz-size></span></div> <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div> <div class="dz-error-message"><span data-dz-errormessage></span></div> <div class="dz-success-mark"> <i class="material-icons">done</i> </div> <div class="dz-error-mark"><i class="material-icons">error</i></div></div>',
|
|
||||||
init() {
|
|
||||||
const val = vm.defaultImg;
|
|
||||||
if (!val) return;
|
|
||||||
if (Array.isArray(val)) {
|
|
||||||
if (val.length === 0) return;
|
|
||||||
val.map((v, i) => {
|
|
||||||
const mockFile = { name: 'name' + i, size: 12345, url: v };
|
|
||||||
this.options.addedfile.call(this, mockFile);
|
|
||||||
this.options.thumbnail.call(this, mockFile, v);
|
|
||||||
mockFile.previewElement.classList.add('dz-success');
|
|
||||||
mockFile.previewElement.classList.add('dz-complete');
|
|
||||||
vm.initOnce = false;
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const mockFile = { name: 'name', size: 12345, url: val };
|
|
||||||
this.options.addedfile.call(this, mockFile);
|
|
||||||
this.options.thumbnail.call(this, mockFile, val);
|
|
||||||
mockFile.previewElement.classList.add('dz-success');
|
|
||||||
mockFile.previewElement.classList.add('dz-complete');
|
|
||||||
vm.initOnce = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
accept: (file, done) => {
|
|
||||||
/* 七牛*/
|
|
||||||
// const token = this.$store.getters.token;
|
|
||||||
// getToken(token).then(response => {
|
|
||||||
// file.token = response.data.qiniu_token;
|
|
||||||
// file.key = response.data.qiniu_key;
|
|
||||||
// file.url = response.data.qiniu_url;
|
|
||||||
// done();
|
|
||||||
// })
|
|
||||||
done();
|
|
||||||
},
|
|
||||||
sending: (file, xhr, formData) => {
|
|
||||||
/* 七牛*/
|
|
||||||
console.log(file, xhr, formData)
|
|
||||||
// formData.append('token', file.token);
|
|
||||||
// formData.append('key', file.key);
|
|
||||||
vm.initOnce = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.couldPaste) {
|
|
||||||
document.addEventListener('paste', this.pasteImg)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dropzone.on('success', file => {
|
|
||||||
vm.$emit('dropzone-success', file, vm.dropzone.element)
|
|
||||||
});
|
|
||||||
this.dropzone.on('addedfile', file => {
|
|
||||||
vm.$emit('dropzone-fileAdded', file)
|
|
||||||
});
|
|
||||||
this.dropzone.on('removedfile', file => {
|
|
||||||
vm.$emit('dropzone-removedFile', file)
|
|
||||||
});
|
|
||||||
this.dropzone.on('error', (file, error, xhr) => {
|
|
||||||
vm.$emit('dropzone-error', file, error, xhr)
|
|
||||||
});
|
|
||||||
this.dropzone.on('successmultiple', (file, error, xhr) => {
|
|
||||||
vm.$emit('dropzone-successmultiple', file, error, xhr)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
removeAllFiles() {
|
|
||||||
this.dropzone.removeAllFiles(true)
|
|
||||||
},
|
|
||||||
processQueue() {
|
|
||||||
this.dropzone.processQueue()
|
|
||||||
},
|
|
||||||
pasteImg(event) {
|
|
||||||
const items = (event.clipboardData || event.originalEvent.clipboardData).items;
|
|
||||||
if (items[0].kind === 'file') {
|
|
||||||
this.dropzone.addFile(items[0].getAsFile())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
initImages(val) {
|
|
||||||
if (!val) return;
|
|
||||||
if (Array.isArray(val)) {
|
|
||||||
val.map((v, i) => {
|
|
||||||
const mockFile = { name: 'name' + i, size: 12345, url: v };
|
|
||||||
this.dropzone.options.addedfile.call(this.dropzone, mockFile);
|
|
||||||
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, v);
|
|
||||||
mockFile.previewElement.classList.add('dz-success');
|
|
||||||
mockFile.previewElement.classList.add('dz-complete');
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const mockFile = { name: 'name', size: 12345, url: val };
|
|
||||||
this.dropzone.options.addedfile.call(this.dropzone, mockFile);
|
|
||||||
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, val);
|
|
||||||
mockFile.previewElement.classList.add('dz-success');
|
|
||||||
mockFile.previewElement.classList.add('dz-complete');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
document.removeEventListener('paste', this.pasteImg);
|
|
||||||
this.dropzone.destroy();
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
defaultImg(val) {
|
|
||||||
if (val.length === 0) {
|
|
||||||
this.initOnce = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.initOnce) return;
|
|
||||||
this.initImages(val);
|
|
||||||
this.initOnce = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
id: {
|
id: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -164,7 +30,8 @@
|
|||||||
default: '上传图片'
|
default: '上传图片'
|
||||||
},
|
},
|
||||||
acceptedFiles: {
|
acceptedFiles: {
|
||||||
type: String
|
type: String,
|
||||||
|
default: ''
|
||||||
},
|
},
|
||||||
thumbnailHeight: {
|
thumbnailHeight: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -195,11 +62,145 @@
|
|||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
defaultImg: {
|
defaultImg: {
|
||||||
default: false
|
default: '',
|
||||||
|
type: [String, Array]
|
||||||
},
|
},
|
||||||
couldPaste: {
|
couldPaste: {
|
||||||
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dropzone: '',
|
||||||
|
initOnce: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
defaultImg(val) {
|
||||||
|
if (val.length === 0) {
|
||||||
|
this.initOnce = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.initOnce) return
|
||||||
|
this.initImages(val)
|
||||||
|
this.initOnce = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const element = document.getElementById(this.id)
|
||||||
|
const vm = this
|
||||||
|
this.dropzone = new Dropzone(element, {
|
||||||
|
clickable: this.clickable,
|
||||||
|
thumbnailWidth: this.thumbnailWidth,
|
||||||
|
thumbnailHeight: this.thumbnailHeight,
|
||||||
|
maxFiles: this.maxFiles,
|
||||||
|
maxFilesize: this.maxFilesize,
|
||||||
|
dictRemoveFile: 'Remove',
|
||||||
|
addRemoveLinks: this.showRemoveLink,
|
||||||
|
acceptedFiles: this.acceptedFiles,
|
||||||
|
autoProcessQueue: this.autoProcessQueue,
|
||||||
|
dictDefaultMessage: '<i style="margin-top: 3em;display: inline-block" class="material-icons">' + this.defaultMsg + '</i><br>Drop files here to upload',
|
||||||
|
dictMaxFilesExceeded: '只能一个图',
|
||||||
|
previewTemplate: '<div class="dz-preview dz-file-preview"> <div class="dz-image" style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" ><img style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" data-dz-thumbnail /></div> <div class="dz-details"><div class="dz-size"><span data-dz-size></span></div> <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div> <div class="dz-error-message"><span data-dz-errormessage></span></div> <div class="dz-success-mark"> <i class="material-icons">done</i> </div> <div class="dz-error-mark"><i class="material-icons">error</i></div></div>',
|
||||||
|
init() {
|
||||||
|
const val = vm.defaultImg
|
||||||
|
if (!val) return
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
if (val.length === 0) return
|
||||||
|
val.map((v, i) => {
|
||||||
|
const mockFile = { name: 'name' + i, size: 12345, url: v }
|
||||||
|
this.options.addedfile.call(this, mockFile)
|
||||||
|
this.options.thumbnail.call(this, mockFile, v)
|
||||||
|
mockFile.previewElement.classList.add('dz-success')
|
||||||
|
mockFile.previewElement.classList.add('dz-complete')
|
||||||
|
vm.initOnce = false
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const mockFile = { name: 'name', size: 12345, url: val }
|
||||||
|
this.options.addedfile.call(this, mockFile)
|
||||||
|
this.options.thumbnail.call(this, mockFile, val)
|
||||||
|
mockFile.previewElement.classList.add('dz-success')
|
||||||
|
mockFile.previewElement.classList.add('dz-complete')
|
||||||
|
vm.initOnce = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
accept: (file, done) => {
|
||||||
|
/* 七牛*/
|
||||||
|
// const token = this.$store.getters.token;
|
||||||
|
// getToken(token).then(response => {
|
||||||
|
// file.token = response.data.qiniu_token;
|
||||||
|
// file.key = response.data.qiniu_key;
|
||||||
|
// file.url = response.data.qiniu_url;
|
||||||
|
// done();
|
||||||
|
// })
|
||||||
|
done()
|
||||||
|
},
|
||||||
|
sending: (file, xhr, formData) => {
|
||||||
|
// formData.append('token', file.token);
|
||||||
|
// formData.append('key', file.key);
|
||||||
|
vm.initOnce = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.couldPaste) {
|
||||||
|
document.addEventListener('paste', this.pasteImg)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dropzone.on('success', file => {
|
||||||
|
vm.$emit('dropzone-success', file, vm.dropzone.element)
|
||||||
|
})
|
||||||
|
this.dropzone.on('addedfile', file => {
|
||||||
|
vm.$emit('dropzone-fileAdded', file)
|
||||||
|
})
|
||||||
|
this.dropzone.on('removedfile', file => {
|
||||||
|
vm.$emit('dropzone-removedFile', file)
|
||||||
|
})
|
||||||
|
this.dropzone.on('error', (file, error, xhr) => {
|
||||||
|
vm.$emit('dropzone-error', file, error, xhr)
|
||||||
|
})
|
||||||
|
this.dropzone.on('successmultiple', (file, error, xhr) => {
|
||||||
|
vm.$emit('dropzone-successmultiple', file, error, xhr)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
document.removeEventListener('paste', this.pasteImg)
|
||||||
|
this.dropzone.destroy()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
removeAllFiles() {
|
||||||
|
this.dropzone.removeAllFiles(true)
|
||||||
|
},
|
||||||
|
processQueue() {
|
||||||
|
this.dropzone.processQueue()
|
||||||
|
},
|
||||||
|
pasteImg(event) {
|
||||||
|
const items = (event.clipboardData || event.originalEvent.clipboardData).items
|
||||||
|
if (items[0].kind === 'file') {
|
||||||
|
this.dropzone.addFile(items[0].getAsFile())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initImages(val) {
|
||||||
|
if (!val) return
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
val.map((v, i) => {
|
||||||
|
const mockFile = { name: 'name' + i, size: 12345, url: v }
|
||||||
|
this.dropzone.options.addedfile.call(this.dropzone, mockFile)
|
||||||
|
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, v)
|
||||||
|
mockFile.previewElement.classList.add('dz-success')
|
||||||
|
mockFile.previewElement.classList.add('dz-complete')
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const mockFile = { name: 'name', size: 12345, url: val }
|
||||||
|
this.dropzone.options.addedfile.call(this.dropzone, mockFile)
|
||||||
|
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, val)
|
||||||
|
mockFile.previewElement.classList.add('dz-success')
|
||||||
|
mockFile.previewElement.classList.add('dz-complete')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -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>
|
|
63
src/components/ErrorLog/index.vue
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="errorLogs.length>0">
|
||||||
|
<el-badge :is-dot="true" style="line-height: 25px;margin-top: -5px;" @click.native="dialogTableVisible=true">
|
||||||
|
<el-button style="padding: 8px 10px;" size="small" type="danger">
|
||||||
|
<svg-icon icon-class="bug" />
|
||||||
|
</el-button>
|
||||||
|
</el-badge>
|
||||||
|
|
||||||
|
<el-dialog :visible.sync="dialogTableVisible" title="Error Log" 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>
|
||||||
|
.message-title {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
54
src/components/GithubCorner/index.vue
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<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:#40c9c6; color:#fff;"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" />
|
||||||
|
<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"
|
||||||
|
fill="currentColor"
|
||||||
|
style="transform-origin: 130px 106px;"
|
||||||
|
class="octo-arm"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
|
||||||
|
fill="currentColor"
|
||||||
|
class="octo-body"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</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,20 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="padding: 0 15px;" @click="toggleClick">
|
||||||
<svg t="1492500959545" @click="toggleClick" class="wscn-icon hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
|
<svg
|
||||||
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">
|
:class="{'is-active':isActive}"
|
||||||
<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"
|
class="hamburger"
|
||||||
p-id="1692"></path>
|
viewBox="0 0 1024 1024"
|
||||||
<path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 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 856.07443 998.200404 881.527125 966.8023 881.527125z"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
p-id="1693"></path>
|
width="64"
|
||||||
<path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
|
height="64"
|
||||||
p-id="1694"></path>
|
>
|
||||||
|
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'hamburger',
|
name: 'Hamburger',
|
||||||
props: {
|
props: {
|
||||||
isActive: {
|
isActive: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -31,16 +32,12 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.hamburger {
|
.hamburger {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
vertical-align: middle;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
transform: rotate(0deg);
|
|
||||||
transition: .38s;
|
|
||||||
transform-origin: 50% 50%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hamburger.is-active {
|
.hamburger.is-active {
|
||||||
transform: rotate(90deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
188
src/components/HeaderSearch/index.vue
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="{'show':show}" class="header-search">
|
||||||
|
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
||||||
|
<el-select
|
||||||
|
ref="headerSearchSelect"
|
||||||
|
v-model="search"
|
||||||
|
:remote-method="querySearch"
|
||||||
|
filterable
|
||||||
|
default-first-option
|
||||||
|
remote
|
||||||
|
placeholder="Search"
|
||||||
|
class="header-search-select"
|
||||||
|
@change="change"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Fuse from 'fuse.js'
|
||||||
|
import path from 'path'
|
||||||
|
import i18n from '@/lang'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HeaderSearch',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
search: '',
|
||||||
|
options: [],
|
||||||
|
searchPool: [],
|
||||||
|
show: false,
|
||||||
|
fuse: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
routes() {
|
||||||
|
return this.$store.getters.permission_routes
|
||||||
|
},
|
||||||
|
lang() {
|
||||||
|
return this.$store.getters.language
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
lang() {
|
||||||
|
this.searchPool = this.generateRoutes(this.routes)
|
||||||
|
},
|
||||||
|
routes() {
|
||||||
|
this.searchPool = this.generateRoutes(this.routes)
|
||||||
|
},
|
||||||
|
searchPool(list) {
|
||||||
|
this.initFuse(list)
|
||||||
|
},
|
||||||
|
show(value) {
|
||||||
|
if (value) {
|
||||||
|
document.body.addEventListener('click', this.close)
|
||||||
|
} else {
|
||||||
|
document.body.removeEventListener('click', this.close)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.searchPool = this.generateRoutes(this.routes)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.show = !this.show
|
||||||
|
if (this.show) {
|
||||||
|
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
|
||||||
|
this.options = []
|
||||||
|
this.show = false
|
||||||
|
},
|
||||||
|
change(val) {
|
||||||
|
this.$router.push(val.path)
|
||||||
|
this.search = ''
|
||||||
|
this.options = []
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.show = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initFuse(list) {
|
||||||
|
this.fuse = new Fuse(list, {
|
||||||
|
shouldSort: true,
|
||||||
|
threshold: 0.4,
|
||||||
|
location: 0,
|
||||||
|
distance: 100,
|
||||||
|
maxPatternLength: 32,
|
||||||
|
minMatchCharLength: 1,
|
||||||
|
keys: [{
|
||||||
|
name: 'title',
|
||||||
|
weight: 0.7
|
||||||
|
}, {
|
||||||
|
name: 'path',
|
||||||
|
weight: 0.3
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// Filter out the routes that can be displayed in the sidebar
|
||||||
|
// And generate the internationalized title
|
||||||
|
generateRoutes(routes, basePath = '/', prefixTitle = []) {
|
||||||
|
let res = []
|
||||||
|
|
||||||
|
for (const router of routes) {
|
||||||
|
// skip hidden router
|
||||||
|
if (router.hidden) { continue }
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
path: path.resolve(basePath, router.path),
|
||||||
|
title: [...prefixTitle]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (router.meta && router.meta.title) {
|
||||||
|
// generate internationalized title
|
||||||
|
const i18ntitle = i18n.t(`route.${router.meta.title}`)
|
||||||
|
|
||||||
|
data.title = [...data.title, i18ntitle]
|
||||||
|
|
||||||
|
if (router.redirect !== 'noredirect') {
|
||||||
|
// only push the routes with title
|
||||||
|
// special case: need to exclude parent router without redirect
|
||||||
|
res.push(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive child routes
|
||||||
|
if (router.children) {
|
||||||
|
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
|
||||||
|
if (tempRoutes.length >= 1) {
|
||||||
|
res = [...res, ...tempRoutes]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
querySearch(query) {
|
||||||
|
if (query !== '') {
|
||||||
|
this.options = this.fuse.search(query)
|
||||||
|
} else {
|
||||||
|
this.options = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.header-search {
|
||||||
|
font-size: 0 !important;
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-search-select {
|
||||||
|
font-size: 18px;
|
||||||
|
transition: width 0.2s;
|
||||||
|
width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
/deep/ .el-input__inner {
|
||||||
|
border-radius: 0;
|
||||||
|
border: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border-bottom: 1px solid #d9d9d9;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
.header-search-select {
|
||||||
|
width: 210px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</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});
|
|
||||||
};
|
|
19
src/components/ImageCropper/utils/data2blob.js
Executable file
@@ -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
|
||||||
|
})
|
||||||
|
}
|
39
src/components/ImageCropper/utils/effectRipple.js
Executable file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
232
src/components/ImageCropper/utils/language.js
Executable file
@@ -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: '画像が小さすぎます。最小サイズ: '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/components/ImageCropper/utils/mimes.js
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
export default {
|
||||||
|
'jpg': 'image/jpeg',
|
||||||
|
'png': 'image/png',
|
||||||
|
'gif': 'image/gif',
|
||||||
|
'svg': 'image/svg+xml',
|
||||||
|
'psd': 'image/photoshop'
|
||||||
|
}
|
72
src/components/JsonEditor/index.vue
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<div class="json-editor">
|
||||||
|
<textarea ref="textarea" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CodeMirror from 'codemirror'
|
||||||
|
import 'codemirror/addon/lint/lint.css'
|
||||||
|
import 'codemirror/lib/codemirror.css'
|
||||||
|
import 'codemirror/theme/rubyblue.css'
|
||||||
|
require('script-loader!jsonlint')
|
||||||
|
import 'codemirror/mode/javascript/javascript'
|
||||||
|
import 'codemirror/addon/lint/lint'
|
||||||
|
import 'codemirror/addon/lint/json-lint'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'JsonEditor',
|
||||||
|
/* eslint-disable vue/require-prop-types */
|
||||||
|
props: ['value'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
jsonEditor: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(value) {
|
||||||
|
const editor_value = this.jsonEditor.getValue()
|
||||||
|
if (value !== editor_value) {
|
||||||
|
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.jsonEditor = CodeMirror.fromTextArea(this.$refs.textarea, {
|
||||||
|
lineNumbers: true,
|
||||||
|
mode: 'application/json',
|
||||||
|
gutters: ['CodeMirror-lint-markers'],
|
||||||
|
theme: 'rubyblue',
|
||||||
|
lint: true
|
||||||
|
})
|
||||||
|
|
||||||
|
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
|
||||||
|
this.jsonEditor.on('change', cm => {
|
||||||
|
this.$emit('changed', cm.getValue())
|
||||||
|
this.$emit('input', cm.getValue())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getValue() {
|
||||||
|
return this.jsonEditor.getValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.json-editor{
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.json-editor >>> .CodeMirror {
|
||||||
|
height: auto;
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.json-editor >>> .CodeMirror-scroll{
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.json-editor >>> .cm-s-rubyblue span.cm-string {
|
||||||
|
color: #F08047;
|
||||||
|
}
|
||||||
|
</style>
|
90
src/components/Kanban/index.vue
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<div class="board-column">
|
||||||
|
<div class="board-column-header">
|
||||||
|
{{ headerText }}
|
||||||
|
</div>
|
||||||
|
<draggable
|
||||||
|
:list="list"
|
||||||
|
:options="options"
|
||||||
|
class="board-column-content"
|
||||||
|
>
|
||||||
|
<div v-for="element in list" :key="element.id" class="board-item">
|
||||||
|
{{ element.name }} {{ element.id }}
|
||||||
|
</div>
|
||||||
|
</draggable>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DragKanbanDemo',
|
||||||
|
components: {
|
||||||
|
draggable
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
headerText: {
|
||||||
|
type: String,
|
||||||
|
default: 'Header'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.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>
|
||||||
|
|
38
src/components/LangSelect/index.vue
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<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 :disabled="language==='zh'" command="zh">
|
||||||
|
中文
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item :disabled="language==='en'" command="en">
|
||||||
|
English
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item :disabled="language==='es'" command="es">
|
||||||
|
Español
|
||||||
|
</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>
|
@@ -1,144 +1,197 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="material-input__component" :class="computedClasses">
|
<div :class="computedClasses" class="material-input__component">
|
||||||
<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 v-if="icon" :class="['el-icon-' + icon]" class="el-input__icon material-input__icon" />
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
<input
|
||||||
<input v-if="type === 'url'" type="url" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
v-if="type === 'email'"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
|
v-model="currentValue"
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
:name="name"
|
||||||
<input v-if="type === 'number'" type="number" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
:placeholder="fillPlaceHolder"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :minlength="minlength" :maxlength="maxlength"
|
:readonly="readonly"
|
||||||
:required="required" @focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
:disabled="disabled"
|
||||||
<input v-if="type === 'password'" type="password" class="material-input" :name="name" :id="id" :placeholder="placeholder"
|
:autoComplete="autoComplete"
|
||||||
v-model="valueCopy" :readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :max="max" :min="min" :required="required"
|
:required="required"
|
||||||
@focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
type="email"
|
||||||
<input v-if="type === 'tel'" type="tel" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
class="material-input"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :required="required" @focus="handleFocus(true)"
|
@focus="handleMdFocus"
|
||||||
@blur="handleFocus(false)" @input="handleModelInput">
|
@blur="handleMdBlur"
|
||||||
<input v-if="type === 'text'" type="text" class="material-input" :name="name" :id="id" :placeholder="placeholder" v-model="valueCopy"
|
@input="handleModelInput"
|
||||||
:readonly="readonly" :disabled="disabled" :autocomplete="autocomplete" :minlength="minlength" :maxlength="maxlength" :required="required"
|
>
|
||||||
@focus="handleFocus(true)" @blur="handleFocus(false)" @input="handleModelInput">
|
<input
|
||||||
|
v-if="type === 'url'"
|
||||||
<span class="material-input-bar"></span>
|
v-model="currentValue"
|
||||||
|
:name="name"
|
||||||
|
:placeholder="fillPlaceHolder"
|
||||||
|
:readonly="readonly"
|
||||||
|
:disabled="disabled"
|
||||||
|
:autoComplete="autoComplete"
|
||||||
|
:required="required"
|
||||||
|
type="url"
|
||||||
|
class="material-input"
|
||||||
|
@focus="handleMdFocus"
|
||||||
|
@blur="handleMdBlur"
|
||||||
|
@input="handleModelInput"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-if="type === 'number'"
|
||||||
|
v-model="currentValue"
|
||||||
|
:name="name"
|
||||||
|
:placeholder="fillPlaceHolder"
|
||||||
|
:step="step"
|
||||||
|
:readonly="readonly"
|
||||||
|
:disabled="disabled"
|
||||||
|
:autoComplete="autoComplete"
|
||||||
|
:max="max"
|
||||||
|
:min="min"
|
||||||
|
:minlength="minlength"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
:required="required"
|
||||||
|
type="number"
|
||||||
|
class="material-input"
|
||||||
|
@focus="handleMdFocus"
|
||||||
|
@blur="handleMdBlur"
|
||||||
|
@input="handleModelInput"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-if="type === 'password'"
|
||||||
|
v-model="currentValue"
|
||||||
|
:name="name"
|
||||||
|
:placeholder="fillPlaceHolder"
|
||||||
|
:readonly="readonly"
|
||||||
|
:disabled="disabled"
|
||||||
|
:autoComplete="autoComplete"
|
||||||
|
:max="max"
|
||||||
|
:min="min"
|
||||||
|
:required="required"
|
||||||
|
type="password"
|
||||||
|
class="material-input"
|
||||||
|
@focus="handleMdFocus"
|
||||||
|
@blur="handleMdBlur"
|
||||||
|
@input="handleModelInput"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-if="type === 'tel'"
|
||||||
|
v-model="currentValue"
|
||||||
|
:name="name"
|
||||||
|
:placeholder="fillPlaceHolder"
|
||||||
|
:readonly="readonly"
|
||||||
|
:disabled="disabled"
|
||||||
|
:autoComplete="autoComplete"
|
||||||
|
:required="required"
|
||||||
|
type="tel"
|
||||||
|
class="material-input"
|
||||||
|
@focus="handleMdFocus"
|
||||||
|
@blur="handleMdBlur"
|
||||||
|
@input="handleModelInput"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-if="type === 'text'"
|
||||||
|
v-model="currentValue"
|
||||||
|
:name="name"
|
||||||
|
:placeholder="fillPlaceHolder"
|
||||||
|
:readonly="readonly"
|
||||||
|
:disabled="disabled"
|
||||||
|
:autoComplete="autoComplete"
|
||||||
|
:minlength="minlength"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
:required="required"
|
||||||
|
type="text"
|
||||||
|
class="material-input"
|
||||||
|
@focus="handleMdFocus"
|
||||||
|
@blur="handleMdBlur"
|
||||||
|
@input="handleModelInput"
|
||||||
|
>
|
||||||
|
<span class="material-input-bar" />
|
||||||
<label class="material-label">
|
<label class="material-label">
|
||||||
<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: 'MdInput',
|
||||||
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: {
|
/* eslint-disable */
|
||||||
type: String,
|
icon: String,
|
||||||
default: null
|
name: String,
|
||||||
},
|
|
||||||
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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentValue: this.value,
|
||||||
|
focus: false,
|
||||||
|
fillPlaceHolder: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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 +203,20 @@
|
|||||||
$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 +229,46 @@
|
|||||||
|
|
||||||
// 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 +277,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.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 +319,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 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 +352,9 @@
|
|||||||
.material-input-bar {
|
.material-input-bar {
|
||||||
&:before,
|
&:before,
|
||||||
&:after {
|
&:after {
|
||||||
background: $color-red;
|
background: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.material-errors {
|
|
||||||
color: $color-red;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
31
src/components/MarkdownEditor/defaultOptions.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// doc: https://nhnent.github.io/tui.editor/api/latest/ToastUIEditor.html#ToastUIEditor
|
||||||
|
export default {
|
||||||
|
minHeight: '200px',
|
||||||
|
previewStyle: 'vertical',
|
||||||
|
useCommandShortcut: true,
|
||||||
|
useDefaultHTMLSanitizer: true,
|
||||||
|
usageStatistics: false,
|
||||||
|
hideModeSwitch: false,
|
||||||
|
toolbarItems: [
|
||||||
|
'heading',
|
||||||
|
'bold',
|
||||||
|
'italic',
|
||||||
|
'strike',
|
||||||
|
'divider',
|
||||||
|
'hr',
|
||||||
|
'quote',
|
||||||
|
'divider',
|
||||||
|
'ul',
|
||||||
|
'ol',
|
||||||
|
'task',
|
||||||
|
'indent',
|
||||||
|
'outdent',
|
||||||
|
'divider',
|
||||||
|
'table',
|
||||||
|
'image',
|
||||||
|
'link',
|
||||||
|
'divider',
|
||||||
|
'code',
|
||||||
|
'codeblock'
|
||||||
|
]
|
||||||
|
}
|
118
src/components/MarkdownEditor/index.vue
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div :id="id" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// deps for editor
|
||||||
|
import 'codemirror/lib/codemirror.css' // codemirror
|
||||||
|
import 'tui-editor/dist/tui-editor.css' // editor ui
|
||||||
|
import 'tui-editor/dist/tui-editor-contents.css' // editor content
|
||||||
|
|
||||||
|
import Editor from 'tui-editor'
|
||||||
|
import defaultOptions from './defaultOptions'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MarddownEditor',
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default() {
|
||||||
|
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return defaultOptions
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'markdown'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: '300px'
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'en_US' // https://github.com/nhnent/tui.editor/tree/master/src/js/langs
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
editorOptions() {
|
||||||
|
const options = Object.assign({}, defaultOptions, this.options)
|
||||||
|
options.initialEditType = this.mode
|
||||||
|
options.height = this.height
|
||||||
|
options.language = this.language
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(newValue, preValue) {
|
||||||
|
if (newValue !== preValue && newValue !== this.editor.getValue()) {
|
||||||
|
this.editor.setValue(newValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
language(val) {
|
||||||
|
this.destroyEditor()
|
||||||
|
this.initEditor()
|
||||||
|
},
|
||||||
|
height(newValue) {
|
||||||
|
this.editor.height(newValue)
|
||||||
|
},
|
||||||
|
mode(newValue) {
|
||||||
|
this.editor.changeMode(newValue)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initEditor()
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.destroyEditor()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initEditor() {
|
||||||
|
this.editor = new Editor({
|
||||||
|
el: document.getElementById(this.id),
|
||||||
|
...this.editorOptions
|
||||||
|
})
|
||||||
|
if (this.value) {
|
||||||
|
this.editor.setValue(this.value)
|
||||||
|
}
|
||||||
|
this.editor.on('change', () => {
|
||||||
|
this.$emit('input', this.editor.getValue())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
destroyEditor() {
|
||||||
|
if (!this.editor) return
|
||||||
|
this.editor.off('change')
|
||||||
|
this.editor.remove()
|
||||||
|
},
|
||||||
|
setValue(value) {
|
||||||
|
this.editor.setValue(value)
|
||||||
|
},
|
||||||
|
getValue() {
|
||||||
|
return this.editor.getValue()
|
||||||
|
},
|
||||||
|
setHtml(value) {
|
||||||
|
this.editor.setHtml(value)
|
||||||
|
},
|
||||||
|
getHtml() {
|
||||||
|
return this.editor.getHtml()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@@ -1,114 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class='simplemde-container' :style="{height:height+'px',zIndex:zIndex}">
|
|
||||||
<textarea :id='id'>
|
|
||||||
</textarea>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import 'simplemde/dist/simplemde.min.css';
|
|
||||||
import SimpleMDE from 'simplemde';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Sticky',
|
|
||||||
props: {
|
|
||||||
value: String,
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: 'markdown-editor'
|
|
||||||
},
|
|
||||||
autofocus: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: Number,
|
|
||||||
default: 150
|
|
||||||
},
|
|
||||||
zIndex: {
|
|
||||||
type: Number,
|
|
||||||
default: 10
|
|
||||||
},
|
|
||||||
toolbar: {
|
|
||||||
type: Array
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
simplemde: null,
|
|
||||||
hasChange: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
value(val) {
|
|
||||||
if (val === this.simplemde.value() && !this.hasChange) return;
|
|
||||||
this.simplemde.value(val);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.simplemde = new SimpleMDE({
|
|
||||||
element: document.getElementById(this.id),
|
|
||||||
autofocus: this.autofocus,
|
|
||||||
toolbar: this.toolbar,
|
|
||||||
spellChecker: false,
|
|
||||||
insertTexts: {
|
|
||||||
link: ['[', ']( )']
|
|
||||||
},
|
|
||||||
// hideIcons: ['guide', 'heading', 'quote', 'image', 'preview', 'side-by-side', 'fullscreen'],
|
|
||||||
placeholder: this.placeholder
|
|
||||||
});
|
|
||||||
if (this.value) {
|
|
||||||
this.simplemde.value(this.value);
|
|
||||||
}
|
|
||||||
this.simplemde.codemirror.on('change', () => {
|
|
||||||
if (this.hasChange) {
|
|
||||||
this.hasChange = true
|
|
||||||
}
|
|
||||||
this.$emit('input', this.simplemde.value());
|
|
||||||
});
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.simplemde = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.simplemde-container .CodeMirror {
|
|
||||||
/*height: 150px;*/
|
|
||||||
min-height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simplemde-container .CodeMirror-scroll {
|
|
||||||
min-height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simplemde-container .CodeMirror-code {
|
|
||||||
padding-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simplemde-container .editor-statusbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simplemde-container .CodeMirror .CodeMirror-code .cm-link {
|
|
||||||
color: #1482F0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simplemde-container .CodeMirror .CodeMirror-code .cm-string.cm-url {
|
|
||||||
color: #2d3b4d;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.simplemde-container .CodeMirror .CodeMirror-code .cm-formatting-link-string.cm-url {
|
|
||||||
padding: 0 2px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #E61E1E;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
101
src/components/Pagination/index.vue
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="{'hidden':hidden}" class="pagination-container">
|
||||||
|
<el-pagination
|
||||||
|
:background="background"
|
||||||
|
:current-page.sync="currentPage"
|
||||||
|
:page-size.sync="pageSize"
|
||||||
|
:layout="layout"
|
||||||
|
:page-sizes="pageSizes"
|
||||||
|
:total="total"
|
||||||
|
v-bind="$attrs"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { scrollTo } from '@/utils/scrollTo'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Pagination',
|
||||||
|
props: {
|
||||||
|
total: {
|
||||||
|
required: true,
|
||||||
|
type: Number
|
||||||
|
},
|
||||||
|
page: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
type: Number,
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
|
pageSizes: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [10, 20, 30, 50]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
layout: {
|
||||||
|
type: String,
|
||||||
|
default: 'total, sizes, prev, pager, next, jumper'
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
autoScroll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
hidden: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
currentPage: {
|
||||||
|
get() {
|
||||||
|
return this.page
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('update:page', val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pageSize: {
|
||||||
|
get() {
|
||||||
|
return this.limit
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit('update:limit', val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleSizeChange(val) {
|
||||||
|
this.$emit('pagination', { page: this.currentPage, limit: val })
|
||||||
|
if (this.autoScroll) {
|
||||||
|
scrollTo(0, 800)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleCurrentChange(val) {
|
||||||
|
this.$emit('pagination', { page: val, limit: this.pageSize })
|
||||||
|
if (this.autoScroll) {
|
||||||
|
scrollTo(0, 800)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pagination-container {
|
||||||
|
background: #fff;
|
||||||
|
padding: 32px 16px;
|
||||||
|
}
|
||||||
|
.pagination-container.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pan-item" :style="{zIndex:zIndex,height:height,width:width}">
|
<div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
|
||||||
<div class="pan-info">
|
<div class="pan-info">
|
||||||
<div class="pan-info-roles-container">
|
<div class="pan-info-roles-container">
|
||||||
<slot></slot>
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<img class="pan-thumb" :src="image">
|
<img :src="image" class="pan-thumb">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
},
|
},
|
||||||
zIndex: {
|
zIndex: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 100
|
default: 1
|
||||||
},
|
},
|
||||||
width: {
|
width: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
default: '150px'
|
default: '150px'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@@ -1,53 +1,51 @@
|
|||||||
<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-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
|
||||||
<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"
|
</div>
|
||||||
p-id="4110" />
|
|
||||||
</svg>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import screenfull from 'screenfull';
|
import screenfull from 'screenfull'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'hamburger',
|
name: 'Screenfull',
|
||||||
props: {
|
|
||||||
width: {
|
|
||||||
type: Number,
|
|
||||||
default: 22
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: Number,
|
|
||||||
default: 22
|
|
||||||
},
|
|
||||||
fill: {
|
|
||||||
type: String,
|
|
||||||
default: '#48576a'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isFullscreen: false
|
isFullscreen: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
click() {
|
click() {
|
||||||
if (!screenfull.enabled) {
|
if (!screenfull.enabled) {
|
||||||
this.$message({
|
this.$message({
|
||||||
message: 'you browser can not work',
|
message: 'you browser can not work',
|
||||||
type: 'warning'
|
type: 'warning'
|
||||||
});
|
})
|
||||||
return false;
|
return false
|
||||||
|
}
|
||||||
|
screenfull.toggle()
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
if (screenfull.enabled) {
|
||||||
|
screenfull.on('change', () => {
|
||||||
|
this.isFullscreen = screenfull.isFullscreen
|
||||||
|
})
|
||||||
}
|
}
|
||||||
screenfull.toggle();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</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>
|
||||||
|
100
src/components/Share/dropdownMenu.vue
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="{active:isActive}" class="share-dropdown-menu">
|
||||||
|
<div class="share-dropdown-menu-wrapper">
|
||||||
|
<span class="share-dropdown-menu-title" @click.self="clickTitle">{{ title }}</span>
|
||||||
|
<div v-for="(item,index) of items" :key="index" class="share-dropdown-menu-item">
|
||||||
|
<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,
|
||||||
|
default: function() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: 'vue'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isActive: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickTitle() {
|
||||||
|
this.isActive = !this.isActive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style rel="stylesheet/scss" lang="scss" >
|
||||||
|
$n: 8; //和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>
|
56
src/components/SizeSelect/index.vue
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<el-dropdown trigger="click" @command="handleSetSize">
|
||||||
|
<div>
|
||||||
|
<svg-icon class-name="size-icon" icon-class="size" />
|
||||||
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
|
||||||
|
{{ item.label }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
sizeOptions: [
|
||||||
|
{ label: 'Default', value: 'default' },
|
||||||
|
{ label: 'Medium', value: 'medium' },
|
||||||
|
{ label: 'Small', value: 'small' },
|
||||||
|
{ label: 'Mini', value: 'mini' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
size() {
|
||||||
|
return this.$store.getters.size
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleSetSize(size) {
|
||||||
|
this.$ELEMENT.size = size
|
||||||
|
this.$store.dispatch('setSize', size)
|
||||||
|
this.refreshView()
|
||||||
|
this.$message({
|
||||||
|
message: 'Switch Size Success',
|
||||||
|
type: 'success'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
refreshView() {
|
||||||
|
// In order to make the cached page re-rendered
|
||||||
|
this.$store.dispatch('delAllCachedViews', this.$route)
|
||||||
|
|
||||||
|
const { fullPath } = this.$route
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$router.replace({
|
||||||
|
path: '/redirect' + fullPath
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
@@ -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>
|
|
@@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{height:height+'px',zIndex:zIndex}">
|
<div :style="{height:height+'px',zIndex:zIndex}">
|
||||||
<div :class="className" :style="{top:stickyTop+'px',zIndex:zIndex,position:position,width:width,height:height+'px'}">
|
<div
|
||||||
|
:class="className"
|
||||||
|
:style="{top:(isSticky ? stickyTop +'px' : ''),zIndex:zIndex,position:position,width:width,height:height+'px'}"
|
||||||
|
>
|
||||||
<slot>
|
<slot>
|
||||||
<div>sticky</div>
|
<div>sticky</div>
|
||||||
</slot>
|
</slot>
|
||||||
@@ -21,54 +24,68 @@
|
|||||||
default: 1
|
default: 1
|
||||||
},
|
},
|
||||||
className: {
|
className: {
|
||||||
type: String
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
active: false,
|
active: false,
|
||||||
position: '',
|
position: '',
|
||||||
currentTop: '',
|
|
||||||
width: undefined,
|
width: undefined,
|
||||||
height: undefined,
|
height: undefined,
|
||||||
child: null,
|
isSticky: false
|
||||||
stickyHeight: 0
|
}
|
||||||
|
},
|
||||||
};
|
mounted() {
|
||||||
|
this.height = this.$el.getBoundingClientRect().height
|
||||||
|
window.addEventListener('scroll', this.handleScroll)
|
||||||
|
window.addEventListener('resize', this.handleReize)
|
||||||
|
},
|
||||||
|
activated() {
|
||||||
|
this.handleScroll()
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
window.removeEventListener('scroll', this.handleScroll)
|
||||||
|
window.removeEventListener('resize', this.handleReize)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
sticky() {
|
sticky() {
|
||||||
if (this.active) {
|
if (this.active) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.position = 'fixed';
|
this.position = 'fixed'
|
||||||
this.active = true;
|
this.active = true
|
||||||
this.width = this.width + 'px';
|
this.width = this.width + 'px'
|
||||||
|
this.isSticky = true
|
||||||
},
|
},
|
||||||
reset() {
|
handleReset() {
|
||||||
if (!this.active) {
|
if (!this.active) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.position = '';
|
this.reset()
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
this.position = ''
|
||||||
this.width = 'auto'
|
this.width = 'auto'
|
||||||
this.active = false
|
this.active = false
|
||||||
|
this.isSticky = false
|
||||||
},
|
},
|
||||||
handleScroll() {
|
handleScroll() {
|
||||||
this.width = this.$el.getBoundingClientRect().width;
|
const width = this.$el.getBoundingClientRect().width
|
||||||
const offsetTop = this.$el.getBoundingClientRect().top;
|
this.width = width || 'auto'
|
||||||
if (offsetTop <= this.stickyTop) {
|
const offsetTop = this.$el.getBoundingClientRect().top
|
||||||
this.sticky();
|
if (offsetTop < this.stickyTop) {
|
||||||
|
this.sticky()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.reset()
|
this.handleReset()
|
||||||
}
|
|
||||||
},
|
},
|
||||||
mounted() {
|
handleReize() {
|
||||||
this.height = this.$el.getBoundingClientRect().height;
|
if (this.isSticky) {
|
||||||
window.addEventListener('scroll', this.handleScroll);
|
this.width = this.$el.getBoundingClientRect().width + 'px'
|
||||||
},
|
}
|
||||||
destroyed() {
|
}
|
||||||
window.removeEventListener('scroll', this.handleScroll);
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
43
src/components/SvgIcon/index.vue
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<svg :class="svgClass" aria-hidden="true" v-on="$listeners">
|
||||||
|
<use :xlink:href="iconName" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'SvgIcon',
|
||||||
|
props: {
|
||||||
|
iconClass: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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>
|
113
src/components/TextHoverEffect/Mallki.vue
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<template>
|
||||||
|
<a :class="className" class="link--mallki" href="#">
|
||||||
|
{{ text }}
|
||||||
|
<span :data-letters="text" />
|
||||||
|
<span :data-letters="text" />
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
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>
|
157
src/components/ThemePicker/index.vue
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<template>
|
||||||
|
<el-color-picker
|
||||||
|
v-model="theme"
|
||||||
|
:predefine="['#409EFF', '#11a983', '#13c2c2', '#6959CD', '#f5222d', '#eb2f96', '#DB7093', '#e6a23c', '#8B8989', '#212121']"
|
||||||
|
class="theme-picker"
|
||||||
|
popper-class="theme-picker-dropdown"
|
||||||
|
/>
|
||||||
|
</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) {
|
||||||
|
const oldVal = this.theme
|
||||||
|
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) {
|
||||||
|
const colorOverrides = [] // only capture color overides
|
||||||
|
oldCluster.forEach((color, index) => {
|
||||||
|
const value = newCluster[index]
|
||||||
|
const color_plain = color.replace(/([()])/g, '\\$1')
|
||||||
|
const repl = new RegExp(`(^|})([^{]+{[^{}]+)${color_plain}\\b([^}]*)(?=})`, 'gi')
|
||||||
|
const nestRepl = new RegExp(color_plain, 'ig') // for greed matching before the 'color'
|
||||||
|
let v
|
||||||
|
while ((v = repl.exec(style))) {
|
||||||
|
colorOverrides.push(v[2].replace(nestRepl, value) + value + v[3] + '}') // '}' not captured in the regexp repl to reserve it as locator-boundary
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return colorOverrides.join('')
|
||||||
|
},
|
||||||
|
|
||||||
|
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 {
|
||||||
|
margin-top: 12px;
|
||||||
|
height: 26px!important;
|
||||||
|
width: 26px!important;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-picker-dropdown .el-color-dropdown__link-btn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
105
src/components/Tinymce/components/editorImage.vue
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<div class="upload-container">
|
||||||
|
<el-button :style="{background:color,borderColor:color}" icon="el-icon-upload" size="mini" type="primary" @click=" dialogVisible=true">
|
||||||
|
上传图片
|
||||||
|
</el-button>
|
||||||
|
<el-dialog :visible.sync="dialogVisible">
|
||||||
|
<el-upload
|
||||||
|
:multiple="true"
|
||||||
|
:file-list="fileList"
|
||||||
|
:show-file-list="true"
|
||||||
|
:on-remove="handleRemove"
|
||||||
|
:on-success="handleSuccess"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
class="editor-slide-upload"
|
||||||
|
action="https://httpbin.org/post"
|
||||||
|
list-type="picture-card"
|
||||||
|
>
|
||||||
|
<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
|
||||||
|
}
|
||||||
|
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>
|
||||||
|
.editor-slide-upload {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
/deep/ .el-upload--picture-card {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,17 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class='tinymce-container editor-container'>
|
<div :class="{fullscreen:fullscreen}" class="tinymce-container editor-container">
|
||||||
<textarea class='tinymce-textarea' :id="id"></textarea>
|
<textarea :id="tinymceId" class="tinymce-textarea" />
|
||||||
|
<div class="editor-custom-btn-container">
|
||||||
|
<editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// import { getToken, upload } from 'api/qiniu'; // 七牛
|
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'
|
default: function() {
|
||||||
|
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -21,17 +30,12 @@
|
|||||||
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: ''
|
type: String,
|
||||||
|
default: 'file edit insert view format table'
|
||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@@ -39,46 +43,84 @@
|
|||||||
default: 360
|
default: 360
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
data() {
|
||||||
value(val) {
|
return {
|
||||||
if (!this.hasChange && this.hasInit) {
|
hasChange: false,
|
||||||
this.$nextTick(() => tinymce.get(this.id).setContent(val))
|
hasInit: false,
|
||||||
|
tinymceId: this.id,
|
||||||
|
fullscreen: false,
|
||||||
|
languageTypeList: {
|
||||||
|
'en': 'en',
|
||||||
|
'zh': 'zh_CN'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
language() {
|
||||||
|
return this.languageTypeList[this.$store.getters.language]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(val) {
|
||||||
|
if (!this.hasChange && this.hasInit) {
|
||||||
|
this.$nextTick(() =>
|
||||||
|
window.tinymce.get(this.tinymceId).setContent(val || ''))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
language() {
|
||||||
|
this.destroyTinymce()
|
||||||
|
this.$nextTick(() => this.initTinymce())
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const _this = this;
|
this.initTinymce()
|
||||||
tinymce.init({
|
},
|
||||||
selector: `#${this.id}`,
|
activated() {
|
||||||
|
this.initTinymce()
|
||||||
|
},
|
||||||
|
deactivated() {
|
||||||
|
this.destroyTinymce()
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.destroyTinymce()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initTinymce() {
|
||||||
|
const _this = this
|
||||||
|
window.tinymce.init({
|
||||||
|
language: this.language,
|
||||||
|
selector: `#${this.tinymceId}`,
|
||||||
height: this.height,
|
height: this.height,
|
||||||
body_class: 'panel-body ',
|
body_class: 'panel-body ',
|
||||||
object_resizing: false,
|
object_resizing: false,
|
||||||
// language: 'zh_CN',
|
toolbar: this.toolbar.length > 0 ? this.toolbar : toolbar,
|
||||||
// language_url: '/static/tinymce/langs/zh_CN.js',
|
|
||||||
toolbar: this.toolbar,
|
|
||||||
menubar: this.menubar,
|
menubar: this.menubar,
|
||||||
plugins: 'advlist,autolink,code,paste,textcolor, colorpicker,fullscreen,link,lists,media,wordcount, imagetools,watermark',
|
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,
|
||||||
|
nonbreaking_force_tab: true, // inserting nonbreaking space need Nonbreaking Space Plugin
|
||||||
init_instance_callback: editor => {
|
init_instance_callback: editor => {
|
||||||
if (_this.value) {
|
if (_this.value) {
|
||||||
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(() => {
|
||||||
@@ -112,62 +154,56 @@
|
|||||||
// 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;
|
const tinymce = window.tinymce.get(this.tinymceId)
|
||||||
editor.on('init', () => {
|
if (this.fullscreen) {
|
||||||
editor.formatter.formatChanged('h2', state => {
|
tinymce.execCommand('mceFullScreen')
|
||||||
btn.active(state);
|
}
|
||||||
});
|
|
||||||
});
|
if (tinymce) {
|
||||||
|
tinymce.destroy()
|
||||||
}
|
}
|
||||||
});
|
|
||||||
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 => {
|
|
||||||
btn.active(state);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
destroyed() {
|
getContent() {
|
||||||
tinymce.get(this.id).destroy();
|
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}" >`)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.tinymce-container {
|
.tinymce-container {
|
||||||
position: relative
|
position: relative;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
.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 {
|
.editor-custom-btn-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 15px;
|
right: 4px;
|
||||||
top: 18px;
|
top: 4px;
|
||||||
|
/*z-index: 2005;*/
|
||||||
|
}
|
||||||
|
.fullscreen .editor-custom-btn-container {
|
||||||
|
z-index: 10000;
|
||||||
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editor-upload-btn {
|
.editor-upload-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|