Compare commits

...

238 Commits

Author SHA1 Message Date
花裤衩 b6fcfddbb0 Merge branch 'i18n' into deploy 2020-09-07 21:46:39 +08:00
花裤衩 ab97bc2259 perf: refine documentation button css 2020-09-07 21:46:05 +08:00
花裤衩 fce7214967 docs: add vue-java-admin-dashboard-spring 2020-09-07 21:40:46 +08:00
花裤衩 097ff8d91f docs: remove gitads 2020-09-07 21:40:36 +08:00
花裤衩 347791f319 docs: add GitAds 2020-09-07 21:40:27 +08:00
Kerollos Magdy e7da4ea532 typo: replace Css with CSS (#3323) 2020-09-07 21:40:14 +08:00
dyz 0d04d543a7 perf[permission.js]: remove useless code (#3301) 2020-09-07 21:40:04 +08:00
crayymumu c63755f4ca perf[Tinymce]: remove useless code (#3295) 2020-09-07 21:39:55 +08:00
花裤衩 3782a9f332 perf[chore]: remove preserveWhitespace config (#3280) 2020-09-07 21:39:28 +08:00
花裤衩 dc3f409986 chore: ad 2020-07-07 10:40:52 +08:00
花裤衩 e95137dc59 chore: update carbonads 2020-07-02 10:16:32 +08:00
花裤衩 12cd95b837 chore: add carbon 2020-07-01 22:01:12 +08:00
花裤衩 a9f1de65a5 chore: rm ad 2020-07-01 10:07:52 +08:00
花裤衩 088172b578 Merge branch 'i18n' into deploy 2020-06-23 21:14:20 +08:00
花裤衩 f55dd06f5a fix[chore]: do not preload runtime.js (#3279) 2020-06-23 21:13:55 +08:00
花裤衩 fa26b7991d update 2020-06-21 21:29:17 +08:00
Dihak 81a14524d1 bump: update to vue-cli@4 (#3028) 2020-06-21 21:27:49 +08:00
花裤衩 0bb3b38fcf [release] 4.3.1 2020-06-21 21:27:39 +08:00
花裤衩 1d22adb6fc Revert "change codefund"
This reverts commit 05ce7ac1ec.
2020-06-17 11:34:31 +08:00
花裤衩 f321343f09 fix some typos 2020-06-15 17:23:24 +08:00
qige2016 215ff05bd1 fix[plop]: set trim => trim() (#3254)
notEmpty
2020-06-15 17:22:52 +08:00
花裤衩 8c89992c6c chore: update element-ui to 2.13.2 2020-06-15 17:22:44 +08:00
花裤衩 bee999f291 fix[v-permission]: support dynamic set roles (#3251) 2020-06-15 17:22:36 +08:00
花裤衩 e9419b6277 perf: lint code 2020-06-15 17:22:29 +08:00
Silentdoer 07dec8ff47 perf: remove unused showdown
Co-authored-by: 花裤衩 <panfree23@gmail.com>
2020-06-15 17:22:21 +08:00
MaYuanhai 8132ad106e fix[utils]: param2Obj bug when url params includes ==(#3100) 2020-06-15 17:22:03 +08:00
Cat73 e001dab7e0 feat[Menu]: menu icon support el-icon 2020-06-15 17:21:42 +08:00
花裤衩 6831120a83 refactor: change mock files to commonjs (#3246) 2020-06-15 17:20:28 +08:00
花裤衩 e773715767 chore: turn on the preload 2020-06-15 17:20:21 +08:00
花裤衩 05ce7ac1ec change codefund 2020-06-09 11:50:34 +08:00
花裤衩 8b5f4d00d6 Merge branch 'i18n' into deploy 2020-06-09 11:41:46 +08:00
花裤衩 9975a7a938 docs: fix wrong link 2020-06-09 11:41:25 +08:00
花裤衩 9d0bcf44cf [release] 4.3.0 2020-06-09 11:40:16 +08:00
花裤衩 41c210e829 perf: change >>> ::v-deep 2020-06-09 11:40:08 +08:00
Cat73 9b7e60c16b chore: change node-sass to dart-sass (#3040) 2020-06-09 11:39:58 +08:00
花裤衩 11e6e065d0 [release] 4.2.2 2020-06-09 11:38:30 +08:00
Edwin Betancourt 0e194fea76 docs: Improve read me files and changes in Spanish. (#3234) 2020-06-09 11:38:20 +08:00
Nickbing Lao 7dc2c977a0 fix[css]: min btn width (#3164) 2020-06-04 21:08:53 +08:00
cooper 2ed1951355 fix[parseTime]: fixed when pass null (#3038) 2020-06-04 21:08:40 +08:00
AiMe1991 b8c934c81a perf: when tags-view scroll close the right-menu 2020-06-04 21:08:14 +08:00
花裤衩 fe72cae1e5 docs: add tips 2020-06-04 21:08:07 +08:00
garethx d17cfd067a feat: add option to try project on CodeSandbox (#2976) 2020-06-04 21:08:00 +08:00
花裤衩 4fedd2e8d8 fix: compatibility with vetur (#1700) 2020-06-04 21:07:20 +08:00
ntnyq 5c6ddaad38 fix[element-variables]: missing space in element-variables (#3144) 2020-06-04 21:07:13 +08:00
Aisen 2ffff40bfd perf[Tinymce]: editor try to keep these URLs intact (#3141) 2020-06-04 21:07:07 +08:00
花裤衩 c6266ea396 fix: use vue-cli default source-map (#3097)
cheap-module-eval-source-map
2020-06-04 21:06:59 +08:00
Alex S e29e5838bd fixed typo (#3091) 2020-06-04 21:06:51 +08:00
花裤衩 2975c4181a fix: svg support old broswer (#3085) 2020-06-04 21:06:33 +08:00
花裤衩 cd404bc128 Update README.zh-CN.md 2020-06-04 21:06:27 +08:00
花裤衩 348e1bbafd docs: add smallsticker 2020-06-04 21:06:19 +08:00
echofly 43629c09c3 perf: format component names as PascalCase (#3074)
format: component names should be PascalCase
2020-06-04 21:06:07 +08:00
Aisen60 4597711d9d fix:fixed parseTime bug in ie and safari(#3066)
* /src/utils/index.js parseTime 添加IE浏览器(版本10以下,包括版本10)兼容。

* perf: update

Co-authored-by: aisen60 <aisen60@qq.com>
Co-authored-by: 花裤衩 <panfree23@gmail.com>
2020-06-04 21:05:57 +08:00
echofly f788d681e6 fix[profile/UserCard]: fixed wrong key name (#3056)
roles => role
2020-06-04 21:05:49 +08:00
花裤衩 8ad5c90f8f perf: change script-loader to dependencies 2020-06-04 21:05:37 +08:00
Shota Aratono 11bcb43326 docs: improve Japanese translation (#2970) 2020-06-04 21:05:21 +08:00
RoBlues 4a2401b574 perf[Mock]: set responseFake to mock-server.js(#2966)
* modify 把mock/index.js中与mock-server相关的代码转移到mock-server.js中去,实现两则功能分割
2020-06-04 21:05:05 +08:00
李小斐 dc4832ad5b fix: fixed redirect path regex (#2933) 2020-06-04 21:04:41 +08:00
MaYuanhai 39b2b9b872
feat[Search]: route search supports pinyin (#2643) 2020-05-04 21:38:43 +08:00
花裤衩 e75e9a301a Merge branch 'i18n' into deploy 2020-01-09 20:25:46 +08:00
花裤衩 255989138d fix: fixed require mock bug in production 2020-01-09 20:25:12 +08:00
花裤衩 f1d5e5c19b Merge branch 'i18n' into deploy 2020-01-09 17:46:51 +08:00
花裤衩 a6bb84b763 bump: update element-ui version 2020-01-09 17:46:17 +08:00
花裤衩 025d5e46a2 fix: fixed mock server (#2929)
* init

* refine

* update
2020-01-09 17:46:05 +08:00
花裤衩 95561d4977 fix[Charts]: fix charts resize in keep-alive bug (#2922)
* fix[Charts]: fix charts resize in keep-alive bug

* refine
2020-01-09 17:45:54 +08:00
RussXD ea27da43b7 perf: optimize checkCapslock method (#2635)
* optimize checkCapslock method

* update

Co-authored-by: 花裤衩 <panfree23@gmail.com>
2020-01-09 17:45:41 +08:00
AndyLZC/AndyLZC.github.io 93e01926e3 perf[complex-table]:refine code (#2825) 2020-01-09 17:45:31 +08:00
Kaitian Xie be18a69fa4 perf[Menu]: remove unused menu-wrapper (#2903) 2020-01-09 17:40:38 +08:00
任羽飞 1d707e4ab6 perf: import mockXHR only in production (#2910)
* 自动排除mock

生产环境,使用webpack的条件编译自动排除mock数据

* perf: refine

Co-authored-by: 花裤衩 <panfree23@gmail.com>
2020-01-09 17:40:26 +08:00
4339504db2 fix[Logout]: click blank area of ​​dropDown able to logout (#2896) 2020-01-09 17:40:11 +08:00
花裤衩 2d27251f2e Merge branch 'i18n' into deploy 2019-12-16 10:34:18 +08:00
花裤衩 c656f2ed00 perf[documentation]: refine css 2019-12-16 10:32:13 +08:00
flitrue 230575a6fd fix[icons]:fixed eslint 1 error and 2 warnings (#2835) 2019-12-16 10:32:07 +08:00
monkeycf ded67b054a feat: plop new generate store (#2805) 2019-12-16 10:31:59 +08:00
xuanzai ad444fe3ae perf[views/icons]: use grid (#2803) 2019-12-16 10:31:52 +08:00
Phạm Ngọc Hòa b2f8373a5b perf: format pdf download (#2791) 2019-12-16 10:31:43 +08:00
Phạm Ngọc Hòa b70cc183d6 format: space in user card (#2744) 2019-12-16 10:31:34 +08:00
bbigcd dbc41b5275 update 'MarkdownEditor' components name 2019-12-16 10:31:26 +08:00
Phạm Ngọc Hòa 44f8f39465 perf: text i18n (#2739) 2019-12-16 10:31:16 +08:00
Phạm Ngọc Hòa a4d4bc8a3e perf: complex table (#2732) 2019-12-16 10:31:04 +08:00
Phạm Ngọc Hòa 92a3e2da45 perf: format drag table (#2733)
move one format `{row}`
2019-12-16 10:26:47 +08:00
Phạm Ngọc Hòa 1e6aab3970 perf: format inline edit table (#2725)
move one format `{row}`
2019-12-16 10:26:37 +08:00
Phạm Ngọc Hòa daec48bbbe perf: format dropdown menu code (#2720) 2019-12-16 10:26:29 +08:00
花裤衩 1f0ac624fc style: fix el-date-picker css style 2019-12-16 10:26:10 +08:00
BradyBromley d957bc1f4a docs: improved README.md (#2656) 2019-12-16 10:24:27 +08:00
花裤衩 5d981eee7e Revert "change codefund"
This reverts commit 136d962c1e.
2019-12-03 10:35:00 +08:00
花裤衩 136d962c1e change codefund 2019-11-29 10:15:33 +08:00
花裤衩 da5de5c689 merge 2019-10-12 19:30:30 +08:00
花裤衩 45d72a6ef5 feat: add job 2019-10-12 19:29:31 +08:00
花裤衩 fb2c852a0c merge master 2019-10-12 18:26:30 +08:00
花裤衩 b6929ca915 Merge branch 'i18n' into deploy 2019-10-12 18:08:04 +08:00
花裤衩 ae92d6f95e docs: add job ad 2019-10-12 18:06:47 +08:00
花裤衩 f5608a7511 fix[TagsView]: fixed click.middle can close affixed tag bug (#2649) 2019-10-12 18:06:35 +08:00
MaYuanhai ce667850cf perf[SvgIcon]: change xlink:href to href(#2645)
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href
2019-10-12 18:03:09 +08:00
花裤衩 b7c032b509 fix[TagsView]: fixed toLastView bug (#2634) 2019-10-12 18:03:02 +08:00
花裤衩 a3137fb6cb fix[logout]: empty tagsview when logout (#2632) 2019-10-12 18:02:53 +08:00
花裤衩 50dcb90b53 fix[tagsView]: fixed DEL_OTHERS_CACHED_VIEWS bug 2019-10-12 18:02:46 +08:00
monkeycf ed0b023767 perf[tagsView]: pref DEL_CACHED_VIEW and DEL_OTHERS_CACHED_VIEWS function (#2626) 2019-10-12 18:02:39 +08:00
monkeycf 137c1c3eff perf[utils.js]: perf parseTime function (#2625) 2019-10-12 18:02:33 +08:00
花裤衩 d571715c3d fix[example]: fixed create.vue cache error
https://github.com/PanJiaChen/vue-element-admin/issues/2608
2019-10-12 18:02:24 +08:00
花裤衩 4342032fb9 fix: fixed numberFormatter bug
https://github.com/PanJiaChen/vue-element-admin/issues/2568
2019-10-12 18:02:17 +08:00
MaYuanhai 159e21c56b refactor[ImageCropper]: fix lint error (#2365) 2019-10-12 18:01:57 +08:00
Serge e4f2b1e587 perf: optimize import file-saver way(#2347) 2019-10-12 18:01:48 +08:00
Francis 6c05e7ddb9 perf: VS Code support webpack alias file jump (#2609) 2019-10-12 18:01:32 +08:00
MaYuanhai 1a83a40106 fix[Dashboard]: fixed debounce bug (#2586) (#2597)
To fixed https://github.com/PanJiaChen/vue-element-admin/issues/2586
2019-10-12 18:01:24 +08:00
花裤衩 1602577733 docs: add awesome-project 2019-10-12 18:01:16 +08:00
Baskerville* d747879195 fix: typos (#2532)
Role Nmae => Role Name
2019-10-12 18:01:01 +08:00
花裤衩 c4b9090b0b fix: fixed missing icons 2019-10-12 18:00:53 +08:00
why 7be0bd5751 fix[complex-table]: form header sort icon is out of sync (#2382) 2019-10-12 17:58:54 +08:00
Pan 9ff40abd74 chore: allow dynamic set port 2019-10-12 17:54:37 +08:00
itsccn 6a89136805 bump: update @vue/cli-plugin-eslint version (#2327)
FIx  cannot find module '.../node_modules/eslint/lib/api.js/package.json' bug,see https://github.com/vuejs/vue-cli/issues/4231.
2019-10-12 17:54:06 +08:00
Pan 5d12cbd75c bump: update axios for security vulnerability 2019-10-12 17:53:55 +08:00
MaYuanhai acbbc5f52d perf[clipboard.js]: remove redundant code (#2307) 2019-10-12 17:53:43 +08:00
TinaryTree e216e11618 docs: fix typo README.zh-CN.md (#2283)
修改错别字
2019-10-12 17:53:26 +08:00
MaYuanhai cafdbf41f2 perf[PanThumb]: Replace the image tag with background-image to prevent the stretching (#2202) 2019-10-12 17:52:54 +08:00
Pan e0da0d0268 change api 2019-06-05 09:39:36 +08:00
Pan b7b12acbd2 Merge branch 'i18n' into deploy 2019-06-05 09:38:00 +08:00
肖敏 a9e21c2ce2 fix: input attribute autocomplete error (#2191) 2019-06-05 09:37:26 +08:00
Jessynt 921cdab858 docs: fix typo (#2170) 2019-06-05 09:37:20 +08:00
MaYuanhai 440b5c6596 fix[ImageCropper]: removeEventListener when destroyed(#2169) 2019-06-05 09:37:14 +08:00
Pan 884587cccf perf: default not set withCredentials 2019-06-05 09:37:07 +08:00
Pan f1637ed780 Merge branch 'i18n' into deploy 2019-05-27 16:33:43 +08:00
Pan 00c853c54d [release] 4.2.1 2019-05-27 16:33:14 +08:00
Serge 686b1d37fd perf[request.js]: refine error reject (#2160) 2019-05-27 16:33:08 +08:00
花裤衩 6f45fd987d feat: add tab url demo (#2114) 2019-05-27 16:33:01 +08:00
花裤衩 f1bc06b082 fix[Tinymce]: fixed bug when init multiple tinymces at the same time (#2152) 2019-05-27 16:32:51 +08:00
bpzhang 786d9662fb chore: add autoprefixer to devDependencies 2019-05-27 16:32:06 +08:00
Pan e945c29a3c update github ISSUE_TEMPLATE 2019-05-27 16:31:59 +08:00
花裤衩 3058cfefcb chore: set localhost => 127.0.0.1 (#2142) 2019-05-27 16:31:42 +08:00
花裤衩 4413d3383f Create FUNDING.yml 2019-05-27 16:31:35 +08:00
花裤衩 caf7614ab2 fix[Chart]: fixed chart bug in keep-alive (#2119) 2019-05-23 11:30:37 +08:00
Pan 52f56ee55f perf[Style]: refine example css 2019-05-23 11:28:20 +08:00
Pan 5b70eba9a0 merge 2019-05-21 10:58:51 +08:00
Pan 5b1b05b18e [release] 4.2.0 2019-05-21 10:57:14 +08:00
花裤衩 cf1f40ddad perf[Tinymce]: dynamic import tinymce(#2102) 2019-05-21 10:56:18 +08:00
Pan bd81477202 refactor[chore]: generate postcss.config.js instead of .postcssrc.js
consistent with vue-cli
2019-05-21 10:56:09 +08:00
花裤衩 a582eec089 perf[Login]: support other query (#2013) 2019-05-21 10:56:02 +08:00
Yamel Senih c85ce21951 perf[store]: add support to sub-modules (#2047) 2019-05-21 10:55:55 +08:00
花裤衩 fa23feeed4 perf[Breadcrumb]: do not update breadcrumbs when go to redirect page (#2086) 2019-05-21 10:55:48 +08:00
花裤衩 cdf3ea06c7 fix: fixed change roles bug (#2072) 2019-05-21 10:55:41 +08:00
花裤衩 73babc4880 feat[SvgIcon]: support import svg from url (#2052) 2019-05-21 10:55:31 +08:00
liugq cc7554f386 perf[RightPanel]: tidy css (#2101) 2019-05-21 10:55:21 +08:00
Pan 4f9efc8ea4 perf[Exapme]: set page title according to article id 2019-05-21 10:55:13 +08:00
Yamel Senih 71ece14be1 docs[es]: add some translation(#2080) 2019-05-21 10:55:06 +08:00
Yamel Senih d897df5e2b docs: add support to readme for Spanish (#2070) 2019-05-21 10:54:55 +08:00
Pan 5f536fdfc4 fix[redirect]: fix redirect bug in vue-devtool again 2019-05-13 17:33:50 +08:00
Pan b6aa00d5de perf[Tinymce]: update tinymce cdn version 2019-05-13 09:57:33 +08:00
Pan 3281d16131 fix[sidebar.css]: remove redundant css 2019-05-10 18:30:40 +08:00
Pan 504c06f648 chore: use mockjs in production environment 2019-05-10 14:48:44 +08:00
Pan f606b77472 Merge branch 'i18n' into deploy 2019-05-09 12:47:59 +08:00
Pan 63f8635538 doc: add new article 2019-05-09 12:47:01 +08:00
Pan ad689e3f96 perf[Style]: refine fixed-header style when open el-dialog 2019-05-08 18:13:05 +08:00
花裤衩 6c8d7a164f perf[Profile]: adapt the profile page to the mobile (#2020) 2019-05-07 14:11:14 +08:00
Pan c2063f95fd Merge branch 'i18n' into deploy 2019-05-05 17:21:36 +08:00
Pan 6346ab3d80 merge master 2019-05-05 17:16:14 +08:00
Pan 818b565658 update doc 2019-05-05 16:13:57 +08:00
Pan b303d02783 Merge branch 'master' into deploy 2019-05-03 17:34:39 +08:00
Pan 8123266fe5 Merge branch 'master' into deploy 2019-05-02 14:01:30 +08:00
Pan b70718b50a merge 2019-04-30 16:45:19 +08:00
Pan d9503de853 d 2019-04-23 13:09:23 +08:00
Pan 59800bfaa3 d 2019-04-23 13:09:11 +08:00
Pan 965c2eca65 Merge branch 'master' into deploy 2019-04-23 13:06:46 +08:00
Pan 1c9723949d refine 2019-04-16 16:19:36 +08:00
Pan 061ab5ee6d refine 2019-04-16 16:19:04 +08:00
Pan 8835c5b48f merge master 2019-04-16 15:49:12 +08:00
Pan ee101f4a78 Merge branch 'master' into deploy 2019-04-10 10:38:06 +08:00
Pan ffc98f6e81 fix ad bug 2019-04-08 14:33:20 +08:00
Pan caffe6f470 Merge branch 'master' into deploy 2019-04-08 14:13:53 +08:00
Pan 9b68a0835e Merge branch 'master' into deploy 2019-04-03 18:20:13 +08:00
Pan 1b96709250 Merge branch 'master' into deploy 2019-04-03 18:12:49 +08:00
Pan 86fa7dd654 Merge branch 'master' into deploy 2019-04-01 17:39:24 +08:00
Pan a319df72e6 merge 2019-04-01 17:26:23 +08:00
Pan 3905ce454d Merge branch 'master' into deploy 2019-03-21 11:21:11 +08:00
Pan 082b62e960 Merge branch 'master' into deploy 2019-03-21 11:20:29 +08:00
Pan ae02d6bb56 merge master 2019-03-19 15:42:05 +08:00
Pan 0e9f32f25a Merge branch 'master' into deploy 2019-03-15 18:13:50 +08:00
Pan 49ed3e2399 Merge branch 'master' into deploy 2019-03-12 11:14:19 +08:00
Pan ae29f1b030 ADD 2019-03-08 14:01:16 +08:00
Pan 93b2a6c7ad rm 2019-03-08 14:00:54 +08:00
Pan 37c5c13560 Merge branch 'master' into deploy 2019-03-07 17:51:03 +08:00
Pan d48fc1e711 rm 2019-03-07 15:45:26 +08:00
Pan 8f69cf7643 merge master 2019-03-07 15:34:42 +08:00
Pan 163a41fe8f perf[utils]: optimize code 2019-02-19 10:07:18 +08:00
Pan 002a525352 Merge branch 'master' into deploy 2019-02-15 16:20:09 +08:00
Pan d0c0f9313c Merge branch 'master' into deploy 2019-02-15 10:05:41 +08:00
Pan 07bcdddc45 Merge branch 'master' into deploy 2019-02-13 16:34:26 +08:00
Pan f1ed620fc2 Merge branch 'master' into deploy 2019-02-13 15:11:10 +08:00
Pan 10d9007f81 Merge branch 'master' into deploy 2019-01-30 14:09:51 +08:00
Pan 11264d163b merge 2019-01-23 11:36:59 +08:00
Pan 422037372c Merge branch 'master' into deploy 2019-01-17 11:11:03 +08:00
Pan 9a32666286 update 2019-01-15 16:20:15 +08:00
Pan c39ef38f15 update 2019-01-15 14:24:36 +08:00
Pan f6ede59859 Merge branch 'master' into deploy 2019-01-15 14:15:16 +08:00
Pan 92c25dacc6 update codefund 2018-12-30 21:13:40 +08:00
Pan e8e530de54 Merge branch 'master' into deploy 2018-12-27 13:46:47 +08:00
Pan b59d22ac18 Merge branch 'master' into deploy 2018-12-24 17:52:55 +08:00
Pan 51385c96b0 Merge branch 'master' into deploy 2018-12-04 18:18:33 +08:00
Pan 7c683b6f11 Merge branch 'master' into deploy 2018-12-04 14:02:12 +08:00
Pan 42da911819 Merge branch 'master' into deploy 2018-11-28 14:25:01 +08:00
Pan d87c1b1944 Merge branch 'master' into deploy 2018-10-24 16:07:38 +08:00
Pan 01a0d9e5f0 Merge branch 'master' into deploy 2018-10-24 16:07:06 +08:00
Pan 07cf4791dc Merge branch 'master' into deploy 2018-10-19 14:56:37 +08:00
Pan a543b0ba7c Merge branch 'master' into deploy 2018-10-17 14:16:11 +08:00
Pan ec491002f8 Merge branch 'master' into deploy 2018-10-15 16:32:33 +08:00
Pan 4cf48ca656 change ad position 2018-10-12 14:06:22 +08:00
Pan 251d9c46d4 change id 2018-10-10 13:33:33 +08:00
Pan 1166017676 Merge branch 'master' into deploy 2018-10-09 16:12:14 +08:00
Pan 0cf4f2e518 fix bug 2018-10-09 13:25:23 +08:00
Pan 27725ac9d7 add ga 2018-10-08 18:26:39 +08:00
Pan 65ac600b54 fix[TagsView]: fixed visitedViews bug
Some strange bugs occur when the names of the routes are the same.
2018-10-08 18:19:48 +08:00
Pan 1f6010612f refine example demo 2018-10-08 18:19:48 +08:00
花裤衩 78be45fe04 perf[sidebar]: hightlight submenu when is active (#1154) 2018-10-08 18:19:48 +08:00
Pan 67d2b38e7b pref[Sidebar]: refine key 2018-10-08 18:19:48 +08:00
Pan f7bbc6a9e9 tweak 2018-10-08 18:19:48 +08:00
花裤衩 c799c94da2 fix:[Sidebar]: fixed bug in iOS (#1152) 2018-10-08 18:19:48 +08:00
花裤衩 56e9ba491f feature[tagsView]: support middle click (#1149) 2018-10-08 18:19:48 +08:00
花裤衩 648868657a feature: add pathToRegexp to compile path (#1148) 2018-10-08 18:19:48 +08:00
花裤衩 f56385788c feature[Excel]: support bookType option (#1144)
Documentation: https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html
2018-10-08 18:19:48 +08:00
Pan 9563f2abe2 fix sidebar css bug #1142 2018-10-08 18:19:48 +08:00
zhaoguoweiLLHC 9f535925a6 fix[UploadExcel]: fixed bug when there were multiple components(#1136)
复用此组件时因为id不可重复的问题会导致onSuccess指向错误。
2018-10-08 18:19:48 +08:00
Pan 64e4ae7330 tweak code 2018-10-08 18:19:48 +08:00
花裤衩 24c29aeded fix[Sidebar]: link bug (#1134)
Fixed #1125
2018-10-08 18:19:48 +08:00
Pan d0d5d91e8f remove unnecessary assets 2018-10-08 18:19:48 +08:00
Pan 7c11d5949a refine css 2018-10-08 15:50:44 +08:00
Pan eb6b222ad2 add ad 2018-10-08 15:42:46 +08:00
Pan 28f80bc7cf Merge branch 'master' into deploy 2018-09-18 09:40:44 +08:00
Pan 0a65f69cef Merge branch 'master' into deploy 2018-09-07 17:58:59 +08:00
Pan e28d3acf17 Merge branch 'master' into deploy 2018-08-31 16:25:18 +08:00
Pan a5f373dcf7 Merge branch 'master' into deploy 2018-08-31 16:20:10 +08:00
Pan 1cfcd49fe2 Merge branch 'master' into deploy 2018-08-29 15:26:24 +08:00
Pan 33ca4a3ad9 change path 2018-08-20 10:27:56 +08:00
Pan 9bf85bfc97 Merge branch 'master' into deploy 2018-08-20 10:26:57 +08:00
Pan 0d38ff1c16 Merge branch 'master' into deploy 2018-08-19 16:59:08 +08:00
Pan 5935f7a56c Merge branch 'master' into deploy 2018-08-15 17:32:06 +08:00
Pan ab526d1976 update 2018-08-08 17:15:57 +08:00
Pan 641790162d Merge branch 'master' into deploy 2018-07-16 11:19:08 +08:00
Pan 95709f7369 Merge branch 'master' into deploy 2018-07-13 11:28:24 +08:00
Pan 27012a4b52 touch .nojekyll 2018-07-13 11:28:06 +08:00
Pan 700cc822cd deploy 2018-07-12 12:44:53 +08:00
112 changed files with 2586 additions and 907 deletions

View File

@ -3,12 +3,3 @@ ENV = 'development'
# base api # base api
VUE_APP_BASE_API = '/dev-api' VUE_APP_BASE_API = '/dev-api'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
# to control whether the babel-plugin-dynamic-import-node plugin is enabled.
# It only does one thing by converting all import() to require().
# This configuration can significantly increase the speed of hot updates,
# when you have a large number of pages.
# Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
VUE_CLI_BABEL_TRANSPILE_MODULES = true

View File

@ -51,51 +51,61 @@ Vue Element Admin es una solución práctica basada en la nueva plataforma de de
- Plantilla de Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Créditos: [@Armour](https://github.com/Armour)) - Plantilla de Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Créditos: [@Armour](https://github.com/Armour))
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) - [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
**Después de la versión `v4.1.0+`, la rama por defecto master no tendrá soporte para i18n. Por favor use [i18n](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), los cambios serán incluidos en la rama master** **Después de la versión `v4.1.0+`, la rama por defecto master no tendrá soporte para i18n. Por favor utilice la rama [i18n](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), los cambios serán incluidos en la rama master**
**la versión actual es `v4.0+` construida con `vue-cli`. Si encuentra algún problema, por favor coloque un [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). Si desea usar la versión anterior, puede cambiar de rama a [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), no relacionado con `vue-cli`** **la versión actual es `v4.0+` construida con `vue-cli`. Si encuentra algún problema, por favor coloque un [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). Si desea usar la versión anterior, puede cambiar de rama a [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), no relacionado con `vue-cli`**
**Este proyecto no está soportado para versiones muy viejas de navegadores (e.g. IE).** **Este proyecto no está soportado para versiones antigüas de navegadores (ej. IE).**
## Preparación ## Preparación
Necesita instalar [node](https://nodejs.org/) y [git](https://git-scm.com/) localmente. El proyecto es basado en [ES2015+](https://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/), [vue-cli](https://github.com/vuejs/vue-cli) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), toda la solicitud de datos simulada se realiza a través de [Mock.js](https://github.com/nuysoft/Mock). Necesita instalar [node](https://nodejs.org/) y [git](https://git-scm.com/) localmente. El proyecto es basado en [ES2015+](https://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/), [vue-cli](https://github.com/vuejs/vue-cli) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), toda la solicitud de datos simulada se realiza a través de [Mock.js](https://github.com/nuysoft/Mock).
Entendiendo y aprendiendo esto pudiera ayudarle con su proyecto. Entendiendo y aprendiendo esto pudiera ayudarle con su proyecto.
<p align="center"> [![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png"> <img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p> </p>
## Patrocinantes ## Patrocinantes
Se un patrocinante y pon tu logo en nuestro README on GitHub con un enlace directo a tu sitio web. [[Se un Patrocinante]](https://www.patreon.com/panjiachen) Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace directo a su sitio web. [[Se un Patrocinante]](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>Plantilla de Dashboard de administración hecha con Vue, React y Angular.</p> ### Akveo
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Java backend integration</p>
### Flatlogic
<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>
## Características ## Características
``` ```
- Iniciar / Cerrar Sesión - Iniciar / Cerrar Sesión
- Permisos de Authentication - Permisos de Autenticación
- Página de Permisos - Página de Permisos
- Directivas de permisos - Directivas de permisos
- Página de configuración de permisos - Página de configuración de permisos
- Autenticación por dos pasos - Autenticación por dos pasos
- Construcción Multi-entorno - Construcción Multi-entorno
- dev sit stage producción - Desarrollo (dev)
- sit
- Escenario de pruebas (stage),
- Producción (prod)
- Características Globales - Características Globales
- I18n - I18n
- Temas dinámicos - Temas dinámicos
- Dynamic sidebar (soporte a rutas multi-nivel) - Menu lateral dinámico (soporte a rutas multi-nivel)
- Barra de rutas dinámica - Barra de rutas dinámica
- Tags-view (Tab page Support right-click operation) - Tags-view (Pestañas de página, Soporta operación de clic derecho)
- Svg Sprite - Svg Sprite
- Datos de simulación con Mock - Datos de simulación con Mock
- Pantalla completa - Pantalla completa
- Responsive Sidebar - Menu lateral responsivo
- Editor - Editor
- Editor de Texto Enriquecido - Editor de Texto Enriquecido
@ -106,7 +116,7 @@ Se un patrocinante y pon tu logo en nuestro README on GitHub con un enlace direc
- Exportación a Excel - Exportación a Excel
- Carga de Excel - Carga de Excel
- Visualización de Excel - Visualización de Excel
- Exportación como zip - Exportación como ZIP
- Tabla - Tabla
- Tabla Dinámica - Tabla Dinámica
@ -135,7 +145,7 @@ Se un patrocinante y pon tu logo en nuestro README on GitHub con un enlace direc
- Página de Guías - Página de Guías
- ECharts (Gráficos) - ECharts (Gráficos)
- Portapapeles - Portapapeles
- Convertidor de Markdown a html - Convertidor de Markdown a HTML
``` ```
## Iniciando ## Iniciando
@ -208,7 +218,7 @@ Navegadores modernos e 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" />](https://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" />](https://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" />](https://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" />](https://godban.github.io/browsers-support-badges/)</br>Safari | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://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" />](https://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" />](https://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" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- | | --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| últimas 2 versiones| últimas 2 versiones| últimas 2 versiones | IE10, IE11, Edge | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones |
## Licencia ## Licencia

View File

@ -30,7 +30,7 @@
## 概要 ## 概要
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) は管理画面のフロントエンドのインタフェース[vue](https://github.com/vuejs/vue) と [element-ui](https://github.com/ElemeFE/element)を使っています。i18nの多言語対応、可変ルート、権限、典型的なビジネスアプリテンプレートであり、豊富なコンポーネントを提供しています素早くビジネス用の管理画面の現型を構築に役立ちます。 [vue-element-admin](https://panjiachen.github.io/vue-element-admin) は管理画面のフロントエンドのインタフェースで、[vue](https://github.com/vuejs/vue) と [element-ui](https://github.com/ElemeFE/element)を使っています。i18nの多言語対応、可変ルート、権限、典型的なビジネスアプリテンプレートであり、豊富なコンポーネントを提供しています素早くビジネス用の管理画面の現型を構築に役立ちます。
- [デモページ](https://panjiachen.github.io/vue-element-admin) - [デモページ](https://panjiachen.github.io/vue-element-admin)
@ -44,22 +44,24 @@
- おすすめシンプルテンプレート: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template) - おすすめシンプルテンプレート: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- デスクトップバージョン: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) - デスクトップバージョン: [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)) - Typescriptバージョン: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (感謝: [@Armour](https://github.com/Armour))
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) - [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
**After the `v4.1.0+` version, the default master branch will not support i18n. Please use [i18n Branch](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), it will keep up with the master update** **バージョン`v4.1.0+`以降について、デフォルトのmasterブランチではi18nをサポートしていません。masterブランチと共にアップデートされる[i18n Branch](https://github.com/PanJiaChen/vue-element-admin/tree/i18n)を使用してください。 **
**現在のバージョン `v4.0+``vue-cli` で構築バグ報告は[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)のissueでお願いします。旧バージョン[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0)もあります。`vue-cli`に依存しないです。** **現在のバージョン `v4.0+``vue-cli` で構築していて、バグ報告は[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)のissueでお願いします。旧バージョン[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0)もあります。こちらは`vue-cli`に依存しないです。**
**低いバージョンのブラウザはサーポートしないです(例えば ie),必要があれば polyfill を追加してください。 [詳細はこちら](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)** **低いバージョンのブラウザはサーポートしないです(例えば 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/) 、[vue-cli](https://github.com/vuejs/vue-cli) 、[axios](https://github.com/axios/axios) [element-ui](https://github.com/ElemeFE/element)で開発しています。Requestは[Mock.js](https://github.com/nuysoft/Mock)のモックデータを使っています。 ローカル環境に [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/) 、[vue-cli](https://github.com/vuejs/vue-cli) 、[axios](https://github.com/axios/axios) [element-ui](https://github.com/ElemeFE/element)で開発しています。Requestは[Mock.js](https://github.com/nuysoft/Mock)のモックデータを使っています。
**バグ修正や新規機能追加のissue と pull requestは大歓迎です。** **バグ修正や新規機能追加のissue と pull requestは大歓迎です。**
<p align="center"> [![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png"> <img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p> </p>
@ -67,6 +69,11 @@
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) 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)
### Akveo
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Java backend integration</p>
### Flatlogic
<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> <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>
## 機能一覧 ## 機能一覧
@ -81,15 +88,18 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- 外部IDでログイン - 外部IDでログイン
- 複数環境デプロイ - 複数環境デプロイ
- dev sit stage prod - dev
- sit
- stage
- prod
- 共通機能 - 共通機能
- 多言語切替 - 多言語切替
- テーマ切替 - テーマ切替
- サイトメニュー(ルートから生成) - サイトメニュー(ルートから生成)
- Breadcrumb Navigation - パンくずリストナビゲーション
- Tag Navigation - タブナビゲーション
- Svg Sprite Icon - Svg Sprite アイコン
- ローカル/バックエンド モック データ - ローカル/バックエンド モック データ
- Screenfull - Screenfull
@ -104,33 +114,33 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- リード - リード
- Zip - Zip
- Table - テーブル
- Dynamic Table - ダイナミックテーブル
- Drag And Drop Table - ドラッグアンドドロップテーブル
- Inline Edit Table - インラインエディットテーブル
- Error Page - エラーページ
- 401 - 401
- 404 - 404
- コンポーネント - コンポーネント
- Avatar Upload - アバターアップロード
- Back To Top - トップに戻る
- Drag Dialog - ドラッグダイアログ
- Drag Select - ドラッグ選択
- Drag Kanban - ドラッグKanban
- Drag List - ドラッグリスト
- SplitPane - ペインの分割
- Dropzone - Dropzone
- Sticky - スティッキー
- CountTo - CountTo
- Advanced Example - 高度なサンプル
- Error Log - エラーログ
- Dashboard - ダッシュボード
- Guide Page - ガイドページ
- ECharts - ECharts
- Clipboard - クリップボード
- Markdown to html - Markdown to html
``` ```
@ -138,7 +148,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
```bash ```bash
# clone the project # clone the project
git clone https://github.com/PanJiaChen/vue-element-admin.git git clone -b i18n git@github.com:PanJiaChen/vue-element-admin.git
# enter the project directory # enter the project directory
cd vue-element-admin cd vue-element-admin
@ -150,7 +160,7 @@ npm install
npm run dev npm run dev
``` ```
This will automatically open http://localhost:9527 http://localhost:9527 が自動的に開きます。
## Build ## Build
@ -178,11 +188,11 @@ npm run lint
npm run lint -- --fix npm run lint -- --fix
``` ```
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information 詳細は [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) を参照してください。
## Changelog ## Changelog
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases). 各リリースの詳細は [release notes](https://github.com/PanJiaChen/vue-element-admin/releases) にあります。
## Online Demo ## Online Demo
@ -204,7 +214,7 @@ 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" />](https://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" />](https://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" />](https://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" />](https://godban.github.io/browsers-support-badges/)</br>Safari | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://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" />](https://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" />](https://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" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- | | --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions | IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## License ## License

View File

@ -30,9 +30,9 @@ English | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | [Spa
## Introduction ## Introduction
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) is a production-ready front-end solution for admin interfaces. It based on [vue](https://github.com/vuejs/vue) and use the UI Toolkit [element-ui](https://github.com/ElemeFE/element). [vue-element-admin](https://panjiachen.github.io/vue-element-admin) is a production-ready front-end solution for admin interfaces. It is based on [vue](https://github.com/vuejs/vue) and uses the UI Toolkit [element-ui](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. [vue-element-admin](https://panjiachen.github.io/vue-element-admin) is based on the newest development stack of vue and it has a built-in i18n solution, typical templates for enterprise applications, and lots of awesome features. It helps you build large and complex Single-Page Applications. I believe whatever your needs are, this project will help you.
- [Preview](https://panjiachen.github.io/vue-element-admin) - [Preview](https://panjiachen.github.io/vue-element-admin)
@ -62,7 +62,9 @@ It is a magical vue admin based on the newest development stack of vue, built-in
You need to install [node](https://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](https://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/), [vue-cli](https://github.com/vuejs/vue-cli) , [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). You need to install [node](https://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](https://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/), [vue-cli](https://github.com/vuejs/vue-cli) , [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).
Understanding and learning this knowledge in advance will greatly help the use of this project. Understanding and learning this knowledge in advance will greatly help the use of this project.
<p align="center"> [![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png"> <img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p> </p>
@ -70,6 +72,11 @@ Understanding and learning this knowledge in advance will greatly help the use o
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) 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)
### Akveo
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Java backend integration</p>
### Flatlogic
<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> <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 ## Features
@ -84,7 +91,10 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- Two-step login - Two-step login
- Multi-environment build - Multi-environment build
- dev sit stage prod - Develop (dev)
- sit
- Stage Test (stage)
- Production (prod)
- Global Features - Global Features
- I18n - I18n
@ -142,7 +152,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
```bash ```bash
# clone the project # clone the project
git clone https://github.com/PanJiaChen/vue-element-admin.git git clone -b i18n git@github.com:PanJiaChen/vue-element-admin.git
# enter the project directory # enter the project directory
cd vue-element-admin cd vue-element-admin
@ -208,7 +218,7 @@ 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" />](https://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" />](https://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" />](https://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" />](https://godban.github.io/browsers-support-badges/)</br>Safari | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://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" />](https://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" />](https://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" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- | | --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions | IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## License ## License

View File

@ -77,7 +77,9 @@
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr** **如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
<p align="center"> [![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png"> <img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p> </p>
@ -85,8 +87,14 @@
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) 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)
### Akveo
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Java 后端整合</p>
### Flatlogic
<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> <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>
## 功能 ## 功能
``` ```
@ -99,7 +107,10 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
- 二步登录 - 二步登录
- 多环境发布 - 多环境发布
- dev sit stage prod - dev
- sit
- stage
- prod
- 全局功能 - 全局功能
- 国际化多语言 - 国际化多语言
@ -157,7 +168,7 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
```bash ```bash
# 克隆项目 # 克隆项目
git clone https://github.com/PanJiaChen/vue-element-admin.git git clone -b i18n git@github.com:PanJiaChen/vue-element-admin.git
# 进入项目目录 # 进入项目目录
cd vue-element-admin cd vue-element-admin
@ -221,13 +232,17 @@ Detailed changes for each release are documented in the [release notes](https://
[Buy me a coffee](https://www.buymeacoffee.com/Pan) [Buy me a coffee](https://www.buymeacoffee.com/Pan)
## 购买贴纸
你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,本项目将获得 2 元的捐赠。
## Browsers support ## Browsers support
Modern browsers and Internet Explorer 10+. 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" />](https://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" />](https://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" />](https://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" />](https://godban.github.io/browsers-support-badges/)</br>Safari | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://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" />](https://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" />](https://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" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- | | --------- | --------- | --------- | --------- |
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions | IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## License ## License

View File

@ -1,5 +1,14 @@
module.exports = { module.exports = {
presets: [ presets: [
'@vue/app' // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
] '@vue/cli-plugin-babel/preset'
],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
'plugins': ['dynamic-import-node']
}
}
} }

88
config/index.js Normal file
View File

@ -0,0 +1,88 @@
'use strict'
// Template version: 1.2.6
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
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"
// with this option, according to the CSS-Loader README
// (https://github.com/webpack/css-loader#sourcemaps)
// In our experience, they generally work as expected,
// just be aware of this issue when enabling this option.
cssSourceMap: false
},
build: {
// 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: '/vue-element-admin/', // If you are deployed on the root path, please use '/'
/**
* 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
}
}

25
deploy.sh Normal file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env sh
# abort on errors
set -e
# build
npm run build:prod -- --report
# navigate into the build output directory
cd dist
# if you are deploying to a custom domain
# echo 'www.example.com' > CNAME
#创建.nojekyll 防止Github Pages build错误
touch .nojekyll
git init
git add -A
git commit -m 'deploy'
# if you are deploying to https://<USERNAME>.github.io/<REPO>
git push -f git@github.com:PanJiaChen/vue-element-admin.git master:gh-pages
cd -

View File

@ -1,4 +1,4 @@
import Mock from 'mockjs' const Mock = require('mockjs')
const List = [] const List = []
const count = 100 const count = 100
@ -18,7 +18,7 @@ for (let i = 0; i < count; i++) {
forecast: '@float(0, 100, 2, 2)', forecast: '@float(0, 100, 2, 2)',
importance: '@integer(1, 3)', importance: '@integer(1, 3)',
'type|1': ['CN', 'US', 'JP', 'EU'], 'type|1': ['CN', 'US', 'JP', 'EU'],
'status|1': ['published', 'draft', 'deleted'], 'status|1': ['published', 'draft'],
display_time: '@datetime', display_time: '@datetime',
comment_disabled: true, comment_disabled: true,
pageviews: '@integer(300, 5000)', pageviews: '@integer(300, 5000)',
@ -27,9 +27,9 @@ for (let i = 0; i < count; i++) {
})) }))
} }
export default [ module.exports = [
{ {
url: '/article/list', url: '/vue-element-admin/article/list',
type: 'get', type: 'get',
response: config => { response: config => {
const { importance, type, title, page = 1, limit = 20, sort } = config.query const { importance, type, title, page = 1, limit = 20, sort } = config.query
@ -58,7 +58,7 @@ export default [
}, },
{ {
url: '/article/detail', url: '/vue-element-admin/article/detail',
type: 'get', type: 'get',
response: config => { response: config => {
const { id } = config.query const { id } = config.query
@ -74,7 +74,7 @@ export default [
}, },
{ {
url: '/article/pv', url: '/vue-element-admin/article/pv',
type: 'get', type: 'get',
response: _ => { response: _ => {
return { return {
@ -92,7 +92,7 @@ export default [
}, },
{ {
url: '/article/create', url: '/vue-element-admin/article/create',
type: 'post', type: 'post',
response: _ => { response: _ => {
return { return {
@ -103,7 +103,7 @@ export default [
}, },
{ {
url: '/article/update', url: '/vue-element-admin/article/update',
type: 'post', type: 'post',
response: _ => { response: _ => {
return { return {

View File

@ -1,10 +1,10 @@
import Mock from 'mockjs' const Mock = require('mockjs')
import { param2Obj } from '../src/utils' const { param2Obj } = require('./utils')
import user from './user' const user = require('./user')
import role from './role' const role = require('./role')
import article from './article' const article = require('./article')
import search from './remote-search' const search = require('./remote-search')
const mocks = [ const mocks = [
...user, ...user,
@ -16,7 +16,7 @@ const mocks = [
// for front mock // for front mock
// please use it cautiously, it will redefine XMLHttpRequest, // please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event). // which will cause many of your third-party libraries to be invalidated(like progress event).
export function mockXHR() { function mockXHR() {
// mock patch // mock patch
// https://github.com/nuysoft/Mock/issues/300 // https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
@ -54,17 +54,7 @@ export function mockXHR() {
} }
} }
// for mock server module.exports = {
const responseFake = (url, type, respond) => { mocks,
return { mockXHR
url: new RegExp(`/mock${url}`),
type: type || 'get',
response(req, res) {
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
}
}
} }
export default mocks.map(route => {
return responseFake(route.url, route.type, route.response)
})

View File

@ -2,17 +2,21 @@ const chokidar = require('chokidar')
const bodyParser = require('body-parser') const bodyParser = require('body-parser')
const chalk = require('chalk') const chalk = require('chalk')
const path = require('path') const path = require('path')
const Mock = require('mockjs')
const mockDir = path.join(process.cwd(), 'mock') const mockDir = path.join(process.cwd(), 'mock')
function registerRoutes(app) { function registerRoutes(app) {
let mockLastIndex let mockLastIndex
const { default: mocks } = require('./index.js') const { mocks } = require('./index.js')
for (const mock of mocks) { const mocksForServer = mocks.map(route => {
return responseFake(route.url, route.type, route.response)
})
for (const mock of mocksForServer) {
app[mock.type](mock.url, mock.response) app[mock.type](mock.url, mock.response)
mockLastIndex = app._router.stack.length mockLastIndex = app._router.stack.length
} }
const mockRoutesLength = Object.keys(mocks).length const mockRoutesLength = Object.keys(mocksForServer).length
return { return {
mockRoutesLength: mockRoutesLength, mockRoutesLength: mockRoutesLength,
mockStartIndex: mockLastIndex - mockRoutesLength mockStartIndex: mockLastIndex - mockRoutesLength
@ -27,10 +31,19 @@ function unregisterRoutes() {
}) })
} }
module.exports = app => { // for mock server
// es6 polyfill const responseFake = (url, type, respond) => {
require('@babel/register') return {
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
type: type || 'get',
response(req, res) {
console.log('request invoke:' + req.path)
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
}
}
}
module.exports = app => {
// parse app.body // parse app.body
// https://expressjs.com/en/4x/api.html#req.body // https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json()) app.use(bodyParser.json())

View File

@ -1,4 +1,4 @@
import Mock from 'mockjs' const Mock = require('mockjs')
const NameList = [] const NameList = []
const count = 100 const count = 100
@ -10,10 +10,10 @@ for (let i = 0; i < count; i++) {
} }
NameList.push({ name: 'mock-Pan' }) NameList.push({ name: 'mock-Pan' })
export default [ module.exports = [
// username search // username search
{ {
url: '/search/user', url: '/vue-element-admin/search/user',
type: 'get', type: 'get',
response: config => { response: config => {
const { name } = config.query const { name } = config.query
@ -30,7 +30,7 @@ export default [
// transaction list // transaction list
{ {
url: '/transaction/list', url: '/vue-element-admin/transaction/list',
type: 'get', type: 'get',
response: _ => { response: _ => {
return { return {

View File

@ -1,6 +1,6 @@
import Mock from 'mockjs' const Mock = require('mockjs')
import { deepClone } from '../../src/utils/index.js' const { deepClone } = require('../utils')
import { asyncRoutes, constantRoutes } from './routes.js' const { asyncRoutes, constantRoutes } = require('./routes.js')
const routes = deepClone([...constantRoutes, ...asyncRoutes]) const routes = deepClone([...constantRoutes, ...asyncRoutes])
@ -35,10 +35,10 @@ const roles = [
} }
] ]
export default [ module.exports = [
// mock get all routes form server // mock get all routes form server
{ {
url: '/routes', url: '/vue-element-admin/routes',
type: 'get', type: 'get',
response: _ => { response: _ => {
return { return {
@ -50,7 +50,7 @@ export default [
// mock get all roles form server // mock get all roles form server
{ {
url: '/roles', url: '/vue-element-admin/roles',
type: 'get', type: 'get',
response: _ => { response: _ => {
return { return {
@ -62,7 +62,7 @@ export default [
// add role // add role
{ {
url: '/role', url: '/vue-element-admin/role',
type: 'post', type: 'post',
response: { response: {
code: 20000, code: 20000,
@ -74,7 +74,7 @@ export default [
// update role // update role
{ {
url: '/role/[A-Za-z0-9]', url: '/vue-element-admin/role/[A-Za-z0-9]',
type: 'put', type: 'put',
response: { response: {
code: 20000, code: 20000,
@ -86,7 +86,7 @@ export default [
// delete role // delete role
{ {
url: '/role/[A-Za-z0-9]', url: '/vue-element-admin/role/[A-Za-z0-9]',
type: 'delete', type: 'delete',
response: { response: {
code: 20000, code: 20000,

View File

@ -1,6 +1,6 @@
// Just a mock data // Just a mock data
export const constantRoutes = [ const constantRoutes = [
{ {
path: '/redirect', path: '/redirect',
component: 'layout/Layout', component: 'layout/Layout',
@ -41,7 +41,7 @@ export const constantRoutes = [
path: 'dashboard', path: 'dashboard',
component: 'views/dashboard/index', component: 'views/dashboard/index',
name: 'Dashboard', name: 'Dashboard',
meta: { title: 'Dashboard', icon: 'dashboard', affix: true } meta: { title: 'dashboard', icon: 'dashboard', affix: true }
} }
] ]
}, },
@ -53,7 +53,7 @@ export const constantRoutes = [
path: 'index', path: 'index',
component: 'views/documentation/index', component: 'views/documentation/index',
name: 'Documentation', name: 'Documentation',
meta: { title: 'Documentation', icon: 'documentation', affix: true } meta: { title: 'documentation', icon: 'documentation', affix: true }
} }
] ]
}, },
@ -66,20 +66,20 @@ export const constantRoutes = [
path: 'index', path: 'index',
component: 'views/guide/index', component: 'views/guide/index',
name: 'Guide', name: 'Guide',
meta: { title: 'Guide', icon: 'guide', noCache: true } meta: { title: 'guide', icon: 'guide', noCache: true }
} }
] ]
} }
] ]
export const asyncRoutes = [ const asyncRoutes = [
{ {
path: '/permission', path: '/permission',
component: 'layout/Layout', component: 'layout/Layout',
redirect: '/permission/index', redirect: '/permission/index',
alwaysShow: true, alwaysShow: true,
meta: { meta: {
title: 'Permission', title: 'permission',
icon: 'lock', icon: 'lock',
roles: ['admin', 'editor'] roles: ['admin', 'editor']
}, },
@ -89,7 +89,7 @@ export const asyncRoutes = [
component: 'views/permission/page', component: 'views/permission/page',
name: 'PagePermission', name: 'PagePermission',
meta: { meta: {
title: 'Page Permission', title: 'pagePermission',
roles: ['admin'] roles: ['admin']
} }
}, },
@ -98,7 +98,7 @@ export const asyncRoutes = [
component: 'views/permission/directive', component: 'views/permission/directive',
name: 'DirectivePermission', name: 'DirectivePermission',
meta: { meta: {
title: 'Directive Permission' title: 'directivePermission'
} }
}, },
{ {
@ -106,7 +106,7 @@ export const asyncRoutes = [
component: 'views/permission/role', component: 'views/permission/role',
name: 'RolePermission', name: 'RolePermission',
meta: { meta: {
title: 'Role Permission', title: 'rolePermission',
roles: ['admin'] roles: ['admin']
} }
} }
@ -121,7 +121,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: 'views/icons/index', component: 'views/icons/index',
name: 'Icons', name: 'Icons',
meta: { title: 'Icons', icon: 'icon', noCache: true } meta: { title: 'icons', icon: 'icon', noCache: true }
} }
] ]
}, },
@ -132,7 +132,7 @@ export const asyncRoutes = [
redirect: 'noRedirect', redirect: 'noRedirect',
name: 'ComponentDemo', name: 'ComponentDemo',
meta: { meta: {
title: 'Components', title: 'components',
icon: 'component' icon: 'component'
}, },
children: [ children: [
@ -140,49 +140,49 @@ export const asyncRoutes = [
path: 'tinymce', path: 'tinymce',
component: 'views/components-demo/tinymce', component: 'views/components-demo/tinymce',
name: 'TinymceDemo', name: 'TinymceDemo',
meta: { title: 'Tinymce' } meta: { title: 'tinymce' }
}, },
{ {
path: 'markdown', path: 'markdown',
component: 'views/components-demo/markdown', component: 'views/components-demo/markdown',
name: 'MarkdownDemo', name: 'MarkdownDemo',
meta: { title: 'Markdown' } meta: { title: 'markdown' }
}, },
{ {
path: 'json-editor', path: 'json-editor',
component: 'views/components-demo/json-editor', component: 'views/components-demo/json-editor',
name: 'JsonEditorDemo', name: 'JsonEditorDemo',
meta: { title: 'Json Editor' } meta: { title: 'jsonEditor' }
}, },
{ {
path: 'split-pane', path: 'split-pane',
component: 'views/components-demo/split-pane', component: 'views/components-demo/split-pane',
name: 'SplitpaneDemo', name: 'SplitpaneDemo',
meta: { title: 'SplitPane' } meta: { title: 'splitPane' }
}, },
{ {
path: 'avatar-upload', path: 'avatar-upload',
component: 'views/components-demo/avatar-upload', component: 'views/components-demo/avatar-upload',
name: 'AvatarUploadDemo', name: 'AvatarUploadDemo',
meta: { title: 'Avatar Upload' } meta: { title: 'avatarUpload' }
}, },
{ {
path: 'dropzone', path: 'dropzone',
component: 'views/components-demo/dropzone', component: 'views/components-demo/dropzone',
name: 'DropzoneDemo', name: 'DropzoneDemo',
meta: { title: 'Dropzone' } meta: { title: 'dropzone' }
}, },
{ {
path: 'sticky', path: 'sticky',
component: 'views/components-demo/sticky', component: 'views/components-demo/sticky',
name: 'StickyDemo', name: 'StickyDemo',
meta: { title: 'Sticky' } meta: { title: 'sticky' }
}, },
{ {
path: 'count-to', path: 'count-to',
component: 'views/components-demo/count-to', component: 'views/components-demo/count-to',
name: 'CountToDemo', name: 'CountToDemo',
meta: { title: 'Count To' } meta: { title: 'countTo' }
}, },
{ {
path: 'mixin', path: 'mixin',
@ -194,31 +194,31 @@ export const asyncRoutes = [
path: 'back-to-top', path: 'back-to-top',
component: 'views/components-demo/back-to-top', component: 'views/components-demo/back-to-top',
name: 'BackToTopDemo', name: 'BackToTopDemo',
meta: { title: 'Back To Top' } meta: { title: 'backToTop' }
}, },
{ {
path: 'drag-dialog', path: 'drag-dialog',
component: 'views/components-demo/drag-dialog', component: 'views/components-demo/drag-dialog',
name: 'DragDialogDemo', name: 'DragDialogDemo',
meta: { title: 'Drag Dialog' } meta: { title: 'dragDialog' }
}, },
{ {
path: 'drag-select', path: 'drag-select',
component: 'views/components-demo/drag-select', component: 'views/components-demo/drag-select',
name: 'DragSelectDemo', name: 'DragSelectDemo',
meta: { title: 'Drag Select' } meta: { title: 'dragSelect' }
}, },
{ {
path: 'dnd-list', path: 'dnd-list',
component: 'views/components-demo/dnd-list', component: 'views/components-demo/dnd-list',
name: 'DndListDemo', name: 'DndListDemo',
meta: { title: 'Dnd List' } meta: { title: 'dndList' }
}, },
{ {
path: 'drag-kanban', path: 'drag-kanban',
component: 'views/components-demo/drag-kanban', component: 'views/components-demo/drag-kanban',
name: 'DragKanbanDemo', name: 'DragKanbanDemo',
meta: { title: 'Drag Kanban' } meta: { title: 'dragKanban' }
} }
] ]
}, },
@ -228,7 +228,7 @@ export const asyncRoutes = [
redirect: 'noRedirect', redirect: 'noRedirect',
name: 'Charts', name: 'Charts',
meta: { meta: {
title: 'Charts', title: 'charts',
icon: 'chart' icon: 'chart'
}, },
children: [ children: [
@ -236,19 +236,19 @@ export const asyncRoutes = [
path: 'keyboard', path: 'keyboard',
component: 'views/charts/keyboard', component: 'views/charts/keyboard',
name: 'KeyboardChart', name: 'KeyboardChart',
meta: { title: 'Keyboard Chart', noCache: true } meta: { title: 'keyboardChart', noCache: true }
}, },
{ {
path: 'line', path: 'line',
component: 'views/charts/line', component: 'views/charts/line',
name: 'LineChart', name: 'LineChart',
meta: { title: 'Line Chart', noCache: true } meta: { title: 'lineChart', noCache: true }
}, },
{ {
path: 'mixchart', path: 'mixchart',
component: 'views/charts/mixChart', component: 'views/charts/mixChart',
name: 'MixChart', name: 'MixChart',
meta: { title: 'Mix Chart', noCache: true } meta: { title: 'mixChart', noCache: true }
} }
] ]
}, },
@ -258,7 +258,7 @@ export const asyncRoutes = [
redirect: '/nested/menu1/menu1-1', redirect: '/nested/menu1/menu1-1',
name: 'Nested', name: 'Nested',
meta: { meta: {
title: 'Nested', title: 'nested',
icon: 'nested' icon: 'nested'
}, },
children: [ children: [
@ -266,33 +266,33 @@ export const asyncRoutes = [
path: 'menu1', path: 'menu1',
component: 'views/nested/menu1/index', component: 'views/nested/menu1/index',
name: 'Menu1', name: 'Menu1',
meta: { title: 'Menu1' }, meta: { title: 'menu1' },
redirect: '/nested/menu1/menu1-1', redirect: '/nested/menu1/menu1-1',
children: [ children: [
{ {
path: 'menu1-1', path: 'menu1-1',
component: 'views/nested/menu1/menu1-1', component: 'views/nested/menu1/menu1-1',
name: 'Menu1-1', name: 'Menu1-1',
meta: { title: 'Menu1-1' } meta: { title: 'menu1-1' }
}, },
{ {
path: 'menu1-2', path: 'menu1-2',
component: 'views/nested/menu1/menu1-2', component: 'views/nested/menu1/menu1-2',
name: 'Menu1-2', name: 'Menu1-2',
redirect: '/nested/menu1/menu1-2/menu1-2-1', redirect: '/nested/menu1/menu1-2/menu1-2-1',
meta: { title: 'Menu1-2' }, meta: { title: 'menu1-2' },
children: [ children: [
{ {
path: 'menu1-2-1', path: 'menu1-2-1',
component: 'views/nested/menu1/menu1-2/menu1-2-1', component: 'views/nested/menu1/menu1-2/menu1-2-1',
name: 'Menu1-2-1', name: 'Menu1-2-1',
meta: { title: 'Menu1-2-1' } meta: { title: 'menu1-2-1' }
}, },
{ {
path: 'menu1-2-2', path: 'menu1-2-2',
component: 'views/nested/menu1/menu1-2/menu1-2-2', component: 'views/nested/menu1/menu1-2/menu1-2-2',
name: 'Menu1-2-2', name: 'Menu1-2-2',
meta: { title: 'Menu1-2-2' } meta: { title: 'menu1-2-2' }
} }
] ]
}, },
@ -300,7 +300,7 @@ export const asyncRoutes = [
path: 'menu1-3', path: 'menu1-3',
component: 'views/nested/menu1/menu1-3', component: 'views/nested/menu1/menu1-3',
name: 'Menu1-3', name: 'Menu1-3',
meta: { title: 'Menu1-3' } meta: { title: 'menu1-3' }
} }
] ]
}, },
@ -308,7 +308,7 @@ export const asyncRoutes = [
path: 'menu2', path: 'menu2',
name: 'Menu2', name: 'Menu2',
component: 'views/nested/menu2/index', component: 'views/nested/menu2/index',
meta: { title: 'Menu2' } meta: { title: 'menu2' }
} }
] ]
}, },
@ -319,7 +319,7 @@ export const asyncRoutes = [
redirect: '/example/list', redirect: '/example/list',
name: 'Example', name: 'Example',
meta: { meta: {
title: 'Example', title: 'example',
icon: 'example' icon: 'example'
}, },
children: [ children: [
@ -327,20 +327,20 @@ export const asyncRoutes = [
path: 'create', path: 'create',
component: 'views/example/create', component: 'views/example/create',
name: 'CreateArticle', name: 'CreateArticle',
meta: { title: 'Create Article', icon: 'edit' } meta: { title: 'createArticle', icon: 'edit' }
}, },
{ {
path: 'edit/:id(\\d+)', path: 'edit/:id(\\d+)',
component: 'views/example/edit', component: 'views/example/edit',
name: 'EditArticle', name: 'EditArticle',
meta: { title: 'Edit Article', noCache: true }, meta: { title: 'editArticle', noCache: true },
hidden: true hidden: true
}, },
{ {
path: 'list', path: 'list',
component: 'views/example/list', component: 'views/example/list',
name: 'ArticleList', name: 'ArticleList',
meta: { title: 'Article List', icon: 'list' } meta: { title: 'articleList', icon: 'list' }
} }
] ]
}, },
@ -353,7 +353,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: 'views/tab/index', component: 'views/tab/index',
name: 'Tab', name: 'Tab',
meta: { title: 'Tab', icon: 'tab' } meta: { title: 'tab', icon: 'tab' }
} }
] ]
}, },
@ -364,7 +364,7 @@ export const asyncRoutes = [
redirect: 'noRedirect', redirect: 'noRedirect',
name: 'ErrorPages', name: 'ErrorPages',
meta: { meta: {
title: 'Error Pages', title: 'errorPages',
icon: '404' icon: '404'
}, },
children: [ children: [
@ -372,13 +372,13 @@ export const asyncRoutes = [
path: '401', path: '401',
component: 'views/error-page/401', component: 'views/error-page/401',
name: 'Page401', name: 'Page401',
meta: { title: 'Page 401', noCache: true } meta: { title: 'page401', noCache: true }
}, },
{ {
path: '404', path: '404',
component: 'views/error-page/404', component: 'views/error-page/404',
name: 'Page404', name: 'Page404',
meta: { title: 'Page 404', noCache: true } meta: { title: 'page404', noCache: true }
} }
] ]
}, },
@ -392,7 +392,7 @@ export const asyncRoutes = [
path: 'log', path: 'log',
component: 'views/error-log/index', component: 'views/error-log/index',
name: 'ErrorLog', name: 'ErrorLog',
meta: { title: 'Error Log', icon: 'bug' } meta: { title: 'errorLog', icon: 'bug' }
} }
] ]
}, },
@ -403,7 +403,7 @@ export const asyncRoutes = [
redirect: '/excel/export-excel', redirect: '/excel/export-excel',
name: 'Excel', name: 'Excel',
meta: { meta: {
title: 'Excel', title: 'excel',
icon: 'excel' icon: 'excel'
}, },
children: [ children: [
@ -411,25 +411,25 @@ export const asyncRoutes = [
path: 'export-excel', path: 'export-excel',
component: 'views/excel/export-excel', component: 'views/excel/export-excel',
name: 'ExportExcel', name: 'ExportExcel',
meta: { title: 'Export Excel' } meta: { title: 'exportExcel' }
}, },
{ {
path: 'export-selected-excel', path: 'export-selected-excel',
component: 'views/excel/select-excel', component: 'views/excel/select-excel',
name: 'SelectExcel', name: 'SelectExcel',
meta: { title: 'Select Excel' } meta: { title: 'selectExcel' }
}, },
{ {
path: 'export-merge-header', path: 'export-merge-header',
component: 'views/excel/merge-header', component: 'views/excel/merge-header',
name: 'MergeHeader', name: 'MergeHeader',
meta: { title: 'Merge Header' } meta: { title: 'mergeHeader' }
}, },
{ {
path: 'upload-excel', path: 'upload-excel',
component: 'views/excel/upload-excel', component: 'views/excel/upload-excel',
name: 'UploadExcel', name: 'UploadExcel',
meta: { title: 'Upload Excel' } meta: { title: 'uploadExcel' }
} }
] ]
}, },
@ -439,13 +439,13 @@ export const asyncRoutes = [
component: 'layout/Layout', component: 'layout/Layout',
redirect: '/zip/download', redirect: '/zip/download',
alwaysShow: true, alwaysShow: true,
meta: { title: 'Zip', icon: 'zip' }, meta: { title: 'zip', icon: 'zip' },
children: [ children: [
{ {
path: 'download', path: 'download',
component: 'views/zip/index', component: 'views/zip/index',
name: 'ExportZip', name: 'ExportZip',
meta: { title: 'Export Zip' } meta: { title: 'exportZip' }
} }
] ]
}, },
@ -459,7 +459,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: 'views/pdf/index', component: 'views/pdf/index',
name: 'PDF', name: 'PDF',
meta: { title: 'PDF', icon: 'pdf' } meta: { title: 'pdf', icon: 'pdf' }
} }
] ]
}, },
@ -478,7 +478,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: 'views/theme/index', component: 'views/theme/index',
name: 'Theme', name: 'Theme',
meta: { title: 'Theme', icon: 'theme' } meta: { title: 'theme', icon: 'theme' }
} }
] ]
}, },
@ -492,7 +492,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: 'views/clipboard/index', component: 'views/clipboard/index',
name: 'ClipboardDemo', name: 'ClipboardDemo',
meta: { title: 'Clipboard Demo', icon: 'clipboard' } meta: { title: 'clipboardDemo', icon: 'clipboard' }
} }
] ]
}, },
@ -505,7 +505,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: 'views/i18n-demo/index', component: 'views/i18n-demo/index',
name: 'I18n', name: 'I18n',
meta: { title: 'I18n', icon: 'international' } meta: { title: 'i18n', icon: 'international' }
} }
] ]
}, },
@ -516,10 +516,15 @@ export const asyncRoutes = [
children: [ children: [
{ {
path: 'https://github.com/PanJiaChen/vue-element-admin', path: 'https://github.com/PanJiaChen/vue-element-admin',
meta: { title: 'External Link', icon: 'link' } meta: { title: 'externalLink', icon: 'link' }
} }
] ]
}, },
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }
] ]
module.exports = {
constantRoutes,
asyncRoutes
}

View File

@ -23,10 +23,10 @@ const users = {
} }
} }
export default [ module.exports = [
// user login // user login
{ {
url: '/user/login', url: '/vue-element-admin/user/login',
type: 'post', type: 'post',
response: config => { response: config => {
const { username } = config.body const { username } = config.body
@ -49,7 +49,7 @@ export default [
// get user info // get user info
{ {
url: '/user/info\.*', url: '/vue-element-admin/user/info\.*',
type: 'get', type: 'get',
response: config => { response: config => {
const { token } = config.query const { token } = config.query
@ -72,7 +72,7 @@ export default [
// user logout // user logout
{ {
url: '/user/logout', url: '/vue-element-admin/user/logout',
type: 'post', type: 'post',
response: _ => { response: _ => {
return { return {

48
mock/utils.js Normal file
View File

@ -0,0 +1,48 @@
/**
* @param {string} url
* @returns {Object}
*/
function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) {
return {}
}
const obj = {}
const searchArr = search.split('&')
searchArr.forEach(v => {
const index = v.indexOf('=')
if (index !== -1) {
const name = v.substring(0, index)
const val = v.substring(index + 1, v.length)
obj[name] = val
}
})
return obj
}
/**
* This is just a simple version of deep copy
* Has a lot of edge cases bug
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
* @param {Object} source
* @returns {Object}
*/
function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
module.exports = {
param2Obj,
deepClone
}

View File

@ -1,30 +1,91 @@
{ {
"name": "vue-element-admin", "name": "vue-element-admin",
"version": "4.2.1", "version": "4.3.1",
"description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features", "description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
"author": "Pan <panfree23@gmail.com>", "author": "Pan <panfree23@gmail.com>",
"license": "MIT",
"scripts": { "scripts": {
"dev": "vue-cli-service serve", "dev": "vue-cli-service serve",
"lint": "eslint --ext .js,.vue src",
"build:prod": "vue-cli-service build", "build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging", "build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview", "preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src", "new": "plop",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"test:unit": "jest --clearCache && vue-cli-service test:unit", "test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit", "test:ci": "npm run lint && npm run test:unit",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml", "deploy": "bash deploy.sh"
"new": "plop"
}, },
"husky": { "dependencies": {
"hooks": { "axios": "0.18.1",
"pre-commit": "lint-staged" "clipboard": "2.0.4",
} "codemirror": "5.45.0",
"core-js": "3.6.5",
"driver.js": "0.9.5",
"dropzone": "5.5.1",
"echarts": "4.2.1",
"element-ui": "2.13.2",
"file-saver": "2.0.1",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
"jsonlint": "1.6.3",
"jszip": "3.2.1",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"pinyin": "2.9.0",
"screenfull": "4.2.0",
"script-loader": "0.7.2",
"sortablejs": "1.8.4",
"tui-editor": "1.3.3",
"vue": "2.6.10",
"vue-analytics": "5.16.0",
"vue-count-to": "1.0.13",
"vue-i18n": "7.3.2",
"vue-router": "3.0.2",
"vue-splitpane": "1.0.4",
"vuedraggable": "2.20.0",
"vuex": "3.1.0",
"xlsx": "0.14.1"
}, },
"lint-staged": { "devDependencies": {
"src/**/*.{js,vue}": [ "@vue/cli-plugin-babel": "4.4.4",
"eslint --fix", "@vue/cli-plugin-eslint": "4.4.4",
"git add" "@vue/cli-plugin-unit-jest": "4.4.4",
] "@vue/cli-service": "4.4.4",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "9.5.1",
"babel-eslint": "10.1.0",
"babel-jest": "23.6.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "2.4.2",
"chokidar": "2.1.5",
"connect": "3.6.6",
"eslint": "6.7.2",
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "3.2.0",
"husky": "1.3.1",
"lint-staged": "8.1.5",
"mockjs": "1.0.1-beta3",
"plop": "2.3.0",
"runjs": "4.3.2",
"sass": "1.26.2",
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.3",
"serve-static": "1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.0",
"vue-template-compiler": "2.6.10"
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"bugs": {
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
}, },
"keywords": [ "keywords": [
"vue", "vue",
@ -35,79 +96,20 @@
"admin-template", "admin-template",
"management-system" "management-system"
], ],
"license": "MIT",
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git" "url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
}, }
"bugs": {
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
},
"dependencies": {
"axios": "0.18.1",
"clipboard": "2.0.4",
"codemirror": "5.45.0",
"driver.js": "0.9.5",
"dropzone": "5.5.1",
"echarts": "4.2.1",
"element-ui": "2.7.0",
"file-saver": "2.0.1",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
"jsonlint": "1.6.3",
"jszip": "3.2.1",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"screenfull": "4.2.0",
"showdown": "1.9.0",
"sortablejs": "1.8.4",
"tui-editor": "1.3.3",
"vue": "2.6.10",
"vue-count-to": "1.0.13",
"vue-router": "3.0.2",
"vue-splitpane": "1.0.4",
"vuedraggable": "2.20.0",
"vuex": "3.1.0",
"xlsx": "0.14.1"
},
"devDependencies": {
"@babel/core": "7.0.0",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.5.3",
"@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-plugin-unit-jest": "3.5.3",
"@vue/cli-service": "3.5.3",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "^9.5.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"babel-jest": "23.6.0",
"chalk": "2.4.2",
"chokidar": "2.1.5",
"connect": "3.6.6",
"eslint": "5.15.3",
"eslint-plugin-vue": "5.2.2",
"html-webpack-plugin": "3.2.0",
"husky": "1.3.1",
"lint-staged": "8.1.5",
"mockjs": "1.0.1-beta3",
"node-sass": "^4.9.0",
"plop": "2.3.0",
"runjs": "^4.3.2",
"sass-loader": "^7.1.0",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.0",
"vue-template-compiler": "2.6.10"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions"
]
} }

View File

@ -0,0 +1,16 @@
{{#if state}}
const state = {}
{{/if}}
{{#if mutations}}
const mutations = {}
{{/if}}
{{#if actions}}
const actions = {}
{{/if}}
export default {
namespaced: true,
{{options}}
}

View File

@ -0,0 +1,62 @@
const { notEmpty } = require('../utils.js')
module.exports = {
description: 'generate store',
prompts: [{
type: 'input',
name: 'name',
message: 'store name please',
validate: notEmpty('name')
},
{
type: 'checkbox',
name: 'blocks',
message: 'Blocks:',
choices: [{
name: 'state',
value: 'state',
checked: true
},
{
name: 'mutations',
value: 'mutations',
checked: true
},
{
name: 'actions',
value: 'actions',
checked: true
}
],
validate(value) {
if (!value.includes('state') || !value.includes('mutations')) {
return 'store require at least state and mutations'
}
return true
}
}
],
actions(data) {
const name = '{{name}}'
const { blocks } = data
const options = ['state', 'mutations']
const joinFlag = `,
`
if (blocks.length === 3) {
options.push('actions')
}
const actions = [{
type: 'add',
path: `src/store/modules/${name}.js`,
templateFile: 'plop-templates/store/index.hbs',
data: {
options: options.join(joinFlag),
state: blocks.includes('state'),
mutations: blocks.includes('mutations'),
actions: blocks.includes('actions')
}
}]
return actions
}
}

View File

@ -1,9 +1,2 @@
exports.notEmpty = name => { exports.notEmpty = name => v =>
return v => { !v || v.trim() === '' ? `${name} is required` : true
if (!v || v.trim === '') {
return `${name} is required`
} else {
return true
}
}
}

View File

@ -1,7 +1,9 @@
const viewGenerator = require('./plop-templates/view/prompt') const viewGenerator = require('./plop-templates/view/prompt')
const componentGenerator = require('./plop-templates/component/prompt') const componentGenerator = require('./plop-templates/component/prompt')
const storeGenerator = require('./plop-templates/store/prompt.js')
module.exports = function(plop) { module.exports = function(plop) {
plop.setGenerator('view', viewGenerator) plop.setGenerator('view', viewGenerator)
plop.setGenerator('component', componentGenerator) plop.setGenerator('component', componentGenerator)
plop.setGenerator('store', storeGenerator)
} }

View File

@ -9,7 +9,70 @@
<title><%= webpackConfig.name %></title> <title><%= webpackConfig.name %></title>
</head> </head>
<body> <body>
<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CE7IK5QY&placement=panjiachengithubio" id="_carbonads_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>
<style>
#carbonads {
display: flex;
max-width: 280px;
background-color: hsl(0, 0%, 98%);
box-shadow: 0 1px 4px 1px hsla(0, 0%, 0%, .1);
z-index: 2;
position: fixed;
right: 0;
bottom: 0;
}
#carbonads a {
color: inherit;
text-decoration: none;
}
#carbonads a:hover {
color: inherit;
}
#carbonads span {
position: relative;
display: block;
overflow: hidden;
}
#carbonads .carbon-wrap {
display: flex;
}
.carbon-img {
display: block;
margin: 0;
line-height: 1;
}
.carbon-img img {
display: block;
}
.carbon-text {
font-size: 13px;
padding: 10px;
line-height: 1.4;
text-align: left;
}
.carbon-poweredby {
display: block;
padding: 8px 10px;
background: repeating-linear-gradient(-45deg, transparent, transparent 5px, hsla(0, 0%, 0%, .025) 5px, hsla(0, 0%, 0%, .025) 10px) hsla(203, 11%, 95%, .4);
text-align: center;
text-transform: uppercase;
letter-spacing: .5px;
font-weight: 600;
font-size: 9px;
line-height: 1;
}
</style>

View File

@ -6,6 +6,15 @@
<script> <script>
export default { export default {
name: 'App' name: 'App',
watch: {
'$route.path': {
handler: function() {
if (document.getElementById('carbonads')) {
window._carbonads && window._carbonads.refresh()
}
}
}
}
} }
</script> </script>

View File

@ -2,7 +2,7 @@ import request from '@/utils/request'
export function fetchList(query) { export function fetchList(query) {
return request({ return request({
url: '/article/list', url: '/vue-element-admin/article/list',
method: 'get', method: 'get',
params: query params: query
}) })
@ -10,7 +10,7 @@ export function fetchList(query) {
export function fetchArticle(id) { export function fetchArticle(id) {
return request({ return request({
url: '/article/detail', url: '/vue-element-admin/article/detail',
method: 'get', method: 'get',
params: { id } params: { id }
}) })
@ -18,7 +18,7 @@ export function fetchArticle(id) {
export function fetchPv(pv) { export function fetchPv(pv) {
return request({ return request({
url: '/article/pv', url: '/vue-element-admin/article/pv',
method: 'get', method: 'get',
params: { pv } params: { pv }
}) })
@ -26,7 +26,7 @@ export function fetchPv(pv) {
export function createArticle(data) { export function createArticle(data) {
return request({ return request({
url: '/article/create', url: '/vue-element-admin/article/create',
method: 'post', method: 'post',
data data
}) })
@ -34,7 +34,7 @@ export function createArticle(data) {
export function updateArticle(data) { export function updateArticle(data) {
return request({ return request({
url: '/article/update', url: '/vue-element-admin/article/update',
method: 'post', method: 'post',
data data
}) })

View File

@ -2,7 +2,7 @@ import request from '@/utils/request'
export function searchUser(name) { export function searchUser(name) {
return request({ return request({
url: '/search/user', url: '/vue-element-admin/search/user',
method: 'get', method: 'get',
params: { name } params: { name }
}) })
@ -10,7 +10,7 @@ export function searchUser(name) {
export function transactionList(query) { export function transactionList(query) {
return request({ return request({
url: '/transaction/list', url: '/vue-element-admin/transaction/list',
method: 'get', method: 'get',
params: query params: query
}) })

View File

@ -2,21 +2,21 @@ import request from '@/utils/request'
export function getRoutes() { export function getRoutes() {
return request({ return request({
url: '/routes', url: '/vue-element-admin/routes',
method: 'get' method: 'get'
}) })
} }
export function getRoles() { export function getRoles() {
return request({ return request({
url: '/roles', url: '/vue-element-admin/roles',
method: 'get' method: 'get'
}) })
} }
export function addRole(data) { export function addRole(data) {
return request({ return request({
url: '/role', url: '/vue-element-admin/role',
method: 'post', method: 'post',
data data
}) })
@ -24,7 +24,7 @@ export function addRole(data) {
export function updateRole(id, data) { export function updateRole(id, data) {
return request({ return request({
url: `/role/${id}`, url: `/vue-element-admin/role/${id}`,
method: 'put', method: 'put',
data data
}) })
@ -32,7 +32,7 @@ export function updateRole(id, data) {
export function deleteRole(id) { export function deleteRole(id) {
return request({ return request({
url: `/role/${id}`, url: `/vue-element-admin/role/${id}`,
method: 'delete' method: 'delete'
}) })
} }

View File

@ -2,7 +2,7 @@ import request from '@/utils/request'
export function login(data) { export function login(data) {
return request({ return request({
url: '/user/login', url: '/vue-element-admin/user/login',
method: 'post', method: 'post',
data data
}) })
@ -10,7 +10,7 @@ export function login(data) {
export function getInfo(token) { export function getInfo(token) {
return request({ return request({
url: '/user/info', url: '/vue-element-admin/user/info',
method: 'get', method: 'get',
params: { token } params: { token }
}) })
@ -18,7 +18,7 @@ export function getInfo(token) {
export function logout() { export function logout() {
return request({ return request({
url: '/user/logout', url: '/vue-element-admin/user/logout',
method: 'post' method: 'post'
}) })
} }

View File

@ -0,0 +1,62 @@
<template>
<div id="codefund" />
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
loadSuccess: true
}
},
watch: {
'$route.path': {
handler: function(val, oldVal) {
this.getCodefund()
}
}
},
mounted() {
this.getCodefund()
},
methods: {
getCodefund() {
if (this.$isServer) return
const codefundId = this.isGitee()
? '111'
: '96'
const template = 'horizontal'
axios.get(`https://codefund.io/properties/${codefundId}/funder.html?template=${template}`)
.then(function(response) {
document.getElementById('codefund').innerHTML = response.data
})
},
isGitee() {
const origin = window.location.origin
if (origin.includes('gitee.io')) {
return true
}
return false
},
loadError(oError) {
this.loadSuccess = false
}
}
}
</script>
<style lang="scss">
.cf-wrapper {
margin: 0 !important;
}
.fixed-header+#codefund {
margin-top: 50px;
}
.hasTagsView {
.fixed-header+#codefund {
margin-top: 84px;
}
}
</style>

View File

@ -2,14 +2,17 @@
<el-breadcrumb class="app-breadcrumb" separator="/"> <el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb"> <transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path"> <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">{{ item.meta.title }}</span> <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a> {{ generateTitle(item.meta.title) }}
</span>
<a v-else @click.prevent="handleLink(item)">{{ generateTitle(item.meta.title) }}</a>
</el-breadcrumb-item> </el-breadcrumb-item>
</transition-group> </transition-group>
</el-breadcrumb> </el-breadcrumb>
</template> </template>
<script> <script>
import { generateTitle } from '@/utils/i18n'
import pathToRegexp from 'path-to-regexp' import pathToRegexp from 'path-to-regexp'
export default { export default {
@ -31,13 +34,14 @@ export default {
this.getBreadcrumb() this.getBreadcrumb()
}, },
methods: { methods: {
generateTitle,
getBreadcrumb() { getBreadcrumb() {
// only show routes with meta.title // only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title) let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0] const first = matched[0]
if (!this.isDashboard(first)) { if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched) matched = [{ path: '/dashboard', meta: { title: 'dashboard' }}].concat(matched)
} }
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)

View File

@ -3,32 +3,54 @@ import { debounce } from '@/utils'
export default { export default {
data() { data() {
return { return {
$_sidebarElm: null $_sidebarElm: null,
$_resizeHandler: null
} }
}, },
mounted() { mounted() {
this.__resizeHandler = debounce(() => { this.initListener()
if (this.chart) { },
this.chart.resize() activated() {
} if (!this.$_resizeHandler) {
}, 100) // avoid duplication init
window.addEventListener('resize', this.__resizeHandler) this.initListener()
}
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] // when keep-alive chart activated, auto resize
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) this.resize()
}, },
beforeDestroy() { beforeDestroy() {
window.removeEventListener('resize', this.__resizeHandler) this.destroyListener()
},
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) deactivated() {
this.destroyListener()
}, },
methods: { methods: {
// use $_ for mixins properties // use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_sidebarResizeHandler(e) { $_sidebarResizeHandler(e) {
if (e.propertyName === 'width') { if (e.propertyName === 'width') {
this.__resizeHandler() this.$_resizeHandler()
} }
},
initListener() {
this.$_resizeHandler = debounce(() => {
this.resize()
}, 100)
window.addEventListener('resize', this.$_resizeHandler)
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
destroyListener() {
window.removeEventListener('resize', this.$_resizeHandler)
this.$_resizeHandler = null
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
},
resize() {
const { chart } = this
chart && chart.resize()
} }
} }
} }

View File

@ -48,14 +48,18 @@ export default {
} }
</script> </script>
<style scoped> <style lang="scss" scoped>
.drag-select >>> .sortable-ghost { .drag-select {
opacity: .8; ::v-deep {
color: #fff!important; .sortable-ghost {
background: #42b983!important; opacity: .8;
} color: #fff !important;
background: #42b983 !important;
}
.drag-select >>> .el-tag { .el-tag {
cursor: pointer; cursor: pointer;
}
}
} }
</style> </style>

View File

@ -22,6 +22,7 @@
// make search results more in line with expectations // make search results more in line with expectations
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import path from 'path' import path from 'path'
import i18n from '@/lang'
export default { export default {
name: 'HeaderSearch', name: 'HeaderSearch',
@ -37,13 +38,26 @@ export default {
computed: { computed: {
routes() { routes() {
return this.$store.getters.permission_routes return this.$store.getters.permission_routes
},
lang() {
return this.$store.getters.language
},
supportPinyinSearch() {
return this.$store.state.settings.supportPinyinSearch
} }
}, },
watch: { watch: {
lang() {
this.searchPool = this.generateRoutes(this.routes)
},
routes() { routes() {
this.searchPool = this.generateRoutes(this.routes) this.searchPool = this.generateRoutes(this.routes)
}, },
searchPool(list) { searchPool(list) {
// Support pinyin search
if (this.lang === 'zh' && this.supportPinyinSearch) {
this.addPinyinField(list)
}
this.initFuse(list) this.initFuse(list)
}, },
show(value) { show(value) {
@ -58,6 +72,23 @@ export default {
this.searchPool = this.generateRoutes(this.routes) this.searchPool = this.generateRoutes(this.routes)
}, },
methods: { methods: {
async addPinyinField(list) {
const { default: pinyin } = await import('pinyin')
if (Array.isArray(list)) {
list.forEach(element => {
const title = element.title
if (Array.isArray(title)) {
title.forEach(v => {
v = pinyin(v, {
style: pinyin.STYLE_NORMAL
}).join('')
element.pinyinTitle = v
})
}
})
return list
}
},
click() { click() {
this.show = !this.show this.show = !this.show
if (this.show) { if (this.show) {
@ -88,6 +119,9 @@ export default {
keys: [{ keys: [{
name: 'title', name: 'title',
weight: 0.7 weight: 0.7
}, {
name: 'pinyinTitle',
weight: 0.3
}, { }, {
name: 'path', name: 'path',
weight: 0.3 weight: 0.3
@ -98,26 +132,23 @@ export default {
// And generate the internationalized title // And generate the internationalized title
generateRoutes(routes, basePath = '/', prefixTitle = []) { generateRoutes(routes, basePath = '/', prefixTitle = []) {
let res = [] let res = []
for (const router of routes) { for (const router of routes) {
// skip hidden router // skip hidden router
if (router.hidden) { continue } if (router.hidden) { continue }
const data = { const data = {
path: path.resolve(basePath, router.path), path: path.resolve(basePath, router.path),
title: [...prefixTitle] title: [...prefixTitle]
} }
if (router.meta && router.meta.title) { if (router.meta && router.meta.title) {
data.title = [...data.title, router.meta.title] // generate internationalized title
const i18ntitle = i18n.t(`route.${router.meta.title}`)
data.title = [...data.title, i18ntitle]
if (router.redirect !== 'noRedirect') { if (router.redirect !== 'noRedirect') {
// only push the routes with title // only push the routes with title
// special case: need to exclude parent router without redirect // special case: need to exclude parent router without redirect
res.push(data) res.push(data)
} }
} }
// recursive child routes // recursive child routes
if (router.children) { if (router.children) {
const tempRoutes = this.generateRoutes(router.children, data.path, data.title) const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
@ -142,13 +173,11 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.header-search { .header-search {
font-size: 0 !important; font-size: 0 !important;
.search-icon { .search-icon {
cursor: pointer; cursor: pointer;
font-size: 18px; font-size: 18px;
vertical-align: middle; vertical-align: middle;
} }
.header-search-select { .header-search-select {
font-size: 18px; font-size: 18px;
transition: width 0.2s; transition: width 0.2s;
@ -159,7 +188,7 @@ export default {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
/deep/ .el-input__inner { ::v-deep .el-input__inner {
border-radius: 0; border-radius: 0;
border: 0; border: 0;
padding-left: 0; padding-left: 0;
@ -169,7 +198,6 @@ export default {
vertical-align: middle; vertical-align: middle;
} }
} }
&.show { &.show {
.header-search-select { .header-search-select {
width: 210px; width: 210px;

View File

@ -248,6 +248,7 @@ export default {
// //
isSupported, isSupported,
// //
// eslint-disable-next-line no-prototype-builtins
isSupportTouch: document.hasOwnProperty('ontouchstart'), isSupportTouch: document.hasOwnProperty('ontouchstart'),
// //
step: 1, // 1 2 3 step: 1, // 1 2 3

View File

@ -54,19 +54,24 @@ export default {
} }
</script> </script>
<style scoped> <style lang="scss" scoped>
.json-editor{ .json-editor {
height: 100%; height: 100%;
position: relative; position: relative;
}
.json-editor >>> .CodeMirror { ::v-deep {
height: auto; .CodeMirror {
min-height: 300px; height: auto;
} min-height: 300px;
.json-editor >>> .CodeMirror-scroll{ }
min-height: 300px;
} .CodeMirror-scroll {
.json-editor >>> .cm-s-rubyblue span.cm-string { min-height: 300px;
color: #F08047; }
.cm-s-rubyblue span.cm-string {
color: #F08047;
}
}
} }
</style> </style>

View File

@ -0,0 +1,41 @@
<template>
<el-dropdown trigger="click" class="international" @command="handleSetLanguage">
<div>
<svg-icon class-name="international-icon" icon-class="language" />
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :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-item :disabled="language==='ja'" command="ja">
日本語
</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('app/setLanguage', lang)
this.$message({
message: 'Switch Language Success',
type: 'success'
})
}
}
}
</script>

View File

@ -12,7 +12,7 @@ import Editor from 'tui-editor'
import defaultOptions from './default-options' import defaultOptions from './default-options'
export default { export default {
name: 'MarddownEditor', name: 'MarkdownEditor',
props: { props: {
value: { value: {
type: String, type: String,

View File

@ -44,6 +44,7 @@ $t: .1s;
width: 250px; width: 250px;
position: relative; position: relative;
z-index: 1; z-index: 1;
height: auto!important;
&-title { &-title {
width: 100%; width: 100%;
display: block; display: block;
@ -65,10 +66,12 @@ $t: .1s;
position: absolute; position: absolute;
width: 100%; width: 100%;
background: #e0e0e0; background: #e0e0e0;
color: #000;
line-height: 60px; line-height: 60px;
height: 60px; height: 60px;
cursor: pointer; cursor: pointer;
font-size: 20px; font-size: 18px;
overflow: hidden;
opacity: 1; opacity: 1;
transition: transform 0.28s ease; transition: transform 0.28s ease;
&:hover { &:hover {
@ -90,7 +93,7 @@ $t: .1s;
.share-dropdown-menu-item { .share-dropdown-menu-item {
@for $i from 1 through $n { @for $i from 1 through $n {
&:nth-of-type(#{$i}) { &:nth-of-type(#{$i}) {
transition-delay: ($n - $i)*$t; transition-delay: ($n - $i)*$t;
transform: translate3d(0, ($i - 1)*60px, 0); transform: translate3d(0, ($i - 1)*60px, 0);
} }
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" /> <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners"> <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :href="iconName" /> <use :xlink:href="iconName" />
</svg> </svg>
</template> </template>

View File

@ -104,7 +104,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.editor-slide-upload { .editor-slide-upload {
margin-bottom: 20px; margin-bottom: 20px;
/deep/ .el-upload--picture-card { ::v-deep .el-upload--picture-card {
width: 100%; width: 100%;
} }
} }

View File

@ -71,6 +71,9 @@ export default {
} }
}, },
computed: { computed: {
language() {
return this.languageTypeList[this.$store.getters.language]
},
containerWidth() { containerWidth() {
const width = this.width const width = this.width
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'` if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
@ -85,6 +88,10 @@ export default {
this.$nextTick(() => this.$nextTick(() =>
window.tinymce.get(this.tinymceId).setContent(val || '')) window.tinymce.get(this.tinymceId).setContent(val || ''))
} }
},
language() {
this.destroyTinymce()
this.$nextTick(() => this.initTinymce())
} }
}, },
mounted() { mounted() {
@ -115,8 +122,8 @@ export default {
initTinymce() { initTinymce() {
const _this = this const _this = this
window.tinymce.init({ window.tinymce.init({
language: this.language,
selector: `#${this.tinymceId}`, selector: `#${this.tinymceId}`,
language: this.languageTypeList['en'],
height: this.height, height: this.height,
body_class: 'panel-body ', body_class: 'panel-body ',
object_resizing: false, object_resizing: false,
@ -147,7 +154,11 @@ export default {
editor.on('FullscreenStateChanged', (e) => { editor.on('FullscreenStateChanged', (e) => {
_this.fullscreen = e.state _this.fullscreen = e.state
}) })
} },
// it will try to keep these URLs intact
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
convert_urls: false
// //
// images_dataimg_filter(img) { // images_dataimg_filter(img) {
// setTimeout(() => { // setTimeout(() => {
@ -200,37 +211,43 @@ export default {
window.tinymce.get(this.tinymceId).getContent() window.tinymce.get(this.tinymceId).getContent()
}, },
imageSuccessCBK(arr) { imageSuccessCBK(arr) {
const _this = this arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`))
arr.forEach(v => {
window.tinymce.get(_this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`)
})
} }
} }
} }
</script> </script>
<style scoped> <style lang="scss" scoped>
.tinymce-container { .tinymce-container {
position: relative; position: relative;
line-height: normal; line-height: normal;
} }
.tinymce-container>>>.mce-fullscreen {
z-index: 10000; .tinymce-container {
::v-deep {
.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: 4px; right: 4px;
top: 4px; top: 4px;
/*z-index: 2005;*/ /*z-index: 2005;*/
} }
.fullscreen .editor-custom-btn-container { .fullscreen .editor-custom-btn-container {
z-index: 10000; z-index: 10000;
position: fixed; position: fixed;
} }
.editor-upload-btn { .editor-upload-btn {
display: inline-block; display: inline-block;
} }

View File

@ -1,11 +1,11 @@
import store from '@/store' import store from '@/store'
export default { function checkPermission(el, binding) {
inserted(el, binding, vnode) { const { value } = binding
const { value } = binding const roles = store.getters && store.getters.roles
const roles = store.getters && store.getters.roles
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array) {
if (value.length > 0) {
const permissionRoles = value const permissionRoles = value
const hasPermission = roles.some(role => { const hasPermission = roles.some(role => {
@ -15,8 +15,17 @@ export default {
if (!hasPermission) { if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el) el.parentNode && el.parentNode.removeChild(el)
} }
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`)
} }
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`)
}
}
export default {
inserted(el, binding) {
checkPermission(el, binding)
},
update(el, binding) {
checkPermission(el, binding)
} }
} }

1
src/icons/svg/donate.svg Normal file
View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1547533298036" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2337" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><defs><style type="text/css"></style></defs><path d="M799.835567 409.343969c-7.124258 0-17.45658 1.125637-26.720571 0-51.567469 15.005762-88.169085 59.042721-106.883309 106.749256-23.420409-29.151947-62.499449-52.284807-106.883309-53.374628-5.526877 1.088798-15.553231 2.187829-26.720572 0-75.839269 22.039969-132.216277 117.15628-120.243594 200.153576 32.484855 177.732937 359.762737 234.369865 360.730784 253.528204-0.968048 15.081487 15.32094-79.065753 66.802452-160.122861 51.226708-80.33977 121.281227-110.282732 106.883309-226.841402-13.123902-72.211649-76.882018-120.089076-146.96519-120.092145zM345.58176 903.057487c-0.069585 0-0.159636-0.097214-0.241501-0.152473-0.11461 0.100284-0.048095 0.152473 0.241501 0.152473z" p-id="2338"></path><path d="M733.033116 129.128963c-115.27442-8.884344-205.739804 94.891184-253.848499 173.466773-28.197202-65.910129-108.804055-148.775418-173.685761-146.778948-111.029746-0.483001-231.309156 76.278267-240.48719 213.497489C54.354955 565.682643 190.689017 610.455359 265.419022 729.590713c49.859571 75.175143 75.201749 170.110329 79.921237 173.314301 1.494027-1.316995 37.989219-12.054547 120.485095-53.222155-58.424644-36.85028-103.33346-92.574419-120.243594-160.122861-15.33015-119.972419 42.422182-261.34831 146.965189-280.216029 27.203572-11.225669 95.869465-34.045397 160.325475 26.686802 29.960359-66.275449 71.678506-82.142835 120.243595-93.405343 9.8176-1.951445 23.158443-3.786233 40.080858 0 53.009308-3.783163 105.278765 18.951631 146.965189 53.374628-2.736321-9.131985-1.047866-20.48352 0-26.686802 7.274684-149.553131-88.768743-228.409107-227.12895-240.184291z" p-id="2339"></path></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

176
src/lang/en.js Normal file
View File

@ -0,0 +1,176 @@
export default {
route: {
dashboard: 'Dashboard',
documentation: 'Documentation',
guide: 'Guide',
permission: 'Permission',
pagePermission: 'Page Permission',
rolePermission: 'Role Permission',
directivePermission: 'Directive Permission',
icons: 'Icons',
components: 'Components',
tinymce: 'Tinymce',
markdown: 'Markdown',
jsonEditor: 'JSON Editor',
dndList: 'Dnd List',
splitPane: 'SplitPane',
avatarUpload: 'Avatar Upload',
dropzone: 'Dropzone',
sticky: 'Sticky',
countTo: 'Count To',
componentMixin: 'Mixin',
backToTop: 'Back To Top',
dragDialog: 'Drag Dialog',
dragSelect: 'Drag Select',
dragKanban: 'Drag Kanban',
charts: 'Charts',
keyboardChart: 'Keyboard Chart',
lineChart: 'Line Chart',
mixChart: 'Mix Chart',
example: 'Example',
nested: 'Nested Routes',
menu1: 'Menu 1',
'menu1-1': 'Menu 1-1',
'menu1-2': 'Menu 1-2',
'menu1-2-1': 'Menu 1-2-1',
'menu1-2-2': 'Menu 1-2-2',
'menu1-3': 'Menu 1-3',
menu2: 'Menu 2',
Table: 'Table',
dynamicTable: 'Dynamic Table',
dragTable: 'Drag Table',
inlineEditTable: 'Inline Edit',
complexTable: 'Complex Table',
tab: 'Tab',
form: 'Form',
createArticle: 'Create Article',
editArticle: 'Edit Article',
articleList: 'Article List',
errorPages: 'Error Pages',
page401: '401',
page404: '404',
errorLog: 'Error Log',
excel: 'Excel',
exportExcel: 'Export Excel',
selectExcel: 'Export Selected',
mergeHeader: 'Merge Header',
uploadExcel: 'Upload Excel',
zip: 'Zip',
pdf: 'PDF',
exportZip: 'Export Zip',
theme: 'Theme',
clipboardDemo: 'Clipboard',
i18n: 'I18n',
externalLink: 'External Link',
donate: 'Donate',
profile: 'Profile'
},
navbar: {
dashboard: 'Dashboard',
github: 'Github',
logOut: 'Log Out',
profile: 'Profile',
theme: 'Theme',
size: 'Global Size'
},
login: {
title: 'Login Form',
logIn: 'Login',
username: 'Username',
password: 'Password',
any: 'any',
thirdparty: 'Or connect with',
thirdpartyTips: 'Can not be simulated on local, so please combine you own business simulation! ! !'
},
documentation: {
documentation: 'Documentation',
github: 'Github Repository'
},
permission: {
addRole: 'New Role',
editPermission: 'Edit',
roles: 'Your roles',
switchRoles: 'Switch roles',
tips: 'In some cases, using v-permission will have no effect. For example: Element-UI el-tab or el-table-column and other scenes that dynamically render dom. You can only do this with v-if.',
delete: 'Delete',
confirm: 'Confirm',
cancel: 'Cancel'
},
guide: {
description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ',
button: 'Show Guide'
},
components: {
documentation: 'Documentation',
tinymceTips: 'Rich text is a core feature of the management backend, but at the same time it is a place with lots of pits. In the process of selecting rich texts, I also took a lot of detours. The common rich texts on the market have been basically used, and I finally chose Tinymce. See the more detailed rich text comparison and introduction.',
dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.',
stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.',
backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner',
backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally',
imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.'
},
table: {
dynamicTips1: 'Fixed header, sorted by header order',
dynamicTips2: 'Not fixed header, sorted by click order',
dragTips1: 'The default order',
dragTips2: 'The after dragging order',
title: 'Title',
importance: 'Imp',
type: 'Type',
remark: 'Remark',
search: 'Search',
add: 'Add',
export: 'Export',
reviewer: 'reviewer',
id: 'ID',
date: 'Date',
author: 'Author',
readings: 'Readings',
status: 'Status',
actions: 'Actions',
edit: 'Edit',
publish: 'Publish',
draft: 'Draft',
delete: 'Delete',
cancel: 'Cancel',
confirm: 'Confirm'
},
example: {
warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details'
},
errorLog: {
tips: 'Please click the bug icon in the upper right corner',
description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',
documentation: 'Document introduction'
},
excel: {
export: 'Export',
selectedExport: 'Export Selected Items',
placeholder: 'Please enter the file name (default excel-list)'
},
zip: {
export: 'Export',
placeholder: 'Please enter the file name (default file)'
},
pdf: {
tips: 'Here we use window.print() to implement the feature of downloading PDF.'
},
theme: {
change: 'Change Theme',
documentation: 'Theme documentation',
tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.'
},
tagsView: {
refresh: 'Refresh',
close: 'Close',
closeOthers: 'Close Others',
closeAll: 'Close All'
},
settings: {
title: 'Page style setting',
theme: 'Theme Color',
tagsView: 'Open Tags-View',
fixedHeader: 'Fixed Header',
sidebarLogo: 'Sidebar Logo'
}
}

176
src/lang/es.js Executable file
View File

@ -0,0 +1,176 @@
export default {
route: {
dashboard: 'Panel de control',
documentation: 'Documentación',
guide: 'Guía',
permission: 'Permisos',
rolePermission: 'Permisos de rol',
pagePermission: 'Permisos de la página',
directivePermission: 'Permisos de la directiva',
icons: 'Iconos',
components: 'Componentes',
tinymce: 'Tinymce',
markdown: 'Markdown',
jsonEditor: 'Editor JSON',
dndList: 'Lista Dnd',
splitPane: 'Panel dividido',
avatarUpload: 'Subir avatar',
dropzone: 'Subir ficheros',
sticky: 'Sticky',
countTo: 'CountTo',
componentMixin: 'Mixin',
backToTop: 'Ir arriba',
dragDialog: 'Drag Dialog',
dragSelect: 'Drag Select',
dragKanban: 'Drag Kanban',
charts: 'Gráficos',
keyboardChart: 'Keyboard Chart',
lineChart: 'Gráfico de líneas',
mixChart: 'Mix Chart',
example: 'Ejemplo',
nested: 'Rutas anidadass',
menu1: 'Menu 1',
'menu1-1': 'Menu 1-1',
'menu1-2': 'Menu 1-2',
'menu1-2-1': 'Menu 1-2-1',
'menu1-2-2': 'Menu 1-2-2',
'menu1-3': 'Menu 1-3',
menu2: 'Menu 2',
Table: 'Tabla',
dynamicTable: 'Tabla dinámica',
dragTable: 'Arrastrar tabla',
inlineEditTable: 'Editor',
complexTable: 'Complex Table',
tab: 'Pestaña',
form: 'Formulario',
createArticle: 'Crear artículo',
editArticle: 'Editar artículo',
articleList: 'Listado de artículos',
errorPages: 'Páginas de error',
page401: '401',
page404: '404',
errorLog: 'Registro de errores',
excel: 'Excel',
exportExcel: 'Exportar a Excel',
selectExcel: 'Export seleccionado',
mergeHeader: 'Merge Header',
uploadExcel: 'Subir Excel',
zip: 'Zip',
pdf: 'PDF',
exportZip: 'Exportar a Zip',
theme: 'Tema',
clipboardDemo: 'Clipboard',
i18n: 'I18n',
externalLink: 'Enlace externo',
donate: 'Donate',
profile: 'Profile'
},
navbar: {
logOut: 'Salir',
dashboard: 'Panel de control',
github: 'Github',
theme: 'Tema',
size: 'Tamaño global',
profile: 'Profile'
},
login: {
title: 'Formulario de acceso',
logIn: 'Acceso',
username: 'Usuario',
password: 'Contraseña',
any: 'nada',
thirdparty: 'Conectar con',
thirdpartyTips: 'No se puede simular en local, así que combine su propia simulación de negocios. ! !'
},
documentation: {
documentation: 'Documentación',
github: 'Repositorio Github'
},
permission: {
addRole: 'Nuevo rol',
editPermission: 'Permiso de edición',
roles: 'Tus permisos',
switchRoles: 'Cambiar permisos',
tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.',
delete: 'Borrar',
confirm: 'Confirmar',
cancel: 'Cancelar'
},
guide: {
description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ',
button: 'Ver guía'
},
components: {
documentation: 'Documentación',
tinymceTips: 'Rich text editor is a core part of management system, but at the same time is a place with lots of problems. In the process of selecting rich texts, I also walked a lot of detours. The common rich text editors in the market are basically used, and the finally chose Tinymce. See documentation for more detailed rich text editor comparisons and introductions.',
dropzoneTips: 'Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone.',
stickyTips: 'when the page is scrolled to the preset position will be sticky on the top.',
backToTopTips1: 'When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner',
backToTopTips2: 'You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally',
imageUploadTips: 'Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version.'
},
table: {
dynamicTips1: 'Fixed header, sorted by header order',
dynamicTips2: 'Not fixed header, sorted by click order',
dragTips1: 'Orden por defecto',
dragTips2: 'The after dragging order',
title: 'Título',
importance: 'Importancia',
type: 'Tipo',
remark: 'Remark',
search: 'Buscar',
add: 'Añadir',
export: 'Exportar',
reviewer: 'reviewer',
id: 'ID',
date: 'Fecha',
author: 'Autor',
readings: 'Lector',
status: 'Estado',
actions: 'Acciones',
edit: 'Editar',
publish: 'Publicar',
draft: 'Draft',
delete: 'Eliminar',
cancel: 'Cancelar',
confirm: 'Confirmar'
},
example: {
warning: 'Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all pages directly. See details'
},
errorLog: {
tips: 'Please click the bug icon in the upper right corner',
description: 'Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions.',
documentation: 'Documento de introducción'
},
excel: {
export: 'Exportar',
selectedExport: 'Exportar seleccionados',
placeholder: 'Por favor escribe un nombre de fichero'
},
zip: {
export: 'Exportar',
placeholder: 'Por favor escribe un nombre de fichero'
},
pdf: {
tips: 'Here we use window.print() to implement the feature of downloading pdf.'
},
theme: {
change: 'Cambiar tema',
documentation: 'Documentación del tema',
tips: 'Tips: It is different from the theme-pick on the navbar is two different skinning methods, each with different application scenarios. Refer to the documentation for details.'
},
tagsView: {
refresh: 'Actualizar',
close: 'Cerrar',
closeOthers: 'Cerrar otros',
closeAll: 'Cerrar todos'
},
settings: {
title: 'Page style setting',
theme: 'Theme Color',
tagsView: 'Open Tags-View',
fixedHeader: 'Fixed Header',
sidebarLogo: 'Sidebar Logo'
}
}

55
src/lang/index.js Normal file
View File

@ -0,0 +1,55 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import Cookies from 'js-cookie'
import elementEnLocale from 'element-ui/lib/locale/lang/en' // element-ui lang
import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'// element-ui lang
import elementEsLocale from 'element-ui/lib/locale/lang/es'// element-ui lang
import elementJaLocale from 'element-ui/lib/locale/lang/ja'// element-ui lang
import enLocale from './en'
import zhLocale from './zh'
import esLocale from './es'
import jaLocale from './ja'
Vue.use(VueI18n)
const messages = {
en: {
...enLocale,
...elementEnLocale
},
zh: {
...zhLocale,
...elementZhLocale
},
es: {
...esLocale,
...elementEsLocale
},
ja: {
...jaLocale,
...elementJaLocale
}
}
export function getLanguage() {
const chooseLanguage = Cookies.get('language')
if (chooseLanguage) return chooseLanguage
// if has not choose language
const language = (navigator.language || navigator.browserLanguage).toLowerCase()
const locales = Object.keys(messages)
for (const locale of locales) {
if (language.indexOf(locale) > -1) {
return locale
}
}
return 'en'
}
const i18n = new VueI18n({
// set locale
// options: en | zh | es
locale: getLanguage(),
// set locale messages
messages
})
export default i18n

175
src/lang/ja.js Normal file
View File

@ -0,0 +1,175 @@
export default {
route: {
dashboard: 'トップ',
documentation: 'ドキュメント',
guide: 'ガイド',
permission: '権限',
rolePermission: '権限ロール',
pagePermission: 'ページ権限',
directivePermission: 'ディレクティブ権限',
icons: 'アイコン',
components: 'コンポーネント',
tinymce: 'TinyMCE',
markdown: 'Markdown',
jsonEditor: 'JSON Editor',
dndList: 'Drag-And-Drop',
splitPane: 'パネル',
avatarUpload: 'アバターアップロード',
dropzone: 'Dropzone',
sticky: 'Sticky',
countTo: 'Count To',
componentMixin: 'コンポーネントMixin',
backToTop: 'BackToTop',
dragDialog: 'Drag Dialog',
dragSelect: 'Drag Select',
dragKanban: 'Drag 看板',
charts: 'チャート',
keyboardChart: 'Keyboardチャート',
lineChart: 'Lineチャート',
mixChart: 'Mixチャート',
example: 'Example',
nested: 'Nested Routes',
menu1: 'メニュー1',
'menu1-1': 'メニュー 1-1',
'menu1-2': 'メニュー 1-2',
'menu1-2-1': 'メニュー 1-2-1',
'menu1-2-2': 'メニュー 1-2-2',
'menu1-3': 'メニュー 1-3',
menu2: 'メニュー 2',
Table: 'Table',
dynamicTable: '可変 Table',
dragTable: 'Drag Table',
inlineEditTable: 'Inline Edit Table',
complexTable: 'Complex Table',
tab: 'Tab',
form: 'フォーム',
createArticle: '投稿作成',
editArticle: '投稿編集',
articleList: '投稿リスト',
errorPages: 'エラーページ',
page401: '401',
page404: '404',
errorLog: 'エラーログ',
excel: 'Excel',
exportExcel: '一括エクスポート',
selectExcel: '複数選択エクスポート',
mergeHeader: 'ヘッダーマージ',
uploadExcel: 'アップロード',
zip: 'Zip',
pdf: 'PDF',
exportZip: 'Export Zip',
theme: 'テーマ変更',
clipboardDemo: 'Clipboard',
i18n: '多言語',
externalLink: '外部リンク',
profile: 'プロフィール'
},
navbar: {
dashboard: 'トップ',
github: 'GitHub',
logOut: 'ログアウト',
profile: 'プロフィール',
theme: 'テーマ変更',
size: '画面サイズ'
},
login: {
title: 'ユーザログイン',
logIn: 'ログイン',
username: 'ユーザ名',
password: 'パスワード',
any: 'password',
thirdparty: '外部IDでログイン',
thirdpartyTips: 'ローカル環境ではログインできません。実装が必要です。'
},
documentation: {
documentation: 'ドキュメント',
github: 'Github Link'
},
permission: {
addRole: 'ロール追加',
editPermission: 'ロール変更',
roles: 'ロール',
switchRoles: 'ロール切替',
tips: 'v-permissionは使えない時があります。例えば: Element-UI の el-tab、 el-table-column 及び他の dom。v-ifを使う必要があります。',
delete: '削除',
confirm: '確認',
cancel: 'キャンセル'
},
guide: {
description: 'ガイドは各機能の説明です。',
button: 'ガイドを見る'
},
components: {
documentation: 'ドキュメント',
tinymceTips: 'tinymceは管理画面に重要な機能ですが、その同時に落とし穴がありあす。tinymceを使う道のりが大変でした。Tinymceを使う時に各自のプロジェクト状況で判断が必要です。ドキュメントはこちら',
dropzoneTips: 'Third partyのパッケージを使わず、独自の実装しています。詳細は @/components/Dropzone',
stickyTips: 'ページの指定位置へスクロールした場合、表示されます。',
backToTopTips1: 'トップへスクロールが表示されます。',
backToTopTips2: 'ボタンのスタイルはカスタマイズできます。例えば、show/hide、height、position。 またはElementのel-tooltipを使って、ツールチップを実装できます。',
imageUploadTips: 'mockjsは使えないため、カスタマイズしています。公式の最新バージョンを使ってください。'
},
table: {
dynamicTips1: '先頭は固定、最後に追加',
dynamicTips2: '戦後に追加せず、指定列に追加',
dragTips1: 'デフォルト順番',
dragTips2: 'Drag後の順番',
title: 'タイトル',
importance: '重要',
type: 'タイプ',
remark: '評価',
search: '検索',
add: '追加',
export: 'エクスポート',
reviewer: 'レビュアー',
id: '番号',
date: '日時',
author: '作成者',
readings: '閲覧数',
status: 'ステータス',
actions: '操作',
edit: '編集',
publish: '公開',
draft: '下書き',
delete: 'キャンセル',
cancel: 'キャンセル',
confirm: '確認'
},
example: {
warning: '新規作成と編集画面は keep-alive を使えないです。keep-alive の include はrouteのキャッシュは使えないです。そのため、component name を使ってキャッシュさせるようにします。このようなキャッシュ機能を作りたい場合localStorageを使う手があります。もしくは keep-alive の includeを使って、全ページキャッシュする方法はあります。'
},
errorLog: {
tips: '右上のbugアイコンをクリックしてください。',
description: '管理画面はspaを使う場合が多い、ユーザ体現向上はできますが、想定外エラーが発生する場合があります。Vueはそのエラーハンドリング機能を提供し、エラーレポートができます。',
documentation: 'ドキュメント'
},
excel: {
export: 'エクスポート',
selectedExport: 'エクスポート対象を選択してください。',
placeholder: 'ファイル名を入力してください。'
},
zip: {
export: 'エクスポート',
placeholder: 'ファイル名を入力してください。'
},
pdf: {
tips: 'window.print() を使ってPDFダウンロードしています。'
},
theme: {
change: 'テーマ切替',
documentation: 'ドキュメント',
tips: 'Tips: テーマの切り替え方法はnavbarのtheme-pickと異なります、使い方はドキュメントを確認してください。'
},
tagsView: {
refresh: '更新',
close: '閉じる',
closeOthers: 'その他閉じる',
closeAll: 'すべて閉じる'
},
settings: {
title: 'システムテーマ',
theme: 'テーマ色',
tagsView: 'Tags-View 開く',
fixedHeader: 'Fixed Header',
sidebarLogo: 'Sidebar Logo'
}
}

176
src/lang/zh.js Normal file
View File

@ -0,0 +1,176 @@
export default {
route: {
dashboard: '首页',
documentation: '文档',
guide: '引导页',
permission: '权限测试页',
rolePermission: '角色权限',
pagePermission: '页面权限',
directivePermission: '指令权限',
icons: '图标',
components: '组件',
tinymce: '富文本编辑器',
markdown: 'Markdown',
jsonEditor: 'JSON 编辑器',
dndList: '列表拖拽',
splitPane: 'Splitpane',
avatarUpload: '头像上传',
dropzone: 'Dropzone',
sticky: 'Sticky',
countTo: 'Count To',
componentMixin: '小组件',
backToTop: '返回顶部',
dragDialog: '拖拽 Dialog',
dragSelect: '拖拽 Select',
dragKanban: '可拖拽看板',
charts: '图表',
keyboardChart: '键盘图表',
lineChart: '折线图',
mixChart: '混合图表',
example: '综合实例',
nested: '路由嵌套',
menu1: '菜单1',
'menu1-1': '菜单 1-1',
'menu1-2': '菜单 1-2',
'menu1-2-1': '菜单 1-2-1',
'menu1-2-2': '菜单 1-2-2',
'menu1-3': '菜单 1-3',
menu2: '菜单 2',
Table: 'Table',
dynamicTable: '动态 Table',
dragTable: '拖拽 Table',
inlineEditTable: 'Table 内编辑',
complexTable: '综合 Table',
tab: 'Tab',
form: '表单',
createArticle: '创建文章',
editArticle: '编辑文章',
articleList: '文章列表',
errorPages: '错误页面',
page401: '401',
page404: '404',
errorLog: '错误日志',
excel: 'Excel',
exportExcel: '导出 Excel',
selectExcel: '导出 已选择项',
mergeHeader: '导出 多级表头',
uploadExcel: '上传 Excel',
zip: 'Zip',
pdf: 'PDF',
exportZip: 'Export Zip',
theme: '换肤',
clipboardDemo: 'Clipboard',
i18n: '国际化',
externalLink: '外链',
donate: '打赏',
profile: '个人中心'
},
navbar: {
dashboard: '首页',
github: '项目地址',
logOut: '退出登录',
profile: '个人中心',
theme: '换肤',
size: '布局大小'
},
login: {
title: '系统登录',
logIn: '登录',
username: '账号',
password: '密码',
any: '随便填',
thirdparty: '第三方登录',
thirdpartyTips: '本地不能模拟,请结合自己业务进行模拟!!!'
},
documentation: {
documentation: '文档',
github: 'Github 地址'
},
permission: {
addRole: '新增角色',
editPermission: '编辑权限',
roles: '你的权限',
switchRoles: '切换权限',
tips: '在某些情况下,不适合使用 v-permission。例如Element-UI 的 el-tab 或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。',
delete: '删除',
confirm: '确定',
cancel: '取消'
},
guide: {
description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于',
button: '打开引导'
},
components: {
documentation: '文档',
tinymceTips: '富文本是管理后台一个核心的功能但同时又是一个有很多坑的地方。在选择富文本的过程中我也走了不少的弯路市面上常见的富文本都基本用过了最终权衡了一下选择了Tinymce。更详细的富文本比较和介绍见',
dropzoneTips: '由于我司业务有特殊需求,而且要传七牛 所以没用第三方,选择了自己封装。代码非常的简单,具体代码你可以在这里看到 @/components/Dropzone',
stickyTips: '当页面滚动到预设的位置会吸附在顶部',
backToTopTips1: '页面滚动到指定位置会在右下角出现返回顶部按钮',
backToTopTips2: '可自定义按钮的样式、show/hide、出现的高度、返回的位置 如需文字提示可在外部使用Element的el-tooltip元素',
imageUploadTips: '由于我在使用时它只有vue@1版本而且和mockjs不兼容所以自己改造了一下如果大家要使用的话优先还是使用官方版本。'
},
table: {
dynamicTips1: '固定表头, 按照表头顺序排序',
dynamicTips2: '不固定表头, 按照点击顺序排序',
dragTips1: '默认顺序',
dragTips2: '拖拽后顺序',
title: '标题',
importance: '重要性',
type: '类型',
remark: '点评',
search: '搜索',
add: '添加',
export: '导出',
reviewer: '审核人',
id: '序号',
date: '时间',
author: '作者',
readings: '阅读数',
status: '状态',
actions: '操作',
edit: '编辑',
publish: '发布',
draft: '草稿',
delete: '删除',
cancel: '取 消',
confirm: '确 定'
},
example: {
warning: '创建和编辑页面是不能被 keep-alive 缓存的因为keep-alive 的 include 目前不支持根据路由来缓存,所以目前都是基于 component name 来进行缓存的。如果你想类似的实现缓存效果,可以使用 localStorage 等浏览器缓存方案。或者不要使用 keep-alive 的 include直接缓存所有页面。详情见'
},
errorLog: {
tips: '请点击右上角bug小图标',
description: '现在的管理后台基本都是spa的形式了它增强了用户体验但同时也会增加页面出问题的可能性可能一个小小的疏忽就导致整个页面的死锁。好在 Vue 官网提供了一个方法来捕获处理异常,你可以在其中进行错误处理或者异常上报。',
documentation: '文档介绍'
},
excel: {
export: '导出',
selectedExport: '导出已选择项',
placeholder: '请输入文件名(默认excel-list)'
},
zip: {
export: '导出',
placeholder: '请输入文件名(默认file)'
},
pdf: {
tips: '这里使用 window.print() 来实现下载pdf的功能'
},
theme: {
change: '换肤',
documentation: '换肤文档',
tips: 'Tips: 它区别于 navbar 上的 theme-pick, 是两种不同的换肤方法,各自有不同的应用场景,具体请参考文档。'
},
tagsView: {
refresh: '刷新',
close: '关闭',
closeOthers: '关闭其它',
closeAll: '关闭所有'
},
settings: {
title: '系统布局配置',
theme: '主题色',
tagsView: '开启 Tags-View',
fixedHeader: '固定 Header',
sidebarLogo: '侧边栏 Logo'
}
}

View File

@ -25,7 +25,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.app-main { .app-main {
/* 50= navbar 50 */ /* 50= navbar 50 */
min-height: calc(100vh - 50px); min-height: calc(100vh - 50px - 43px);
width: 100%; width: 100%;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
@ -38,7 +38,7 @@ export default {
.hasTagsView { .hasTagsView {
.app-main { .app-main {
/* 84 = navbar + tags-view = 50 + 34 */ /* 84 = navbar + tags-view = 50 + 34 */
min-height: calc(100vh - 84px); min-height: calc(100vh - 84px - 43px);
} }
.fixed-header+.app-main { .fixed-header+.app-main {

View File

@ -12,10 +12,12 @@
<screenfull id="screenfull" class="right-menu-item hover-effect" /> <screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="Global Size" effect="dark" placement="bottom"> <el-tooltip :content="$t('navbar.size')" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" /> <size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
<lang-select class="right-menu-item hover-effect" />
</template> </template>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click"> <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
@ -25,19 +27,25 @@
</div> </div>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<router-link to="/profile/index"> <router-link to="/profile/index">
<el-dropdown-item>Profile</el-dropdown-item> <el-dropdown-item>
{{ $t('navbar.profile') }}
</el-dropdown-item>
</router-link> </router-link>
<router-link to="/"> <router-link to="/">
<el-dropdown-item>Dashboard</el-dropdown-item> <el-dropdown-item>
{{ $t('navbar.dashboard') }}
</el-dropdown-item>
</router-link> </router-link>
<a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/"> <a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">
<el-dropdown-item>Github</el-dropdown-item> <el-dropdown-item>
{{ $t('navbar.github') }}
</el-dropdown-item>
</a> </a>
<a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
<el-dropdown-item>Docs</el-dropdown-item> <el-dropdown-item>Docs</el-dropdown-item>
</a> </a>
<el-dropdown-item divided> <el-dropdown-item divided @click.native="logout">
<span style="display:block;" @click="logout">Log Out</span> <span style="display:block;">{{ $t('navbar.logOut') }}</span>
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
@ -52,6 +60,7 @@ import Hamburger from '@/components/Hamburger'
import ErrorLog from '@/components/ErrorLog' import ErrorLog from '@/components/ErrorLog'
import Screenfull from '@/components/Screenfull' import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect' import SizeSelect from '@/components/SizeSelect'
import LangSelect from '@/components/LangSelect'
import Search from '@/components/HeaderSearch' import Search from '@/components/HeaderSearch'
export default { export default {
@ -61,6 +70,7 @@ export default {
ErrorLog, ErrorLog,
Screenfull, Screenfull,
SizeSelect, SizeSelect,
LangSelect,
Search Search
}, },
computed: { computed: {

View File

@ -1,27 +1,39 @@
<template> <template>
<div class="drawer-container"> <div class="drawer-container">
<div> <div>
<h3 class="drawer-title">Page style setting</h3> <h3 class="drawer-title">{{ $t('settings.title') }}</h3>
<div class="drawer-item"> <div class="drawer-item">
<span>Theme Color</span> <span>{{ $t('settings.theme') }}</span>
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" /> <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
</div> </div>
<div class="drawer-item"> <div class="drawer-item">
<span>Open Tags-View</span> <span>{{ $t('settings.tagsView') }}</span>
<el-switch v-model="tagsView" class="drawer-switch" /> <el-switch v-model="tagsView" class="drawer-switch" />
</div> </div>
<div class="drawer-item"> <div class="drawer-item">
<span>Fixed Header</span> <span>{{ $t('settings.fixedHeader') }}</span>
<el-switch v-model="fixedHeader" class="drawer-switch" /> <el-switch v-model="fixedHeader" class="drawer-switch" />
</div> </div>
<div class="drawer-item"> <div class="drawer-item">
<span>Sidebar Logo</span> <span>{{ $t('settings.sidebarLogo') }}</span>
<el-switch v-model="sidebarLogo" class="drawer-switch" /> <el-switch v-model="sidebarLogo" class="drawer-switch" />
</div> </div>
<a v-if="isShowJob" href="https://panjiachen.github.io/vue-element-admin-site/zh/job/" target="_blank" class="job-link">
<el-alert
title="部门目前非常缺人!有兴趣的可以点击了解详情。坐标: 字节跳动"
type="success"
:closable="false"
/>
</a>
<div v-if="lang === 'zh'" class="drawer-item">
<span>菜单支持拼音搜索</span>
<el-switch v-model="supportPinyinSearch" class="drawer-switch" />
</div>
</div> </div>
</div> </div>
@ -36,6 +48,9 @@ export default {
return {} return {}
}, },
computed: { computed: {
isShowJob() {
return this.$store.getters.language === 'zh'
},
fixedHeader: { fixedHeader: {
get() { get() {
return this.$store.state.settings.fixedHeader return this.$store.state.settings.fixedHeader
@ -68,6 +83,20 @@ export default {
value: val value: val
}) })
} }
},
supportPinyinSearch: {
get() {
return this.$store.state.settings.supportPinyinSearch
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'supportPinyinSearch',
value: val
})
}
},
lang() {
return this.$store.getters.language
} }
}, },
methods: { methods: {
@ -104,5 +133,13 @@ export default {
.drawer-switch { .drawer-switch {
float: right float: right
} }
.job-link{
display: block;
position: absolute;
width: 100%;
left: 0;
bottom: 0;
}
} }
</style> </style>

View File

@ -17,7 +17,11 @@ export default {
const vnodes = [] const vnodes = []
if (icon) { if (icon) {
vnodes.push(<svg-icon icon-class={icon}/>) if (icon.includes('el-icon')) {
vnodes.push(<i class={[icon, 'sub-el-icon']} />)
} else {
vnodes.push(<svg-icon icon-class={icon}/>)
}
} }
if (title) { if (title) {
@ -27,3 +31,11 @@ export default {
} }
} }
</script> </script>
<style scoped>
.sub-el-icon {
color: currentColor;
width: 1em;
height: 1em;
}
</style>

View File

@ -1,7 +1,5 @@
<template> <template>
<!-- eslint-disable vue/require-component-is --> <component :is="type" v-bind="linkProps(to)">
<component v-bind="linkProps(to)">
<slot /> <slot />
</component> </component>
</template> </template>
@ -16,19 +14,28 @@ export default {
required: true required: true
} }
}, },
computed: {
isExternal() {
return isExternal(this.to)
},
type() {
if (this.isExternal) {
return 'a'
}
return 'router-link'
}
},
methods: { methods: {
linkProps(url) { linkProps(to) {
if (isExternal(url)) { if (this.isExternal) {
return { return {
is: 'a', href: to,
href: url,
target: '_blank', target: '_blank',
rel: 'noopener' rel: 'noopener'
} }
} }
return { return {
is: 'router-link', to: to
to: url
} }
} }
} }

View File

@ -1,16 +1,16 @@
<template> <template>
<div v-if="!item.hidden" class="menu-wrapper"> <div v-if="!item.hidden">
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="generateTitle(onlyOneChild.meta.title)" />
</el-menu-item> </el-menu-item>
</app-link> </app-link>
</template> </template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title"> <template slot="title">
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="generateTitle(item.meta.title)" />
</template> </template>
<sidebar-item <sidebar-item
v-for="child in item.children" v-for="child in item.children"
@ -26,6 +26,7 @@
<script> <script>
import path from 'path' import path from 'path'
import { generateTitle } from '@/utils/i18n'
import { isExternal } from '@/utils/validate' import { isExternal } from '@/utils/validate'
import Item from './Item' import Item from './Item'
import AppLink from './Link' import AppLink from './Link'
@ -89,7 +90,9 @@ export default {
return this.basePath return this.basePath
} }
return path.resolve(this.basePath, routePath) return path.resolve(this.basePath, routePath)
} },
generateTitle
} }
} }
</script> </script>

View File

@ -19,12 +19,21 @@ export default {
return this.$refs.scrollContainer.$refs.wrap return this.$refs.scrollContainer.$refs.wrap
} }
}, },
mounted() {
this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
},
beforeDestroy() {
this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
},
methods: { methods: {
handleScroll(e) { handleScroll(e) {
const eventDelta = e.wheelDelta || -e.deltaY * 40 const eventDelta = e.wheelDelta || -e.deltaY * 40
const $scrollWrapper = this.scrollWrapper const $scrollWrapper = this.scrollWrapper
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4 $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
}, },
emitScroll() {
this.$emit('scroll')
},
moveToTarget(currentTag) { moveToTarget(currentTag) {
const $container = this.$refs.scrollContainer.$el const $container = this.$refs.scrollContainer.$el
const $containerWidth = $container.offsetWidth const $containerWidth = $container.offsetWidth
@ -73,7 +82,7 @@ export default {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
/deep/ { ::v-deep {
.el-scrollbar__bar { .el-scrollbar__bar {
bottom: 0px; bottom: 0px;
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<div id="tags-view-container" class="tags-view-container"> <div id="tags-view-container" class="tags-view-container">
<scroll-pane ref="scrollPane" class="tags-view-wrapper"> <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
<router-link <router-link
v-for="tag in visitedViews" v-for="tag in visitedViews"
ref="tag" ref="tag"
@ -12,21 +12,22 @@
@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''" @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
@contextmenu.prevent.native="openMenu(tag,$event)" @contextmenu.prevent.native="openMenu(tag,$event)"
> >
{{ tag.title }} {{ generateTitle(tag.title) }}
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
</router-link> </router-link>
</scroll-pane> </scroll-pane>
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"> <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)">Refresh</li> <li @click="refreshSelectedTag(selectedTag)">{{ $t('tagsView.refresh') }}</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li> <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">{{ $t('tagsView.close') }}</li>
<li @click="closeOthersTags">Close Others</li> <li @click="closeOthersTags">{{ $t('tagsView.closeOthers') }}</li>
<li @click="closeAllTags(selectedTag)">Close All</li> <li @click="closeAllTags(selectedTag)">{{ $t('tagsView.closeAll') }}</li>
</ul> </ul>
</div> </div>
</template> </template>
<script> <script>
import ScrollPane from './ScrollPane' import ScrollPane from './ScrollPane'
import { generateTitle } from '@/utils/i18n'
import path from 'path' import path from 'path'
export default { export default {
@ -66,6 +67,7 @@ export default {
this.addTags() this.addTags()
}, },
methods: { methods: {
generateTitle, // generateTitle by vue-i18n
isActive(route) { isActive(route) {
return route.path === this.$route.path return route.path === this.$route.path
}, },
@ -189,6 +191,9 @@ export default {
}, },
closeMenu() { closeMenu() {
this.visible = false this.visible = false
},
handleScroll() {
this.closeMenu()
} }
} }
} }

View File

@ -13,27 +13,36 @@ import App from './App'
import store from './store' import store from './store'
import router from './router' import router from './router'
import i18n from './lang' // internationalization
import './icons' // icon import './icons' // icon
import './permission' // permission control import './permission' // permission control
import './utils/error-log' // error log import './utils/error-log' // error log
import * as filters from './filters' // global filters import * as filters from './filters' // global filters
import VueAnalytics from 'vue-analytics'
Vue.use(VueAnalytics, {
id: 'UA-109340118-1',
router
})
/** /**
* If you don't want to use mock-server * If you don't want to use mock-server
* you want to use MockJs for mock api * you want to use MockJs for mock api
* you can execute: mockXHR() * you can execute: mockXHR()
* *
* Currently MockJs will be used in the production environment, * Currently MockJs will be used in the production environment,
* please remove it before going online! ! ! * please remove it before going online ! ! !
*/ */
import { mockXHR } from '../mock'
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
const { mockXHR } = require('../mock')
mockXHR() mockXHR()
} }
Vue.use(Element, { Vue.use(Element, {
size: Cookies.get('size') || 'medium' // set element-ui default size size: Cookies.get('size') || 'medium', // set element-ui default size
i18n: (key, value) => i18n.t(key, value)
}) })
// register global utility filters // register global utility filters
@ -47,5 +56,6 @@ new Vue({
el: '#app', el: '#app',
router, router,
store, store,
i18n,
render: h => h(App) render: h => h(App)
}) })

View File

@ -24,7 +24,7 @@ router.beforeEach(async(to, from, next) => {
if (to.path === '/login') { if (to.path === '/login') {
// if is logged in, redirect to the home page // if is logged in, redirect to the home page
next({ path: '/' }) next({ path: '/' })
NProgress.done() NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
} else { } else {
// determine whether the user has obtained his permission roles through getInfo // determine whether the user has obtained his permission roles through getInfo
const hasRoles = store.getters.roles && store.getters.roles.length > 0 const hasRoles = store.getters.roles && store.getters.roles.length > 0

View File

@ -25,7 +25,7 @@ import nestedRouter from './modules/nested'
* meta : { * meta : {
roles: ['admin','editor'] control the page roles (you can set multiple roles) roles: ['admin','editor'] control the page roles (you can set multiple roles)
title: 'title' the name show in sidebar and breadcrumb (recommend set) title: 'title' the name show in sidebar and breadcrumb (recommend set)
icon: 'svg-name' the icon show in the sidebar icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
noCache: true if set true, the page will no be cached(default is false) noCache: true if set true, the page will no be cached(default is false)
affix: true if set true, the tag will affix in the tags-view affix: true if set true, the tag will affix in the tags-view
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) breadcrumb: false if set false, the item will hidden in breadcrumb(default is true)
@ -45,7 +45,7 @@ export const constantRoutes = [
hidden: true, hidden: true,
children: [ children: [
{ {
path: '/redirect/:path*', path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index') component: () => import('@/views/redirect/index')
} }
] ]
@ -71,15 +71,15 @@ export const constantRoutes = [
hidden: true hidden: true
}, },
{ {
path: '/', path: '',
component: Layout, component: Layout,
redirect: '/dashboard', redirect: 'dashboard',
children: [ children: [
{ {
path: 'dashboard', path: 'dashboard',
component: () => import('@/views/dashboard/index'), component: () => import('@/views/dashboard/index'),
name: 'Dashboard', name: 'Dashboard',
meta: { title: 'Dashboard', icon: 'dashboard', affix: true } meta: { title: 'dashboard', icon: 'dashboard', affix: true }
} }
] ]
}, },
@ -91,7 +91,7 @@ export const constantRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/documentation/index'), component: () => import('@/views/documentation/index'),
name: 'Documentation', name: 'Documentation',
meta: { title: 'Documentation', icon: 'documentation', affix: true } meta: { title: 'documentation', icon: 'documentation', affix: true }
} }
] ]
}, },
@ -104,7 +104,7 @@ export const constantRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/guide/index'), component: () => import('@/views/guide/index'),
name: 'Guide', name: 'Guide',
meta: { title: 'Guide', icon: 'guide', noCache: true } meta: { title: 'guide', icon: 'guide', noCache: true }
} }
] ]
}, },
@ -118,7 +118,7 @@ export const constantRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/profile/index'), component: () => import('@/views/profile/index'),
name: 'Profile', name: 'Profile',
meta: { title: 'Profile', icon: 'user', noCache: true } meta: { title: 'profile', icon: 'user', noCache: true }
} }
] ]
} }
@ -136,7 +136,7 @@ export const asyncRoutes = [
alwaysShow: true, // will always show the root menu alwaysShow: true, // will always show the root menu
name: 'Permission', name: 'Permission',
meta: { meta: {
title: 'Permission', title: 'permission',
icon: 'lock', icon: 'lock',
roles: ['admin', 'editor'] // you can set roles in root nav roles: ['admin', 'editor'] // you can set roles in root nav
}, },
@ -146,7 +146,7 @@ export const asyncRoutes = [
component: () => import('@/views/permission/page'), component: () => import('@/views/permission/page'),
name: 'PagePermission', name: 'PagePermission',
meta: { meta: {
title: 'Page Permission', title: 'pagePermission',
roles: ['admin'] // or you can only set roles in sub nav roles: ['admin'] // or you can only set roles in sub nav
} }
}, },
@ -155,7 +155,7 @@ export const asyncRoutes = [
component: () => import('@/views/permission/directive'), component: () => import('@/views/permission/directive'),
name: 'DirectivePermission', name: 'DirectivePermission',
meta: { meta: {
title: 'Directive Permission' title: 'directivePermission'
// if do not set roles, means: this page does not require permission // if do not set roles, means: this page does not require permission
} }
}, },
@ -164,7 +164,7 @@ export const asyncRoutes = [
component: () => import('@/views/permission/role'), component: () => import('@/views/permission/role'),
name: 'RolePermission', name: 'RolePermission',
meta: { meta: {
title: 'Role Permission', title: 'rolePermission',
roles: ['admin'] roles: ['admin']
} }
} }
@ -179,7 +179,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/icons/index'), component: () => import('@/views/icons/index'),
name: 'Icons', name: 'Icons',
meta: { title: 'Icons', icon: 'icon', noCache: true } meta: { title: 'icons', icon: 'icon', noCache: true }
} }
] ]
}, },
@ -196,28 +196,28 @@ export const asyncRoutes = [
redirect: '/example/list', redirect: '/example/list',
name: 'Example', name: 'Example',
meta: { meta: {
title: 'Example', title: 'example',
icon: 'example' icon: 'el-icon-s-help'
}, },
children: [ children: [
{ {
path: 'create', path: 'create',
component: () => import('@/views/example/create'), component: () => import('@/views/example/create'),
name: 'CreateArticle', name: 'CreateArticle',
meta: { title: 'Create Article', icon: 'edit' } meta: { title: 'createArticle', icon: 'edit' }
}, },
{ {
path: 'edit/:id(\\d+)', path: 'edit/:id(\\d+)',
component: () => import('@/views/example/edit'), component: () => import('@/views/example/edit'),
name: 'EditArticle', name: 'EditArticle',
meta: { title: 'Edit Article', noCache: true, activeMenu: '/example/list' }, meta: { title: 'editArticle', noCache: true, activeMenu: '/example/list' },
hidden: true hidden: true
}, },
{ {
path: 'list', path: 'list',
component: () => import('@/views/example/list'), component: () => import('@/views/example/list'),
name: 'ArticleList', name: 'ArticleList',
meta: { title: 'Article List', icon: 'list' } meta: { title: 'articleList', icon: 'list' }
} }
] ]
}, },
@ -230,7 +230,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/tab/index'), component: () => import('@/views/tab/index'),
name: 'Tab', name: 'Tab',
meta: { title: 'Tab', icon: 'tab' } meta: { title: 'tab', icon: 'tab' }
} }
] ]
}, },
@ -241,7 +241,7 @@ export const asyncRoutes = [
redirect: 'noRedirect', redirect: 'noRedirect',
name: 'ErrorPages', name: 'ErrorPages',
meta: { meta: {
title: 'Error Pages', title: 'errorPages',
icon: '404' icon: '404'
}, },
children: [ children: [
@ -249,13 +249,13 @@ export const asyncRoutes = [
path: '401', path: '401',
component: () => import('@/views/error-page/401'), component: () => import('@/views/error-page/401'),
name: 'Page401', name: 'Page401',
meta: { title: '401', noCache: true } meta: { title: 'page401', noCache: true }
}, },
{ {
path: '404', path: '404',
component: () => import('@/views/error-page/404'), component: () => import('@/views/error-page/404'),
name: 'Page404', name: 'Page404',
meta: { title: '404', noCache: true } meta: { title: 'page404', noCache: true }
} }
] ]
}, },
@ -268,7 +268,7 @@ export const asyncRoutes = [
path: 'log', path: 'log',
component: () => import('@/views/error-log/index'), component: () => import('@/views/error-log/index'),
name: 'ErrorLog', name: 'ErrorLog',
meta: { title: 'Error Log', icon: 'bug' } meta: { title: 'errorLog', icon: 'bug' }
} }
] ]
}, },
@ -279,7 +279,7 @@ export const asyncRoutes = [
redirect: '/excel/export-excel', redirect: '/excel/export-excel',
name: 'Excel', name: 'Excel',
meta: { meta: {
title: 'Excel', title: 'excel',
icon: 'excel' icon: 'excel'
}, },
children: [ children: [
@ -287,25 +287,25 @@ export const asyncRoutes = [
path: 'export-excel', path: 'export-excel',
component: () => import('@/views/excel/export-excel'), component: () => import('@/views/excel/export-excel'),
name: 'ExportExcel', name: 'ExportExcel',
meta: { title: 'Export Excel' } meta: { title: 'exportExcel' }
}, },
{ {
path: 'export-selected-excel', path: 'export-selected-excel',
component: () => import('@/views/excel/select-excel'), component: () => import('@/views/excel/select-excel'),
name: 'SelectExcel', name: 'SelectExcel',
meta: { title: 'Export Selected' } meta: { title: 'selectExcel' }
}, },
{ {
path: 'export-merge-header', path: 'export-merge-header',
component: () => import('@/views/excel/merge-header'), component: () => import('@/views/excel/merge-header'),
name: 'MergeHeader', name: 'MergeHeader',
meta: { title: 'Merge Header' } meta: { title: 'mergeHeader' }
}, },
{ {
path: 'upload-excel', path: 'upload-excel',
component: () => import('@/views/excel/upload-excel'), component: () => import('@/views/excel/upload-excel'),
name: 'UploadExcel', name: 'UploadExcel',
meta: { title: 'Upload Excel' } meta: { title: 'uploadExcel' }
} }
] ]
}, },
@ -316,13 +316,13 @@ export const asyncRoutes = [
redirect: '/zip/download', redirect: '/zip/download',
alwaysShow: true, alwaysShow: true,
name: 'Zip', name: 'Zip',
meta: { title: 'Zip', icon: 'zip' }, meta: { title: 'zip', icon: 'zip' },
children: [ children: [
{ {
path: 'download', path: 'download',
component: () => import('@/views/zip/index'), component: () => import('@/views/zip/index'),
name: 'ExportZip', name: 'ExportZip',
meta: { title: 'Export Zip' } meta: { title: 'exportZip' }
} }
] ]
}, },
@ -336,7 +336,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/pdf/index'), component: () => import('@/views/pdf/index'),
name: 'PDF', name: 'PDF',
meta: { title: 'PDF', icon: 'pdf' } meta: { title: 'pdf', icon: 'pdf' }
} }
] ]
}, },
@ -354,7 +354,7 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/theme/index'), component: () => import('@/views/theme/index'),
name: 'Theme', name: 'Theme',
meta: { title: 'Theme', icon: 'theme' } meta: { title: 'theme', icon: 'theme' }
} }
] ]
}, },
@ -367,7 +367,20 @@ export const asyncRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/clipboard/index'), component: () => import('@/views/clipboard/index'),
name: 'ClipboardDemo', name: 'ClipboardDemo',
meta: { title: 'Clipboard', icon: 'clipboard' } meta: { title: 'clipboardDemo', icon: 'clipboard' }
}
]
},
{
path: '/i18n',
component: Layout,
children: [
{
path: 'index',
component: () => import('@/views/i18n-demo/index'),
name: 'I18n',
meta: { title: 'i18n', icon: 'international' }
} }
] ]
}, },
@ -378,12 +391,22 @@ export const asyncRoutes = [
children: [ children: [
{ {
path: 'https://github.com/PanJiaChen/vue-element-admin', path: 'https://github.com/PanJiaChen/vue-element-admin',
meta: { title: 'External Link', icon: 'link' } meta: { title: 'externalLink', icon: 'link' }
}
]
},
{
path: 'donate',
component: Layout,
children: [
{
path: 'https://panjiachen.gitee.io/vue-element-admin-site/zh/donate/',
meta: { title: 'donate', icon: 'donate' }
} }
] ]
}, },
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true } { path: '*', redirect: '/404', hidden: true }
] ]

View File

@ -8,7 +8,7 @@ const chartsRouter = {
redirect: 'noRedirect', redirect: 'noRedirect',
name: 'Charts', name: 'Charts',
meta: { meta: {
title: 'Charts', title: 'charts',
icon: 'chart' icon: 'chart'
}, },
children: [ children: [
@ -16,19 +16,19 @@ const chartsRouter = {
path: 'keyboard', path: 'keyboard',
component: () => import('@/views/charts/keyboard'), component: () => import('@/views/charts/keyboard'),
name: 'KeyboardChart', name: 'KeyboardChart',
meta: { title: 'Keyboard Chart', noCache: true } meta: { title: 'keyboardChart', noCache: true }
}, },
{ {
path: 'line', path: 'line',
component: () => import('@/views/charts/line'), component: () => import('@/views/charts/line'),
name: 'LineChart', name: 'LineChart',
meta: { title: 'Line Chart', noCache: true } meta: { title: 'lineChart', noCache: true }
}, },
{ {
path: 'mix-chart', path: 'mix-chart',
component: () => import('@/views/charts/mix-chart'), component: () => import('@/views/charts/mix-chart'),
name: 'MixChart', name: 'MixChart',
meta: { title: 'Mix Chart', noCache: true } meta: { title: 'mixChart', noCache: true }
} }
] ]
} }

View File

@ -8,7 +8,7 @@ const componentsRouter = {
redirect: 'noRedirect', redirect: 'noRedirect',
name: 'ComponentDemo', name: 'ComponentDemo',
meta: { meta: {
title: 'Components', title: 'components',
icon: 'component' icon: 'component'
}, },
children: [ children: [
@ -16,85 +16,85 @@ const componentsRouter = {
path: 'tinymce', path: 'tinymce',
component: () => import('@/views/components-demo/tinymce'), component: () => import('@/views/components-demo/tinymce'),
name: 'TinymceDemo', name: 'TinymceDemo',
meta: { title: 'Tinymce' } meta: { title: 'tinymce' }
}, },
{ {
path: 'markdown', path: 'markdown',
component: () => import('@/views/components-demo/markdown'), component: () => import('@/views/components-demo/markdown'),
name: 'MarkdownDemo', name: 'MarkdownDemo',
meta: { title: 'Markdown' } meta: { title: 'markdown' }
}, },
{ {
path: 'json-editor', path: 'json-editor',
component: () => import('@/views/components-demo/json-editor'), component: () => import('@/views/components-demo/json-editor'),
name: 'JsonEditorDemo', name: 'JsonEditorDemo',
meta: { title: 'JSON Editor' } meta: { title: 'jsonEditor' }
}, },
{ {
path: 'split-pane', path: 'split-pane',
component: () => import('@/views/components-demo/split-pane'), component: () => import('@/views/components-demo/split-pane'),
name: 'SplitpaneDemo', name: 'SplitpaneDemo',
meta: { title: 'SplitPane' } meta: { title: 'splitPane' }
}, },
{ {
path: 'avatar-upload', path: 'avatar-upload',
component: () => import('@/views/components-demo/avatar-upload'), component: () => import('@/views/components-demo/avatar-upload'),
name: 'AvatarUploadDemo', name: 'AvatarUploadDemo',
meta: { title: 'Upload' } meta: { title: 'avatarUpload' }
}, },
{ {
path: 'dropzone', path: 'dropzone',
component: () => import('@/views/components-demo/dropzone'), component: () => import('@/views/components-demo/dropzone'),
name: 'DropzoneDemo', name: 'DropzoneDemo',
meta: { title: 'Dropzone' } meta: { title: 'dropzone' }
}, },
{ {
path: 'sticky', path: 'sticky',
component: () => import('@/views/components-demo/sticky'), component: () => import('@/views/components-demo/sticky'),
name: 'StickyDemo', name: 'StickyDemo',
meta: { title: 'Sticky' } meta: { title: 'sticky' }
}, },
{ {
path: 'count-to', path: 'count-to',
component: () => import('@/views/components-demo/count-to'), component: () => import('@/views/components-demo/count-to'),
name: 'CountToDemo', name: 'CountToDemo',
meta: { title: 'Count To' } meta: { title: 'countTo' }
}, },
{ {
path: 'mixin', path: 'mixin',
component: () => import('@/views/components-demo/mixin'), component: () => import('@/views/components-demo/mixin'),
name: 'ComponentMixinDemo', name: 'ComponentMixinDemo',
meta: { title: 'Component Mixin' } meta: { title: 'componentMixin' }
}, },
{ {
path: 'back-to-top', path: 'back-to-top',
component: () => import('@/views/components-demo/back-to-top'), component: () => import('@/views/components-demo/back-to-top'),
name: 'BackToTopDemo', name: 'BackToTopDemo',
meta: { title: 'Back To Top' } meta: { title: 'backToTop' }
}, },
{ {
path: 'drag-dialog', path: 'drag-dialog',
component: () => import('@/views/components-demo/drag-dialog'), component: () => import('@/views/components-demo/drag-dialog'),
name: 'DragDialogDemo', name: 'DragDialogDemo',
meta: { title: 'Drag Dialog' } meta: { title: 'dragDialog' }
}, },
{ {
path: 'drag-select', path: 'drag-select',
component: () => import('@/views/components-demo/drag-select'), component: () => import('@/views/components-demo/drag-select'),
name: 'DragSelectDemo', name: 'DragSelectDemo',
meta: { title: 'Drag Select' } meta: { title: 'dragSelect' }
}, },
{ {
path: 'dnd-list', path: 'dnd-list',
component: () => import('@/views/components-demo/dnd-list'), component: () => import('@/views/components-demo/dnd-list'),
name: 'DndListDemo', name: 'DndListDemo',
meta: { title: 'Dnd List' } meta: { title: 'dndList' }
}, },
{ {
path: 'drag-kanban', path: 'drag-kanban',
component: () => import('@/views/components-demo/drag-kanban'), component: () => import('@/views/components-demo/drag-kanban'),
name: 'DragKanbanDemo', name: 'DragKanbanDemo',
meta: { title: 'Drag Kanban' } meta: { title: 'dragKanban' }
} }
] ]
} }

View File

@ -8,7 +8,7 @@ const nestedRouter = {
redirect: '/nested/menu1/menu1-1', redirect: '/nested/menu1/menu1-1',
name: 'Nested', name: 'Nested',
meta: { meta: {
title: 'Nested Routes', title: 'nested',
icon: 'nested' icon: 'nested'
}, },
children: [ children: [
@ -16,33 +16,33 @@ const nestedRouter = {
path: 'menu1', path: 'menu1',
component: () => import('@/views/nested/menu1/index'), // Parent router-view component: () => import('@/views/nested/menu1/index'), // Parent router-view
name: 'Menu1', name: 'Menu1',
meta: { title: 'Menu 1' }, meta: { title: 'menu1' },
redirect: '/nested/menu1/menu1-1', redirect: '/nested/menu1/menu1-1',
children: [ children: [
{ {
path: 'menu1-1', path: 'menu1-1',
component: () => import('@/views/nested/menu1/menu1-1'), component: () => import('@/views/nested/menu1/menu1-1'),
name: 'Menu1-1', name: 'Menu1-1',
meta: { title: 'Menu 1-1' } meta: { title: 'menu1-1' }
}, },
{ {
path: 'menu1-2', path: 'menu1-2',
component: () => import('@/views/nested/menu1/menu1-2'), component: () => import('@/views/nested/menu1/menu1-2'),
name: 'Menu1-2', name: 'Menu1-2',
redirect: '/nested/menu1/menu1-2/menu1-2-1', redirect: '/nested/menu1/menu1-2/menu1-2-1',
meta: { title: 'Menu 1-2' }, meta: { title: 'menu1-2' },
children: [ children: [
{ {
path: 'menu1-2-1', path: 'menu1-2-1',
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'), component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
name: 'Menu1-2-1', name: 'Menu1-2-1',
meta: { title: 'Menu 1-2-1' } meta: { title: 'menu1-2-1' }
}, },
{ {
path: 'menu1-2-2', path: 'menu1-2-2',
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'), component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
name: 'Menu1-2-2', name: 'Menu1-2-2',
meta: { title: 'Menu 1-2-2' } meta: { title: 'menu1-2-2' }
} }
] ]
}, },
@ -50,7 +50,7 @@ const nestedRouter = {
path: 'menu1-3', path: 'menu1-3',
component: () => import('@/views/nested/menu1/menu1-3'), component: () => import('@/views/nested/menu1/menu1-3'),
name: 'Menu1-3', name: 'Menu1-3',
meta: { title: 'Menu 1-3' } meta: { title: 'menu1-3' }
} }
] ]
}, },
@ -58,7 +58,7 @@ const nestedRouter = {
path: 'menu2', path: 'menu2',
name: 'Menu2', name: 'Menu2',
component: () => import('@/views/nested/menu2/index'), component: () => import('@/views/nested/menu2/index'),
meta: { title: 'Menu 2' } meta: { title: 'menu2' }
} }
] ]
} }

View File

@ -16,25 +16,25 @@ const tableRouter = {
path: 'dynamic-table', path: 'dynamic-table',
component: () => import('@/views/table/dynamic-table/index'), component: () => import('@/views/table/dynamic-table/index'),
name: 'DynamicTable', name: 'DynamicTable',
meta: { title: 'Dynamic Table' } meta: { title: 'dynamicTable' }
}, },
{ {
path: 'drag-table', path: 'drag-table',
component: () => import('@/views/table/drag-table'), component: () => import('@/views/table/drag-table'),
name: 'DragTable', name: 'DragTable',
meta: { title: 'Drag Table' } meta: { title: 'dragTable' }
}, },
{ {
path: 'inline-edit-table', path: 'inline-edit-table',
component: () => import('@/views/table/inline-edit-table'), component: () => import('@/views/table/inline-edit-table'),
name: 'InlineEditTable', name: 'InlineEditTable',
meta: { title: 'Inline Edit' } meta: { title: 'inlineEditTable' }
}, },
{ {
path: 'complex-table', path: 'complex-table',
component: () => import('@/views/table/complex-table'), component: () => import('@/views/table/complex-table'),
name: 'ComplexTable', name: 'ComplexTable',
meta: { title: 'Complex Table' } meta: { title: 'complexTable' }
} }
] ]
} }

View File

@ -25,6 +25,13 @@ module.exports = {
*/ */
sidebarLogo: false, sidebarLogo: false,
/**
* @type {boolean} true | false
* @description Whether support pinyin search in headerSearch
* Bundle size minified 47.3kb,minified + gzipped 63kb
*/
supportPinyinSearch: true,
/** /**
* @type {string | array} 'production' | ['production', 'development'] * @type {string | array} 'production' | ['production', 'development']
* @description Need show err logs component. * @description Need show err logs component.

View File

@ -1,5 +1,6 @@
const getters = { const getters = {
sidebar: state => state.app.sidebar, sidebar: state => state.app.sidebar,
language: state => state.app.language,
size: state => state.app.size, size: state => state.app.size,
device: state => state.app.device, device: state => state.app.device,
visitedViews: state => state.tagsView.visitedViews, visitedViews: state => state.tagsView.visitedViews,

View File

@ -1,4 +1,5 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { getLanguage } from '@/lang/index'
const state = { const state = {
sidebar: { sidebar: {
@ -6,6 +7,7 @@ const state = {
withoutAnimation: false withoutAnimation: false
}, },
device: 'desktop', device: 'desktop',
language: getLanguage(),
size: Cookies.get('size') || 'medium' size: Cookies.get('size') || 'medium'
} }
@ -27,6 +29,10 @@ const mutations = {
TOGGLE_DEVICE: (state, device) => { TOGGLE_DEVICE: (state, device) => {
state.device = device state.device = device
}, },
SET_LANGUAGE: (state, language) => {
state.language = language
Cookies.set('language', language)
},
SET_SIZE: (state, size) => { SET_SIZE: (state, size) => {
state.size = size state.size = size
Cookies.set('size', size) Cookies.set('size', size)
@ -43,6 +49,9 @@ const actions = {
toggleDevice({ commit }, device) { toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device) commit('TOGGLE_DEVICE', device)
}, },
setLanguage({ commit }, language) {
commit('SET_LANGUAGE', language)
},
setSize({ commit }, size) { setSize({ commit }, size) {
commit('SET_SIZE', size) commit('SET_SIZE', size)
} }

View File

@ -1,18 +1,20 @@
import variables from '@/styles/element-variables.scss' import variables from '@/styles/element-variables.scss'
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings const { showSettings, tagsView, fixedHeader, sidebarLogo, supportPinyinSearch } = defaultSettings
const state = { const state = {
theme: variables.theme, theme: variables.theme,
showSettings: showSettings, showSettings,
tagsView: tagsView, tagsView,
fixedHeader: fixedHeader, fixedHeader,
sidebarLogo: sidebarLogo sidebarLogo,
supportPinyinSearch
} }
const mutations = { const mutations = {
CHANGE_SETTING: (state, { key, value }) => { CHANGE_SETTING: (state, { key, value }) => {
// eslint-disable-next-line no-prototype-builtins
if (state.hasOwnProperty(key)) { if (state.hasOwnProperty(key)) {
state[key] = value state[key] = value
} }

View File

@ -103,28 +103,23 @@ const actions = {
}, },
// dynamically modify permissions // dynamically modify permissions
changeRoles({ commit, dispatch }, role) { async changeRoles({ commit, dispatch }, role) {
return new Promise(async resolve => { const token = role + '-token'
const token = role + '-token'
commit('SET_TOKEN', token) commit('SET_TOKEN', token)
setToken(token) setToken(token)
const { roles } = await dispatch('getInfo') const { roles } = await dispatch('getInfo')
resetRouter() resetRouter()
// generate accessible routes map based on roles // generate accessible routes map based on roles
const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true }) const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })
// dynamically add accessible routes
router.addRoutes(accessRoutes)
// dynamically add accessible routes // reset visited views and cached views
router.addRoutes(accessRoutes) dispatch('tagsView/delAllViews', null, { root: true })
// reset visited views and cached views
dispatch('tagsView/delAllViews', null, { root: true })
resolve()
})
} }
} }

View File

@ -31,7 +31,7 @@
.fixed-width { .fixed-width {
.el-button--mini { .el-button--mini {
padding: 7px 10px; padding: 7px 10px;
width: 60px; min-width: 60px;
} }
} }
@ -77,3 +77,8 @@
.el-range-editor.el-input__inner { .el-range-editor.el-input__inner {
display: inline-flex !important; display: inline-flex !important;
} }
// to fix el-date-picker css style
.el-range-separator {
box-sizing: content-box;
}

View File

@ -6,7 +6,7 @@
/* theme color */ /* theme color */
$--color-primary: #1890ff; $--color-primary: #1890ff;
$--color-success: #13ce66; $--color-success: #13ce66;
$--color-warning: #FFBA00; $--color-warning: #ffba00;
$--color-danger: #ff4949; $--color-danger: #ff4949;
// $--color-info: #1E1E1E; // $--color-info: #1E1E1E;
@ -17,10 +17,10 @@ $--button-font-weight: 400;
$--border-color-light: #dfe4ed; $--border-color-light: #dfe4ed;
$--border-color-lighter: #e6ebf5; $--border-color-lighter: #e6ebf5;
$--table-border:1px solid#dfe6ec; $--table-border: 1px solid #dfe6ec;
/* icon font path, required */ /* icon font path, required */
$--font-path: '~element-ui/lib/theme-chalk/fonts'; $--font-path: "~element-ui/lib/theme-chalk/fonts";
@import "~element-ui/packages/theme-chalk/src/index"; @import "~element-ui/packages/theme-chalk/src/index";

View File

@ -57,6 +57,11 @@
margin-right: 16px; margin-right: 16px;
} }
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
.el-menu { .el-menu {
border: none; border: none;
height: 100%; height: 100%;
@ -105,6 +110,10 @@
.svg-icon { .svg-icon {
margin-left: 20px; margin-left: 20px;
} }
.sub-el-icon {
margin-left: 19px;
}
} }
} }
@ -118,6 +127,10 @@
margin-left: 20px; margin-left: 20px;
} }
.sub-el-icon {
margin-left: 19px;
}
.el-submenu__icon-arrow { .el-submenu__icon-arrow {
display: none; display: none;
} }
@ -178,6 +191,10 @@
.svg-icon { .svg-icon {
margin-right: 16px; margin-right: 16px;
} }
.sub-el-icon {
margin-right: 12px;
margin-left: -2px;
}
} }
.nest-menu .el-submenu>.el-submenu__title, .nest-menu .el-submenu>.el-submenu__title,

View File

@ -1,10 +1,13 @@
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
import i18n from '@/lang'
const title = defaultSettings.title || 'Vue Element Admin' const title = defaultSettings.title || 'Vue Element Admin'
export default function getPageTitle(pageTitle) { export default function getPageTitle(key) {
if (pageTitle) { const hasKey = i18n.te(`route.${key}`)
return `${pageTitle} - ${title}` if (hasKey) {
const pageName = i18n.t(`route.${key}`)
return `${pageName} - ${title}`
} }
return `${title}` return `${title}`
} }

12
src/utils/i18n.js Normal file
View File

@ -0,0 +1,12 @@
// translate router.meta.title, be used in breadcrumb sidebar tagsview
export function generateTitle(title) {
const hasKey = this.$te('route.' + title)
if (hasKey) {
// $t :this method from vue-i18n, inject in @/lang/index.js
const translatedTitle = this.$t('route.' + title)
return translatedTitle
}
return title
}

View File

@ -9,7 +9,7 @@
* @returns {string | null} * @returns {string | null}
*/ */
export function parseTime(time, cFormat) { export function parseTime(time, cFormat) {
if (arguments.length === 0) { if (arguments.length === 0 || !time) {
return null return null
} }
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
@ -17,9 +17,17 @@ export function parseTime(time, cFormat) {
if (typeof time === 'object') { if (typeof time === 'object') {
date = time date = time
} else { } else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { if ((typeof time === 'string')) {
time = parseInt(time) if ((/^[0-9]+$/.test(time))) {
// support "1548221490638"
time = parseInt(time)
} else {
// support safari
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
time = time.replace(new RegExp(/-/gm), '/')
}
} }
if ((typeof time === 'number') && (time.toString().length === 10)) { if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000 time = time * 1000
} }
@ -154,19 +162,21 @@ export function param(json) {
* @returns {Object} * @returns {Object}
*/ */
export function param2Obj(url) { export function param2Obj(url) {
const search = url.split('?')[1] const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) { if (!search) {
return {} return {}
} }
return JSON.parse( const obj = {}
'{"' + const searchArr = search.split('&')
decodeURIComponent(search) searchArr.forEach(v => {
.replace(/"/g, '\\"') const index = v.indexOf('=')
.replace(/&/g, '","') if (index !== -1) {
.replace(/=/g, '":"') const name = v.substring(0, index)
.replace(/\+/g, ' ') + const val = v.substring(index + 1, v.length)
'"}' obj[name] = val
) }
})
return obj
} }
/** /**

View File

@ -13,11 +13,7 @@ export default function checkPermission(value) {
const hasPermission = roles.some(role => { const hasPermission = roles.some(role => {
return permissionRoles.includes(role) return permissionRoles.includes(role)
}) })
return hasPermission
if (!hasPermission) {
return false
}
return true
} else { } else {
console.error(`need roles! Like v-permission="['admin','editor']"`) console.error(`need roles! Like v-permission="['admin','editor']"`)
return false return false

View File

@ -2,7 +2,7 @@
<div class="components-container"> <div class="components-container">
<aside>This is based on <aside>This is based on
<a class="link-type" href="//github.com/dai-siki/vue-image-crop-upload"> vue-image-crop-upload</a>. <a class="link-type" href="//github.com/dai-siki/vue-image-crop-upload"> vue-image-crop-upload</a>.
Since I was using only the vue@1 version, and it is not compatible with mockjs at the moment, I modified it myself, and if you are going to use it, it is better to use official version. {{ $t('components.imageUploadTips') }}
</aside> </aside>
<pan-thumb :image="image" /> <pan-thumb :image="image" />

View File

@ -1,11 +1,7 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<aside> <aside>{{ $t('components.backToTopTips1') }}</aside>
When the page is scrolled to the specified position, the Back to Top button appears in the lower right corner <aside>{{ $t('components.backToTopTips2') }}</aside>
</aside>
<aside>
You can customize the style of the button, show / hide, height of appearance, height of the return. If you need a text prompt, you can use element-ui el-tooltip elements externally
</aside>
<div class="placeholder-container"> <div class="placeholder-container">
<div>placeholder</div> <div>placeholder</div>
<div>placeholder</div> <div>placeholder</div>

View File

@ -2,7 +2,7 @@
<div class="components-container"> <div class="components-container">
<aside> <aside>
Based on <a class="link-type" href="https://github.com/rowanwins/vue-dropzone"> dropzone </a>. Based on <a class="link-type" href="https://github.com/rowanwins/vue-dropzone"> dropzone </a>.
Because my business has special needs, and has to upload images to qiniu, so instead of a third party, I chose encapsulate it by myself. It is very simple, you can see the detail code in @/components/Dropzone. {{ $t('components.dropzoneTips') }}
</aside> </aside>
<div class="editor-container"> <div class="editor-container">
<dropzone id="myVueDropzone" url="https://httpbin.org/post" @dropzone-removedFile="dropzoneR" @dropzone-success="dropzoneS" /> <dropzone id="myVueDropzone" url="https://httpbin.org/post" @dropzone-removedFile="dropzoneR" @dropzone-success="dropzoneS" />

View File

@ -79,7 +79,7 @@ export default {
}, },
computed: { computed: {
language() { language() {
return this.languageTypeList['en'] return this.languageTypeList[this.$store.getters.language]
} }
}, },
methods: { methods: {

View File

@ -37,9 +37,7 @@
</sticky> </sticky>
<div class="components-container"> <div class="components-container">
<aside> <aside>Sticky header, {{ $t('components.stickyTips') }}</aside>
Sticky header, When the page is scrolled to the preset position will be sticky on the top.
</aside>
<div>placeholder</div> <div>placeholder</div>
<div>placeholder</div> <div>placeholder</div>
<div>placeholder</div> <div>placeholder</div>

View File

@ -1,8 +1,8 @@
<template> <template>
<div class="components-container"> <div class="components-container">
<aside> <aside>
Rich text is a core feature of the management backend, but at the same time it is a place with lots of pits. In the process of selecting rich texts, I also took a lot of detours. The common rich texts on the market have been basically used, and I finally chose Tinymce. See the more detailed rich text comparison and introduction. {{ $t('components.tinymceTips') }}
<a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/component/rich-editor.html">Documentation</a> <a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html"> {{ $t('components.documentation') }}</a>
</aside> </aside>
<div> <div>
<tinymce v-model="content" :height="300" /> <tinymce v-model="content" :height="300" />

View File

@ -15,7 +15,7 @@
<el-progress :percentage="18" /> <el-progress :percentage="18" />
</div> </div>
<div class="progress-item"> <div class="progress-item">
<span>Css</span> <span>CSS</span>
<el-progress :percentage="12" /> <el-progress :percentage="12" />
</div> </div>
<div class="progress-item"> <div class="progress-item">
@ -101,7 +101,7 @@ export default {
background-color: #fff; background-color: #fff;
margin: auto; margin: auto;
box-shadow: none!important; box-shadow: none!important;
/deep/ .pan-info { ::v-deep .pan-info {
box-shadow: none!important; box-shadow: none!important;
} }
} }

View File

@ -70,7 +70,7 @@ export default {
indicator: [ indicator: [
{ name: 'Sales', max: 10000 }, { name: 'Sales', max: 10000 },
{ name: 'Administration', max: 20000 }, { name: 'Administration', max: 20000 },
{ name: 'Information Techology', max: 20000 }, { name: 'Information Technology', max: 20000 },
{ name: 'Customer Support', max: 20000 }, { name: 'Customer Support', max: 20000 },
{ name: 'Development', max: 20000 }, { name: 'Development', max: 20000 },
{ name: 'Marketing', max: 20000 } { name: 'Marketing', max: 20000 }

View File

@ -1,26 +1,11 @@
<template> <template>
<div class="app-container documentation-container"> <div class="app-container documentation-container">
<a <a class="document-btn" target="_blank" href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=demo_English_button">Java backend integration</a>
class="document-btn" <a class="document-btn" target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/">Documentation</a>
target="_blank" <a class="document-btn" target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">Github Repository</a>
href="https://panjiachen.github.io/vue-element-admin-site/" <a class="document-btn" target="_blank" href="https://panjiachen.gitee.io/vue-element-admin-site/zh/">国内文档</a>
>Documentation</a> <dropdown-menu class="document-btn" :items="articleList" title="系列文章" />
<a <a class="document-btn" target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/zh/job/">内推招聘</a>
class="document-btn"
target="_blank"
href="https://github.com/PanJiaChen/vue-element-admin/"
>Github Repository</a>
<a
class="document-btn"
target="_blank"
href="https://panjiachen.gitee.io/vue-element-admin-site/zh/"
>国内文档</a>
<dropdown-menu :items="articleList" style="float:left;margin-left:50px;" title="系列文章" />
<a
class="document-btn"
target="_blank"
href="https://panjiachen.github.io/vue-element-admin-site/zh/job/"
>内推招聘</a>
</div> </div>
</template> </template>
@ -53,15 +38,17 @@ export default {
margin: 50px; margin: 50px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-start;
.document-btn { .document-btn {
margin-left: 50px; flex-shrink: 0;
display: block; display: block;
cursor: pointer; cursor: pointer;
background: black; background: black;
color: white; color: white;
height: 60px; height: 60px;
width: 200px; padding: 0 16px;
margin-bottom: 16px; margin: 16px;
line-height: 60px; line-height: 60px;
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;

View File

@ -2,11 +2,12 @@
<div class="errPage-container"> <div class="errPage-container">
<ErrorA /> <ErrorA />
<ErrorB /> <ErrorB />
<h3>Please click the bug icon in the upper right corner</h3> <!-- $t is vue-i18n global function to translate lang -->
<h3>{{ $t('errorLog.tips') }}</h3>
<aside> <aside>
Now the management system are basically the form of the spa, it enhances the user experience, but it also increases the possibility of page problems, a small negligence may lead to the entire page deadlock. Fortunately Vue provides a way to catch handling exceptions, where you can handle errors or report exceptions. {{ $t('errorLog.description') }}
<a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/error.html"> <a target="_blank" class="link-type" href="https://panjiachen.github.io/vue-element-admin-site/guide/advanced/error.html">
Document introduction {{ $t('errorLog.documentation') }}
</a> </a>
</aside> </aside>
<a href="#"> <a href="#">

View File

@ -1,7 +1,6 @@
<template> <template>
<div class="createPost-container"> <div class="createPost-container">
<el-form ref="postForm" :model="postForm" :rules="rules" class="form-container"> <el-form ref="postForm" :model="postForm" :rules="rules" class="form-container">
<sticky :z-index="10" :class-name="'sub-navbar '+postForm.status"> <sticky :z-index="10" :class-name="'sub-navbar '+postForm.status">
<CommentDropdown v-model="postForm.comment_disabled" /> <CommentDropdown v-model="postForm.comment_disabled" />
<PlatformDropdown v-model="postForm.platforms" /> <PlatformDropdown v-model="postForm.platforms" />
@ -153,6 +152,9 @@ export default {
contentShortLength() { contentShortLength() {
return this.postForm.content_short.length return this.postForm.content_short.length
}, },
lang() {
return this.$store.getters.language
},
displayTime: { displayTime: {
// set and get is useful when the data // set and get is useful when the data
// returned by the back end api is different from the front end // returned by the back end api is different from the front end
@ -196,7 +198,7 @@ export default {
}) })
}, },
setTagsViewTitle() { setTagsViewTitle() {
const title = 'Edit Article' const title = this.lang === 'zh' ? '编辑文章' : 'Edit Article'
const route = Object.assign({}, this.tempRoute, { title: `${title}-${this.postForm.id}` }) const route = Object.assign({}, this.tempRoute, { title: `${title}-${this.postForm.id}` })
this.$store.dispatch('tagsView/updateVisitedView', route) this.$store.dispatch('tagsView/updateVisitedView', route)
}, },
@ -277,7 +279,7 @@ export default {
} }
} }
.article-textarea /deep/ { .article-textarea ::v-deep {
textarea { textarea {
padding-right: 40px; padding-right: 40px;
resize: none; resize: none;

View File

@ -1,9 +1,6 @@
<template> <template>
<aside> <aside>
Creating and editing pages cannot be cached by keep-alive because keep-alive include does not currently support {{ $t('example.warning') }}
caching based on routes, so it is currently cached based on component name. If you want to achieve a similar caching
effect, you can use a browser caching scheme such as localStorage. Or do not use keep-alive include to cache all
pages directly. See details
<a <a
href="https://panjiachen.github.io/vue-element-admin-site/guide/essentials/tags-view.html" href="https://panjiachen.github.io/vue-element-admin-site/guide/essentials/tags-view.html"
target="_blank" target="_blank"

View File

@ -1,7 +1,8 @@
<template> <template>
<div style="display:inline-block;"> <div style="display:inline-block;">
<!-- $t is vue-i18n global function to translate lang -->
<label class="radio-label" style="padding-left:0;">Filename: </label> <label class="radio-label" style="padding-left:0;">Filename: </label>
<el-input v-model="filename" placeholder="Please enter the file name (default excel-list)" style="width:345px;" prefix-icon="el-icon-document" /> <el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:350px;" prefix-icon="el-icon-document" />
</div> </div>
</template> </template>

View File

@ -1,19 +1,19 @@
<template> <template>
<!-- $t is vue-i18n global function to translate lang -->
<div class="app-container"> <div class="app-container">
<div> <div>
<FilenameOption v-model="filename" /> <FilenameOption v-model="filename" />
<AutoWidthOption v-model="autoWidth" /> <AutoWidthOption v-model="autoWidth" />
<BookTypeOption v-model="bookType" /> <BookTypeOption v-model="bookType" />
<el-button :loading="downloadLoading" style="margin:0 0 20px 20px;" type="primary" icon="el-icon-document" @click="handleDownload"> <el-button :loading="downloadLoading" style="margin:0 0 20px 20px;" type="primary" icon="el-icon-document" @click="handleDownload">
Export Excel {{ $t('excel.export') }} Excel
</el-button> </el-button>
<a href="https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html" target="_blank" style="margin-left:15px;"> <a href="https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html" target="_blank" style="margin-left:15px;">
<el-tag type="info">Documentation</el-tag> <el-tag type="info">Documentation</el-tag>
</a> </a>
</div> </div>
<el-table v-loading="listLoading" :data="list" element-loading-text="拼命加载中" border fit highlight-current-row> <el-table v-loading="listLoading" :data="list" element-loading-text="Loading..." border fit highlight-current-row>
<el-table-column align="center" label="Id" width="95"> <el-table-column align="center" label="Id" width="95">
<template slot-scope="scope"> <template slot-scope="scope">
{{ scope.$index }} {{ scope.$index }}
@ -51,7 +51,6 @@ import { parseTime } from '@/utils'
import FilenameOption from './components/FilenameOption' import FilenameOption from './components/FilenameOption'
import AutoWidthOption from './components/AutoWidthOption' import AutoWidthOption from './components/AutoWidthOption'
import BookTypeOption from './components/BookTypeOption' import BookTypeOption from './components/BookTypeOption'
export default { export default {
name: 'ExportExcel', name: 'ExportExcel',
components: { FilenameOption, AutoWidthOption, BookTypeOption }, components: { FilenameOption, AutoWidthOption, BookTypeOption },

View File

@ -71,21 +71,21 @@ export default {
}, },
handleDownload() { handleDownload() {
this.downloadLoading = true this.downloadLoading = true
import('@/vendor/Export2Excel').then(excel => { import('@/vendor/Export2Excel').then(excel => {
const multiHeader = [['Id', 'Main Information', '', '', 'Date']] const multiHeader = [['Id', 'Main Information', '', '', 'Date']]
const header = ['', 'Title', 'Author', 'Readings', ''] const header = ['', 'Title', 'Author', 'Readings', '']
const filterVal = ['id', 'title', 'author', 'pageviews', 'display_time'] const filterVal = ['id', 'title', 'author', 'pageviews', 'display_time']
const list = this.list const list = this.list
const data = this.formatJson(filterVal, list) const data = this.formatJson(filterVal, list)
const merges = ['A1:A2', 'B1:D1', 'E1:E2'] const merges = ['A1:A2', 'B1:D1', 'E1:E2']
excel.export_json_to_excel({ excel.export_json_to_excel({
multiHeader, multiHeader,
header, header,
merges, merges,
data data
})
this.downloadLoading = false
}) })
this.downloadLoading = false
})
}, },
formatJson(filterVal, jsonData) { formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => { return jsonData.map(v => filterVal.map(j => {

View File

@ -1,8 +1,9 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-input v-model="filename" placeholder="Please enter the file name (default excel-list)" style="width:350px;" prefix-icon="el-icon-document" /> <!-- $t is vue-i18n global function to translate lang -->
<el-input v-model="filename" :placeholder="$t('excel.placeholder')" style="width:350px;" prefix-icon="el-icon-document" />
<el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="el-icon-document" @click="handleDownload"> <el-button :loading="downloadLoading" style="margin-bottom:20px" type="primary" icon="el-icon-document" @click="handleDownload">
Export Selected Items {{ $t('excel.selectedExport') }}
</el-button> </el-button>
<a href="https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html" target="_blank" style="margin-left:15px;"> <a href="https://panjiachen.github.io/vue-element-admin-site/feature/component/excel.html" target="_blank" style="margin-left:15px;">
<el-tag type="info">Documentation</el-tag> <el-tag type="info">Documentation</el-tag>

View File

@ -1,12 +1,11 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<aside> <aside>
The guide page is useful for some people who entered the project for the first time. You can briefly introduce the {{ $t('guide.description') }}
features of the project. Demo is based on
<a href="https://github.com/kamranahmedse/driver.js" target="_blank">driver.js.</a> <a href="https://github.com/kamranahmedse/driver.js" target="_blank">driver.js.</a>
</aside> </aside>
<el-button icon="el-icon-question" type="primary" @click.prevent.stop="guide"> <el-button icon="el-icon-question" type="primary" @click.prevent.stop="guide">
Show Guide {{ $t('guide.button') }}
</el-button> </el-button>
</div> </div>
</template> </template>

View File

@ -0,0 +1,168 @@
<template>
<div>
<el-card class="box-card" style="margin-top:40px;">
<div slot="header" class="clearfix">
<svg-icon icon-class="international" />
<span style="margin-left:10px;">{{ $t('i18nView.title') }}</span>
</div>
<div>
<el-radio-group v-model="lang" size="small">
<el-radio label="zh" border>
简体中文
</el-radio>
<el-radio label="en" border>
English
</el-radio>
<el-radio label="es" border>
Español
</el-radio>
<el-radio label="ja" border>
日本語
</el-radio>
</el-radio-group>
<el-tag style="margin-top:15px;display:block;" type="info">
{{ $t('i18nView.note') }}
</el-tag>
</div>
</el-card>
<el-row :gutter="20" style="margin:100px 15px 50px;">
<el-col :span="12" :xs="24">
<div class="block">
<el-date-picker v-model="date" :placeholder="$t('i18nView.datePlaceholder')" type="date" />
</div>
<div class="block">
<el-select v-model="value" :placeholder="$t('i18nView.selectPlaceholder')">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<div class="block">
<el-button class="item-btn" size="small">
{{ $t('i18nView.default') }}
</el-button>
<el-button class="item-btn" size="small" type="primary">
{{ $t('i18nView.primary') }}
</el-button>
<el-button class="item-btn" size="small" type="success">
{{ $t('i18nView.success') }}
</el-button>
<el-button class="item-btn" size="small" type="info">
{{ $t('i18nView.info') }}
</el-button>
<el-button class="item-btn" size="small" type="warning">
{{ $t('i18nView.warning') }}
</el-button>
<el-button class="item-btn" size="small" type="danger">
{{ $t('i18nView.danger') }}
</el-button>
</div>
</el-col>
<el-col :span="12" :xs="24">
<el-table :data="tableData" fit highlight-current-row border style="width: 100%">
<el-table-column :label="$t('i18nView.tableName')" prop="name" width="100" align="center" />
<el-table-column :label="$t('i18nView.tableDate')" prop="date" width="120" align="center" />
<el-table-column :label="$t('i18nView.tableAddress')" prop="address" />
</el-table>
</el-col>
</el-row>
</div>
</template>
<script>
import local from './local'
const viewName = 'i18nView'
export default {
name: 'I18n',
data() {
return {
date: '',
tableData: [{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
}],
options: [],
value: ''
}
},
computed: {
lang: {
get() {
return this.$store.state.app.language
},
set(lang) {
this.$i18n.locale = lang
this.$store.dispatch('app/setLanguage', lang)
}
}
},
watch: {
lang() {
this.setOptions()
}
},
created() {
if (!this.$i18n.getLocaleMessage('en')[viewName]) {
this.$i18n.mergeLocaleMessage('en', local.en)
this.$i18n.mergeLocaleMessage('zh', local.zh)
this.$i18n.mergeLocaleMessage('es', local.es)
this.$i18n.mergeLocaleMessage('ja', local.ja)
}
this.setOptions() // set default select options
},
methods: {
setOptions() {
this.options = [
{
value: '1',
label: this.$t('i18nView.one')
},
{
value: '2',
label: this.$t('i18nView.two')
},
{
value: '3',
label: this.$t('i18nView.three')
}
]
}
}
}
</script>
<style scoped>
.box-card {
width: 600px;
max-width: 100%;
margin: 20px auto;
}
.item-btn{
margin-bottom: 15px;
margin-left: 0px;
}
.block {
padding: 25px;
}
</style>

View File

@ -0,0 +1,83 @@
export default {
zh: {
i18nView: {
title: '切换语言',
note: '本项目国际化基于 vue-i18n',
datePlaceholder: '请选择日期',
selectPlaceholder: '请选择',
tableDate: '日期',
tableName: '姓名',
tableAddress: '地址',
default: '默认按钮',
primary: '主要按钮',
success: '成功按钮',
info: '信息按钮',
warning: '警告按钮',
danger: '危险按钮',
one: '一',
two: '二',
three: '三'
}
},
en: {
i18nView: {
title: 'Switch Language',
note: 'The internationalization of this project is based on vue-i18n',
datePlaceholder: 'Pick a day',
selectPlaceholder: 'Select',
tableDate: 'tableDate',
tableName: 'tableName',
tableAddress: 'tableAddress',
default: 'default:',
primary: 'primary',
success: 'success',
info: 'info',
warning: 'warning',
danger: 'danger',
one: 'One',
two: 'Two',
three: 'Three'
}
},
es: {
i18nView: {
title: 'Switch Language',
note: 'The internationalization of this project is based on vue-i18n',
datePlaceholder: 'Pick a day',
selectPlaceholder: 'Select',
tableDate: 'tableDate',
tableName: 'tableName',
tableAddress: 'tableAddress',
default: 'default:',
primary: 'primary',
success: 'success',
info: 'info',
warning: 'warning',
danger: 'danger',
one: 'One',
two: 'Two',
three: 'Three'
}
},
ja: {
i18nView: {
title: '言語切替',
note: 'vue-i18nを使っています',
datePlaceholder: '日時選択',
selectPlaceholder: '選択してください',
tableDate: '日時',
tableName: '姓名',
tableAddress: '住所',
default: 'default',
primary: 'primary',
success: 'success',
info: 'info',
warning: 'warning',
danger: 'danger',
one: '1',
two: '2',
three: '3'
}
}
}

View File

@ -1,74 +1,3 @@
const elementIcons = [ const elementIcons = ['platform-eleme', 'eleme', 'delete-solid', 'delete', 's-tools', 'setting', 'user-solid', 'user', 'phone', 'phone-outline', 'more', 'more-outline', 'star-on', 'star-off', 's-goods', 'goods', 'warning', 'warning-outline', 'question', 'info', 'remove', 'circle-plus', 'success', 'error', 'zoom-in', 'zoom-out', 'remove-outline', 'circle-plus-outline', 'circle-check', 'circle-close', 's-help', 'help', 'minus', 'plus', 'check', 'close', 'picture', 'picture-outline', 'picture-outline-round', 'upload', 'upload2', 'download', 'camera-solid', 'camera', 'video-camera-solid', 'video-camera', 'message-solid', 'bell', 's-cooperation', 's-order', 's-platform', 's-fold', 's-unfold', 's-operation', 's-promotion', 's-home', 's-release', 's-ticket', 's-management', 's-open', 's-shop', 's-marketing', 's-flag', 's-comment', 's-finance', 's-claim', 's-custom', 's-opportunity', 's-data', 's-check', 's-grid', 'menu', 'share', 'd-caret', 'caret-left', 'caret-right', 'caret-bottom', 'caret-top', 'bottom-left', 'bottom-right', 'back', 'right', 'bottom', 'top', 'top-left', 'top-right', 'arrow-left', 'arrow-right', 'arrow-down', 'arrow-up', 'd-arrow-left', 'd-arrow-right', 'video-pause', 'video-play', 'refresh', 'refresh-right', 'refresh-left', 'finished', 'sort', 'sort-up', 'sort-down', 'rank', 'loading', 'view', 'c-scale-to-original', 'date', 'edit', 'edit-outline', 'folder', 'folder-opened', 'folder-add', 'folder-remove', 'folder-delete', 'folder-checked', 'tickets', 'document-remove', 'document-delete', 'document-copy', 'document-checked', 'document', 'document-add', 'printer', 'paperclip', 'takeaway-box', 'search', 'monitor', 'attract', 'mobile', 'scissors', 'umbrella', 'headset', 'brush', 'mouse', 'coordinate', 'magic-stick', 'reading', 'data-line', 'data-board', 'pie-chart', 'data-analysis', 'collection-tag', 'film', 'suitcase', 'suitcase-1', 'receiving', 'collection', 'files', 'notebook-1', 'notebook-2', 'toilet-paper', 'office-building', 'school', 'table-lamp', 'house', 'no-smoking', 'smoking', 'shopping-cart-full', 'shopping-cart-1', 'shopping-cart-2', 'shopping-bag-1', 'shopping-bag-2', 'sold-out', 'sell', 'present', 'box', 'bank-card', 'money', 'coin', 'wallet', 'discount', 'price-tag', 'news', 'guide', 'male', 'female', 'thumb', 'cpu', 'link', 'connection', 'open', 'turn-off', 'set-up', 'chat-round', 'chat-line-round', 'chat-square', 'chat-dot-round', 'chat-dot-square', 'chat-line-square', 'message', 'postcard', 'position', 'turn-off-microphone', 'microphone', 'close-notification', 'bangzhu', 'time', 'odometer', 'crop', 'aim', 'switch-button', 'full-screen', 'copy-document', 'mic', 'stopwatch', 'medal-1', 'medal', 'trophy', 'trophy-1', 'first-aid-kit', 'discover', 'place', 'location', 'location-outline', 'location-information', 'add-location', 'delete-location', 'map-location', 'alarm-clock', 'timer', 'watch-1', 'watch', 'lock', 'unlock', 'key', 'service', 'mobile-phone', 'bicycle', 'truck', 'ship', 'basketball', 'football', 'soccer', 'baseball', 'wind-power', 'light-rain', 'lightning', 'heavy-rain', 'sunrise', 'sunrise-1', 'sunset', 'sunny', 'cloudy', 'partly-cloudy', 'cloudy-and-sunny', 'moon', 'moon-night', 'dish', 'dish-1', 'food', 'chicken', 'fork-spoon', 'knife-fork', 'burger', 'tableware', 'sugar', 'dessert', 'ice-cream', 'hot-water', 'water-cup', 'coffee-cup', 'cold-drink', 'goblet', 'goblet-full', 'goblet-square', 'goblet-square-full', 'refrigerator', 'grape', 'watermelon', 'cherry', 'apple', 'pear', 'orange', 'coffee', 'ice-tea', 'ice-drink', 'milk-tea', 'potato-strips', 'lollipop', 'ice-cream-square', 'ice-cream-round']
'info',
'error',
'success',
'warning',
'question',
'back',
'arrow-left',
'arrow-down',
'arrow-right',
'arrow-up',
'caret-left',
'caret-bottom',
'caret-top',
'caret-right',
'd-arrow-left',
'd-arrow-right',
'minus',
'plus',
'remove',
'circle-plus',
'remove-outline',
'circle-plus-outline',
'close',
'check',
'circle-close',
'circle-check',
'circle-close-outline',
'circle-check-outline',
'zoom-out',
'zoom-in',
'd-caret',
'sort',
'sort-down',
'sort-up',
'tickets',
'document',
'goods',
'sold-out',
'news',
'message',
'date',
'printer',
'time',
'bell',
'mobile-phone',
'service',
'view',
'menu',
'more',
'more-outline',
'star-on',
'star-off',
'location',
'location-outline',
'phone',
'phone-outline',
'picture',
'picture-outline',
'delete',
'search',
'edit',
'edit-outline',
'rank',
'refresh',
'share',
'setting',
'upload',
'upload2',
'download',
'loading'
]
export default elementIcons export default elementIcons

View File

@ -6,29 +6,33 @@
</aside> </aside>
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane label="Icons"> <el-tab-pane label="Icons">
<div v-for="item of svgIcons" :key="item" @click="handleClipboard(generateIconCode(item),$event)"> <div class="grid">
<el-tooltip placement="top"> <div v-for="item of svgIcons" :key="item" @click="handleClipboard(generateIconCode(item),$event)">
<div slot="content"> <el-tooltip placement="top">
{{ generateIconCode(item) }} <div slot="content">
</div> {{ generateIconCode(item) }}
<div class="icon-item"> </div>
<svg-icon :icon-class="item" class-name="disabled" /> <div class="icon-item">
<span>{{ item }}</span> <svg-icon :icon-class="item" class-name="disabled" />
</div> <span>{{ item }}</span>
</el-tooltip> </div>
</el-tooltip>
</div>
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="Element-UI Icons"> <el-tab-pane label="Element-UI Icons">
<div v-for="item of elementIcons" :key="item" @click="handleClipboard(generateElementIconCode(item),$event)"> <div class="grid">
<el-tooltip placement="top"> <div v-for="item of elementIcons" :key="item" @click="handleClipboard(generateElementIconCode(item),$event)">
<div slot="content"> <el-tooltip placement="top">
{{ generateElementIconCode(item) }} <div slot="content">
</div> {{ generateElementIconCode(item) }}
<div class="icon-item"> </div>
<i :class="'el-icon-' + item" /> <div class="icon-item">
<span>{{ item }}</span> <i :class="'el-icon-' + item" />
</div> <span>{{ item }}</span>
</el-tooltip> </div>
</el-tooltip>
</div>
</div> </div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@ -67,6 +71,12 @@ export default {
margin: 10px 20px 0; margin: 10px 20px 0;
overflow: hidden; overflow: hidden;
.grid {
position: relative;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
.icon-item { .icon-item {
margin: 20px; margin: 20px;
height: 85px; height: 85px;

View File

@ -3,7 +3,10 @@
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
<div class="title-container"> <div class="title-container">
<h3 class="title">Login Form</h3> <h3 class="title">
{{ $t('login.title') }}
</h3>
<lang-select class="set-language" />
</div> </div>
<el-form-item prop="username"> <el-form-item prop="username">
@ -13,7 +16,7 @@
<el-input <el-input
ref="username" ref="username"
v-model="loginForm.username" v-model="loginForm.username"
placeholder="Username" :placeholder="$t('login.username')"
name="username" name="username"
type="text" type="text"
tabindex="1" tabindex="1"
@ -31,7 +34,7 @@
ref="password" ref="password"
v-model="loginForm.password" v-model="loginForm.password"
:type="passwordType" :type="passwordType"
placeholder="Password" :placeholder="$t('login.password')"
name="password" name="password"
tabindex="2" tabindex="2"
autocomplete="on" autocomplete="on"
@ -45,26 +48,30 @@
</el-form-item> </el-form-item>
</el-tooltip> </el-tooltip>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button> <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">
{{ $t('login.logIn') }}
</el-button>
<div style="position:relative"> <div style="position:relative">
<div class="tips"> <div class="tips">
<span>Username : admin</span> <span>{{ $t('login.username') }} : admin</span>
<span>Password : any</span> <span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
</div> </div>
<div class="tips"> <div class="tips">
<span style="margin-right:18px;">Username : editor</span> <span style="margin-right:18px;">
<span>Password : any</span> {{ $t('login.username') }} : editor
</span>
<span>{{ $t('login.password') }} : {{ $t('login.any') }}</span>
</div> </div>
<el-button class="thirdparty-button" type="primary" @click="showDialog=true"> <el-button class="thirdparty-button" type="primary" @click="showDialog=true">
Or connect with {{ $t('login.thirdparty') }}
</el-button> </el-button>
</div> </div>
</el-form> </el-form>
<el-dialog title="Or connect with" :visible.sync="showDialog"> <el-dialog :title="$t('login.thirdparty')" :visible.sync="showDialog">
Can not be simulated on local, so please combine you own business simulation! ! ! {{ $t('login.thirdpartyTips') }}
<br> <br>
<br> <br>
<br> <br>
@ -75,11 +82,12 @@
<script> <script>
import { validUsername } from '@/utils/validate' import { validUsername } from '@/utils/validate'
import LangSelect from '@/components/LangSelect'
import SocialSign from './components/SocialSignin' import SocialSign from './components/SocialSignin'
export default { export default {
name: 'Login', name: 'Login',
components: { SocialSign }, components: { LangSelect, SocialSign },
data() { data() {
const validateUsername = (rule, value, callback) => { const validateUsername = (rule, value, callback) => {
if (!validUsername(value)) { if (!validUsername(value)) {
@ -138,17 +146,9 @@ export default {
// window.removeEventListener('storage', this.afterQRScan) // window.removeEventListener('storage', this.afterQRScan)
}, },
methods: { methods: {
checkCapslock({ shiftKey, key } = {}) { checkCapslock(e) {
if (key && key.length === 1) { const { key } = e
if (shiftKey && (key >= 'a' && key <= 'z') || !shiftKey && (key >= 'A' && key <= 'Z')) { this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
this.capsTooltip = true
} else {
this.capsTooltip = false
}
}
if (key === 'CapsLock' && this.capsTooltip === true) {
this.capsTooltip = false
}
}, },
showPwd() { showPwd() {
if (this.passwordType === 'password') { if (this.passwordType === 'password') {
@ -305,6 +305,15 @@ $light_gray:#eee;
text-align: center; text-align: center;
font-weight: bold; font-weight: bold;
} }
.set-language {
color: #fff;
position: absolute;
top: 3px;
font-size: 18px;
right: 0px;
cursor: pointer;
}
} }
.show-pwd { .show-pwd {

View File

@ -26,17 +26,17 @@ export default {
}, },
methods: { methods: {
fetchData() { fetchData() {
import('./content.js').then(data => { import('./content.js').then(data => {
const { title } = data.default const { title } = data.default
document.title = title document.title = title
this.article = data.default this.article = data.default
setTimeout(() => { setTimeout(() => {
this.fullscreenLoading = false this.fullscreenLoading = false
this.$nextTick(() => { this.$nextTick(() => {
window.print() window.print()
}) })
}, 3000) }, 3000)
}) })
} }
} }
} }

View File

@ -1,8 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<aside style="margin-top:15px;"> <aside style="margin-top:15px;">{{ $t('pdf.tips') }}</aside>
Here we use window.print() to implement the feature of downloading PDF.
</aside>
<router-link target="_blank" to="/pdf/download"> <router-link target="_blank" to="/pdf/download">
<el-button type="primary"> <el-button type="primary">
Click to download PDF Click to download PDF

View File

@ -1,9 +1,9 @@
<template> <template>
<div> <div>
<div style="margin-bottom:15px;"> <div style="margin-bottom:15px;">
Your roles: {{ roles }} {{ $t('permission.roles') }}: {{ roles }}
</div> </div>
Switch roles: {{ $t('permission.switchRoles') }}:
<el-radio-group v-model="switchRoles"> <el-radio-group v-model="switchRoles">
<el-radio-button label="editor" /> <el-radio-button label="editor" />
<el-radio-button label="admin" /> <el-radio-button label="admin" />

View File

@ -36,7 +36,7 @@
<div :key="'checkPermission'+key" style="margin-top:60px;"> <div :key="'checkPermission'+key" style="margin-top:60px;">
<aside> <aside>
In some cases, using v-permission will have no effect. For example: Element-UI's Tab component or el-table-column and other scenes that dynamically render dom. You can only do this with v-if. {{ $t('permission.tips') }}
<br> e.g. <br> e.g.
</aside> </aside>
@ -91,7 +91,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.app-container { .app-container {
/deep/ .permission-alert { ::v-deep .permission-alert {
width: 320px; width: 320px;
margin-top: 15px; margin-top: 15px;
background-color: #f0f9eb; background-color: #f0f9eb;
@ -100,10 +100,10 @@ export default {
border-radius: 4px; border-radius: 4px;
display: inline-block; display: inline-block;
} }
/deep/ .permission-sourceCode { ::v-deep .permission-sourceCode {
margin-left: 15px; margin-left: 15px;
} }
/deep/ .permission-tag { ::v-deep .permission-tag {
background-color: #ecf5ff; background-color: #ecf5ff;
} }
} }

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